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