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