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