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