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