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
28static void smb_encode_sd(struct smb_xa *, smb_sd_t *, uint32_t);
29static void smb_encode_sacl(struct smb_xa *, smb_acl_t *);
30static void smb_encode_dacl(struct smb_xa *, smb_acl_t *);
31static 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
59smb_sdrc_t
60smb_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 */
152smb_sdrc_t
153smb_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 */
225static void
226smb_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 */
284void
285smb_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 */
308static void
309smb_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 */
335static void
336smb_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 */
366uint32_t
367smb_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
432decode_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 */
444smb_sid_t *
445smb_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
484decode_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 */
496static smb_acl_t *
497smb_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
545decode_error:
546	smb_acl_free(acl);
547	return (NULL);
548}
549