smb_sd.c revision 11963:061945695ce1
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/*
27 * This module provides Security Descriptor handling functions.
28 */
29
30#include <smbsrv/smb_kproto.h>
31#include <smbsrv/smb_fsops.h>
32#include <smbsrv/smb_idmap.h>
33
34static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
35static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
36static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *);
37
38void
39smb_sd_init(smb_sd_t *sd, uint8_t revision)
40{
41	bzero(sd, sizeof (smb_sd_t));
42	sd->sd_revision = revision;
43}
44
45/*
46 * smb_sd_term
47 *
48 * Free non-NULL members of 'sd' which has to be in
49 * absolute (pointer) form.
50 */
51void
52smb_sd_term(smb_sd_t *sd)
53{
54	ASSERT(sd);
55	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
56
57	smb_sid_free(sd->sd_owner);
58	smb_sid_free(sd->sd_group);
59	smb_acl_free(sd->sd_dacl);
60	smb_acl_free(sd->sd_sacl);
61
62	bzero(sd, sizeof (smb_sd_t));
63}
64
65uint32_t
66smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
67{
68	uint32_t length = SMB_SD_HDRSIZE;
69
70	if (secinfo & SMB_OWNER_SECINFO)
71		length += smb_sid_len(sd->sd_owner);
72
73	if (secinfo & SMB_GROUP_SECINFO)
74		length += smb_sid_len(sd->sd_group);
75
76	if (secinfo & SMB_DACL_SECINFO)
77		length += smb_acl_len(sd->sd_dacl);
78
79	if (secinfo & SMB_SACL_SECINFO)
80		length += smb_acl_len(sd->sd_sacl);
81
82	return (length);
83}
84
85/*
86 * smb_sd_get_secinfo
87 *
88 * Return the security information mask for the specified security
89 * descriptor.
90 */
91uint32_t
92smb_sd_get_secinfo(smb_sd_t *sd)
93{
94	uint32_t sec_info = 0;
95
96	if (sd == NULL)
97		return (0);
98
99	if (sd->sd_owner)
100		sec_info |= SMB_OWNER_SECINFO;
101
102	if (sd->sd_group)
103		sec_info |= SMB_GROUP_SECINFO;
104
105	if (sd->sd_dacl)
106		sec_info |= SMB_DACL_SECINFO;
107
108	if (sd->sd_sacl)
109		sec_info |= SMB_SACL_SECINFO;
110
111	return (sec_info);
112}
113
114/*
115 * smb_sd_read
116 *
117 * Read uid, gid and ACL from filesystem. The returned ACL from read
118 * routine is always in ZFS format. Convert the ZFS acl to a Win acl
119 * and return the Win SD in absolute form.
120 *
121 * NOTE: upon successful return caller MUST free the memory allocated
122 * for the returned SD by calling smb_sd_term().
123 */
124uint32_t
125smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
126{
127	smb_fssd_t fs_sd;
128	smb_error_t smb_err;
129	smb_node_t *node;
130	uint32_t status = NT_STATUS_SUCCESS;
131	uint32_t sd_flags;
132	int error;
133
134	node = sr->fid_ofile->f_node;
135	sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
136	smb_fssd_init(&fs_sd, secinfo, sd_flags);
137
138	error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
139	if (error) {
140		smbsr_map_errno(error, &smb_err);
141		return (smb_err.status);
142	}
143
144	status = smb_sd_fromfs(&fs_sd, sd);
145	smb_fssd_term(&fs_sd);
146
147	return (status);
148}
149
150/*
151 * smb_sd_write
152 *
153 * Takes a Win SD in absolute form, converts it to
154 * ZFS format and write it to filesystem. The write routine
155 * converts ZFS acl to Posix acl if required.
156 */
157uint32_t
158smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
159{
160	smb_node_t *node;
161	smb_fssd_t fs_sd;
162	smb_error_t smb_err;
163	uint32_t status;
164	uint32_t sd_flags;
165	int error;
166
167	node = sr->fid_ofile->f_node;
168	sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
169	smb_fssd_init(&fs_sd, secinfo, sd_flags);
170
171	status = smb_sd_tofs(sd, &fs_sd);
172	if (status != NT_STATUS_SUCCESS) {
173		smb_fssd_term(&fs_sd);
174		return (status);
175	}
176
177	error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
178	smb_fssd_term(&fs_sd);
179
180	if (error) {
181		if (error == EBADE)
182			return (NT_STATUS_INVALID_OWNER);
183		smbsr_map_errno(error, &smb_err);
184		return (smb_err.status);
185	}
186
187	return (NT_STATUS_SUCCESS);
188}
189
190
191/*
192 * smb_sd_tofs
193 *
194 * Creates a filesystem security structure based on the given
195 * Windows security descriptor.
196 */
197uint32_t
198smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
199{
200	smb_sid_t *sid;
201	uint32_t status = NT_STATUS_SUCCESS;
202	uint16_t sd_control;
203	idmap_stat idm_stat;
204	int idtype;
205	int flags = 0;
206
207	sd_control = sd->sd_control;
208
209	/*
210	 * ZFS only has one set of flags so for now only
211	 * Windows DACL flags are taken into account.
212	 */
213	if (sd_control & SE_DACL_DEFAULTED)
214		flags |= ACL_DEFAULTED;
215	if (sd_control & SE_DACL_AUTO_INHERITED)
216		flags |= ACL_AUTO_INHERIT;
217	if (sd_control & SE_DACL_PROTECTED)
218		flags |= ACL_PROTECTED;
219
220	if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
221		flags |= ACL_IS_DIR;
222
223	/* Owner */
224	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
225		sid = sd->sd_owner;
226		if (!smb_sid_isvalid(sid))
227			return (NT_STATUS_INVALID_SID);
228
229		idtype = SMB_IDMAP_USER;
230		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
231		if (idm_stat != IDMAP_SUCCESS) {
232			return (NT_STATUS_NONE_MAPPED);
233		}
234	}
235
236	/* Group */
237	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
238		sid = sd->sd_group;
239		if (!smb_sid_isvalid(sid))
240			return (NT_STATUS_INVALID_SID);
241
242		idtype = SMB_IDMAP_GROUP;
243		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
244		if (idm_stat != IDMAP_SUCCESS) {
245			return (NT_STATUS_NONE_MAPPED);
246		}
247	}
248
249	/* DACL */
250	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
251		if (sd->sd_control & SE_DACL_PRESENT) {
252			status = smb_acl_to_zfs(sd->sd_dacl, flags,
253			    SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
254			if (status != NT_STATUS_SUCCESS)
255				return (status);
256		}
257		else
258			return (NT_STATUS_INVALID_ACL);
259	}
260
261	/* SACL */
262	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
263		if (sd->sd_control & SE_SACL_PRESENT) {
264			status = smb_acl_to_zfs(sd->sd_sacl, flags,
265			    SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
266			if (status != NT_STATUS_SUCCESS) {
267				return (status);
268			}
269		} else {
270			return (NT_STATUS_INVALID_ACL);
271		}
272	}
273
274	return (status);
275}
276
277/*
278 * smb_sd_fromfs
279 *
280 * Makes an Windows style security descriptor in absolute form
281 * based on the given filesystem security information.
282 *
283 * Should call smb_sd_term() for the returned sd to free allocated
284 * members.
285 */
286static uint32_t
287smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
288{
289	uint32_t status = NT_STATUS_SUCCESS;
290	smb_acl_t *acl = NULL;
291	smb_sid_t *sid;
292	idmap_stat idm_stat;
293
294	ASSERT(fs_sd);
295	ASSERT(sd);
296
297	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
298
299	/* Owner */
300	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
301		idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
302		    SMB_IDMAP_USER, &sid);
303
304		if (idm_stat != IDMAP_SUCCESS) {
305			smb_sd_term(sd);
306			return (NT_STATUS_NONE_MAPPED);
307		}
308
309		sd->sd_owner = sid;
310	}
311
312	/* Group */
313	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
314		idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
315		    SMB_IDMAP_GROUP, &sid);
316
317		if (idm_stat != IDMAP_SUCCESS) {
318			smb_sd_term(sd);
319			return (NT_STATUS_NONE_MAPPED);
320		}
321
322		sd->sd_group = sid;
323	}
324
325	/* DACL */
326	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
327		if (fs_sd->sd_zdacl != NULL) {
328			acl = smb_acl_from_zfs(fs_sd->sd_zdacl);
329			if (acl == NULL) {
330				smb_sd_term(sd);
331				return (NT_STATUS_INTERNAL_ERROR);
332			}
333
334			/*
335			 * Need to sort the ACL before send it to Windows
336			 * clients. Winodws GUI is sensitive about the order
337			 * of ACEs.
338			 */
339			smb_acl_sort(acl);
340			smb_sd_set_dacl(sd, acl, B_TRUE,
341			    fs_sd->sd_zdacl->acl_flags);
342		} else {
343			smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
344		}
345	}
346
347	/* SACL */
348	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
349		if (fs_sd->sd_zsacl != NULL) {
350			acl = smb_acl_from_zfs(fs_sd->sd_zsacl);
351			if (acl == NULL) {
352				smb_sd_term(sd);
353				return (NT_STATUS_INTERNAL_ERROR);
354			}
355
356			smb_sd_set_sacl(sd, acl, B_TRUE,
357			    fs_sd->sd_zsacl->acl_flags);
358		} else {
359			smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
360		}
361	}
362
363	return (status);
364}
365
366static void
367smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
368{
369	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
370
371	sd->sd_dacl = acl;
372
373	if (flags & ACL_DEFAULTED)
374		sd->sd_control |= SE_DACL_DEFAULTED;
375	if (flags & ACL_AUTO_INHERIT)
376		sd->sd_control |= SE_DACL_AUTO_INHERITED;
377	if (flags & ACL_PROTECTED)
378		sd->sd_control |= SE_DACL_PROTECTED;
379
380	if (present)
381		sd->sd_control |= SE_DACL_PRESENT;
382}
383
384static void
385smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
386{
387	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
388
389	sd->sd_sacl = acl;
390
391	if (flags & ACL_DEFAULTED)
392		sd->sd_control |= SE_SACL_DEFAULTED;
393	if (flags & ACL_AUTO_INHERIT)
394		sd->sd_control |= SE_SACL_AUTO_INHERITED;
395	if (flags & ACL_PROTECTED)
396		sd->sd_control |= SE_SACL_PROTECTED;
397
398	if (present)
399		sd->sd_control |= SE_SACL_PRESENT;
400}
401
402/*
403 * smb_fssd_init
404 *
405 * Initializes the given FS SD structure.
406 */
407void
408smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
409{
410	bzero(fs_sd, sizeof (smb_fssd_t));
411	fs_sd->sd_secinfo = secinfo;
412	fs_sd->sd_flags = flags;
413}
414
415/*
416 * smb_fssd_term
417 *
418 * Frees allocated memory for acl fields.
419 */
420void
421smb_fssd_term(smb_fssd_t *fs_sd)
422{
423	ASSERT(fs_sd);
424
425	smb_fsacl_free(fs_sd->sd_zdacl);
426	smb_fsacl_free(fs_sd->sd_zsacl);
427	bzero(fs_sd, sizeof (smb_fssd_t));
428}
429