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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
26 */
27
28 /*
29 * This module provides Security Descriptor handling functions.
30 */
31
32 #include <smbsrv/smb_kproto.h>
33 #include <smbsrv/smb_fsops.h>
34 #include <smbsrv/smb_idmap.h>
35
36 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
37 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
38 static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *);
39
40 void
smb_sd_init(smb_sd_t * sd,uint8_t revision)41 smb_sd_init(smb_sd_t *sd, uint8_t revision)
42 {
43 bzero(sd, sizeof (smb_sd_t));
44 sd->sd_revision = revision;
45 }
46
47 /*
48 * smb_sd_term
49 *
50 * Free non-NULL members of 'sd' which has to be in
51 * absolute (pointer) form.
52 */
53 void
smb_sd_term(smb_sd_t * sd)54 smb_sd_term(smb_sd_t *sd)
55 {
56 ASSERT(sd);
57 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
58
59 smb_sid_free(sd->sd_owner);
60 smb_sid_free(sd->sd_group);
61 smb_acl_free(sd->sd_dacl);
62 smb_acl_free(sd->sd_sacl);
63
64 bzero(sd, sizeof (smb_sd_t));
65 }
66
67 uint32_t
smb_sd_len(smb_sd_t * sd,uint32_t secinfo)68 smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
69 {
70 uint32_t length = SMB_SD_HDRSIZE;
71
72 if (secinfo & SMB_OWNER_SECINFO)
73 length += smb_sid_len(sd->sd_owner);
74
75 if (secinfo & SMB_GROUP_SECINFO)
76 length += smb_sid_len(sd->sd_group);
77
78 if (secinfo & SMB_DACL_SECINFO)
79 length += smb_acl_len(sd->sd_dacl);
80
81 if (secinfo & SMB_SACL_SECINFO)
82 length += smb_acl_len(sd->sd_sacl);
83
84 return (length);
85 }
86
87 /*
88 * smb_sd_get_secinfo
89 *
90 * Return the security information mask for the specified security
91 * descriptor.
92 *
93 * Note: This is used for 'create-with-sd'. 'set-security-info' provides the
94 * secinfo as part of the request, but create does not, so we must infer it.
95 */
96 uint32_t
smb_sd_get_secinfo(smb_sd_t * sd)97 smb_sd_get_secinfo(smb_sd_t *sd)
98 {
99 uint32_t sec_info = 0;
100
101 if (sd == NULL)
102 return (0);
103
104 if (sd->sd_owner)
105 sec_info |= SMB_OWNER_SECINFO;
106
107 if (sd->sd_group)
108 sec_info |= SMB_GROUP_SECINFO;
109
110 if ((sd->sd_control & SE_DACL_PRESENT) != 0)
111 sec_info |= SMB_DACL_SECINFO;
112
113 if ((sd->sd_control & SE_SACL_PRESENT) != 0)
114 sec_info |= SMB_SACL_SECINFO;
115
116 return (sec_info);
117 }
118
119 /*
120 * smb_sd_read
121 *
122 * Read uid, gid and ACL from filesystem. The returned ACL from read
123 * routine is always in ZFS format. Convert the ZFS acl to a Win acl
124 * and return the Win SD in absolute form.
125 *
126 * NOTE: upon successful return caller MUST free the memory allocated
127 * for the returned SD by calling smb_sd_term().
128 */
129 uint32_t
smb_sd_read(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)130 smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
131 {
132 smb_fssd_t fs_sd;
133 smb_node_t *node;
134 uint32_t status = NT_STATUS_SUCCESS;
135 uint32_t sd_flags;
136 int error;
137
138 node = sr->fid_ofile->f_node;
139 sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
140 smb_fssd_init(&fs_sd, secinfo, sd_flags);
141
142 error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
143 if (error)
144 return (smb_errno2status(error));
145
146 status = smb_sd_fromfs(&fs_sd, sd);
147 smb_fssd_term(&fs_sd);
148
149 return (status);
150 }
151
152 /*
153 * smb_sd_write
154 *
155 * Takes a Win SD in absolute form, converts it to
156 * ZFS format and write it to filesystem. The write routine
157 * converts ZFS acl to Posix acl if required.
158 */
159 uint32_t
smb_sd_write(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)160 smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
161 {
162 smb_node_t *node;
163 smb_fssd_t fs_sd;
164 uint32_t status;
165 uint32_t sd_flags;
166 int error;
167
168 node = sr->fid_ofile->f_node;
169 sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
170 smb_fssd_init(&fs_sd, secinfo, sd_flags);
171
172 status = smb_sd_tofs(sd, &fs_sd);
173 if (status != NT_STATUS_SUCCESS) {
174 smb_fssd_term(&fs_sd);
175 return (status);
176 }
177
178 error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
179 smb_fssd_term(&fs_sd);
180
181 if (error) {
182 if (error == EBADE)
183 return (NT_STATUS_INVALID_OWNER);
184 return (smb_errno2status(error));
185 }
186
187 return (NT_STATUS_SUCCESS);
188 }
189
190
191 /*
192 * smb_sd_tofs
193 *
194 * Creates a filesystem security structure based on the given
195 * Windows security descriptor.
196 */
197 uint32_t
smb_sd_tofs(smb_sd_t * sd,smb_fssd_t * fs_sd)198 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
199 {
200 smb_sid_t *sid;
201 uint32_t status = NT_STATUS_SUCCESS;
202 uint16_t sd_control;
203 idmap_stat idm_stat;
204 int idtype;
205 int flags = 0;
206
207 sd_control = sd->sd_control;
208
209 /*
210 * ZFS only has one set of flags so for now only
211 * Windows DACL flags are taken into account.
212 */
213 if (sd_control & SE_DACL_DEFAULTED)
214 flags |= ACL_DEFAULTED;
215 if (sd_control & SE_DACL_AUTO_INHERITED)
216 flags |= ACL_AUTO_INHERIT;
217 if (sd_control & SE_DACL_PROTECTED)
218 flags |= ACL_PROTECTED;
219
220 if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
221 flags |= ACL_IS_DIR;
222
223 /* Owner */
224 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
225 sid = sd->sd_owner;
226 if (!smb_sid_isvalid(sid))
227 return (NT_STATUS_INVALID_SID);
228
229 idtype = SMB_IDMAP_USER;
230 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
231 if (idm_stat != IDMAP_SUCCESS) {
232 return (NT_STATUS_NONE_MAPPED);
233 }
234 }
235
236 /* Group */
237 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
238 sid = sd->sd_group;
239 if (!smb_sid_isvalid(sid))
240 return (NT_STATUS_INVALID_SID);
241
242 idtype = SMB_IDMAP_GROUP;
243 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
244 if (idm_stat != IDMAP_SUCCESS) {
245 return (NT_STATUS_NONE_MAPPED);
246 }
247 }
248
249 /*
250 * In SMB, the 'secinfo' determines which parts of the SD the client
251 * intends to change. Notably, this includes changing the DACL_PRESENT
252 * and SACL_PRESENT control bits. The client can specify e.g.
253 * SACL_SECINFO, but not SACL_PRESENT, and this means the client intends
254 * to remove the SACL.
255 *
256 * Note that Windows behavior differs from that described in [MS-DTYP].
257 * MS-DTYP states that the offset is nonzero if-and-only-if the PRESENT
258 * bit is set. It also states that a DACL that is marked non-present
259 * is equivalent to 'no security', but one that is marked present and
260 * provides no ACEs is equivalent to 'no access'.
261 *
262 * Windows, on the other hand, allows the offset to be 0 even when
263 * the PRESENT bit is set, and only provides security when the DACL
264 * offset is non-zero. It will also convert an SD where the DACL is
265 * marked not-present to one where the PRESENT bit is set and the
266 * offset is 0.
267 *
268 * If the *_PRESENT bit isn't set, then the respective ACL will be NULL.
269 * For the fssd, we allow the SACL to be NULL, but we MUST have a DACL.
270 * If the DACL is NULL, that's equivalent to "everyone:full_set:allow".
271 *
272 * The IMPLY's should be enforced by smb_decode_sd().
273 */
274
275 /* DACL */
276 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
277 IMPLY(sd->sd_dacl != NULL,
278 (sd->sd_control & SE_DACL_PRESENT) != 0);
279 status = smb_acl_to_zfs(sd->sd_dacl, flags,
280 SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
281 if (status != NT_STATUS_SUCCESS)
282 return (status);
283 }
284
285 /* SACL */
286 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
287 IMPLY(sd->sd_sacl != NULL,
288 (sd->sd_control & SE_SACL_PRESENT) != 0);
289 if (sd->sd_control & SE_SACL_PRESENT) {
290 status = smb_acl_to_zfs(sd->sd_sacl, flags,
291 SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
292 if (status != NT_STATUS_SUCCESS) {
293 return (status);
294 }
295 }
296 }
297
298 return (status);
299 }
300
301 /*
302 * smb_sd_fromfs
303 *
304 * Makes an Windows style security descriptor in absolute form
305 * based on the given filesystem security information.
306 *
307 * Should call smb_sd_term() for the returned sd to free allocated
308 * members.
309 */
310 static uint32_t
smb_sd_fromfs(smb_fssd_t * fs_sd,smb_sd_t * sd)311 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
312 {
313 uint32_t status = NT_STATUS_SUCCESS;
314 smb_acl_t *acl = NULL;
315 smb_sid_t *sid;
316 idmap_stat idm_stat;
317
318 ASSERT(fs_sd);
319 ASSERT(sd);
320
321 smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
322
323 /* Owner */
324 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
325 idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
326 SMB_IDMAP_USER, &sid);
327
328 if (idm_stat != IDMAP_SUCCESS) {
329 smb_sd_term(sd);
330 return (NT_STATUS_NONE_MAPPED);
331 }
332
333 sd->sd_owner = sid;
334 }
335
336 /* Group */
337 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
338 idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
339 SMB_IDMAP_GROUP, &sid);
340
341 if (idm_stat != IDMAP_SUCCESS) {
342 smb_sd_term(sd);
343 return (NT_STATUS_NONE_MAPPED);
344 }
345
346 sd->sd_group = sid;
347 }
348
349 /* DACL */
350 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
351 if (fs_sd->sd_zdacl != NULL) {
352 acl = smb_acl_from_zfs(fs_sd->sd_zdacl);
353 if (acl == NULL) {
354 smb_sd_term(sd);
355 return (NT_STATUS_INTERNAL_ERROR);
356 }
357
358 /*
359 * Need to sort the ACL before send it to Windows
360 * clients. Winodws GUI is sensitive about the order
361 * of ACEs.
362 */
363 smb_acl_sort(acl);
364 smb_sd_set_dacl(sd, acl, B_TRUE,
365 fs_sd->sd_zdacl->acl_flags);
366 } else {
367 smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
368 }
369 }
370
371 /* SACL */
372 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
373 if (fs_sd->sd_zsacl != NULL) {
374 acl = smb_acl_from_zfs(fs_sd->sd_zsacl);
375 if (acl == NULL) {
376 smb_sd_term(sd);
377 return (NT_STATUS_INTERNAL_ERROR);
378 }
379
380 smb_sd_set_sacl(sd, acl, B_TRUE,
381 fs_sd->sd_zsacl->acl_flags);
382 } else {
383 smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
384 }
385 }
386
387 return (status);
388 }
389
390 static void
smb_sd_set_dacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)391 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
392 {
393 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
394
395 sd->sd_dacl = acl;
396
397 if (flags & ACL_DEFAULTED)
398 sd->sd_control |= SE_DACL_DEFAULTED;
399 if (flags & ACL_AUTO_INHERIT)
400 sd->sd_control |= SE_DACL_AUTO_INHERITED;
401 if (flags & ACL_PROTECTED)
402 sd->sd_control |= SE_DACL_PROTECTED;
403
404 if (present)
405 sd->sd_control |= SE_DACL_PRESENT;
406 }
407
408 static void
smb_sd_set_sacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)409 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
410 {
411 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
412
413 sd->sd_sacl = acl;
414
415 if (flags & ACL_DEFAULTED)
416 sd->sd_control |= SE_SACL_DEFAULTED;
417 if (flags & ACL_AUTO_INHERIT)
418 sd->sd_control |= SE_SACL_AUTO_INHERITED;
419 if (flags & ACL_PROTECTED)
420 sd->sd_control |= SE_SACL_PROTECTED;
421
422 if (present)
423 sd->sd_control |= SE_SACL_PRESENT;
424 }
425
426 /*
427 * smb_fssd_init
428 *
429 * Initializes the given FS SD structure.
430 */
431 void
smb_fssd_init(smb_fssd_t * fs_sd,uint32_t secinfo,uint32_t flags)432 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
433 {
434 bzero(fs_sd, sizeof (smb_fssd_t));
435 fs_sd->sd_secinfo = secinfo;
436 fs_sd->sd_flags = flags;
437 }
438
439 /*
440 * smb_fssd_term
441 *
442 * Frees allocated memory for acl fields.
443 */
444 void
smb_fssd_term(smb_fssd_t * fs_sd)445 smb_fssd_term(smb_fssd_t *fs_sd)
446 {
447 ASSERT(fs_sd);
448
449 smb_fsacl_free(fs_sd->sd_zdacl);
450 smb_fsacl_free(fs_sd->sd_zsacl);
451 bzero(fs_sd, sizeof (smb_fssd_t));
452 }
453