xref: /titanic_41/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c (revision 148c5f43199ca0b43fc8e3b643aab11cd66ea327)
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  */
25 
26 #include <smbsrv/smb_kproto.h>
27 
28 static void smb_encode_sd(struct smb_xa *, smb_sd_t *, uint32_t);
29 static void smb_encode_sacl(struct smb_xa *, smb_acl_t *);
30 static void smb_encode_dacl(struct smb_xa *, smb_acl_t *);
31 static smb_acl_t *smb_decode_acl(struct smb_xa *, 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
smb_nt_transact_query_security_info(struct smb_request * sr,struct smb_xa * xa)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, &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
smb_nt_transact_set_security_info(struct smb_request * sr,struct smb_xa * xa)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, &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 static void
smb_encode_sd(struct smb_xa * xa,smb_sd_t * sd,uint32_t secinfo)226 smb_encode_sd(struct smb_xa *xa, smb_sd_t *sd, uint32_t secinfo)
227 {
228 	uint32_t offset = SMB_SD_HDRSIZE;
229 
230 	/* encode header */
231 	(void) smb_mbc_encodef(&xa->rep_data_mb, "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(&xa->rep_data_mb, "l", offset);
238 		offset += smb_sid_len(sd->sd_owner);
239 	} else {
240 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
241 	}
242 
243 	/* group offset */
244 	if (secinfo & SMB_GROUP_SECINFO) {
245 		ASSERT(sd->sd_group);
246 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
247 		offset += smb_sid_len(sd->sd_group);
248 	} else {
249 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
250 	}
251 
252 	/* SACL offset */
253 	if ((secinfo & SMB_SACL_SECINFO) && (sd->sd_sacl)) {
254 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
255 		offset += smb_acl_len(sd->sd_sacl);
256 	} else {
257 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
258 	}
259 
260 	/* DACL offset */
261 	if ((secinfo & SMB_DACL_SECINFO) && (sd->sd_dacl))
262 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
263 	else
264 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
265 
266 	if (secinfo & SMB_OWNER_SECINFO)
267 		smb_encode_sid(xa, sd->sd_owner);
268 
269 	if (secinfo & SMB_GROUP_SECINFO)
270 		smb_encode_sid(xa, sd->sd_group);
271 
272 	if (secinfo & SMB_SACL_SECINFO)
273 		smb_encode_sacl(xa, sd->sd_sacl);
274 
275 	if (secinfo & SMB_DACL_SECINFO)
276 		smb_encode_dacl(xa, sd->sd_dacl);
277 }
278 
279 /*
280  * smb_encode_sid
281  *
282  * Encodes given SID in the reply buffer.
283  */
284 void
smb_encode_sid(struct smb_xa * xa,smb_sid_t * sid)285 smb_encode_sid(struct smb_xa *xa, smb_sid_t *sid)
286 {
287 	int i;
288 
289 	(void) smb_mbc_encodef(&xa->rep_data_mb, "bb",
290 	    sid->sid_revision, sid->sid_subauthcnt);
291 
292 	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
293 		(void) smb_mbc_encodef(&xa->rep_data_mb, "b",
294 		    sid->sid_authority[i]);
295 	}
296 
297 	for (i = 0; i < sid->sid_subauthcnt; i++) {
298 		(void) smb_mbc_encodef(&xa->rep_data_mb, "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
smb_encode_sacl(struct smb_xa * xa,smb_acl_t * acl)309 smb_encode_sacl(struct smb_xa *xa, 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(&xa->rep_data_mb, "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(&xa->rep_data_mb, "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(xa, ace->se_sid);
327 	}
328 }
329 
330 /*
331  * smb_encode_dacl
332  *
333  * Encodes given DACL in the reply buffer.
334  */
335 static void
smb_encode_dacl(struct smb_xa * xa,smb_acl_t * acl)336 smb_encode_dacl(struct smb_xa *xa, 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(&xa->rep_data_mb, "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(&xa->rep_data_mb, "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(xa, 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
smb_decode_sd(struct smb_xa * xa,smb_sd_t * sd)367 smb_decode_sd(struct smb_xa *xa, 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, &xa->req_data_mb,
378 	    xa->req_data_mb.chain_offset,
379 	    xa->req_data_mb.max_bytes - xa->req_data_mb.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(xa, 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(xa, 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(xa, 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(xa, 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 *
smb_decode_sid(struct smb_xa * xa,uint32_t offset)445 smb_decode_sid(struct smb_xa *xa, 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 += xa->req_data_mb.chain_offset;
456 	bytes_left = xa->req_data_mb.max_bytes - offset;
457 	if (bytes_left < sizeof (smb_sid_t))
458 		return (NULL);
459 
460 	(void) MBC_SHADOW_CHAIN(&sidbuf, &xa->req_data_mb, offset, bytes_left);
461 
462 	if (smb_mbc_decodef(&sidbuf, "bb", &revision, &subauth_cnt))
463 		return (NULL);
464 
465 	sidlen = sizeof (smb_sid_t) - sizeof (uint32_t) +
466 	    (subauth_cnt * sizeof (uint32_t));
467 	sid = kmem_alloc(sidlen, KM_SLEEP);
468 
469 	sid->sid_revision = revision;
470 	sid->sid_subauthcnt = subauth_cnt;
471 
472 	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
473 		if (smb_mbc_decodef(&sidbuf, "b", &sid->sid_authority[i]))
474 			goto decode_err;
475 	}
476 
477 	for (i = 0; i < sid->sid_subauthcnt; i++) {
478 		if (smb_mbc_decodef(&sidbuf, "l", &sid->sid_subauth[i]))
479 			goto decode_err;
480 	}
481 
482 	return (sid);
483 
484 decode_err:
485 	kmem_free(sid, sidlen);
486 	return (NULL);
487 }
488 
489 /*
490  * smb_decode_acl
491  *
492  * Allocates memory and decodes the ACL in the request buffer
493  * Upon successful return, caller must free the allocated memory
494  * by calling smb_acl_free().
495  */
496 static smb_acl_t *
smb_decode_acl(struct smb_xa * xa,uint32_t offset)497 smb_decode_acl(struct smb_xa *xa, uint32_t offset)
498 {
499 	struct mbuf_chain aclbuf;
500 	smb_acl_t *acl;
501 	smb_ace_t *ace;
502 	uint8_t revision;
503 	uint16_t size;
504 	uint16_t acecnt;
505 	int bytes_left;
506 	uint32_t sid_offs = offset;
507 	int sidlen;
508 	int i;
509 
510 	offset += xa->req_data_mb.chain_offset;
511 	bytes_left = xa->req_data_mb.max_bytes - offset;
512 	if (bytes_left < SMB_ACL_HDRSIZE)
513 		return (NULL);
514 
515 	(void) MBC_SHADOW_CHAIN(&aclbuf, &xa->req_data_mb, offset, bytes_left);
516 
517 	if (smb_mbc_decodef(&aclbuf, "b.ww2.", &revision, &size, &acecnt))
518 		return (NULL);
519 
520 	if (size == 0)
521 		return (NULL);
522 
523 	acl = smb_acl_alloc(revision, size, acecnt);
524 
525 	sid_offs += SMB_ACL_HDRSIZE;
526 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
527 		if (smb_mbc_decodef(&aclbuf, "bbwl",
528 		    &ace->se_hdr.se_type, &ace->se_hdr.se_flags,
529 		    &ace->se_hdr.se_bsize, &ace->se_mask))
530 			goto decode_error;
531 
532 		sid_offs += SMB_ACE_HDRSIZE + sizeof (ace->se_mask);
533 		ace->se_sid = smb_decode_sid(xa, sid_offs);
534 		if (ace->se_sid == NULL)
535 			goto decode_error;
536 		/* This is SID length plus any paddings between ACEs */
537 		sidlen = ace->se_hdr.se_bsize -
538 		    (SMB_ACE_HDRSIZE + sizeof (ace->se_mask));
539 		aclbuf.chain_offset += sidlen;
540 		sid_offs += sidlen;
541 	}
542 
543 	return (acl);
544 
545 decode_error:
546 	smb_acl_free(acl);
547 	return (NULL);
548 }
549