xref: /titanic_41/usr/src/uts/common/fs/smbsrv/smb_sd.c (revision ac19272f7eb4a433cfccf2fdccc769cca5528169)
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 2007 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 /*
29  * This module provides Security Descriptor handling functions.
30  */
31 
32 #include <smbsrv/smb_incl.h>
33 #include <smbsrv/smb_fsops.h>
34 #include <smbsrv/smb_idmap.h>
35 
36 #define	AS_DWORD(X)		(*(uint32_t *)&(X))
37 #define	SELF_REL(P, M, T)	(T *)(((char *)(P)) + AS_DWORD((P)->M))
38 
39 void smb_fmt_sid(char *buf, nt_sid_t *sid);
40 
41 void
42 smb_sd_init(smb_sd_t *sd, uint8_t revision)
43 {
44 	bzero(sd, sizeof (smb_sd_t));
45 	sd->sd_hdr.sd_revision = revision;
46 }
47 
48 /*
49  * smb_sd_term
50  *
51  * Free non-NULL members of 'sd' which has to be in
52  * absolute (pointer) form.
53  */
54 void
55 smb_sd_term(smb_sd_t *sd)
56 {
57 	ASSERT(sd);
58 	ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
59 
60 	if (sd->sd_owner)
61 		MEM_FREE("libnt", sd->sd_owner);
62 
63 	if (sd->sd_group)
64 		MEM_FREE("libnt", sd->sd_group);
65 
66 	if (sd->sd_dacl)
67 		kmem_free(sd->sd_dacl, sd->sd_dacl->sl_size);
68 
69 	if (sd->sd_sacl)
70 		kmem_free(sd->sd_sacl, sd->sd_sacl->sl_size);
71 
72 	bzero(sd, sizeof (smb_sd_t));
73 }
74 
75 /*
76  * Hmmm. For all of these smb_sd_set_xxx() functions,
77  * what do we do if the affected member is already set?
78  * Should we free() it? For now, punt and risk a memory leak.
79  */
80 
81 void
82 smb_sd_set_owner(smb_sd_t *sd, nt_sid_t *owner, int defaulted)
83 {
84 	ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
85 
86 	sd->sd_owner = owner;
87 	if (defaulted)
88 		sd->sd_hdr.sd_control |= SE_OWNER_DEFAULTED;
89 	else
90 		sd->sd_hdr.sd_control &= ~SE_OWNER_DEFAULTED;
91 }
92 
93 void
94 smb_sd_set_group(smb_sd_t *sd, nt_sid_t *group, int defaulted)
95 {
96 	ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
97 
98 	sd->sd_group = group;
99 	if (defaulted)
100 		sd->sd_hdr.sd_control |= SE_GROUP_DEFAULTED;
101 	else
102 		sd->sd_hdr.sd_control &= ~SE_GROUP_DEFAULTED;
103 }
104 
105 void
106 smb_sd_set_dacl(smb_sd_t *sd, int present, smb_acl_t *acl, int flags)
107 {
108 	ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
109 
110 	sd->sd_dacl = acl;
111 
112 	if (flags & ACL_DEFAULTED)
113 		sd->sd_hdr.sd_control |= SE_DACL_DEFAULTED;
114 	if (flags & ACL_AUTO_INHERIT)
115 		sd->sd_hdr.sd_control |= SE_DACL_AUTO_INHERITED;
116 	if (flags & ACL_PROTECTED)
117 		sd->sd_hdr.sd_control |= SE_DACL_PROTECTED;
118 
119 	if (present)
120 		sd->sd_hdr.sd_control |= SE_DACL_PRESENT;
121 }
122 
123 void
124 smb_sd_set_sacl(smb_sd_t *sd, int present, smb_acl_t *acl, int flags)
125 {
126 	ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
127 
128 	sd->sd_sacl = acl;
129 
130 	if (flags & ACL_DEFAULTED)
131 		sd->sd_hdr.sd_control |= SE_SACL_DEFAULTED;
132 	if (flags & ACL_AUTO_INHERIT)
133 		sd->sd_hdr.sd_control |= SE_SACL_AUTO_INHERITED;
134 	if (flags & ACL_PROTECTED)
135 		sd->sd_hdr.sd_control |= SE_SACL_PROTECTED;
136 
137 	if (present)
138 		sd->sd_hdr.sd_control |= SE_SACL_PRESENT;
139 }
140 
141 nt_sid_t *
142 smb_sd_get_owner(void *sd, int *defaulted)
143 {
144 	smb_sdbuf_t *sr_sd;
145 	smb_sd_hdr_t *sd_hdr;
146 	nt_sid_t *sid;
147 
148 	sd_hdr = (smb_sd_hdr_t *)sd;
149 	if (defaulted != NULL)
150 		*defaulted = (sd_hdr->sd_control & SE_OWNER_DEFAULTED) ? 1 : 0;
151 
152 	if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
153 		sr_sd = ((smb_sdbuf_t *)sd);
154 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
155 		sid = SELF_REL(sr_sd, sd_owner_offs, nt_sid_t);
156 	}
157 	else
158 		sid = ((smb_sd_t *)sd)->sd_owner;
159 
160 	return (sid);
161 }
162 
163 nt_sid_t *
164 smb_sd_get_group(void *sd, int *defaulted)
165 {
166 	smb_sdbuf_t *sr_sd;
167 	smb_sd_hdr_t *sd_hdr;
168 	nt_sid_t *sid;
169 
170 	sd_hdr = (smb_sd_hdr_t *)sd;
171 	if (defaulted != NULL)
172 		*defaulted = (sd_hdr->sd_control & SE_GROUP_DEFAULTED) ? 1 : 0;
173 
174 	if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
175 		sr_sd = ((smb_sdbuf_t *)sd);
176 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
177 		sid = SELF_REL(sr_sd, sd_group_offs, nt_sid_t);
178 	}
179 	else
180 		sid = ((smb_sd_t *)sd)->sd_group;
181 
182 	return (sid);
183 }
184 
185 smb_acl_t *
186 smb_sd_get_dacl(void *sd, int *present, int *defaulted)
187 {
188 	smb_sdbuf_t *sr_sd;
189 	smb_sd_hdr_t *sd_hdr;
190 	smb_acl_t *acl = NULL;
191 
192 	sd_hdr = (smb_sd_hdr_t *)sd;
193 	if (present != NULL)
194 		*present = (sd_hdr->sd_control & SE_DACL_PRESENT) ? 1 : 0;
195 
196 	if (defaulted != NULL)
197 		*defaulted = (sd_hdr->sd_control & SE_DACL_DEFAULTED) ? 1 : 0;
198 
199 	if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
200 		sr_sd = ((smb_sdbuf_t *)sd);
201 		if (sr_sd->sd_dacl_offs) {
202 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
203 			acl = SELF_REL(sr_sd, sd_dacl_offs, smb_acl_t);
204 		}
205 	}
206 	else
207 		acl = ((smb_sd_t *)sd)->sd_dacl;
208 
209 	return (acl);
210 }
211 
212 smb_acl_t *
213 smb_sd_get_sacl(void *sd, int *present, int *defaulted)
214 {
215 	smb_sdbuf_t *sr_sd;
216 	smb_sd_hdr_t *sd_hdr;
217 	smb_acl_t *acl = NULL;
218 
219 	sd_hdr = (smb_sd_hdr_t *)sd;
220 	if (present != NULL)
221 		*present = (sd_hdr->sd_control & SE_SACL_PRESENT) ? 1 : 0;
222 
223 	if (defaulted != NULL)
224 		*defaulted = (sd_hdr->sd_control & SE_SACL_DEFAULTED) ? 1 : 0;
225 
226 	if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
227 		sr_sd = ((smb_sdbuf_t *)sd);
228 		if (sr_sd->sd_sacl_offs) {
229 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
230 			acl = SELF_REL(sr_sd, sd_sacl_offs, smb_acl_t);
231 		}
232 	}
233 	else
234 		acl = ((smb_sd_t *)sd)->sd_sacl;
235 
236 	return (acl);
237 }
238 
239 uint32_t
240 smb_sd_len(void *sd, uint32_t secinfo)
241 {
242 	uint32_t length = 0;
243 	nt_sid_t *sid;
244 	smb_acl_t *acl;
245 	int present;
246 
247 	/* SD Header */
248 	length += sizeof (smb_sdbuf_t);
249 
250 	/* Owner */
251 	if (secinfo & SMB_OWNER_SECINFO) {
252 		sid = smb_sd_get_owner(sd, NULL);
253 		if (sid)
254 			length += nt_sid_length(sid);
255 	}
256 
257 
258 	/* Group */
259 	if (secinfo & SMB_GROUP_SECINFO) {
260 		sid = smb_sd_get_group(sd, NULL);
261 		if (sid)
262 			length += nt_sid_length(sid);
263 	}
264 
265 
266 	/* DACL */
267 	if (secinfo & SMB_DACL_SECINFO) {
268 		acl = smb_sd_get_dacl(sd, &present, NULL);
269 		if (present && acl)
270 			length += smb_acl_len(acl);
271 	}
272 
273 	/* SACL */
274 	if (secinfo & SMB_SACL_SECINFO) {
275 		acl = smb_sd_get_sacl(sd, &present, NULL);
276 		if (present && acl)
277 			length += smb_acl_len(acl);
278 	}
279 
280 	return (length);
281 }
282 
283 /*
284  * smb_sd_get_secinfo
285  *
286  * Return the security information mask for the specified security
287  * descriptor.
288  */
289 uint32_t
290 smb_sd_get_secinfo(void *sd)
291 {
292 	uint32_t sec_info = 0;
293 	smb_acl_t *acl;
294 	int present;
295 
296 	if (sd == 0)
297 		return (0);
298 
299 	if (smb_sd_get_owner(sd, NULL) != 0)
300 		sec_info |= SMB_OWNER_SECINFO;
301 
302 	if (smb_sd_get_group(sd, NULL) != 0)
303 		sec_info |= SMB_GROUP_SECINFO;
304 
305 	acl = smb_sd_get_dacl(sd, &present, NULL);
306 	if (acl && present)
307 		sec_info |= SMB_DACL_SECINFO;
308 
309 	acl = smb_sd_get_sacl(sd, &present, NULL);
310 	if (acl && present)
311 		sec_info |= SMB_SACL_SECINFO;
312 
313 	return (sec_info);
314 }
315 
316 /*
317  * smb_sd_abs2selfrel
318  *
319  * This function takes an absolute SD (sd) and make a self relative
320  * SD which will be returned in srel_sd.
321  *
322  * srel_sdsz contains the size of buffer which srel_sd points to.
323  *
324  * Do not add new error codes here without checking the impact on
325  * all callers of this function.
326  *
327  * Returns NT status codes:
328  *		NT_STATUS_SUCCESS
329  *		NT_STATUS_BUFFER_TOO_SMALL
330  *		NT_STATUS_INVALID_SECURITY_DESCR
331  */
332 static uint32_t
333 smb_sd_abs2selfrel(
334     smb_sd_t *sd,
335     uint32_t secinfo,
336     smb_sdbuf_t *srel_sd,
337     uint32_t srel_sdsz)
338 {
339 	uint32_t avail_len = srel_sdsz;
340 	uint32_t length = 0;
341 	unsigned char *scan_beg = (unsigned char *) srel_sd;
342 	unsigned char *scan = scan_beg;
343 	unsigned char *scan_end;
344 	nt_sid_t *sid;
345 	smb_acl_t *acl;
346 	int present, defaulted;
347 
348 	length = smb_sd_len(sd, secinfo);
349 
350 	if (length == 0)
351 		return (NT_STATUS_INVALID_SECURITY_DESCR);
352 
353 	if (avail_len < length)
354 		return (NT_STATUS_BUFFER_TOO_SMALL);
355 
356 	bzero(srel_sd, length);
357 	scan_end = scan_beg + length;
358 
359 	/* SD Header */
360 	length = sizeof (smb_sdbuf_t);
361 	srel_sd->sd_hdr.sd_revision = sd->sd_hdr.sd_revision;
362 	srel_sd->sd_hdr.sd_control  = SE_SELF_RELATIVE;
363 	scan += length;
364 
365 	if (secinfo & SMB_OWNER_SECINFO) {
366 		/* Owner */
367 		sid = smb_sd_get_owner(sd, &defaulted);
368 
369 		if (defaulted)
370 			srel_sd->sd_hdr.sd_control |= SE_OWNER_DEFAULTED;
371 
372 		if (sid) {
373 			/*LINTED E_PTRDIFF_OVERFLOW*/
374 			length = nt_sid_copy((void*)scan, sid, scan_end - scan);
375 			if (length == 0)
376 				goto fail;
377 			/*LINTED E_PTRDIFF_OVERFLOW*/
378 			srel_sd->sd_owner_offs = scan - scan_beg;
379 			scan += length;
380 		}
381 	}
382 
383 	if (secinfo & SMB_GROUP_SECINFO) {
384 		/* Group */
385 		sid = smb_sd_get_group(sd, &defaulted);
386 
387 		if (defaulted)
388 			srel_sd->sd_hdr.sd_control |= SE_GROUP_DEFAULTED;
389 
390 		if (sid) {
391 			/*LINTED E_PTRDIFF_OVERFLOW*/
392 			length = nt_sid_copy((void*)scan, sid, scan_end - scan);
393 			if (length == 0)
394 				goto fail;
395 			/*LINTED E_PTRDIFF_OVERFLOW*/
396 			srel_sd->sd_group_offs = scan - scan_beg;
397 			scan += length;
398 		}
399 	}
400 
401 
402 	if (secinfo & SMB_DACL_SECINFO) {
403 		/* Dacl */
404 		acl = smb_sd_get_dacl(sd, &present, &defaulted);
405 
406 		srel_sd->sd_hdr.sd_control |=
407 		    (sd->sd_hdr.sd_control & SE_DACL_INHERITANCE_MASK);
408 
409 		if (defaulted)
410 			srel_sd->sd_hdr.sd_control |= SE_DACL_DEFAULTED;
411 
412 		if (present)
413 			srel_sd->sd_hdr.sd_control |= SE_DACL_PRESENT;
414 
415 		if (present && acl) {
416 			/*LINTED E_PTRDIFF_OVERFLOW*/
417 			length = smb_acl_copy(scan_end - scan,
418 			    (void*) scan, acl);
419 			if (length == 0)
420 				goto fail;
421 			/*LINTED E_PTRDIFF_OVERFLOW*/
422 			srel_sd->sd_dacl_offs = scan - scan_beg;
423 			/*LINTED E_PTRDIFF_OVERFLOW*/
424 			acl = (smb_acl_t *)scan;
425 			acl->sl_size = (WORD)length;	/* set the size */
426 			scan += length;
427 		}
428 	}
429 
430 	if (secinfo & SMB_SACL_SECINFO) {
431 		/* Sacl */
432 		acl = smb_sd_get_sacl(sd, &present, &defaulted);
433 
434 		srel_sd->sd_hdr.sd_control |=
435 		    (sd->sd_hdr.sd_control & SE_SACL_INHERITANCE_MASK);
436 
437 		if (defaulted)
438 			srel_sd->sd_hdr.sd_control |= SE_SACL_DEFAULTED;
439 
440 		if (present)
441 			srel_sd->sd_hdr.sd_control |= SE_SACL_PRESENT;
442 
443 		if (present && acl) {
444 			/*LINTED E_PTRDIFF_OVERFLOW*/
445 			length = smb_acl_copy(scan_end - scan,
446 			    (void*) scan, acl);
447 			if (length == 0)
448 				goto fail;
449 			/*LINTED E_PTRDIFF_OVERFLOW*/
450 			srel_sd->sd_sacl_offs = scan - scan_beg;
451 			/*LINTED E_PTRDIFF_OVERFLOW*/
452 			acl = (smb_acl_t *)scan;
453 			acl->sl_size = (WORD)length;	/* set the size */
454 			scan += length;
455 		}
456 	}
457 
458 	return (NT_STATUS_SUCCESS);
459 
460 fail:
461 	return (NT_STATUS_INVALID_SECURITY_DESCR);
462 }
463 
464 /*
465  * smb_sd_fromfs
466  *
467  * Makes an Windows style security descriptor in absolute form
468  * based on the given filesystem security information.
469  *
470  * Should call smb_sd_term() for the returned sd to free allocated
471  * members.
472  */
473 static uint32_t
474 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
475 {
476 	uint32_t status = NT_STATUS_SUCCESS;
477 	smb_acl_t *acl = NULL;
478 	smb_acl_t *sorted_acl;
479 	nt_sid_t *sid;
480 	idmap_stat idm_stat;
481 
482 	ASSERT(fs_sd);
483 	ASSERT(sd);
484 
485 	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
486 
487 	/* Owner */
488 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
489 		idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
490 		    SMB_IDMAP_USER, &sid);
491 
492 		if (idm_stat != IDMAP_SUCCESS) {
493 			return (NT_STATUS_NONE_MAPPED);
494 		}
495 
496 		smb_sd_set_owner(sd, sid, 0);
497 	}
498 
499 	/* Group */
500 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
501 		idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
502 		    SMB_IDMAP_GROUP, &sid);
503 
504 		if (idm_stat != IDMAP_SUCCESS) {
505 			smb_sd_term(sd);
506 			return (NT_STATUS_NONE_MAPPED);
507 		}
508 
509 		smb_sd_set_group(sd, sid, 0);
510 	}
511 
512 	/* DACL */
513 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
514 		if (fs_sd->sd_zdacl != NULL) {
515 			acl = smb_acl_from_zfs(fs_sd->sd_zdacl, fs_sd->sd_uid,
516 			    fs_sd->sd_gid);
517 			if (acl == NULL) {
518 				smb_sd_term(sd);
519 				return (NT_STATUS_INTERNAL_ERROR);
520 			}
521 
522 			/*
523 			 * Need to sort the ACL before send it to Windows
524 			 * clients. Winodws GUI is sensitive about the order
525 			 * of ACEs.
526 			 */
527 			sorted_acl = smb_acl_sort(acl);
528 			if (sorted_acl && (sorted_acl != acl)) {
529 				kmem_free(acl, acl->sl_size);
530 				acl = sorted_acl;
531 			}
532 			smb_sd_set_dacl(sd, 1, acl, fs_sd->sd_zdacl->acl_flags);
533 		} else {
534 			smb_sd_set_dacl(sd, 0, NULL, 0);
535 		}
536 	}
537 
538 	/* SACL */
539 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
540 		if (fs_sd->sd_zsacl != NULL) {
541 			acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid,
542 			    fs_sd->sd_gid);
543 			if (acl == NULL) {
544 				smb_sd_term(sd);
545 				return (NT_STATUS_INTERNAL_ERROR);
546 			}
547 
548 			smb_sd_set_sacl(sd, 1, acl, fs_sd->sd_zsacl->acl_flags);
549 		} else {
550 			smb_sd_set_sacl(sd, 0, NULL, 0);
551 		}
552 	}
553 
554 	return (status);
555 }
556 
557 /*
558  * smb_sd_tofs
559  *
560  * Creates a filesystem security structure based on the given
561  * Windows security descriptor.
562  */
563 uint32_t
564 smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd)
565 {
566 	nt_sid_t *sid;
567 	smb_acl_t *acl;
568 	uint32_t status = NT_STATUS_SUCCESS;
569 	uint16_t sd_control;
570 	idmap_stat idm_stat;
571 	int present;
572 	int idtype;
573 	int flags = 0;
574 
575 	sd_control = sr_sd->sd_hdr.sd_control;
576 
577 	/*
578 	 * ZFS only has one set of flags so for now only
579 	 * Windows DACL flags are taken into account.
580 	 */
581 	if (sd_control & SE_DACL_DEFAULTED)
582 		flags |= ACL_DEFAULTED;
583 	if (sd_control & SE_DACL_AUTO_INHERITED)
584 		flags |= ACL_AUTO_INHERIT;
585 	if (sd_control & SE_DACL_PROTECTED)
586 		flags |= ACL_PROTECTED;
587 
588 	if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
589 		flags |= ACL_IS_DIR;
590 
591 	/* Owner */
592 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
593 		sid = smb_sd_get_owner(sr_sd, NULL);
594 		if (nt_sid_is_valid(sid) == 0) {
595 			return (NT_STATUS_INVALID_SID);
596 		}
597 
598 		idtype = SMB_IDMAP_UNKNOWN;
599 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
600 		if (idm_stat != IDMAP_SUCCESS) {
601 			return (NT_STATUS_NONE_MAPPED);
602 		}
603 	}
604 
605 	/* Group */
606 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
607 		sid = smb_sd_get_group(sr_sd, NULL);
608 		if (nt_sid_is_valid(sid) == 0) {
609 			return (NT_STATUS_INVALID_SID);
610 		}
611 
612 		idtype = SMB_IDMAP_UNKNOWN;
613 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
614 		if (idm_stat != IDMAP_SUCCESS) {
615 			return (NT_STATUS_NONE_MAPPED);
616 		}
617 	}
618 
619 	/* DACL */
620 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
621 		acl = smb_sd_get_dacl(sr_sd, &present, NULL);
622 		if (present) {
623 			status = smb_acl_to_zfs(acl, flags,
624 			    SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
625 			if (status != NT_STATUS_SUCCESS)
626 				return (status);
627 		}
628 		else
629 			return (NT_STATUS_INVALID_ACL);
630 	}
631 
632 	/* SACL */
633 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
634 		acl = smb_sd_get_sacl(sr_sd, &present, NULL);
635 		if (present) {
636 			status = smb_acl_to_zfs(acl, flags,
637 			    SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
638 			if (status != NT_STATUS_SUCCESS) {
639 				return (status);
640 			}
641 		} else {
642 			return (NT_STATUS_INVALID_ACL);
643 		}
644 	}
645 
646 	return (status);
647 }
648 
649 /*
650  * smb_sd_read
651  *
652  * Read uid, gid and ACL from filesystem. The returned ACL from read
653  * routine is always in ZFS format. Convert the ZFS acl to a Win acl
654  * and return the Win SD in relative form.
655  *
656  * NOTE: upon successful return caller MUST free the memory allocated
657  * for the returned SD by calling kmem_free(). The length of the allocated
658  * buffer is returned in 'buflen'.
659  */
660 uint32_t
661 smb_sd_read(smb_request_t *sr, smb_sdbuf_t **sr_sd,
662     uint32_t secinfo, uint32_t *buflen)
663 {
664 	smb_sd_t sd;
665 	smb_fssd_t fs_sd;
666 	smb_error_t smb_err;
667 	smb_sdbuf_t *sdbuf;
668 	smb_node_t *node;
669 	uint32_t sdlen;
670 	uint32_t status = NT_STATUS_SUCCESS;
671 	uint32_t sd_flags;
672 	int error;
673 
674 	*sr_sd = NULL;
675 
676 	node = sr->fid_ofile->f_node;
677 	sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
678 	smb_fsop_sdinit(&fs_sd, secinfo, sd_flags);
679 
680 	error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
681 	if (error) {
682 		smb_errmap_unix2smb(error, &smb_err);
683 		return (smb_err.status);
684 	}
685 
686 	status = smb_sd_fromfs(&fs_sd, &sd);
687 	smb_fsop_sdterm(&fs_sd);
688 
689 	if (status != NT_STATUS_SUCCESS)
690 		return (status);
691 
692 	sdlen = smb_sd_len(&sd, secinfo);
693 
694 	if (*buflen < sdlen) {
695 		/* return the required size */
696 		*buflen = sdlen;
697 		smb_sd_term(&sd);
698 		return (NT_STATUS_BUFFER_TOO_SMALL);
699 	}
700 
701 	sdbuf = kmem_alloc(sdlen, KM_SLEEP);
702 	status = smb_sd_abs2selfrel(&sd, secinfo, sdbuf, sdlen);
703 	smb_sd_term(&sd);
704 
705 	if (status == NT_STATUS_SUCCESS) {
706 		*sr_sd = sdbuf;
707 		*buflen = sdlen;
708 	}
709 	else
710 		kmem_free(sdbuf, sdlen);
711 
712 	return (status);
713 }
714 
715 /*
716  * smb_sd_write
717  *
718  * Takes a Win SD in self-relative form, convert it to
719  * ZFS format and write it to filesystem. The write routine
720  * converts ZFS acl to Posix acl if required.
721  */
722 uint32_t
723 smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd, uint32_t secinfo)
724 {
725 	smb_node_t *node;
726 	smb_fssd_t fs_sd;
727 	smb_error_t smb_err;
728 	uint32_t status;
729 	uint32_t sd_flags;
730 	int error;
731 
732 	node = sr->fid_ofile->f_node;
733 	sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
734 	smb_fsop_sdinit(&fs_sd, secinfo, sd_flags);
735 
736 	status = smb_sd_tofs(sr_sd, &fs_sd);
737 	if (status != NT_STATUS_SUCCESS) {
738 		smb_fsop_sdterm(&fs_sd);
739 		return (status);
740 	}
741 
742 	error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
743 	smb_fsop_sdterm(&fs_sd);
744 
745 	if (error) {
746 		smb_errmap_unix2smb(error, &smb_err);
747 		return (smb_err.status);
748 	}
749 
750 	return (NT_STATUS_SUCCESS);
751 }
752 
753 /*
754  * smb_fmt_sid
755  *
756  * Make an string SID and copy the result into the specified buffer.
757  */
758 void
759 smb_fmt_sid(char *buf, nt_sid_t *sid)
760 {
761 	char *sid_str;
762 
763 	sid_str = nt_sid_format(sid);
764 	if (sid_str) {
765 		(void) strcpy(buf, sid_str);
766 		MEM_FREE("smb", sid_str);
767 	} else {
768 		(void) strcpy(buf, "<invalid SID>");
769 	}
770 }
771 
772 /*
773  * smb_sd_log
774  *
775  * log the given Windows style security descriptor information
776  * in system log. This is for debugging purposes.
777  */
778 void
779 smb_sd_log(void *sd)
780 {
781 	smb_acl_t *acl;
782 	smb_ace_t *ace;
783 	nt_sid_t *sid;
784 	int present, defaulted;
785 	char entry[128];
786 	char *inherit;
787 	char *type;
788 	int ix_dacl;
789 
790 	sid = smb_sd_get_owner(sd, &defaulted);
791 	if (sid)
792 		smb_fmt_sid(entry, sid);
793 	else
794 		(void) strcpy(entry, "NULL");
795 
796 	cmn_err(CE_NOTE, "  Owner: %s", entry);
797 
798 	sid = smb_sd_get_group(sd, &defaulted);
799 	if (sid)
800 		smb_fmt_sid(entry, sid);
801 	else
802 		(void) strcpy(entry, "NULL");
803 
804 	cmn_err(CE_NOTE, "  Primary Group: %s", entry);
805 
806 	acl = smb_sd_get_dacl(sd, &present, &defaulted);
807 
808 	if (!present || !acl) {
809 		cmn_err(CE_NOTE, "  No DACL");
810 		return;
811 	}
812 
813 	for (ix_dacl = 0;
814 	    ace = smb_ace_get(acl, ix_dacl);
815 	    ix_dacl++) {
816 		/*
817 		 * Make sure the ACE type is something we grok.
818 		 * All ACE, now and in the future, have a valid
819 		 * header. Can't access fields passed the Header
820 		 * until we're sure it's right.
821 		 */
822 		switch (ace->se_header.se_type) {
823 		case ACCESS_ALLOWED_ACE_TYPE:
824 			type = "(Allow)";
825 			break;
826 		case ACCESS_DENIED_ACE_TYPE:
827 			type = "(Deny)";
828 			break;
829 
830 		case SYSTEM_AUDIT_ACE_TYPE:
831 		default:
832 			/* Ignore unrecognized/misplaced ACE */
833 			continue;
834 		}
835 
836 		smb_fmt_sid(entry, &ace->se_sid);
837 
838 		switch (ace->se_header.se_flags & INHERIT_MASK_ACE) {
839 		case OBJECT_INHERIT_ACE:
840 			inherit = "(OI)";
841 			break;
842 		case CONTAINER_INHERIT_ACE:
843 			inherit = "(CI)";
844 			break;
845 		case INHERIT_ONLY_ACE:
846 			inherit = "(IO)";
847 			break;
848 		case NO_PROPOGATE_INHERIT_ACE:
849 			inherit = "(NP)";
850 			break;
851 		default:
852 			inherit = "";
853 		}
854 
855 		(void) snprintf(entry + strlen(entry), sizeof (entry),
856 		    ":%s 0x%X %s", inherit, ace->se_mask, type);
857 
858 		cmn_err(CE_NOTE, "  %s", entry);
859 	}
860 
861 	cmn_err(CE_NOTE, "  %d ACE(s)", ix_dacl);
862 }
863