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 module provides Security Descriptor handling functions.
28 */
29
30 #include <strings.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <smbsrv/ntifs.h>
34 #include <smbsrv/smb_idmap.h>
35 #include <smbsrv/libsmb.h>
36
37 #define SMB_SHR_ACE_READ_PERMS (ACE_READ_PERMS | ACE_EXECUTE | ACE_SYNCHRONIZE)
38 #define SMB_SHR_ACE_CONTROL_PERMS (ACE_MODIFY_PERMS & (~ACE_DELETE_CHILD))
39
40 /*
41 * This mapping table is provided to map permissions set by chmod
42 * using 'read_set' and 'modify_set' to what Windows share ACL GUI
43 * expects as Read and Control, respectively.
44 */
45 static struct {
46 int am_ace_perms;
47 int am_share_perms;
48 } smb_ace_map[] = {
49 { ACE_MODIFY_PERMS, SMB_SHR_ACE_CONTROL_PERMS },
50 { ACE_READ_PERMS, SMB_SHR_ACE_READ_PERMS }
51 };
52
53 #define SMB_ACE_MASK_MAP_SIZE (sizeof (smb_ace_map)/sizeof (smb_ace_map[0]))
54
55 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
56 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
57
58 void
smb_sd_init(smb_sd_t * sd,uint8_t revision)59 smb_sd_init(smb_sd_t *sd, uint8_t revision)
60 {
61 bzero(sd, sizeof (smb_sd_t));
62 sd->sd_revision = revision;
63 }
64
65 /*
66 * smb_sd_term
67 *
68 * Free non-NULL members of 'sd' which has to be in
69 * absolute (pointer) form.
70 */
71 void
smb_sd_term(smb_sd_t * sd)72 smb_sd_term(smb_sd_t *sd)
73 {
74 assert(sd);
75 assert((sd->sd_control & SE_SELF_RELATIVE) == 0);
76
77 smb_sid_free(sd->sd_owner);
78 smb_sid_free(sd->sd_group);
79 smb_acl_free(sd->sd_dacl);
80 smb_acl_free(sd->sd_sacl);
81
82 bzero(sd, sizeof (smb_sd_t));
83 }
84
85 uint32_t
smb_sd_len(smb_sd_t * sd,uint32_t secinfo)86 smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
87 {
88 uint32_t length = SMB_SD_HDRSIZE;
89
90 if (secinfo & SMB_OWNER_SECINFO)
91 length += smb_sid_len(sd->sd_owner);
92
93 if (secinfo & SMB_GROUP_SECINFO)
94 length += smb_sid_len(sd->sd_group);
95
96 if (secinfo & SMB_DACL_SECINFO)
97 length += smb_acl_len(sd->sd_dacl);
98
99 if (secinfo & SMB_SACL_SECINFO)
100 length += smb_acl_len(sd->sd_sacl);
101
102 return (length);
103 }
104
105 /*
106 * smb_sd_get_secinfo
107 *
108 * Return the security information mask for the specified security
109 * descriptor.
110 */
111 uint32_t
smb_sd_get_secinfo(smb_sd_t * sd)112 smb_sd_get_secinfo(smb_sd_t *sd)
113 {
114 uint32_t sec_info = 0;
115
116 if (sd == NULL)
117 return (0);
118
119 if (sd->sd_owner)
120 sec_info |= SMB_OWNER_SECINFO;
121
122 if (sd->sd_group)
123 sec_info |= SMB_GROUP_SECINFO;
124
125 if (sd->sd_dacl)
126 sec_info |= SMB_DACL_SECINFO;
127
128 if (sd->sd_sacl)
129 sec_info |= SMB_SACL_SECINFO;
130
131 return (sec_info);
132 }
133
134 /*
135 * Adjust the Access Mask so that ZFS ACE mask and Windows ACE read mask match.
136 */
137 static int
smb_sd_adjust_read_mask(int mask)138 smb_sd_adjust_read_mask(int mask)
139 {
140 int i;
141
142 for (i = 0; i < SMB_ACE_MASK_MAP_SIZE; ++i) {
143 if (smb_ace_map[i].am_ace_perms == mask)
144 return (smb_ace_map[i].am_share_perms);
145 }
146
147 return (mask);
148 }
149
150 /*
151 * Get ZFS acl from the share path via acl_get() method.
152 */
153 static uint32_t
smb_sd_read_acl(char * path,smb_fssd_t * fs_sd)154 smb_sd_read_acl(char *path, smb_fssd_t *fs_sd)
155 {
156 acl_t *z_acl;
157 ace_t *z_ace;
158
159 fs_sd->sd_gid = fs_sd->sd_uid = 0;
160
161 errno = 0;
162 if (acl_get(path, 0, &z_acl) != 0) {
163 switch (errno) {
164 case EACCES:
165 return (NT_STATUS_ACCESS_DENIED);
166 case ENOENT:
167 return (NT_STATUS_OBJECT_PATH_NOT_FOUND);
168 default:
169 return (NT_STATUS_INTERNAL_ERROR);
170 }
171 }
172
173 if ((z_ace = (ace_t *)z_acl->acl_aclp) == NULL)
174 return (NT_STATUS_INVALID_ACL);
175
176 for (int i = 0; i < z_acl->acl_cnt; i++, z_ace++)
177 z_ace->a_access_mask =
178 smb_sd_adjust_read_mask(z_ace->a_access_mask);
179
180 fs_sd->sd_zdacl = z_acl;
181 fs_sd->sd_zsacl = NULL;
182 return (NT_STATUS_SUCCESS);
183 }
184
185 /*
186 * smb_sd_read
187 *
188 * Reads ZFS acl from filesystem using acl_get() method. Convert the ZFS acl to
189 * a Win SD and return the Win SD in absolute form.
190 *
191 * NOTE: upon successful return caller MUST free the memory allocated
192 * for the returned SD by calling smb_sd_term().
193 */
194 uint32_t
smb_sd_read(char * path,smb_sd_t * sd,uint32_t secinfo)195 smb_sd_read(char *path, smb_sd_t *sd, uint32_t secinfo)
196 {
197 smb_fssd_t fs_sd;
198 uint32_t status = NT_STATUS_SUCCESS;
199 uint32_t sd_flags;
200 int error;
201
202 sd_flags = SMB_FSSD_FLAGS_DIR;
203 smb_fssd_init(&fs_sd, secinfo, sd_flags);
204
205 error = smb_sd_read_acl(path, &fs_sd);
206 if (error != NT_STATUS_SUCCESS) {
207 smb_fssd_term(&fs_sd);
208 return (error);
209 }
210
211 status = smb_sd_fromfs(&fs_sd, sd);
212 smb_fssd_term(&fs_sd);
213
214 return (status);
215 }
216
217 /*
218 * Apply ZFS acl to the share path via acl_set() method.
219 * A NULL ACL pointer here represents an error.
220 * Null or empty ACLs are handled in smb_sd_tofs().
221 */
222 static uint32_t
smb_sd_write_acl(char * path,smb_fssd_t * fs_sd)223 smb_sd_write_acl(char *path, smb_fssd_t *fs_sd)
224 {
225 acl_t *z_acl;
226 ace_t *z_ace;
227 uint32_t status = NT_STATUS_SUCCESS;
228
229 z_acl = fs_sd->sd_zdacl;
230 if (z_acl == NULL)
231 return (NT_STATUS_INVALID_ACL);
232
233 z_ace = (ace_t *)z_acl->acl_aclp;
234 if (z_ace == NULL)
235 return (NT_STATUS_INVALID_ACL);
236
237 fs_sd->sd_gid = fs_sd->sd_uid = 0;
238 if (acl_set(path, z_acl) != 0)
239 status = NT_STATUS_INTERNAL_ERROR;
240
241 return (status);
242 }
243
244 /*
245 * smb_sd_write
246 *
247 * Takes a Win SD in absolute form, converts it to
248 * ZFS acl and applies the acl to the share path via acl_set() method.
249 */
250 uint32_t
smb_sd_write(char * path,smb_sd_t * sd,uint32_t secinfo)251 smb_sd_write(char *path, smb_sd_t *sd, uint32_t secinfo)
252 {
253 smb_fssd_t fs_sd;
254 uint32_t status = NT_STATUS_SUCCESS;
255 uint32_t sd_flags;
256 int error;
257
258 sd_flags = SMB_FSSD_FLAGS_DIR;
259 smb_fssd_init(&fs_sd, secinfo, sd_flags);
260
261 error = smb_sd_tofs(sd, &fs_sd);
262 if (error != NT_STATUS_SUCCESS) {
263 smb_fssd_term(&fs_sd);
264 return (error);
265 }
266
267 status = smb_sd_write_acl(path, &fs_sd);
268 smb_fssd_term(&fs_sd);
269
270 return (status);
271 }
272
273 /*
274 * smb_sd_tofs
275 *
276 * Creates a filesystem security structure based on the given
277 * Windows security descriptor.
278 */
279 uint32_t
smb_sd_tofs(smb_sd_t * sd,smb_fssd_t * fs_sd)280 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
281 {
282 smb_sid_t *sid;
283 uint32_t status = NT_STATUS_SUCCESS;
284 uint16_t sd_control;
285 idmap_stat idm_stat;
286 int idtype;
287 int flags = 0;
288
289 sd_control = sd->sd_control;
290
291 /*
292 * ZFS only has one set of flags so for now only
293 * Windows DACL flags are taken into account.
294 */
295 if (sd_control & SE_DACL_DEFAULTED)
296 flags |= ACL_DEFAULTED;
297 if (sd_control & SE_DACL_AUTO_INHERITED)
298 flags |= ACL_AUTO_INHERIT;
299 if (sd_control & SE_DACL_PROTECTED)
300 flags |= ACL_PROTECTED;
301
302 if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
303 flags |= ACL_IS_DIR;
304
305 /* Owner */
306 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
307 sid = sd->sd_owner;
308 if (!smb_sid_isvalid(sid))
309 return (NT_STATUS_INVALID_SID);
310
311 idtype = SMB_IDMAP_USER;
312 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
313 if (idm_stat != IDMAP_SUCCESS) {
314 return (NT_STATUS_NONE_MAPPED);
315 }
316 }
317
318 /* Group */
319 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
320 sid = sd->sd_group;
321 if (!smb_sid_isvalid(sid))
322 return (NT_STATUS_INVALID_SID);
323
324 idtype = SMB_IDMAP_GROUP;
325 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
326 if (idm_stat != IDMAP_SUCCESS) {
327 return (NT_STATUS_NONE_MAPPED);
328 }
329 }
330
331 /* DACL */
332 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
333 if (sd->sd_control & SE_DACL_PRESENT) {
334 status = smb_acl_to_zfs(sd->sd_dacl, flags,
335 SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
336 if (status != NT_STATUS_SUCCESS)
337 return (status);
338 }
339 else
340 return (NT_STATUS_INVALID_ACL);
341 }
342
343 /* SACL */
344 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
345 if (sd->sd_control & SE_SACL_PRESENT) {
346 status = smb_acl_to_zfs(sd->sd_sacl, flags,
347 SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
348 if (status != NT_STATUS_SUCCESS) {
349 return (status);
350 }
351 } else {
352 return (NT_STATUS_INVALID_ACL);
353 }
354 }
355
356 return (status);
357 }
358
359 /*
360 * smb_sd_fromfs
361 *
362 * Makes an Windows style security descriptor in absolute form
363 * based on the given filesystem security information.
364 *
365 * Should call smb_sd_term() for the returned sd to free allocated
366 * members.
367 */
368 uint32_t
smb_sd_fromfs(smb_fssd_t * fs_sd,smb_sd_t * sd)369 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
370 {
371 uint32_t status = NT_STATUS_SUCCESS;
372 smb_acl_t *acl = NULL;
373 smb_sid_t *sid;
374 idmap_stat idm_stat;
375
376 assert(fs_sd);
377 assert(sd);
378
379 smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
380
381 /* Owner */
382 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
383 idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
384 SMB_IDMAP_USER, &sid);
385
386 if (idm_stat != IDMAP_SUCCESS) {
387 smb_sd_term(sd);
388 return (NT_STATUS_NONE_MAPPED);
389 }
390
391 sd->sd_owner = sid;
392 }
393
394 /* Group */
395 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
396 idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
397 SMB_IDMAP_GROUP, &sid);
398
399 if (idm_stat != IDMAP_SUCCESS) {
400 smb_sd_term(sd);
401 return (NT_STATUS_NONE_MAPPED);
402 }
403
404 sd->sd_group = sid;
405 }
406
407 /* DACL */
408 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
409 if (fs_sd->sd_zdacl != NULL) {
410 acl = smb_acl_from_zfs(fs_sd->sd_zdacl);
411 if (acl == NULL) {
412 smb_sd_term(sd);
413 return (NT_STATUS_INTERNAL_ERROR);
414 }
415
416 /*
417 * Need to sort the ACL before send it to Windows
418 * clients. Winodws GUI is sensitive about the order
419 * of ACEs.
420 */
421 smb_acl_sort(acl);
422 smb_sd_set_dacl(sd, acl, B_TRUE,
423 fs_sd->sd_zdacl->acl_flags);
424 } else {
425 smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
426 }
427 }
428
429 /* SACL */
430 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
431 if (fs_sd->sd_zsacl != NULL) {
432 acl = smb_acl_from_zfs(fs_sd->sd_zsacl);
433 if (acl == NULL) {
434 smb_sd_term(sd);
435 return (NT_STATUS_INTERNAL_ERROR);
436 }
437
438 smb_sd_set_sacl(sd, acl, B_TRUE,
439 fs_sd->sd_zsacl->acl_flags);
440 } else {
441 smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
442 }
443 }
444
445 return (status);
446 }
447
448 static void
smb_sd_set_dacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)449 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
450 {
451 assert((sd->sd_control & SE_SELF_RELATIVE) == 0);
452
453 sd->sd_dacl = acl;
454
455 if (flags & ACL_DEFAULTED)
456 sd->sd_control |= SE_DACL_DEFAULTED;
457 if (flags & ACL_AUTO_INHERIT)
458 sd->sd_control |= SE_DACL_AUTO_INHERITED;
459 if (flags & ACL_PROTECTED)
460 sd->sd_control |= SE_DACL_PROTECTED;
461
462 if (present)
463 sd->sd_control |= SE_DACL_PRESENT;
464 }
465
466 static void
smb_sd_set_sacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)467 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
468 {
469 assert((sd->sd_control & SE_SELF_RELATIVE) == 0);
470
471 sd->sd_sacl = acl;
472
473 if (flags & ACL_DEFAULTED)
474 sd->sd_control |= SE_SACL_DEFAULTED;
475 if (flags & ACL_AUTO_INHERIT)
476 sd->sd_control |= SE_SACL_AUTO_INHERITED;
477 if (flags & ACL_PROTECTED)
478 sd->sd_control |= SE_SACL_PROTECTED;
479
480 if (present)
481 sd->sd_control |= SE_SACL_PRESENT;
482 }
483
484 /*
485 * smb_fssd_init
486 *
487 * Initializes the given FS SD structure.
488 */
489 void
smb_fssd_init(smb_fssd_t * fs_sd,uint32_t secinfo,uint32_t flags)490 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
491 {
492 bzero(fs_sd, sizeof (smb_fssd_t));
493 fs_sd->sd_secinfo = secinfo;
494 fs_sd->sd_flags = flags;
495 }
496
497 /*
498 * smb_fssd_term
499 *
500 * Frees allocated memory for acl fields.
501 */
502 void
smb_fssd_term(smb_fssd_t * fs_sd)503 smb_fssd_term(smb_fssd_t *fs_sd)
504 {
505 assert(fs_sd);
506
507 acl_free(fs_sd->sd_zdacl);
508 acl_free(fs_sd->sd_zsacl);
509
510 bzero(fs_sd, sizeof (smb_fssd_t));
511 }
512