smb_nt_transact_security.c revision 6432:98715880dd9e
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 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <smbsrv/smb_kproto.h>
29#include <smbsrv/ntstatus.h>
30#include <smbsrv/nterror.h>
31#include <smbsrv/doserror.h>
32#include <smbsrv/cifs.h>
33
34static void smb_encode_sd(struct smb_xa *, smb_sd_t *, uint32_t);
35static void smb_encode_sid(struct smb_xa *, smb_sid_t *);
36static void smb_encode_sacl(struct smb_xa *, smb_acl_t *);
37static void smb_encode_dacl(struct smb_xa *, smb_acl_t *);
38
39uint32_t smb_decode_sd(struct smb_xa *, smb_sd_t *);
40static smb_sid_t *smb_decode_sid(struct smb_xa *, uint32_t);
41static smb_acl_t *smb_decode_acl(struct smb_xa *, uint32_t);
42
43/*
44 * smb_nt_transact_query_security_info
45 *
46 * This command allows the client to retrieve the security descriptor
47 * on a file. The result of the call is returned to the client in the
48 * Data part of the transaction response.
49 *
50 * Some clients specify a non-zero maximum data return size (mdrcnt)
51 * for the SD and some specify zero. In either case, if the mdrcnt is
52 * too small we need to return NT_STATUS_BUFFER_TOO_SMALL and a buffer
53 * size hint. The client should then retry with the appropriate buffer
54 * size.
55 *
56 *  Client Parameter Block             Description
57 *  ================================== =================================
58 *
59 *  USHORT Fid;                        FID of target
60 *  USHORT Reserved;                   MBZ
61 *  ULONG secinfo;                     Fields of descriptor to set
62 *
63 *   Data Block Encoding                Description
64 *   ================================== ==================================
65 *
66 *   Data[TotalDataCount]               Security Descriptor information
67 */
68
69smb_sdrc_t
70smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
71{
72	smb_sd_t sd;
73	uint32_t secinfo;
74	uint32_t sdlen;
75	uint32_t status;
76	smb_error_t err;
77
78	if (smb_decode_mbc(&xa->req_param_mb, "w2.l",
79	    &sr->smb_fid, &secinfo) != 0) {
80		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
81		return (SDRC_ERROR);
82	}
83
84	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
85	if (sr->fid_ofile == NULL) {
86		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
87		return (SDRC_ERROR);
88	}
89
90
91	if ((sr->fid_ofile->f_node == NULL) ||
92	    (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
93		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
94		    ERRDOS, ERROR_ACCESS_DENIED);
95		return (SDRC_ERROR);
96	}
97
98	if (sr->tid_tree->t_acltype != ACE_T) {
99		/*
100		 * If target filesystem doesn't support ACE_T acls then
101		 * don't process SACL
102		 */
103		secinfo &= ~SMB_SACL_SECINFO;
104	}
105
106	status = smb_sd_read(sr, &sd, secinfo);
107	if (status != NT_STATUS_SUCCESS) {
108		smbsr_error(sr, status, 0, 0);
109		return (SDRC_ERROR);
110	}
111
112	sdlen = smb_sd_len(&sd, secinfo);
113	if (sdlen == 0) {
114		smb_sd_term(&sd);
115		smbsr_error(sr, NT_STATUS_INVALID_SECURITY_DESCR, 0, 0);
116		return (SDRC_ERROR);
117	}
118
119	if (sdlen > xa->smb_mdrcnt) {
120		/*
121		 * The maximum data return count specified by the
122		 * client is not big enough to hold the security
123		 * descriptor. We have to return an error but we
124		 * should provide a buffer size hint for the client.
125		 */
126		(void) smb_encode_mbc(&xa->rep_param_mb, "l", sdlen);
127		err.severity = ERROR_SEVERITY_ERROR;
128		err.status   = NT_STATUS_BUFFER_TOO_SMALL;
129		err.errcls   = ERRDOS;
130		err.errcode  = ERROR_INSUFFICIENT_BUFFER;
131		smbsr_set_error(sr, &err);
132		smb_sd_term(&sd);
133		return (SDRC_SUCCESS);
134	}
135
136	smb_encode_sd(xa, &sd, secinfo);
137	(void) smb_encode_mbc(&xa->rep_param_mb, "l", sdlen);
138	smb_sd_term(&sd);
139	return (SDRC_SUCCESS);
140}
141
142/*
143 * smb_nt_transact_set_security_info
144 *
145 * This command allows the client to change the security descriptor on a
146 * file. All we do here is decode the parameters and the data. The data
147 * is passed directly to smb_nt_set_security_object, with the security
148 * information describing the information to set. There are no response
149 * parameters or data.
150 *
151 *   Client Parameter Block Encoding    Description
152 *   ================================== ==================================
153 *   USHORT Fid;                        FID of target
154 *   USHORT Reserved;                   MBZ
155 *   ULONG SecurityInformation;         Fields of SD that to set
156 *
157 *   Data Block Encoding                Description
158 *   ================================== ==================================
159 *   Data[TotalDataCount]               Security Descriptor information
160 */
161smb_sdrc_t
162smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
163{
164	smb_sd_t sd;
165	uint32_t secinfo;
166	uint32_t status;
167
168	if (smb_decode_mbc(&xa->req_param_mb, "w2.l",
169	    &sr->smb_fid, &secinfo) != 0) {
170		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
171		return (SDRC_ERROR);
172	}
173
174	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
175	if (sr->fid_ofile == NULL) {
176		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
177		return (SDRC_ERROR);
178	}
179
180	if ((sr->fid_ofile->f_node == NULL) ||
181	    (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
182		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 0, 0);
183		return (SDRC_ERROR);
184	}
185
186	if (sr->fid_ofile->f_node->flags & NODE_READ_ONLY) {
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 */
230static void
231smb_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_encode_mbc(&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_encode_mbc(&xa->rep_data_mb, "l", offset);
243		offset += smb_sid_len(sd->sd_owner);
244	} else {
245		(void) smb_encode_mbc(&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_encode_mbc(&xa->rep_data_mb, "l", offset);
252		offset += smb_sid_len(sd->sd_group);
253	} else {
254		(void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
255	}
256
257	/* SACL offset */
258	if ((secinfo & SMB_SACL_SECINFO) && (sd->sd_sacl)) {
259		(void) smb_encode_mbc(&xa->rep_data_mb, "l", offset);
260		offset += smb_acl_len(sd->sd_sacl);
261	} else {
262		(void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
263	}
264
265	/* DACL offset */
266	if ((secinfo & SMB_DACL_SECINFO) && (sd->sd_dacl))
267		(void) smb_encode_mbc(&xa->rep_data_mb, "l", offset);
268	else
269		(void) smb_encode_mbc(&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 */
289static void
290smb_encode_sid(struct smb_xa *xa, smb_sid_t *sid)
291{
292	int i;
293
294	(void) smb_encode_mbc(&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_encode_mbc(&xa->rep_data_mb, "b",
299		    sid->sid_authority[i]);
300	}
301
302	for (i = 0; i < sid->sid_subauthcnt; i++) {
303		(void) smb_encode_mbc(&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 */
313static void
314smb_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_encode_mbc(&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_encode_mbc(&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 */
340static void
341smb_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_encode_mbc(&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_encode_mbc(&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 */
371uint32_t
372smb_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_decode_mbc(&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
437decode_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 */
449static smb_sid_t *
450smb_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_decode_mbc(&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_decode_mbc(&sidbuf, "b", &sid->sid_authority[i]))
479			goto decode_err;
480	}
481
482	for (i = 0; i < sid->sid_subauthcnt; i++) {
483		if (smb_decode_mbc(&sidbuf, "l", &sid->sid_subauth[i]))
484			goto decode_err;
485	}
486
487	return (sid);
488
489decode_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 */
501static smb_acl_t *
502smb_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_decode_mbc(&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_decode_mbc(&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		sidlen = smb_sid_len(ace->se_sid);
542		aclbuf.chain_offset += sidlen;
543		sid_offs += sidlen;
544	}
545
546	return (acl);
547
548decode_error:
549	smb_acl_free(acl);
550	return (NULL);
551}
552