xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_sd.c (revision d11e14a72ad0bfccf84405261d5d93e6eaafe6a7)
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 2020 Nexenta 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
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
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
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 uint32_t
94 smb_sd_get_secinfo(smb_sd_t *sd)
95 {
96 	uint32_t sec_info = 0;
97 
98 	if (sd == NULL)
99 		return (0);
100 
101 	if (sd->sd_owner)
102 		sec_info |= SMB_OWNER_SECINFO;
103 
104 	if (sd->sd_group)
105 		sec_info |= SMB_GROUP_SECINFO;
106 
107 	if (sd->sd_dacl)
108 		sec_info |= SMB_DACL_SECINFO;
109 
110 	if (sd->sd_sacl)
111 		sec_info |= SMB_SACL_SECINFO;
112 
113 	return (sec_info);
114 }
115 
116 /*
117  * smb_sd_read
118  *
119  * Read uid, gid and ACL from filesystem. The returned ACL from read
120  * routine is always in ZFS format. Convert the ZFS acl to a Win acl
121  * and return the Win SD in absolute form.
122  *
123  * NOTE: upon successful return caller MUST free the memory allocated
124  * for the returned SD by calling smb_sd_term().
125  */
126 uint32_t
127 smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
128 {
129 	smb_fssd_t fs_sd;
130 	smb_node_t *node;
131 	uint32_t status = NT_STATUS_SUCCESS;
132 	uint32_t sd_flags;
133 	int error;
134 
135 	node = sr->fid_ofile->f_node;
136 	sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
137 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
138 
139 	error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
140 	if (error)
141 		return (smb_errno2status(error));
142 
143 	status = smb_sd_fromfs(&fs_sd, sd);
144 	smb_fssd_term(&fs_sd);
145 
146 	return (status);
147 }
148 
149 /*
150  * smb_sd_write
151  *
152  * Takes a Win SD in absolute form, converts it to
153  * ZFS format and write it to filesystem. The write routine
154  * converts ZFS acl to Posix acl if required.
155  */
156 uint32_t
157 smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
158 {
159 	smb_node_t *node;
160 	smb_fssd_t fs_sd;
161 	uint32_t status;
162 	uint32_t sd_flags;
163 	int error;
164 
165 	node = sr->fid_ofile->f_node;
166 	sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
167 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
168 
169 	status = smb_sd_tofs(sd, &fs_sd);
170 	if (status != NT_STATUS_SUCCESS) {
171 		smb_fssd_term(&fs_sd);
172 		return (status);
173 	}
174 
175 	error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
176 	smb_fssd_term(&fs_sd);
177 
178 	if (error) {
179 		if (error == EBADE)
180 			return (NT_STATUS_INVALID_OWNER);
181 		return (smb_errno2status(error));
182 	}
183 
184 	return (NT_STATUS_SUCCESS);
185 }
186 
187 
188 /*
189  * smb_sd_tofs
190  *
191  * Creates a filesystem security structure based on the given
192  * Windows security descriptor.
193  */
194 uint32_t
195 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
196 {
197 	smb_sid_t *sid;
198 	uint32_t status = NT_STATUS_SUCCESS;
199 	uint16_t sd_control;
200 	idmap_stat idm_stat;
201 	int idtype;
202 	int flags = 0;
203 
204 	sd_control = sd->sd_control;
205 
206 	/*
207 	 * ZFS only has one set of flags so for now only
208 	 * Windows DACL flags are taken into account.
209 	 */
210 	if (sd_control & SE_DACL_DEFAULTED)
211 		flags |= ACL_DEFAULTED;
212 	if (sd_control & SE_DACL_AUTO_INHERITED)
213 		flags |= ACL_AUTO_INHERIT;
214 	if (sd_control & SE_DACL_PROTECTED)
215 		flags |= ACL_PROTECTED;
216 
217 	if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
218 		flags |= ACL_IS_DIR;
219 
220 	/* Owner */
221 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
222 		sid = sd->sd_owner;
223 		if (!smb_sid_isvalid(sid))
224 			return (NT_STATUS_INVALID_SID);
225 
226 		idtype = SMB_IDMAP_USER;
227 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
228 		if (idm_stat != IDMAP_SUCCESS) {
229 			return (NT_STATUS_NONE_MAPPED);
230 		}
231 	}
232 
233 	/* Group */
234 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
235 		sid = sd->sd_group;
236 		if (!smb_sid_isvalid(sid))
237 			return (NT_STATUS_INVALID_SID);
238 
239 		idtype = SMB_IDMAP_GROUP;
240 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
241 		if (idm_stat != IDMAP_SUCCESS) {
242 			return (NT_STATUS_NONE_MAPPED);
243 		}
244 	}
245 
246 	/*
247 	 * In SMB, the 'secinfo' determines which parts of the SD the client
248 	 * intends to change. Notably, this includes changing the DACL_PRESENT
249 	 * and SACL_PRESENT control bits. The client can specify e.g.
250 	 * SACL_SECINFO, but not SACL_PRESENT, and this means the client intends
251 	 * to remove the SACL.
252 	 *
253 	 * If the *_PRESENT bit isn't set, then the respective ACL will be NULL.
254 	 * [MS-DTYP] disallows providing an ACL when the PRESENT bit isn't set.
255 	 * This is enforced by smb_decode_sd().
256 	 *
257 	 * We allow the SACL to be NULL, but we MUST have a DACL.
258 	 * If the DACL is NULL, that's equivalent to "everyone:full_set:allow".
259 	 */
260 
261 	/* DACL */
262 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
263 		ASSERT3U(((sd->sd_control & SE_DACL_PRESENT) != 0), ==,
264 		    (sd->sd_dacl != NULL));
265 		status = smb_acl_to_zfs(sd->sd_dacl, flags,
266 		    SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
267 		if (status != NT_STATUS_SUCCESS)
268 			return (status);
269 	}
270 
271 	/* SACL */
272 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
273 		if (sd->sd_control & SE_SACL_PRESENT) {
274 			status = smb_acl_to_zfs(sd->sd_sacl, flags,
275 			    SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
276 			if (status != NT_STATUS_SUCCESS) {
277 				return (status);
278 			}
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 	smb_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);
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);
359 			if (acl == NULL) {
360 				smb_sd_term(sd);
361 				return (NT_STATUS_INTERNAL_ERROR);
362 			}
363 
364 			smb_sd_set_sacl(sd, acl, B_TRUE,
365 			    fs_sd->sd_zsacl->acl_flags);
366 		} else {
367 			smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
368 		}
369 	}
370 
371 	return (status);
372 }
373 
374 static void
375 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
376 {
377 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
378 
379 	sd->sd_dacl = acl;
380 
381 	if (flags & ACL_DEFAULTED)
382 		sd->sd_control |= SE_DACL_DEFAULTED;
383 	if (flags & ACL_AUTO_INHERIT)
384 		sd->sd_control |= SE_DACL_AUTO_INHERITED;
385 	if (flags & ACL_PROTECTED)
386 		sd->sd_control |= SE_DACL_PROTECTED;
387 
388 	if (present)
389 		sd->sd_control |= SE_DACL_PRESENT;
390 }
391 
392 static void
393 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
394 {
395 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
396 
397 	sd->sd_sacl = acl;
398 
399 	if (flags & ACL_DEFAULTED)
400 		sd->sd_control |= SE_SACL_DEFAULTED;
401 	if (flags & ACL_AUTO_INHERIT)
402 		sd->sd_control |= SE_SACL_AUTO_INHERITED;
403 	if (flags & ACL_PROTECTED)
404 		sd->sd_control |= SE_SACL_PROTECTED;
405 
406 	if (present)
407 		sd->sd_control |= SE_SACL_PRESENT;
408 }
409 
410 /*
411  * smb_fssd_init
412  *
413  * Initializes the given FS SD structure.
414  */
415 void
416 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
417 {
418 	bzero(fs_sd, sizeof (smb_fssd_t));
419 	fs_sd->sd_secinfo = secinfo;
420 	fs_sd->sd_flags = flags;
421 }
422 
423 /*
424  * smb_fssd_term
425  *
426  * Frees allocated memory for acl fields.
427  */
428 void
429 smb_fssd_term(smb_fssd_t *fs_sd)
430 {
431 	ASSERT(fs_sd);
432 
433 	smb_fsacl_free(fs_sd->sd_zdacl);
434 	smb_fsacl_free(fs_sd->sd_zsacl);
435 	bzero(fs_sd, sizeof (smb_fssd_t));
436 }
437