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 }