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