xref: /titanic_51/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c (revision a90cf9f29973990687fa61de9f1f6ea22e924e40)
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