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
26 /*
27 * This module provides Security Descriptor handling functions.
28 */
29
30 #include <smbsrv/smb_kproto.h>
31 #include <smbsrv/smb_fsops.h>
32 #include <smbsrv/smb_idmap.h>
33
34 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
35 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
36 static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *);
37
38 void
smb_sd_init(smb_sd_t * sd,uint8_t revision)39 smb_sd_init(smb_sd_t *sd, uint8_t revision)
40 {
41 bzero(sd, sizeof (smb_sd_t));
42 sd->sd_revision = revision;
43 }
44
45 /*
46 * smb_sd_term
47 *
48 * Free non-NULL members of 'sd' which has to be in
49 * absolute (pointer) form.
50 */
51 void
smb_sd_term(smb_sd_t * sd)52 smb_sd_term(smb_sd_t *sd)
53 {
54 ASSERT(sd);
55 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
56
57 smb_sid_free(sd->sd_owner);
58 smb_sid_free(sd->sd_group);
59 smb_acl_free(sd->sd_dacl);
60 smb_acl_free(sd->sd_sacl);
61
62 bzero(sd, sizeof (smb_sd_t));
63 }
64
65 uint32_t
smb_sd_len(smb_sd_t * sd,uint32_t secinfo)66 smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
67 {
68 uint32_t length = SMB_SD_HDRSIZE;
69
70 if (secinfo & SMB_OWNER_SECINFO)
71 length += smb_sid_len(sd->sd_owner);
72
73 if (secinfo & SMB_GROUP_SECINFO)
74 length += smb_sid_len(sd->sd_group);
75
76 if (secinfo & SMB_DACL_SECINFO)
77 length += smb_acl_len(sd->sd_dacl);
78
79 if (secinfo & SMB_SACL_SECINFO)
80 length += smb_acl_len(sd->sd_sacl);
81
82 return (length);
83 }
84
85 /*
86 * smb_sd_get_secinfo
87 *
88 * Return the security information mask for the specified security
89 * descriptor.
90 */
91 uint32_t
smb_sd_get_secinfo(smb_sd_t * sd)92 smb_sd_get_secinfo(smb_sd_t *sd)
93 {
94 uint32_t sec_info = 0;
95
96 if (sd == NULL)
97 return (0);
98
99 if (sd->sd_owner)
100 sec_info |= SMB_OWNER_SECINFO;
101
102 if (sd->sd_group)
103 sec_info |= SMB_GROUP_SECINFO;
104
105 if (sd->sd_dacl)
106 sec_info |= SMB_DACL_SECINFO;
107
108 if (sd->sd_sacl)
109 sec_info |= SMB_SACL_SECINFO;
110
111 return (sec_info);
112 }
113
114 /*
115 * smb_sd_read
116 *
117 * Read uid, gid and ACL from filesystem. The returned ACL from read
118 * routine is always in ZFS format. Convert the ZFS acl to a Win acl
119 * and return the Win SD in absolute form.
120 *
121 * NOTE: upon successful return caller MUST free the memory allocated
122 * for the returned SD by calling smb_sd_term().
123 */
124 uint32_t
smb_sd_read(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)125 smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
126 {
127 smb_fssd_t fs_sd;
128 smb_error_t smb_err;
129 smb_node_t *node;
130 uint32_t status = NT_STATUS_SUCCESS;
131 uint32_t sd_flags;
132 int error;
133
134 node = sr->fid_ofile->f_node;
135 sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
136 smb_fssd_init(&fs_sd, secinfo, sd_flags);
137
138 error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
139 if (error) {
140 smbsr_map_errno(error, &smb_err);
141 return (smb_err.status);
142 }
143
144 status = smb_sd_fromfs(&fs_sd, sd);
145 smb_fssd_term(&fs_sd);
146
147 return (status);
148 }
149
150 /*
151 * smb_sd_write
152 *
153 * Takes a Win SD in absolute form, converts it to
154 * ZFS format and write it to filesystem. The write routine
155 * converts ZFS acl to Posix acl if required.
156 */
157 uint32_t
smb_sd_write(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)158 smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
159 {
160 smb_node_t *node;
161 smb_fssd_t fs_sd;
162 smb_error_t smb_err;
163 uint32_t status;
164 uint32_t sd_flags;
165 int error;
166
167 node = sr->fid_ofile->f_node;
168 sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
169 smb_fssd_init(&fs_sd, secinfo, sd_flags);
170
171 status = smb_sd_tofs(sd, &fs_sd);
172 if (status != NT_STATUS_SUCCESS) {
173 smb_fssd_term(&fs_sd);
174 return (status);
175 }
176
177 error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
178 smb_fssd_term(&fs_sd);
179
180 if (error) {
181 if (error == EBADE)
182 return (NT_STATUS_INVALID_OWNER);
183 smbsr_map_errno(error, &smb_err);
184 return (smb_err.status);
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 /* DACL */
250 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
251 if (sd->sd_control & SE_DACL_PRESENT) {
252 status = smb_acl_to_zfs(sd->sd_dacl, flags,
253 SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
254 if (status != NT_STATUS_SUCCESS)
255 return (status);
256 }
257 else
258 return (NT_STATUS_INVALID_ACL);
259 }
260
261 /* SACL */
262 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
263 if (sd->sd_control & SE_SACL_PRESENT) {
264 status = smb_acl_to_zfs(sd->sd_sacl, flags,
265 SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
266 if (status != NT_STATUS_SUCCESS) {
267 return (status);
268 }
269 } else {
270 return (NT_STATUS_INVALID_ACL);
271 }
272 }
273
274 return (status);
275 }
276
277 /*
278 * smb_sd_fromfs
279 *
280 * Makes an Windows style security descriptor in absolute form
281 * based on the given filesystem security information.
282 *
283 * Should call smb_sd_term() for the returned sd to free allocated
284 * members.
285 */
286 static uint32_t
smb_sd_fromfs(smb_fssd_t * fs_sd,smb_sd_t * sd)287 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
288 {
289 uint32_t status = NT_STATUS_SUCCESS;
290 smb_acl_t *acl = NULL;
291 smb_sid_t *sid;
292 idmap_stat idm_stat;
293
294 ASSERT(fs_sd);
295 ASSERT(sd);
296
297 smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
298
299 /* Owner */
300 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
301 idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
302 SMB_IDMAP_USER, &sid);
303
304 if (idm_stat != IDMAP_SUCCESS) {
305 smb_sd_term(sd);
306 return (NT_STATUS_NONE_MAPPED);
307 }
308
309 sd->sd_owner = sid;
310 }
311
312 /* Group */
313 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
314 idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
315 SMB_IDMAP_GROUP, &sid);
316
317 if (idm_stat != IDMAP_SUCCESS) {
318 smb_sd_term(sd);
319 return (NT_STATUS_NONE_MAPPED);
320 }
321
322 sd->sd_group = sid;
323 }
324
325 /* DACL */
326 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
327 if (fs_sd->sd_zdacl != NULL) {
328 acl = smb_acl_from_zfs(fs_sd->sd_zdacl);
329 if (acl == NULL) {
330 smb_sd_term(sd);
331 return (NT_STATUS_INTERNAL_ERROR);
332 }
333
334 /*
335 * Need to sort the ACL before send it to Windows
336 * clients. Winodws GUI is sensitive about the order
337 * of ACEs.
338 */
339 smb_acl_sort(acl);
340 smb_sd_set_dacl(sd, acl, B_TRUE,
341 fs_sd->sd_zdacl->acl_flags);
342 } else {
343 smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
344 }
345 }
346
347 /* SACL */
348 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
349 if (fs_sd->sd_zsacl != NULL) {
350 acl = smb_acl_from_zfs(fs_sd->sd_zsacl);
351 if (acl == NULL) {
352 smb_sd_term(sd);
353 return (NT_STATUS_INTERNAL_ERROR);
354 }
355
356 smb_sd_set_sacl(sd, acl, B_TRUE,
357 fs_sd->sd_zsacl->acl_flags);
358 } else {
359 smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
360 }
361 }
362
363 return (status);
364 }
365
366 static void
smb_sd_set_dacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)367 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
368 {
369 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
370
371 sd->sd_dacl = acl;
372
373 if (flags & ACL_DEFAULTED)
374 sd->sd_control |= SE_DACL_DEFAULTED;
375 if (flags & ACL_AUTO_INHERIT)
376 sd->sd_control |= SE_DACL_AUTO_INHERITED;
377 if (flags & ACL_PROTECTED)
378 sd->sd_control |= SE_DACL_PROTECTED;
379
380 if (present)
381 sd->sd_control |= SE_DACL_PRESENT;
382 }
383
384 static void
smb_sd_set_sacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)385 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
386 {
387 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
388
389 sd->sd_sacl = acl;
390
391 if (flags & ACL_DEFAULTED)
392 sd->sd_control |= SE_SACL_DEFAULTED;
393 if (flags & ACL_AUTO_INHERIT)
394 sd->sd_control |= SE_SACL_AUTO_INHERITED;
395 if (flags & ACL_PROTECTED)
396 sd->sd_control |= SE_SACL_PROTECTED;
397
398 if (present)
399 sd->sd_control |= SE_SACL_PRESENT;
400 }
401
402 /*
403 * smb_fssd_init
404 *
405 * Initializes the given FS SD structure.
406 */
407 void
smb_fssd_init(smb_fssd_t * fs_sd,uint32_t secinfo,uint32_t flags)408 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
409 {
410 bzero(fs_sd, sizeof (smb_fssd_t));
411 fs_sd->sd_secinfo = secinfo;
412 fs_sd->sd_flags = flags;
413 }
414
415 /*
416 * smb_fssd_term
417 *
418 * Frees allocated memory for acl fields.
419 */
420 void
smb_fssd_term(smb_fssd_t * fs_sd)421 smb_fssd_term(smb_fssd_t *fs_sd)
422 {
423 ASSERT(fs_sd);
424
425 smb_fsacl_free(fs_sd->sd_zdacl);
426 smb_fsacl_free(fs_sd->sd_zsacl);
427 bzero(fs_sd, sizeof (smb_fssd_t));
428 }
429