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 2013 Nexenta Systems, 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 uint32_t
smb_sd_get_secinfo(smb_sd_t * sd)94 smb_sd_get_secinfo(smb_sd_t *sd)
95 {
96 uint32_t sec_info = 0;
97
98 if (sd == NULL)
99 return (0);
100
101 if (sd->sd_owner)
102 sec_info |= SMB_OWNER_SECINFO;
103
104 if (sd->sd_group)
105 sec_info |= SMB_GROUP_SECINFO;
106
107 if (sd->sd_dacl)
108 sec_info |= SMB_DACL_SECINFO;
109
110 if (sd->sd_sacl)
111 sec_info |= SMB_SACL_SECINFO;
112
113 return (sec_info);
114 }
115
116 /*
117 * smb_sd_read
118 *
119 * Read uid, gid and ACL from filesystem. The returned ACL from read
120 * routine is always in ZFS format. Convert the ZFS acl to a Win acl
121 * and return the Win SD in absolute form.
122 *
123 * NOTE: upon successful return caller MUST free the memory allocated
124 * for the returned SD by calling smb_sd_term().
125 */
126 uint32_t
smb_sd_read(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)127 smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
128 {
129 smb_fssd_t fs_sd;
130 smb_node_t *node;
131 uint32_t status = NT_STATUS_SUCCESS;
132 uint32_t sd_flags;
133 int error;
134
135 node = sr->fid_ofile->f_node;
136 sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
137 smb_fssd_init(&fs_sd, secinfo, sd_flags);
138
139 error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
140 if (error)
141 return (smb_errno2status(error));
142
143 status = smb_sd_fromfs(&fs_sd, sd);
144 smb_fssd_term(&fs_sd);
145
146 return (status);
147 }
148
149 /*
150 * smb_sd_write
151 *
152 * Takes a Win SD in absolute form, converts it to
153 * ZFS format and write it to filesystem. The write routine
154 * converts ZFS acl to Posix acl if required.
155 */
156 uint32_t
smb_sd_write(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)157 smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
158 {
159 smb_node_t *node;
160 smb_fssd_t fs_sd;
161 uint32_t status;
162 uint32_t sd_flags;
163 int error;
164
165 node = sr->fid_ofile->f_node;
166 sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
167 smb_fssd_init(&fs_sd, secinfo, sd_flags);
168
169 status = smb_sd_tofs(sd, &fs_sd);
170 if (status != NT_STATUS_SUCCESS) {
171 smb_fssd_term(&fs_sd);
172 return (status);
173 }
174
175 error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
176 smb_fssd_term(&fs_sd);
177
178 if (error) {
179 if (error == EBADE)
180 return (NT_STATUS_INVALID_OWNER);
181 return (smb_errno2status(error));
182 }
183
184 return (NT_STATUS_SUCCESS);
185 }
186
187
188 /*
189 * smb_sd_tofs
190 *
191 * Creates a filesystem security structure based on the given
192 * Windows security descriptor.
193 */
194 uint32_t
smb_sd_tofs(smb_sd_t * sd,smb_fssd_t * fs_sd)195 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
196 {
197 smb_sid_t *sid;
198 uint32_t status = NT_STATUS_SUCCESS;
199 uint16_t sd_control;
200 idmap_stat idm_stat;
201 int idtype;
202 int flags = 0;
203
204 sd_control = sd->sd_control;
205
206 /*
207 * ZFS only has one set of flags so for now only
208 * Windows DACL flags are taken into account.
209 */
210 if (sd_control & SE_DACL_DEFAULTED)
211 flags |= ACL_DEFAULTED;
212 if (sd_control & SE_DACL_AUTO_INHERITED)
213 flags |= ACL_AUTO_INHERIT;
214 if (sd_control & SE_DACL_PROTECTED)
215 flags |= ACL_PROTECTED;
216
217 if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
218 flags |= ACL_IS_DIR;
219
220 /* Owner */
221 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
222 sid = sd->sd_owner;
223 if (!smb_sid_isvalid(sid))
224 return (NT_STATUS_INVALID_SID);
225
226 idtype = SMB_IDMAP_USER;
227 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
228 if (idm_stat != IDMAP_SUCCESS) {
229 return (NT_STATUS_NONE_MAPPED);
230 }
231 }
232
233 /* Group */
234 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
235 sid = sd->sd_group;
236 if (!smb_sid_isvalid(sid))
237 return (NT_STATUS_INVALID_SID);
238
239 idtype = SMB_IDMAP_GROUP;
240 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
241 if (idm_stat != IDMAP_SUCCESS) {
242 return (NT_STATUS_NONE_MAPPED);
243 }
244 }
245
246 /* DACL */
247 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
248 if (sd->sd_control & SE_DACL_PRESENT) {
249 status = smb_acl_to_zfs(sd->sd_dacl, flags,
250 SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
251 if (status != NT_STATUS_SUCCESS)
252 return (status);
253 }
254 else
255 return (NT_STATUS_INVALID_ACL);
256 }
257
258 /* SACL */
259 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
260 if (sd->sd_control & SE_SACL_PRESENT) {
261 status = smb_acl_to_zfs(sd->sd_sacl, flags,
262 SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
263 if (status != NT_STATUS_SUCCESS) {
264 return (status);
265 }
266 } else {
267 return (NT_STATUS_INVALID_ACL);
268 }
269 }
270
271 return (status);
272 }
273
274 /*
275 * smb_sd_fromfs
276 *
277 * Makes an Windows style security descriptor in absolute form
278 * based on the given filesystem security information.
279 *
280 * Should call smb_sd_term() for the returned sd to free allocated
281 * members.
282 */
283 static uint32_t
smb_sd_fromfs(smb_fssd_t * fs_sd,smb_sd_t * sd)284 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
285 {
286 uint32_t status = NT_STATUS_SUCCESS;
287 smb_acl_t *acl = NULL;
288 smb_sid_t *sid;
289 idmap_stat idm_stat;
290
291 ASSERT(fs_sd);
292 ASSERT(sd);
293
294 smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
295
296 /* Owner */
297 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
298 idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
299 SMB_IDMAP_USER, &sid);
300
301 if (idm_stat != IDMAP_SUCCESS) {
302 smb_sd_term(sd);
303 return (NT_STATUS_NONE_MAPPED);
304 }
305
306 sd->sd_owner = sid;
307 }
308
309 /* Group */
310 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
311 idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
312 SMB_IDMAP_GROUP, &sid);
313
314 if (idm_stat != IDMAP_SUCCESS) {
315 smb_sd_term(sd);
316 return (NT_STATUS_NONE_MAPPED);
317 }
318
319 sd->sd_group = sid;
320 }
321
322 /* DACL */
323 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
324 if (fs_sd->sd_zdacl != NULL) {
325 acl = smb_acl_from_zfs(fs_sd->sd_zdacl);
326 if (acl == NULL) {
327 smb_sd_term(sd);
328 return (NT_STATUS_INTERNAL_ERROR);
329 }
330
331 /*
332 * Need to sort the ACL before send it to Windows
333 * clients. Winodws GUI is sensitive about the order
334 * of ACEs.
335 */
336 smb_acl_sort(acl);
337 smb_sd_set_dacl(sd, acl, B_TRUE,
338 fs_sd->sd_zdacl->acl_flags);
339 } else {
340 smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
341 }
342 }
343
344 /* SACL */
345 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
346 if (fs_sd->sd_zsacl != NULL) {
347 acl = smb_acl_from_zfs(fs_sd->sd_zsacl);
348 if (acl == NULL) {
349 smb_sd_term(sd);
350 return (NT_STATUS_INTERNAL_ERROR);
351 }
352
353 smb_sd_set_sacl(sd, acl, B_TRUE,
354 fs_sd->sd_zsacl->acl_flags);
355 } else {
356 smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
357 }
358 }
359
360 return (status);
361 }
362
363 static void
smb_sd_set_dacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)364 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
365 {
366 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
367
368 sd->sd_dacl = acl;
369
370 if (flags & ACL_DEFAULTED)
371 sd->sd_control |= SE_DACL_DEFAULTED;
372 if (flags & ACL_AUTO_INHERIT)
373 sd->sd_control |= SE_DACL_AUTO_INHERITED;
374 if (flags & ACL_PROTECTED)
375 sd->sd_control |= SE_DACL_PROTECTED;
376
377 if (present)
378 sd->sd_control |= SE_DACL_PRESENT;
379 }
380
381 static void
smb_sd_set_sacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)382 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
383 {
384 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
385
386 sd->sd_sacl = acl;
387
388 if (flags & ACL_DEFAULTED)
389 sd->sd_control |= SE_SACL_DEFAULTED;
390 if (flags & ACL_AUTO_INHERIT)
391 sd->sd_control |= SE_SACL_AUTO_INHERITED;
392 if (flags & ACL_PROTECTED)
393 sd->sd_control |= SE_SACL_PROTECTED;
394
395 if (present)
396 sd->sd_control |= SE_SACL_PRESENT;
397 }
398
399 /*
400 * smb_fssd_init
401 *
402 * Initializes the given FS SD structure.
403 */
404 void
smb_fssd_init(smb_fssd_t * fs_sd,uint32_t secinfo,uint32_t flags)405 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
406 {
407 bzero(fs_sd, sizeof (smb_fssd_t));
408 fs_sd->sd_secinfo = secinfo;
409 fs_sd->sd_flags = flags;
410 }
411
412 /*
413 * smb_fssd_term
414 *
415 * Frees allocated memory for acl fields.
416 */
417 void
smb_fssd_term(smb_fssd_t * fs_sd)418 smb_fssd_term(smb_fssd_t *fs_sd)
419 {
420 ASSERT(fs_sd);
421
422 smb_fsacl_free(fs_sd->sd_zdacl);
423 smb_fsacl_free(fs_sd->sd_zsacl);
424 bzero(fs_sd, sizeof (smb_fssd_t));
425 }
426