xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c (revision 9fb67ea305c66b6a297583b9b0db6796b0dfe497)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
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
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.severity = ERROR_SEVERITY_ERROR;
120 		err.status   = NT_STATUS_BUFFER_TOO_SMALL;
121 		err.errcls   = ERRDOS;
122 		err.errcode  = ERROR_INSUFFICIENT_BUFFER;
123 		smbsr_set_error(sr, &err);
124 		smb_sd_term(&sd);
125 		return (SDRC_SUCCESS);
126 	}
127 
128 	smb_encode_sd(xa, &sd, secinfo);
129 	(void) smb_mbc_encodef(&xa->rep_param_mb, "l", sdlen);
130 	smb_sd_term(&sd);
131 	return (SDRC_SUCCESS);
132 }
133 
134 /*
135  * smb_nt_transact_set_security_info
136  *
137  * This command allows the client to change the security descriptor on a
138  * file. All we do here is decode the parameters and the data. The data
139  * is passed directly to smb_nt_set_security_object, with the security
140  * information describing the information to set. There are no response
141  * parameters or data.
142  *
143  *   Client Parameter Block Encoding    Description
144  *   ================================== ==================================
145  *   USHORT Fid;                        FID of target
146  *   USHORT Reserved;                   MBZ
147  *   ULONG SecurityInformation;         Fields of SD that to set
148  *
149  *   Data Block Encoding                Description
150  *   ================================== ==================================
151  *   Data[TotalDataCount]               Security Descriptor information
152  */
153 smb_sdrc_t
154 smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
155 {
156 	smb_sd_t sd;
157 	uint32_t secinfo;
158 	uint32_t status;
159 
160 	if (smb_mbc_decodef(&xa->req_param_mb, "w2.l",
161 	    &sr->smb_fid, &secinfo) != 0) {
162 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
163 		return (SDRC_ERROR);
164 	}
165 
166 	smbsr_lookup_file(sr);
167 	if (sr->fid_ofile == NULL) {
168 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
169 		return (SDRC_ERROR);
170 	}
171 
172 	if ((sr->fid_ofile->f_node == NULL) ||
173 	    (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
174 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 0, 0);
175 		return (SDRC_ERROR);
176 	}
177 
178 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
179 
180 	if (SMB_TREE_IS_READONLY(sr)) {
181 		smbsr_error(sr, NT_STATUS_MEDIA_WRITE_PROTECTED, 0, 0);
182 		return (SDRC_ERROR);
183 	}
184 
185 	if (sr->tid_tree->t_acltype != ACE_T) {
186 		/*
187 		 * If target filesystem doesn't support ACE_T acls then
188 		 * don't process SACL
189 		 */
190 		secinfo &= ~SMB_SACL_SECINFO;
191 	}
192 
193 	if ((secinfo & SMB_ALL_SECINFO) == 0) {
194 		return (NT_STATUS_SUCCESS);
195 	}
196 
197 	status = smb_decode_sd(xa, &sd);
198 	if (status != NT_STATUS_SUCCESS) {
199 		smbsr_error(sr, status, 0, 0);
200 		return (SDRC_ERROR);
201 	}
202 
203 	if (((secinfo & SMB_OWNER_SECINFO) && (sd.sd_owner == NULL)) ||
204 	    ((secinfo & SMB_GROUP_SECINFO) && (sd.sd_group == NULL))) {
205 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
206 		return (SDRC_ERROR);
207 	}
208 
209 	if (!smb_node_is_system(sr->fid_ofile->f_node))
210 		status = smb_sd_write(sr, &sd, secinfo);
211 
212 	smb_sd_term(&sd);
213 	if (status != NT_STATUS_SUCCESS) {
214 		smbsr_error(sr, status, 0, 0);
215 		return (SDRC_ERROR);
216 	}
217 
218 	return (SDRC_SUCCESS);
219 }
220 
221 /*
222  * smb_encode_sd
223  *
224  * Encodes given security descriptor in the reply buffer.
225  */
226 static void
227 smb_encode_sd(struct smb_xa *xa, smb_sd_t *sd, uint32_t secinfo)
228 {
229 	uint32_t offset = SMB_SD_HDRSIZE;
230 
231 	/* encode header */
232 	(void) smb_mbc_encodef(&xa->rep_data_mb, "b.w",
233 	    sd->sd_revision, sd->sd_control | SE_SELF_RELATIVE);
234 
235 	/* owner offset */
236 	if (secinfo & SMB_OWNER_SECINFO) {
237 		ASSERT(sd->sd_owner);
238 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
239 		offset += smb_sid_len(sd->sd_owner);
240 	} else {
241 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
242 	}
243 
244 	/* group offset */
245 	if (secinfo & SMB_GROUP_SECINFO) {
246 		ASSERT(sd->sd_group);
247 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
248 		offset += smb_sid_len(sd->sd_group);
249 	} else {
250 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
251 	}
252 
253 	/* SACL offset */
254 	if ((secinfo & SMB_SACL_SECINFO) && (sd->sd_sacl)) {
255 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
256 		offset += smb_acl_len(sd->sd_sacl);
257 	} else {
258 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
259 	}
260 
261 	/* DACL offset */
262 	if ((secinfo & SMB_DACL_SECINFO) && (sd->sd_dacl))
263 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", offset);
264 	else
265 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
266 
267 	if (secinfo & SMB_OWNER_SECINFO)
268 		smb_encode_sid(xa, sd->sd_owner);
269 
270 	if (secinfo & SMB_GROUP_SECINFO)
271 		smb_encode_sid(xa, sd->sd_group);
272 
273 	if (secinfo & SMB_SACL_SECINFO)
274 		smb_encode_sacl(xa, sd->sd_sacl);
275 
276 	if (secinfo & SMB_DACL_SECINFO)
277 		smb_encode_dacl(xa, sd->sd_dacl);
278 }
279 
280 /*
281  * smb_encode_sid
282  *
283  * Encodes given SID in the reply buffer.
284  */
285 void
286 smb_encode_sid(struct smb_xa *xa, smb_sid_t *sid)
287 {
288 	int i;
289 
290 	(void) smb_mbc_encodef(&xa->rep_data_mb, "bb",
291 	    sid->sid_revision, sid->sid_subauthcnt);
292 
293 	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
294 		(void) smb_mbc_encodef(&xa->rep_data_mb, "b",
295 		    sid->sid_authority[i]);
296 	}
297 
298 	for (i = 0; i < sid->sid_subauthcnt; i++) {
299 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
300 		    sid->sid_subauth[i]);
301 	}
302 }
303 
304 /*
305  * smb_encode_sacl
306  *
307  * Encodes given SACL in the reply buffer.
308  */
309 static void
310 smb_encode_sacl(struct smb_xa *xa, smb_acl_t *acl)
311 {
312 	smb_ace_t *ace;
313 	int i;
314 
315 	if (acl == NULL)
316 		return;
317 
318 	/* encode header */
319 	(void) smb_mbc_encodef(&xa->rep_data_mb, "b.ww2.", acl->sl_revision,
320 	    acl->sl_bsize, acl->sl_acecnt);
321 
322 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
323 		(void) smb_mbc_encodef(&xa->rep_data_mb, "bbwl",
324 		    ace->se_hdr.se_type, ace->se_hdr.se_flags,
325 		    ace->se_hdr.se_bsize, ace->se_mask);
326 
327 		smb_encode_sid(xa, ace->se_sid);
328 	}
329 }
330 
331 /*
332  * smb_encode_dacl
333  *
334  * Encodes given DACL in the reply buffer.
335  */
336 static void
337 smb_encode_dacl(struct smb_xa *xa, smb_acl_t *acl)
338 {
339 	smb_ace_t *ace;
340 
341 	if (acl == NULL)
342 		return;
343 
344 	/* encode header */
345 	(void) smb_mbc_encodef(&xa->rep_data_mb, "b.ww2.", acl->sl_revision,
346 	    acl->sl_bsize, acl->sl_acecnt);
347 
348 	ace = list_head(&acl->sl_sorted);
349 	while (ace) {
350 		(void) smb_mbc_encodef(&xa->rep_data_mb, "bbwl",
351 		    ace->se_hdr.se_type, ace->se_hdr.se_flags,
352 		    ace->se_hdr.se_bsize, ace->se_mask);
353 
354 		smb_encode_sid(xa, ace->se_sid);
355 		ace = list_next(&acl->sl_sorted, ace);
356 	}
357 }
358 
359 /*
360  * smb_decode_sd
361  *
362  * Decodes the security descriptor in the request buffer
363  * and set the fields of 'sd' appropraitely. Upon successful
364  * return, caller must free allocated memories by calling
365  * smb_sd_term().
366  */
367 uint32_t
368 smb_decode_sd(struct smb_xa *xa, smb_sd_t *sd)
369 {
370 	struct mbuf_chain sdbuf;
371 	uint32_t owner_offs;
372 	uint32_t group_offs;
373 	uint32_t sacl_offs;
374 	uint32_t dacl_offs;
375 
376 	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
377 
378 	(void) MBC_SHADOW_CHAIN(&sdbuf, &xa->req_data_mb,
379 	    xa->req_data_mb.chain_offset,
380 	    xa->req_data_mb.max_bytes - xa->req_data_mb.chain_offset);
381 
382 	if (smb_mbc_decodef(&sdbuf, "b.wllll",
383 	    &sd->sd_revision, &sd->sd_control,
384 	    &owner_offs, &group_offs, &sacl_offs, &dacl_offs))
385 		goto decode_error;
386 
387 	sd->sd_control &= ~SE_SELF_RELATIVE;
388 
389 	if (owner_offs != 0) {
390 		if (owner_offs < SMB_SD_HDRSIZE)
391 			goto decode_error;
392 
393 		sd->sd_owner = smb_decode_sid(xa, owner_offs);
394 		if (sd->sd_owner == NULL)
395 			goto decode_error;
396 	}
397 
398 	if (group_offs != 0) {
399 		if (group_offs < SMB_SD_HDRSIZE)
400 			goto decode_error;
401 
402 		sd->sd_group = smb_decode_sid(xa, group_offs);
403 		if (sd->sd_group == NULL)
404 			goto decode_error;
405 	}
406 
407 	if (sacl_offs != 0) {
408 		if ((sd->sd_control & SE_SACL_PRESENT) == 0)
409 			goto decode_error;
410 
411 		if (sacl_offs < SMB_SD_HDRSIZE)
412 			goto decode_error;
413 
414 		sd->sd_sacl = smb_decode_acl(xa, sacl_offs);
415 		if (sd->sd_sacl == NULL)
416 			goto decode_error;
417 	}
418 
419 	if (dacl_offs != 0) {
420 		if ((sd->sd_control & SE_DACL_PRESENT) == 0)
421 			goto decode_error;
422 
423 		if (dacl_offs < SMB_SD_HDRSIZE)
424 			goto decode_error;
425 
426 		sd->sd_dacl = smb_decode_acl(xa, dacl_offs);
427 		if (sd->sd_dacl == NULL)
428 			goto decode_error;
429 	}
430 
431 	return (NT_STATUS_SUCCESS);
432 
433 decode_error:
434 	smb_sd_term(sd);
435 	return (NT_STATUS_INVALID_SECURITY_DESCR);
436 }
437 
438 /*
439  * smb_decode_sid
440  *
441  * Allocates memory and decodes the SID in the request buffer
442  * Upon successful return, caller must free the allocated memory
443  * by calling smb_sid_free()
444  */
445 smb_sid_t *
446 smb_decode_sid(struct smb_xa *xa, uint32_t offset)
447 {
448 	uint8_t revision;
449 	uint8_t subauth_cnt;
450 	struct mbuf_chain sidbuf;
451 	smb_sid_t *sid;
452 	int sidlen;
453 	int bytes_left;
454 	int i;
455 
456 	offset += xa->req_data_mb.chain_offset;
457 	bytes_left = xa->req_data_mb.max_bytes - offset;
458 	if (bytes_left < sizeof (smb_sid_t))
459 		return (NULL);
460 
461 	(void) MBC_SHADOW_CHAIN(&sidbuf, &xa->req_data_mb, offset, bytes_left);
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(struct smb_xa *xa, 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 += xa->req_data_mb.chain_offset;
512 	bytes_left = xa->req_data_mb.max_bytes - offset;
513 	if (bytes_left < SMB_ACL_HDRSIZE)
514 		return (NULL);
515 
516 	(void) MBC_SHADOW_CHAIN(&aclbuf, &xa->req_data_mb, offset, bytes_left);
517 
518 	if (smb_mbc_decodef(&aclbuf, "b.ww2.", &revision, &size, &acecnt))
519 		return (NULL);
520 
521 	if (size == 0)
522 		return (NULL);
523 
524 	acl = smb_acl_alloc(revision, size, acecnt);
525 
526 	sid_offs += SMB_ACL_HDRSIZE;
527 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
528 		if (smb_mbc_decodef(&aclbuf, "bbwl",
529 		    &ace->se_hdr.se_type, &ace->se_hdr.se_flags,
530 		    &ace->se_hdr.se_bsize, &ace->se_mask))
531 			goto decode_error;
532 
533 		sid_offs += SMB_ACE_HDRSIZE + sizeof (ace->se_mask);
534 		ace->se_sid = smb_decode_sid(xa, sid_offs);
535 		if (ace->se_sid == NULL)
536 			goto decode_error;
537 		/* This is SID length plus any paddings between ACEs */
538 		sidlen = ace->se_hdr.se_bsize -
539 		    (SMB_ACE_HDRSIZE + sizeof (ace->se_mask));
540 		aclbuf.chain_offset += sidlen;
541 		sid_offs += sidlen;
542 	}
543 
544 	return (acl);
545 
546 decode_error:
547 	smb_acl_free(acl);
548 	return (NULL);
549 }
550