xref: /onnv-gate/usr/src/cmd/fs.d/smbclnt/chacl/chacl.c (revision 11564:184d27948276)
1*11564SGordon.Ross@Sun.COM /*
2*11564SGordon.Ross@Sun.COM  * CDDL HEADER START
3*11564SGordon.Ross@Sun.COM  *
4*11564SGordon.Ross@Sun.COM  * The contents of this file are subject to the terms of the
5*11564SGordon.Ross@Sun.COM  * Common Development and Distribution License (the "License").
6*11564SGordon.Ross@Sun.COM  * You may not use this file except in compliance with the License.
7*11564SGordon.Ross@Sun.COM  *
8*11564SGordon.Ross@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*11564SGordon.Ross@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*11564SGordon.Ross@Sun.COM  * See the License for the specific language governing permissions
11*11564SGordon.Ross@Sun.COM  * and limitations under the License.
12*11564SGordon.Ross@Sun.COM  *
13*11564SGordon.Ross@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*11564SGordon.Ross@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*11564SGordon.Ross@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*11564SGordon.Ross@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*11564SGordon.Ross@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*11564SGordon.Ross@Sun.COM  *
19*11564SGordon.Ross@Sun.COM  * CDDL HEADER END
20*11564SGordon.Ross@Sun.COM  */
21*11564SGordon.Ross@Sun.COM 
22*11564SGordon.Ross@Sun.COM /*
23*11564SGordon.Ross@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24*11564SGordon.Ross@Sun.COM  * Use is subject to license terms.
25*11564SGordon.Ross@Sun.COM  */
26*11564SGordon.Ross@Sun.COM 
27*11564SGordon.Ross@Sun.COM /*
28*11564SGordon.Ross@Sun.COM  * This is the smbfs/chacl command.
29*11564SGordon.Ross@Sun.COM  * (just for testing - not installed)
30*11564SGordon.Ross@Sun.COM  *
31*11564SGordon.Ross@Sun.COM  * Works like chmod(1), but only supporting A=... forms.
32*11564SGordon.Ross@Sun.COM  * i.e. chacl A=everyone@:full_set:fd:allow /mnt/foo
33*11564SGordon.Ross@Sun.COM  *
34*11564SGordon.Ross@Sun.COM  * Some more test cases:
35*11564SGordon.Ross@Sun.COM  *	/usr/lib/fs/smbfs/chacl -v
36*11564SGordon.Ross@Sun.COM  *	A=user:2147483649:rwxpdDaARWcCos::allow,
37*11564SGordon.Ross@Sun.COM  *	user:2147483653:raRcs::allow,
38*11564SGordon.Ross@Sun.COM  *	everyone@:raRcs::allow
39*11564SGordon.Ross@Sun.COM  */
40*11564SGordon.Ross@Sun.COM 
41*11564SGordon.Ross@Sun.COM #include <sys/types.h>
42*11564SGordon.Ross@Sun.COM #include <sys/errno.h>
43*11564SGordon.Ross@Sun.COM #include <sys/stat.h>
44*11564SGordon.Ross@Sun.COM #include <sys/acl.h>
45*11564SGordon.Ross@Sun.COM #include <sys/acl_impl.h>
46*11564SGordon.Ross@Sun.COM 
47*11564SGordon.Ross@Sun.COM #include <fcntl.h>
48*11564SGordon.Ross@Sun.COM #include <stdio.h>
49*11564SGordon.Ross@Sun.COM #include <stdlib.h>
50*11564SGordon.Ross@Sun.COM #include <unistd.h>
51*11564SGordon.Ross@Sun.COM #include <string.h>
52*11564SGordon.Ross@Sun.COM #include <aclutils.h>
53*11564SGordon.Ross@Sun.COM 
54*11564SGordon.Ross@Sun.COM #include <netsmb/smbfs_acl.h>
55*11564SGordon.Ross@Sun.COM 
56*11564SGordon.Ross@Sun.COM char *progname;
57*11564SGordon.Ross@Sun.COM int Vflag;
58*11564SGordon.Ross@Sun.COM 
59*11564SGordon.Ross@Sun.COM void chacl(char *, uint32_t, uid_t, gid_t, acl_t *);
60*11564SGordon.Ross@Sun.COM 
61*11564SGordon.Ross@Sun.COM static const char Usage[] =
62*11564SGordon.Ross@Sun.COM 	"Usage: %s [-v] [-u UID] [-g GID] A=ACL... file ...\n"
63*11564SGordon.Ross@Sun.COM 	"\twhere A=ACL is like chmod(1)\n";
64*11564SGordon.Ross@Sun.COM 
65*11564SGordon.Ross@Sun.COM void
usage(void)66*11564SGordon.Ross@Sun.COM usage(void)
67*11564SGordon.Ross@Sun.COM {
68*11564SGordon.Ross@Sun.COM 	fprintf(stderr, Usage, progname);
69*11564SGordon.Ross@Sun.COM 	exit(1);
70*11564SGordon.Ross@Sun.COM }
71*11564SGordon.Ross@Sun.COM 
72*11564SGordon.Ross@Sun.COM int
main(int argc,char ** argv)73*11564SGordon.Ross@Sun.COM main(int argc, char **argv)
74*11564SGordon.Ross@Sun.COM {
75*11564SGordon.Ross@Sun.COM 	uid_t uid = (uid_t)-1;
76*11564SGordon.Ross@Sun.COM 	gid_t gid = (gid_t)-1;
77*11564SGordon.Ross@Sun.COM 	acl_t *acl = NULL;
78*11564SGordon.Ross@Sun.COM 	char *acl_arg;
79*11564SGordon.Ross@Sun.COM 	ulong_t tl;
80*11564SGordon.Ross@Sun.COM 	int c, error;
81*11564SGordon.Ross@Sun.COM 	uint32_t selector;
82*11564SGordon.Ross@Sun.COM 
83*11564SGordon.Ross@Sun.COM 	progname = argv[0];
84*11564SGordon.Ross@Sun.COM 
85*11564SGordon.Ross@Sun.COM 	while ((c = getopt(argc, argv, "vu:g:")) != -1) {
86*11564SGordon.Ross@Sun.COM 		switch (c) {
87*11564SGordon.Ross@Sun.COM 		case 'v':
88*11564SGordon.Ross@Sun.COM 			Vflag++;
89*11564SGordon.Ross@Sun.COM 			break;
90*11564SGordon.Ross@Sun.COM 		case 'u':
91*11564SGordon.Ross@Sun.COM 			tl = strtoul(optarg, NULL, 10);
92*11564SGordon.Ross@Sun.COM 			if (tl == 0)
93*11564SGordon.Ross@Sun.COM 				goto badopt;
94*11564SGordon.Ross@Sun.COM 			uid = (uid_t)tl;
95*11564SGordon.Ross@Sun.COM 			break;
96*11564SGordon.Ross@Sun.COM 		case 'g':
97*11564SGordon.Ross@Sun.COM 			tl = strtoul(optarg, NULL, 10);
98*11564SGordon.Ross@Sun.COM 			if (tl == 0)
99*11564SGordon.Ross@Sun.COM 				goto badopt;
100*11564SGordon.Ross@Sun.COM 			gid = (gid_t)tl;
101*11564SGordon.Ross@Sun.COM 			break;
102*11564SGordon.Ross@Sun.COM 		case ':':
103*11564SGordon.Ross@Sun.COM 			fprintf(stderr, "%s: option %c requires arg\n",
104*11564SGordon.Ross@Sun.COM 			    progname, c);
105*11564SGordon.Ross@Sun.COM 			usage();
106*11564SGordon.Ross@Sun.COM 			break;
107*11564SGordon.Ross@Sun.COM 
108*11564SGordon.Ross@Sun.COM 		badopt:
109*11564SGordon.Ross@Sun.COM 		default:
110*11564SGordon.Ross@Sun.COM 			fprintf(stderr, "%s: bad option: %c\n",
111*11564SGordon.Ross@Sun.COM 			    progname, c);
112*11564SGordon.Ross@Sun.COM 			usage();
113*11564SGordon.Ross@Sun.COM 			break;
114*11564SGordon.Ross@Sun.COM 		}
115*11564SGordon.Ross@Sun.COM 	}
116*11564SGordon.Ross@Sun.COM 
117*11564SGordon.Ross@Sun.COM 	if (optind + 1 > argc)
118*11564SGordon.Ross@Sun.COM 		usage();
119*11564SGordon.Ross@Sun.COM 	acl_arg = argv[optind++];
120*11564SGordon.Ross@Sun.COM 
121*11564SGordon.Ross@Sun.COM 	/*
122*11564SGordon.Ross@Sun.COM 	 * Ask libsec to parse the ACL arg.
123*11564SGordon.Ross@Sun.COM 	 */
124*11564SGordon.Ross@Sun.COM 	if (strncmp(acl_arg, "A=", 2) != 0)
125*11564SGordon.Ross@Sun.COM 		usage();
126*11564SGordon.Ross@Sun.COM 	error = acl_parse(acl_arg + 2, &acl);
127*11564SGordon.Ross@Sun.COM 	if (error) {
128*11564SGordon.Ross@Sun.COM 		fprintf(stderr, "%s: can not parse ACL: %s\n",
129*11564SGordon.Ross@Sun.COM 		    progname, acl_arg);
130*11564SGordon.Ross@Sun.COM 		exit(1);
131*11564SGordon.Ross@Sun.COM 	}
132*11564SGordon.Ross@Sun.COM 	if (acl->acl_type != ACE_T) {
133*11564SGordon.Ross@Sun.COM 		fprintf(stderr, "%s: ACL not ACE_T type: %s\n",
134*11564SGordon.Ross@Sun.COM 		    progname, acl_arg);
135*11564SGordon.Ross@Sun.COM 		exit(1);
136*11564SGordon.Ross@Sun.COM 	}
137*11564SGordon.Ross@Sun.COM 
138*11564SGordon.Ross@Sun.COM 	/*
139*11564SGordon.Ross@Sun.COM 	 * Which parts of the SD are being modified?
140*11564SGordon.Ross@Sun.COM 	 */
141*11564SGordon.Ross@Sun.COM 	selector = 0;
142*11564SGordon.Ross@Sun.COM 	if (acl)
143*11564SGordon.Ross@Sun.COM 		selector |= DACL_SECURITY_INFORMATION;
144*11564SGordon.Ross@Sun.COM 	if (uid != (uid_t)-1)
145*11564SGordon.Ross@Sun.COM 		selector |= OWNER_SECURITY_INFORMATION;
146*11564SGordon.Ross@Sun.COM 	if (gid != (gid_t)-1)
147*11564SGordon.Ross@Sun.COM 		selector |= GROUP_SECURITY_INFORMATION;
148*11564SGordon.Ross@Sun.COM 
149*11564SGordon.Ross@Sun.COM 	if (optind == argc)
150*11564SGordon.Ross@Sun.COM 		usage();
151*11564SGordon.Ross@Sun.COM 	for (; optind < argc; optind++)
152*11564SGordon.Ross@Sun.COM 		chacl(argv[optind], selector, uid, gid, acl);
153*11564SGordon.Ross@Sun.COM 
154*11564SGordon.Ross@Sun.COM done:
155*11564SGordon.Ross@Sun.COM 	acl_free(acl);
156*11564SGordon.Ross@Sun.COM 	return (0);
157*11564SGordon.Ross@Sun.COM }
158*11564SGordon.Ross@Sun.COM 
159*11564SGordon.Ross@Sun.COM void
chacl(char * file,uint32_t selector,uid_t uid,gid_t gid,acl_t * acl)160*11564SGordon.Ross@Sun.COM chacl(char *file, uint32_t selector, uid_t uid, gid_t gid, acl_t *acl)
161*11564SGordon.Ross@Sun.COM {
162*11564SGordon.Ross@Sun.COM 	struct stat st;
163*11564SGordon.Ross@Sun.COM 	struct i_ntsd *sd = NULL;
164*11564SGordon.Ross@Sun.COM 	int error, fd;
165*11564SGordon.Ross@Sun.COM 
166*11564SGordon.Ross@Sun.COM 	/*
167*11564SGordon.Ross@Sun.COM 	 * OK, try setting the ACL (via ioctl).  Open
168*11564SGordon.Ross@Sun.COM 	 * read-only because we're NOT writing data.
169*11564SGordon.Ross@Sun.COM 	 * The driver will re-open with the necessary
170*11564SGordon.Ross@Sun.COM 	 * access rights to set the ACL.
171*11564SGordon.Ross@Sun.COM 	 */
172*11564SGordon.Ross@Sun.COM 	fd = open(file, O_RDONLY, 0);
173*11564SGordon.Ross@Sun.COM 	if (fd < 0) {
174*11564SGordon.Ross@Sun.COM 		perror(file);
175*11564SGordon.Ross@Sun.COM 		exit(1);
176*11564SGordon.Ross@Sun.COM 	}
177*11564SGordon.Ross@Sun.COM 
178*11564SGordon.Ross@Sun.COM 	if (uid == (uid_t)-1 || gid == (gid_t)-1) {
179*11564SGordon.Ross@Sun.COM 		/*
180*11564SGordon.Ross@Sun.COM 		 * If not setting owner or group, we need the
181*11564SGordon.Ross@Sun.COM 		 * current owner and group for translating
182*11564SGordon.Ross@Sun.COM 		 * references via owner@ or group@ ACEs.
183*11564SGordon.Ross@Sun.COM 		 */
184*11564SGordon.Ross@Sun.COM 		if (fstat(fd, &st) != 0) {
185*11564SGordon.Ross@Sun.COM 			perror(file);
186*11564SGordon.Ross@Sun.COM 			exit(1);
187*11564SGordon.Ross@Sun.COM 		}
188*11564SGordon.Ross@Sun.COM 		if (uid == (uid_t)-1)
189*11564SGordon.Ross@Sun.COM 			uid = st.st_uid;
190*11564SGordon.Ross@Sun.COM 		if (gid == (gid_t)-1)
191*11564SGordon.Ross@Sun.COM 			gid = st.st_gid;
192*11564SGordon.Ross@Sun.COM 	}
193*11564SGordon.Ross@Sun.COM 
194*11564SGordon.Ross@Sun.COM 	/*
195*11564SGordon.Ross@Sun.COM 	 * Convert the ZFS ACL to an NT SD.
196*11564SGordon.Ross@Sun.COM 	 */
197*11564SGordon.Ross@Sun.COM 	error = smbfs_acl_zfs2sd(acl, uid, gid, selector, &sd);
198*11564SGordon.Ross@Sun.COM 	if (error) {
199*11564SGordon.Ross@Sun.COM 		fprintf(stderr, "%s: failed to convert ACL\n", progname);
200*11564SGordon.Ross@Sun.COM 		exit(1);
201*11564SGordon.Ross@Sun.COM 	}
202*11564SGordon.Ross@Sun.COM 
203*11564SGordon.Ross@Sun.COM 	if (Vflag) {
204*11564SGordon.Ross@Sun.COM 
205*11564SGordon.Ross@Sun.COM 		/*
206*11564SGordon.Ross@Sun.COM 		 * Print the SD in ZFS form.
207*11564SGordon.Ross@Sun.COM 		 */
208*11564SGordon.Ross@Sun.COM 		printf("Solaris security data:\n");
209*11564SGordon.Ross@Sun.COM 		if (uid == (uid_t)-1)
210*11564SGordon.Ross@Sun.COM 			printf("owner: -1\n");
211*11564SGordon.Ross@Sun.COM 		else
212*11564SGordon.Ross@Sun.COM 			printf("owner: %u\n", uid);
213*11564SGordon.Ross@Sun.COM 		if (gid == (gid_t)-1)
214*11564SGordon.Ross@Sun.COM 			printf("group: -1\n");
215*11564SGordon.Ross@Sun.COM 		else
216*11564SGordon.Ross@Sun.COM 			printf("group: %u\n", gid);
217*11564SGordon.Ross@Sun.COM 		acl_printacl(acl, 80, 1);
218*11564SGordon.Ross@Sun.COM 		printf("\n");
219*11564SGordon.Ross@Sun.COM 
220*11564SGordon.Ross@Sun.COM 		/*
221*11564SGordon.Ross@Sun.COM 		 * Print the SD in Windows form.
222*11564SGordon.Ross@Sun.COM 		 */
223*11564SGordon.Ross@Sun.COM 		printf("CIFS security data:\n");
224*11564SGordon.Ross@Sun.COM 		smbfs_acl_print_sd(stdout, sd);
225*11564SGordon.Ross@Sun.COM 		printf("\n");
226*11564SGordon.Ross@Sun.COM 	}
227*11564SGordon.Ross@Sun.COM 
228*11564SGordon.Ross@Sun.COM 	error = smbfs_acl_setsd(fd, selector, sd);
229*11564SGordon.Ross@Sun.COM 	(void) close(fd);
230*11564SGordon.Ross@Sun.COM 
231*11564SGordon.Ross@Sun.COM 	if (error) {
232*11564SGordon.Ross@Sun.COM 		fprintf(stderr, "%s: ACL set failed, %s\n",
233*11564SGordon.Ross@Sun.COM 		    file, strerror(error));
234*11564SGordon.Ross@Sun.COM 		exit(1);
235*11564SGordon.Ross@Sun.COM 	}
236*11564SGordon.Ross@Sun.COM 
237*11564SGordon.Ross@Sun.COM 	smbfs_acl_free_sd(sd);
238*11564SGordon.Ross@Sun.COM }
239