xref: /titanic_51/usr/src/uts/common/fs/smbsrv/smb_sd.c (revision c5aee8047f101b999b8f96ced79e802071372a52)
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 2009 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 
34 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
35 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
36 static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *);
37 
38 void
39 smb_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  */
51 void
52 smb_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 
65 uint32_t
66 smb_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  */
91 uint32_t
92 smb_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  */
124 uint32_t
125 smb_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 = (node->vp->v_type == VDIR) ? 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  */
157 uint32_t
158 smb_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 = (node->vp->v_type == VDIR) ? 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  */
197 uint32_t
198 smb_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  */
286 static uint32_t
287 smb_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, fs_sd->sd_uid,
329 			    fs_sd->sd_gid);
330 			if (acl == NULL) {
331 				smb_sd_term(sd);
332 				return (NT_STATUS_INTERNAL_ERROR);
333 			}
334 
335 			/*
336 			 * Need to sort the ACL before send it to Windows
337 			 * clients. Winodws GUI is sensitive about the order
338 			 * of ACEs.
339 			 */
340 			smb_acl_sort(acl);
341 			smb_sd_set_dacl(sd, acl, B_TRUE,
342 			    fs_sd->sd_zdacl->acl_flags);
343 		} else {
344 			smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
345 		}
346 	}
347 
348 	/* SACL */
349 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
350 		if (fs_sd->sd_zsacl != NULL) {
351 			acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid,
352 			    fs_sd->sd_gid);
353 			if (acl == NULL) {
354 				smb_sd_term(sd);
355 				return (NT_STATUS_INTERNAL_ERROR);
356 			}
357 
358 			smb_sd_set_sacl(sd, acl, B_TRUE,
359 			    fs_sd->sd_zsacl->acl_flags);
360 		} else {
361 			smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
362 		}
363 	}
364 
365 	return (status);
366 }
367 
368 static void
369 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
370 {
371 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
372 
373 	sd->sd_dacl = acl;
374 
375 	if (flags & ACL_DEFAULTED)
376 		sd->sd_control |= SE_DACL_DEFAULTED;
377 	if (flags & ACL_AUTO_INHERIT)
378 		sd->sd_control |= SE_DACL_AUTO_INHERITED;
379 	if (flags & ACL_PROTECTED)
380 		sd->sd_control |= SE_DACL_PROTECTED;
381 
382 	if (present)
383 		sd->sd_control |= SE_DACL_PRESENT;
384 }
385 
386 static void
387 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
388 {
389 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
390 
391 	sd->sd_sacl = acl;
392 
393 	if (flags & ACL_DEFAULTED)
394 		sd->sd_control |= SE_SACL_DEFAULTED;
395 	if (flags & ACL_AUTO_INHERIT)
396 		sd->sd_control |= SE_SACL_AUTO_INHERITED;
397 	if (flags & ACL_PROTECTED)
398 		sd->sd_control |= SE_SACL_PROTECTED;
399 
400 	if (present)
401 		sd->sd_control |= SE_SACL_PRESENT;
402 }
403 
404 /*
405  * smb_fssd_init
406  *
407  * Initializes the given FS SD structure.
408  */
409 void
410 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
411 {
412 	bzero(fs_sd, sizeof (smb_fssd_t));
413 	fs_sd->sd_secinfo = secinfo;
414 	fs_sd->sd_flags = flags;
415 }
416 
417 /*
418  * smb_fssd_term
419  *
420  * Frees allocated memory for acl fields.
421  */
422 void
423 smb_fssd_term(smb_fssd_t *fs_sd)
424 {
425 	ASSERT(fs_sd);
426 
427 	smb_fsacl_free(fs_sd->sd_zdacl);
428 	smb_fsacl_free(fs_sd->sd_zsacl);
429 	bzero(fs_sd, sizeof (smb_fssd_t));
430 }
431