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