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