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