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