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
srvsvc_shareacl_getpath(smb_share_t * si,char * shr_acl_path)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
srvsvc_sd_set(smb_share_t * si,uint8_t * sdbuf)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
srvsvc_sd_get(smb_share_t * si,uint8_t * sdbuf,uint32_t * size)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
srvsvc_sd_get_autohome(const smb_share_t * si,smb_sd_t * sd)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
srvsvc_ace_set_relative(mslm_ace_t * m_ace,struct mslm_sid * m_sid,smb_ace_t * ace)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 *
srvsvc_acl_set_relative(uint8_t * sdbuf,smb_acl_t * 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
srvsvc_sd_set_relative(smb_sd_t * sd,uint8_t * sdbuf)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
srvsvc_ace_set_absolute(mslm_ace_t * m_ace,struct mslm_sid * m_sid,smb_ace_t * ace)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 *
srvsvc_acl_set_absolute(uint8_t * sdbuf,int * offset)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
srvsvc_sd_set_absolute(uint8_t * sdbuf,smb_sd_t * sd)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
srvsvc_sd_status_to_error(uint32_t status)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