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 is a helper file to get/set Windows SD. This is used by 28 * SRVSVC service. 29 */ 30 #include <strings.h> 31 #include <libzfs.h> 32 #include <smbsrv/nterror.h> 33 #include <smbsrv/ntstatus.h> 34 #include <smbsrv/libmlsvc.h> 35 #include <smbsrv/ndl/srvsvc.ndl> 36 37 /* Size of offset members in mslm_security_descriptor structure */ 38 #define SRVSVC_SD_OFFSET_SZ 16 39 40 #define SRVSVC_ACE_OFFSET 8 41 #define SRVSVC_SID_OFFSET 8 42 43 static uint32_t srvsvc_sd_get_autohome(const smb_share_t *, smb_sd_t *); 44 static uint32_t srvsvc_sd_status_to_error(uint32_t); 45 static uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *); 46 static uint32_t srvsvc_sd_set_absolute(uint8_t *, smb_sd_t *); 47 48 /* 49 * This method computes ACL on share path from a share name. 50 * Return 0 upon success, -1 upon failure. 51 */ 52 static int 53 srvsvc_shareacl_getpath(smb_share_t *si, char *shr_acl_path) 54 { 55 char dataset[MAXPATHLEN]; 56 char mp[ZFS_MAXPROPLEN]; 57 libzfs_handle_t *libhd; 58 zfs_handle_t *zfshd; 59 int ret = 0; 60 61 ret = smb_getdataset(si->shr_path, dataset, MAXPATHLEN); 62 if (ret != 0) 63 return (ret); 64 65 if ((libhd = libzfs_init()) == NULL) 66 return (-1); 67 68 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { 69 libzfs_fini(libhd); 70 return (-1); 71 } 72 73 if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, 74 NULL, 0, B_FALSE) != 0) { 75 zfs_close(zfshd); 76 libzfs_fini(libhd); 77 return (-1); 78 } 79 80 zfs_close(zfshd); 81 libzfs_fini(libhd); 82 83 (void) snprintf(shr_acl_path, MAXPATHLEN, "%s/.zfs/shares/%s", 84 mp, si->shr_name); 85 86 return (ret); 87 } 88 89 /* 90 * This method sets Security Descriptor on a share path. 91 * 92 * Returns: 93 * ERROR_SUCCESS 94 * ERROR_NOT_ENOUGH_MEMORY 95 * ERROR_INVALID_ACL 96 * ERROR_INVALID_SID 97 * ERROR_INVALID_SECURITY_DESCR 98 * ERROR_NONE_MAPPED 99 * ERROR_INTERNAL_ERROR 100 * ERROR_PATH_NOT_FOUND 101 */ 102 uint32_t 103 srvsvc_sd_set(smb_share_t *si, uint8_t *sdbuf) 104 { 105 smb_sd_t sd; 106 uint32_t status = ERROR_SUCCESS; 107 char path[MAXPATHLEN]; 108 int ret = 0; 109 110 ret = srvsvc_shareacl_getpath(si, path); 111 if (ret != 0) 112 return (ERROR_PATH_NOT_FOUND); 113 114 smb_sd_init(&sd, 0); 115 status = srvsvc_sd_set_absolute(sdbuf, &sd); 116 if (status != ERROR_SUCCESS) { 117 smb_sd_term(&sd); 118 return (status); 119 } 120 121 status = smb_sd_write(path, &sd, SMB_DACL_SECINFO); 122 status = srvsvc_sd_status_to_error(status); 123 smb_sd_term(&sd); 124 125 return (status); 126 } 127 128 /* 129 * This method returns a Security Descriptor of a share path in self relative 130 * format. Call to this function with NULL buffer, returns the size of the 131 * security descriptor, which can be used to allocate buffer. 132 * 133 * Returns: 134 * ERROR_SUCCESS 135 * ERROR_NOT_ENOUGH_MEMORY 136 * ERROR_INVALID_ACL 137 * ERROR_INVALID_SID 138 * ERROR_INVALID_SECURITY_DESCR 139 * ERROR_INVALID_PARAMETER 140 * ERROR_NONE_MAPPED 141 * ERROR_INTERNAL_ERROR 142 * ERROR_PATH_NOT_FOUND 143 */ 144 uint32_t 145 srvsvc_sd_get(smb_share_t *si, uint8_t *sdbuf, uint32_t *size) 146 { 147 smb_sd_t sd; 148 uint32_t status = ERROR_SUCCESS; 149 char path[MAXPATHLEN]; 150 int ret = 0; 151 152 if (sdbuf == NULL && size == NULL) 153 return (ERROR_INVALID_PARAMETER); 154 155 bzero(&sd, sizeof (smb_sd_t)); 156 157 if (si->shr_flags & SMB_SHRF_AUTOHOME) { 158 status = srvsvc_sd_get_autohome(si, &sd); 159 } else { 160 ret = srvsvc_shareacl_getpath(si, path); 161 if (ret != 0) 162 return (ERROR_PATH_NOT_FOUND); 163 164 status = smb_sd_read(path, &sd, SMB_ALL_SECINFO); 165 status = srvsvc_sd_status_to_error(status); 166 } 167 168 if (status != ERROR_SUCCESS) { 169 smb_sd_term(&sd); 170 return (status); 171 } 172 173 if (sdbuf == NULL) { 174 *size = smb_sd_len(&sd, SMB_ALL_SECINFO); 175 smb_sd_term(&sd); 176 return (status); 177 } 178 179 status = srvsvc_sd_set_relative(&sd, sdbuf); 180 181 smb_sd_term(&sd); 182 return (status); 183 } 184 185 static uint32_t 186 srvsvc_sd_get_autohome(const smb_share_t *si, smb_sd_t *sd) 187 { 188 smb_fssd_t fs_sd; 189 acl_t *acl; 190 uint32_t status; 191 192 if (acl_fromtext("owner@:rwxpdDaARWcCos::allow", &acl) != 0) 193 return (ERROR_NOT_ENOUGH_MEMORY); 194 195 smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); 196 fs_sd.sd_uid = si->shr_uid; 197 fs_sd.sd_gid = si->shr_gid; 198 fs_sd.sd_zdacl = acl; 199 fs_sd.sd_zsacl = NULL; 200 201 status = smb_sd_fromfs(&fs_sd, sd); 202 status = srvsvc_sd_status_to_error(status); 203 smb_fssd_term(&fs_sd); 204 return (status); 205 } 206 207 /* 208 * This method converts an ACE from absolute (pointer) to 209 * self relative (flat buffer) format. 210 * 211 * Returns Win32 error codes. 212 */ 213 static uint32_t 214 srvsvc_ace_set_relative(mslm_ace_t *m_ace, struct mslm_sid *m_sid, 215 smb_ace_t *ace) 216 { 217 if ((m_ace == NULL) || (ace == NULL)) 218 return (ERROR_INVALID_PARAMETER); 219 220 bcopy(&ace->se_hdr, &m_ace->header, sizeof (mslm_ace_hdr_t)); 221 m_ace->mask = ace->se_mask; 222 223 if ((ace->se_sid == NULL) || (m_sid == NULL)) 224 return (ERROR_INVALID_PARAMETER); 225 bcopy(ace->se_sid, m_sid, smb_sid_len(ace->se_sid)); 226 227 return (ERROR_SUCCESS); 228 } 229 230 /* 231 * This method converts an ACL from absolute (pointer) to 232 * self relative (flat buffer) format. 233 * 234 * Returns an initialized mslm_acl structure on success. 235 * Returns NULL on failure. 236 */ 237 static struct mslm_acl * 238 srvsvc_acl_set_relative(uint8_t *sdbuf, smb_acl_t *acl) 239 { 240 struct mslm_acl *m_acl; 241 242 if (sdbuf == NULL) 243 return (NULL); 244 245 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 246 m_acl = (struct mslm_acl *)sdbuf; 247 m_acl->revision = acl->sl_revision; 248 m_acl->sbz1 = 0; 249 m_acl->size = acl->sl_bsize; 250 m_acl->sbz2 = 0; 251 m_acl->ace_count = acl->sl_acecnt; 252 253 return (m_acl); 254 } 255 256 /* 257 * This method converts Security Descriptor from absolute (pointer) to 258 * self relative (flat buffer) format. 259 * 260 * Returns Win32 error codes. 261 */ 262 static uint32_t 263 srvsvc_sd_set_relative(smb_sd_t *sd, uint8_t *sdbuf) 264 { 265 mslm_security_descriptor_t *msd; 266 int offset, len, i; 267 smb_ace_t *ace; 268 mslm_ace_t *m_ace; 269 struct mslm_sid *m_sid; 270 uint16_t ace_cnt; 271 uint32_t status = ERROR_SUCCESS; 272 273 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 274 msd = (mslm_security_descriptor_t *)sdbuf; 275 if (msd == NULL) 276 return (ERROR_INVALID_SECURITY_DESCR); 277 278 msd->revision = sd->sd_revision; 279 msd->sbz1 = 0; 280 msd->control = sd->sd_control | SE_SELF_RELATIVE; 281 282 offset = sizeof (mslm_security_descriptor_t) - SRVSVC_SD_OFFSET_SZ; 283 msd->offset_owner = msd->offset_group = 0; 284 msd->offset_sacl = msd->offset_dacl = 0; 285 286 if (sd->sd_owner != NULL) { 287 msd->offset_owner = offset; 288 289 if (sd->sd_owner == NULL) 290 return (ERROR_NOT_ENOUGH_MEMORY); 291 292 len = smb_sid_len(sd->sd_owner); 293 bcopy(sd->sd_owner, &sdbuf[offset], len); 294 offset += len; 295 } 296 297 if (sd->sd_group != NULL) { 298 msd->offset_group = offset; 299 300 if (sd->sd_group == NULL) 301 return (ERROR_NOT_ENOUGH_MEMORY); 302 303 len = smb_sid_len(sd->sd_group); 304 bcopy(sd->sd_group, &sdbuf[offset], len); 305 offset += len; 306 } 307 308 if (sd->sd_sacl != NULL) { 309 msd->offset_sacl = offset; 310 msd->sacl = srvsvc_acl_set_relative(&sdbuf[offset], 311 sd->sd_sacl); 312 if (msd->sacl == NULL) 313 return (ERROR_INVALID_PARAMETER); 314 315 ace = sd->sd_sacl->sl_aces; 316 ace_cnt = msd->sacl->ace_count; 317 offset += SRVSVC_ACE_OFFSET; 318 319 for (i = 0; i < ace_cnt; i++, ace++) { 320 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 321 m_ace = (mslm_ace_t *)&sdbuf[offset]; 322 offset += SRVSVC_SID_OFFSET; 323 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 324 m_sid = (struct mslm_sid *)&sdbuf[offset]; 325 326 status = srvsvc_ace_set_relative(m_ace, m_sid, ace); 327 if (status != ERROR_SUCCESS) 328 return (status); 329 offset += smb_sid_len(ace->se_sid); 330 } 331 } 332 333 if (sd->sd_dacl != NULL) { 334 msd->offset_dacl = offset; 335 msd->dacl = srvsvc_acl_set_relative(&sdbuf[offset], 336 sd->sd_dacl); 337 if (msd->dacl == NULL) 338 return (ERROR_INVALID_PARAMETER); 339 340 ace = sd->sd_dacl->sl_aces; 341 ace_cnt = msd->dacl->ace_count; 342 offset += SRVSVC_ACE_OFFSET; 343 344 for (i = 0; i < ace_cnt; i++, ace++) { 345 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 346 m_ace = (mslm_ace_t *)&sdbuf[offset]; 347 offset += SRVSVC_SID_OFFSET; 348 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 349 m_sid = (struct mslm_sid *)&sdbuf[offset]; 350 351 status = srvsvc_ace_set_relative(m_ace, m_sid, ace); 352 if (status != ERROR_SUCCESS) 353 return (status); 354 offset += smb_sid_len(ace->se_sid); 355 } 356 } 357 358 return (status); 359 } 360 361 /* 362 * This method converts an ACE from self relative (flat buffer) to 363 * absolute (pointer) format. 364 * 365 * Returns Win32 error codes. 366 */ 367 static uint32_t 368 srvsvc_ace_set_absolute(mslm_ace_t *m_ace, struct mslm_sid *m_sid, 369 smb_ace_t *ace) 370 { 371 int sid_size = 0; 372 if ((m_ace == NULL) || (ace == NULL) || (m_sid == NULL)) 373 return (ERROR_INVALID_PARAMETER); 374 375 bzero(ace, sizeof (smb_ace_t)); 376 bcopy(&m_ace->header, &ace->se_hdr, sizeof (mslm_ace_hdr_t)); 377 ace->se_mask = m_ace->mask; 378 379 sid_size = smb_sid_len((smb_sid_t *)m_sid); 380 if ((ace->se_sid = malloc(sid_size)) == NULL) 381 return (ERROR_NOT_ENOUGH_MEMORY); 382 bcopy(m_sid, ace->se_sid, sid_size); 383 384 return (ERROR_SUCCESS); 385 } 386 387 /* 388 * This method converts an ACL from self relative (flat buffer) to 389 * absolute (pointer) format. 390 * 391 * Returns an initialized smb_acl_t structure on success. 392 * Returns NULL on failure. 393 */ 394 static smb_acl_t * 395 srvsvc_acl_set_absolute(uint8_t *sdbuf, int *offset) 396 { 397 uint8_t rev; 398 uint16_t sz, ace_cnt; 399 smb_acl_t *acl; 400 401 bcopy(&sdbuf[*offset], &rev, sizeof (uint8_t)); 402 *offset += 2; /* Pad for Sbz1 */ 403 bcopy(&sdbuf[*offset], &sz, sizeof (uint16_t)); 404 *offset += 2; 405 bcopy(&sdbuf[*offset], &ace_cnt, sizeof (uint16_t)); 406 *offset += 4; /* Pad for Sbz2 */ 407 408 acl = smb_acl_alloc(rev, sz, ace_cnt); 409 410 return (acl); 411 } 412 413 /* 414 * This method converts Security Descriptor from self relative (flat buffer) to 415 * absolute (pointer) format. 416 * 417 * Returns Win32 error codes. 418 */ 419 static uint32_t 420 srvsvc_sd_set_absolute(uint8_t *sdbuf, smb_sd_t *sd) 421 { 422 mslm_security_descriptor_t *msd; 423 mslm_ace_t *m_ace; 424 struct mslm_sid *m_sid; 425 smb_ace_t *ace; 426 uint16_t ace_cnt; 427 int offset, i, sid_size; 428 uint32_t status = ERROR_SUCCESS; 429 430 if (sdbuf == NULL) 431 return (ERROR_INVALID_SECURITY_DESCR); 432 433 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 434 msd = (mslm_security_descriptor_t *)sdbuf; 435 436 sd->sd_revision = msd->revision; 437 sd->sd_control = msd->control & (~SE_SELF_RELATIVE); 438 439 if (msd->offset_owner != 0) { 440 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 441 m_sid = (struct mslm_sid *)&sdbuf[msd->offset_owner]; 442 sid_size = smb_sid_len((smb_sid_t *)m_sid); 443 444 if ((sd->sd_owner = malloc(sid_size)) == NULL) 445 return (ERROR_NOT_ENOUGH_MEMORY); 446 bcopy(m_sid, sd->sd_owner, sid_size); 447 } 448 449 if (msd->offset_group != 0) { 450 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 451 m_sid = (struct mslm_sid *)&sdbuf[msd->offset_group]; 452 sid_size = smb_sid_len((smb_sid_t *)m_sid); 453 454 if ((sd->sd_group = malloc(sid_size)) == NULL) 455 return (ERROR_NOT_ENOUGH_MEMORY); 456 bcopy(m_sid, sd->sd_group, sid_size); 457 } 458 459 if (msd->offset_sacl != 0) { 460 offset = msd->offset_sacl; 461 sd->sd_sacl = srvsvc_acl_set_absolute(sdbuf, &offset); 462 if (sd->sd_sacl == NULL) 463 return (ERROR_NOT_ENOUGH_MEMORY); 464 465 ace = sd->sd_sacl->sl_aces; 466 ace_cnt = sd->sd_sacl->sl_acecnt; 467 468 for (i = 0; i < ace_cnt; i++, ace++) { 469 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 470 m_ace = (mslm_ace_t *)&sdbuf[offset]; 471 offset += SRVSVC_SID_OFFSET; 472 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 473 m_sid = (struct mslm_sid *)&sdbuf[offset]; 474 475 status = srvsvc_ace_set_absolute(m_ace, m_sid, ace); 476 if (status != ERROR_SUCCESS) 477 return (status); 478 offset += smb_sid_len(ace->se_sid); 479 } 480 } 481 482 if (msd->offset_dacl != 0) { 483 offset = msd->offset_dacl; 484 sd->sd_dacl = srvsvc_acl_set_absolute(sdbuf, &offset); 485 if (sd->sd_dacl == NULL) 486 return (ERROR_NOT_ENOUGH_MEMORY); 487 488 ace = sd->sd_dacl->sl_aces; 489 ace_cnt = sd->sd_dacl->sl_acecnt; 490 491 for (i = 0; i < ace_cnt; i++, ace++) { 492 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 493 m_ace = (mslm_ace_t *)&sdbuf[offset]; 494 offset += SRVSVC_SID_OFFSET; 495 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 496 m_sid = (struct mslm_sid *)&sdbuf[offset]; 497 498 status = srvsvc_ace_set_absolute(m_ace, m_sid, ace); 499 if (status != ERROR_SUCCESS) 500 return (status); 501 offset += smb_sid_len(ace->se_sid); 502 } 503 } 504 505 return (status); 506 } 507 508 /* 509 * This method maps NT status codes into Win 32 error codes. 510 * This method operates on status codes that are related 511 * to processing of Security Descriptor. 512 */ 513 static uint32_t 514 srvsvc_sd_status_to_error(uint32_t status) 515 { 516 int i; 517 static struct { 518 uint32_t nt_status; 519 uint32_t err_code; 520 } errmap[] = { 521 { NT_STATUS_SUCCESS, ERROR_SUCCESS }, 522 { NT_STATUS_INVALID_ACL, ERROR_INVALID_ACL }, 523 { NT_STATUS_INVALID_SID, ERROR_INVALID_SID }, 524 { NT_STATUS_NONE_MAPPED, ERROR_NONE_MAPPED } 525 }; 526 527 for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) { 528 if (status == errmap[i].nt_status) 529 return (errmap[i].err_code); 530 } 531 532 return (ERROR_INTERNAL_ERROR); 533 } 534