xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_sd.c (revision 87b817582bc68a9992ad7109bd09617975ea4725)
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 /*
23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 /*
28  * This is a helper file to get/set Windows SD. This is used by
29  * SRVSVC service.
30  */
31 #include <strings.h>
32 #include <libzfs.h>
33 
34 #include <smbsrv/libsmb.h>
35 #include <smbsrv/libmlsvc.h>
36 #include <smbsrv/ndl/srvsvc.ndl>
37 
38 /* Size of offset members in mslm_security_descriptor structure */
39 #define	SRVSVC_SD_OFFSET_SZ	16
40 
41 #define	SRVSVC_ACE_OFFSET	8
42 #define	SRVSVC_SID_OFFSET	8
43 
44 uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *);
45 
46 static uint32_t srvsvc_sd_get_autohome(const smb_share_t *, smb_sd_t *);
47 static uint32_t srvsvc_sd_status_to_error(uint32_t);
48 static uint32_t srvsvc_sd_set_absolute(uint8_t *, smb_sd_t *);
49 
50 /*
51  * This method computes ACL on share path from a share name.
52  * Return 0 upon success, -1 upon failure.
53  */
54 static int
srvsvc_shareacl_getpath(smb_share_t * si,char * shr_acl_path)55 srvsvc_shareacl_getpath(smb_share_t *si, char *shr_acl_path)
56 {
57 	char dataset[MAXPATHLEN];
58 	char mp[ZFS_MAXPROPLEN];
59 	libzfs_handle_t *libhd;
60 	zfs_handle_t *zfshd;
61 	int ret = 0;
62 
63 	if ((libhd = libzfs_init()) == NULL)
64 		return (-1);
65 
66 	ret = smb_getdataset(libhd, si->shr_path, dataset, MAXPATHLEN);
67 	if (ret != 0) {
68 		libzfs_fini(libhd);
69 		return (ret);
70 	}
71 
72 
73 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) {
74 		libzfs_fini(libhd);
75 		return (-1);
76 	}
77 
78 	if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL,
79 	    NULL, 0, B_FALSE) != 0) {
80 		zfs_close(zfshd);
81 		libzfs_fini(libhd);
82 		return (-1);
83 	}
84 
85 	zfs_close(zfshd);
86 	libzfs_fini(libhd);
87 
88 	(void) snprintf(shr_acl_path, MAXPATHLEN, "%s/.zfs/shares/%s",
89 	    mp, si->shr_name);
90 
91 	return (ret);
92 }
93 
94 /*
95  * This method sets Security Descriptor on a share path.
96  *
97  * Returns:
98  *	ERROR_SUCCESS
99  *	ERROR_NOT_ENOUGH_MEMORY
100  *	ERROR_INVALID_ACL
101  *	ERROR_INVALID_SID
102  *	ERROR_INVALID_SECURITY_DESCR
103  *	ERROR_NONE_MAPPED
104  *	ERROR_INTERNAL_ERROR
105  *	ERROR_PATH_NOT_FOUND
106  */
107 uint32_t
srvsvc_sd_set(smb_share_t * si,uint8_t * sdbuf)108 srvsvc_sd_set(smb_share_t *si, uint8_t *sdbuf)
109 {
110 	smb_sd_t sd;
111 	uint32_t status = ERROR_SUCCESS;
112 	char path[MAXPATHLEN];
113 	int ret = 0;
114 
115 	ret = srvsvc_shareacl_getpath(si, path);
116 	if (ret != 0)
117 		return (ERROR_PATH_NOT_FOUND);
118 
119 	smb_sd_init(&sd, 0);
120 	status = srvsvc_sd_set_absolute(sdbuf, &sd);
121 	if (status != ERROR_SUCCESS) {
122 		smb_sd_term(&sd);
123 		return (status);
124 	}
125 
126 	status = smb_sd_write(path, &sd, SMB_DACL_SECINFO);
127 	status = srvsvc_sd_status_to_error(status);
128 	smb_sd_term(&sd);
129 
130 	return (status);
131 }
132 
133 /*
134  * This method returns a Security Descriptor of a share path in self relative
135  * format. Call to this function with NULL buffer, returns the size of the
136  * security descriptor, which can be used to allocate buffer.
137  *
138  * Returns:
139  *	ERROR_SUCCESS
140  *	ERROR_NOT_ENOUGH_MEMORY
141  *	ERROR_INVALID_ACL
142  *	ERROR_INVALID_SID
143  *	ERROR_INVALID_SECURITY_DESCR
144  *	ERROR_INVALID_PARAMETER
145  *	ERROR_NONE_MAPPED
146  *	ERROR_INTERNAL_ERROR
147  *	ERROR_PATH_NOT_FOUND
148  */
149 uint32_t
srvsvc_sd_get(smb_share_t * si,uint8_t * sdbuf,uint32_t * size)150 srvsvc_sd_get(smb_share_t *si, uint8_t *sdbuf, uint32_t *size)
151 {
152 	smb_sd_t sd;
153 	uint32_t status = ERROR_SUCCESS;
154 	char path[MAXPATHLEN];
155 	int ret = 0;
156 
157 	if (sdbuf == NULL && size == NULL)
158 		return (ERROR_INVALID_PARAMETER);
159 
160 	bzero(&sd, sizeof (smb_sd_t));
161 
162 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
163 		status = srvsvc_sd_get_autohome(si, &sd);
164 	} else {
165 		ret = srvsvc_shareacl_getpath(si, path);
166 		if (ret != 0)
167 			return (ERROR_PATH_NOT_FOUND);
168 
169 		status = smb_sd_read(path, &sd, SMB_ALL_SECINFO);
170 		status = srvsvc_sd_status_to_error(status);
171 	}
172 
173 	if (status != ERROR_SUCCESS) {
174 		smb_sd_term(&sd);
175 		return (status);
176 	}
177 
178 	if (sdbuf == NULL) {
179 		*size = smb_sd_len(&sd, SMB_ALL_SECINFO);
180 		smb_sd_term(&sd);
181 		return (status);
182 	}
183 
184 	status = srvsvc_sd_set_relative(&sd, sdbuf);
185 
186 	smb_sd_term(&sd);
187 	return (status);
188 }
189 
190 static uint32_t
srvsvc_sd_get_autohome(const smb_share_t * si,smb_sd_t * sd)191 srvsvc_sd_get_autohome(const smb_share_t *si, smb_sd_t *sd)
192 {
193 	smb_fssd_t	fs_sd;
194 	acl_t		*acl;
195 	uint32_t	status;
196 
197 	if (acl_fromtext("owner@:rwxpdDaARWcCos::allow", &acl) != 0)
198 		return (ERROR_NOT_ENOUGH_MEMORY);
199 
200 	smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR);
201 	fs_sd.sd_uid = si->shr_uid;
202 	fs_sd.sd_gid = si->shr_gid;
203 	fs_sd.sd_zdacl = acl;
204 	fs_sd.sd_zsacl = NULL;
205 
206 	status = smb_sd_fromfs(&fs_sd, sd);
207 	status = srvsvc_sd_status_to_error(status);
208 	smb_fssd_term(&fs_sd);
209 	return (status);
210 }
211 
212 /*
213  * This method converts an ACE from absolute (pointer) to
214  * self relative (flat buffer) format.
215  *
216  * Returns Win32 error codes.
217  */
218 static uint32_t
srvsvc_ace_set_relative(mslm_ace_t * m_ace,struct mslm_sid * m_sid,smb_ace_t * ace)219 srvsvc_ace_set_relative(mslm_ace_t *m_ace, struct mslm_sid *m_sid,
220     smb_ace_t *ace)
221 {
222 	if ((m_ace == NULL) || (ace == NULL))
223 		return (ERROR_INVALID_PARAMETER);
224 
225 	bcopy(&ace->se_hdr, &m_ace->header, sizeof (mslm_ace_hdr_t));
226 	m_ace->mask = ace->se_mask;
227 
228 	if ((ace->se_sid == NULL) || (m_sid == NULL))
229 		return (ERROR_INVALID_PARAMETER);
230 	bcopy(ace->se_sid, m_sid, smb_sid_len(ace->se_sid));
231 
232 	return (ERROR_SUCCESS);
233 }
234 
235 /*
236  * This method converts an ACL from absolute (pointer) to
237  * self relative (flat buffer) format.
238  *
239  * Returns an initialized mslm_acl structure on success.
240  * Returns NULL on failure.
241  */
242 static struct mslm_acl *
srvsvc_acl_set_relative(uint8_t * sdbuf,smb_acl_t * acl)243 srvsvc_acl_set_relative(uint8_t *sdbuf, smb_acl_t *acl)
244 {
245 	struct mslm_acl *m_acl;
246 
247 	if (sdbuf == NULL)
248 		return (NULL);
249 
250 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
251 	m_acl = (struct mslm_acl *)sdbuf;
252 	m_acl->revision = acl->sl_revision;
253 	m_acl->sbz1 = 0;
254 	m_acl->size = acl->sl_bsize;
255 	m_acl->sbz2 = 0;
256 	m_acl->ace_count = acl->sl_acecnt;
257 
258 	return (m_acl);
259 }
260 
261 /*
262  * This method converts Security Descriptor from absolute (pointer) to
263  * self relative (flat buffer) format.
264  *
265  * Returns Win32 error codes.
266  */
267 uint32_t
srvsvc_sd_set_relative(smb_sd_t * sd,uint8_t * sdbuf)268 srvsvc_sd_set_relative(smb_sd_t *sd, uint8_t *sdbuf)
269 {
270 	mslm_security_descriptor_t *msd;
271 	int offset, len, i;
272 	smb_ace_t *ace;
273 	mslm_ace_t *m_ace;
274 	struct mslm_sid *m_sid;
275 	uint16_t ace_cnt;
276 	uint32_t status = ERROR_SUCCESS;
277 
278 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
279 	msd = (mslm_security_descriptor_t *)sdbuf;
280 	if (msd == NULL)
281 		return (ERROR_INVALID_SECURITY_DESCR);
282 
283 	msd->revision = sd->sd_revision;
284 	msd->sbz1 = 0;
285 	msd->control = sd->sd_control | SE_SELF_RELATIVE;
286 
287 	offset = sizeof (mslm_security_descriptor_t) - SRVSVC_SD_OFFSET_SZ;
288 	msd->offset_owner = msd->offset_group = 0;
289 	msd->offset_sacl = msd->offset_dacl = 0;
290 
291 	if (sd->sd_owner != NULL) {
292 		msd->offset_owner = offset;
293 
294 		if (sd->sd_owner == NULL)
295 			return (ERROR_NOT_ENOUGH_MEMORY);
296 
297 		len = smb_sid_len(sd->sd_owner);
298 		bcopy(sd->sd_owner, &sdbuf[offset], len);
299 		offset += len;
300 	}
301 
302 	if (sd->sd_group != NULL) {
303 		msd->offset_group = offset;
304 
305 		if (sd->sd_group == NULL)
306 			return (ERROR_NOT_ENOUGH_MEMORY);
307 
308 		len = smb_sid_len(sd->sd_group);
309 		bcopy(sd->sd_group, &sdbuf[offset], len);
310 		offset += len;
311 	}
312 
313 	if (sd->sd_sacl != NULL) {
314 		msd->offset_sacl = offset;
315 		msd->sacl = srvsvc_acl_set_relative(&sdbuf[offset],
316 		    sd->sd_sacl);
317 		if (msd->sacl == NULL)
318 			return (ERROR_INVALID_PARAMETER);
319 
320 		ace = sd->sd_sacl->sl_aces;
321 		ace_cnt = msd->sacl->ace_count;
322 		offset += SRVSVC_ACE_OFFSET;
323 
324 		for (i = 0; i < ace_cnt; i++, ace++) {
325 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
326 			m_ace = (mslm_ace_t *)&sdbuf[offset];
327 			offset += SRVSVC_SID_OFFSET;
328 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
329 			m_sid = (struct mslm_sid *)&sdbuf[offset];
330 
331 			status = srvsvc_ace_set_relative(m_ace, m_sid, ace);
332 			if (status != ERROR_SUCCESS)
333 				return (status);
334 			offset += smb_sid_len(ace->se_sid);
335 		}
336 	}
337 
338 	if (sd->sd_dacl != NULL) {
339 		msd->offset_dacl = offset;
340 		msd->dacl = srvsvc_acl_set_relative(&sdbuf[offset],
341 		    sd->sd_dacl);
342 		if (msd->dacl == NULL)
343 			return (ERROR_INVALID_PARAMETER);
344 
345 		ace = sd->sd_dacl->sl_aces;
346 		ace_cnt = msd->dacl->ace_count;
347 		offset += SRVSVC_ACE_OFFSET;
348 
349 		for (i = 0; i < ace_cnt; i++, ace++) {
350 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
351 			m_ace = (mslm_ace_t *)&sdbuf[offset];
352 			offset += SRVSVC_SID_OFFSET;
353 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
354 			m_sid = (struct mslm_sid *)&sdbuf[offset];
355 
356 			status = srvsvc_ace_set_relative(m_ace, m_sid, ace);
357 			if (status != ERROR_SUCCESS)
358 				return (status);
359 			offset += smb_sid_len(ace->se_sid);
360 		}
361 	}
362 
363 	return (status);
364 }
365 
366 /*
367  * This method converts an ACE from self relative (flat buffer) to
368  * absolute (pointer) format.
369  *
370  * Returns Win32 error codes.
371  */
372 static uint32_t
srvsvc_ace_set_absolute(mslm_ace_t * m_ace,struct mslm_sid * m_sid,smb_ace_t * ace)373 srvsvc_ace_set_absolute(mslm_ace_t *m_ace, struct mslm_sid *m_sid,
374     smb_ace_t *ace)
375 {
376 	int sid_size = 0;
377 	if ((m_ace == NULL) || (ace == NULL) || (m_sid == NULL))
378 		return (ERROR_INVALID_PARAMETER);
379 
380 	bzero(ace, sizeof (smb_ace_t));
381 	bcopy(&m_ace->header, &ace->se_hdr, sizeof (mslm_ace_hdr_t));
382 	ace->se_mask = m_ace->mask;
383 
384 	sid_size = smb_sid_len((smb_sid_t *)m_sid);
385 	if ((ace->se_sid = malloc(sid_size)) == NULL)
386 		return (ERROR_NOT_ENOUGH_MEMORY);
387 	bcopy(m_sid, ace->se_sid, sid_size);
388 
389 	return (ERROR_SUCCESS);
390 }
391 
392 /*
393  * This method converts an ACL from self relative (flat buffer) to
394  * absolute (pointer) format.
395  *
396  * Returns an initialized smb_acl_t structure on success.
397  * Returns NULL on failure.
398  */
399 static smb_acl_t *
srvsvc_acl_set_absolute(uint8_t * sdbuf,int * offset)400 srvsvc_acl_set_absolute(uint8_t *sdbuf, int *offset)
401 {
402 	uint8_t rev;
403 	uint16_t sz, ace_cnt;
404 	smb_acl_t *acl;
405 
406 	bcopy(&sdbuf[*offset], &rev, sizeof (uint8_t));
407 	*offset += 2; /* Pad for Sbz1 */
408 	bcopy(&sdbuf[*offset], &sz, sizeof (uint16_t));
409 	*offset += 2;
410 	bcopy(&sdbuf[*offset], &ace_cnt, sizeof (uint16_t));
411 	*offset += 4; /* Pad for Sbz2 */
412 
413 	acl = smb_acl_alloc(rev, sz, ace_cnt);
414 
415 	return (acl);
416 }
417 
418 /*
419  * This method converts Security Descriptor from self relative (flat buffer) to
420  * absolute (pointer) format.
421  *
422  * Returns Win32 error codes.
423  */
424 static uint32_t
srvsvc_sd_set_absolute(uint8_t * sdbuf,smb_sd_t * sd)425 srvsvc_sd_set_absolute(uint8_t *sdbuf, smb_sd_t *sd)
426 {
427 	mslm_security_descriptor_t *msd;
428 	mslm_ace_t *m_ace;
429 	struct mslm_sid *m_sid;
430 	smb_ace_t *ace;
431 	uint16_t ace_cnt;
432 	int offset, i, sid_size;
433 	uint32_t status = ERROR_SUCCESS;
434 
435 	if (sdbuf == NULL)
436 		return (ERROR_INVALID_SECURITY_DESCR);
437 
438 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
439 	msd = (mslm_security_descriptor_t *)sdbuf;
440 
441 	sd->sd_revision = msd->revision;
442 	sd->sd_control = msd->control & (~SE_SELF_RELATIVE);
443 
444 	if (msd->offset_owner != 0) {
445 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
446 		m_sid = (struct mslm_sid *)&sdbuf[msd->offset_owner];
447 		sid_size = smb_sid_len((smb_sid_t *)m_sid);
448 
449 		if ((sd->sd_owner = malloc(sid_size)) == NULL)
450 			return (ERROR_NOT_ENOUGH_MEMORY);
451 		bcopy(m_sid, sd->sd_owner, sid_size);
452 	}
453 
454 	if (msd->offset_group != 0) {
455 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
456 		m_sid = (struct mslm_sid *)&sdbuf[msd->offset_group];
457 		sid_size = smb_sid_len((smb_sid_t *)m_sid);
458 
459 		if ((sd->sd_group = malloc(sid_size)) == NULL)
460 			return (ERROR_NOT_ENOUGH_MEMORY);
461 		bcopy(m_sid, sd->sd_group, sid_size);
462 	}
463 
464 	if (msd->offset_sacl != 0) {
465 		offset = msd->offset_sacl;
466 		sd->sd_sacl = srvsvc_acl_set_absolute(sdbuf, &offset);
467 		if (sd->sd_sacl == NULL)
468 			return (ERROR_NOT_ENOUGH_MEMORY);
469 
470 		ace = sd->sd_sacl->sl_aces;
471 		ace_cnt = sd->sd_sacl->sl_acecnt;
472 
473 		for (i = 0; i < ace_cnt; i++, ace++) {
474 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
475 			m_ace = (mslm_ace_t *)&sdbuf[offset];
476 			offset += SRVSVC_SID_OFFSET;
477 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
478 			m_sid = (struct mslm_sid *)&sdbuf[offset];
479 
480 			status = srvsvc_ace_set_absolute(m_ace, m_sid, ace);
481 			if (status != ERROR_SUCCESS)
482 				return (status);
483 			offset += smb_sid_len(ace->se_sid);
484 		}
485 	}
486 
487 	if (msd->offset_dacl != 0) {
488 		offset = msd->offset_dacl;
489 		sd->sd_dacl = srvsvc_acl_set_absolute(sdbuf, &offset);
490 		if (sd->sd_dacl == NULL)
491 			return (ERROR_NOT_ENOUGH_MEMORY);
492 
493 		ace = sd->sd_dacl->sl_aces;
494 		ace_cnt = sd->sd_dacl->sl_acecnt;
495 
496 		for (i = 0; i < ace_cnt; i++, ace++) {
497 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
498 			m_ace = (mslm_ace_t *)&sdbuf[offset];
499 			offset += SRVSVC_SID_OFFSET;
500 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
501 			m_sid = (struct mslm_sid *)&sdbuf[offset];
502 
503 			status = srvsvc_ace_set_absolute(m_ace, m_sid, ace);
504 			if (status != ERROR_SUCCESS)
505 				return (status);
506 			offset += smb_sid_len(ace->se_sid);
507 		}
508 	}
509 
510 	return (status);
511 }
512 
513 /*
514  * This method maps NT status codes into Win 32 error codes.
515  * This method operates on status codes that are related
516  * to processing of Security Descriptor.
517  */
518 static uint32_t
srvsvc_sd_status_to_error(uint32_t status)519 srvsvc_sd_status_to_error(uint32_t status)
520 {
521 	int i;
522 	static struct {
523 		uint32_t	nt_status;
524 		uint32_t	err_code;
525 	} errmap[] = {
526 		{ NT_STATUS_SUCCESS,		ERROR_SUCCESS },
527 		{ NT_STATUS_INVALID_ACL,	ERROR_INVALID_ACL },
528 		{ NT_STATUS_INVALID_SID,	ERROR_INVALID_SID },
529 		{ NT_STATUS_NONE_MAPPED,	ERROR_NONE_MAPPED }
530 	};
531 
532 	for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
533 		if (status == errmap[i].nt_status)
534 			return (errmap[i].err_code);
535 	}
536 
537 	return (ERROR_INTERNAL_ERROR);
538 }
539