xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_sd.c (revision fe1c642d06e14b412cd83ae2179303186ab08972)
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 2009 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 <strings.h>
31 #include <assert.h>
32 #include <smbsrv/ntifs.h>
33 #include <smbsrv/smb_idmap.h>
34 #include <smbsrv/ntstatus.h>
35 #include <smbsrv/libsmb.h>
36 
37 #define	SMB_SHR_ACE_READ_PERMS	(ACE_READ_PERMS | ACE_EXECUTE | ACE_SYNCHRONIZE)
38 #define	SMB_SHR_ACE_CONTROL_PERMS	(ACE_MODIFY_PERMS & (~ACE_DELETE_CHILD))
39 
40 #define	SMB_SHR_ACE_MODIFY_PERMS	(ACE_MODIFY_PERMS &		\
41 	(~(ACE_READ_DATA | ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |	\
42 	ACE_EXECUTE | ACE_DELETE_CHILD)))
43 
44 static struct {
45 	int am_ace_perms;
46 	int am_share_perms;
47 } smb_ace_map[] = {
48 	{ ACE_ALL_PERMS,	ACE_ALL_PERMS },
49 	{ ACE_MODIFY_PERMS,	SMB_SHR_ACE_CONTROL_PERMS },
50 	{ ACE_MODIFY_PERMS,	SMB_SHR_ACE_MODIFY_PERMS },
51 	{ ACE_READ_PERMS,	SMB_SHR_ACE_READ_PERMS }
52 };
53 
54 #define	SMB_ACE_MASK_MAP_SIZE	(sizeof (smb_ace_map)/sizeof (smb_ace_map[0]))
55 
56 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
57 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
58 
59 void
60 smb_sd_init(smb_sd_t *sd, uint8_t revision)
61 {
62 	bzero(sd, sizeof (smb_sd_t));
63 	sd->sd_revision = revision;
64 }
65 
66 /*
67  * smb_sd_term
68  *
69  * Free non-NULL members of 'sd' which has to be in
70  * absolute (pointer) form.
71  */
72 void
73 smb_sd_term(smb_sd_t *sd)
74 {
75 	assert(sd);
76 	assert((sd->sd_control & SE_SELF_RELATIVE) == 0);
77 
78 	smb_sid_free(sd->sd_owner);
79 	smb_sid_free(sd->sd_group);
80 	smb_acl_free(sd->sd_dacl);
81 	smb_acl_free(sd->sd_sacl);
82 
83 	bzero(sd, sizeof (smb_sd_t));
84 }
85 
86 uint32_t
87 smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
88 {
89 	uint32_t length = SMB_SD_HDRSIZE;
90 
91 	if (secinfo & SMB_OWNER_SECINFO)
92 		length += smb_sid_len(sd->sd_owner);
93 
94 	if (secinfo & SMB_GROUP_SECINFO)
95 		length += smb_sid_len(sd->sd_group);
96 
97 	if (secinfo & SMB_DACL_SECINFO)
98 		length += smb_acl_len(sd->sd_dacl);
99 
100 	if (secinfo & SMB_SACL_SECINFO)
101 		length += smb_acl_len(sd->sd_sacl);
102 
103 	return (length);
104 }
105 
106 /*
107  * smb_sd_get_secinfo
108  *
109  * Return the security information mask for the specified security
110  * descriptor.
111  */
112 uint32_t
113 smb_sd_get_secinfo(smb_sd_t *sd)
114 {
115 	uint32_t sec_info = 0;
116 
117 	if (sd == NULL)
118 		return (0);
119 
120 	if (sd->sd_owner)
121 		sec_info |= SMB_OWNER_SECINFO;
122 
123 	if (sd->sd_group)
124 		sec_info |= SMB_GROUP_SECINFO;
125 
126 	if (sd->sd_dacl)
127 		sec_info |= SMB_DACL_SECINFO;
128 
129 	if (sd->sd_sacl)
130 		sec_info |= SMB_SACL_SECINFO;
131 
132 	return (sec_info);
133 }
134 
135 /*
136  * Adjust the Access Mask so that ZFS ACE mask and Windows ACE read mask match.
137  */
138 static int
139 smb_sd_adjust_read_mask(int mask)
140 {
141 	int i;
142 
143 	for (i = 0; i < SMB_ACE_MASK_MAP_SIZE; ++i) {
144 		if (smb_ace_map[i].am_ace_perms == mask)
145 			return (smb_ace_map[i].am_share_perms);
146 	}
147 
148 	return (-1);
149 }
150 
151 /*
152  * Get ZFS acl from the share path via acl_get() method.
153  */
154 static uint32_t
155 smb_sd_read_acl(char *path, smb_fssd_t *fs_sd)
156 {
157 	acl_t *z_acl;
158 	ace_t *z_ace;
159 	int mask;
160 
161 	fs_sd->sd_gid = fs_sd->sd_uid = 0;
162 	if (acl_trivial(path) != 1)
163 		return (NT_STATUS_INTERNAL_ERROR);
164 
165 	if (acl_get(path, ACL_NO_TRIVIAL, &z_acl) != 0)
166 		return (NT_STATUS_INTERNAL_ERROR);
167 
168 	if ((z_ace = (ace_t *)z_acl->acl_aclp) == NULL)
169 		return (NT_STATUS_INVALID_ACL);
170 
171 	for (int i = 0; i < z_acl->acl_cnt; i++, z_ace++) {
172 		mask = smb_sd_adjust_read_mask(z_ace->a_access_mask);
173 		if (mask == -1)
174 			return (NT_STATUS_INVALID_ACL);
175 		z_ace->a_access_mask = mask;
176 	}
177 
178 	fs_sd->sd_zdacl = z_acl;
179 	fs_sd->sd_zsacl = NULL;
180 	return (NT_STATUS_SUCCESS);
181 }
182 
183 /*
184  * smb_sd_read
185  *
186  * Reads ZFS acl from filesystem using acl_get() method. Convert the ZFS acl to
187  * a Win SD and return the Win SD in absolute form.
188  *
189  * NOTE: upon successful return caller MUST free the memory allocated
190  * for the returned SD by calling smb_sd_term().
191  */
192 uint32_t
193 smb_sd_read(char *path, smb_sd_t *sd, uint32_t secinfo)
194 {
195 	smb_fssd_t fs_sd;
196 	uint32_t status = NT_STATUS_SUCCESS;
197 	uint32_t sd_flags;
198 	int error;
199 
200 	sd_flags = SMB_FSSD_FLAGS_DIR;
201 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
202 
203 	error = smb_sd_read_acl(path, &fs_sd);
204 	if (error != NT_STATUS_SUCCESS) {
205 		smb_fssd_term(&fs_sd);
206 		return (error);
207 	}
208 
209 	status = smb_sd_fromfs(&fs_sd, sd);
210 	smb_fssd_term(&fs_sd);
211 
212 	return (status);
213 }
214 
215 /*
216  * Adjust the Access Mask so that ZFS ACE mask and Windows ACE write mask match.
217  */
218 static int
219 smb_sd_adjust_write_mask(int mask)
220 {
221 	int i;
222 
223 	for (i = 0; i < SMB_ACE_MASK_MAP_SIZE; ++i) {
224 		if (smb_ace_map[i].am_share_perms == mask)
225 			return (smb_ace_map[i].am_ace_perms);
226 	}
227 
228 	return (-1);
229 }
230 
231 /*
232  * Apply ZFS acl to the share path via acl_set() method.
233  */
234 static uint32_t
235 smb_sd_write_acl(char *path, smb_fssd_t *fs_sd)
236 {
237 	acl_t *z_acl;
238 	ace_t *z_ace;
239 	int mask;
240 	uint32_t status = NT_STATUS_SUCCESS;
241 
242 	if ((z_acl = fs_sd->sd_zdacl) == NULL)
243 		return (NT_STATUS_INVALID_ACL);
244 
245 	if ((z_ace = (ace_t *)z_acl->acl_aclp) == NULL)
246 		return (NT_STATUS_INVALID_ACL);
247 
248 	for (int i = 0; i < z_acl->acl_cnt; i++, z_ace++) {
249 		mask = smb_sd_adjust_write_mask(z_ace->a_access_mask);
250 		if (mask == -1)
251 			return (NT_STATUS_INVALID_ACL);
252 		z_ace->a_access_mask = mask;
253 	}
254 
255 	fs_sd->sd_gid = fs_sd->sd_uid = 0;
256 	if (acl_set(path, z_acl) != 0)
257 		status = NT_STATUS_INTERNAL_ERROR;
258 
259 	return (status);
260 }
261 
262 /*
263  * smb_sd_write
264  *
265  * Takes a Win SD in absolute form, converts it to
266  * ZFS acl and applies the acl to the share path via acl_set() method.
267  */
268 uint32_t
269 smb_sd_write(char *path, smb_sd_t *sd, uint32_t secinfo)
270 {
271 	smb_fssd_t fs_sd;
272 	uint32_t status = NT_STATUS_SUCCESS;
273 	uint32_t sd_flags;
274 	int error;
275 
276 	sd_flags = SMB_FSSD_FLAGS_DIR;
277 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
278 
279 	error = smb_sd_tofs(sd, &fs_sd);
280 	if (error != NT_STATUS_SUCCESS) {
281 		smb_fssd_term(&fs_sd);
282 		return (error);
283 	}
284 
285 	status = smb_sd_write_acl(path, &fs_sd);
286 	smb_fssd_term(&fs_sd);
287 
288 	return (status);
289 }
290 
291 /*
292  * smb_sd_tofs
293  *
294  * Creates a filesystem security structure based on the given
295  * Windows security descriptor.
296  */
297 uint32_t
298 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
299 {
300 	smb_sid_t *sid;
301 	uint32_t status = NT_STATUS_SUCCESS;
302 	uint16_t sd_control;
303 	idmap_stat idm_stat;
304 	int idtype;
305 	int flags = 0;
306 
307 	sd_control = sd->sd_control;
308 
309 	/*
310 	 * ZFS only has one set of flags so for now only
311 	 * Windows DACL flags are taken into account.
312 	 */
313 	if (sd_control & SE_DACL_DEFAULTED)
314 		flags |= ACL_DEFAULTED;
315 	if (sd_control & SE_DACL_AUTO_INHERITED)
316 		flags |= ACL_AUTO_INHERIT;
317 	if (sd_control & SE_DACL_PROTECTED)
318 		flags |= ACL_PROTECTED;
319 
320 	if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
321 		flags |= ACL_IS_DIR;
322 
323 	/* Owner */
324 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
325 		sid = sd->sd_owner;
326 		if (!smb_sid_isvalid(sid))
327 			return (NT_STATUS_INVALID_SID);
328 
329 		idtype = SMB_IDMAP_USER;
330 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
331 		if (idm_stat != IDMAP_SUCCESS) {
332 			return (NT_STATUS_NONE_MAPPED);
333 		}
334 	}
335 
336 	/* Group */
337 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
338 		sid = sd->sd_group;
339 		if (!smb_sid_isvalid(sid))
340 			return (NT_STATUS_INVALID_SID);
341 
342 		idtype = SMB_IDMAP_GROUP;
343 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
344 		if (idm_stat != IDMAP_SUCCESS) {
345 			return (NT_STATUS_NONE_MAPPED);
346 		}
347 	}
348 
349 	/* DACL */
350 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
351 		if (sd->sd_control & SE_DACL_PRESENT) {
352 			status = smb_acl_to_zfs(sd->sd_dacl, flags,
353 			    SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
354 			if (status != NT_STATUS_SUCCESS)
355 				return (status);
356 		}
357 		else
358 			return (NT_STATUS_INVALID_ACL);
359 	}
360 
361 	/* SACL */
362 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
363 		if (sd->sd_control & SE_SACL_PRESENT) {
364 			status = smb_acl_to_zfs(sd->sd_sacl, flags,
365 			    SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
366 			if (status != NT_STATUS_SUCCESS) {
367 				return (status);
368 			}
369 		} else {
370 			return (NT_STATUS_INVALID_ACL);
371 		}
372 	}
373 
374 	return (status);
375 }
376 
377 /*
378  * smb_sd_fromfs
379  *
380  * Makes an Windows style security descriptor in absolute form
381  * based on the given filesystem security information.
382  *
383  * Should call smb_sd_term() for the returned sd to free allocated
384  * members.
385  */
386 uint32_t
387 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
388 {
389 	uint32_t status = NT_STATUS_SUCCESS;
390 	smb_acl_t *acl = NULL;
391 	smb_sid_t *sid;
392 	idmap_stat idm_stat;
393 
394 	assert(fs_sd);
395 	assert(sd);
396 
397 	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
398 
399 	/* Owner */
400 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
401 		idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
402 		    SMB_IDMAP_USER, &sid);
403 
404 		if (idm_stat != IDMAP_SUCCESS) {
405 			smb_sd_term(sd);
406 			return (NT_STATUS_NONE_MAPPED);
407 		}
408 
409 		sd->sd_owner = sid;
410 	}
411 
412 	/* Group */
413 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
414 		idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
415 		    SMB_IDMAP_GROUP, &sid);
416 
417 		if (idm_stat != IDMAP_SUCCESS) {
418 			smb_sd_term(sd);
419 			return (NT_STATUS_NONE_MAPPED);
420 		}
421 
422 		sd->sd_group = sid;
423 	}
424 
425 	/* DACL */
426 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
427 		if (fs_sd->sd_zdacl != NULL) {
428 			acl = smb_acl_from_zfs(fs_sd->sd_zdacl, fs_sd->sd_uid,
429 			    fs_sd->sd_gid);
430 			if (acl == NULL) {
431 				smb_sd_term(sd);
432 				return (NT_STATUS_INTERNAL_ERROR);
433 			}
434 
435 			/*
436 			 * Need to sort the ACL before send it to Windows
437 			 * clients. Winodws GUI is sensitive about the order
438 			 * of ACEs.
439 			 */
440 			smb_acl_sort(acl);
441 			smb_sd_set_dacl(sd, acl, B_TRUE,
442 			    fs_sd->sd_zdacl->acl_flags);
443 		} else {
444 			smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
445 		}
446 	}
447 
448 	/* SACL */
449 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
450 		if (fs_sd->sd_zsacl != NULL) {
451 			acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid,
452 			    fs_sd->sd_gid);
453 			if (acl == NULL) {
454 				smb_sd_term(sd);
455 				return (NT_STATUS_INTERNAL_ERROR);
456 			}
457 
458 			smb_sd_set_sacl(sd, acl, B_TRUE,
459 			    fs_sd->sd_zsacl->acl_flags);
460 		} else {
461 			smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
462 		}
463 	}
464 
465 	return (status);
466 }
467 
468 static void
469 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
470 {
471 	assert((sd->sd_control & SE_SELF_RELATIVE) == 0);
472 
473 	sd->sd_dacl = acl;
474 
475 	if (flags & ACL_DEFAULTED)
476 		sd->sd_control |= SE_DACL_DEFAULTED;
477 	if (flags & ACL_AUTO_INHERIT)
478 		sd->sd_control |= SE_DACL_AUTO_INHERITED;
479 	if (flags & ACL_PROTECTED)
480 		sd->sd_control |= SE_DACL_PROTECTED;
481 
482 	if (present)
483 		sd->sd_control |= SE_DACL_PRESENT;
484 }
485 
486 static void
487 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
488 {
489 	assert((sd->sd_control & SE_SELF_RELATIVE) == 0);
490 
491 	sd->sd_sacl = acl;
492 
493 	if (flags & ACL_DEFAULTED)
494 		sd->sd_control |= SE_SACL_DEFAULTED;
495 	if (flags & ACL_AUTO_INHERIT)
496 		sd->sd_control |= SE_SACL_AUTO_INHERITED;
497 	if (flags & ACL_PROTECTED)
498 		sd->sd_control |= SE_SACL_PROTECTED;
499 
500 	if (present)
501 		sd->sd_control |= SE_SACL_PRESENT;
502 }
503 
504 /*
505  * smb_fssd_init
506  *
507  * Initializes the given FS SD structure.
508  */
509 void
510 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
511 {
512 	bzero(fs_sd, sizeof (smb_fssd_t));
513 	fs_sd->sd_secinfo = secinfo;
514 	fs_sd->sd_flags = flags;
515 }
516 
517 /*
518  * smb_fssd_term
519  *
520  * Frees allocated memory for acl fields.
521  */
522 void
523 smb_fssd_term(smb_fssd_t *fs_sd)
524 {
525 	assert(fs_sd);
526 
527 	acl_free(fs_sd->sd_zdacl);
528 	acl_free(fs_sd->sd_zsacl);
529 
530 	bzero(fs_sd, sizeof (smb_fssd_t));
531 }
532