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