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