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