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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/sid.h>
26 #include <sys/nbmlock.h>
27 #include <smbsrv/smb_fsops.h>
28 #include <smbsrv/smb_kproto.h>
29 #include <acl/acl_common.h>
30 #include <sys/fcntl.h>
31 #include <sys/flock.h>
32 #include <fs/fs_subr.h>
33
34 extern caller_context_t smb_ct;
35
36 static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *,
37 char *, char *, int, smb_attr_t *, smb_node_t **);
38
39 static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *,
40 char *, int, smb_attr_t *, smb_node_t **);
41
42 static int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *,
43 char *, smb_attr_t *, smb_node_t **, smb_fssd_t *);
44
45 static int smb_fsop_sdinherit(smb_request_t *, smb_node_t *, smb_fssd_t *);
46
47 /*
48 * The smb_fsop_* functions have knowledge of CIFS semantics.
49 *
50 * The smb_vop_* functions have minimal knowledge of CIFS semantics and
51 * serve as an interface to the VFS layer.
52 *
53 * Hence, smb_request_t and smb_node_t structures should not be passed
54 * from the smb_fsop_* layer to the smb_vop_* layer.
55 *
56 * In general, CIFS service code should only ever call smb_fsop_*
57 * functions directly, and never smb_vop_* functions directly.
58 *
59 * smb_fsop_* functions should call smb_vop_* functions where possible, instead
60 * of their smb_fsop_* counterparts. However, there are times when
61 * this cannot be avoided.
62 */
63
64 /*
65 * Note: Stream names cannot be mangled.
66 */
67
68 /*
69 * smb_fsop_amask_to_omode
70 *
71 * Convert the access mask to the open mode (for use
72 * with the VOP_OPEN call).
73 *
74 * Note that opening a file for attribute only access
75 * will also translate into an FREAD or FWRITE open mode
76 * (i.e., it's not just for data).
77 *
78 * This is needed so that opens are tracked appropriately
79 * for oplock processing.
80 */
81
82 int
smb_fsop_amask_to_omode(uint32_t access)83 smb_fsop_amask_to_omode(uint32_t access)
84 {
85 int mode = 0;
86
87 if (access & (FILE_READ_DATA | FILE_EXECUTE |
88 FILE_READ_ATTRIBUTES | FILE_READ_EA))
89 mode |= FREAD;
90
91 if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA |
92 FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))
93 mode |= FWRITE;
94
95 if (access & FILE_APPEND_DATA)
96 mode |= FAPPEND;
97
98 return (mode);
99 }
100
101 int
smb_fsop_open(smb_node_t * node,int mode,cred_t * cred)102 smb_fsop_open(smb_node_t *node, int mode, cred_t *cred)
103 {
104 /*
105 * Assuming that the same vnode is returned as we had before.
106 * (I.e., with certain types of files or file systems, a
107 * different vnode might be returned by VOP_OPEN)
108 */
109 return (smb_vop_open(&node->vp, mode, cred));
110 }
111
112 void
smb_fsop_close(smb_node_t * node,int mode,cred_t * cred)113 smb_fsop_close(smb_node_t *node, int mode, cred_t *cred)
114 {
115 smb_vop_close(node->vp, mode, cred);
116 }
117
118 static int
smb_fsop_create_with_sd(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,smb_attr_t * attr,smb_node_t ** ret_snode,smb_fssd_t * fs_sd)119 smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr,
120 smb_node_t *dnode, char *name,
121 smb_attr_t *attr, smb_node_t **ret_snode, smb_fssd_t *fs_sd)
122 {
123 vsecattr_t *vsap;
124 vsecattr_t vsecattr;
125 acl_t *acl, *dacl, *sacl;
126 smb_attr_t set_attr;
127 vnode_t *vp;
128 int aclbsize = 0; /* size of acl list in bytes */
129 int flags = 0;
130 int rc;
131 boolean_t is_dir;
132
133 ASSERT(fs_sd);
134
135 if (SMB_TREE_IS_CASEINSENSITIVE(sr))
136 flags = SMB_IGNORE_CASE;
137 if (SMB_TREE_SUPPORTS_CATIA(sr))
138 flags |= SMB_CATIA;
139
140 ASSERT(cr);
141
142 is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0);
143
144 if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) {
145 if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
146 dacl = fs_sd->sd_zdacl;
147 sacl = fs_sd->sd_zsacl;
148 ASSERT(dacl || sacl);
149 if (dacl && sacl) {
150 acl = smb_fsacl_merge(dacl, sacl);
151 } else if (dacl) {
152 acl = dacl;
153 } else {
154 acl = sacl;
155 }
156
157 rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize);
158
159 if (dacl && sacl)
160 acl_free(acl);
161
162 if (rc != 0)
163 return (rc);
164
165 vsap = &vsecattr;
166 } else {
167 vsap = NULL;
168 }
169
170 /* The tree ACEs may prevent a create */
171 rc = EACCES;
172 if (is_dir) {
173 if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0)
174 rc = smb_vop_mkdir(dnode->vp, name, attr,
175 &vp, flags, cr, vsap);
176 } else {
177 if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0)
178 rc = smb_vop_create(dnode->vp, name, attr,
179 &vp, flags, cr, vsap);
180 }
181
182 if (vsap != NULL)
183 kmem_free(vsap->vsa_aclentp, aclbsize);
184
185 if (rc != 0)
186 return (rc);
187
188 set_attr.sa_mask = 0;
189
190 /*
191 * Ideally we should be able to specify the owner and owning
192 * group at create time along with the ACL. Since we cannot
193 * do that right now, kcred is passed to smb_vop_setattr so it
194 * doesn't fail due to lack of permission.
195 */
196 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
197 set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
198 set_attr.sa_mask |= SMB_AT_UID;
199 }
200
201 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
202 set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
203 set_attr.sa_mask |= SMB_AT_GID;
204 }
205
206 if (set_attr.sa_mask)
207 rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred);
208
209 if (rc == 0) {
210 *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
211 name, dnode, NULL);
212
213 if (*ret_snode == NULL)
214 rc = ENOMEM;
215
216 VN_RELE(vp);
217 }
218 } else {
219 /*
220 * For filesystems that don't support ACL-on-create, try
221 * to set the specified SD after create, which could actually
222 * fail because of conflicts between inherited security
223 * attributes upon creation and the specified SD.
224 *
225 * Passing kcred to smb_fsop_sdwrite() to overcome this issue.
226 */
227
228 if (is_dir) {
229 rc = smb_vop_mkdir(dnode->vp, name, attr, &vp,
230 flags, cr, NULL);
231 } else {
232 rc = smb_vop_create(dnode->vp, name, attr, &vp,
233 flags, cr, NULL);
234 }
235
236 if (rc != 0)
237 return (rc);
238
239 *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
240 name, dnode, NULL);
241
242 if (*ret_snode != NULL) {
243 if (!smb_tree_has_feature(sr->tid_tree,
244 SMB_TREE_NFS_MOUNTED))
245 rc = smb_fsop_sdwrite(sr, kcred, *ret_snode,
246 fs_sd, 1);
247 } else {
248 rc = ENOMEM;
249 }
250
251 VN_RELE(vp);
252 }
253
254 if (rc != 0) {
255 if (is_dir)
256 (void) smb_vop_rmdir(dnode->vp, name, flags, cr);
257 else
258 (void) smb_vop_remove(dnode->vp, name, flags, cr);
259 }
260
261 return (rc);
262 }
263
264 /*
265 * smb_fsop_create
266 *
267 * All SMB functions should use this wrapper to ensure that
268 * all the smb_vop_creates are performed with the appropriate credentials.
269 * Please document any direct calls to explain the reason for avoiding
270 * this wrapper.
271 *
272 * *ret_snode is returned with a reference upon success. No reference is
273 * taken if an error is returned.
274 */
275 int
smb_fsop_create(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,smb_attr_t * attr,smb_node_t ** ret_snode)276 smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
277 char *name, smb_attr_t *attr, smb_node_t **ret_snode)
278 {
279 int rc = 0;
280 int flags = 0;
281 char *fname, *sname;
282 char *longname = NULL;
283
284 ASSERT(cr);
285 ASSERT(dnode);
286 ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
287 ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
288
289 ASSERT(ret_snode);
290 *ret_snode = 0;
291
292 ASSERT(name);
293 if (*name == 0)
294 return (EINVAL);
295
296 ASSERT(sr);
297 ASSERT(sr->tid_tree);
298
299 if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
300 return (EACCES);
301
302 if (SMB_TREE_IS_READONLY(sr))
303 return (EROFS);
304
305 if (SMB_TREE_IS_CASEINSENSITIVE(sr))
306 flags = SMB_IGNORE_CASE;
307 if (SMB_TREE_SUPPORTS_CATIA(sr))
308 flags |= SMB_CATIA;
309 if (SMB_TREE_SUPPORTS_ABE(sr))
310 flags |= SMB_ABE;
311
312 if (smb_is_stream_name(name)) {
313 fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
314 sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
315 smb_stream_parse_name(name, fname, sname);
316
317 rc = smb_fsop_create_stream(sr, cr, dnode,
318 fname, sname, flags, attr, ret_snode);
319
320 kmem_free(fname, MAXNAMELEN);
321 kmem_free(sname, MAXNAMELEN);
322 return (rc);
323 }
324
325 /* Not a named stream */
326
327 if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) {
328 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
329 rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
330 kmem_free(longname, MAXNAMELEN);
331
332 if (rc == 0)
333 rc = EEXIST;
334 if (rc != ENOENT)
335 return (rc);
336 }
337
338 rc = smb_fsop_create_file(sr, cr, dnode, name, flags,
339 attr, ret_snode);
340 return (rc);
341
342 }
343
344
345 /*
346 * smb_fsop_create_stream
347 *
348 * Create NTFS named stream file (sname) on unnamed stream
349 * file (fname), creating the unnamed stream file if it
350 * doesn't exist.
351 * If we created the unnamed stream file and then creation
352 * of the named stream file fails, we delete the unnamed stream.
353 * Since we use the real file name for the smb_vop_remove we
354 * clear the SMB_IGNORE_CASE flag to ensure a case sensitive
355 * match.
356 *
357 * The second parameter of smb_vop_setattr() is set to
358 * NULL, even though an unnamed stream exists. This is
359 * because we want to set the UID and GID on the named
360 * stream in this case for consistency with the (unnamed
361 * stream) file (see comments for smb_vop_setattr()).
362 */
363 static int
smb_fsop_create_stream(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * fname,char * sname,int flags,smb_attr_t * attr,smb_node_t ** ret_snode)364 smb_fsop_create_stream(smb_request_t *sr, cred_t *cr,
365 smb_node_t *dnode, char *fname, char *sname, int flags,
366 smb_attr_t *attr, smb_node_t **ret_snode)
367 {
368 smb_node_t *fnode;
369 smb_attr_t fattr;
370 vnode_t *xattrdvp;
371 vnode_t *vp;
372 int rc = 0;
373 boolean_t fcreate = B_FALSE;
374
375 /* Look up / create the unnamed stream, fname */
376 rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
377 sr->tid_tree->t_snode, dnode, fname, &fnode);
378 if (rc == ENOENT) {
379 fcreate = B_TRUE;
380 rc = smb_fsop_create_file(sr, cr, dnode, fname, flags,
381 attr, &fnode);
382 }
383 if (rc != 0)
384 return (rc);
385
386 fattr.sa_mask = SMB_AT_UID | SMB_AT_GID;
387 rc = smb_vop_getattr(fnode->vp, NULL, &fattr, 0, kcred);
388
389 if (rc == 0) {
390 /* create the named stream, sname */
391 rc = smb_vop_stream_create(fnode->vp, sname, attr,
392 &vp, &xattrdvp, flags, cr);
393 }
394 if (rc != 0) {
395 if (fcreate) {
396 flags &= ~SMB_IGNORE_CASE;
397 (void) smb_vop_remove(dnode->vp,
398 fnode->od_name, flags, cr);
399 }
400 smb_node_release(fnode);
401 return (rc);
402 }
403
404 attr->sa_vattr.va_uid = fattr.sa_vattr.va_uid;
405 attr->sa_vattr.va_gid = fattr.sa_vattr.va_gid;
406 attr->sa_mask = SMB_AT_UID | SMB_AT_GID;
407
408 rc = smb_vop_setattr(vp, NULL, attr, 0, kcred);
409 if (rc != 0) {
410 smb_node_release(fnode);
411 return (rc);
412 }
413
414 *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp,
415 vp, sname);
416
417 smb_node_release(fnode);
418 VN_RELE(xattrdvp);
419 VN_RELE(vp);
420
421 if (*ret_snode == NULL)
422 rc = ENOMEM;
423
424 /* notify change to the unnamed stream */
425 if (rc == 0)
426 smb_node_notify_change(dnode);
427
428 return (rc);
429 }
430
431 /*
432 * smb_fsop_create_file
433 */
434 static int
smb_fsop_create_file(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,int flags,smb_attr_t * attr,smb_node_t ** ret_snode)435 smb_fsop_create_file(smb_request_t *sr, cred_t *cr,
436 smb_node_t *dnode, char *name, int flags,
437 smb_attr_t *attr, smb_node_t **ret_snode)
438 {
439 smb_arg_open_t *op = &sr->sr_open;
440 vnode_t *vp;
441 smb_fssd_t fs_sd;
442 uint32_t secinfo;
443 uint32_t status;
444 int rc = 0;
445
446 if (op->sd) {
447 /*
448 * SD sent by client in Windows format. Needs to be
449 * converted to FS format. No inheritance.
450 */
451 secinfo = smb_sd_get_secinfo(op->sd);
452 smb_fssd_init(&fs_sd, secinfo, 0);
453
454 status = smb_sd_tofs(op->sd, &fs_sd);
455 if (status == NT_STATUS_SUCCESS) {
456 rc = smb_fsop_create_with_sd(sr, cr, dnode,
457 name, attr, ret_snode, &fs_sd);
458 } else {
459 rc = EINVAL;
460 }
461 smb_fssd_term(&fs_sd);
462 } else if (sr->tid_tree->t_acltype == ACE_T) {
463 /*
464 * No incoming SD and filesystem is ZFS
465 * Server applies Windows inheritance rules,
466 * see smb_fsop_sdinherit() comments as to why.
467 */
468 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0);
469 rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
470 if (rc == 0) {
471 rc = smb_fsop_create_with_sd(sr, cr, dnode,
472 name, attr, ret_snode, &fs_sd);
473 }
474
475 smb_fssd_term(&fs_sd);
476 } else {
477 /*
478 * No incoming SD and filesystem is not ZFS
479 * let the filesystem handles the inheritance.
480 */
481 rc = smb_vop_create(dnode->vp, name, attr, &vp,
482 flags, cr, NULL);
483
484 if (rc == 0) {
485 *ret_snode = smb_node_lookup(sr, op, cr, vp,
486 name, dnode, NULL);
487
488 if (*ret_snode == NULL)
489 rc = ENOMEM;
490
491 VN_RELE(vp);
492 }
493
494 }
495
496 if (rc == 0)
497 smb_node_notify_parents(dnode);
498
499 return (rc);
500 }
501
502 /*
503 * smb_fsop_mkdir
504 *
505 * All SMB functions should use this wrapper to ensure that
506 * the the calls are performed with the appropriate credentials.
507 * Please document any direct call to explain the reason
508 * for avoiding this wrapper.
509 *
510 * It is assumed that a reference exists on snode coming into this routine.
511 *
512 * *ret_snode is returned with a reference upon success. No reference is
513 * taken if an error is returned.
514 */
515 int
smb_fsop_mkdir(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,smb_attr_t * attr,smb_node_t ** ret_snode)516 smb_fsop_mkdir(
517 smb_request_t *sr,
518 cred_t *cr,
519 smb_node_t *dnode,
520 char *name,
521 smb_attr_t *attr,
522 smb_node_t **ret_snode)
523 {
524 struct open_param *op = &sr->arg.open;
525 char *longname;
526 vnode_t *vp;
527 int flags = 0;
528 smb_fssd_t fs_sd;
529 uint32_t secinfo;
530 uint32_t status;
531 int rc;
532 ASSERT(cr);
533 ASSERT(dnode);
534 ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
535 ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
536
537 ASSERT(ret_snode);
538 *ret_snode = 0;
539
540 ASSERT(name);
541 if (*name == 0)
542 return (EINVAL);
543
544 ASSERT(sr);
545 ASSERT(sr->tid_tree);
546
547 if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
548 return (EACCES);
549
550 if (SMB_TREE_IS_READONLY(sr))
551 return (EROFS);
552 if (SMB_TREE_SUPPORTS_CATIA(sr))
553 flags |= SMB_CATIA;
554 if (SMB_TREE_SUPPORTS_ABE(sr))
555 flags |= SMB_ABE;
556
557 if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) {
558 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
559 rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
560 kmem_free(longname, MAXNAMELEN);
561
562 /*
563 * If the name passed in by the client has an unmangled
564 * equivalent that is found in the specified directory,
565 * then the mkdir cannot succeed. Return EEXIST.
566 *
567 * Only if ENOENT is returned will a mkdir be attempted.
568 */
569
570 if (rc == 0)
571 rc = EEXIST;
572
573 if (rc != ENOENT)
574 return (rc);
575 }
576
577 if (SMB_TREE_IS_CASEINSENSITIVE(sr))
578 flags = SMB_IGNORE_CASE;
579
580 if (op->sd) {
581 /*
582 * SD sent by client in Windows format. Needs to be
583 * converted to FS format. No inheritance.
584 */
585 secinfo = smb_sd_get_secinfo(op->sd);
586 smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
587
588 status = smb_sd_tofs(op->sd, &fs_sd);
589 if (status == NT_STATUS_SUCCESS) {
590 rc = smb_fsop_create_with_sd(sr, cr, dnode,
591 name, attr, ret_snode, &fs_sd);
592 }
593 else
594 rc = EINVAL;
595 smb_fssd_term(&fs_sd);
596 } else if (sr->tid_tree->t_acltype == ACE_T) {
597 /*
598 * No incoming SD and filesystem is ZFS
599 * Server applies Windows inheritance rules,
600 * see smb_fsop_sdinherit() comments as to why.
601 */
602 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR);
603 rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
604 if (rc == 0) {
605 rc = smb_fsop_create_with_sd(sr, cr, dnode,
606 name, attr, ret_snode, &fs_sd);
607 }
608
609 smb_fssd_term(&fs_sd);
610
611 } else {
612 rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr,
613 NULL);
614
615 if (rc == 0) {
616 *ret_snode = smb_node_lookup(sr, op, cr, vp, name,
617 dnode, NULL);
618
619 if (*ret_snode == NULL)
620 rc = ENOMEM;
621
622 VN_RELE(vp);
623 }
624 }
625
626 if (rc == 0)
627 smb_node_notify_parents(dnode);
628
629 return (rc);
630 }
631
632 /*
633 * smb_fsop_remove
634 *
635 * All SMB functions should use this wrapper to ensure that
636 * the the calls are performed with the appropriate credentials.
637 * Please document any direct call to explain the reason
638 * for avoiding this wrapper.
639 *
640 * It is assumed that a reference exists on snode coming into this routine.
641 *
642 * A null smb_request might be passed to this function.
643 */
644 int
smb_fsop_remove(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,uint32_t flags)645 smb_fsop_remove(
646 smb_request_t *sr,
647 cred_t *cr,
648 smb_node_t *dnode,
649 char *name,
650 uint32_t flags)
651 {
652 smb_node_t *fnode;
653 char *longname;
654 char *fname;
655 char *sname;
656 int rc;
657
658 ASSERT(cr);
659 /*
660 * The state of the node could be SMB_NODE_STATE_DESTROYING if this
661 * function is called during the deletion of the node (because of
662 * DELETE_ON_CLOSE).
663 */
664 ASSERT(dnode);
665 ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
666
667 if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
668 SMB_TREE_HAS_ACCESS(sr, ACE_DELETE) == 0)
669 return (EACCES);
670
671 if (SMB_TREE_IS_READONLY(sr))
672 return (EROFS);
673
674 fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
675 sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
676
677 if (dnode->flags & NODE_XATTR_DIR) {
678 fnode = dnode->n_dnode;
679 rc = smb_vop_stream_remove(fnode->vp, name, flags, cr);
680
681 /* notify change to the unnamed stream */
682 if ((rc == 0) && fnode->n_dnode)
683 smb_node_notify_change(fnode->n_dnode);
684
685 } else if (smb_is_stream_name(name)) {
686 smb_stream_parse_name(name, fname, sname);
687
688 /*
689 * Look up the unnamed stream (i.e. fname).
690 * Unmangle processing will be done on fname
691 * as well as any link target.
692 */
693
694 rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
695 sr->tid_tree->t_snode, dnode, fname, &fnode);
696
697 if (rc != 0) {
698 kmem_free(fname, MAXNAMELEN);
699 kmem_free(sname, MAXNAMELEN);
700 return (rc);
701 }
702
703 /*
704 * XXX
705 * Need to find out what permission is required by NTFS
706 * to remove a stream.
707 */
708 rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr);
709
710 smb_node_release(fnode);
711
712 /* notify change to the unnamed stream */
713 if (rc == 0)
714 smb_node_notify_change(dnode);
715 } else {
716 rc = smb_vop_remove(dnode->vp, name, flags, cr);
717
718 if (rc == ENOENT) {
719 if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
720 !smb_maybe_mangled(name)) {
721 kmem_free(fname, MAXNAMELEN);
722 kmem_free(sname, MAXNAMELEN);
723 return (rc);
724 }
725 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
726
727 if (SMB_TREE_SUPPORTS_ABE(sr))
728 flags |= SMB_ABE;
729
730 rc = smb_unmangle(dnode, name, longname, MAXNAMELEN,
731 flags);
732
733 if (rc == 0) {
734 /*
735 * longname is the real (case-sensitive)
736 * on-disk name.
737 * We make sure we do a remove on this exact
738 * name, as the name was mangled and denotes
739 * a unique file.
740 */
741 flags &= ~SMB_IGNORE_CASE;
742 rc = smb_vop_remove(dnode->vp, longname,
743 flags, cr);
744 }
745
746 if (rc == 0)
747 smb_node_notify_parents(dnode);
748
749 kmem_free(longname, MAXNAMELEN);
750 }
751 }
752
753 kmem_free(fname, MAXNAMELEN);
754 kmem_free(sname, MAXNAMELEN);
755
756 return (rc);
757 }
758
759 /*
760 * smb_fsop_remove_streams
761 *
762 * This function removes a file's streams without removing the
763 * file itself.
764 *
765 * It is assumed that fnode is not a link.
766 */
767 int
smb_fsop_remove_streams(smb_request_t * sr,cred_t * cr,smb_node_t * fnode)768 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode)
769 {
770 int rc, flags = 0;
771 uint16_t odid;
772 smb_odir_t *od;
773 smb_odirent_t *odirent;
774 boolean_t eos;
775
776 ASSERT(sr);
777 ASSERT(cr);
778 ASSERT(fnode);
779 ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
780 ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
781
782 if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) {
783 smbsr_errno(sr, EACCES);
784 return (-1);
785 }
786
787 if (SMB_TREE_IS_READONLY(sr)) {
788 smbsr_errno(sr, EROFS);
789 return (-1);
790 }
791
792 if (SMB_TREE_IS_CASEINSENSITIVE(sr))
793 flags = SMB_IGNORE_CASE;
794
795 if (SMB_TREE_SUPPORTS_CATIA(sr))
796 flags |= SMB_CATIA;
797
798 if ((odid = smb_odir_openat(sr, fnode)) == 0) {
799 smbsr_errno(sr, ENOENT);
800 return (-1);
801 }
802
803 if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) {
804 smbsr_errno(sr, ENOENT);
805 return (-1);
806 }
807
808 odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
809 for (;;) {
810 rc = smb_odir_read(sr, od, odirent, &eos);
811 if ((rc != 0) || (eos))
812 break;
813 (void) smb_vop_remove(od->d_dnode->vp, odirent->od_name,
814 flags, cr);
815 }
816 kmem_free(odirent, sizeof (smb_odirent_t));
817
818 smb_odir_close(od);
819 smb_odir_release(od);
820 return (rc);
821 }
822
823 /*
824 * smb_fsop_rmdir
825 *
826 * All SMB functions should use this wrapper to ensure that
827 * the the calls are performed with the appropriate credentials.
828 * Please document any direct call to explain the reason
829 * for avoiding this wrapper.
830 *
831 * It is assumed that a reference exists on snode coming into this routine.
832 */
833 int
smb_fsop_rmdir(smb_request_t * sr,cred_t * cr,smb_node_t * dnode,char * name,uint32_t flags)834 smb_fsop_rmdir(
835 smb_request_t *sr,
836 cred_t *cr,
837 smb_node_t *dnode,
838 char *name,
839 uint32_t flags)
840 {
841 int rc;
842 char *longname;
843
844 ASSERT(cr);
845 /*
846 * The state of the node could be SMB_NODE_STATE_DESTROYING if this
847 * function is called during the deletion of the node (because of
848 * DELETE_ON_CLOSE).
849 */
850 ASSERT(dnode);
851 ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
852
853 if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 ||
854 SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0)
855 return (EACCES);
856
857 if (SMB_TREE_IS_READONLY(sr))
858 return (EROFS);
859
860 rc = smb_vop_rmdir(dnode->vp, name, flags, cr);
861
862 if (rc == ENOENT) {
863 if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
864 !smb_maybe_mangled(name)) {
865 return (rc);
866 }
867
868 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
869
870 if (SMB_TREE_SUPPORTS_ABE(sr))
871 flags |= SMB_ABE;
872 rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
873
874 if (rc == 0) {
875 /*
876 * longname is the real (case-sensitive)
877 * on-disk name.
878 * We make sure we do a rmdir on this exact
879 * name, as the name was mangled and denotes
880 * a unique directory.
881 */
882 flags &= ~SMB_IGNORE_CASE;
883 rc = smb_vop_rmdir(dnode->vp, longname, flags, cr);
884 }
885
886 kmem_free(longname, MAXNAMELEN);
887 }
888
889 if (rc == 0)
890 smb_node_notify_parents(dnode);
891
892 return (rc);
893 }
894
895 /*
896 * smb_fsop_getattr
897 *
898 * All SMB functions should use this wrapper to ensure that
899 * the the calls are performed with the appropriate credentials.
900 * Please document any direct call to explain the reason
901 * for avoiding this wrapper.
902 *
903 * It is assumed that a reference exists on snode coming into this routine.
904 */
905 int
smb_fsop_getattr(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_attr_t * attr)906 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
907 smb_attr_t *attr)
908 {
909 smb_node_t *unnamed_node;
910 vnode_t *unnamed_vp = NULL;
911 uint32_t status;
912 uint32_t access = 0;
913 int flags = 0;
914 int rc;
915
916 ASSERT(cr);
917 ASSERT(snode);
918 ASSERT(snode->n_magic == SMB_NODE_MAGIC);
919 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
920
921 if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 ||
922 SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0)
923 return (EACCES);
924
925 /* sr could be NULL in some cases */
926 if (sr && sr->fid_ofile) {
927 /* if uid and/or gid is requested */
928 if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
929 access |= READ_CONTROL;
930
931 /* if anything else is also requested */
932 if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID))
933 access |= FILE_READ_ATTRIBUTES;
934
935 status = smb_ofile_access(sr->fid_ofile, cr, access);
936 if (status != NT_STATUS_SUCCESS)
937 return (EACCES);
938
939 if (smb_tree_has_feature(sr->tid_tree,
940 SMB_TREE_ACEMASKONACCESS))
941 flags = ATTR_NOACLCHECK;
942 }
943
944 unnamed_node = SMB_IS_STREAM(snode);
945
946 if (unnamed_node) {
947 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
948 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
949 unnamed_vp = unnamed_node->vp;
950 }
951
952 rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr);
953
954 if ((rc == 0) && smb_node_is_dfslink(snode)) {
955 /* a DFS link should be treated as a directory */
956 attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
957 }
958
959 return (rc);
960 }
961
962 /*
963 * smb_fsop_link
964 *
965 * All SMB functions should use this smb_vop_link wrapper to ensure that
966 * the smb_vop_link is performed with the appropriate credentials.
967 * Please document any direct call to smb_vop_link to explain the reason
968 * for avoiding this wrapper.
969 *
970 * It is assumed that references exist on from_dnode and to_dnode coming
971 * into this routine.
972 */
973 int
smb_fsop_link(smb_request_t * sr,cred_t * cr,smb_node_t * from_fnode,smb_node_t * to_dnode,char * to_name)974 smb_fsop_link(smb_request_t *sr, cred_t *cr, smb_node_t *from_fnode,
975 smb_node_t *to_dnode, char *to_name)
976 {
977 char *longname = NULL;
978 int flags = 0;
979 int rc;
980
981 ASSERT(sr);
982 ASSERT(sr->tid_tree);
983 ASSERT(cr);
984 ASSERT(to_dnode);
985 ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
986 ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
987 ASSERT(from_fnode);
988 ASSERT(from_fnode->n_magic == SMB_NODE_MAGIC);
989 ASSERT(from_fnode->n_state != SMB_NODE_STATE_DESTROYING);
990
991 if (SMB_TREE_CONTAINS_NODE(sr, from_fnode) == 0)
992 return (EACCES);
993
994 if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
995 return (EACCES);
996
997 if (SMB_TREE_IS_READONLY(sr))
998 return (EROFS);
999
1000 if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1001 flags = SMB_IGNORE_CASE;
1002 if (SMB_TREE_SUPPORTS_CATIA(sr))
1003 flags |= SMB_CATIA;
1004 if (SMB_TREE_SUPPORTS_ABE(sr))
1005 flags |= SMB_ABE;
1006
1007 if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(to_name)) {
1008 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1009 rc = smb_unmangle(to_dnode, to_name, longname,
1010 MAXNAMELEN, flags);
1011 kmem_free(longname, MAXNAMELEN);
1012
1013 if (rc == 0)
1014 rc = EEXIST;
1015 if (rc != ENOENT)
1016 return (rc);
1017 }
1018
1019 rc = smb_vop_link(to_dnode->vp, from_fnode->vp, to_name, flags, cr);
1020
1021 if ((rc == 0) && from_fnode->n_dnode)
1022 smb_node_notify_parents(from_fnode->n_dnode);
1023
1024 return (rc);
1025 }
1026
1027 /*
1028 * smb_fsop_rename
1029 *
1030 * All SMB functions should use this smb_vop_rename wrapper to ensure that
1031 * the smb_vop_rename is performed with the appropriate credentials.
1032 * Please document any direct call to smb_vop_rename to explain the reason
1033 * for avoiding this wrapper.
1034 *
1035 * It is assumed that references exist on from_dnode and to_dnode coming
1036 * into this routine.
1037 */
1038 int
smb_fsop_rename(smb_request_t * sr,cred_t * cr,smb_node_t * from_dnode,char * from_name,smb_node_t * to_dnode,char * to_name)1039 smb_fsop_rename(
1040 smb_request_t *sr,
1041 cred_t *cr,
1042 smb_node_t *from_dnode,
1043 char *from_name,
1044 smb_node_t *to_dnode,
1045 char *to_name)
1046 {
1047 smb_node_t *from_snode;
1048 smb_attr_t from_attr;
1049 vnode_t *from_vp;
1050 int flags = 0, ret_flags;
1051 int rc;
1052 boolean_t isdir;
1053
1054 ASSERT(cr);
1055 ASSERT(from_dnode);
1056 ASSERT(from_dnode->n_magic == SMB_NODE_MAGIC);
1057 ASSERT(from_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1058
1059 ASSERT(to_dnode);
1060 ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC);
1061 ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING);
1062
1063 if (SMB_TREE_CONTAINS_NODE(sr, from_dnode) == 0)
1064 return (EACCES);
1065
1066 if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0)
1067 return (EACCES);
1068
1069 ASSERT(sr);
1070 ASSERT(sr->tid_tree);
1071 if (SMB_TREE_IS_READONLY(sr))
1072 return (EROFS);
1073
1074 /*
1075 * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE
1076 * here.
1077 *
1078 * A case-sensitive rename is always done in this routine
1079 * because we are using the on-disk name from an earlier lookup.
1080 * If a mangled name was passed in by the caller (denoting a
1081 * deterministic lookup), then the exact file must be renamed
1082 * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or
1083 * else the underlying file system might return a "first-match"
1084 * on this on-disk name, possibly resulting in the wrong file).
1085 */
1086
1087 if (SMB_TREE_SUPPORTS_CATIA(sr))
1088 flags |= SMB_CATIA;
1089
1090 /*
1091 * XXX: Lock required through smb_node_release() below?
1092 */
1093
1094 rc = smb_vop_lookup(from_dnode->vp, from_name, &from_vp, NULL,
1095 flags, &ret_flags, NULL, &from_attr, cr);
1096
1097 if (rc != 0)
1098 return (rc);
1099
1100 if (from_attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) {
1101 VN_RELE(from_vp);
1102 return (EACCES);
1103 }
1104
1105 isdir = ((from_attr.sa_dosattr & FILE_ATTRIBUTE_DIRECTORY) != 0);
1106
1107 if ((isdir && SMB_TREE_HAS_ACCESS(sr,
1108 ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) !=
1109 (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) ||
1110 (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) !=
1111 (ACE_DELETE | ACE_ADD_FILE))) {
1112 VN_RELE(from_vp);
1113 return (EACCES);
1114 }
1115
1116 /*
1117 * SMB checks access on open and retains an access granted
1118 * mask for use while the file is open. ACL changes should
1119 * not affect access to an open file.
1120 *
1121 * If the rename is being performed on an ofile:
1122 * - Check the ofile's access granted mask to see if the
1123 * rename is permitted - requires DELETE access.
1124 * - If the file system does access checking, set the
1125 * ATTR_NOACLCHECK flag to ensure that the file system
1126 * does not check permissions on subsequent calls.
1127 */
1128 if (sr && sr->fid_ofile) {
1129 rc = smb_ofile_access(sr->fid_ofile, cr, DELETE);
1130 if (rc != NT_STATUS_SUCCESS) {
1131 VN_RELE(from_vp);
1132 return (EACCES);
1133 }
1134
1135 if (smb_tree_has_feature(sr->tid_tree,
1136 SMB_TREE_ACEMASKONACCESS))
1137 flags = ATTR_NOACLCHECK;
1138 }
1139
1140 rc = smb_vop_rename(from_dnode->vp, from_name, to_dnode->vp,
1141 to_name, flags, cr);
1142
1143 if (rc == 0) {
1144 from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name,
1145 from_dnode, NULL);
1146
1147 if (from_snode == NULL) {
1148 rc = ENOMEM;
1149 } else {
1150 smb_node_rename(from_dnode, from_snode,
1151 to_dnode, to_name);
1152 smb_node_release(from_snode);
1153 }
1154 }
1155 VN_RELE(from_vp);
1156
1157 if (rc == 0)
1158 smb_node_notify_parents(from_dnode);
1159
1160 /* XXX: unlock */
1161
1162 return (rc);
1163 }
1164
1165 /*
1166 * smb_fsop_setattr
1167 *
1168 * All SMB functions should use this wrapper to ensure that
1169 * the the calls are performed with the appropriate credentials.
1170 * Please document any direct call to explain the reason
1171 * for avoiding this wrapper.
1172 *
1173 * It is assumed that a reference exists on snode coming into
1174 * this function.
1175 * A null smb_request might be passed to this function.
1176 */
1177 int
smb_fsop_setattr(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_attr_t * set_attr)1178 smb_fsop_setattr(
1179 smb_request_t *sr,
1180 cred_t *cr,
1181 smb_node_t *snode,
1182 smb_attr_t *set_attr)
1183 {
1184 smb_node_t *unnamed_node;
1185 vnode_t *unnamed_vp = NULL;
1186 uint32_t status;
1187 uint32_t access;
1188 int rc = 0;
1189 int flags = 0;
1190 uint_t sa_mask;
1191
1192 ASSERT(cr);
1193 ASSERT(snode);
1194 ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1195 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1196
1197 if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0)
1198 return (EACCES);
1199
1200 if (SMB_TREE_IS_READONLY(sr))
1201 return (EROFS);
1202
1203 if (SMB_TREE_HAS_ACCESS(sr,
1204 ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0)
1205 return (EACCES);
1206
1207 /*
1208 * The file system cannot detect pending READDONLY
1209 * (i.e. if the file has been opened readonly but
1210 * not yet closed) so we need to test READONLY here.
1211 */
1212 if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) {
1213 if (sr->fid_ofile) {
1214 if (SMB_OFILE_IS_READONLY(sr->fid_ofile))
1215 return (EACCES);
1216 } else {
1217 if (SMB_PATHFILE_IS_READONLY(sr, snode))
1218 return (EACCES);
1219 }
1220 }
1221
1222 /*
1223 * SMB checks access on open and retains an access granted
1224 * mask for use while the file is open. ACL changes should
1225 * not affect access to an open file.
1226 *
1227 * If the setattr is being performed on an ofile:
1228 * - Check the ofile's access granted mask to see if the
1229 * setattr is permitted.
1230 * UID, GID - require WRITE_OWNER
1231 * SIZE, ALLOCSZ - require FILE_WRITE_DATA
1232 * all other attributes require FILE_WRITE_ATTRIBUTES
1233 *
1234 * - If the file system does access checking, set the
1235 * ATTR_NOACLCHECK flag to ensure that the file system
1236 * does not check permissions on subsequent calls.
1237 */
1238 if (sr && sr->fid_ofile) {
1239 sa_mask = set_attr->sa_mask;
1240 access = 0;
1241
1242 if (sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ)) {
1243 access |= FILE_WRITE_DATA;
1244 sa_mask &= ~(SMB_AT_SIZE | SMB_AT_ALLOCSZ);
1245 }
1246
1247 if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) {
1248 access |= WRITE_OWNER;
1249 sa_mask &= ~(SMB_AT_UID|SMB_AT_GID);
1250 }
1251
1252 if (sa_mask)
1253 access |= FILE_WRITE_ATTRIBUTES;
1254
1255 status = smb_ofile_access(sr->fid_ofile, cr, access);
1256 if (status != NT_STATUS_SUCCESS)
1257 return (EACCES);
1258
1259 if (smb_tree_has_feature(sr->tid_tree,
1260 SMB_TREE_ACEMASKONACCESS))
1261 flags = ATTR_NOACLCHECK;
1262 }
1263
1264 unnamed_node = SMB_IS_STREAM(snode);
1265
1266 if (unnamed_node) {
1267 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1268 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1269 unnamed_vp = unnamed_node->vp;
1270 }
1271
1272 rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr);
1273 return (rc);
1274 }
1275
1276 /*
1277 * smb_fsop_read
1278 *
1279 * All SMB functions should use this wrapper to ensure that
1280 * the the calls are performed with the appropriate credentials.
1281 * Please document any direct call to explain the reason
1282 * for avoiding this wrapper.
1283 *
1284 * It is assumed that a reference exists on snode coming into this routine.
1285 */
1286 int
smb_fsop_read(smb_request_t * sr,cred_t * cr,smb_node_t * snode,uio_t * uio)1287 smb_fsop_read(smb_request_t *sr, cred_t *cr, smb_node_t *snode, uio_t *uio)
1288 {
1289 caller_context_t ct;
1290 int svmand;
1291 int rc;
1292
1293 ASSERT(cr);
1294 ASSERT(snode);
1295 ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1296 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1297
1298 ASSERT(sr);
1299 ASSERT(sr->fid_ofile);
1300
1301 if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_DATA) == 0)
1302 return (EACCES);
1303
1304 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA);
1305 if ((rc != NT_STATUS_SUCCESS) &&
1306 (sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE))
1307 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE);
1308
1309 if (rc != NT_STATUS_SUCCESS)
1310 return (EACCES);
1311
1312 /*
1313 * Streams permission are checked against the unnamed stream,
1314 * but in FS level they have their own permissions. To avoid
1315 * rejection by FS due to lack of permission on the actual
1316 * extended attr kcred is passed for streams.
1317 */
1318 if (SMB_IS_STREAM(snode))
1319 cr = kcred;
1320
1321 smb_node_start_crit(snode, RW_READER);
1322 rc = nbl_svmand(snode->vp, kcred, &svmand);
1323 if (rc) {
1324 smb_node_end_crit(snode);
1325 return (rc);
1326 }
1327
1328 ct = smb_ct;
1329 ct.cc_pid = sr->fid_ofile->f_uniqid;
1330 rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset,
1331 uio->uio_iov->iov_len, svmand, &ct);
1332
1333 if (rc) {
1334 smb_node_end_crit(snode);
1335 return (ERANGE);
1336 }
1337
1338 rc = smb_vop_read(snode->vp, uio, cr);
1339 smb_node_end_crit(snode);
1340
1341 return (rc);
1342 }
1343
1344 /*
1345 * smb_fsop_write
1346 *
1347 * This is a wrapper function used for smb_write and smb_write_raw operations.
1348 *
1349 * It is assumed that a reference exists on snode coming into this routine.
1350 */
1351 int
smb_fsop_write(smb_request_t * sr,cred_t * cr,smb_node_t * snode,uio_t * uio,uint32_t * lcount,int ioflag)1352 smb_fsop_write(
1353 smb_request_t *sr,
1354 cred_t *cr,
1355 smb_node_t *snode,
1356 uio_t *uio,
1357 uint32_t *lcount,
1358 int ioflag)
1359 {
1360 caller_context_t ct;
1361 int svmand;
1362 int rc;
1363
1364 ASSERT(cr);
1365 ASSERT(snode);
1366 ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1367 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1368
1369 ASSERT(sr);
1370 ASSERT(sr->tid_tree);
1371 ASSERT(sr->fid_ofile);
1372
1373 if (SMB_TREE_IS_READONLY(sr))
1374 return (EROFS);
1375
1376 if (SMB_OFILE_IS_READONLY(sr->fid_ofile) ||
1377 SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_DATA | ACE_APPEND_DATA) == 0)
1378 return (EACCES);
1379
1380 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA);
1381 if (rc != NT_STATUS_SUCCESS) {
1382 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA);
1383 if (rc != NT_STATUS_SUCCESS)
1384 return (EACCES);
1385 }
1386
1387 /*
1388 * Streams permission are checked against the unnamed stream,
1389 * but in FS level they have their own permissions. To avoid
1390 * rejection by FS due to lack of permission on the actual
1391 * extended attr kcred is passed for streams.
1392 */
1393 if (SMB_IS_STREAM(snode))
1394 cr = kcred;
1395
1396 smb_node_start_crit(snode, RW_READER);
1397 rc = nbl_svmand(snode->vp, kcred, &svmand);
1398 if (rc) {
1399 smb_node_end_crit(snode);
1400 return (rc);
1401 }
1402
1403 ct = smb_ct;
1404 ct.cc_pid = sr->fid_ofile->f_uniqid;
1405 rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset,
1406 uio->uio_iov->iov_len, svmand, &ct);
1407
1408 if (rc) {
1409 smb_node_end_crit(snode);
1410 return (ERANGE);
1411 }
1412
1413 rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr);
1414 smb_node_end_crit(snode);
1415
1416 return (rc);
1417 }
1418
1419 /*
1420 * smb_fsop_statfs
1421 *
1422 * This is a wrapper function used for stat operations.
1423 */
1424 int
smb_fsop_statfs(cred_t * cr,smb_node_t * snode,struct statvfs64 * statp)1425 smb_fsop_statfs(
1426 cred_t *cr,
1427 smb_node_t *snode,
1428 struct statvfs64 *statp)
1429 {
1430 ASSERT(cr);
1431 ASSERT(snode);
1432 ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1433 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1434
1435 return (smb_vop_statfs(snode->vp, statp, cr));
1436 }
1437
1438 /*
1439 * smb_fsop_access
1440 *
1441 * Named streams do not have separate permissions from the associated
1442 * unnamed stream. Thus, if node is a named stream, the permissions
1443 * check will be performed on the associated unnamed stream.
1444 *
1445 * However, our named streams do have their own quarantine attribute,
1446 * separate from that on the unnamed stream. If READ or EXECUTE
1447 * access has been requested on a named stream, an additional access
1448 * check is performed on the named stream in case it has been
1449 * quarantined. kcred is used to avoid issues with the permissions
1450 * set on the extended attribute file representing the named stream.
1451 */
1452 int
smb_fsop_access(smb_request_t * sr,cred_t * cr,smb_node_t * snode,uint32_t faccess)1453 smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1454 uint32_t faccess)
1455 {
1456 int access = 0;
1457 int error;
1458 vnode_t *dir_vp;
1459 boolean_t acl_check = B_TRUE;
1460 smb_node_t *unnamed_node;
1461
1462 ASSERT(sr);
1463 ASSERT(cr);
1464 ASSERT(snode);
1465 ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1466 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1467
1468 /* Requests for no access should be denied. */
1469 if (faccess == 0)
1470 return (NT_STATUS_ACCESS_DENIED);
1471
1472 if (SMB_TREE_IS_READONLY(sr)) {
1473 if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA|
1474 FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES|
1475 DELETE|WRITE_DAC|WRITE_OWNER)) {
1476 return (NT_STATUS_ACCESS_DENIED);
1477 }
1478 }
1479
1480 if (smb_node_is_reparse(snode) && (faccess & DELETE))
1481 return (NT_STATUS_ACCESS_DENIED);
1482
1483 unnamed_node = SMB_IS_STREAM(snode);
1484 if (unnamed_node) {
1485 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1486 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1487
1488 /*
1489 * Perform VREAD access check on the named stream in case it
1490 * is quarantined. kcred is passed to smb_vop_access so it
1491 * doesn't fail due to lack of permission.
1492 */
1493 if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) {
1494 error = smb_vop_access(snode->vp, VREAD,
1495 0, NULL, kcred);
1496 if (error)
1497 return (NT_STATUS_ACCESS_DENIED);
1498 }
1499
1500 /*
1501 * Streams authorization should be performed against the
1502 * unnamed stream.
1503 */
1504 snode = unnamed_node;
1505 }
1506
1507 if (faccess & ACCESS_SYSTEM_SECURITY) {
1508 /*
1509 * This permission is required for reading/writing SACL and
1510 * it's not part of DACL. It's only granted via proper
1511 * privileges.
1512 */
1513 if ((sr->uid_user->u_privileges &
1514 (SMB_USER_PRIV_BACKUP |
1515 SMB_USER_PRIV_RESTORE |
1516 SMB_USER_PRIV_SECURITY)) == 0)
1517 return (NT_STATUS_PRIVILEGE_NOT_HELD);
1518
1519 faccess &= ~ACCESS_SYSTEM_SECURITY;
1520 }
1521
1522 /* Links don't have ACL */
1523 if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) ||
1524 smb_node_is_symlink(snode))
1525 acl_check = B_FALSE;
1526
1527 /* Deny access based on the share access mask */
1528
1529 if ((faccess & ~sr->tid_tree->t_access) != 0)
1530 return (NT_STATUS_ACCESS_DENIED);
1531
1532 if (acl_check) {
1533 dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
1534 error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
1535 cr);
1536 } else {
1537 /*
1538 * FS doesn't understand 32-bit mask, need to map
1539 */
1540 if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))
1541 access |= VWRITE;
1542
1543 if (faccess & FILE_READ_DATA)
1544 access |= VREAD;
1545
1546 if (faccess & FILE_EXECUTE)
1547 access |= VEXEC;
1548
1549 error = smb_vop_access(snode->vp, access, 0, NULL, cr);
1550 }
1551
1552 return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS);
1553 }
1554
1555 /*
1556 * smb_fsop_lookup_name()
1557 *
1558 * If name indicates that the file is a stream file, perform
1559 * stream specific lookup, otherwise call smb_fsop_lookup.
1560 *
1561 * Return an error if the looked-up file is in outside the tree.
1562 * (Required when invoked from open path.)
1563 *
1564 * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE):
1565 * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
1566 * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE
1567 * flag is set in the flags value passed as a parameter, a case insensitive
1568 * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set
1569 * or not).
1570 */
1571
1572 int
smb_fsop_lookup_name(smb_request_t * sr,cred_t * cr,int flags,smb_node_t * root_node,smb_node_t * dnode,char * name,smb_node_t ** ret_snode)1573 smb_fsop_lookup_name(
1574 smb_request_t *sr,
1575 cred_t *cr,
1576 int flags,
1577 smb_node_t *root_node,
1578 smb_node_t *dnode,
1579 char *name,
1580 smb_node_t **ret_snode)
1581 {
1582 smb_node_t *fnode;
1583 vnode_t *xattrdirvp;
1584 vnode_t *vp;
1585 char *od_name;
1586 char *fname;
1587 char *sname;
1588 int rc;
1589
1590 ASSERT(cr);
1591 ASSERT(dnode);
1592 ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1593 ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
1594
1595 /*
1596 * The following check is required for streams processing, below
1597 */
1598
1599 if (!(flags & SMB_CASE_SENSITIVE)) {
1600 if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1601 flags |= SMB_IGNORE_CASE;
1602 }
1603
1604 fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1605 sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1606
1607 if (smb_is_stream_name(name)) {
1608 smb_stream_parse_name(name, fname, sname);
1609
1610 /*
1611 * Look up the unnamed stream (i.e. fname).
1612 * Unmangle processing will be done on fname
1613 * as well as any link target.
1614 */
1615 rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode,
1616 fname, &fnode);
1617
1618 if (rc != 0) {
1619 kmem_free(fname, MAXNAMELEN);
1620 kmem_free(sname, MAXNAMELEN);
1621 return (rc);
1622 }
1623
1624 od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1625
1626 /*
1627 * od_name is the on-disk name of the stream, except
1628 * without the prepended stream prefix (SMB_STREAM_PREFIX)
1629 */
1630
1631 /*
1632 * XXX
1633 * What permissions NTFS requires for stream lookup if any?
1634 */
1635 rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name,
1636 &xattrdirvp, flags, root_node->vp, cr);
1637
1638 if (rc != 0) {
1639 smb_node_release(fnode);
1640 kmem_free(fname, MAXNAMELEN);
1641 kmem_free(sname, MAXNAMELEN);
1642 kmem_free(od_name, MAXNAMELEN);
1643 return (rc);
1644 }
1645
1646 *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
1647 vp, od_name);
1648
1649 kmem_free(od_name, MAXNAMELEN);
1650 smb_node_release(fnode);
1651 VN_RELE(xattrdirvp);
1652 VN_RELE(vp);
1653
1654 if (*ret_snode == NULL) {
1655 kmem_free(fname, MAXNAMELEN);
1656 kmem_free(sname, MAXNAMELEN);
1657 return (ENOMEM);
1658 }
1659 } else {
1660 rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name,
1661 ret_snode);
1662 }
1663
1664 if (rc == 0) {
1665 ASSERT(ret_snode);
1666 if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) {
1667 smb_node_release(*ret_snode);
1668 *ret_snode = NULL;
1669 rc = EACCES;
1670 }
1671 }
1672
1673 kmem_free(fname, MAXNAMELEN);
1674 kmem_free(sname, MAXNAMELEN);
1675
1676 return (rc);
1677 }
1678
1679 /*
1680 * smb_fsop_lookup
1681 *
1682 * All SMB functions should use this smb_vop_lookup wrapper to ensure that
1683 * the smb_vop_lookup is performed with the appropriate credentials and using
1684 * case insensitive compares. Please document any direct call to smb_vop_lookup
1685 * to explain the reason for avoiding this wrapper.
1686 *
1687 * It is assumed that a reference exists on dnode coming into this routine
1688 * (and that it is safe from deallocation).
1689 *
1690 * Same with the root_node.
1691 *
1692 * *ret_snode is returned with a reference upon success. No reference is
1693 * taken if an error is returned.
1694 *
1695 * Note: The returned ret_snode may be in a child mount. This is ok for
1696 * readdir.
1697 *
1698 * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent
1699 * operations on files not in the parent mount.
1700 *
1701 * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE):
1702 * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
1703 * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE
1704 * flag is set in the flags value passed as a parameter, a case insensitive
1705 * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set
1706 * or not).
1707 */
1708 int
smb_fsop_lookup(smb_request_t * sr,cred_t * cr,int flags,smb_node_t * root_node,smb_node_t * dnode,char * name,smb_node_t ** ret_snode)1709 smb_fsop_lookup(
1710 smb_request_t *sr,
1711 cred_t *cr,
1712 int flags,
1713 smb_node_t *root_node,
1714 smb_node_t *dnode,
1715 char *name,
1716 smb_node_t **ret_snode)
1717 {
1718 smb_node_t *lnk_target_node;
1719 smb_node_t *lnk_dnode;
1720 char *longname;
1721 char *od_name;
1722 vnode_t *vp;
1723 int rc;
1724 int ret_flags;
1725 smb_attr_t attr;
1726
1727 ASSERT(cr);
1728 ASSERT(dnode);
1729 ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
1730 ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING);
1731
1732 if (name == NULL)
1733 return (EINVAL);
1734
1735 if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0)
1736 return (EACCES);
1737
1738 if (!(flags & SMB_CASE_SENSITIVE)) {
1739 if (SMB_TREE_IS_CASEINSENSITIVE(sr))
1740 flags |= SMB_IGNORE_CASE;
1741 }
1742 if (SMB_TREE_SUPPORTS_CATIA(sr))
1743 flags |= SMB_CATIA;
1744 if (SMB_TREE_SUPPORTS_ABE(sr))
1745 flags |= SMB_ABE;
1746
1747 od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1748
1749 rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags,
1750 &ret_flags, root_node ? root_node->vp : NULL, &attr, cr);
1751
1752 if (rc != 0) {
1753 if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
1754 !smb_maybe_mangled(name)) {
1755 kmem_free(od_name, MAXNAMELEN);
1756 return (rc);
1757 }
1758
1759 longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1760 rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
1761 if (rc != 0) {
1762 kmem_free(od_name, MAXNAMELEN);
1763 kmem_free(longname, MAXNAMELEN);
1764 return (rc);
1765 }
1766
1767 /*
1768 * longname is the real (case-sensitive)
1769 * on-disk name.
1770 * We make sure we do a lookup on this exact
1771 * name, as the name was mangled and denotes
1772 * a unique file.
1773 */
1774
1775 if (flags & SMB_IGNORE_CASE)
1776 flags &= ~SMB_IGNORE_CASE;
1777
1778 rc = smb_vop_lookup(dnode->vp, longname, &vp, od_name,
1779 flags, &ret_flags, root_node ? root_node->vp : NULL, &attr,
1780 cr);
1781
1782 kmem_free(longname, MAXNAMELEN);
1783
1784 if (rc != 0) {
1785 kmem_free(od_name, MAXNAMELEN);
1786 return (rc);
1787 }
1788 }
1789
1790 if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK) &&
1791 ((attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)) {
1792 rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode,
1793 &lnk_dnode, &lnk_target_node, cr);
1794
1795 if (rc != 0) {
1796 /*
1797 * The link is assumed to be for the last component
1798 * of a path. Hence any ENOTDIR error will be returned
1799 * as ENOENT.
1800 */
1801 if (rc == ENOTDIR)
1802 rc = ENOENT;
1803
1804 VN_RELE(vp);
1805 kmem_free(od_name, MAXNAMELEN);
1806 return (rc);
1807 }
1808
1809 /*
1810 * Release the original VLNK vnode
1811 */
1812
1813 VN_RELE(vp);
1814 vp = lnk_target_node->vp;
1815
1816 rc = smb_vop_traverse_check(&vp);
1817
1818 if (rc != 0) {
1819 smb_node_release(lnk_dnode);
1820 smb_node_release(lnk_target_node);
1821 kmem_free(od_name, MAXNAMELEN);
1822 return (rc);
1823 }
1824
1825 /*
1826 * smb_vop_traverse_check() may have returned a different vnode
1827 */
1828
1829 if (lnk_target_node->vp == vp) {
1830 *ret_snode = lnk_target_node;
1831 } else {
1832 *ret_snode = smb_node_lookup(sr, NULL, cr, vp,
1833 lnk_target_node->od_name, lnk_dnode, NULL);
1834 VN_RELE(vp);
1835
1836 if (*ret_snode == NULL)
1837 rc = ENOMEM;
1838 smb_node_release(lnk_target_node);
1839 }
1840
1841 smb_node_release(lnk_dnode);
1842
1843 } else {
1844
1845 rc = smb_vop_traverse_check(&vp);
1846 if (rc) {
1847 VN_RELE(vp);
1848 kmem_free(od_name, MAXNAMELEN);
1849 return (rc);
1850 }
1851
1852 *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
1853 dnode, NULL);
1854 VN_RELE(vp);
1855
1856 if (*ret_snode == NULL)
1857 rc = ENOMEM;
1858 }
1859
1860 kmem_free(od_name, MAXNAMELEN);
1861 return (rc);
1862 }
1863
1864 int /*ARGSUSED*/
smb_fsop_commit(smb_request_t * sr,cred_t * cr,smb_node_t * snode)1865 smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
1866 {
1867 ASSERT(cr);
1868 ASSERT(snode);
1869 ASSERT(snode->n_magic == SMB_NODE_MAGIC);
1870 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
1871
1872 ASSERT(sr);
1873 ASSERT(sr->tid_tree);
1874 if (SMB_TREE_IS_READONLY(sr))
1875 return (EROFS);
1876
1877 return (smb_vop_commit(snode->vp, cr));
1878 }
1879
1880 /*
1881 * smb_fsop_aclread
1882 *
1883 * Retrieve filesystem ACL. Depends on requested ACLs in
1884 * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in
1885 * fs_sd. Note that requesting a DACL/SACL doesn't mean that
1886 * the corresponding field in fs_sd should be non-NULL upon
1887 * return, since the target ACL might not contain that type of
1888 * entries.
1889 *
1890 * Returned ACL is always in ACE_T (aka ZFS) format.
1891 * If successful the allocated memory for the ACL should be freed
1892 * using smb_fsacl_free() or smb_fssd_term()
1893 */
1894 int
smb_fsop_aclread(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_fssd_t * fs_sd)1895 smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1896 smb_fssd_t *fs_sd)
1897 {
1898 int error = 0;
1899 int flags = 0;
1900 int access = 0;
1901 acl_t *acl;
1902 smb_node_t *unnamed_node;
1903
1904 ASSERT(cr);
1905
1906 if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0)
1907 return (EACCES);
1908
1909 if (sr->fid_ofile) {
1910 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
1911 access = READ_CONTROL;
1912
1913 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
1914 access |= ACCESS_SYSTEM_SECURITY;
1915
1916 error = smb_ofile_access(sr->fid_ofile, cr, access);
1917 if (error != NT_STATUS_SUCCESS) {
1918 return (EACCES);
1919 }
1920 }
1921
1922 unnamed_node = SMB_IS_STREAM(snode);
1923 if (unnamed_node) {
1924 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1925 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1926 /*
1927 * Streams don't have ACL, any read ACL attempt on a stream
1928 * should be performed on the unnamed stream.
1929 */
1930 snode = unnamed_node;
1931 }
1932
1933 if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS))
1934 flags = ATTR_NOACLCHECK;
1935
1936 error = smb_vop_acl_read(snode->vp, &acl, flags,
1937 sr->tid_tree->t_acltype, cr);
1938 if (error != 0) {
1939 return (error);
1940 }
1941
1942 error = acl_translate(acl, _ACL_ACE_ENABLED,
1943 smb_node_is_dir(snode), fs_sd->sd_uid, fs_sd->sd_gid);
1944
1945 if (error == 0) {
1946 smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
1947 fs_sd->sd_secinfo);
1948 }
1949
1950 acl_free(acl);
1951 return (error);
1952 }
1953
1954 /*
1955 * smb_fsop_aclwrite
1956 *
1957 * Stores the filesystem ACL provided in fs_sd->sd_acl.
1958 */
1959 int
smb_fsop_aclwrite(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_fssd_t * fs_sd)1960 smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
1961 smb_fssd_t *fs_sd)
1962 {
1963 int target_flavor;
1964 int error = 0;
1965 int flags = 0;
1966 int access = 0;
1967 acl_t *acl, *dacl, *sacl;
1968 smb_node_t *unnamed_node;
1969
1970 ASSERT(cr);
1971
1972 ASSERT(sr);
1973 ASSERT(sr->tid_tree);
1974 if (SMB_TREE_IS_READONLY(sr))
1975 return (EROFS);
1976
1977 if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0)
1978 return (EACCES);
1979
1980 if (sr->fid_ofile) {
1981 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
1982 access = WRITE_DAC;
1983
1984 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
1985 access |= ACCESS_SYSTEM_SECURITY;
1986
1987 error = smb_ofile_access(sr->fid_ofile, cr, access);
1988 if (error != NT_STATUS_SUCCESS)
1989 return (EACCES);
1990 }
1991
1992 switch (sr->tid_tree->t_acltype) {
1993 case ACLENT_T:
1994 target_flavor = _ACL_ACLENT_ENABLED;
1995 break;
1996
1997 case ACE_T:
1998 target_flavor = _ACL_ACE_ENABLED;
1999 break;
2000 default:
2001 return (EINVAL);
2002 }
2003
2004 unnamed_node = SMB_IS_STREAM(snode);
2005 if (unnamed_node) {
2006 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
2007 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
2008 /*
2009 * Streams don't have ACL, any write ACL attempt on a stream
2010 * should be performed on the unnamed stream.
2011 */
2012 snode = unnamed_node;
2013 }
2014
2015 dacl = fs_sd->sd_zdacl;
2016 sacl = fs_sd->sd_zsacl;
2017
2018 ASSERT(dacl || sacl);
2019 if ((dacl == NULL) && (sacl == NULL))
2020 return (EINVAL);
2021
2022 if (dacl && sacl)
2023 acl = smb_fsacl_merge(dacl, sacl);
2024 else if (dacl)
2025 acl = dacl;
2026 else
2027 acl = sacl;
2028
2029 error = acl_translate(acl, target_flavor, smb_node_is_dir(snode),
2030 fs_sd->sd_uid, fs_sd->sd_gid);
2031 if (error == 0) {
2032 if (smb_tree_has_feature(sr->tid_tree,
2033 SMB_TREE_ACEMASKONACCESS))
2034 flags = ATTR_NOACLCHECK;
2035
2036 error = smb_vop_acl_write(snode->vp, acl, flags, cr);
2037 }
2038
2039 if (dacl && sacl)
2040 acl_free(acl);
2041
2042 return (error);
2043 }
2044
2045 acl_type_t
smb_fsop_acltype(smb_node_t * snode)2046 smb_fsop_acltype(smb_node_t *snode)
2047 {
2048 return (smb_vop_acl_type(snode->vp));
2049 }
2050
2051 /*
2052 * smb_fsop_sdread
2053 *
2054 * Read the requested security descriptor items from filesystem.
2055 * The items are specified in fs_sd->sd_secinfo.
2056 */
2057 int
smb_fsop_sdread(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_fssd_t * fs_sd)2058 smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2059 smb_fssd_t *fs_sd)
2060 {
2061 int error = 0;
2062 int getowner = 0;
2063 cred_t *ga_cred;
2064 smb_attr_t attr;
2065
2066 ASSERT(cr);
2067 ASSERT(fs_sd);
2068
2069 /*
2070 * File's uid/gid is fetched in two cases:
2071 *
2072 * 1. it's explicitly requested
2073 *
2074 * 2. target ACL is ACE_T (ZFS ACL). They're needed for
2075 * owner@/group@ entries. In this case kcred should be used
2076 * because uid/gid are fetched on behalf of smb server.
2077 */
2078 if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) {
2079 getowner = 1;
2080 ga_cred = cr;
2081 } else if (sr->tid_tree->t_acltype == ACE_T) {
2082 getowner = 1;
2083 ga_cred = kcred;
2084 }
2085
2086 if (getowner) {
2087 /*
2088 * Windows require READ_CONTROL to read owner/group SID since
2089 * they're part of Security Descriptor.
2090 * ZFS only requires read_attribute. Need to have a explicit
2091 * access check here.
2092 */
2093 if (sr->fid_ofile == NULL) {
2094 error = smb_fsop_access(sr, ga_cred, snode,
2095 READ_CONTROL);
2096 if (error)
2097 return (EACCES);
2098 }
2099
2100 attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2101 error = smb_fsop_getattr(sr, ga_cred, snode, &attr);
2102 if (error == 0) {
2103 fs_sd->sd_uid = attr.sa_vattr.va_uid;
2104 fs_sd->sd_gid = attr.sa_vattr.va_gid;
2105 } else {
2106 return (error);
2107 }
2108 }
2109
2110 if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2111 error = smb_fsop_aclread(sr, cr, snode, fs_sd);
2112 }
2113
2114 return (error);
2115 }
2116
2117 /*
2118 * smb_fsop_sdmerge
2119 *
2120 * From SMB point of view DACL and SACL are two separate list
2121 * which can be manipulated independently without one affecting
2122 * the other, but entries for both DACL and SACL will end up
2123 * in the same ACL if target filesystem supports ACE_T ACLs.
2124 *
2125 * So, if either DACL or SACL is present in the client set request
2126 * the entries corresponding to the non-present ACL shouldn't
2127 * be touched in the FS ACL.
2128 *
2129 * fs_sd parameter contains DACL and SACL specified by SMB
2130 * client to be set on a file/directory. The client could
2131 * specify both or one of these ACLs (if none is specified
2132 * we don't get this far). When both DACL and SACL are given
2133 * by client the existing ACL should be overwritten. If only
2134 * one of them is specified the entries corresponding to the other
2135 * ACL should not be touched. For example, if only DACL
2136 * is specified in input fs_sd, the function reads audit entries
2137 * of the existing ACL of the file and point fs_sd->sd_zsdacl
2138 * pointer to the fetched SACL, this way when smb_fsop_sdwrite()
2139 * function is called the passed fs_sd would point to the specified
2140 * DACL by client and fetched SACL from filesystem, so the file
2141 * will end up with correct ACL.
2142 */
2143 static int
smb_fsop_sdmerge(smb_request_t * sr,smb_node_t * snode,smb_fssd_t * fs_sd)2144 smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
2145 {
2146 smb_fssd_t cur_sd;
2147 int error = 0;
2148
2149 if (sr->tid_tree->t_acltype != ACE_T)
2150 /* Don't bother if target FS doesn't support ACE_T */
2151 return (0);
2152
2153 if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) {
2154 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
2155 /*
2156 * Don't overwrite existing audit entries
2157 */
2158 smb_fssd_init(&cur_sd, SMB_SACL_SECINFO,
2159 fs_sd->sd_flags);
2160
2161 error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
2162 if (error == 0) {
2163 ASSERT(fs_sd->sd_zsacl == NULL);
2164 fs_sd->sd_zsacl = cur_sd.sd_zsacl;
2165 if (fs_sd->sd_zsacl && fs_sd->sd_zdacl)
2166 fs_sd->sd_zsacl->acl_flags =
2167 fs_sd->sd_zdacl->acl_flags;
2168 }
2169 } else {
2170 /*
2171 * Don't overwrite existing access entries
2172 */
2173 smb_fssd_init(&cur_sd, SMB_DACL_SECINFO,
2174 fs_sd->sd_flags);
2175
2176 error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
2177 if (error == 0) {
2178 ASSERT(fs_sd->sd_zdacl == NULL);
2179 fs_sd->sd_zdacl = cur_sd.sd_zdacl;
2180 if (fs_sd->sd_zdacl && fs_sd->sd_zsacl)
2181 fs_sd->sd_zdacl->acl_flags =
2182 fs_sd->sd_zsacl->acl_flags;
2183 }
2184 }
2185
2186 if (error)
2187 smb_fssd_term(&cur_sd);
2188 }
2189
2190 return (error);
2191 }
2192
2193 /*
2194 * smb_fsop_sdwrite
2195 *
2196 * Stores the given uid, gid and acl in filesystem.
2197 * Provided items in fs_sd are specified by fs_sd->sd_secinfo.
2198 *
2199 * A SMB security descriptor could contain owner, primary group,
2200 * DACL and SACL. Setting an SD should be atomic but here it has to
2201 * be done via two separate FS operations: VOP_SETATTR and
2202 * VOP_SETSECATTR. Therefore, this function has to simulate the
2203 * atomicity as well as it can.
2204 *
2205 * Get the current uid, gid before setting the new uid/gid
2206 * so if smb_fsop_aclwrite fails they can be restored. root cred is
2207 * used to get currend uid/gid since this operation is performed on
2208 * behalf of the server not the user.
2209 *
2210 * If setting uid/gid fails with EPERM it means that and invalid
2211 * owner has been specified. Callers should translate this to
2212 * STATUS_INVALID_OWNER which is not the normal mapping for EPERM
2213 * in upper layers, so EPERM is mapped to EBADE.
2214 */
2215 int
smb_fsop_sdwrite(smb_request_t * sr,cred_t * cr,smb_node_t * snode,smb_fssd_t * fs_sd,int overwrite)2216 smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2217 smb_fssd_t *fs_sd, int overwrite)
2218 {
2219 int error = 0;
2220 int access = 0;
2221 smb_attr_t set_attr;
2222 smb_attr_t orig_attr;
2223
2224 ASSERT(cr);
2225 ASSERT(fs_sd);
2226
2227 ASSERT(sr);
2228 ASSERT(sr->tid_tree);
2229 if (SMB_TREE_IS_READONLY(sr))
2230 return (EROFS);
2231
2232 bzero(&set_attr, sizeof (smb_attr_t));
2233
2234 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
2235 set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
2236 set_attr.sa_mask |= SMB_AT_UID;
2237 access |= WRITE_OWNER;
2238 }
2239
2240 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
2241 set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
2242 set_attr.sa_mask |= SMB_AT_GID;
2243 access |= WRITE_OWNER;
2244 }
2245
2246 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
2247 access |= WRITE_DAC;
2248
2249 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
2250 access |= ACCESS_SYSTEM_SECURITY;
2251
2252 if (sr->fid_ofile)
2253 error = smb_ofile_access(sr->fid_ofile, cr, access);
2254 else
2255 error = smb_fsop_access(sr, cr, snode, access);
2256
2257 if (error)
2258 return (EACCES);
2259
2260 if (set_attr.sa_mask) {
2261 orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
2262 error = smb_fsop_getattr(sr, kcred, snode, &orig_attr);
2263 if (error == 0) {
2264 error = smb_fsop_setattr(sr, cr, snode, &set_attr);
2265 if (error == EPERM)
2266 error = EBADE;
2267 }
2268
2269 if (error)
2270 return (error);
2271 }
2272
2273 if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
2274 if (overwrite == 0) {
2275 error = smb_fsop_sdmerge(sr, snode, fs_sd);
2276 if (error)
2277 return (error);
2278 }
2279
2280 error = smb_fsop_aclwrite(sr, cr, snode, fs_sd);
2281 if (error) {
2282 /*
2283 * Revert uid/gid changes if required.
2284 */
2285 if (set_attr.sa_mask) {
2286 orig_attr.sa_mask = set_attr.sa_mask;
2287 (void) smb_fsop_setattr(sr, kcred, snode,
2288 &orig_attr);
2289 }
2290 }
2291 }
2292
2293 return (error);
2294 }
2295
2296 /*
2297 * smb_fsop_sdinherit
2298 *
2299 * Inherit the security descriptor from the parent container.
2300 * This function is called after FS has created the file/folder
2301 * so if this doesn't do anything it means FS inheritance is
2302 * in place.
2303 *
2304 * Do inheritance for ZFS internally.
2305 *
2306 * If we want to let ZFS does the inheritance the
2307 * following setting should be true:
2308 *
2309 * - aclinherit = passthrough
2310 * - aclmode = passthrough
2311 * - smbd umask = 0777
2312 *
2313 * This will result in right effective permissions but
2314 * ZFS will always add 6 ACEs for owner, owning group
2315 * and others to be POSIX compliant. This is not what
2316 * Windows clients/users expect, so we decided that CIFS
2317 * implements Windows rules and overwrite whatever ZFS
2318 * comes up with. This way we also don't have to care
2319 * about ZFS aclinherit and aclmode settings.
2320 */
2321 static int
smb_fsop_sdinherit(smb_request_t * sr,smb_node_t * dnode,smb_fssd_t * fs_sd)2322 smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
2323 {
2324 acl_t *dacl = NULL;
2325 acl_t *sacl = NULL;
2326 int is_dir;
2327 int error;
2328
2329 ASSERT(fs_sd);
2330
2331 if (sr->tid_tree->t_acltype != ACE_T) {
2332 /*
2333 * No forced inheritance for non-ZFS filesystems.
2334 */
2335 fs_sd->sd_secinfo = 0;
2336 return (0);
2337 }
2338
2339
2340 /* Fetch parent directory's ACL */
2341 error = smb_fsop_sdread(sr, kcred, dnode, fs_sd);
2342 if (error) {
2343 return (error);
2344 }
2345
2346 is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR);
2347 dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO,
2348 sr->user_cr);
2349 sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO,
2350 sr->user_cr);
2351
2352 if (sacl == NULL)
2353 fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO;
2354
2355 smb_fsacl_free(fs_sd->sd_zdacl);
2356 smb_fsacl_free(fs_sd->sd_zsacl);
2357
2358 fs_sd->sd_zdacl = dacl;
2359 fs_sd->sd_zsacl = sacl;
2360
2361 return (0);
2362 }
2363
2364 /*
2365 * smb_fsop_eaccess
2366 *
2367 * Returns the effective permission of the given credential for the
2368 * specified object.
2369 *
2370 * This is just a workaround. We need VFS/FS support for this.
2371 */
2372 void
smb_fsop_eaccess(smb_request_t * sr,cred_t * cr,smb_node_t * snode,uint32_t * eaccess)2373 smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
2374 uint32_t *eaccess)
2375 {
2376 int access = 0;
2377 vnode_t *dir_vp;
2378 smb_node_t *unnamed_node;
2379
2380 ASSERT(cr);
2381 ASSERT(snode);
2382 ASSERT(snode->n_magic == SMB_NODE_MAGIC);
2383 ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
2384
2385 unnamed_node = SMB_IS_STREAM(snode);
2386 if (unnamed_node) {
2387 ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
2388 ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
2389 /*
2390 * Streams authorization should be performed against the
2391 * unnamed stream.
2392 */
2393 snode = unnamed_node;
2394 }
2395
2396 if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) {
2397 dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
2398 smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
2399 cr);
2400 return;
2401 }
2402
2403 /*
2404 * FS doesn't understand 32-bit mask
2405 */
2406 smb_vop_eaccess(snode->vp, &access, 0, NULL, cr);
2407 access &= sr->tid_tree->t_access;
2408
2409 *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES;
2410
2411 if (access & VREAD)
2412 *eaccess |= FILE_READ_DATA;
2413
2414 if (access & VEXEC)
2415 *eaccess |= FILE_EXECUTE;
2416
2417 if (access & VWRITE)
2418 *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
2419 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
2420 }
2421
2422 /*
2423 * smb_fsop_shrlock
2424 *
2425 * For the current open request, check file sharing rules
2426 * against existing opens.
2427 *
2428 * Returns NT_STATUS_SHARING_VIOLATION if there is any
2429 * sharing conflict. Returns NT_STATUS_SUCCESS otherwise.
2430 *
2431 * Full system-wide share reservation synchronization is available
2432 * when the nbmand (non-blocking mandatory) mount option is set
2433 * (i.e. nbl_need_crit() is true) and nbmand critical regions are used.
2434 * This provides synchronization with NFS and local processes. The
2435 * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called
2436 * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well
2437 * as the CIFS rename and delete paths.
2438 *
2439 * The CIFS server will also enter the nbl critical region in the open,
2440 * rename, and delete paths when nbmand is not set. There is limited
2441 * coordination with local and VFS share reservations in this case.
2442 * Note that when the nbmand mount option is not set, the VFS layer
2443 * only processes advisory reservations and the delete mode is not checked.
2444 *
2445 * Whether or not the nbmand mount option is set, intra-CIFS share
2446 * checking is done in the open, delete, and rename paths using a CIFS
2447 * critical region (node->n_share_lock).
2448 */
2449 uint32_t
smb_fsop_shrlock(cred_t * cr,smb_node_t * node,uint32_t uniq_fid,uint32_t desired_access,uint32_t share_access)2450 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid,
2451 uint32_t desired_access, uint32_t share_access)
2452 {
2453 int rc;
2454
2455 /* Allow access if the request is just for meta data */
2456 if ((desired_access & FILE_DATA_ALL) == 0)
2457 return (NT_STATUS_SUCCESS);
2458
2459 rc = smb_node_open_check(node, desired_access, share_access);
2460 if (rc)
2461 return (NT_STATUS_SHARING_VIOLATION);
2462
2463 rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access,
2464 cr);
2465 if (rc)
2466 return (NT_STATUS_SHARING_VIOLATION);
2467
2468 return (NT_STATUS_SUCCESS);
2469 }
2470
2471 void
smb_fsop_unshrlock(cred_t * cr,smb_node_t * node,uint32_t uniq_fid)2472 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid)
2473 {
2474 (void) smb_vop_unshrlock(node->vp, uniq_fid, cr);
2475 }
2476
2477 int
smb_fsop_frlock(smb_node_t * node,smb_lock_t * lock,boolean_t unlock,cred_t * cr)2478 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock,
2479 cred_t *cr)
2480 {
2481 flock64_t bf;
2482 int flag = F_REMOTELOCK;
2483
2484 /*
2485 * VOP_FRLOCK() will not be called if:
2486 *
2487 * 1) The lock has a range of zero bytes. The semantics of Windows and
2488 * POSIX are different. In the case of POSIX it asks for the locking
2489 * of all the bytes from the offset provided until the end of the
2490 * file. In the case of Windows a range of zero locks nothing and
2491 * doesn't conflict with any other lock.
2492 *
2493 * 2) The lock rolls over (start + lenght < start). Solaris will assert
2494 * if such a request is submitted. This will not create
2495 * incompatibilities between POSIX and Windows. In the Windows world,
2496 * if a client submits such a lock, the server will not lock any
2497 * bytes. Interestingly if the same lock (same offset and length) is
2498 * resubmitted Windows will consider that there is an overlap and
2499 * the granting rules will then apply.
2500 */
2501 if ((lock->l_length == 0) ||
2502 ((lock->l_start + lock->l_length - 1) < lock->l_start))
2503 return (0);
2504
2505 bzero(&bf, sizeof (bf));
2506
2507 if (unlock) {
2508 bf.l_type = F_UNLCK;
2509 } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) {
2510 bf.l_type = F_RDLCK;
2511 flag |= FREAD;
2512 } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) {
2513 bf.l_type = F_WRLCK;
2514 flag |= FWRITE;
2515 }
2516
2517 bf.l_start = lock->l_start;
2518 bf.l_len = lock->l_length;
2519 bf.l_pid = lock->l_file->f_uniqid;
2520 bf.l_sysid = smb_ct.cc_sysid;
2521
2522 return (smb_vop_frlock(node->vp, cr, flag, &bf));
2523 }
2524