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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * This module provides Security Descriptor handling functions. 28 */ 29 30 #include <strings.h> 31 #include <assert.h> 32 #include <smbsrv/ntifs.h> 33 #include <smbsrv/smb_idmap.h> 34 #include <smbsrv/libsmb.h> 35 36 #define SMB_SHR_ACE_READ_PERMS (ACE_READ_PERMS | ACE_EXECUTE | ACE_SYNCHRONIZE) 37 #define SMB_SHR_ACE_CONTROL_PERMS (ACE_MODIFY_PERMS & (~ACE_DELETE_CHILD)) 38 39 /* 40 * This mapping table is provided to map permissions set by chmod 41 * using 'read_set' and 'modify_set' to what Windows share ACL GUI 42 * expects as Read and Control, respectively. 43 */ 44 static struct { 45 int am_ace_perms; 46 int am_share_perms; 47 } smb_ace_map[] = { 48 { ACE_MODIFY_PERMS, SMB_SHR_ACE_CONTROL_PERMS }, 49 { ACE_READ_PERMS, SMB_SHR_ACE_READ_PERMS } 50 }; 51 52 #define SMB_ACE_MASK_MAP_SIZE (sizeof (smb_ace_map)/sizeof (smb_ace_map[0])) 53 54 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int); 55 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int); 56 57 void 58 smb_sd_init(smb_sd_t *sd, uint8_t revision) 59 { 60 bzero(sd, sizeof (smb_sd_t)); 61 sd->sd_revision = revision; 62 } 63 64 /* 65 * smb_sd_term 66 * 67 * Free non-NULL members of 'sd' which has to be in 68 * absolute (pointer) form. 69 */ 70 void 71 smb_sd_term(smb_sd_t *sd) 72 { 73 assert(sd); 74 assert((sd->sd_control & SE_SELF_RELATIVE) == 0); 75 76 smb_sid_free(sd->sd_owner); 77 smb_sid_free(sd->sd_group); 78 smb_acl_free(sd->sd_dacl); 79 smb_acl_free(sd->sd_sacl); 80 81 bzero(sd, sizeof (smb_sd_t)); 82 } 83 84 uint32_t 85 smb_sd_len(smb_sd_t *sd, uint32_t secinfo) 86 { 87 uint32_t length = SMB_SD_HDRSIZE; 88 89 if (secinfo & SMB_OWNER_SECINFO) 90 length += smb_sid_len(sd->sd_owner); 91 92 if (secinfo & SMB_GROUP_SECINFO) 93 length += smb_sid_len(sd->sd_group); 94 95 if (secinfo & SMB_DACL_SECINFO) 96 length += smb_acl_len(sd->sd_dacl); 97 98 if (secinfo & SMB_SACL_SECINFO) 99 length += smb_acl_len(sd->sd_sacl); 100 101 return (length); 102 } 103 104 /* 105 * smb_sd_get_secinfo 106 * 107 * Return the security information mask for the specified security 108 * descriptor. 109 */ 110 uint32_t 111 smb_sd_get_secinfo(smb_sd_t *sd) 112 { 113 uint32_t sec_info = 0; 114 115 if (sd == NULL) 116 return (0); 117 118 if (sd->sd_owner) 119 sec_info |= SMB_OWNER_SECINFO; 120 121 if (sd->sd_group) 122 sec_info |= SMB_GROUP_SECINFO; 123 124 if (sd->sd_dacl) 125 sec_info |= SMB_DACL_SECINFO; 126 127 if (sd->sd_sacl) 128 sec_info |= SMB_SACL_SECINFO; 129 130 return (sec_info); 131 } 132 133 /* 134 * Adjust the Access Mask so that ZFS ACE mask and Windows ACE read mask match. 135 */ 136 static int 137 smb_sd_adjust_read_mask(int mask) 138 { 139 int i; 140 141 for (i = 0; i < SMB_ACE_MASK_MAP_SIZE; ++i) { 142 if (smb_ace_map[i].am_ace_perms == mask) 143 return (smb_ace_map[i].am_share_perms); 144 } 145 146 return (mask); 147 } 148 149 /* 150 * Get ZFS acl from the share path via acl_get() method. 151 */ 152 static uint32_t 153 smb_sd_read_acl(char *path, smb_fssd_t *fs_sd) 154 { 155 acl_t *z_acl; 156 ace_t *z_ace; 157 158 fs_sd->sd_gid = fs_sd->sd_uid = 0; 159 if (acl_trivial(path) != 1) 160 return (NT_STATUS_INTERNAL_ERROR); 161 162 if (acl_get(path, ACL_NO_TRIVIAL, &z_acl) != 0) 163 return (NT_STATUS_INTERNAL_ERROR); 164 165 if ((z_ace = (ace_t *)z_acl->acl_aclp) == NULL) 166 return (NT_STATUS_INVALID_ACL); 167 168 for (int i = 0; i < z_acl->acl_cnt; i++, z_ace++) 169 z_ace->a_access_mask = 170 smb_sd_adjust_read_mask(z_ace->a_access_mask); 171 172 fs_sd->sd_zdacl = z_acl; 173 fs_sd->sd_zsacl = NULL; 174 return (NT_STATUS_SUCCESS); 175 } 176 177 /* 178 * smb_sd_read 179 * 180 * Reads ZFS acl from filesystem using acl_get() method. Convert the ZFS acl to 181 * a Win SD and return the Win SD in absolute form. 182 * 183 * NOTE: upon successful return caller MUST free the memory allocated 184 * for the returned SD by calling smb_sd_term(). 185 */ 186 uint32_t 187 smb_sd_read(char *path, smb_sd_t *sd, uint32_t secinfo) 188 { 189 smb_fssd_t fs_sd; 190 uint32_t status = NT_STATUS_SUCCESS; 191 uint32_t sd_flags; 192 int error; 193 194 sd_flags = SMB_FSSD_FLAGS_DIR; 195 smb_fssd_init(&fs_sd, secinfo, sd_flags); 196 197 error = smb_sd_read_acl(path, &fs_sd); 198 if (error != NT_STATUS_SUCCESS) { 199 smb_fssd_term(&fs_sd); 200 return (error); 201 } 202 203 status = smb_sd_fromfs(&fs_sd, sd); 204 smb_fssd_term(&fs_sd); 205 206 return (status); 207 } 208 209 /* 210 * Apply ZFS acl to the share path via acl_set() method. 211 * A NULL ACL pointer here represents an error. 212 * Null or empty ACLs are handled in smb_sd_tofs(). 213 */ 214 static uint32_t 215 smb_sd_write_acl(char *path, smb_fssd_t *fs_sd) 216 { 217 acl_t *z_acl; 218 ace_t *z_ace; 219 uint32_t status = NT_STATUS_SUCCESS; 220 221 z_acl = fs_sd->sd_zdacl; 222 if (z_acl == NULL) 223 return (NT_STATUS_INVALID_ACL); 224 225 z_ace = (ace_t *)z_acl->acl_aclp; 226 if (z_ace == NULL) 227 return (NT_STATUS_INVALID_ACL); 228 229 fs_sd->sd_gid = fs_sd->sd_uid = 0; 230 if (acl_set(path, z_acl) != 0) 231 status = NT_STATUS_INTERNAL_ERROR; 232 233 return (status); 234 } 235 236 /* 237 * smb_sd_write 238 * 239 * Takes a Win SD in absolute form, converts it to 240 * ZFS acl and applies the acl to the share path via acl_set() method. 241 */ 242 uint32_t 243 smb_sd_write(char *path, smb_sd_t *sd, uint32_t secinfo) 244 { 245 smb_fssd_t fs_sd; 246 uint32_t status = NT_STATUS_SUCCESS; 247 uint32_t sd_flags; 248 int error; 249 250 sd_flags = SMB_FSSD_FLAGS_DIR; 251 smb_fssd_init(&fs_sd, secinfo, sd_flags); 252 253 error = smb_sd_tofs(sd, &fs_sd); 254 if (error != NT_STATUS_SUCCESS) { 255 smb_fssd_term(&fs_sd); 256 return (error); 257 } 258 259 status = smb_sd_write_acl(path, &fs_sd); 260 smb_fssd_term(&fs_sd); 261 262 return (status); 263 } 264 265 /* 266 * smb_sd_tofs 267 * 268 * Creates a filesystem security structure based on the given 269 * Windows security descriptor. 270 */ 271 uint32_t 272 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd) 273 { 274 smb_sid_t *sid; 275 uint32_t status = NT_STATUS_SUCCESS; 276 uint16_t sd_control; 277 idmap_stat idm_stat; 278 int idtype; 279 int flags = 0; 280 281 sd_control = sd->sd_control; 282 283 /* 284 * ZFS only has one set of flags so for now only 285 * Windows DACL flags are taken into account. 286 */ 287 if (sd_control & SE_DACL_DEFAULTED) 288 flags |= ACL_DEFAULTED; 289 if (sd_control & SE_DACL_AUTO_INHERITED) 290 flags |= ACL_AUTO_INHERIT; 291 if (sd_control & SE_DACL_PROTECTED) 292 flags |= ACL_PROTECTED; 293 294 if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) 295 flags |= ACL_IS_DIR; 296 297 /* Owner */ 298 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 299 sid = sd->sd_owner; 300 if (!smb_sid_isvalid(sid)) 301 return (NT_STATUS_INVALID_SID); 302 303 idtype = SMB_IDMAP_USER; 304 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype); 305 if (idm_stat != IDMAP_SUCCESS) { 306 return (NT_STATUS_NONE_MAPPED); 307 } 308 } 309 310 /* Group */ 311 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 312 sid = sd->sd_group; 313 if (!smb_sid_isvalid(sid)) 314 return (NT_STATUS_INVALID_SID); 315 316 idtype = SMB_IDMAP_GROUP; 317 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype); 318 if (idm_stat != IDMAP_SUCCESS) { 319 return (NT_STATUS_NONE_MAPPED); 320 } 321 } 322 323 /* DACL */ 324 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 325 if (sd->sd_control & SE_DACL_PRESENT) { 326 status = smb_acl_to_zfs(sd->sd_dacl, flags, 327 SMB_DACL_SECINFO, &fs_sd->sd_zdacl); 328 if (status != NT_STATUS_SUCCESS) 329 return (status); 330 } 331 else 332 return (NT_STATUS_INVALID_ACL); 333 } 334 335 /* SACL */ 336 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) { 337 if (sd->sd_control & SE_SACL_PRESENT) { 338 status = smb_acl_to_zfs(sd->sd_sacl, flags, 339 SMB_SACL_SECINFO, &fs_sd->sd_zsacl); 340 if (status != NT_STATUS_SUCCESS) { 341 return (status); 342 } 343 } else { 344 return (NT_STATUS_INVALID_ACL); 345 } 346 } 347 348 return (status); 349 } 350 351 /* 352 * smb_sd_fromfs 353 * 354 * Makes an Windows style security descriptor in absolute form 355 * based on the given filesystem security information. 356 * 357 * Should call smb_sd_term() for the returned sd to free allocated 358 * members. 359 */ 360 uint32_t 361 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd) 362 { 363 uint32_t status = NT_STATUS_SUCCESS; 364 smb_acl_t *acl = NULL; 365 smb_sid_t *sid; 366 idmap_stat idm_stat; 367 368 assert(fs_sd); 369 assert(sd); 370 371 smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION); 372 373 /* Owner */ 374 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 375 idm_stat = smb_idmap_getsid(fs_sd->sd_uid, 376 SMB_IDMAP_USER, &sid); 377 378 if (idm_stat != IDMAP_SUCCESS) { 379 smb_sd_term(sd); 380 return (NT_STATUS_NONE_MAPPED); 381 } 382 383 sd->sd_owner = sid; 384 } 385 386 /* Group */ 387 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 388 idm_stat = smb_idmap_getsid(fs_sd->sd_gid, 389 SMB_IDMAP_GROUP, &sid); 390 391 if (idm_stat != IDMAP_SUCCESS) { 392 smb_sd_term(sd); 393 return (NT_STATUS_NONE_MAPPED); 394 } 395 396 sd->sd_group = sid; 397 } 398 399 /* DACL */ 400 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 401 if (fs_sd->sd_zdacl != NULL) { 402 acl = smb_acl_from_zfs(fs_sd->sd_zdacl); 403 if (acl == NULL) { 404 smb_sd_term(sd); 405 return (NT_STATUS_INTERNAL_ERROR); 406 } 407 408 /* 409 * Need to sort the ACL before send it to Windows 410 * clients. Winodws GUI is sensitive about the order 411 * of ACEs. 412 */ 413 smb_acl_sort(acl); 414 smb_sd_set_dacl(sd, acl, B_TRUE, 415 fs_sd->sd_zdacl->acl_flags); 416 } else { 417 smb_sd_set_dacl(sd, NULL, B_FALSE, 0); 418 } 419 } 420 421 /* SACL */ 422 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) { 423 if (fs_sd->sd_zsacl != NULL) { 424 acl = smb_acl_from_zfs(fs_sd->sd_zsacl); 425 if (acl == NULL) { 426 smb_sd_term(sd); 427 return (NT_STATUS_INTERNAL_ERROR); 428 } 429 430 smb_sd_set_sacl(sd, acl, B_TRUE, 431 fs_sd->sd_zsacl->acl_flags); 432 } else { 433 smb_sd_set_sacl(sd, NULL, B_FALSE, 0); 434 } 435 } 436 437 return (status); 438 } 439 440 static void 441 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags) 442 { 443 assert((sd->sd_control & SE_SELF_RELATIVE) == 0); 444 445 sd->sd_dacl = acl; 446 447 if (flags & ACL_DEFAULTED) 448 sd->sd_control |= SE_DACL_DEFAULTED; 449 if (flags & ACL_AUTO_INHERIT) 450 sd->sd_control |= SE_DACL_AUTO_INHERITED; 451 if (flags & ACL_PROTECTED) 452 sd->sd_control |= SE_DACL_PROTECTED; 453 454 if (present) 455 sd->sd_control |= SE_DACL_PRESENT; 456 } 457 458 static void 459 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags) 460 { 461 assert((sd->sd_control & SE_SELF_RELATIVE) == 0); 462 463 sd->sd_sacl = acl; 464 465 if (flags & ACL_DEFAULTED) 466 sd->sd_control |= SE_SACL_DEFAULTED; 467 if (flags & ACL_AUTO_INHERIT) 468 sd->sd_control |= SE_SACL_AUTO_INHERITED; 469 if (flags & ACL_PROTECTED) 470 sd->sd_control |= SE_SACL_PROTECTED; 471 472 if (present) 473 sd->sd_control |= SE_SACL_PRESENT; 474 } 475 476 /* 477 * smb_fssd_init 478 * 479 * Initializes the given FS SD structure. 480 */ 481 void 482 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags) 483 { 484 bzero(fs_sd, sizeof (smb_fssd_t)); 485 fs_sd->sd_secinfo = secinfo; 486 fs_sd->sd_flags = flags; 487 } 488 489 /* 490 * smb_fssd_term 491 * 492 * Frees allocated memory for acl fields. 493 */ 494 void 495 smb_fssd_term(smb_fssd_t *fs_sd) 496 { 497 assert(fs_sd); 498 499 acl_free(fs_sd->sd_zdacl); 500 acl_free(fs_sd->sd_zsacl); 501 502 bzero(fs_sd, sizeof (smb_fssd_t)); 503 } 504