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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 #include <smbsrv/smb_kproto.h>
  28 
  29 static void smb_encode_sacl(mbuf_chain_t *, smb_acl_t *);
  30 static void smb_encode_dacl(mbuf_chain_t *, smb_acl_t *);
  31 static smb_acl_t *smb_decode_acl(mbuf_chain_t *, uint32_t);
  32 
  33 /*
  34  * smb_nt_transact_query_security_info
  35  *
  36  * This command allows the client to retrieve the security descriptor
  37  * on a file. The result of the call is returned to the client in the
  38  * Data part of the transaction response.
  39  *
  40  * Some clients specify a non-zero maximum data return size (mdrcnt)
  41  * for the SD and some specify zero. In either case, if the mdrcnt is
  42  * too small we need to return NT_STATUS_BUFFER_TOO_SMALL and a buffer
  43  * size hint. The client should then retry with the appropriate buffer
  44  * size.
  45  *
  46  *  Client Parameter Block             Description
  47  *  ================================== =================================
  48  *
  49  *  USHORT Fid;                        FID of target
  50  *  USHORT Reserved;                   MBZ
  51  *  ULONG secinfo;                     Fields of descriptor to set
  52  *
  53  *   Data Block Encoding                Description
  54  *   ================================== ==================================
  55  *
  56  *   Data[TotalDataCount]               Security Descriptor information
  57  */
  58 
  59 smb_sdrc_t
  60 smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
  61 {
  62         smb_sd_t sd;
  63         uint32_t secinfo;
  64         uint32_t sdlen;
  65         uint32_t status;
  66         smb_error_t err;
  67 
  68         if (smb_mbc_decodef(&xa->req_param_mb, "w2.l",
  69             &sr->smb_fid, &secinfo) != 0) {
  70                 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
  71                 return (SDRC_ERROR);
  72         }
  73 
  74         smbsr_lookup_file(sr);
  75         if (sr->fid_ofile == NULL) {
  76                 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
  77                 return (SDRC_ERROR);
  78         }
  79 
  80 
  81         if ((sr->fid_ofile->f_node == NULL) ||
  82             (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
  83                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
  84                     ERRDOS, ERROR_ACCESS_DENIED);
  85                 return (SDRC_ERROR);
  86         }
  87 
  88         sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
  89 
  90         if (sr->tid_tree->t_acltype != ACE_T) {
  91                 /*
  92                  * If target filesystem doesn't support ACE_T acls then
  93                  * don't process SACL
  94                  */
  95                 secinfo &= ~SMB_SACL_SECINFO;
  96         }
  97 
  98         status = smb_sd_read(sr, &sd, secinfo);
  99         if (status != NT_STATUS_SUCCESS) {
 100                 smbsr_error(sr, status, 0, 0);
 101                 return (SDRC_ERROR);
 102         }
 103 
 104         sdlen = smb_sd_len(&sd, secinfo);
 105         if (sdlen == 0) {
 106                 smb_sd_term(&sd);
 107                 smbsr_error(sr, NT_STATUS_INVALID_SECURITY_DESCR, 0, 0);
 108                 return (SDRC_ERROR);
 109         }
 110 
 111         if (sdlen > xa->smb_mdrcnt) {
 112                 /*
 113                  * The maximum data return count specified by the
 114                  * client is not big enough to hold the security
 115                  * descriptor. We have to return an error but we
 116                  * should provide a buffer size hint for the client.
 117                  */
 118                 (void) smb_mbc_encodef(&xa->rep_param_mb, "l", sdlen);
 119                 err.status   = NT_STATUS_BUFFER_TOO_SMALL;
 120                 err.errcls   = ERRDOS;
 121                 err.errcode  = ERROR_INSUFFICIENT_BUFFER;
 122                 smbsr_set_error(sr, &err);
 123                 smb_sd_term(&sd);
 124                 return (SDRC_SUCCESS);
 125         }
 126 
 127         smb_encode_sd(&xa->rep_data_mb, &sd, secinfo);
 128         (void) smb_mbc_encodef(&xa->rep_param_mb, "l", sdlen);
 129         smb_sd_term(&sd);
 130         return (SDRC_SUCCESS);
 131 }
 132 
 133 /*
 134  * smb_nt_transact_set_security_info
 135  *
 136  * This command allows the client to change the security descriptor on a
 137  * file. All we do here is decode the parameters and the data. The data
 138  * is passed directly to smb_nt_set_security_object, with the security
 139  * information describing the information to set. There are no response
 140  * parameters or data.
 141  *
 142  *   Client Parameter Block Encoding    Description
 143  *   ================================== ==================================
 144  *   USHORT Fid;                        FID of target
 145  *   USHORT Reserved;                   MBZ
 146  *   ULONG SecurityInformation;         Fields of SD that to set
 147  *
 148  *   Data Block Encoding                Description
 149  *   ================================== ==================================
 150  *   Data[TotalDataCount]               Security Descriptor information
 151  */
 152 smb_sdrc_t
 153 smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
 154 {
 155         smb_sd_t sd;
 156         uint32_t secinfo;
 157         uint32_t status;
 158 
 159         if (smb_mbc_decodef(&xa->req_param_mb, "w2.l",
 160             &sr->smb_fid, &secinfo) != 0) {
 161                 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
 162                 return (SDRC_ERROR);
 163         }
 164 
 165         smbsr_lookup_file(sr);
 166         if (sr->fid_ofile == NULL) {
 167                 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
 168                 return (SDRC_ERROR);
 169         }
 170 
 171         if ((sr->fid_ofile->f_node == NULL) ||
 172             (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
 173                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 0, 0);
 174                 return (SDRC_ERROR);
 175         }
 176 
 177         sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
 178 
 179         if (SMB_TREE_IS_READONLY(sr)) {
 180                 smbsr_error(sr, NT_STATUS_MEDIA_WRITE_PROTECTED, 0, 0);
 181                 return (SDRC_ERROR);
 182         }
 183 
 184         if (sr->tid_tree->t_acltype != ACE_T) {
 185                 /*
 186                  * If target filesystem doesn't support ACE_T acls then
 187                  * don't process SACL
 188                  */
 189                 secinfo &= ~SMB_SACL_SECINFO;
 190         }
 191 
 192         if ((secinfo & SMB_ALL_SECINFO) == 0) {
 193                 return (NT_STATUS_SUCCESS);
 194         }
 195 
 196         status = smb_decode_sd(&xa->req_data_mb, &sd);
 197         if (status != NT_STATUS_SUCCESS) {
 198                 smbsr_error(sr, status, 0, 0);
 199                 return (SDRC_ERROR);
 200         }
 201 
 202         if (((secinfo & SMB_OWNER_SECINFO) && (sd.sd_owner == NULL)) ||
 203             ((secinfo & SMB_GROUP_SECINFO) && (sd.sd_group == NULL))) {
 204                 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
 205                 return (SDRC_ERROR);
 206         }
 207 
 208         if (!smb_node_is_system(sr->fid_ofile->f_node))
 209                 status = smb_sd_write(sr, &sd, secinfo);
 210 
 211         smb_sd_term(&sd);
 212         if (status != NT_STATUS_SUCCESS) {
 213                 smbsr_error(sr, status, 0, 0);
 214                 return (SDRC_ERROR);
 215         }
 216 
 217         return (SDRC_SUCCESS);
 218 }
 219 
 220 /*
 221  * smb_encode_sd
 222  *
 223  * Encodes given security descriptor in the reply buffer.
 224  */
 225 void
 226 smb_encode_sd(mbuf_chain_t *mbc, smb_sd_t *sd, uint32_t secinfo)
 227 {
 228         uint32_t offset = SMB_SD_HDRSIZE;
 229 
 230         /* encode header */
 231         (void) smb_mbc_encodef(mbc, "b.w",
 232             sd->sd_revision, sd->sd_control | SE_SELF_RELATIVE);
 233 
 234         /* owner offset */
 235         if (secinfo & SMB_OWNER_SECINFO) {
 236                 ASSERT(sd->sd_owner);
 237                 (void) smb_mbc_encodef(mbc, "l", offset);
 238                 offset += smb_sid_len(sd->sd_owner);
 239         } else {
 240                 (void) smb_mbc_encodef(mbc, "l", 0);
 241         }
 242 
 243         /* group offset */
 244         if (secinfo & SMB_GROUP_SECINFO) {
 245                 ASSERT(sd->sd_group);
 246                 (void) smb_mbc_encodef(mbc, "l", offset);
 247                 offset += smb_sid_len(sd->sd_group);
 248         } else {
 249                 (void) smb_mbc_encodef(mbc, "l", 0);
 250         }
 251 
 252         /* SACL offset */
 253         if ((secinfo & SMB_SACL_SECINFO) && (sd->sd_sacl)) {
 254                 (void) smb_mbc_encodef(mbc, "l", offset);
 255                 offset += smb_acl_len(sd->sd_sacl);
 256         } else {
 257                 (void) smb_mbc_encodef(mbc, "l", 0);
 258         }
 259 
 260         /* DACL offset */
 261         if ((secinfo & SMB_DACL_SECINFO) && (sd->sd_dacl))
 262                 (void) smb_mbc_encodef(mbc, "l", offset);
 263         else
 264                 (void) smb_mbc_encodef(mbc, "l", 0);
 265 
 266         if (secinfo & SMB_OWNER_SECINFO)
 267                 smb_encode_sid(mbc, sd->sd_owner);
 268 
 269         if (secinfo & SMB_GROUP_SECINFO)
 270                 smb_encode_sid(mbc, sd->sd_group);
 271 
 272         if (secinfo & SMB_SACL_SECINFO)
 273                 smb_encode_sacl(mbc, sd->sd_sacl);
 274 
 275         if (secinfo & SMB_DACL_SECINFO)
 276                 smb_encode_dacl(mbc, sd->sd_dacl);
 277 }
 278 
 279 /*
 280  * smb_encode_sid
 281  *
 282  * Encodes given SID in the reply buffer.
 283  */
 284 void
 285 smb_encode_sid(mbuf_chain_t *mbc, smb_sid_t *sid)
 286 {
 287         int i;
 288 
 289         (void) smb_mbc_encodef(mbc, "bb",
 290             sid->sid_revision, sid->sid_subauthcnt);
 291 
 292         for (i = 0; i < NT_SID_AUTH_MAX; i++) {
 293                 (void) smb_mbc_encodef(mbc, "b",
 294                     sid->sid_authority[i]);
 295         }
 296 
 297         for (i = 0; i < sid->sid_subauthcnt; i++) {
 298                 (void) smb_mbc_encodef(mbc, "l",
 299                     sid->sid_subauth[i]);
 300         }
 301 }
 302 
 303 /*
 304  * smb_encode_sacl
 305  *
 306  * Encodes given SACL in the reply buffer.
 307  */
 308 static void
 309 smb_encode_sacl(mbuf_chain_t *mbc, smb_acl_t *acl)
 310 {
 311         smb_ace_t *ace;
 312         int i;
 313 
 314         if (acl == NULL)
 315                 return;
 316 
 317         /* encode header */
 318         (void) smb_mbc_encodef(mbc, "b.ww2.", acl->sl_revision,
 319             acl->sl_bsize, acl->sl_acecnt);
 320 
 321         for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
 322                 (void) smb_mbc_encodef(mbc, "bbwl",
 323                     ace->se_hdr.se_type, ace->se_hdr.se_flags,
 324                     ace->se_hdr.se_bsize, ace->se_mask);
 325 
 326                 smb_encode_sid(mbc, ace->se_sid);
 327         }
 328 }
 329 
 330 /*
 331  * smb_encode_dacl
 332  *
 333  * Encodes given DACL in the reply buffer.
 334  */
 335 static void
 336 smb_encode_dacl(mbuf_chain_t *mbc, smb_acl_t *acl)
 337 {
 338         smb_ace_t *ace;
 339 
 340         if (acl == NULL)
 341                 return;
 342 
 343         /* encode header */
 344         (void) smb_mbc_encodef(mbc, "b.ww2.", acl->sl_revision,
 345             acl->sl_bsize, acl->sl_acecnt);
 346 
 347         ace = list_head(&acl->sl_sorted);
 348         while (ace) {
 349                 (void) smb_mbc_encodef(mbc, "bbwl",
 350                     ace->se_hdr.se_type, ace->se_hdr.se_flags,
 351                     ace->se_hdr.se_bsize, ace->se_mask);
 352 
 353                 smb_encode_sid(mbc, ace->se_sid);
 354                 ace = list_next(&acl->sl_sorted, ace);
 355         }
 356 }
 357 
 358 /*
 359  * smb_decode_sd
 360  *
 361  * Decodes the security descriptor in the request buffer
 362  * and set the fields of 'sd' appropraitely. Upon successful
 363  * return, caller must free allocated memories by calling
 364  * smb_sd_term().
 365  */
 366 uint32_t
 367 smb_decode_sd(mbuf_chain_t *mbc, smb_sd_t *sd)
 368 {
 369         struct mbuf_chain sdbuf;
 370         uint32_t owner_offs;
 371         uint32_t group_offs;
 372         uint32_t sacl_offs;
 373         uint32_t dacl_offs;
 374 
 375         smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
 376 
 377         (void) MBC_SHADOW_CHAIN(&sdbuf, mbc,
 378             mbc->chain_offset,
 379             mbc->max_bytes - mbc->chain_offset);
 380 
 381         if (smb_mbc_decodef(&sdbuf, "b.wllll",
 382             &sd->sd_revision, &sd->sd_control,
 383             &owner_offs, &group_offs, &sacl_offs, &dacl_offs))
 384                 goto decode_error;
 385 
 386         sd->sd_control &= ~SE_SELF_RELATIVE;
 387 
 388         if (owner_offs != 0) {
 389                 if (owner_offs < SMB_SD_HDRSIZE)
 390                         goto decode_error;
 391 
 392                 sd->sd_owner = smb_decode_sid(mbc, owner_offs);
 393                 if (sd->sd_owner == NULL)
 394                         goto decode_error;
 395         }
 396 
 397         if (group_offs != 0) {
 398                 if (group_offs < SMB_SD_HDRSIZE)
 399                         goto decode_error;
 400 
 401                 sd->sd_group = smb_decode_sid(mbc, group_offs);
 402                 if (sd->sd_group == NULL)
 403                         goto decode_error;
 404         }
 405 
 406         if (sacl_offs != 0) {
 407                 if ((sd->sd_control & SE_SACL_PRESENT) == 0)
 408                         goto decode_error;
 409 
 410                 if (sacl_offs < SMB_SD_HDRSIZE)
 411                         goto decode_error;
 412 
 413                 sd->sd_sacl = smb_decode_acl(mbc, sacl_offs);
 414                 if (sd->sd_sacl == NULL)
 415                         goto decode_error;
 416         }
 417 
 418         if (dacl_offs != 0) {
 419                 if ((sd->sd_control & SE_DACL_PRESENT) == 0)
 420                         goto decode_error;
 421 
 422                 if (dacl_offs < SMB_SD_HDRSIZE)
 423                         goto decode_error;
 424 
 425                 sd->sd_dacl = smb_decode_acl(mbc, dacl_offs);
 426                 if (sd->sd_dacl == NULL)
 427                         goto decode_error;
 428         }
 429 
 430         return (NT_STATUS_SUCCESS);
 431 
 432 decode_error:
 433         smb_sd_term(sd);
 434         return (NT_STATUS_INVALID_SECURITY_DESCR);
 435 }
 436 
 437 /*
 438  * smb_decode_sid
 439  *
 440  * Allocates memory and decodes the SID in the request buffer
 441  * Upon successful return, caller must free the allocated memory
 442  * by calling smb_sid_free()
 443  */
 444 smb_sid_t *
 445 smb_decode_sid(mbuf_chain_t *mbc, uint32_t offset)
 446 {
 447         uint8_t revision;
 448         uint8_t subauth_cnt;
 449         struct mbuf_chain sidbuf;
 450         smb_sid_t *sid;
 451         int sidlen;
 452         int bytes_left;
 453         int i;
 454 
 455         offset += mbc->chain_offset;
 456         bytes_left = mbc->max_bytes - offset;
 457         if (bytes_left < (int)sizeof (smb_sid_t))
 458                 return (NULL);
 459 
 460         if (MBC_SHADOW_CHAIN(&sidbuf, mbc, offset, bytes_left) != 0)
 461                 return (NULL);
 462 
 463         if (smb_mbc_decodef(&sidbuf, "bb", &revision, &subauth_cnt))
 464                 return (NULL);
 465 
 466         sidlen = sizeof (smb_sid_t) - sizeof (uint32_t) +
 467             (subauth_cnt * sizeof (uint32_t));
 468         sid = kmem_alloc(sidlen, KM_SLEEP);
 469 
 470         sid->sid_revision = revision;
 471         sid->sid_subauthcnt = subauth_cnt;
 472 
 473         for (i = 0; i < NT_SID_AUTH_MAX; i++) {
 474                 if (smb_mbc_decodef(&sidbuf, "b", &sid->sid_authority[i]))
 475                         goto decode_err;
 476         }
 477 
 478         for (i = 0; i < sid->sid_subauthcnt; i++) {
 479                 if (smb_mbc_decodef(&sidbuf, "l", &sid->sid_subauth[i]))
 480                         goto decode_err;
 481         }
 482 
 483         return (sid);
 484 
 485 decode_err:
 486         kmem_free(sid, sidlen);
 487         return (NULL);
 488 }
 489 
 490 /*
 491  * smb_decode_acl
 492  *
 493  * Allocates memory and decodes the ACL in the request buffer
 494  * Upon successful return, caller must free the allocated memory
 495  * by calling smb_acl_free().
 496  */
 497 static smb_acl_t *
 498 smb_decode_acl(mbuf_chain_t *mbc, uint32_t offset)
 499 {
 500         struct mbuf_chain aclbuf;
 501         smb_acl_t *acl;
 502         smb_ace_t *ace;
 503         uint8_t revision;
 504         uint16_t size;
 505         uint16_t acecnt;
 506         int bytes_left;
 507         uint32_t sid_offs = offset;
 508         int sidlen;
 509         int i;
 510 
 511         offset += mbc->chain_offset;
 512         bytes_left = mbc->max_bytes - offset;
 513         if (bytes_left < SMB_ACL_HDRSIZE)
 514                 return (NULL);
 515 
 516         if (MBC_SHADOW_CHAIN(&aclbuf, mbc, offset, bytes_left) != 0)
 517                 return (NULL);
 518 
 519         if (smb_mbc_decodef(&aclbuf, "b.ww2.", &revision, &size, &acecnt))
 520                 return (NULL);
 521 
 522         if (size == 0)
 523                 return (NULL);
 524 
 525         acl = smb_acl_alloc(revision, size, acecnt);
 526 
 527         sid_offs += SMB_ACL_HDRSIZE;
 528         for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
 529                 if (smb_mbc_decodef(&aclbuf, "bbwl",
 530                     &ace->se_hdr.se_type, &ace->se_hdr.se_flags,
 531                     &ace->se_hdr.se_bsize, &ace->se_mask))
 532                         goto decode_error;
 533 
 534                 sid_offs += SMB_ACE_HDRSIZE + sizeof (ace->se_mask);
 535                 ace->se_sid = smb_decode_sid(mbc, sid_offs);
 536                 if (ace->se_sid == NULL)
 537                         goto decode_error;
 538                 /* This is SID length plus any paddings between ACEs */
 539                 sidlen = ace->se_hdr.se_bsize -
 540                     (SMB_ACE_HDRSIZE + sizeof (ace->se_mask));
 541                 aclbuf.chain_offset += sidlen;
 542                 sid_offs += sidlen;
 543         }
 544 
 545         return (acl);
 546 
 547 decode_error:
 548         smb_acl_free(acl);
 549         return (NULL);
 550 }