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