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