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