xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_sd.c (revision e8d80663e4f91871f843bb8ad9108dc0b76dfcf3)
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 
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 = 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  */
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 = 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  */
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);
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 
366 static void
367 smb_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 
384 static void
385 smb_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  */
407 void
408 smb_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  */
420 void
421 smb_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