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