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