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 } 551