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 }