1 /*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
33 */
34
35 /*
36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37 */
38
39 #include <sys/systm.h>
40 #include <sys/cred.h>
41 #include <sys/vnode.h>
42 #include <sys/vfs.h>
43 #include <sys/filio.h>
44 #include <sys/uio.h>
45 #include <sys/dirent.h>
46 #include <sys/errno.h>
47 #include <sys/sunddi.h>
48 #include <sys/sysmacros.h>
49 #include <sys/kmem.h>
50 #include <sys/cmn_err.h>
51 #include <sys/vfs_opreg.h>
52 #include <sys/policy.h>
53
54 #include <netsmb/smb_osdep.h>
55 #include <netsmb/smb.h>
56 #include <netsmb/smb_conn.h>
57 #include <netsmb/smb_subr.h>
58
59 #include <smbfs/smbfs.h>
60 #include <smbfs/smbfs_node.h>
61 #include <smbfs/smbfs_subr.h>
62
63 #include <sys/fs/smbfs_ioctl.h>
64 #include <fs/fs_subr.h>
65
66 /*
67 * We assign directory offsets like the NFS client, where the
68 * offset increments by _one_ after each directory entry.
69 * Further, the entries "." and ".." are always at offsets
70 * zero and one (respectively) and the "real" entries from
71 * the server appear at offsets starting with two. This
72 * macro is used to initialize the n_dirofs field after
73 * setting n_dirseq with a _findopen call.
74 */
75 #define FIRST_DIROFS 2
76
77 /*
78 * These characters are illegal in NTFS file names.
79 * ref: http://support.microsoft.com/kb/147438
80 *
81 * Careful! The check in the XATTR case skips the
82 * first character to allow colon in XATTR names.
83 */
84 static const char illegal_chars[] = {
85 ':', /* colon - keep this first! */
86 '\\', /* back slash */
87 '/', /* slash */
88 '*', /* asterisk */
89 '?', /* question mark */
90 '"', /* double quote */
91 '<', /* less than sign */
92 '>', /* greater than sign */
93 '|', /* vertical bar */
94 0
95 };
96
97 /*
98 * Turning this on causes nodes to be created in the cache
99 * during directory listings, normally avoiding a second
100 * OtW attribute fetch just after a readdir.
101 */
102 int smbfs_fastlookup = 1;
103
104 /* local static function defines */
105
106 static int smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
107 cred_t *);
108 static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
109 int cache_ok, caller_context_t *);
110 static int smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
111 int flags);
112 static int smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp,
113 char *nnm, struct smb_cred *scred, int flags);
114 static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
115 static int smbfs_accessx(void *, int, cred_t *);
116 static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
117 caller_context_t *);
118 static void smbfs_rele_fid(smbnode_t *, struct smb_cred *);
119 static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *);
120
121 /*
122 * These are the vnode ops routines which implement the vnode interface to
123 * the networked file system. These routines just take their parameters,
124 * make them look networkish by putting the right info into interface structs,
125 * and then calling the appropriate remote routine(s) to do the work.
126 *
127 * Note on directory name lookup cacheing: If we detect a stale fhandle,
128 * we purge the directory cache relative to that vnode. This way, the
129 * user won't get burned by the cache repeatedly. See <smbfs/smbnode.h> for
130 * more details on smbnode locking.
131 */
132
133 static int smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
134 static int smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
135 caller_context_t *);
136 static int smbfs_read(vnode_t *, struct uio *, int, cred_t *,
137 caller_context_t *);
138 static int smbfs_write(vnode_t *, struct uio *, int, cred_t *,
139 caller_context_t *);
140 static int smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
141 caller_context_t *);
142 static int smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
143 caller_context_t *);
144 static int smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
145 caller_context_t *);
146 static int smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
147 static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
148 static void smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
149 static int smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
150 int, vnode_t *, cred_t *, caller_context_t *,
151 int *, pathname_t *);
152 static int smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
153 int, vnode_t **, cred_t *, int, caller_context_t *,
154 vsecattr_t *);
155 static int smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
156 int);
157 static int smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
158 caller_context_t *, int);
159 static int smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
160 cred_t *, caller_context_t *, int, vsecattr_t *);
161 static int smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
162 caller_context_t *, int);
163 static int smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
164 caller_context_t *, int);
165 static int smbfs_rwlock(vnode_t *, int, caller_context_t *);
166 static void smbfs_rwunlock(vnode_t *, int, caller_context_t *);
167 static int smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
168 static int smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
169 struct flk_callback *, cred_t *, caller_context_t *);
170 static int smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
171 cred_t *, caller_context_t *);
172 static int smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
173 caller_context_t *);
174 static int smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
175 caller_context_t *);
176 static int smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
177 caller_context_t *);
178 static int smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
179 caller_context_t *);
180
181 /* Dummy function to use until correct function is ported in */
182 int noop_vnodeop() {
183 return (0);
184 }
185
186 struct vnodeops *smbfs_vnodeops = NULL;
187
188 /*
189 * Most unimplemented ops will return ENOSYS because of fs_nosys().
190 * The only ops where that won't work are ACCESS (due to open(2)
191 * failures) and ... (anything else left?)
192 */
193 const fs_operation_def_t smbfs_vnodeops_template[] = {
194 { VOPNAME_OPEN, { .vop_open = smbfs_open } },
195 { VOPNAME_CLOSE, { .vop_close = smbfs_close } },
196 { VOPNAME_READ, { .vop_read = smbfs_read } },
197 { VOPNAME_WRITE, { .vop_write = smbfs_write } },
198 { VOPNAME_IOCTL, { .vop_ioctl = smbfs_ioctl } },
199 { VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } },
200 { VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } },
201 { VOPNAME_ACCESS, { .vop_access = smbfs_access } },
202 { VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } },
203 { VOPNAME_CREATE, { .vop_create = smbfs_create } },
204 { VOPNAME_REMOVE, { .vop_remove = smbfs_remove } },
205 { VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */
206 { VOPNAME_RENAME, { .vop_rename = smbfs_rename } },
207 { VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } },
208 { VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } },
209 { VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } },
210 { VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */
211 { VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */
212 { VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } },
213 { VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } },
214 { VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */
215 { VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } },
216 { VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } },
217 { VOPNAME_SEEK, { .vop_seek = smbfs_seek } },
218 { VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } },
219 { VOPNAME_SPACE, { .vop_space = smbfs_space } },
220 { VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */
221 { VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */
222 { VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */
223 { VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */
224 { VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */
225 { VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */
226 { VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */
227 { VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } },
228 { VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */
229 { VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr } },
230 { VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr } },
231 { VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } },
232 { NULL, NULL }
233 };
234
235 /*
236 * XXX
237 * When new and relevant functionality is enabled, we should be
238 * calling vfs_set_feature() to inform callers that pieces of
239 * functionality are available, per PSARC 2007/227.
240 */
241 /* ARGSUSED */
242 static int
243 smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
244 {
245 smbnode_t *np;
246 vnode_t *vp;
247 smbfattr_t fa;
248 u_int32_t rights, rightsrcvd;
249 u_int16_t fid, oldfid;
250 int oldgenid;
251 struct smb_cred scred;
252 smbmntinfo_t *smi;
253 smb_share_t *ssp;
254 cred_t *oldcr;
255 int tmperror;
256 int error = 0;
257
258 vp = *vpp;
259 np = VTOSMB(vp);
260 smi = VTOSMI(vp);
261 ssp = smi->smi_share;
262
263 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
264 return (EIO);
265
266 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
267 return (EIO);
268
269 if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
270 SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
271 return (EACCES);
272 }
273
274 /*
275 * Get exclusive access to n_fid and related stuff.
276 * No returns after this until out.
277 */
278 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
279 return (EINTR);
280 smb_credinit(&scred, cr);
281
282 /*
283 * Keep track of the vnode type at first open.
284 * It may change later, and we need close to do
285 * cleanup for the type we opened. Also deny
286 * open of new types until old type is closed.
287 * XXX: Per-open instance nodes whould help.
288 */
289 if (np->n_ovtype == VNON) {
290 ASSERT(np->n_dirrefs == 0);
291 ASSERT(np->n_fidrefs == 0);
292 } else if (np->n_ovtype != vp->v_type) {
293 SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
294 np->n_ovtype, vp->v_type);
295 error = EACCES;
296 goto out;
297 }
298
299 /*
300 * Directory open. See smbfs_readvdir()
301 */
302 if (vp->v_type == VDIR) {
303 if (np->n_dirseq == NULL) {
304 /* first open */
305 error = smbfs_smb_findopen(np, "*", 1,
306 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
307 &scred, &np->n_dirseq);
308 if (error != 0)
309 goto out;
310 }
311 np->n_dirofs = FIRST_DIROFS;
312 np->n_dirrefs++;
313 goto have_fid;
314 }
315
316 /*
317 * If caller specified O_TRUNC/FTRUNC, then be sure to set
318 * FWRITE (to drive successful setattr(size=0) after open)
319 */
320 if (flag & FTRUNC)
321 flag |= FWRITE;
322
323 /*
324 * If we already have it open, and the FID is still valid,
325 * check whether the rights are sufficient for FID reuse.
326 */
327 if (np->n_fidrefs > 0 &&
328 np->n_vcgenid == ssp->ss_vcgenid) {
329 int upgrade = 0;
330
331 if ((flag & FWRITE) &&
332 !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
333 upgrade = 1;
334 if ((flag & FREAD) &&
335 !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
336 upgrade = 1;
337 if (!upgrade) {
338 /*
339 * the existing open is good enough
340 */
341 np->n_fidrefs++;
342 goto have_fid;
343 }
344 }
345 rights = np->n_fidrefs ? np->n_rights : 0;
346
347 /*
348 * we always ask for READ_CONTROL so we can always get the
349 * owner/group IDs to satisfy a stat. Ditto attributes.
350 */
351 rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
352 SA_RIGHT_FILE_READ_ATTRIBUTES);
353 if ((flag & FREAD))
354 rights |= SA_RIGHT_FILE_READ_DATA;
355 if ((flag & FWRITE))
356 rights |= SA_RIGHT_FILE_WRITE_DATA |
357 SA_RIGHT_FILE_APPEND_DATA |
358 SA_RIGHT_FILE_WRITE_ATTRIBUTES;
359
360 bzero(&fa, sizeof (fa));
361 error = smbfs_smb_open(np,
362 NULL, 0, 0, /* name nmlen xattr */
363 rights, &scred,
364 &fid, &rightsrcvd, &fa);
365 if (error)
366 goto out;
367 smbfs_attrcache_fa(vp, &fa);
368
369 /*
370 * We have a new FID and access rights.
371 */
372 oldfid = np->n_fid;
373 oldgenid = np->n_vcgenid;
374 np->n_fid = fid;
375 np->n_vcgenid = ssp->ss_vcgenid;
376 np->n_rights = rightsrcvd;
377 np->n_fidrefs++;
378 if (np->n_fidrefs > 1 &&
379 oldgenid == ssp->ss_vcgenid) {
380 /*
381 * We already had it open (presumably because
382 * it was open with insufficient rights.)
383 * Close old wire-open.
384 */
385 tmperror = smbfs_smb_close(ssp,
386 oldfid, NULL, &scred);
387 if (tmperror)
388 SMBVDEBUG("error %d closing %s\n",
389 tmperror, np->n_rpath);
390 }
391
392 /*
393 * This thread did the open.
394 * Save our credentials too.
395 */
396 mutex_enter(&np->r_statelock);
397 oldcr = np->r_cred;
398 np->r_cred = cr;
399 crhold(cr);
400 if (oldcr)
401 crfree(oldcr);
402 mutex_exit(&np->r_statelock);
403
404 have_fid:
405 /*
406 * Keep track of the vnode type at first open.
407 * (see comments above)
408 */
409 if (np->n_ovtype == VNON)
410 np->n_ovtype = vp->v_type;
411
412 out:
413 smb_credrele(&scred);
414 smbfs_rw_exit(&np->r_lkserlock);
415 return (error);
416 }
417
418 /*ARGSUSED*/
419 static int
420 smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
421 caller_context_t *ct)
422 {
423 smbnode_t *np;
424 smbmntinfo_t *smi;
425 struct smb_cred scred;
426
427 np = VTOSMB(vp);
428 smi = VTOSMI(vp);
429
430 /*
431 * Don't "bail out" for VFS_UNMOUNTED here,
432 * as we want to do cleanup, etc.
433 */
434
435 /*
436 * zone_enter(2) prevents processes from changing zones with SMBFS files
437 * open; if we happen to get here from the wrong zone we can't do
438 * anything over the wire.
439 */
440 if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
441 /*
442 * We could attempt to clean up locks, except we're sure
443 * that the current process didn't acquire any locks on
444 * the file: any attempt to lock a file belong to another zone
445 * will fail, and one can't lock an SMBFS file and then change
446 * zones, as that fails too.
447 *
448 * Returning an error here is the sane thing to do. A
449 * subsequent call to VN_RELE() which translates to a
450 * smbfs_inactive() will clean up state: if the zone of the
451 * vnode's origin is still alive and kicking, an async worker
452 * thread will handle the request (from the correct zone), and
453 * everything (minus the final smbfs_getattr_otw() call) should
454 * be OK. If the zone is going away smbfs_async_inactive() will
455 * throw away cached pages inline.
456 */
457 return (EIO);
458 }
459
460 /*
461 * If we are using local locking for this filesystem, then
462 * release all of the SYSV style record locks. Otherwise,
463 * we are doing network locking and we need to release all
464 * of the network locks. All of the locks held by this
465 * process on this file are released no matter what the
466 * incoming reference count is.
467 */
468 if (smi->smi_flags & SMI_LLOCK) {
469 pid_t pid = ddi_get_pid();
470 cleanlocks(vp, pid, 0);
471 cleanshares(vp, pid);
472 }
473
474 /*
475 * This (passed in) count is the ref. count from the
476 * user's file_t before the closef call (fio.c).
477 * We only care when the reference goes away.
478 */
479 if (count > 1)
480 return (0);
481
482 /*
483 * Decrement the reference count for the FID
484 * and possibly do the OtW close.
485 *
486 * Exclusive lock for modifying n_fid stuff.
487 * Don't want this one ever interruptible.
488 */
489 (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
490 smb_credinit(&scred, cr);
491
492 smbfs_rele_fid(np, &scred);
493
494 smb_credrele(&scred);
495 smbfs_rw_exit(&np->r_lkserlock);
496
497 return (0);
498 }
499
500 /*
501 * Helper for smbfs_close. Decrement the reference count
502 * for an SMB-level file or directory ID, and when the last
503 * reference for the fid goes away, do the OtW close.
504 * Also called in smbfs_inactive (defensive cleanup).
505 */
506 static void
507 smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
508 {
509 smb_share_t *ssp;
510 cred_t *oldcr;
511 struct smbfs_fctx *fctx;
512 int error;
513 uint16_t ofid;
514
515 ssp = np->n_mount->smi_share;
516 error = 0;
517
518 /* Make sure we serialize for n_dirseq use. */
519 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
520
521 /*
522 * Note that vp->v_type may change if a remote node
523 * is deleted and recreated as a different type, and
524 * our getattr may change v_type accordingly.
525 * Now use n_ovtype to keep track of the v_type
526 * we had during open (see comments above).
527 */
528 switch (np->n_ovtype) {
529 case VDIR:
530 ASSERT(np->n_dirrefs > 0);
531 if (--np->n_dirrefs)
532 return;
533 if ((fctx = np->n_dirseq) != NULL) {
534 np->n_dirseq = NULL;
535 np->n_dirofs = 0;
536 error = smbfs_smb_findclose(fctx, scred);
537 }
538 break;
539
540 case VREG:
541 ASSERT(np->n_fidrefs > 0);
542 if (--np->n_fidrefs)
543 return;
544 if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
545 np->n_fid = SMB_FID_UNUSED;
546 /* After reconnect, n_fid is invalid */
547 if (np->n_vcgenid == ssp->ss_vcgenid) {
548 error = smbfs_smb_close(
549 ssp, ofid, NULL, scred);
550 }
551 }
552 break;
553
554 default:
555 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
556 break;
557 }
558 if (error) {
559 SMBVDEBUG("error %d closing %s\n",
560 error, np->n_rpath);
561 }
562
563 /* Allow next open to use any v_type. */
564 np->n_ovtype = VNON;
565
566 /*
567 * Other "last close" stuff.
568 */
569 mutex_enter(&np->r_statelock);
570 if (np->n_flag & NATTRCHANGED)
571 smbfs_attrcache_rm_locked(np);
572 oldcr = np->r_cred;
573 np->r_cred = NULL;
574 mutex_exit(&np->r_statelock);
575 if (oldcr != NULL)
576 crfree(oldcr);
577 }
578
579 /* ARGSUSED */
580 static int
581 smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
582 caller_context_t *ct)
583 {
584 struct smb_cred scred;
585 struct vattr va;
586 smbnode_t *np;
587 smbmntinfo_t *smi;
588 smb_share_t *ssp;
589 offset_t endoff;
590 ssize_t past_eof;
591 int error;
592
593 np = VTOSMB(vp);
594 smi = VTOSMI(vp);
595 ssp = smi->smi_share;
596
597 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
598 return (EIO);
599
600 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
601 return (EIO);
602
603 ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
604
605 if (vp->v_type != VREG)
606 return (EISDIR);
607
608 if (uiop->uio_resid == 0)
609 return (0);
610
611 /*
612 * Like NFS3, just check for 63-bit overflow.
613 * Our SMB layer takes care to return EFBIG
614 * when it has to fallback to a 32-bit call.
615 */
616 endoff = uiop->uio_loffset + uiop->uio_resid;
617 if (uiop->uio_loffset < 0 || endoff < 0)
618 return (EINVAL);
619
620 /* get vnode attributes from server */
621 va.va_mask = AT_SIZE | AT_MTIME;
622 if (error = smbfsgetattr(vp, &va, cr))
623 return (error);
624
625 /* Update mtime with mtime from server here? */
626
627 /* if offset is beyond EOF, read nothing */
628 if (uiop->uio_loffset >= va.va_size)
629 return (0);
630
631 /*
632 * Limit the read to the remaining file size.
633 * Do this by temporarily reducing uio_resid
634 * by the amount the lies beyoned the EOF.
635 */
636 if (endoff > va.va_size) {
637 past_eof = (ssize_t)(endoff - va.va_size);
638 uiop->uio_resid -= past_eof;
639 } else
640 past_eof = 0;
641
642 /* Shared lock for n_fid use in smb_rwuio */
643 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
644 return (EINTR);
645 smb_credinit(&scred, cr);
646
647 /* After reconnect, n_fid is invalid */
648 if (np->n_vcgenid != ssp->ss_vcgenid)
649 error = ESTALE;
650 else
651 error = smb_rwuio(ssp, np->n_fid, UIO_READ,
652 uiop, &scred, smb_timo_read);
653
654 smb_credrele(&scred);
655 smbfs_rw_exit(&np->r_lkserlock);
656
657 /* undo adjustment of resid */
658 uiop->uio_resid += past_eof;
659
660 return (error);
661 }
662
663
664 /* ARGSUSED */
665 static int
666 smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
667 caller_context_t *ct)
668 {
669 struct smb_cred scred;
670 struct vattr va;
671 smbnode_t *np;
672 smbmntinfo_t *smi;
673 smb_share_t *ssp;
674 offset_t endoff, limit;
675 ssize_t past_limit;
676 int error, timo;
677
678 np = VTOSMB(vp);
679 smi = VTOSMI(vp);
680 ssp = smi->smi_share;
681
682 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
683 return (EIO);
684
685 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
686 return (EIO);
687
688 ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
689
690 if (vp->v_type != VREG)
691 return (EISDIR);
692
693 if (uiop->uio_resid == 0)
694 return (0);
695
696 /*
697 * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
698 */
699 if (ioflag & (FAPPEND | FSYNC)) {
700 if (np->n_flag & NMODIFIED) {
701 smbfs_attrcache_remove(np);
702 /* XXX: smbfs_vinvalbuf? */
703 }
704 }
705 if (ioflag & FAPPEND) {
706 /*
707 * File size can be changed by another client
708 */
709 va.va_mask = AT_SIZE;
710 if (error = smbfsgetattr(vp, &va, cr))
711 return (error);
712 uiop->uio_loffset = va.va_size;
713 }
714
715 /*
716 * Like NFS3, just check for 63-bit overflow.
717 */
718 endoff = uiop->uio_loffset + uiop->uio_resid;
719 if (uiop->uio_loffset < 0 || endoff < 0)
720 return (EINVAL);
721
722 /*
723 * Check to make sure that the process will not exceed
724 * its limit on file size. It is okay to write up to
725 * the limit, but not beyond. Thus, the write which
726 * reaches the limit will be short and the next write
727 * will return an error.
728 *
729 * So if we're starting at or beyond the limit, EFBIG.
730 * Otherwise, temporarily reduce resid to the amount
731 * the falls after the limit.
732 */
733 limit = uiop->uio_llimit;
734 if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
735 limit = MAXOFFSET_T;
736 if (uiop->uio_loffset >= limit)
737 return (EFBIG);
738 if (endoff > limit) {
739 past_limit = (ssize_t)(endoff - limit);
740 uiop->uio_resid -= past_limit;
741 } else
742 past_limit = 0;
743
744 /* Timeout: longer for append. */
745 timo = smb_timo_write;
746 if (endoff > np->r_size)
747 timo = smb_timo_append;
748
749 /* Shared lock for n_fid use in smb_rwuio */
750 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
751 return (EINTR);
752 smb_credinit(&scred, cr);
753
754 /* After reconnect, n_fid is invalid */
755 if (np->n_vcgenid != ssp->ss_vcgenid)
756 error = ESTALE;
757 else
758 error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
759 uiop, &scred, timo);
760
761 if (error == 0) {
762 mutex_enter(&np->r_statelock);
763 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
764 if (uiop->uio_loffset > (offset_t)np->r_size)
765 np->r_size = (len_t)uiop->uio_loffset;
766 mutex_exit(&np->r_statelock);
767 if (ioflag & (FSYNC|FDSYNC)) {
768 /* Don't error the I/O if this fails. */
769 (void) smbfs_smb_flush(np, &scred);
770 }
771 }
772
773 smb_credrele(&scred);
774 smbfs_rw_exit(&np->r_lkserlock);
775
776 /* undo adjustment of resid */
777 uiop->uio_resid += past_limit;
778
779 return (error);
780 }
781
782
783 /* ARGSUSED */
784 static int
785 smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
786 cred_t *cr, int *rvalp, caller_context_t *ct)
787 {
788 int error;
789 smbmntinfo_t *smi;
790
791 smi = VTOSMI(vp);
792
793 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
794 return (EIO);
795
796 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
797 return (EIO);
798
799 switch (cmd) {
800 /* First three from ZFS. XXX - need these? */
801
802 case _FIOFFS:
803 error = smbfs_fsync(vp, 0, cr, ct);
804 break;
805
806 /*
807 * The following two ioctls are used by bfu.
808 * Silently ignore to avoid bfu errors.
809 */
810 case _FIOGDIO:
811 case _FIOSDIO:
812 error = 0;
813 break;
814
815 #ifdef NOT_YET /* XXX - from the NFS code. */
816 case _FIODIRECTIO:
817 error = smbfs_directio(vp, (int)arg, cr);
818 #endif
819
820 /*
821 * Allow get/set with "raw" security descriptor (SD) data.
822 * Useful for testing, diagnosing idmap problems, etc.
823 */
824 case SMBFSIO_GETSD:
825 error = smbfs_acl_iocget(vp, arg, flag, cr);
826 break;
827
828 case SMBFSIO_SETSD:
829 error = smbfs_acl_iocset(vp, arg, flag, cr);
830 break;
831
832 default:
833 error = ENOTTY;
834 break;
835 }
836
837 return (error);
838 }
839
840
841 /*
842 * Return either cached or remote attributes. If get remote attr
843 * use them to check and invalidate caches, then cache the new attributes.
844 */
845 /* ARGSUSED */
846 static int
847 smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
848 caller_context_t *ct)
849 {
850 smbnode_t *np;
851 smbmntinfo_t *smi;
852
853 smi = VTOSMI(vp);
854
855 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
856 return (EIO);
857
858 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
859 return (EIO);
860
861 /*
862 * If it has been specified that the return value will
863 * just be used as a hint, and we are only being asked
864 * for size, fsid or rdevid, then return the client's
865 * notion of these values without checking to make sure
866 * that the attribute cache is up to date.
867 * The whole point is to avoid an over the wire GETATTR
868 * call.
869 */
870 np = VTOSMB(vp);
871 if (flags & ATTR_HINT) {
872 if (vap->va_mask ==
873 (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
874 mutex_enter(&np->r_statelock);
875 if (vap->va_mask | AT_SIZE)
876 vap->va_size = np->r_size;
877 if (vap->va_mask | AT_FSID)
878 vap->va_fsid = vp->v_vfsp->vfs_dev;
879 if (vap->va_mask | AT_RDEV)
880 vap->va_rdev = vp->v_rdev;
881 mutex_exit(&np->r_statelock);
882 return (0);
883 }
884 }
885
886 return (smbfsgetattr(vp, vap, cr));
887 }
888
889 /* smbfsgetattr() in smbfs_client.c */
890
891 /*ARGSUSED4*/
892 static int
893 smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
894 caller_context_t *ct)
895 {
896 vfs_t *vfsp;
897 smbmntinfo_t *smi;
898 int error;
899 uint_t mask;
900 struct vattr oldva;
901
902 vfsp = vp->v_vfsp;
903 smi = VFTOSMI(vfsp);
904
905 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
906 return (EIO);
907
908 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
909 return (EIO);
910
911 mask = vap->va_mask;
912 if (mask & AT_NOSET)
913 return (EINVAL);
914
915 if (vfsp->vfs_flag & VFS_RDONLY)
916 return (EROFS);
917
918 /*
919 * This is a _local_ access check so that only the owner of
920 * this mount can set attributes. With ACLs enabled, the
921 * file owner can be different from the mount owner, and we
922 * need to check the _mount_ owner here. See _access_rwx
923 */
924 bzero(&oldva, sizeof (oldva));
925 oldva.va_mask = AT_TYPE | AT_MODE;
926 error = smbfsgetattr(vp, &oldva, cr);
927 if (error)
928 return (error);
929 oldva.va_mask |= AT_UID | AT_GID;
930 oldva.va_uid = smi->smi_uid;
931 oldva.va_gid = smi->smi_gid;
932
933 error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
934 smbfs_accessx, vp);
935 if (error)
936 return (error);
937
938 if (mask & (AT_UID | AT_GID)) {
939 if (smi->smi_flags & SMI_ACL)
940 error = smbfs_acl_setids(vp, vap, cr);
941 else
942 error = ENOSYS;
943 if (error != 0) {
944 SMBVDEBUG("error %d seting UID/GID on %s",
945 error, VTOSMB(vp)->n_rpath);
946 /*
947 * It might be more correct to return the
948 * error here, but that causes complaints
949 * when root extracts a cpio archive, etc.
950 * So ignore this error, and go ahead with
951 * the rest of the setattr work.
952 */
953 }
954 }
955
956 return (smbfssetattr(vp, vap, flags, cr));
957 }
958
959 /*
960 * Mostly from Darwin smbfs_setattr()
961 * but then modified a lot.
962 */
963 /* ARGSUSED */
964 static int
965 smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
966 {
967 int error = 0;
968 smbnode_t *np = VTOSMB(vp);
969 uint_t mask = vap->va_mask;
970 struct timespec *mtime, *atime;
971 struct smb_cred scred;
972 int cerror, modified = 0;
973 unsigned short fid;
974 int have_fid = 0;
975 uint32_t rights = 0;
976 uint32_t dosattr = 0;
977
978 ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
979
980 /*
981 * There are no settable attributes on the XATTR dir,
982 * so just silently ignore these. On XATTR files,
983 * you can set the size but nothing else.
984 */
985 if (vp->v_flag & V_XATTRDIR)
986 return (0);
987 if (np->n_flag & N_XATTR) {
988 if (mask & AT_TIMES)
989 SMBVDEBUG("ignore set time on xattr\n");
990 mask &= AT_SIZE;
991 }
992
993 /*
994 * If our caller is trying to set multiple attributes, they
995 * can make no assumption about what order they are done in.
996 * Here we try to do them in order of decreasing likelihood
997 * of failure, just to minimize the chance we'll wind up
998 * with a partially complete request.
999 */
1000
1001 /* Shared lock for (possible) n_fid use. */
1002 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1003 return (EINTR);
1004 smb_credinit(&scred, cr);
1005
1006 /*
1007 * If the caller has provided extensible attributes,
1008 * map those into DOS attributes supported by SMB.
1009 * Note: zero means "no change".
1010 */
1011 if (mask & AT_XVATTR)
1012 dosattr = xvattr_to_dosattr(np, vap);
1013
1014 /*
1015 * Will we need an open handle for this setattr?
1016 * If so, what rights will we need?
1017 */
1018 if (dosattr || (mask & (AT_ATIME | AT_MTIME))) {
1019 rights |=
1020 SA_RIGHT_FILE_WRITE_ATTRIBUTES;
1021 }
1022 if (mask & AT_SIZE) {
1023 rights |=
1024 SA_RIGHT_FILE_WRITE_DATA |
1025 SA_RIGHT_FILE_APPEND_DATA;
1026 }
1027
1028 /*
1029 * Only SIZE really requires a handle, but it's
1030 * simpler and more reliable to set via a handle.
1031 * Some servers like NT4 won't set times by path.
1032 * Also, we're usually setting everything anyway.
1033 */
1034 if (rights != 0) {
1035 error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
1036 if (error) {
1037 SMBVDEBUG("error %d opening %s\n",
1038 error, np->n_rpath);
1039 goto out;
1040 }
1041 have_fid = 1;
1042 }
1043
1044 /*
1045 * If the server supports the UNIX extensions, right here is where
1046 * we'd support changes to uid, gid, mode, and possibly va_flags.
1047 * For now we claim to have made any such changes.
1048 */
1049
1050 if (mask & AT_SIZE) {
1051 /*
1052 * If the new file size is less than what the client sees as
1053 * the file size, then just change the size and invalidate
1054 * the pages.
1055 * I am commenting this code at present because the function
1056 * smbfs_putapage() is not yet implemented.
1057 */
1058
1059 /*
1060 * Set the file size to vap->va_size.
1061 */
1062 ASSERT(have_fid);
1063 error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
1064 if (error) {
1065 SMBVDEBUG("setsize error %d file %s\n",
1066 error, np->n_rpath);
1067 } else {
1068 /*
1069 * Darwin had code here to zero-extend.
1070 * Tests indicate the server will zero-fill,
1071 * so looks like we don't need to do this.
1072 * Good thing, as this could take forever.
1073 *
1074 * XXX: Reportedly, writing one byte of zero
1075 * at the end offset avoids problems here.
1076 */
1077 mutex_enter(&np->r_statelock);
1078 np->r_size = vap->va_size;
1079 mutex_exit(&np->r_statelock);
1080 modified = 1;
1081 }
1082 }
1083
1084 /*
1085 * XXX: When Solaris has create_time, set that too.
1086 * Note: create_time is different from ctime.
1087 */
1088 mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
1089 atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
1090
1091 if (dosattr || mtime || atime) {
1092 /*
1093 * Always use the handle-based set attr call now.
1094 */
1095 ASSERT(have_fid);
1096 error = smbfs_smb_setfattr(np, fid,
1097 dosattr, mtime, atime, &scred);
1098 if (error) {
1099 SMBVDEBUG("set times error %d file %s\n",
1100 error, np->n_rpath);
1101 } else {
1102 modified = 1;
1103 }
1104 }
1105
1106 out:
1107 if (modified) {
1108 /*
1109 * Invalidate attribute cache in case the server
1110 * doesn't set exactly the attributes we asked.
1111 */
1112 smbfs_attrcache_remove(np);
1113 }
1114
1115 if (have_fid) {
1116 cerror = smbfs_smb_tmpclose(np, fid, &scred);
1117 if (cerror)
1118 SMBVDEBUG("error %d closing %s\n",
1119 cerror, np->n_rpath);
1120 }
1121
1122 smb_credrele(&scred);
1123 smbfs_rw_exit(&np->r_lkserlock);
1124
1125 return (error);
1126 }
1127
1128 /*
1129 * Helper function for extensible system attributes (PSARC 2007/315)
1130 * Compute the DOS attribute word to pass to _setfattr (see above).
1131 * This returns zero IFF no change is being made to attributes.
1132 * Otherwise return the new attributes or SMB_EFA_NORMAL.
1133 */
1134 static uint32_t
1135 xvattr_to_dosattr(smbnode_t *np, struct vattr *vap)
1136 {
1137 xvattr_t *xvap = (xvattr_t *)vap;
1138 xoptattr_t *xoap = NULL;
1139 uint32_t attr = np->r_attr.fa_attr;
1140 boolean_t anyset = B_FALSE;
1141
1142 if ((xoap = xva_getxoptattr(xvap)) == NULL)
1143 return (0);
1144
1145 if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
1146 if (xoap->xoa_archive)
1147 attr |= SMB_FA_ARCHIVE;
1148 else
1149 attr &= ~SMB_FA_ARCHIVE;
1150 XVA_SET_RTN(xvap, XAT_ARCHIVE);
1151 anyset = B_TRUE;
1152 }
1153 if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
1154 if (xoap->xoa_system)
1155 attr |= SMB_FA_SYSTEM;
1156 else
1157 attr &= ~SMB_FA_SYSTEM;
1158 XVA_SET_RTN(xvap, XAT_SYSTEM);
1159 anyset = B_TRUE;
1160 }
1161 if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
1162 if (xoap->xoa_readonly)
1163 attr |= SMB_FA_RDONLY;
1164 else
1165 attr &= ~SMB_FA_RDONLY;
1166 XVA_SET_RTN(xvap, XAT_READONLY);
1167 anyset = B_TRUE;
1168 }
1169 if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
1170 if (xoap->xoa_hidden)
1171 attr |= SMB_FA_HIDDEN;
1172 else
1173 attr &= ~SMB_FA_HIDDEN;
1174 XVA_SET_RTN(xvap, XAT_HIDDEN);
1175 anyset = B_TRUE;
1176 }
1177
1178 if (anyset == B_FALSE)
1179 return (0); /* no change */
1180 if (attr == 0)
1181 attr = SMB_EFA_NORMAL;
1182
1183 return (attr);
1184 }
1185
1186 /*
1187 * smbfs_access_rwx()
1188 * Common function for smbfs_access, etc.
1189 *
1190 * The security model implemented by the FS is unusual
1191 * due to the current "single user mounts" restriction:
1192 * All access under a given mount point uses the CIFS
1193 * credentials established by the owner of the mount.
1194 *
1195 * Most access checking is handled by the CIFS server,
1196 * but we need sufficient Unix access checks here to
1197 * prevent other local Unix users from having access
1198 * to objects under this mount that the uid/gid/mode
1199 * settings in the mount would not allow.
1200 *
1201 * With this model, there is a case where we need the
1202 * ability to do an access check before we have the
1203 * vnode for an object. This function takes advantage
1204 * of the fact that the uid/gid/mode is per mount, and
1205 * avoids the need for a vnode.
1206 *
1207 * We still (sort of) need a vnode when we call
1208 * secpolicy_vnode_access, but that only uses
1209 * the vtype field, so we can use a pair of fake
1210 * vnodes that have only v_type filled in.
1211 *
1212 * XXX: Later, add a new secpolicy_vtype_access()
1213 * that takes the vtype instead of a vnode, and
1214 * get rid of the tmpl_vxxx fake vnodes below.
1215 */
1216 static int
1217 smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
1218 {
1219 /* See the secpolicy call below. */
1220 static const vnode_t tmpl_vdir = { .v_type = VDIR };
1221 static const vnode_t tmpl_vreg = { .v_type = VREG };
1222 vattr_t va;
1223 vnode_t *tvp;
1224 struct smbmntinfo *smi = VFTOSMI(vfsp);
1225 int shift = 0;
1226
1227 /*
1228 * Build our (fabricated) vnode attributes.
1229 * XXX: Could make these templates in the
1230 * per-mount struct and use them here.
1231 */
1232 bzero(&va, sizeof (va));
1233 va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1234 va.va_type = vtype;
1235 va.va_mode = (vtype == VDIR) ?
1236 smi->smi_dmode : smi->smi_fmode;
1237 va.va_uid = smi->smi_uid;
1238 va.va_gid = smi->smi_gid;
1239
1240 /*
1241 * Disallow write attempts on read-only file systems,
1242 * unless the file is a device or fifo node. Note:
1243 * Inline vn_is_readonly and IS_DEVVP here because
1244 * we may not have a vnode ptr. Original expr. was:
1245 * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
1246 */
1247 if ((mode & VWRITE) &&
1248 (vfsp->vfs_flag & VFS_RDONLY) &&
1249 !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
1250 return (EROFS);
1251
1252 /*
1253 * Disallow attempts to access mandatory lock files.
1254 * Similarly, expand MANDLOCK here.
1255 * XXX: not sure we need this.
1256 */
1257 if ((mode & (VWRITE | VREAD | VEXEC)) &&
1258 va.va_type == VREG && MANDMODE(va.va_mode))
1259 return (EACCES);
1260
1261 /*
1262 * Access check is based on only
1263 * one of owner, group, public.
1264 * If not owner, then check group.
1265 * If not a member of the group,
1266 * then check public access.
1267 */
1268 if (crgetuid(cr) != va.va_uid) {
1269 shift += 3;
1270 if (!groupmember(va.va_gid, cr))
1271 shift += 3;
1272 }
1273
1274 /*
1275 * We need a vnode for secpolicy_vnode_access,
1276 * but the only thing it looks at is v_type,
1277 * so pass one of the templates above.
1278 */
1279 tvp = (va.va_type == VDIR) ?
1280 (vnode_t *)&tmpl_vdir :
1281 (vnode_t *)&tmpl_vreg;
1282
1283 return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1284 va.va_mode << shift, mode));
1285 }
1286
1287 /*
1288 * See smbfs_setattr
1289 */
1290 static int
1291 smbfs_accessx(void *arg, int mode, cred_t *cr)
1292 {
1293 vnode_t *vp = arg;
1294 /*
1295 * Note: The caller has checked the current zone,
1296 * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
1297 */
1298 return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
1299 }
1300
1301 /*
1302 * XXX
1303 * This op should support PSARC 2007/403, Modified Access Checks for CIFS
1304 */
1305 /* ARGSUSED */
1306 static int
1307 smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1308 {
1309 vfs_t *vfsp;
1310 smbmntinfo_t *smi;
1311
1312 vfsp = vp->v_vfsp;
1313 smi = VFTOSMI(vfsp);
1314
1315 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1316 return (EIO);
1317
1318 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1319 return (EIO);
1320
1321 return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
1322 }
1323
1324
1325 /*
1326 * Flush local dirty pages to stable storage on the server.
1327 *
1328 * If FNODSYNC is specified, then there is nothing to do because
1329 * metadata changes are not cached on the client before being
1330 * sent to the server.
1331 */
1332 /* ARGSUSED */
1333 static int
1334 smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
1335 {
1336 int error = 0;
1337 smbmntinfo_t *smi;
1338 smbnode_t *np;
1339 struct smb_cred scred;
1340
1341 np = VTOSMB(vp);
1342 smi = VTOSMI(vp);
1343
1344 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1345 return (EIO);
1346
1347 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1348 return (EIO);
1349
1350 if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
1351 return (0);
1352
1353 if ((syncflag & (FSYNC|FDSYNC)) == 0)
1354 return (0);
1355
1356 /* Shared lock for n_fid use in _flush */
1357 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1358 return (EINTR);
1359 smb_credinit(&scred, cr);
1360
1361 error = smbfs_smb_flush(np, &scred);
1362
1363 smb_credrele(&scred);
1364 smbfs_rw_exit(&np->r_lkserlock);
1365
1366 return (error);
1367 }
1368
1369 /*
1370 * Last reference to vnode went away.
1371 */
1372 /* ARGSUSED */
1373 static void
1374 smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1375 {
1376 smbnode_t *np;
1377 struct smb_cred scred;
1378
1379 /*
1380 * Don't "bail out" for VFS_UNMOUNTED here,
1381 * as we want to do cleanup, etc.
1382 * See also pcfs_inactive
1383 */
1384
1385 np = VTOSMB(vp);
1386
1387 /*
1388 * If this is coming from the wrong zone, we let someone in the right
1389 * zone take care of it asynchronously. We can get here due to
1390 * VN_RELE() being called from pageout() or fsflush(). This call may
1391 * potentially turn into an expensive no-op if, for instance, v_count
1392 * gets incremented in the meantime, but it's still correct.
1393 */
1394
1395 /*
1396 * Defend against the possibility that higher-level callers
1397 * might not correctly balance open and close calls. If we
1398 * get here with open references remaining, it means there
1399 * was a missing VOP_CLOSE somewhere. If that happens, do
1400 * the close here so we don't "leak" FIDs on the server.
1401 *
1402 * Exclusive lock for modifying n_fid stuff.
1403 * Don't want this one ever interruptible.
1404 */
1405 (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
1406 smb_credinit(&scred, cr);
1407
1408 switch (np->n_ovtype) {
1409 case VNON:
1410 /* not open (OK) */
1411 break;
1412
1413 case VDIR:
1414 if (np->n_dirrefs == 0)
1415 break;
1416 SMBVDEBUG("open dir: refs %d path %s\n",
1417 np->n_dirrefs, np->n_rpath);
1418 /* Force last close. */
1419 np->n_dirrefs = 1;
1420 smbfs_rele_fid(np, &scred);
1421 break;
1422
1423 case VREG:
1424 if (np->n_fidrefs == 0)
1425 break;
1426 SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1427 np->n_fidrefs, np->n_fid, np->n_rpath);
1428 /* Force last close. */
1429 np->n_fidrefs = 1;
1430 smbfs_rele_fid(np, &scred);
1431 break;
1432
1433 default:
1434 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1435 np->n_ovtype = VNON;
1436 break;
1437 }
1438
1439 smb_credrele(&scred);
1440 smbfs_rw_exit(&np->r_lkserlock);
1441
1442 /*
1443 * XATTR directories (and the files under them) have
1444 * little value for reclaim, so just remove them from
1445 * the "hash" (AVL) as soon as they go inactive.
1446 * Note that the node may already have been removed
1447 * from the hash by smbfsremove.
1448 */
1449 if ((np->n_flag & N_XATTR) != 0 &&
1450 (np->r_flags & RHASHED) != 0)
1451 smbfs_rmhash(np);
1452
1453 smbfs_addfree(np);
1454 }
1455
1456 /*
1457 * Remote file system operations having to do with directory manipulation.
1458 */
1459 /* ARGSUSED */
1460 static int
1461 smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
1462 int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
1463 int *direntflags, pathname_t *realpnp)
1464 {
1465 vfs_t *vfs;
1466 smbmntinfo_t *smi;
1467 smbnode_t *dnp;
1468 int error;
1469
1470 vfs = dvp->v_vfsp;
1471 smi = VFTOSMI(vfs);
1472
1473 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1474 return (EPERM);
1475
1476 if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
1477 return (EIO);
1478
1479 dnp = VTOSMB(dvp);
1480
1481 /*
1482 * Are we looking up extended attributes? If so, "dvp" is
1483 * the file or directory for which we want attributes, and
1484 * we need a lookup of the (faked up) attribute directory
1485 * before we lookup the rest of the path.
1486 */
1487 if (flags & LOOKUP_XATTR) {
1488 /*
1489 * Require the xattr mount option.
1490 */
1491 if ((vfs->vfs_flag & VFS_XATTR) == 0)
1492 return (EINVAL);
1493
1494 error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
1495 return (error);
1496 }
1497
1498 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
1499 return (EINTR);
1500
1501 error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
1502
1503 smbfs_rw_exit(&dnp->r_rwlock);
1504
1505 return (error);
1506 }
1507
1508 /* ARGSUSED */
1509 static int
1510 smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
1511 int cache_ok, caller_context_t *ct)
1512 {
1513 int error;
1514 int supplen; /* supported length */
1515 vnode_t *vp;
1516 smbnode_t *np;
1517 smbnode_t *dnp;
1518 smbmntinfo_t *smi;
1519 /* struct smb_vc *vcp; */
1520 const char *ill;
1521 const char *name = (const char *)nm;
1522 int nmlen = strlen(nm);
1523 int rplen;
1524 struct smb_cred scred;
1525 struct smbfattr fa;
1526
1527 smi = VTOSMI(dvp);
1528 dnp = VTOSMB(dvp);
1529
1530 ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
1531
1532 #ifdef NOT_YET
1533 vcp = SSTOVC(smi->smi_share);
1534
1535 /* XXX: Should compute this once and store it in smbmntinfo_t */
1536 supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
1537 #else
1538 supplen = 255;
1539 #endif
1540
1541 /*
1542 * RWlock must be held, either reader or writer.
1543 * XXX: Can we check without looking directly
1544 * inside the struct smbfs_rwlock_t?
1545 */
1546 ASSERT(dnp->r_rwlock.count != 0);
1547
1548 /*
1549 * If lookup is for "", just return dvp.
1550 * No need to perform any access checks.
1551 */
1552 if (nmlen == 0) {
1553 VN_HOLD(dvp);
1554 *vpp = dvp;
1555 return (0);
1556 }
1557
1558 /*
1559 * Can't do lookups in non-directories.
1560 */
1561 if (dvp->v_type != VDIR)
1562 return (ENOTDIR);
1563
1564 /*
1565 * Need search permission in the directory.
1566 */
1567 error = smbfs_access(dvp, VEXEC, 0, cr, ct);
1568 if (error)
1569 return (error);
1570
1571 /*
1572 * If lookup is for ".", just return dvp.
1573 * Access check was done above.
1574 */
1575 if (nmlen == 1 && name[0] == '.') {
1576 VN_HOLD(dvp);
1577 *vpp = dvp;
1578 return (0);
1579 }
1580
1581 /*
1582 * Now some sanity checks on the name.
1583 * First check the length.
1584 */
1585 if (nmlen > supplen)
1586 return (ENAMETOOLONG);
1587
1588 /*
1589 * Avoid surprises with characters that are
1590 * illegal in Windows file names.
1591 * Todo: CATIA mappings XXX
1592 */
1593 ill = illegal_chars;
1594 if (dnp->n_flag & N_XATTR)
1595 ill++; /* allow colon */
1596 if (strpbrk(nm, ill))
1597 return (EINVAL);
1598
1599 /*
1600 * Special handling for lookup of ".."
1601 *
1602 * We keep full pathnames (as seen on the server)
1603 * so we can just trim off the last component to
1604 * get the full pathname of the parent. Note:
1605 * We don't actually copy and modify, but just
1606 * compute the trimmed length and pass that with
1607 * the current dir path (not null terminated).
1608 *
1609 * We don't go over-the-wire to get attributes
1610 * for ".." because we know it's a directory,
1611 * and we can just leave the rest "stale"
1612 * until someone does a getattr.
1613 */
1614 if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1615 if (dvp->v_flag & VROOT) {
1616 /*
1617 * Already at the root. This can happen
1618 * with directory listings at the root,
1619 * which lookup "." and ".." to get the
1620 * inode numbers. Let ".." be the same
1621 * as "." in the FS root.
1622 */
1623 VN_HOLD(dvp);
1624 *vpp = dvp;
1625 return (0);
1626 }
1627
1628 /*
1629 * Special case for XATTR directory
1630 */
1631 if (dvp->v_flag & V_XATTRDIR) {
1632 error = smbfs_xa_parent(dvp, vpp);
1633 return (error);
1634 }
1635
1636 /*
1637 * Find the parent path length.
1638 */
1639 rplen = dnp->n_rplen;
1640 ASSERT(rplen > 0);
1641 while (--rplen >= 0) {
1642 if (dnp->n_rpath[rplen] == '\\')
1643 break;
1644 }
1645 if (rplen <= 0) {
1646 /* Found our way to the root. */
1647 vp = SMBTOV(smi->smi_root);
1648 VN_HOLD(vp);
1649 *vpp = vp;
1650 return (0);
1651 }
1652 np = smbfs_node_findcreate(smi,
1653 dnp->n_rpath, rplen, NULL, 0, 0,
1654 &smbfs_fattr0); /* force create */
1655 ASSERT(np != NULL);
1656 vp = SMBTOV(np);
1657 vp->v_type = VDIR;
1658
1659 /* Success! */
1660 *vpp = vp;
1661 return (0);
1662 }
1663
1664 /*
1665 * Normal lookup of a name under this directory.
1666 * Note we handled "", ".", ".." above.
1667 */
1668 if (cache_ok) {
1669 /*
1670 * The caller indicated that it's OK to use a
1671 * cached result for this lookup, so try to
1672 * reclaim a node from the smbfs node cache.
1673 */
1674 error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
1675 if (error)
1676 return (error);
1677 if (vp != NULL) {
1678 /* hold taken in lookup_cache */
1679 *vpp = vp;
1680 return (0);
1681 }
1682 }
1683
1684 /*
1685 * OK, go over-the-wire to get the attributes,
1686 * then create the node.
1687 */
1688 smb_credinit(&scred, cr);
1689 /* Note: this can allocate a new "name" */
1690 error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
1691 smb_credrele(&scred);
1692 if (error == ENOTDIR) {
1693 /*
1694 * Lookup failed because this directory was
1695 * removed or renamed by another client.
1696 * Remove any cached attributes under it.
1697 */
1698 smbfs_attrcache_remove(dnp);
1699 smbfs_attrcache_prune(dnp);
1700 }
1701 if (error)
1702 goto out;
1703
1704 error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
1705 if (error)
1706 goto out;
1707
1708 /* Success! */
1709 *vpp = vp;
1710
1711 out:
1712 /* smbfs_smb_lookup may have allocated name. */
1713 if (name != nm)
1714 smbfs_name_free(name, nmlen);
1715
1716 return (error);
1717 }
1718
1719 /*
1720 * smbfslookup_cache
1721 *
1722 * Try to reclaim a node from the smbfs node cache.
1723 * Some statistics for DEBUG.
1724 *
1725 * This mechanism lets us avoid many of the five (or more)
1726 * OtW lookup calls per file seen with "ls -l" if we search
1727 * the smbfs node cache for recently inactive(ated) nodes.
1728 */
1729 #ifdef DEBUG
1730 int smbfs_lookup_cache_calls = 0;
1731 int smbfs_lookup_cache_error = 0;
1732 int smbfs_lookup_cache_miss = 0;
1733 int smbfs_lookup_cache_stale = 0;
1734 int smbfs_lookup_cache_hits = 0;
1735 #endif /* DEBUG */
1736
1737 /* ARGSUSED */
1738 static int
1739 smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
1740 vnode_t **vpp, cred_t *cr)
1741 {
1742 struct vattr va;
1743 smbnode_t *dnp;
1744 smbnode_t *np;
1745 vnode_t *vp;
1746 int error;
1747 char sep;
1748
1749 dnp = VTOSMB(dvp);
1750 *vpp = NULL;
1751
1752 #ifdef DEBUG
1753 smbfs_lookup_cache_calls++;
1754 #endif
1755
1756 /*
1757 * First make sure we can get attributes for the
1758 * directory. Cached attributes are OK here.
1759 * If we removed or renamed the directory, this
1760 * will return ENOENT. If someone else removed
1761 * this directory or file, we'll find out when we
1762 * try to open or get attributes.
1763 */
1764 va.va_mask = AT_TYPE | AT_MODE;
1765 error = smbfsgetattr(dvp, &va, cr);
1766 if (error) {
1767 #ifdef DEBUG
1768 smbfs_lookup_cache_error++;
1769 #endif
1770 return (error);
1771 }
1772
1773 /*
1774 * Passing NULL smbfattr here so we will
1775 * just look, not create.
1776 */
1777 sep = SMBFS_DNP_SEP(dnp);
1778 np = smbfs_node_findcreate(dnp->n_mount,
1779 dnp->n_rpath, dnp->n_rplen,
1780 nm, nmlen, sep, NULL);
1781 if (np == NULL) {
1782 #ifdef DEBUG
1783 smbfs_lookup_cache_miss++;
1784 #endif
1785 return (0);
1786 }
1787
1788 /*
1789 * Found it. Attributes still valid?
1790 */
1791 vp = SMBTOV(np);
1792 if (np->r_attrtime <= gethrtime()) {
1793 /* stale */
1794 #ifdef DEBUG
1795 smbfs_lookup_cache_stale++;
1796 #endif
1797 VN_RELE(vp);
1798 return (0);
1799 }
1800
1801 /*
1802 * Success!
1803 * Caller gets hold from smbfs_node_findcreate
1804 */
1805 #ifdef DEBUG
1806 smbfs_lookup_cache_hits++;
1807 #endif
1808 *vpp = vp;
1809 return (0);
1810 }
1811
1812 /*
1813 * XXX
1814 * vsecattr_t is new to build 77, and we need to eventually support
1815 * it in order to create an ACL when an object is created.
1816 *
1817 * This op should support the new FIGNORECASE flag for case-insensitive
1818 * lookups, per PSARC 2007/244.
1819 */
1820 /* ARGSUSED */
1821 static int
1822 smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
1823 int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
1824 vsecattr_t *vsecp)
1825 {
1826 int error;
1827 int cerror;
1828 vfs_t *vfsp;
1829 vnode_t *vp;
1830 #ifdef NOT_YET
1831 smbnode_t *np;
1832 #endif
1833 smbnode_t *dnp;
1834 smbmntinfo_t *smi;
1835 struct vattr vattr;
1836 struct smbfattr fattr;
1837 struct smb_cred scred;
1838 const char *name = (const char *)nm;
1839 int nmlen = strlen(nm);
1840 uint32_t disp;
1841 uint16_t fid;
1842 int xattr;
1843
1844 vfsp = dvp->v_vfsp;
1845 smi = VFTOSMI(vfsp);
1846 dnp = VTOSMB(dvp);
1847 vp = NULL;
1848
1849 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1850 return (EPERM);
1851
1852 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1853 return (EIO);
1854
1855 /*
1856 * Note: this may break mknod(2) calls to create a directory,
1857 * but that's obscure use. Some other filesystems do this.
1858 * XXX: Later, redirect VDIR type here to _mkdir.
1859 */
1860 if (va->va_type != VREG)
1861 return (EINVAL);
1862
1863 /*
1864 * If the pathname is "", just use dvp, no checks.
1865 * Do this outside of the rwlock (like zfs).
1866 */
1867 if (nmlen == 0) {
1868 VN_HOLD(dvp);
1869 *vpp = dvp;
1870 return (0);
1871 }
1872
1873 /* Don't allow "." or ".." through here. */
1874 if ((nmlen == 1 && name[0] == '.') ||
1875 (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1876 return (EISDIR);
1877
1878 /*
1879 * We make a copy of the attributes because the caller does not
1880 * expect us to change what va points to.
1881 */
1882 vattr = *va;
1883
1884 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1885 return (EINTR);
1886 smb_credinit(&scred, cr);
1887
1888 /*
1889 * NFS needs to go over the wire, just to be sure whether the
1890 * file exists or not. Using a cached result is dangerous in
1891 * this case when making a decision regarding existence.
1892 *
1893 * The SMB protocol does NOT really need to go OTW here
1894 * thanks to the expressive NTCREATE disposition values.
1895 * Unfortunately, to do Unix access checks correctly,
1896 * we need to know if the object already exists.
1897 * When the object does not exist, we need VWRITE on
1898 * the directory. Note: smbfslookup() checks VEXEC.
1899 */
1900 error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1901 if (error == 0) {
1902 /*
1903 * The file already exists. Error?
1904 * NB: have a hold from smbfslookup
1905 */
1906 if (exclusive == EXCL) {
1907 error = EEXIST;
1908 VN_RELE(vp);
1909 goto out;
1910 }
1911 /*
1912 * Verify requested access.
1913 */
1914 error = smbfs_access(vp, mode, 0, cr, ct);
1915 if (error) {
1916 VN_RELE(vp);
1917 goto out;
1918 }
1919
1920 /*
1921 * Truncate (if requested).
1922 */
1923 if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
1924 vattr.va_mask = AT_SIZE;
1925 error = smbfssetattr(vp, &vattr, 0, cr);
1926 if (error) {
1927 VN_RELE(vp);
1928 goto out;
1929 }
1930 }
1931 /* Success! */
1932 #ifdef NOT_YET
1933 vnevent_create(vp, ct);
1934 #endif
1935 *vpp = vp;
1936 goto out;
1937 }
1938
1939 /*
1940 * The file did not exist. Need VWRITE in the directory.
1941 */
1942 error = smbfs_access(dvp, VWRITE, 0, cr, ct);
1943 if (error)
1944 goto out;
1945
1946 /*
1947 * Now things get tricky. We also need to check the
1948 * requested open mode against the file we may create.
1949 * See comments at smbfs_access_rwx
1950 */
1951 error = smbfs_access_rwx(vfsp, VREG, mode, cr);
1952 if (error)
1953 goto out;
1954
1955 /*
1956 * Now the code derived from Darwin,
1957 * but with greater use of NT_CREATE
1958 * disposition options. Much changed.
1959 *
1960 * Create (or open) a new child node.
1961 * Note we handled "." and ".." above.
1962 */
1963
1964 if (exclusive == EXCL)
1965 disp = NTCREATEX_DISP_CREATE;
1966 else {
1967 /* Truncate regular files if requested. */
1968 if ((va->va_type == VREG) &&
1969 (va->va_mask & AT_SIZE) &&
1970 (va->va_size == 0))
1971 disp = NTCREATEX_DISP_OVERWRITE_IF;
1972 else
1973 disp = NTCREATEX_DISP_OPEN_IF;
1974 }
1975 xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
1976 error = smbfs_smb_create(dnp,
1977 name, nmlen, xattr,
1978 disp, &scred, &fid);
1979 if (error)
1980 goto out;
1981
1982 /*
1983 * XXX: Missing some code here to deal with
1984 * the case where we opened an existing file,
1985 * it's size is larger than 32-bits, and we're
1986 * setting the size from a process that's not
1987 * aware of large file offsets. i.e.
1988 * from the NFS3 code:
1989 */
1990 #if NOT_YET /* XXX */
1991 if ((vattr.va_mask & AT_SIZE) &&
1992 vp->v_type == VREG) {
1993 np = VTOSMB(vp);
1994 /*
1995 * Check here for large file handled
1996 * by LF-unaware process (as
1997 * ufs_create() does)
1998 */
1999 if (!(lfaware & FOFFMAX)) {
2000 mutex_enter(&np->r_statelock);
2001 if (np->r_size > MAXOFF32_T)
2002 error = EOVERFLOW;
2003 mutex_exit(&np->r_statelock);
2004 }
2005 if (!error) {
2006 vattr.va_mask = AT_SIZE;
2007 error = smbfssetattr(vp,
2008 &vattr, 0, cr);
2009 }
2010 }
2011 #endif /* XXX */
2012 /*
2013 * Should use the fid to get/set the size
2014 * while we have it opened here. See above.
2015 */
2016
2017 cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
2018 if (cerror)
2019 SMBVDEBUG("error %d closing %s\\%s\n",
2020 cerror, dnp->n_rpath, name);
2021
2022 /*
2023 * In the open case, the name may differ a little
2024 * from what we passed to create (case, etc.)
2025 * so call lookup to get the (opened) name.
2026 *
2027 * XXX: Could avoid this extra lookup if the
2028 * "createact" result from NT_CREATE says we
2029 * created the object.
2030 */
2031 error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2032 if (error)
2033 goto out;
2034
2035 /* update attr and directory cache */
2036 smbfs_attr_touchdir(dnp);
2037
2038 error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2039 if (error)
2040 goto out;
2041
2042 /* XXX invalidate pages if we truncated? */
2043
2044 /* Success! */
2045 *vpp = vp;
2046 error = 0;
2047
2048 out:
2049 smb_credrele(&scred);
2050 smbfs_rw_exit(&dnp->r_rwlock);
2051 if (name != nm)
2052 smbfs_name_free(name, nmlen);
2053 return (error);
2054 }
2055
2056 /*
2057 * XXX
2058 * This op should support the new FIGNORECASE flag for case-insensitive
2059 * lookups, per PSARC 2007/244.
2060 */
2061 /* ARGSUSED */
2062 static int
2063 smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
2064 int flags)
2065 {
2066 struct smb_cred scred;
2067 vnode_t *vp = NULL;
2068 smbnode_t *dnp = VTOSMB(dvp);
2069 smbmntinfo_t *smi = VTOSMI(dvp);
2070 int error;
2071
2072 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2073 return (EPERM);
2074
2075 if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2076 return (EIO);
2077
2078 /*
2079 * Verify access to the dirctory.
2080 */
2081 error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
2082 if (error)
2083 return (error);
2084
2085 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2086 return (EINTR);
2087 smb_credinit(&scred, cr);
2088
2089 /* Lookup the file to remove. */
2090 error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2091 if (error == 0) {
2092 /*
2093 * Do the real remove work
2094 */
2095 error = smbfsremove(dvp, vp, &scred, flags);
2096 VN_RELE(vp);
2097 }
2098
2099 smb_credrele(&scred);
2100 smbfs_rw_exit(&dnp->r_rwlock);
2101
2102 return (error);
2103 }
2104
2105 /*
2106 * smbfsremove does the real work of removing in SMBFS
2107 * Caller has done dir access checks etc.
2108 *
2109 * The normal way to delete a file over SMB is open it (with DELETE access),
2110 * set the "delete-on-close" flag, and close the file. The problem for Unix
2111 * applications is that they expect the file name to be gone once the unlink
2112 * completes, and the SMB server does not actually delete the file until ALL
2113 * opens of that file are closed. We can't assume our open handles are the
2114 * only open handles on a file we're deleting, so to be safe we'll try to
2115 * rename the file to a temporary name and then set delete-on-close. If we
2116 * fail to set delete-on-close (i.e. because other opens prevent it) then
2117 * undo the changes we made and give up with EBUSY. Note that we might have
2118 * permission to delete a file but lack permission to rename, so we want to
2119 * continue in cases where rename fails. As an optimization, only do the
2120 * rename when we have the file open.
2121 *
2122 * This is similar to what NFS does when deleting a file that has local opens,
2123 * but thanks to SMB delete-on-close, we don't need to keep track of when the
2124 * last local open goes away and send a delete. The server does that for us.
2125 */
2126 /* ARGSUSED */
2127 static int
2128 smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
2129 int flags)
2130 {
2131 smbnode_t *dnp = VTOSMB(dvp);
2132 smbnode_t *np = VTOSMB(vp);
2133 char *tmpname = NULL;
2134 int tnlen;
2135 int error;
2136 unsigned short fid;
2137 boolean_t have_fid = B_FALSE;
2138 boolean_t renamed = B_FALSE;
2139
2140 /*
2141 * The dvp RWlock must be held as writer.
2142 */
2143 ASSERT(dnp->r_rwlock.owner == curthread);
2144
2145 /* Never allow link/unlink directories on SMB. */
2146 if (vp->v_type == VDIR)
2147 return (EPERM);
2148
2149 /* Shared lock for n_fid use in smbfs_smb_setdisp etc. */
2150 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
2151 return (EINTR);
2152
2153 /* Force lookup to go OtW */
2154 smbfs_attrcache_remove(np);
2155
2156 /*
2157 * Get a file handle with delete access.
2158 * Close this FID before return.
2159 */
2160 error = smbfs_smb_tmpopen(np, STD_RIGHT_DELETE_ACCESS,
2161 scred, &fid);
2162 if (error) {
2163 SMBVDEBUG("error %d opening %s\n",
2164 error, np->n_rpath);
2165 goto out;
2166 }
2167 have_fid = B_TRUE;
2168
2169 /*
2170 * If we have the file open, try to rename it to a temporary name.
2171 * If we can't rename, continue on and try setting DoC anyway.
2172 */
2173 if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
2174 tmpname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2175 tnlen = smbfs_newname(tmpname, MAXNAMELEN);
2176 error = smbfs_smb_t2rename(np, tmpname, tnlen, scred, fid, 0);
2177 if (error != 0) {
2178 SMBVDEBUG("error %d renaming %s -> %s\n",
2179 error, np->n_rpath, tmpname);
2180 /* Keep going without the rename. */
2181 } else {
2182 renamed = B_TRUE;
2183 }
2184 }
2185
2186 /*
2187 * Mark the file as delete-on-close. If we can't,
2188 * undo what we did and err out.
2189 */
2190 error = smbfs_smb_setdisp(np, fid, 1, scred);
2191 if (error != 0) {
2192 SMBVDEBUG("error %d setting DoC on %s\n",
2193 error, np->n_rpath);
2194 /*
2195 * Failed to set DoC. If we renamed, undo that.
2196 * Need np->n_rpath relative to parent (dnp).
2197 * Use parent path name length plus one for
2198 * the separator ('/' or ':')
2199 */
2200 if (renamed) {
2201 char *oldname;
2202 int oldnlen;
2203 int err2;
2204
2205 oldname = np->n_rpath + (dnp->n_rplen + 1);
2206 oldnlen = np->n_rplen - (dnp->n_rplen + 1);
2207 err2 = smbfs_smb_t2rename(np, oldname, oldnlen,
2208 scred, fid, 0);
2209 SMBVDEBUG("error %d un-renaming %s -> %s\n",
2210 err2, tmpname, np->n_rpath);
2211 }
2212 error = EBUSY;
2213 goto out;
2214 }
2215 /* Done! */
2216 smbfs_attrcache_prune(np);
2217
2218 out:
2219 if (tmpname != NULL)
2220 kmem_free(tmpname, MAXNAMELEN);
2221
2222 if (have_fid)
2223 (void) smbfs_smb_tmpclose(np, fid, scred);
2224 smbfs_rw_exit(&np->r_lkserlock);
2225
2226 if (error == 0) {
2227 /* Keep lookup from finding this node anymore. */
2228 smbfs_rmhash(np);
2229 }
2230
2231 return (error);
2232 }
2233
2234
2235 /*
2236 * XXX
2237 * This op should support the new FIGNORECASE flag for case-insensitive
2238 * lookups, per PSARC 2007/244.
2239 */
2240 /* ARGSUSED */
2241 static int
2242 smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2243 caller_context_t *ct, int flags)
2244 {
2245 struct smb_cred scred;
2246 smbnode_t *odnp = VTOSMB(odvp);
2247 smbnode_t *ndnp = VTOSMB(ndvp);
2248 vnode_t *ovp;
2249 int error;
2250
2251 if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2252 curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
2253 return (EPERM);
2254
2255 if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
2256 VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
2257 odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
2258 ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2259 return (EIO);
2260
2261 if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
2262 strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
2263 return (EINVAL);
2264
2265 /*
2266 * Check that everything is on the same filesystem.
2267 * vn_rename checks the fsid's, but in case we don't
2268 * fill those in correctly, check here too.
2269 */
2270 if (odvp->v_vfsp != ndvp->v_vfsp)
2271 return (EXDEV);
2272
2273 /*
2274 * Need write access on source and target.
2275 * Server takes care of most checks.
2276 */
2277 error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
2278 if (error)
2279 return (error);
2280 if (odvp != ndvp) {
2281 error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
2282 if (error)
2283 return (error);
2284 }
2285
2286 /*
2287 * Need to lock both old/new dirs as writer.
2288 *
2289 * Avoid deadlock here on old vs new directory nodes
2290 * by always taking the locks in order of address.
2291 * The order is arbitrary, but must be consistent.
2292 */
2293 if (odnp < ndnp) {
2294 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2295 SMBINTR(odvp)))
2296 return (EINTR);
2297 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2298 SMBINTR(ndvp))) {
2299 smbfs_rw_exit(&odnp->r_rwlock);
2300 return (EINTR);
2301 }
2302 } else {
2303 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2304 SMBINTR(ndvp)))
2305 return (EINTR);
2306 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2307 SMBINTR(odvp))) {
2308 smbfs_rw_exit(&ndnp->r_rwlock);
2309 return (EINTR);
2310 }
2311 }
2312 smb_credinit(&scred, cr);
2313
2314 /* Lookup the "old" name */
2315 error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
2316 if (error == 0) {
2317 /*
2318 * Do the real rename work
2319 */
2320 error = smbfsrename(odvp, ovp, ndvp, nnm, &scred, flags);
2321 VN_RELE(ovp);
2322 }
2323
2324 smb_credrele(&scred);
2325 smbfs_rw_exit(&odnp->r_rwlock);
2326 smbfs_rw_exit(&ndnp->r_rwlock);
2327
2328 return (error);
2329 }
2330
2331 /*
2332 * smbfsrename does the real work of renaming in SMBFS
2333 * Caller has done dir access checks etc.
2334 */
2335 /* ARGSUSED */
2336 static int
2337 smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
2338 struct smb_cred *scred, int flags)
2339 {
2340 smbnode_t *odnp = VTOSMB(odvp);
2341 smbnode_t *onp = VTOSMB(ovp);
2342 smbnode_t *ndnp = VTOSMB(ndvp);
2343 vnode_t *nvp = NULL;
2344 int error;
2345 int nvp_locked = 0;
2346
2347 /* Things our caller should have checked. */
2348 ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
2349 ASSERT(odvp->v_vfsp == ndvp->v_vfsp);
2350 ASSERT(odnp->r_rwlock.owner == curthread);
2351 ASSERT(ndnp->r_rwlock.owner == curthread);
2352
2353 /*
2354 * Lookup the target file. If it exists, it needs to be
2355 * checked to see whether it is a mount point and whether
2356 * it is active (open).
2357 */
2358 error = smbfslookup(ndvp, nnm, &nvp, scred->scr_cred, 0, NULL);
2359 if (!error) {
2360 /*
2361 * Target (nvp) already exists. Check that it
2362 * has the same type as the source. The server
2363 * will check this also, (and more reliably) but
2364 * this lets us return the correct error codes.
2365 */
2366 if (ovp->v_type == VDIR) {
2367 if (nvp->v_type != VDIR) {
2368 error = ENOTDIR;
2369 goto out;
2370 }
2371 } else {
2372 if (nvp->v_type == VDIR) {
2373 error = EISDIR;
2374 goto out;
2375 }
2376 }
2377
2378 /*
2379 * POSIX dictates that when the source and target
2380 * entries refer to the same file object, rename
2381 * must do nothing and exit without error.
2382 */
2383 if (ovp == nvp) {
2384 error = 0;
2385 goto out;
2386 }
2387
2388 /*
2389 * Also must ensure the target is not a mount point,
2390 * and keep mount/umount away until we're done.
2391 */
2392 if (vn_vfsrlock(nvp)) {
2393 error = EBUSY;
2394 goto out;
2395 }
2396 nvp_locked = 1;
2397 if (vn_mountedvfs(nvp) != NULL) {
2398 error = EBUSY;
2399 goto out;
2400 }
2401
2402 /*
2403 * CIFS may give a SHARING_VIOLATION error when
2404 * trying to rename onto an exising object,
2405 * so try to remove the target first.
2406 * (Only for files, not directories.)
2407 */
2408 if (nvp->v_type == VDIR) {
2409 error = EEXIST;
2410 goto out;
2411 }
2412 error = smbfsremove(ndvp, nvp, scred, flags);
2413 if (error != 0)
2414 goto out;
2415
2416 /*
2417 * OK, removed the target file. Continue as if
2418 * lookup target had failed (nvp == NULL).
2419 */
2420 vn_vfsunlock(nvp);
2421 nvp_locked = 0;
2422 VN_RELE(nvp);
2423 nvp = NULL;
2424 } /* nvp */
2425
2426 smbfs_attrcache_remove(onp);
2427
2428 error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), scred);
2429
2430 /*
2431 * If the old name should no longer exist,
2432 * discard any cached attributes under it.
2433 */
2434 if (error == 0)
2435 smbfs_attrcache_prune(onp);
2436
2437 out:
2438 if (nvp) {
2439 if (nvp_locked)
2440 vn_vfsunlock(nvp);
2441 VN_RELE(nvp);
2442 }
2443
2444 return (error);
2445 }
2446
2447 /*
2448 * XXX
2449 * vsecattr_t is new to build 77, and we need to eventually support
2450 * it in order to create an ACL when an object is created.
2451 *
2452 * This op should support the new FIGNORECASE flag for case-insensitive
2453 * lookups, per PSARC 2007/244.
2454 */
2455 /* ARGSUSED */
2456 static int
2457 smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
2458 cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
2459 {
2460 vnode_t *vp;
2461 struct smbnode *dnp = VTOSMB(dvp);
2462 struct smbmntinfo *smi = VTOSMI(dvp);
2463 struct smb_cred scred;
2464 struct smbfattr fattr;
2465 const char *name = (const char *) nm;
2466 int nmlen = strlen(name);
2467 int error, hiderr;
2468
2469 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2470 return (EPERM);
2471
2472 if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2473 return (EIO);
2474
2475 if ((nmlen == 1 && name[0] == '.') ||
2476 (nmlen == 2 && name[0] == '.' && name[1] == '.'))
2477 return (EEXIST);
2478
2479 /* Only plain files are allowed in V_XATTRDIR. */
2480 if (dvp->v_flag & V_XATTRDIR)
2481 return (EINVAL);
2482
2483 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2484 return (EINTR);
2485 smb_credinit(&scred, cr);
2486
2487 /*
2488 * XXX: Do we need r_lkserlock too?
2489 * No use of any shared fid or fctx...
2490 */
2491
2492 /*
2493 * Require write access in the containing directory.
2494 */
2495 error = smbfs_access(dvp, VWRITE, 0, cr, ct);
2496 if (error)
2497 goto out;
2498
2499 error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
2500 if (error)
2501 goto out;
2502
2503 error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2504 if (error)
2505 goto out;
2506
2507 smbfs_attr_touchdir(dnp);
2508
2509 error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2510 if (error)
2511 goto out;
2512
2513 if (name[0] == '.')
2514 if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
2515 SMBVDEBUG("hide failure %d\n", hiderr);
2516
2517 /* Success! */
2518 *vpp = vp;
2519 error = 0;
2520 out:
2521 smb_credrele(&scred);
2522 smbfs_rw_exit(&dnp->r_rwlock);
2523
2524 if (name != nm)
2525 smbfs_name_free(name, nmlen);
2526
2527 return (error);
2528 }
2529
2530 /*
2531 * XXX
2532 * This op should support the new FIGNORECASE flag for case-insensitive
2533 * lookups, per PSARC 2007/244.
2534 */
2535 /* ARGSUSED */
2536 static int
2537 smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
2538 caller_context_t *ct, int flags)
2539 {
2540 vnode_t *vp = NULL;
2541 int vp_locked = 0;
2542 struct smbmntinfo *smi = VTOSMI(dvp);
2543 struct smbnode *dnp = VTOSMB(dvp);
2544 struct smbnode *np;
2545 struct smb_cred scred;
2546 int error;
2547
2548 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2549 return (EPERM);
2550
2551 if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2552 return (EIO);
2553
2554 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2555 return (EINTR);
2556 smb_credinit(&scred, cr);
2557
2558 /*
2559 * Require w/x access in the containing directory.
2560 * Server handles all other access checks.
2561 */
2562 error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
2563 if (error)
2564 goto out;
2565
2566 /*
2567 * First lookup the entry to be removed.
2568 */
2569 error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2570 if (error)
2571 goto out;
2572 np = VTOSMB(vp);
2573
2574 /*
2575 * Disallow rmdir of "." or current dir, or the FS root.
2576 * Also make sure it's a directory, not a mount point,
2577 * and lock to keep mount/umount away until we're done.
2578 */
2579 if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
2580 error = EINVAL;
2581 goto out;
2582 }
2583 if (vp->v_type != VDIR) {
2584 error = ENOTDIR;
2585 goto out;
2586 }
2587 if (vn_vfsrlock(vp)) {
2588 error = EBUSY;
2589 goto out;
2590 }
2591 vp_locked = 1;
2592 if (vn_mountedvfs(vp) != NULL) {
2593 error = EBUSY;
2594 goto out;
2595 }
2596
2597 smbfs_attrcache_remove(np);
2598 error = smbfs_smb_rmdir(np, &scred);
2599
2600 /*
2601 * Similar to smbfs_remove
2602 */
2603 switch (error) {
2604 case 0:
2605 case ENOENT:
2606 case ENOTDIR:
2607 smbfs_attrcache_prune(np);
2608 break;
2609 }
2610
2611 if (error)
2612 goto out;
2613
2614 mutex_enter(&np->r_statelock);
2615 dnp->n_flag |= NMODIFIED;
2616 mutex_exit(&np->r_statelock);
2617 smbfs_attr_touchdir(dnp);
2618 smbfs_rmhash(np);
2619
2620 out:
2621 if (vp) {
2622 if (vp_locked)
2623 vn_vfsunlock(vp);
2624 VN_RELE(vp);
2625 }
2626 smb_credrele(&scred);
2627 smbfs_rw_exit(&dnp->r_rwlock);
2628
2629 return (error);
2630 }
2631
2632
2633 /* ARGSUSED */
2634 static int
2635 smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
2636 caller_context_t *ct, int flags)
2637 {
2638 struct smbnode *np = VTOSMB(vp);
2639 int error = 0;
2640 smbmntinfo_t *smi;
2641
2642 smi = VTOSMI(vp);
2643
2644 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2645 return (EIO);
2646
2647 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2648 return (EIO);
2649
2650 /*
2651 * Require read access in the directory.
2652 */
2653 error = smbfs_access(vp, VREAD, 0, cr, ct);
2654 if (error)
2655 return (error);
2656
2657 ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
2658
2659 /*
2660 * XXX: Todo readdir cache here
2661 * Note: NFS code is just below this.
2662 *
2663 * I am serializing the entire readdir opreation
2664 * now since we have not yet implemented readdir
2665 * cache. This fix needs to be revisited once
2666 * we implement readdir cache.
2667 */
2668 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2669 return (EINTR);
2670
2671 error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
2672
2673 smbfs_rw_exit(&np->r_lkserlock);
2674
2675 return (error);
2676 }
2677
2678 /* ARGSUSED */
2679 static int
2680 smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
2681 caller_context_t *ct)
2682 {
2683 /*
2684 * Note: "limit" tells the SMB-level FindFirst/FindNext
2685 * functions how many directory entries to request in
2686 * each OtW call. It needs to be large enough so that
2687 * we don't make lots of tiny OtW requests, but there's
2688 * no point making it larger than the maximum number of
2689 * OtW entries that would fit in a maximum sized trans2
2690 * response (64k / 48). Beyond that, it's just tuning.
2691 * WinNT used 512, Win2k used 1366. We use 1000.
2692 */
2693 static const int limit = 1000;
2694 /* Largest possible dirent size. */
2695 static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
2696 struct smb_cred scred;
2697 vnode_t *newvp;
2698 struct smbnode *np = VTOSMB(vp);
2699 struct smbfs_fctx *ctx;
2700 struct dirent64 *dp;
2701 ssize_t save_resid;
2702 offset_t save_offset; /* 64 bits */
2703 int offset; /* yes, 32 bits */
2704 int nmlen, error;
2705 ushort_t reclen;
2706
2707 ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
2708
2709 /* Make sure we serialize for n_dirseq use. */
2710 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
2711
2712 /*
2713 * Make sure smbfs_open filled in n_dirseq
2714 */
2715 if (np->n_dirseq == NULL)
2716 return (EBADF);
2717
2718 /* Check for overflow of (32-bit) directory offset. */
2719 if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
2720 (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
2721 return (EINVAL);
2722
2723 /* Require space for at least one dirent. */
2724 if (uio->uio_resid < dbufsiz)
2725 return (EINVAL);
2726
2727 SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2728 smb_credinit(&scred, cr);
2729 dp = kmem_alloc(dbufsiz, KM_SLEEP);
2730
2731 save_resid = uio->uio_resid;
2732 save_offset = uio->uio_loffset;
2733 offset = uio->uio_offset;
2734 SMBVDEBUG("in: offset=%d, resid=%d\n",
2735 (int)uio->uio_offset, (int)uio->uio_resid);
2736 error = 0;
2737
2738 /*
2739 * Generate the "." and ".." entries here so we can
2740 * (1) make sure they appear (but only once), and
2741 * (2) deal with getting their I numbers which the
2742 * findnext below does only for normal names.
2743 */
2744 while (offset < FIRST_DIROFS) {
2745 /*
2746 * Tricky bit filling in the first two:
2747 * offset 0 is ".", offset 1 is ".."
2748 * so strlen of these is offset+1.
2749 */
2750 reclen = DIRENT64_RECLEN(offset + 1);
2751 if (uio->uio_resid < reclen)
2752 goto out;
2753 bzero(dp, reclen);
2754 dp->d_reclen = reclen;
2755 dp->d_name[0] = '.';
2756 dp->d_name[1] = '.';
2757 dp->d_name[offset + 1] = '\0';
2758 /*
2759 * Want the real I-numbers for the "." and ".."
2760 * entries. For these two names, we know that
2761 * smbfslookup can get the nodes efficiently.
2762 */
2763 error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
2764 if (error) {
2765 dp->d_ino = np->n_ino + offset; /* fiction */
2766 } else {
2767 dp->d_ino = VTOSMB(newvp)->n_ino;
2768 VN_RELE(newvp);
2769 }
2770 /*
2771 * Note: d_off is the offset that a user-level program
2772 * should seek to for reading the NEXT directory entry.
2773 * See libc: readdir, telldir, seekdir
2774 */
2775 dp->d_off = offset + 1;
2776 error = uiomove(dp, reclen, UIO_READ, uio);
2777 if (error)
2778 goto out;
2779 /*
2780 * Note: uiomove updates uio->uio_offset,
2781 * but we want it to be our "cookie" value,
2782 * which just counts dirents ignoring size.
2783 */
2784 uio->uio_offset = ++offset;
2785 }
2786
2787 /*
2788 * If there was a backward seek, we have to reopen.
2789 */
2790 if (offset < np->n_dirofs) {
2791 SMBVDEBUG("Reopening search %d:%d\n",
2792 offset, np->n_dirofs);
2793 error = smbfs_smb_findopen(np, "*", 1,
2794 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2795 &scred, &ctx);
2796 if (error) {
2797 SMBVDEBUG("can not open search, error = %d", error);
2798 goto out;
2799 }
2800 /* free the old one */
2801 (void) smbfs_smb_findclose(np->n_dirseq, &scred);
2802 /* save the new one */
2803 np->n_dirseq = ctx;
2804 np->n_dirofs = FIRST_DIROFS;
2805 } else {
2806 ctx = np->n_dirseq;
2807 }
2808
2809 /*
2810 * Skip entries before the requested offset.
2811 */
2812 while (np->n_dirofs < offset) {
2813 error = smbfs_smb_findnext(ctx, limit, &scred);
2814 if (error != 0)
2815 goto out;
2816 np->n_dirofs++;
2817 }
2818
2819 /*
2820 * While there's room in the caller's buffer:
2821 * get a directory entry from SMB,
2822 * convert to a dirent, copyout.
2823 * We stop when there is no longer room for a
2824 * maximum sized dirent because we must decide
2825 * before we know anything about the next entry.
2826 */
2827 while (uio->uio_resid >= dbufsiz) {
2828 error = smbfs_smb_findnext(ctx, limit, &scred);
2829 if (error != 0)
2830 goto out;
2831 np->n_dirofs++;
2832
2833 /* Sanity check the name length. */
2834 nmlen = ctx->f_nmlen;
2835 if (nmlen > SMB_MAXFNAMELEN) {
2836 nmlen = SMB_MAXFNAMELEN;
2837 SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
2838 }
2839 if (smbfs_fastlookup) {
2840 /* See comment at smbfs_fastlookup above. */
2841 if (smbfs_nget(vp, ctx->f_name, nmlen,
2842 &ctx->f_attr, &newvp) == 0)
2843 VN_RELE(newvp);
2844 }
2845
2846 reclen = DIRENT64_RECLEN(nmlen);
2847 bzero(dp, reclen);
2848 dp->d_reclen = reclen;
2849 bcopy(ctx->f_name, dp->d_name, nmlen);
2850 dp->d_name[nmlen] = '\0';
2851 dp->d_ino = ctx->f_inum;
2852 dp->d_off = offset + 1; /* See d_off comment above */
2853 error = uiomove(dp, reclen, UIO_READ, uio);
2854 if (error)
2855 goto out;
2856 /* See comment re. uio_offset above. */
2857 uio->uio_offset = ++offset;
2858 }
2859
2860 out:
2861 /*
2862 * When we come to the end of a directory, the
2863 * SMB-level functions return ENOENT, but the
2864 * caller is not expecting an error return.
2865 *
2866 * Also note that we must delay the call to
2867 * smbfs_smb_findclose(np->n_dirseq, ...)
2868 * until smbfs_close so that all reads at the
2869 * end of the directory will return no data.
2870 */
2871 if (error == ENOENT) {
2872 error = 0;
2873 if (eofp)
2874 *eofp = 1;
2875 }
2876 /*
2877 * If we encountered an error (i.e. "access denied")
2878 * from the FindFirst call, we will have copied out
2879 * the "." and ".." entries leaving offset == 2.
2880 * In that case, restore the original offset/resid
2881 * so the caller gets no data with the error.
2882 */
2883 if (error != 0 && offset == FIRST_DIROFS) {
2884 uio->uio_loffset = save_offset;
2885 uio->uio_resid = save_resid;
2886 }
2887 SMBVDEBUG("out: offset=%d, resid=%d\n",
2888 (int)uio->uio_offset, (int)uio->uio_resid);
2889
2890 kmem_free(dp, dbufsiz);
2891 smb_credrele(&scred);
2892 return (error);
2893 }
2894
2895
2896 /*
2897 * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
2898 * are optional functions that are called by:
2899 * getdents, before/after VOP_READDIR
2900 * pread, before/after ... VOP_READ
2901 * pwrite, before/after ... VOP_WRITE
2902 * (other places)
2903 *
2904 * Careful here: None of the above check for any
2905 * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
2906 * In fact, the return value from _rwlock is NOT
2907 * an error code, but V_WRITELOCK_TRUE / _FALSE.
2908 *
2909 * Therefore, it's up to _this_ code to make sure
2910 * the lock state remains balanced, which means
2911 * we can't "bail out" on interrupts, etc.
2912 */
2913
2914 /* ARGSUSED2 */
2915 static int
2916 smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2917 {
2918 smbnode_t *np = VTOSMB(vp);
2919
2920 if (!write_lock) {
2921 (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
2922 return (V_WRITELOCK_FALSE);
2923 }
2924
2925
2926 (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
2927 return (V_WRITELOCK_TRUE);
2928 }
2929
2930 /* ARGSUSED */
2931 static void
2932 smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2933 {
2934 smbnode_t *np = VTOSMB(vp);
2935
2936 smbfs_rw_exit(&np->r_rwlock);
2937 }
2938
2939
2940 /* ARGSUSED */
2941 static int
2942 smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2943 {
2944 smbmntinfo_t *smi;
2945
2946 smi = VTOSMI(vp);
2947
2948 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2949 return (EPERM);
2950
2951 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2952 return (EIO);
2953
2954 /*
2955 * Because we stuff the readdir cookie into the offset field
2956 * someone may attempt to do an lseek with the cookie which
2957 * we want to succeed.
2958 */
2959 if (vp->v_type == VDIR)
2960 return (0);
2961
2962 /* Like NFS3, just check for 63-bit overflow. */
2963 if (*noffp < 0)
2964 return (EINVAL);
2965
2966 return (0);
2967 }
2968
2969
2970 /*
2971 * XXX
2972 * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
2973 */
2974 static int
2975 smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2976 offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2977 caller_context_t *ct)
2978 {
2979 if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
2980 return (EIO);
2981
2982 if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2983 return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2984 else
2985 return (ENOSYS);
2986 }
2987
2988 /*
2989 * Free storage space associated with the specified vnode. The portion
2990 * to be freed is specified by bfp->l_start and bfp->l_len (already
2991 * normalized to a "whence" of 0).
2992 *
2993 * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
2994 */
2995 /* ARGSUSED */
2996 static int
2997 smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2998 offset_t offset, cred_t *cr, caller_context_t *ct)
2999 {
3000 int error;
3001 smbmntinfo_t *smi;
3002
3003 smi = VTOSMI(vp);
3004
3005 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3006 return (EIO);
3007
3008 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
3009 return (EIO);
3010
3011 /* Caller (fcntl) has checked v_type */
3012 ASSERT(vp->v_type == VREG);
3013 if (cmd != F_FREESP)
3014 return (EINVAL);
3015
3016 /*
3017 * Like NFS3, no 32-bit offset checks here.
3018 * Our SMB layer takes care to return EFBIG
3019 * when it has to fallback to a 32-bit call.
3020 */
3021
3022 error = convoff(vp, bfp, 0, offset);
3023 if (!error) {
3024 ASSERT(bfp->l_start >= 0);
3025 if (bfp->l_len == 0) {
3026 struct vattr va;
3027
3028 /*
3029 * ftruncate should not change the ctime and
3030 * mtime if we truncate the file to its
3031 * previous size.
3032 */
3033 va.va_mask = AT_SIZE;
3034 error = smbfsgetattr(vp, &va, cr);
3035 if (error || va.va_size == bfp->l_start)
3036 return (error);
3037 va.va_mask = AT_SIZE;
3038 va.va_size = bfp->l_start;
3039 error = smbfssetattr(vp, &va, 0, cr);
3040 } else
3041 error = EINVAL;
3042 }
3043
3044 return (error);
3045 }
3046
3047 /* ARGSUSED */
3048 static int
3049 smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
3050 caller_context_t *ct)
3051 {
3052 vfs_t *vfs;
3053 smbmntinfo_t *smi;
3054 struct smb_share *ssp;
3055
3056 vfs = vp->v_vfsp;
3057 smi = VFTOSMI(vfs);
3058
3059 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3060 return (EIO);
3061
3062 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
3063 return (EIO);
3064
3065 switch (cmd) {
3066 case _PC_FILESIZEBITS:
3067 ssp = smi->smi_share;
3068 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
3069 *valp = 64;
3070 else
3071 *valp = 32;
3072 break;
3073
3074 case _PC_LINK_MAX:
3075 /* We only ever report one link to an object */
3076 *valp = 1;
3077 break;
3078
3079 case _PC_ACL_ENABLED:
3080 /*
3081 * Always indicate that ACLs are enabled and
3082 * that we support ACE_T format, otherwise
3083 * libsec will ask for ACLENT_T format data
3084 * which we don't support.
3085 */
3086 *valp = _ACL_ACE_ENABLED;
3087 break;
3088
3089 case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */
3090 *valp = 0;
3091 break;
3092
3093 case _PC_XATTR_EXISTS:
3094 if (vfs->vfs_flag & VFS_XATTR) {
3095 *valp = smbfs_xa_exists(vp, cr);
3096 break;
3097 }
3098 return (EINVAL);
3099
3100 case _PC_SATTR_ENABLED:
3101 case _PC_SATTR_EXISTS:
3102 *valp = 1;
3103 break;
3104
3105 case _PC_TIMESTAMP_RESOLUTION:
3106 /*
3107 * Windows times are tenths of microseconds
3108 * (multiples of 100 nanoseconds).
3109 */
3110 *valp = 100L;
3111 break;
3112
3113 default:
3114 return (fs_pathconf(vp, cmd, valp, cr, ct));
3115 }
3116 return (0);
3117 }
3118
3119 /* ARGSUSED */
3120 static int
3121 smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3122 caller_context_t *ct)
3123 {
3124 vfs_t *vfsp;
3125 smbmntinfo_t *smi;
3126 int error;
3127 uint_t mask;
3128
3129 vfsp = vp->v_vfsp;
3130 smi = VFTOSMI(vfsp);
3131
3132 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3133 return (EIO);
3134
3135 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3136 return (EIO);
3137
3138 /*
3139 * Our _pathconf indicates _ACL_ACE_ENABLED,
3140 * so we should only see VSA_ACE, etc here.
3141 * Note: vn_create asks for VSA_DFACLCNT,
3142 * and it expects ENOSYS and empty data.
3143 */
3144 mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
3145 VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
3146 if (mask == 0)
3147 return (ENOSYS);
3148
3149 if (smi->smi_flags & SMI_ACL)
3150 error = smbfs_acl_getvsa(vp, vsa, flag, cr);
3151 else
3152 error = ENOSYS;
3153
3154 if (error == ENOSYS)
3155 error = fs_fab_acl(vp, vsa, flag, cr, ct);
3156
3157 return (error);
3158 }
3159
3160 /* ARGSUSED */
3161 static int
3162 smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3163 caller_context_t *ct)
3164 {
3165 vfs_t *vfsp;
3166 smbmntinfo_t *smi;
3167 int error;
3168 uint_t mask;
3169
3170 vfsp = vp->v_vfsp;
3171 smi = VFTOSMI(vfsp);
3172
3173 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3174 return (EIO);
3175
3176 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3177 return (EIO);
3178
3179 /*
3180 * Our _pathconf indicates _ACL_ACE_ENABLED,
3181 * so we should only see VSA_ACE, etc here.
3182 */
3183 mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
3184 if (mask == 0)
3185 return (ENOSYS);
3186
3187 if (vfsp->vfs_flag & VFS_RDONLY)
3188 return (EROFS);
3189
3190 /*
3191 * Allow only the mount owner to do this.
3192 * See comments at smbfs_access_rwx.
3193 */
3194 error = secpolicy_vnode_setdac(cr, smi->smi_uid);
3195 if (error != 0)
3196 return (error);
3197
3198 if (smi->smi_flags & SMI_ACL)
3199 error = smbfs_acl_setvsa(vp, vsa, flag, cr);
3200 else
3201 error = ENOSYS;
3202
3203 return (error);
3204 }
3205
3206
3207 /*
3208 * XXX
3209 * This op should eventually support PSARC 2007/268.
3210 */
3211 static int
3212 smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
3213 caller_context_t *ct)
3214 {
3215 if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3216 return (EIO);
3217
3218 if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3219 return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3220 else
3221 return (ENOSYS);
3222 }