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  */
  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 
  33 #include <smbsrv/libsmb.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 }