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