xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_sd.c (revision 5cfb18f0)
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  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
26  */
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 
36 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
37 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
38 static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *);
39 
40 void
smb_sd_init(smb_sd_t * sd,uint8_t revision)41 smb_sd_init(smb_sd_t *sd, uint8_t revision)
42 {
43 	bzero(sd, sizeof (smb_sd_t));
44 	sd->sd_revision = revision;
45 }
46 
47 /*
48  * smb_sd_term
49  *
50  * Free non-NULL members of 'sd' which has to be in
51  * absolute (pointer) form.
52  */
53 void
smb_sd_term(smb_sd_t * sd)54 smb_sd_term(smb_sd_t *sd)
55 {
56 	ASSERT(sd);
57 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
58 
59 	smb_sid_free(sd->sd_owner);
60 	smb_sid_free(sd->sd_group);
61 	smb_acl_free(sd->sd_dacl);
62 	smb_acl_free(sd->sd_sacl);
63 
64 	bzero(sd, sizeof (smb_sd_t));
65 }
66 
67 uint32_t
smb_sd_len(smb_sd_t * sd,uint32_t secinfo)68 smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
69 {
70 	uint32_t length = SMB_SD_HDRSIZE;
71 
72 	if (secinfo & SMB_OWNER_SECINFO)
73 		length += smb_sid_len(sd->sd_owner);
74 
75 	if (secinfo & SMB_GROUP_SECINFO)
76 		length += smb_sid_len(sd->sd_group);
77 
78 	if (secinfo & SMB_DACL_SECINFO)
79 		length += smb_acl_len(sd->sd_dacl);
80 
81 	if (secinfo & SMB_SACL_SECINFO)
82 		length += smb_acl_len(sd->sd_sacl);
83 
84 	return (length);
85 }
86 
87 /*
88  * smb_sd_get_secinfo
89  *
90  * Return the security information mask for the specified security
91  * descriptor.
92  *
93  * Note: This is used for 'create-with-sd'. 'set-security-info' provides the
94  * secinfo as part of the request, but create does not, so we must infer it.
95  */
96 uint32_t
smb_sd_get_secinfo(smb_sd_t * sd)97 smb_sd_get_secinfo(smb_sd_t *sd)
98 {
99 	uint32_t sec_info = 0;
100 
101 	if (sd == NULL)
102 		return (0);
103 
104 	if (sd->sd_owner)
105 		sec_info |= SMB_OWNER_SECINFO;
106 
107 	if (sd->sd_group)
108 		sec_info |= SMB_GROUP_SECINFO;
109 
110 	if ((sd->sd_control & SE_DACL_PRESENT) != 0)
111 		sec_info |= SMB_DACL_SECINFO;
112 
113 	if ((sd->sd_control & SE_SACL_PRESENT) != 0)
114 		sec_info |= SMB_SACL_SECINFO;
115 
116 	return (sec_info);
117 }
118 
119 /*
120  * smb_sd_read
121  *
122  * Read uid, gid and ACL from filesystem. The returned ACL from read
123  * routine is always in ZFS format. Convert the ZFS acl to a Win acl
124  * and return the Win SD in absolute form.
125  *
126  * NOTE: upon successful return caller MUST free the memory allocated
127  * for the returned SD by calling smb_sd_term().
128  */
129 uint32_t
smb_sd_read(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)130 smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
131 {
132 	smb_fssd_t fs_sd;
133 	smb_node_t *node;
134 	uint32_t status = NT_STATUS_SUCCESS;
135 	uint32_t sd_flags;
136 	int error;
137 
138 	node = sr->fid_ofile->f_node;
139 	sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
140 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
141 
142 	error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
143 	if (error)
144 		return (smb_errno2status(error));
145 
146 	status = smb_sd_fromfs(&fs_sd, sd);
147 	smb_fssd_term(&fs_sd);
148 
149 	return (status);
150 }
151 
152 /*
153  * smb_sd_write
154  *
155  * Takes a Win SD in absolute form, converts it to
156  * ZFS format and write it to filesystem. The write routine
157  * converts ZFS acl to Posix acl if required.
158  */
159 uint32_t
smb_sd_write(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)160 smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
161 {
162 	smb_node_t *node;
163 	smb_fssd_t fs_sd;
164 	uint32_t status;
165 	uint32_t sd_flags;
166 	int error;
167 
168 	node = sr->fid_ofile->f_node;
169 	sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
170 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
171 
172 	status = smb_sd_tofs(sd, &fs_sd);
173 	if (status != NT_STATUS_SUCCESS) {
174 		smb_fssd_term(&fs_sd);
175 		return (status);
176 	}
177 
178 	error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
179 	smb_fssd_term(&fs_sd);
180 
181 	if (error) {
182 		if (error == EBADE)
183 			return (NT_STATUS_INVALID_OWNER);
184 		return (smb_errno2status(error));
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
smb_sd_tofs(smb_sd_t * sd,smb_fssd_t * fs_sd)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 	/*
250 	 * In SMB, the 'secinfo' determines which parts of the SD the client
251 	 * intends to change. Notably, this includes changing the DACL_PRESENT
252 	 * and SACL_PRESENT control bits. The client can specify e.g.
253 	 * SACL_SECINFO, but not SACL_PRESENT, and this means the client intends
254 	 * to remove the SACL.
255 	 *
256 	 * Note that Windows behavior differs from that described in [MS-DTYP].
257 	 * MS-DTYP states that the offset is nonzero if-and-only-if the PRESENT
258 	 * bit is set. It also states that a DACL that is marked non-present
259 	 * is equivalent to 'no security', but one that is marked present and
260 	 * provides no ACEs is equivalent to 'no access'.
261 	 *
262 	 * Windows, on the other hand, allows the offset to be 0 even when
263 	 * the PRESENT bit is set, and only provides security when the DACL
264 	 * offset is non-zero. It will also convert an SD where the DACL is
265 	 * marked not-present to one where the PRESENT bit is set and the
266 	 * offset is 0.
267 	 *
268 	 * If the *_PRESENT bit isn't set, then the respective ACL will be NULL.
269 	 * For the fssd, we allow the SACL to be NULL, but we MUST have a DACL.
270 	 * If the DACL is NULL, that's equivalent to "everyone:full_set:allow".
271 	 *
272 	 * The IMPLY's should be enforced by smb_decode_sd().
273 	 */
274 
275 	/* DACL */
276 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
277 		IMPLY(sd->sd_dacl != NULL,
278 		    (sd->sd_control & SE_DACL_PRESENT) != 0);
279 		status = smb_acl_to_zfs(sd->sd_dacl, flags,
280 		    SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
281 		if (status != NT_STATUS_SUCCESS)
282 			return (status);
283 	}
284 
285 	/* SACL */
286 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
287 		IMPLY(sd->sd_sacl != NULL,
288 		    (sd->sd_control & SE_SACL_PRESENT) != 0);
289 		if (sd->sd_control & SE_SACL_PRESENT) {
290 			status = smb_acl_to_zfs(sd->sd_sacl, flags,
291 			    SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
292 			if (status != NT_STATUS_SUCCESS) {
293 				return (status);
294 			}
295 		}
296 	}
297 
298 	return (status);
299 }
300 
301 /*
302  * smb_sd_fromfs
303  *
304  * Makes an Windows style security descriptor in absolute form
305  * based on the given filesystem security information.
306  *
307  * Should call smb_sd_term() for the returned sd to free allocated
308  * members.
309  */
310 static uint32_t
smb_sd_fromfs(smb_fssd_t * fs_sd,smb_sd_t * sd)311 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
312 {
313 	uint32_t status = NT_STATUS_SUCCESS;
314 	smb_acl_t *acl = NULL;
315 	smb_sid_t *sid;
316 	idmap_stat idm_stat;
317 
318 	ASSERT(fs_sd);
319 	ASSERT(sd);
320 
321 	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
322 
323 	/* Owner */
324 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
325 		idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
326 		    SMB_IDMAP_USER, &sid);
327 
328 		if (idm_stat != IDMAP_SUCCESS) {
329 			smb_sd_term(sd);
330 			return (NT_STATUS_NONE_MAPPED);
331 		}
332 
333 		sd->sd_owner = sid;
334 	}
335 
336 	/* Group */
337 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
338 		idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
339 		    SMB_IDMAP_GROUP, &sid);
340 
341 		if (idm_stat != IDMAP_SUCCESS) {
342 			smb_sd_term(sd);
343 			return (NT_STATUS_NONE_MAPPED);
344 		}
345 
346 		sd->sd_group = sid;
347 	}
348 
349 	/* DACL */
350 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
351 		if (fs_sd->sd_zdacl != NULL) {
352 			acl = smb_acl_from_zfs(fs_sd->sd_zdacl);
353 			if (acl == NULL) {
354 				smb_sd_term(sd);
355 				return (NT_STATUS_INTERNAL_ERROR);
356 			}
357 
358 			/*
359 			 * Need to sort the ACL before send it to Windows
360 			 * clients. Winodws GUI is sensitive about the order
361 			 * of ACEs.
362 			 */
363 			smb_acl_sort(acl);
364 			smb_sd_set_dacl(sd, acl, B_TRUE,
365 			    fs_sd->sd_zdacl->acl_flags);
366 		} else {
367 			smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
368 		}
369 	}
370 
371 	/* SACL */
372 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
373 		if (fs_sd->sd_zsacl != NULL) {
374 			acl = smb_acl_from_zfs(fs_sd->sd_zsacl);
375 			if (acl == NULL) {
376 				smb_sd_term(sd);
377 				return (NT_STATUS_INTERNAL_ERROR);
378 			}
379 
380 			smb_sd_set_sacl(sd, acl, B_TRUE,
381 			    fs_sd->sd_zsacl->acl_flags);
382 		} else {
383 			smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
384 		}
385 	}
386 
387 	return (status);
388 }
389 
390 static void
smb_sd_set_dacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)391 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
392 {
393 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
394 
395 	sd->sd_dacl = acl;
396 
397 	if (flags & ACL_DEFAULTED)
398 		sd->sd_control |= SE_DACL_DEFAULTED;
399 	if (flags & ACL_AUTO_INHERIT)
400 		sd->sd_control |= SE_DACL_AUTO_INHERITED;
401 	if (flags & ACL_PROTECTED)
402 		sd->sd_control |= SE_DACL_PROTECTED;
403 
404 	if (present)
405 		sd->sd_control |= SE_DACL_PRESENT;
406 }
407 
408 static void
smb_sd_set_sacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)409 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
410 {
411 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
412 
413 	sd->sd_sacl = acl;
414 
415 	if (flags & ACL_DEFAULTED)
416 		sd->sd_control |= SE_SACL_DEFAULTED;
417 	if (flags & ACL_AUTO_INHERIT)
418 		sd->sd_control |= SE_SACL_AUTO_INHERITED;
419 	if (flags & ACL_PROTECTED)
420 		sd->sd_control |= SE_SACL_PROTECTED;
421 
422 	if (present)
423 		sd->sd_control |= SE_SACL_PRESENT;
424 }
425 
426 /*
427  * smb_fssd_init
428  *
429  * Initializes the given FS SD structure.
430  */
431 void
smb_fssd_init(smb_fssd_t * fs_sd,uint32_t secinfo,uint32_t flags)432 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
433 {
434 	bzero(fs_sd, sizeof (smb_fssd_t));
435 	fs_sd->sd_secinfo = secinfo;
436 	fs_sd->sd_flags = flags;
437 }
438 
439 /*
440  * smb_fssd_term
441  *
442  * Frees allocated memory for acl fields.
443  */
444 void
smb_fssd_term(smb_fssd_t * fs_sd)445 smb_fssd_term(smb_fssd_t *fs_sd)
446 {
447 	ASSERT(fs_sd);
448 
449 	smb_fsacl_free(fs_sd->sd_zdacl);
450 	smb_fsacl_free(fs_sd->sd_zsacl);
451 	bzero(fs_sd, sizeof (smb_fssd_t));
452 }
453