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_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $
33 */
34
35 /*
36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
37 * Use is subject to license terms.
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/time.h>
43 #include <sys/vnode.h>
44 #include <sys/sunddi.h>
45 #include <sys/cmn_err.h>
46
47 #include <netsmb/smb_osdep.h>
48
49 #include <netsmb/smb.h>
50 #include <netsmb/smb_conn.h>
51 #include <netsmb/smb_subr.h>
52 #include <netsmb/smb_rq.h>
53
54 #include <smbfs/smbfs.h>
55 #include <smbfs/smbfs_node.h>
56 #include <smbfs/smbfs_subr.h>
57
58 /*
59 * Jan 1 1980 as 64 bit NT time.
60 * (tenths of microseconds since 1601)
61 */
62 const uint64_t NT1980 = 11960035200ULL*10000000ULL;
63
64 /*
65 * Local functions.
66 * Not static, to aid debugging.
67 */
68
69 int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
70 struct smbfattr *fap, struct smb_cred *scrp);
71 int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
72 struct smb_cred *scrp, uint16_t infolevel);
73
74 int smbfs_smb_statfsLM1(struct smb_share *ssp,
75 statvfs64_t *sbp, struct smb_cred *scrp);
76 int smbfs_smb_statfsLM2(struct smb_share *ssp,
77 statvfs64_t *sbp, struct smb_cred *scrp);
78
79 int smbfs_smb_setfattrNT(struct smbnode *np, int fid,
80 uint32_t attr, struct timespec *mtime, struct timespec *atime,
81 struct smb_cred *scrp);
82
83 int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
84 struct timespec *mtime, struct timespec *atime,
85 struct smb_cred *scrp);
86
87 int smbfs_smb_setpattr1(struct smbnode *np,
88 const char *name, int len, uint32_t attr,
89 struct timespec *mtime, struct smb_cred *scrp);
90
91
92 /*
93 * Todo: locking over-the-wire
94 */
95 #ifdef APPLE
96
97 static int
smbfs_smb_lockandx(struct smbnode * np,int op,uint32_t pid,offset_t start,uint64_t len,int largelock,struct smb_cred * scrp,uint32_t timeout)98 smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
99 offset_t start, uint64_t len, int largelock,
100 struct smb_cred *scrp, uint32_t timeout)
101 {
102 struct smb_share *ssp = np->n_mount->smi_share;
103 struct smb_rq rq, *rqp = &rq;
104 struct mbchain *mbp;
105 uint8_t ltype = 0;
106 int error;
107
108 /* Shared lock for n_fid use below. */
109 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
110
111 /* After reconnect, n_fid is invalid */
112 if (np->n_vcgenid != ssp->ss_vcgenid)
113 return (ESTALE);
114
115 if (op == SMB_LOCK_SHARED)
116 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
117 /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
118 if (largelock)
119 ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
120 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
121 if (error)
122 return (error);
123 smb_rq_getrequest(rqp, &mbp);
124 smb_rq_wstart(rqp);
125 mb_put_uint8(mbp, 0xff); /* secondary command */
126 mb_put_uint8(mbp, 0); /* MBZ */
127 mb_put_uint16le(mbp, 0);
128 mb_put_uint16le(mbp, np->n_fid);
129 mb_put_uint8(mbp, ltype); /* locktype */
130 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
131 mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
132 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
133 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
134 smb_rq_wend(rqp);
135 smb_rq_bstart(rqp);
136 mb_put_uint16le(mbp, pid);
137 if (!largelock) {
138 mb_put_uint32le(mbp, start);
139 mb_put_uint32le(mbp, len);
140 } else {
141 mb_put_uint16le(mbp, 0); /* pad */
142 mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
143 mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
144 mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
145 mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
146 }
147 smb_rq_bend(rqp);
148 /*
149 * Don't want to risk missing a successful
150 * unlock send or lock response, or we could
151 * lose track of an outstanding lock.
152 */
153 if (op == SMB_LOCK_RELEASE)
154 rqp->sr_flags |= SMBR_NOINTR_SEND;
155 else
156 rqp->sr_flags |= SMBR_NOINTR_RECV;
157
158 error = smb_rq_simple(rqp);
159 smb_rq_done(rqp);
160 return (error);
161 }
162
163 int
smbfs_smb_lock(struct smbnode * np,int op,caddr_t id,offset_t start,uint64_t len,int largelock,struct smb_cred * scrp,uint32_t timeout)164 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
165 offset_t start, uint64_t len, int largelock,
166 struct smb_cred *scrp, uint32_t timeout)
167 {
168 struct smb_share *ssp = np->n_mount->smi_share;
169
170 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
171 /*
172 * TODO: use LOCK_BYTE_RANGE here.
173 */
174 return (EINVAL);
175
176 /*
177 * XXX: compute largelock via:
178 * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)?
179 */
180 return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
181 largelock, scrp, timeout));
182 }
183
184 #endif /* APPLE */
185
186 /*
187 * Helper for smbfs_getattr
188 * Something like nfs_getattr_otw
189 */
190 int
smbfs_smb_getfattr(struct smbnode * np,struct smbfattr * fap,struct smb_cred * scrp)191 smbfs_smb_getfattr(
192 struct smbnode *np,
193 struct smbfattr *fap,
194 struct smb_cred *scrp)
195 {
196 int error;
197
198 /*
199 * This lock is necessary for FID-based calls.
200 * Lock may be writer (via open) or reader.
201 */
202 ASSERT(np->r_lkserlock.count != 0);
203
204 /*
205 * Extended attribute directory or file.
206 */
207 if (np->n_flag & N_XATTR) {
208 error = smbfs_xa_getfattr(np, fap, scrp);
209 return (error);
210 }
211
212 error = smbfs_smb_trans2_query(np, fap, scrp, 0);
213 if (error != EINVAL)
214 return (error);
215
216 /* fallback */
217 error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
218
219 return (error);
220 }
221
222 /*
223 * Common function for QueryFileInfo, QueryPathInfo.
224 */
225 int
smbfs_smb_trans2_query(struct smbnode * np,struct smbfattr * fap,struct smb_cred * scrp,uint16_t infolevel)226 smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
227 struct smb_cred *scrp, uint16_t infolevel)
228 {
229 struct smb_share *ssp = np->n_mount->smi_share;
230 struct smb_vc *vcp = SSTOVC(ssp);
231 struct smb_t2rq *t2p;
232 int error, svtz, timesok = 1;
233 struct mbchain *mbp;
234 struct mdchain *mdp;
235 uint16_t cmd, date, time, wattr;
236 uint64_t llongint, lsize;
237 uint32_t size, dattr;
238
239 /*
240 * Shared lock for n_fid use below.
241 * See smbfs_smb_getfattr()
242 */
243 ASSERT(np->r_lkserlock.count != 0);
244
245 /*
246 * If we have a valid open FID, use it.
247 */
248 if ((np->n_fidrefs > 0) &&
249 (np->n_fid != SMB_FID_UNUSED) &&
250 (np->n_vcgenid == ssp->ss_vcgenid))
251 cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
252 else
253 cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
254
255 top:
256 error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
257 if (error)
258 return (error);
259 mbp = &t2p->t2_tparam;
260 mb_init(mbp);
261 if (!infolevel) {
262 if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
263 infolevel = SMB_QFILEINFO_STANDARD;
264 else
265 infolevel = SMB_QFILEINFO_ALL_INFO;
266 }
267
268 if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
269 mb_put_uint16le(mbp, np->n_fid);
270
271 mb_put_uint16le(mbp, infolevel);
272
273 if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
274 mb_put_uint32le(mbp, 0);
275 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
276 error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
277 if (error) {
278 smb_t2_done(t2p);
279 return (error);
280 }
281 }
282
283 t2p->t2_maxpcount = 2;
284 t2p->t2_maxdcount = vcp->vc_txmax;
285 error = smb_t2_request(t2p);
286 if (error) {
287 smb_t2_done(t2p);
288 /* Invalid info level? Try fallback. */
289 if (error == EINVAL &&
290 infolevel == SMB_QFILEINFO_ALL_INFO) {
291 infolevel = SMB_QFILEINFO_STANDARD;
292 goto top;
293 }
294 return (error);
295 }
296 mdp = &t2p->t2_rdata;
297 svtz = vcp->vc_sopt.sv_tz;
298 switch (infolevel) {
299 case SMB_QFILEINFO_STANDARD:
300 md_get_uint16le(mdp, &date);
301 md_get_uint16le(mdp, &time); /* creation time */
302 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime);
303 md_get_uint16le(mdp, &date);
304 md_get_uint16le(mdp, &time); /* access time */
305 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
306 md_get_uint16le(mdp, &date);
307 md_get_uint16le(mdp, &time); /* modify time */
308 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
309 md_get_uint32le(mdp, &size); /* EOF position */
310 fap->fa_size = size;
311 md_get_uint32le(mdp, &size); /* allocation size */
312 fap->fa_allocsz = size;
313 error = md_get_uint16le(mdp, &wattr);
314 fap->fa_attr = wattr;
315 timesok = 1;
316 break;
317 case SMB_QFILEINFO_ALL_INFO:
318 timesok = 0;
319 /* creation time */
320 md_get_uint64le(mdp, &llongint);
321 if (llongint)
322 timesok++;
323 smb_time_NT2local(llongint, &fap->fa_createtime);
324
325 /* last access time */
326 md_get_uint64le(mdp, &llongint);
327 if (llongint)
328 timesok++;
329 smb_time_NT2local(llongint, &fap->fa_atime);
330
331 /* last write time */
332 md_get_uint64le(mdp, &llongint);
333 if (llongint)
334 timesok++;
335 smb_time_NT2local(llongint, &fap->fa_mtime);
336
337 /* last change time */
338 md_get_uint64le(mdp, &llongint);
339 if (llongint)
340 timesok++;
341 smb_time_NT2local(llongint, &fap->fa_ctime);
342
343 /* attributes */
344 md_get_uint32le(mdp, &dattr);
345 fap->fa_attr = dattr;
346
347 /*
348 * 4-Byte alignment - discard
349 * Specs don't talk about this.
350 */
351 md_get_uint32le(mdp, NULL);
352 /* allocation size */
353 md_get_uint64le(mdp, &lsize);
354 fap->fa_allocsz = lsize;
355 /* File size */
356 error = md_get_uint64le(mdp, &lsize);
357 fap->fa_size = lsize;
358 break;
359 default:
360 SMBVDEBUG("unexpected info level %d\n", infolevel);
361 error = EINVAL;
362 }
363 smb_t2_done(t2p);
364 /*
365 * if all times are zero (observed with FAT on NT4SP6)
366 * then fall back to older info level
367 */
368 if (!timesok) {
369 if (infolevel == SMB_QFILEINFO_ALL_INFO) {
370 infolevel = SMB_QFILEINFO_STANDARD;
371 goto top;
372 }
373 error = EINVAL;
374 }
375 return (error);
376 }
377
378 /*
379 * Support functions for _qstreaminfo
380 * Moved to smbfs_xattr.c
381 */
382
383 int
smbfs_smb_qfsattr(struct smb_share * ssp,struct smb_fs_attr_info * fsa,struct smb_cred * scrp)384 smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
385 struct smb_cred *scrp)
386 {
387 struct smb_t2rq *t2p;
388 struct mbchain *mbp;
389 struct mdchain *mdp;
390 int error;
391 uint32_t nlen;
392
393 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
394 scrp, &t2p);
395 if (error)
396 return (error);
397 mbp = &t2p->t2_tparam;
398 mb_init(mbp);
399 mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
400 t2p->t2_maxpcount = 4;
401 t2p->t2_maxdcount = 4 * 3 + 512;
402 error = smb_t2_request(t2p);
403 if (error)
404 goto out;
405
406 mdp = &t2p->t2_rdata;
407 md_get_uint32le(mdp, &fsa->fsa_aflags);
408 md_get_uint32le(mdp, &fsa->fsa_maxname);
409 error = md_get_uint32le(mdp, &nlen); /* fs name length */
410 if (error)
411 goto out;
412
413 /*
414 * Get the FS type name.
415 */
416 bzero(fsa->fsa_tname, FSTYPSZ);
417 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
418 uint16_t tmpbuf[FSTYPSZ];
419 size_t tmplen, outlen;
420
421 if (nlen > sizeof (tmpbuf))
422 nlen = sizeof (tmpbuf);
423 error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
424 tmplen = nlen / 2; /* UCS-2 chars */
425 outlen = FSTYPSZ - 1;
426 (void) uconv_u16tou8(tmpbuf, &tmplen,
427 (uchar_t *)fsa->fsa_tname, &outlen,
428 UCONV_IN_LITTLE_ENDIAN);
429 } else {
430 if (nlen > (FSTYPSZ - 1))
431 nlen = FSTYPSZ - 1;
432 error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
433 }
434
435 /*
436 * If fs_name starts with FAT, we can't set dates before 1980
437 */
438 if (0 == strncmp(fsa->fsa_tname, "FAT", 3)) {
439 SMB_SS_LOCK(ssp);
440 ssp->ss_flags |= SMBS_FST_FAT;
441 SMB_SS_UNLOCK(ssp);
442 }
443
444 out:
445 smb_t2_done(t2p);
446 return (0);
447 }
448
449 int
smbfs_smb_statfs(struct smb_share * ssp,statvfs64_t * sbp,struct smb_cred * scp)450 smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
451 struct smb_cred *scp)
452 {
453 int error;
454
455 if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
456 error = smbfs_smb_statfsLM2(ssp, sbp, scp);
457 else
458 error = smbfs_smb_statfsLM1(ssp, sbp, scp);
459
460 return (error);
461 }
462
463 int
smbfs_smb_statfsLM2(struct smb_share * ssp,statvfs64_t * sbp,struct smb_cred * scrp)464 smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
465 struct smb_cred *scrp)
466 {
467 struct smb_t2rq *t2p;
468 struct mbchain *mbp;
469 struct mdchain *mdp;
470 uint16_t bsize;
471 uint32_t units, bpu, funits;
472 uint64_t s, t, f;
473 int error;
474
475 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
476 scrp, &t2p);
477 if (error)
478 return (error);
479 mbp = &t2p->t2_tparam;
480 mb_init(mbp);
481 mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
482 t2p->t2_maxpcount = 4;
483 t2p->t2_maxdcount = 4 * 4 + 2;
484 error = smb_t2_request(t2p);
485 if (error)
486 goto out;
487
488 mdp = &t2p->t2_rdata;
489 md_get_uint32le(mdp, NULL); /* fs id */
490 md_get_uint32le(mdp, &bpu);
491 md_get_uint32le(mdp, &units);
492 md_get_uint32le(mdp, &funits);
493 error = md_get_uint16le(mdp, &bsize);
494 if (error)
495 goto out;
496 s = bsize;
497 s *= bpu;
498 t = units;
499 f = funits;
500 /*
501 * Don't allow over-large blocksizes as they determine
502 * Finder List-view size granularities. On the other
503 * hand, we mustn't let the block count overflow the
504 * 31 bits available.
505 */
506 while (s > 16 * 1024) {
507 if (t > LONG_MAX)
508 break;
509 s /= 2;
510 t *= 2;
511 f *= 2;
512 }
513 while (t > LONG_MAX) {
514 t /= 2;
515 f /= 2;
516 s *= 2;
517 }
518 sbp->f_bsize = (ulong_t)s; /* file system block size */
519 sbp->f_blocks = t; /* total data blocks in file system */
520 sbp->f_bfree = f; /* free blocks in fs */
521 sbp->f_bavail = f; /* free blocks avail to non-superuser */
522 sbp->f_files = (-1); /* total file nodes in file system */
523 sbp->f_ffree = (-1); /* free file nodes in fs */
524
525 out:
526 smb_t2_done(t2p);
527 return (0);
528 }
529
530 int
smbfs_smb_statfsLM1(struct smb_share * ssp,statvfs64_t * sbp,struct smb_cred * scrp)531 smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
532 struct smb_cred *scrp)
533 {
534 struct smb_rq rq, *rqp = &rq;
535 struct mdchain *mdp;
536 uint16_t units, bpu, bsize, funits;
537 uint64_t s, t, f;
538 int error;
539
540 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
541 scrp);
542 if (error)
543 return (error);
544 smb_rq_wstart(rqp);
545 smb_rq_wend(rqp);
546 smb_rq_bstart(rqp);
547 smb_rq_bend(rqp);
548 error = smb_rq_simple(rqp);
549 if (error)
550 goto out;
551
552 smb_rq_getreply(rqp, &mdp);
553 md_get_uint16le(mdp, &units);
554 md_get_uint16le(mdp, &bpu);
555 md_get_uint16le(mdp, &bsize);
556 error = md_get_uint16le(mdp, &funits);
557 if (error)
558 goto out;
559 s = bsize;
560 s *= bpu;
561 t = units;
562 f = funits;
563 /*
564 * Don't allow over-large blocksizes as they determine
565 * Finder List-view size granularities. On the other
566 * hand, we mustn't let the block count overflow the
567 * 31 bits available.
568 */
569 while (s > 16 * 1024) {
570 if (t > LONG_MAX)
571 break;
572 s /= 2;
573 t *= 2;
574 f *= 2;
575 }
576 while (t > LONG_MAX) {
577 t /= 2;
578 f /= 2;
579 s *= 2;
580 }
581 sbp->f_bsize = (ulong_t)s; /* file system block size */
582 sbp->f_blocks = t; /* total data blocks in file system */
583 sbp->f_bfree = f; /* free blocks in fs */
584 sbp->f_bavail = f; /* free blocks avail to non-superuser */
585 sbp->f_files = (-1); /* total file nodes in file system */
586 sbp->f_ffree = (-1); /* free file nodes in fs */
587
588 out:
589 smb_rq_done(rqp);
590 return (0);
591 }
592
593 int
smbfs_smb_seteof(struct smb_share * ssp,uint16_t fid,uint64_t newsize,struct smb_cred * scrp)594 smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
595 struct smb_cred *scrp)
596 {
597 struct smb_t2rq *t2p;
598 struct smb_vc *vcp = SSTOVC(ssp);
599 struct mbchain *mbp;
600 int error;
601
602 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
603 scrp, &t2p);
604 if (error)
605 return (error);
606 mbp = &t2p->t2_tparam;
607 mb_init(mbp);
608 mb_put_uint16le(mbp, fid);
609 if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
610 mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
611 else
612 mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
613 mb_put_uint16le(mbp, 0); /* pad */
614 mbp = &t2p->t2_tdata;
615 mb_init(mbp);
616 mb_put_uint64le(mbp, newsize);
617 t2p->t2_maxpcount = 2;
618 t2p->t2_maxdcount = 0;
619 error = smb_t2_request(t2p);
620 smb_t2_done(t2p);
621 return (error);
622 }
623
624 /*ARGSUSED*/
625 int
smbfs_smb_t2rename(struct smbnode * np,struct smbnode * tdnp,const char * tname,int tnmlen,struct smb_cred * scrp,int overwrite)626 smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
627 const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite)
628 {
629 struct smb_t2rq *t2p;
630 struct smb_share *ssp = np->n_mount->smi_share;
631 struct smb_vc *vcp = SSTOVC(ssp);
632 struct mbchain *mbp;
633 int32_t *ucslenp;
634 int error, cerror;
635 uint16_t fid = 0;
636
637 /* Shared lock for n_fid use below. */
638 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
639
640 /* After reconnect, n_fid is invalid */
641 if (np->n_vcgenid != ssp->ss_vcgenid)
642 return (ESTALE);
643
644 if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
645 return (ENOTSUP);
646 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
647 scrp, &t2p);
648 if (error)
649 return (error);
650 if (tdnp) {
651 error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp,
652 &fid);
653 if (error)
654 goto exit;
655 }
656 mbp = &t2p->t2_tparam;
657 mb_init(mbp);
658 mb_put_uint16le(mbp, np->n_fid);
659 mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
660 mb_put_uint16le(mbp, 0); /* reserved, nowadays */
661 mbp = &t2p->t2_tdata;
662 mb_init(mbp);
663 mb_put_uint32le(mbp, overwrite);
664 mb_put_uint16le(mbp, fid); /* base for tname */
665 mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */
666 ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
667 mbp->mb_count = 0;
668 error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE);
669 if (error)
670 goto exit;
671 mbp->mb_count--; /* don't count the null */
672 *ucslenp = htolel(mbp->mb_count);
673 t2p->t2_maxpcount = 2;
674 t2p->t2_maxdcount = 0;
675 error = smb_t2_request(t2p);
676 exit:
677 if (fid) {
678 cerror = smbfs_smb_tmpclose(tdnp, fid, scrp);
679 if (cerror)
680 SMBVDEBUG("error %d closing %s\n",
681 cerror, tdnp->n_rpath);
682 }
683 smb_t2_done(t2p);
684 return (error);
685 }
686
687 int
smbfs_smb_flush(struct smbnode * np,struct smb_cred * scrp)688 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
689 {
690 struct smb_share *ssp = np->n_mount->smi_share;
691 struct smb_rq rq, *rqp = &rq;
692 struct mbchain *mbp;
693 int error;
694
695 /* Shared lock for n_fid use below. */
696 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
697
698 if (!(np->n_flag & NFLUSHWIRE))
699 return (0);
700 if (np->n_fidrefs == 0)
701 return (0); /* not open */
702
703 /* After reconnect, n_fid is invalid */
704 if (np->n_vcgenid != ssp->ss_vcgenid)
705 return (ESTALE);
706
707 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
708 if (error)
709 return (error);
710 smb_rq_getrequest(rqp, &mbp);
711 smb_rq_wstart(rqp);
712 mb_put_uint16le(mbp, np->n_fid);
713 smb_rq_wend(rqp);
714 smb_rq_bstart(rqp);
715 smb_rq_bend(rqp);
716 error = smb_rq_simple(rqp);
717 smb_rq_done(rqp);
718 if (!error) {
719 mutex_enter(&np->r_statelock);
720 np->n_flag &= ~NFLUSHWIRE;
721 mutex_exit(&np->r_statelock);
722 }
723 return (error);
724 }
725
726 int
smbfs_smb_setfsize(struct smbnode * np,uint16_t fid,uint64_t newsize,struct smb_cred * scrp)727 smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
728 struct smb_cred *scrp)
729 {
730 struct smb_share *ssp = np->n_mount->smi_share;
731 struct smb_rq rq, *rqp = &rq;
732 struct mbchain *mbp;
733 int error;
734
735 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
736 /*
737 * This call knows about 64-bit offsets.
738 */
739 error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
740 if (!error) {
741 mutex_enter(&np->r_statelock);
742 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
743 mutex_exit(&np->r_statelock);
744 return (0);
745 }
746 }
747
748 /*
749 * OK, so fallback to SMB_COM_WRITE, but note:
750 * it only supports 32-bit file offsets.
751 */
752 if (newsize > UINT32_MAX)
753 return (EFBIG);
754
755 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
756 if (error)
757 return (error);
758 smb_rq_getrequest(rqp, &mbp);
759 smb_rq_wstart(rqp);
760 mb_put_uint16le(mbp, fid);
761 mb_put_uint16le(mbp, 0);
762 mb_put_uint32le(mbp, newsize);
763 mb_put_uint16le(mbp, 0);
764 smb_rq_wend(rqp);
765 smb_rq_bstart(rqp);
766 mb_put_uint8(mbp, SMB_DT_DATA);
767 mb_put_uint16le(mbp, 0);
768 smb_rq_bend(rqp);
769 error = smb_rq_simple(rqp);
770 smb_rq_done(rqp);
771 mutex_enter(&np->r_statelock);
772 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
773 mutex_exit(&np->r_statelock);
774 return (error);
775 }
776
777 /*
778 * Old method for getting file attributes.
779 */
780 int
smbfs_smb_query_info(struct smbnode * np,const char * name,int nmlen,struct smbfattr * fap,struct smb_cred * scrp)781 smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
782 struct smbfattr *fap, struct smb_cred *scrp)
783 {
784 struct smb_rq rq, *rqp = &rq;
785 struct smb_share *ssp = np->n_mount->smi_share;
786 struct mbchain *mbp;
787 struct mdchain *mdp;
788 uint8_t wc;
789 int error;
790 uint16_t wattr;
791 uint32_t longint;
792
793 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
794 if (error)
795 return (error);
796 smb_rq_getrequest(rqp, &mbp);
797 smb_rq_wstart(rqp);
798 smb_rq_wend(rqp);
799 smb_rq_bstart(rqp);
800 mb_put_uint8(mbp, SMB_DT_ASCII);
801
802 error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
803 name, &nmlen, '\\');
804 if (error)
805 goto out;
806 smb_rq_bend(rqp);
807 error = smb_rq_simple(rqp);
808 if (error)
809 goto out;
810 smb_rq_getreply(rqp, &mdp);
811 error = md_get_uint8(mdp, &wc);
812 if (error)
813 goto out;
814 if (wc != 10) {
815 error = EBADRPC;
816 goto out;
817 }
818 md_get_uint16le(mdp, &wattr);
819 fap->fa_attr = wattr;
820 /*
821 * Be careful using the time returned here, as
822 * with FAT on NT4SP6, at least, the time returned is low
823 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
824 * over about every seven minutes!
825 */
826 md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
827 smb_time_server2local(longint,
828 SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
829 error = md_get_uint32le(mdp, &longint);
830 fap->fa_size = longint;
831
832 out:
833 smb_rq_done(rqp);
834 return (error);
835 }
836
837 /*
838 * Set DOS file attributes. mtime should be NULL for dialects above lm10
839 */
840 int
smbfs_smb_setpattr1(struct smbnode * np,const char * name,int len,uint32_t attr,struct timespec * mtime,struct smb_cred * scrp)841 smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
842 uint32_t attr, struct timespec *mtime,
843 struct smb_cred *scrp)
844 {
845 struct smb_rq rq, *rqp = &rq;
846 struct smb_share *ssp = np->n_mount->smi_share;
847 struct mbchain *mbp;
848 long time;
849 int error, svtz;
850
851 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
852 if (error)
853 return (error);
854 svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
855 smb_rq_getrequest(rqp, &mbp);
856 smb_rq_wstart(rqp);
857 mb_put_uint16le(mbp, (uint16_t)attr);
858 if (mtime) {
859 smb_time_local2server(mtime, svtz, &time);
860 } else
861 time = 0;
862 mb_put_uint32le(mbp, time); /* mtime */
863 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
864 smb_rq_wend(rqp);
865 smb_rq_bstart(rqp);
866 mb_put_uint8(mbp, SMB_DT_ASCII);
867
868 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\');
869 if (error)
870 goto out;
871 mb_put_uint8(mbp, SMB_DT_ASCII);
872 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
873 mb_put_padbyte(mbp);
874 mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
875 }
876 mb_put_uint8(mbp, 0);
877 smb_rq_bend(rqp);
878 error = smb_rq_simple(rqp);
879
880 out:
881 smb_rq_done(rqp);
882 return (error);
883 }
884
885 int
smbfs_smb_hideit(struct smbnode * np,const char * name,int len,struct smb_cred * scrp)886 smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
887 struct smb_cred *scrp)
888 {
889 struct smbfattr fa;
890 int error;
891 uint32_t attr;
892
893 error = smbfs_smb_query_info(np, name, len, &fa, scrp);
894 attr = fa.fa_attr;
895 if (!error && !(attr & SMB_FA_HIDDEN)) {
896 attr |= SMB_FA_HIDDEN;
897 error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
898 }
899 return (error);
900 }
901
902
903 int
smbfs_smb_unhideit(struct smbnode * np,const char * name,int len,struct smb_cred * scrp)904 smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
905 struct smb_cred *scrp)
906 {
907 struct smbfattr fa;
908 uint32_t attr;
909 int error;
910
911 error = smbfs_smb_query_info(np, name, len, &fa, scrp);
912 attr = fa.fa_attr;
913 if (!error && (attr & SMB_FA_HIDDEN)) {
914 attr &= ~SMB_FA_HIDDEN;
915 error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
916 }
917 return (error);
918 }
919
920 /*
921 * Set file attributes (optionally: DOS attr, atime, mtime)
922 * either by open FID or by path name (FID == -1).
923 */
924 int
smbfs_smb_setfattr(struct smbnode * np,int fid,uint32_t attr,struct timespec * mtime,struct timespec * atime,struct smb_cred * scrp)925 smbfs_smb_setfattr(
926 struct smbnode *np,
927 int fid,
928 uint32_t attr,
929 struct timespec *mtime,
930 struct timespec *atime,
931 struct smb_cred *scrp)
932 {
933 struct smb_share *ssp = np->n_mount->smi_share;
934 struct smb_vc *vcp = SSTOVC(ssp);
935 int error;
936
937 /*
938 * Normally can use the trans2 call.
939 */
940 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
941 error = smbfs_smb_setfattrNT(np, fid,
942 attr, mtime, atime, scrp);
943 return (error);
944 }
945
946 /*
947 * Fall-back for older protocols.
948 */
949 if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
950 error = smbfs_smb_setftime1(np, fid,
951 mtime, atime, scrp);
952 return (error);
953 }
954 error = smbfs_smb_setpattr1(np, NULL, 0,
955 attr, mtime, scrp);
956 return (error);
957 }
958
959 /*
960 * Set file atime and mtime. Isn't supported by core dialect.
961 */
962 int
smbfs_smb_setftime1(struct smbnode * np,uint16_t fid,struct timespec * mtime,struct timespec * atime,struct smb_cred * scrp)963 smbfs_smb_setftime1(
964 struct smbnode *np,
965 uint16_t fid,
966 struct timespec *mtime,
967 struct timespec *atime,
968 struct smb_cred *scrp)
969 {
970 struct smb_rq rq, *rqp = &rq;
971 struct smb_share *ssp = np->n_mount->smi_share;
972 struct mbchain *mbp;
973 uint16_t date, time;
974 int error, tzoff;
975
976 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
977 if (error)
978 return (error);
979
980 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
981 smb_rq_getrequest(rqp, &mbp);
982 smb_rq_wstart(rqp);
983 mb_put_uint16le(mbp, fid);
984 mb_put_uint32le(mbp, 0); /* creation time */
985
986 if (atime)
987 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
988 else
989 time = date = 0;
990 mb_put_uint16le(mbp, date);
991 mb_put_uint16le(mbp, time);
992 if (mtime)
993 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
994 else
995 time = date = 0;
996 mb_put_uint16le(mbp, date);
997 mb_put_uint16le(mbp, time);
998 smb_rq_wend(rqp);
999 smb_rq_bstart(rqp);
1000 smb_rq_bend(rqp);
1001 error = smb_rq_simple(rqp);
1002 SMBVDEBUG("%d\n", error);
1003 smb_rq_done(rqp);
1004 return (error);
1005 }
1006
1007 /*
1008 * Set DOS file attributes, either via open FID or by path name.
1009 * Looks like this call can be used only if CAP_NT_SMBS bit is on.
1010 *
1011 * When setting via path (fid == -1):
1012 * *BASIC_INFO works with Samba, but Win2K servers say it is an
1013 * invalid information level on a SET_PATH_INFO. Note Win2K does
1014 * support *BASIC_INFO on a SET_FILE_INFO, and they support the
1015 * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure.
1016 */
1017 int
smbfs_smb_setfattrNT(struct smbnode * np,int fid,uint32_t attr,struct timespec * mtime,struct timespec * atime,struct smb_cred * scrp)1018 smbfs_smb_setfattrNT(
1019 struct smbnode *np,
1020 int fid, /* if fid == -1, set by path */
1021 uint32_t attr,
1022 struct timespec *mtime,
1023 struct timespec *atime,
1024 struct smb_cred *scrp)
1025 {
1026 struct smb_t2rq *t2p;
1027 struct smb_share *ssp = np->n_mount->smi_share;
1028 struct smb_vc *vcp = SSTOVC(ssp);
1029 struct mbchain *mbp;
1030 uint64_t tm;
1031 int error;
1032 uint16_t cmd, level;
1033
1034 if (fid == -1) {
1035 cmd = SMB_TRANS2_SET_PATH_INFORMATION;
1036 } else {
1037 if (fid > UINT16_MAX)
1038 return (EINVAL);
1039 cmd = SMB_TRANS2_SET_FILE_INFORMATION;
1040 }
1041 if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
1042 level = SMB_SFILEINFO_BASIC_INFORMATION;
1043 else
1044 level = SMB_SFILEINFO_BASIC_INFO;
1045
1046 error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
1047 if (error)
1048 return (error);
1049
1050 mbp = &t2p->t2_tparam;
1051 mb_init(mbp);
1052
1053 if (cmd == SMB_TRANS2_SET_FILE_INFORMATION)
1054 mb_put_uint16le(mbp, fid);
1055
1056 mb_put_uint16le(mbp, level);
1057 mb_put_uint32le(mbp, 0); /* MBZ */
1058
1059 if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) {
1060 error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
1061 if (error != 0)
1062 goto out;
1063 }
1064
1065 /* FAT file systems don't support dates earlier than 1980. */
1066
1067 mbp = &t2p->t2_tdata;
1068 mb_init(mbp);
1069 mb_put_uint64le(mbp, 0); /* creation time */
1070 if (atime) {
1071 smb_time_local2NT(atime, &tm);
1072 if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1073 tm < NT1980)
1074 tm = NT1980;
1075 } else
1076 tm = 0;
1077 mb_put_uint64le(mbp, tm); /* access time */
1078 if (mtime) {
1079 smb_time_local2NT(mtime, &tm);
1080 if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1081 tm < NT1980)
1082 tm = NT1980;
1083 } else
1084 tm = 0;
1085 mb_put_uint64le(mbp, tm); /* last write time */
1086 mb_put_uint64le(mbp, 0); /* ctime (no change) */
1087 mb_put_uint32le(mbp, attr);
1088 mb_put_uint32le(mbp, 0); /* padding */
1089 t2p->t2_maxpcount = 2;
1090 t2p->t2_maxdcount = 0;
1091 error = smb_t2_request(t2p);
1092 out:
1093 smb_t2_done(t2p);
1094 return (error);
1095 }
1096
1097 /*
1098 * Modern create/open of file or directory.
1099 *
1100 * If disp is ..._DISP_OPEN, or ...DISP_OPEN_IF, or...
1101 * then this is an open attempt, and:
1102 * If xattr then name is the stream to be opened at np,
1103 * Else np should be opened.
1104 * ...we won't touch *fidp,
1105 * ...we will set or clear *attrcacheupdated.
1106 * Else this is a creation attempt, and:
1107 * If xattr then name is the stream to create at np,
1108 * Else name is the thing to create under directory np.
1109 * ...we will return *fidp,
1110 * ...we won't touch *attrcacheupdated.
1111 *
1112 * Note, We use: disp = ...OPEN_IF, ...OVERWRITE_IF, etc.
1113 * now too, which may or may not create a new object.
1114 */
1115 int
smbfs_smb_ntcreatex(struct smbnode * np,const char * name,int nmlen,int xattr,uint32_t req_acc,uint32_t efa,uint32_t share_acc,uint32_t disp,uint32_t createopt,struct smb_cred * scrp,uint16_t * fidp,uint32_t * cr_act_p,struct smbfattr * fap)1116 smbfs_smb_ntcreatex(
1117 struct smbnode *np,
1118 const char *name,
1119 int nmlen,
1120 int xattr, /* is named stream? */
1121 uint32_t req_acc, /* requested access */
1122 uint32_t efa, /* ext. file attrs (DOS attr +) */
1123 uint32_t share_acc,
1124 uint32_t disp, /* open disposition */
1125 uint32_t createopt, /* NTCREATEX_OPTIONS_ */
1126 struct smb_cred *scrp,
1127 uint16_t *fidp,
1128 uint32_t *cr_act_p, /* create action */
1129 struct smbfattr *fap) /* optional */
1130 {
1131 struct smb_rq rq, *rqp = &rq;
1132 struct smb_share *ssp = np->n_mount->smi_share;
1133 struct smb_vc *vcp = SSTOVC(ssp);
1134 struct mbchain *mbp;
1135 struct mdchain *mdp;
1136 struct smbfattr fa;
1137 uint8_t wc;
1138 uint32_t longint, createact;
1139 uint64_t llongint;
1140 int error;
1141 uint16_t fid, *namelenp;
1142
1143 bzero(&fa, sizeof (fa));
1144 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
1145 if (error)
1146 return (error);
1147 smb_rq_getrequest(rqp, &mbp);
1148 smb_rq_wstart(rqp);
1149 mb_put_uint8(mbp, 0xff); /* secondary command */
1150 mb_put_uint8(mbp, 0); /* MBZ */
1151 mb_put_uint16le(mbp, 0); /* offset to next command (none) */
1152 mb_put_uint8(mbp, 0); /* MBZ */
1153 namelenp = (uint16_t *)mb_reserve(mbp, sizeof (uint16_t));
1154 /*
1155 * XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY
1156 * for creating nor for opening a directory. Samba ignores the bit.
1157 */
1158 mb_put_uint32le(mbp, 0); /* NTCREATEX_FLAGS_* */
1159 mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */
1160 mb_put_uint32le(mbp, req_acc);
1161 mb_put_uint64le(mbp, 0); /* "initial allocation size" */
1162 mb_put_uint32le(mbp, efa);
1163 mb_put_uint32le(mbp, share_acc);
1164 mb_put_uint32le(mbp, disp);
1165 mb_put_uint32le(mbp, createopt);
1166 mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
1167 mb_put_uint8(mbp, 0); /* security flags (?) */
1168 smb_rq_wend(rqp);
1169 smb_rq_bstart(rqp);
1170
1171 if (name == NULL)
1172 nmlen = 0;
1173 error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
1174 xattr ? ':' : '\\');
1175 if (error)
1176 goto done;
1177 *namelenp = htoles(nmlen); /* includes null */
1178 smb_rq_bend(rqp);
1179 /*
1180 * Don't want to risk missing a successful
1181 * open response, or we could "leak" FIDs.
1182 */
1183 rqp->sr_flags |= SMBR_NOINTR_RECV;
1184 error = smb_rq_simple_timed(rqp, smb_timo_open);
1185 if (error)
1186 goto done;
1187 smb_rq_getreply(rqp, &mdp);
1188 /*
1189 * spec says 26 for word count, but 34 words are defined
1190 * and observed from win2000
1191 */
1192 error = md_get_uint8(mdp, &wc);
1193 if (error)
1194 goto done;
1195 if (wc != 26 && wc != 34 && wc != 42) {
1196 error = EBADRPC;
1197 goto done;
1198 }
1199 md_get_uint8(mdp, NULL); /* secondary cmd */
1200 md_get_uint8(mdp, NULL); /* mbz */
1201 md_get_uint16le(mdp, NULL); /* andxoffset */
1202 md_get_uint8(mdp, NULL); /* oplock lvl granted */
1203 md_get_uint16le(mdp, &fid); /* file ID */
1204 md_get_uint32le(mdp, &createact); /* create_action */
1205
1206 md_get_uint64le(mdp, &llongint); /* creation time */
1207 smb_time_NT2local(llongint, &fa.fa_createtime);
1208 md_get_uint64le(mdp, &llongint); /* access time */
1209 smb_time_NT2local(llongint, &fa.fa_atime);
1210 md_get_uint64le(mdp, &llongint); /* write time */
1211 smb_time_NT2local(llongint, &fa.fa_mtime);
1212 md_get_uint64le(mdp, &llongint); /* change time */
1213 smb_time_NT2local(llongint, &fa.fa_ctime);
1214
1215 md_get_uint32le(mdp, &longint); /* attributes */
1216 fa.fa_attr = longint;
1217
1218 md_get_uint64le(mdp, &llongint); /* allocation size */
1219 fa.fa_allocsz = llongint;
1220
1221 md_get_uint64le(mdp, &llongint); /* EOF position */
1222 fa.fa_size = llongint;
1223
1224 error = md_get_uint16le(mdp, NULL); /* file type */
1225 /* other stuff we don't care about */
1226
1227 done:
1228 smb_rq_done(rqp);
1229 if (error)
1230 return (error);
1231
1232 if (fidp)
1233 *fidp = fid;
1234 if (cr_act_p)
1235 *cr_act_p = createact;
1236 if (fap)
1237 *fap = fa; /* struct copy */
1238
1239 return (0);
1240 }
1241
1242 static uint32_t
smb_mode2rights(int mode)1243 smb_mode2rights(int mode)
1244 {
1245 mode = mode & SMB_AM_OPENMODE;
1246 uint32_t rights =
1247 STD_RIGHT_SYNCHRONIZE_ACCESS |
1248 STD_RIGHT_READ_CONTROL_ACCESS;
1249
1250 if ((mode == SMB_AM_OPENREAD) ||
1251 (mode == SMB_AM_OPENRW)) {
1252 rights |=
1253 SA_RIGHT_FILE_READ_ATTRIBUTES |
1254 SA_RIGHT_FILE_READ_DATA;
1255 }
1256
1257 if ((mode == SMB_AM_OPENWRITE) ||
1258 (mode == SMB_AM_OPENRW)) {
1259 rights |=
1260 SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1261 SA_RIGHT_FILE_APPEND_DATA |
1262 SA_RIGHT_FILE_WRITE_DATA;
1263 }
1264
1265 if (mode == SMB_AM_OPENEXEC) {
1266 rights |=
1267 SA_RIGHT_FILE_READ_ATTRIBUTES |
1268 SA_RIGHT_FILE_EXECUTE;
1269 }
1270
1271 return (rights);
1272 }
1273
1274 static int
smb_rights2mode(uint32_t rights)1275 smb_rights2mode(uint32_t rights)
1276 {
1277 int accmode = SMB_AM_OPENEXEC; /* our fallback */
1278
1279 if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
1280 SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1281 SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
1282 STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS))
1283 accmode = SMB_AM_OPENWRITE;
1284 if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
1285 SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS))
1286 accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
1287 : SMB_AM_OPENRW;
1288 return (accmode);
1289 }
1290
1291 static int
smbfs_smb_oldopen(struct smbnode * np,const char * name,int nmlen,int xattr,int accmode,struct smb_cred * scrp,uint16_t * fidp,uint16_t * granted_mode_p,smbfattr_t * fap)1292 smbfs_smb_oldopen(
1293 struct smbnode *np,
1294 const char *name,
1295 int nmlen,
1296 int xattr,
1297 int accmode,
1298 struct smb_cred *scrp,
1299 uint16_t *fidp,
1300 uint16_t *granted_mode_p,
1301 smbfattr_t *fap)
1302 {
1303 struct smb_rq rq, *rqp = &rq;
1304 struct smb_share *ssp = np->n_mount->smi_share;
1305 struct smb_vc *vcp = SSTOVC(ssp);
1306 struct mbchain *mbp;
1307 struct mdchain *mdp;
1308 struct smbfattr fa;
1309 uint8_t wc;
1310 uint16_t wattr;
1311 uint32_t longint;
1312 int error;
1313
1314 bzero(&fa, sizeof (fa));
1315
1316 /*
1317 * XXX: move to callers...
1318 *
1319 * Use DENYNONE to give unixy semantics of permitting
1320 * everything not forbidden by permissions. Ie denial
1321 * is up to server with clients/openers needing to use
1322 * advisory locks for further control.
1323 */
1324 accmode |= SMB_SM_DENYNONE;
1325
1326 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
1327 if (error)
1328 return (error);
1329 smb_rq_getrequest(rqp, &mbp);
1330 smb_rq_wstart(rqp);
1331 mb_put_uint16le(mbp, accmode);
1332 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
1333 SMB_FA_DIR);
1334 smb_rq_wend(rqp);
1335 smb_rq_bstart(rqp);
1336 mb_put_uint8(mbp, SMB_DT_ASCII);
1337
1338 error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
1339 xattr ? ':' : '\\');
1340 if (error)
1341 goto done;
1342 smb_rq_bend(rqp);
1343 /*
1344 * Don't want to risk missing a successful
1345 * open response, or we could "leak" FIDs.
1346 */
1347 rqp->sr_flags |= SMBR_NOINTR_RECV;
1348 error = smb_rq_simple_timed(rqp, smb_timo_open);
1349 if (error)
1350 goto done;
1351 smb_rq_getreply(rqp, &mdp);
1352 /*
1353 * 8/2002 a DAVE server returned wc of 15 so we ignore that.
1354 * (the actual packet length and data was correct)
1355 */
1356 error = md_get_uint8(mdp, &wc);
1357 if (error)
1358 goto done;
1359 if (wc != 7 && wc != 15) {
1360 error = EBADRPC;
1361 goto done;
1362 }
1363 md_get_uint16le(mdp, fidp);
1364 md_get_uint16le(mdp, &wattr);
1365 fa.fa_attr = wattr;
1366 /*
1367 * Be careful using the time returned here, as
1368 * with FAT on NT4SP6, at least, the time returned is low
1369 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
1370 * over about every seven minutes!
1371 */
1372 md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
1373 smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime);
1374 md_get_uint32le(mdp, &longint);
1375 fa.fa_size = longint;
1376 error = md_get_uint16le(mdp, granted_mode_p);
1377
1378 done:
1379 smb_rq_done(rqp);
1380 if (error)
1381 return (error);
1382
1383 if (fap)
1384 *fap = fa; /* struct copy */
1385
1386 return (0);
1387 }
1388
1389 int
smbfs_smb_tmpopen(struct smbnode * np,uint32_t rights,struct smb_cred * scrp,uint16_t * fidp)1390 smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
1391 uint16_t *fidp)
1392 {
1393 struct smb_share *ssp = np->n_mount->smi_share;
1394 struct smb_vc *vcp = SSTOVC(ssp);
1395 int accmode, error;
1396
1397 /* Shared lock for n_fid use below. */
1398 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1399
1400 /* Can we re-use n_fid? or must we open anew? */
1401 mutex_enter(&np->r_statelock);
1402 if (np->n_fidrefs > 0 &&
1403 np->n_vcgenid == ssp->ss_vcgenid &&
1404 (rights & np->n_rights) == rights) {
1405 np->n_fidrefs++;
1406 *fidp = np->n_fid;
1407 mutex_exit(&np->r_statelock);
1408 return (0);
1409 }
1410 mutex_exit(&np->r_statelock);
1411
1412 /* re-open an existing file. */
1413 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1414 error = smbfs_smb_ntcreatex(np,
1415 NULL, 0, 0, /* name nmlen xattr */
1416 rights, SMB_EFA_NORMAL,
1417 NTCREATEX_SHARE_ACCESS_ALL,
1418 NTCREATEX_DISP_OPEN,
1419 0, /* create options */
1420 scrp, fidp,
1421 NULL, NULL); /* cr_act_p fa_p */
1422 return (error);
1423 }
1424
1425 accmode = smb_rights2mode(rights);
1426 error = smbfs_smb_oldopen(np,
1427 NULL, 0, 0, /* name nmlen xattr */
1428 accmode, scrp,
1429 fidp,
1430 NULL, /* granted mode p */
1431 NULL); /* fa p */
1432
1433 return (error);
1434 }
1435
1436 int
smbfs_smb_tmpclose(struct smbnode * np,uint16_t fid,struct smb_cred * scrp)1437 smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
1438 {
1439 struct smb_share *ssp = np->n_mount->smi_share;
1440 int error = 0;
1441 uint16_t oldfid = SMB_FID_UNUSED;
1442
1443 /* Shared lock for n_fid use below. */
1444 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1445
1446 mutex_enter(&np->r_statelock);
1447 if (fid == np->n_fid) {
1448 ASSERT(np->n_fidrefs > 0);
1449 if (--np->n_fidrefs == 0) {
1450 /*
1451 * Don't expect to find the last reference
1452 * here in tmpclose. Hard to deal with as
1453 * we don't have r_lkserlock exclusive.
1454 * Will close oldfid below.
1455 */
1456 oldfid = np->n_fid;
1457 np->n_fid = SMB_FID_UNUSED;
1458 }
1459 } else {
1460 /* Will close the passed fid. */
1461 oldfid = fid;
1462 }
1463 mutex_exit(&np->r_statelock);
1464
1465 if (oldfid != SMB_FID_UNUSED)
1466 error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
1467
1468 return (error);
1469 }
1470
1471 int
smbfs_smb_open(struct smbnode * np,const char * name,int nmlen,int xattr,uint32_t rights,struct smb_cred * scrp,uint16_t * fidp,uint32_t * rightsp,smbfattr_t * fap)1472 smbfs_smb_open(
1473 struct smbnode *np,
1474 const char *name,
1475 int nmlen,
1476 int xattr,
1477 uint32_t rights,
1478 struct smb_cred *scrp,
1479 uint16_t *fidp,
1480 uint32_t *rightsp,
1481 smbfattr_t *fap)
1482 {
1483 struct smb_share *ssp = np->n_mount->smi_share;
1484 struct smb_vc *vcp = SSTOVC(ssp);
1485 int accmode, error;
1486 uint16_t grantedmode;
1487
1488 /* open an existing file */
1489 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1490 error = smbfs_smb_ntcreatex(np,
1491 name, nmlen, xattr,
1492 rights, SMB_EFA_NORMAL,
1493 NTCREATEX_SHARE_ACCESS_ALL,
1494 NTCREATEX_DISP_OPEN,
1495 0, /* create options */
1496 scrp, fidp,
1497 NULL, fap); /* cr_act_p fa_p */
1498 if (error != 0)
1499 return (error);
1500 *rightsp = rights;
1501 return (0);
1502 }
1503
1504 accmode = smb_rights2mode(rights);
1505 error = smbfs_smb_oldopen(np,
1506 name, nmlen, xattr, accmode, scrp,
1507 fidp, &grantedmode, fap);
1508 if (error != 0)
1509 return (error);
1510 *rightsp = smb_mode2rights(grantedmode);
1511 (void) smbfs_smb_getfattr(np, fap, scrp);
1512
1513 return (0);
1514 }
1515
1516 int
smbfs_smb_close(struct smb_share * ssp,uint16_t fid,struct timespec * mtime,struct smb_cred * scrp)1517 smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
1518 struct smb_cred *scrp)
1519 {
1520 struct smb_rq rq, *rqp = &rq;
1521 struct mbchain *mbp;
1522 long time;
1523 int error;
1524
1525 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
1526 if (error)
1527 return (error);
1528 smb_rq_getrequest(rqp, &mbp);
1529 smb_rq_wstart(rqp);
1530 mb_put_uint16le(mbp, fid);
1531 if (mtime) {
1532 int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz;
1533 smb_time_local2server(mtime, sv_tz, &time);
1534 } else
1535 time = 0;
1536 mb_put_uint32le(mbp, time);
1537 smb_rq_wend(rqp);
1538 smb_rq_bstart(rqp);
1539 smb_rq_bend(rqp);
1540
1541 /*
1542 * We don't really care about the result here, but we
1543 * do need to make sure we send this out, or we could
1544 * "leak" open file handles on interrupt or timeout.
1545 * The NOINTR_SEND flag makes this request immune to
1546 * interrupt or timeout until the send is done.
1547 */
1548 rqp->sr_flags |= SMBR_NOINTR_SEND;
1549 error = smb_rq_simple(rqp);
1550 smb_rq_done(rqp);
1551 /*
1552 * ENOTCONN isn't interesting - if the connection is closed,
1553 * so are all our FIDs - and EIO is also not interesting,
1554 * as it means a forced unmount was done. (was ENXIO)
1555 * Also ETIME, which means we sent the request but gave up
1556 * waiting before the response came back.
1557 *
1558 * Don't clog up the system log with warnings about these
1559 * uninteresting failures on closes.
1560 */
1561 switch (error) {
1562 case ENOTCONN:
1563 case ENXIO:
1564 case EIO:
1565 case ETIME:
1566 error = 0;
1567 }
1568 return (error);
1569 }
1570
1571 static int
smbfs_smb_oldcreate(struct smbnode * dnp,const char * name,int nmlen,int xattr,struct smb_cred * scrp,uint16_t * fidp)1572 smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
1573 int xattr, struct smb_cred *scrp, uint16_t *fidp)
1574 {
1575 struct smb_rq rq, *rqp = &rq;
1576 struct smb_share *ssp = dnp->n_mount->smi_share;
1577 struct mbchain *mbp;
1578 struct mdchain *mdp;
1579 struct timespec ctime;
1580 uint8_t wc;
1581 long tm;
1582 int error;
1583 uint16_t attr = SMB_FA_ARCHIVE;
1584
1585 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
1586 if (error)
1587 return (error);
1588 smb_rq_getrequest(rqp, &mbp);
1589 smb_rq_wstart(rqp);
1590 if (name && *name == '.')
1591 attr |= SMB_FA_HIDDEN;
1592 mb_put_uint16le(mbp, attr); /* attributes */
1593 gethrestime(&ctime);
1594 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
1595 mb_put_uint32le(mbp, tm);
1596 smb_rq_wend(rqp);
1597 smb_rq_bstart(rqp);
1598 mb_put_uint8(mbp, SMB_DT_ASCII);
1599 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &nmlen,
1600 xattr ? ':' : '\\');
1601 if (error)
1602 goto out;
1603 smb_rq_bend(rqp);
1604 /*
1605 * Don't want to risk missing a successful
1606 * open response, or we could "leak" FIDs.
1607 */
1608 rqp->sr_flags |= SMBR_NOINTR_RECV;
1609 error = smb_rq_simple_timed(rqp, smb_timo_open);
1610 if (error)
1611 goto out;
1612
1613 smb_rq_getreply(rqp, &mdp);
1614 md_get_uint8(mdp, &wc);
1615 if (wc != 1) {
1616 error = EBADRPC;
1617 goto out;
1618 }
1619 error = md_get_uint16le(mdp, fidp);
1620
1621 out:
1622 smb_rq_done(rqp);
1623 return (error);
1624 }
1625
1626 int
smbfs_smb_create(struct smbnode * dnp,const char * name,int nmlen,int xattr,uint32_t disp,struct smb_cred * scrp,uint16_t * fidp)1627 smbfs_smb_create(
1628 struct smbnode *dnp,
1629 const char *name,
1630 int nmlen,
1631 int xattr,
1632 uint32_t disp,
1633 struct smb_cred *scrp,
1634 uint16_t *fidp)
1635 {
1636 struct smb_share *ssp = dnp->n_mount->smi_share;
1637 struct smb_vc *vcp = SSTOVC(ssp);
1638 uint32_t efa, rights;
1639 int error;
1640
1641 /*
1642 * At present the only access we might need is to WRITE data,
1643 * and that only if we are creating a "symlink". When/if the
1644 * access needed gets more complex it should made a parameter
1645 * and be set upstream.
1646 */
1647 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1648 rights = SA_RIGHT_FILE_WRITE_DATA;
1649 efa = SMB_EFA_NORMAL;
1650 if (!xattr && name && *name == '.')
1651 efa = SMB_EFA_HIDDEN;
1652 error = smbfs_smb_ntcreatex(dnp,
1653 name, nmlen, xattr, rights, efa,
1654 NTCREATEX_SHARE_ACCESS_ALL,
1655 disp, /* != NTCREATEX_DISP_OPEN */
1656 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
1657 scrp, fidp, NULL, NULL); /* cr_act_p fa_p */
1658 return (error);
1659 }
1660
1661 error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp);
1662 return (error);
1663 }
1664
1665 int
smbfs_smb_delete(struct smbnode * np,struct smb_cred * scrp,const char * name,int nmlen,int xattr)1666 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
1667 int nmlen, int xattr)
1668 {
1669 struct smb_rq rq, *rqp = &rq;
1670 struct smb_share *ssp = np->n_mount->smi_share;
1671 struct mbchain *mbp;
1672 int error;
1673
1674 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
1675 if (error)
1676 return (error);
1677 smb_rq_getrequest(rqp, &mbp);
1678 smb_rq_wstart(rqp);
1679 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
1680 smb_rq_wend(rqp);
1681 smb_rq_bstart(rqp);
1682 mb_put_uint8(mbp, SMB_DT_ASCII);
1683 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &nmlen,
1684 xattr ? ':' : '\\');
1685 if (!error) {
1686 smb_rq_bend(rqp);
1687 error = smb_rq_simple(rqp);
1688 }
1689 smb_rq_done(rqp);
1690 return (error);
1691 }
1692
1693 int
smbfs_smb_rename(struct smbnode * src,struct smbnode * tdnp,const char * tname,int tnmlen,struct smb_cred * scrp)1694 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
1695 const char *tname, int tnmlen, struct smb_cred *scrp)
1696 {
1697 struct smb_rq rq, *rqp = &rq;
1698 struct smb_share *ssp = src->n_mount->smi_share;
1699 struct mbchain *mbp;
1700 int error;
1701 uint16_t fa;
1702 char sep;
1703
1704 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
1705 if (error)
1706 return (error);
1707 smb_rq_getrequest(rqp, &mbp);
1708 smb_rq_wstart(rqp);
1709 /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
1710 fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
1711 fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
1712 mb_put_uint16le(mbp, fa);
1713 smb_rq_wend(rqp);
1714 smb_rq_bstart(rqp);
1715
1716 /*
1717 * When we're not adding any component name, the
1718 * passed sep is ignored, so just pass sep=0.
1719 */
1720 mb_put_uint8(mbp, SMB_DT_ASCII);
1721 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, 0);
1722 if (error)
1723 goto out;
1724
1725 /*
1726 * After XATTR directories, separator is ":"
1727 */
1728 sep = (src->n_flag & N_XATTR) ? ':' : '\\';
1729 mb_put_uint8(mbp, SMB_DT_ASCII);
1730 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, sep);
1731 if (error)
1732 goto out;
1733
1734 smb_rq_bend(rqp);
1735 error = smb_rq_simple(rqp);
1736 out:
1737 smb_rq_done(rqp);
1738 return (error);
1739 }
1740
1741 int
smbfs_smb_move(struct smbnode * src,struct smbnode * tdnp,const char * tname,int tnmlen,uint16_t flags,struct smb_cred * scrp)1742 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
1743 const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
1744 {
1745 struct smb_rq rq, *rqp = &rq;
1746 struct smb_share *ssp = src->n_mount->smi_share;
1747 struct mbchain *mbp;
1748 int error;
1749
1750 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
1751 if (error)
1752 return (error);
1753 smb_rq_getrequest(rqp, &mbp);
1754 smb_rq_wstart(rqp);
1755 mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
1756 mb_put_uint16le(mbp, 0x20); /* delete target file */
1757 mb_put_uint16le(mbp, flags);
1758 smb_rq_wend(rqp);
1759 smb_rq_bstart(rqp);
1760 mb_put_uint8(mbp, SMB_DT_ASCII);
1761
1762 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\');
1763 if (error)
1764 goto out;
1765 mb_put_uint8(mbp, SMB_DT_ASCII);
1766 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, '\\');
1767 if (error)
1768 goto out;
1769 smb_rq_bend(rqp);
1770 error = smb_rq_simple(rqp);
1771
1772 out:
1773 smb_rq_done(rqp);
1774 return (error);
1775 }
1776
1777 static int
smbfs_smb_oldmkdir(struct smbnode * dnp,const char * name,int len,struct smb_cred * scrp)1778 smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
1779 struct smb_cred *scrp)
1780 {
1781 struct smb_rq rq, *rqp = &rq;
1782 struct smb_share *ssp = dnp->n_mount->smi_share;
1783 struct mbchain *mbp;
1784 int error;
1785
1786 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
1787 if (error)
1788 return (error);
1789 smb_rq_getrequest(rqp, &mbp);
1790 smb_rq_wstart(rqp);
1791 smb_rq_wend(rqp);
1792 smb_rq_bstart(rqp);
1793 mb_put_uint8(mbp, SMB_DT_ASCII);
1794 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &len, '\\');
1795 if (!error) {
1796 smb_rq_bend(rqp);
1797 error = smb_rq_simple(rqp);
1798 }
1799 smb_rq_done(rqp);
1800 return (error);
1801 }
1802
1803 int
smbfs_smb_mkdir(struct smbnode * dnp,const char * name,int nmlen,struct smb_cred * scrp)1804 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
1805 struct smb_cred *scrp)
1806 {
1807 struct smb_share *ssp = dnp->n_mount->smi_share;
1808 struct smb_vc *vcp = SSTOVC(ssp);
1809 uint32_t rights;
1810 uint16_t fid;
1811 int error;
1812
1813 /*
1814 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
1815 * just to be asking for something. The rights==0 case could
1816 * easily be broken on some old or unusual servers.
1817 */
1818 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1819 rights = SA_RIGHT_FILE_READ_DATA;
1820 error = smbfs_smb_ntcreatex(dnp,
1821 name, nmlen, 0, /* xattr */
1822 rights, SMB_EFA_DIRECTORY,
1823 NTCREATEX_SHARE_ACCESS_ALL,
1824 NTCREATEX_DISP_CREATE,
1825 NTCREATEX_OPTIONS_DIRECTORY,
1826 scrp, &fid, NULL, NULL); /* cr_act_p fa_p */
1827 if (error)
1828 return (error);
1829 (void) smbfs_smb_close(ssp, fid, NULL, scrp);
1830 return (0);
1831 }
1832
1833 error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp);
1834 return (error);
1835 }
1836
1837 int
smbfs_smb_rmdir(struct smbnode * np,struct smb_cred * scrp)1838 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
1839 {
1840 struct smb_rq rq, *rqp = &rq;
1841 struct smb_share *ssp = np->n_mount->smi_share;
1842 struct mbchain *mbp;
1843 int error;
1844
1845 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
1846 if (error)
1847 return (error);
1848 smb_rq_getrequest(rqp, &mbp);
1849 smb_rq_wstart(rqp);
1850 smb_rq_wend(rqp);
1851 smb_rq_bstart(rqp);
1852 mb_put_uint8(mbp, SMB_DT_ASCII);
1853 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, NULL, '\\');
1854 if (!error) {
1855 smb_rq_bend(rqp);
1856 error = smb_rq_simple(rqp);
1857 }
1858 smb_rq_done(rqp);
1859 return (error);
1860 }
1861
1862 static int
smbfs_smb_search(struct smbfs_fctx * ctx)1863 smbfs_smb_search(struct smbfs_fctx *ctx)
1864 {
1865 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1866 struct smb_rq *rqp;
1867 struct mbchain *mbp;
1868 struct mdchain *mdp;
1869 uint8_t wc, bt;
1870 uint16_t ec, dlen, bc;
1871 int len, maxent, error, iseof = 0;
1872
1873 maxent = min(ctx->f_left,
1874 (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
1875 if (ctx->f_rq) {
1876 smb_rq_done(ctx->f_rq);
1877 ctx->f_rq = NULL;
1878 }
1879 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
1880 ctx->f_scred, &rqp);
1881 if (error)
1882 return (error);
1883 ctx->f_rq = rqp;
1884 smb_rq_getrequest(rqp, &mbp);
1885 smb_rq_wstart(rqp);
1886 mb_put_uint16le(mbp, maxent); /* max entries to return */
1887 mb_put_uint16le(mbp, ctx->f_attrmask);
1888 smb_rq_wend(rqp);
1889 smb_rq_bstart(rqp);
1890 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */
1891 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1892 len = ctx->f_wclen;
1893 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard,
1894 &len, '\\');
1895 if (error)
1896 return (error);
1897 mb_put_uint8(mbp, SMB_DT_VARIABLE);
1898 mb_put_uint16le(mbp, 0); /* context length */
1899 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1900 } else {
1901 if (SMB_UNICODE_STRINGS(vcp)) {
1902 mb_put_padbyte(mbp);
1903 mb_put_uint8(mbp, 0);
1904 }
1905 mb_put_uint8(mbp, 0);
1906 mb_put_uint8(mbp, SMB_DT_VARIABLE);
1907 mb_put_uint16le(mbp, SMB_SKEYLEN);
1908 mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1909 }
1910 smb_rq_bend(rqp);
1911 error = smb_rq_simple(rqp);
1912 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
1913 error = 0;
1914 iseof = 1;
1915 ctx->f_flags |= SMBFS_RDD_EOF;
1916 } else if (error)
1917 return (error);
1918 smb_rq_getreply(rqp, &mdp);
1919 error = md_get_uint8(mdp, &wc);
1920 if (error)
1921 return (error);
1922 if (wc != 1)
1923 return (iseof ? ENOENT : EBADRPC);
1924 md_get_uint16le(mdp, &ec);
1925 md_get_uint16le(mdp, &bc);
1926 md_get_uint8(mdp, &bt);
1927 error = md_get_uint16le(mdp, &dlen);
1928 if (error)
1929 return (error);
1930 if (ec == 0)
1931 return (ENOENT);
1932 ctx->f_ecnt = ec;
1933 if (bc < 3)
1934 return (EBADRPC);
1935 bc -= 3;
1936 if (bt != SMB_DT_VARIABLE)
1937 return (EBADRPC);
1938 if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
1939 return (EBADRPC);
1940 return (0);
1941 }
1942
1943
1944 /*ARGSUSED*/
1945 static int
smbfs_smb_findopenLM1(struct smbfs_fctx * ctx,struct smbnode * dnp,const char * wildcard,int wclen,uint16_t attr)1946 smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
1947 const char *wildcard, int wclen, uint16_t attr)
1948 {
1949
1950 ctx->f_type = ft_LM1;
1951 ctx->f_attrmask = attr;
1952 if (wildcard) {
1953 if (wclen == 1 && wildcard[0] == '*') {
1954 ctx->f_wildcard = "*.*";
1955 ctx->f_wclen = 3;
1956 } else {
1957 ctx->f_wildcard = wildcard;
1958 ctx->f_wclen = wclen;
1959 }
1960 } else {
1961 ctx->f_wildcard = NULL;
1962 ctx->f_wclen = 0;
1963 }
1964 ctx->f_name = (char *)ctx->f_fname;
1965 ctx->f_namesz = 0;
1966 return (0);
1967 }
1968
1969 static int
smbfs_smb_findnextLM1(struct smbfs_fctx * ctx,uint16_t limit)1970 smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
1971 {
1972 struct mdchain *mdp;
1973 struct smb_rq *rqp;
1974 char *cp;
1975 uint8_t battr;
1976 uint16_t date, time;
1977 uint32_t size;
1978 int error;
1979 struct timespec ts;
1980
1981 if (ctx->f_ecnt == 0) {
1982 if (ctx->f_flags & SMBFS_RDD_EOF)
1983 return (ENOENT);
1984 ctx->f_left = ctx->f_limit = limit;
1985 gethrestime(&ts);
1986 error = smbfs_smb_search(ctx);
1987 if (error)
1988 return (error);
1989 }
1990 rqp = ctx->f_rq;
1991 smb_rq_getreply(rqp, &mdp);
1992 md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1993 md_get_uint8(mdp, &battr);
1994 md_get_uint16le(mdp, &time);
1995 md_get_uint16le(mdp, &date);
1996 md_get_uint32le(mdp, &size);
1997 cp = ctx->f_name;
1998 error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
1999 cp[sizeof (ctx->f_fname) - 1] = 0;
2000 cp += strlen(cp) - 1;
2001 while (*cp == ' ' && cp >= ctx->f_name)
2002 *cp-- = 0;
2003 ctx->f_attr.fa_attr = battr;
2004 smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
2005 &ctx->f_attr.fa_mtime);
2006 ctx->f_attr.fa_size = size;
2007 ctx->f_nmlen = strlen(ctx->f_name);
2008 ctx->f_ecnt--;
2009 ctx->f_left--;
2010 return (0);
2011 }
2012
2013 static int
smbfs_smb_findcloseLM1(struct smbfs_fctx * ctx)2014 smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
2015 {
2016 if (ctx->f_rq)
2017 smb_rq_done(ctx->f_rq);
2018 return (0);
2019 }
2020
2021 /*
2022 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
2023 */
2024 static int
smbfs_smb_trans2find2(struct smbfs_fctx * ctx)2025 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
2026 {
2027 struct smb_t2rq *t2p;
2028 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
2029 struct mbchain *mbp;
2030 struct mdchain *mdp;
2031 uint16_t ecnt, eos, lno, flags;
2032 int len, error;
2033
2034 if (ctx->f_t2) {
2035 smb_t2_done(ctx->f_t2);
2036 ctx->f_t2 = NULL;
2037 }
2038 flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
2039 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
2040 flags |= FIND2_CLOSE_AFTER_REQUEST;
2041 ctx->f_flags |= SMBFS_RDD_NOCLOSE;
2042 }
2043 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
2044 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
2045 ctx->f_scred, &t2p);
2046 if (error)
2047 return (error);
2048 ctx->f_t2 = t2p;
2049 mbp = &t2p->t2_tparam;
2050 mb_init(mbp);
2051 mb_put_uint16le(mbp, ctx->f_attrmask);
2052 mb_put_uint16le(mbp, ctx->f_limit);
2053 mb_put_uint16le(mbp, flags);
2054 mb_put_uint16le(mbp, ctx->f_infolevel);
2055 mb_put_uint32le(mbp, 0);
2056 len = ctx->f_wclen;
2057 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard,
2058 &len, '\\');
2059 if (error)
2060 return (error);
2061 } else {
2062 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
2063 ctx->f_scred, &t2p);
2064 if (error)
2065 return (error);
2066 ctx->f_t2 = t2p;
2067 mbp = &t2p->t2_tparam;
2068 mb_init(mbp);
2069 mb_put_uint16le(mbp, ctx->f_Sid);
2070 mb_put_uint16le(mbp, ctx->f_limit);
2071 mb_put_uint16le(mbp, ctx->f_infolevel);
2072 /* Send whatever resume key we received... */
2073 mb_put_uint32le(mbp, ctx->f_rkey);
2074 mb_put_uint16le(mbp, flags);
2075 /* ... and the resume name if we have one. */
2076 if (ctx->f_rname) {
2077 /* resume file name */
2078 mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
2079 MB_MSYSTEM);
2080 }
2081 /* Add trailing null - 1 byte if ASCII, 2 if Unicode */
2082 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2083 mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
2084 mb_put_uint8(mbp, 0);
2085 }
2086 t2p->t2_maxpcount = 5 * 2;
2087 t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */
2088 error = smb_t2_request(t2p);
2089 if (error)
2090 return (error);
2091
2092 /*
2093 * This is the "resume name" we just sent.
2094 * We want the new one (if any) that may be
2095 * found in the response we just received and
2096 * will now begin parsing. Free the old one
2097 * now so we'll know if we found a new one.
2098 */
2099 if (ctx->f_rname) {
2100 kmem_free(ctx->f_rname, ctx->f_rnamelen);
2101 ctx->f_rname = NULL;
2102 ctx->f_rnamelen = 0;
2103 }
2104
2105 mdp = &t2p->t2_rparam;
2106 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
2107 if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
2108 goto nodata;
2109 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
2110 }
2111 md_get_uint16le(mdp, &ecnt); /* entry count */
2112 md_get_uint16le(mdp, &eos); /* end of search */
2113 md_get_uint16le(mdp, NULL); /* EA err. off. */
2114 error = md_get_uint16le(mdp, &lno); /* last name off. */
2115 if (error != 0)
2116 goto nodata;
2117
2118 /*
2119 * The "end of search" flag from an XP server sometimes
2120 * comes back zero when the prior find_next returned exactly
2121 * the number of entries requested. in which case we'd try again
2122 * but the search has in fact been closed so an EBADF results.
2123 * our circumvention is to check here for a zero entry count.
2124 */
2125 ctx->f_ecnt = ecnt;
2126 if (eos || ctx->f_ecnt == 0)
2127 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
2128 if (ctx->f_ecnt == 0)
2129 return (ENOENT);
2130
2131 /* Last Name Off (LNO) is the entry with the resume name. */
2132 ctx->f_rnameofs = lno;
2133 ctx->f_eofs = 0;
2134 return (0);
2135
2136 nodata:
2137 /*
2138 * Failed parsing the FindFirst or FindNext response.
2139 * Force this directory listing closed, otherwise the
2140 * calling process may hang in an infinite loop.
2141 */
2142 ctx->f_ecnt = 0; /* Force closed. */
2143 ctx->f_flags |= SMBFS_RDD_EOF;
2144 return (EIO);
2145 }
2146
2147 static int
smbfs_smb_findclose2(struct smbfs_fctx * ctx)2148 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
2149 {
2150 struct smb_rq rq, *rqp = &rq;
2151 struct mbchain *mbp;
2152 int error;
2153
2154 error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
2155 ctx->f_scred);
2156 if (error)
2157 return (error);
2158 smb_rq_getrequest(rqp, &mbp);
2159 smb_rq_wstart(rqp);
2160 mb_put_uint16le(mbp, ctx->f_Sid);
2161 smb_rq_wend(rqp);
2162 smb_rq_bstart(rqp);
2163 smb_rq_bend(rqp);
2164 /* Ditto comments at _smb_close */
2165 rqp->sr_flags |= SMBR_NOINTR_SEND;
2166 error = smb_rq_simple(rqp);
2167 smb_rq_done(rqp);
2168 return (error);
2169 }
2170
2171 /*ARGSUSED*/
2172 static int
smbfs_smb_findopenLM2(struct smbfs_fctx * ctx,struct smbnode * dnp,const char * wildcard,int wclen,uint16_t attr)2173 smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
2174 const char *wildcard, int wclen, uint16_t attr)
2175 {
2176
2177 ctx->f_type = ft_LM2;
2178 ctx->f_namesz = SMB_MAXFNAMELEN + 1;
2179 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2180 ctx->f_namesz *= 2;
2181 ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
2182 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
2183 < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
2184 SMB_FIND_BOTH_DIRECTORY_INFO;
2185 ctx->f_attrmask = attr;
2186 ctx->f_wildcard = wildcard;
2187 ctx->f_wclen = wclen;
2188 return (0);
2189 }
2190
2191 static int
smbfs_smb_findnextLM2(struct smbfs_fctx * ctx,uint16_t limit)2192 smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
2193 {
2194 struct mdchain *mdp;
2195 struct smb_t2rq *t2p;
2196 char *cp;
2197 uint8_t tb;
2198 uint16_t date, time, wattr;
2199 uint32_t size, next, dattr, resumekey = 0;
2200 uint64_t llongint;
2201 int error, svtz, cnt, fxsz, nmlen, recsz;
2202 struct timespec ts;
2203
2204 if (ctx->f_ecnt == 0) {
2205 if (ctx->f_flags & SMBFS_RDD_EOF)
2206 return (ENOENT);
2207 ctx->f_left = ctx->f_limit = limit;
2208 gethrestime(&ts);
2209 error = smbfs_smb_trans2find2(ctx);
2210 if (error)
2211 return (error);
2212 ctx->f_otws++;
2213 }
2214 t2p = ctx->f_t2;
2215 mdp = &t2p->t2_rdata;
2216 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
2217 switch (ctx->f_infolevel) {
2218 case SMB_FIND_STANDARD:
2219 next = 0;
2220 fxsz = 0;
2221 md_get_uint16le(mdp, &date);
2222 md_get_uint16le(mdp, &time); /* creation time */
2223 smb_dos2unixtime(date, time, 0, svtz,
2224 &ctx->f_attr.fa_createtime);
2225 md_get_uint16le(mdp, &date);
2226 md_get_uint16le(mdp, &time); /* access time */
2227 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
2228 md_get_uint16le(mdp, &date);
2229 md_get_uint16le(mdp, &time); /* modify time */
2230 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
2231 md_get_uint32le(mdp, &size);
2232 ctx->f_attr.fa_size = size;
2233 md_get_uint32le(mdp, &size); /* allocation size */
2234 ctx->f_attr.fa_allocsz = size;
2235 md_get_uint16le(mdp, &wattr);
2236 ctx->f_attr.fa_attr = wattr;
2237 error = md_get_uint8(mdp, &tb);
2238 if (error)
2239 goto nodata;
2240 size = nmlen = tb;
2241 fxsz = 23;
2242 recsz = next = 24 + nmlen; /* docs misses zero byte @end */
2243 break;
2244 case SMB_FIND_DIRECTORY_INFO:
2245 case SMB_FIND_BOTH_DIRECTORY_INFO:
2246 md_get_uint32le(mdp, &next);
2247 md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
2248 md_get_uint64le(mdp, &llongint); /* creation time */
2249 smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
2250 md_get_uint64le(mdp, &llongint);
2251 smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
2252 md_get_uint64le(mdp, &llongint);
2253 smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
2254 md_get_uint64le(mdp, &llongint);
2255 smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
2256 md_get_uint64le(mdp, &llongint); /* file size */
2257 ctx->f_attr.fa_size = llongint;
2258 md_get_uint64le(mdp, &llongint); /* alloc. size */
2259 ctx->f_attr.fa_allocsz = llongint;
2260 md_get_uint32le(mdp, &dattr); /* ext. file attributes */
2261 ctx->f_attr.fa_attr = dattr;
2262 error = md_get_uint32le(mdp, &size); /* name len */
2263 if (error)
2264 goto nodata;
2265 fxsz = 64; /* size ofinfo up to filename */
2266 if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
2267 /*
2268 * Skip EaSize(4 bytes), a byte of ShortNameLength,
2269 * a reserved byte, and ShortName(8.3 means 24 bytes,
2270 * as Leach defined it to always be Unicode)
2271 */
2272 error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
2273 if (error)
2274 goto nodata;
2275 fxsz += 30;
2276 }
2277 recsz = next ? next : fxsz + size;
2278 break;
2279 default:
2280 SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
2281 return (EINVAL);
2282 }
2283
2284 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2285 nmlen = min(size, SMB_MAXFNAMELEN * 2);
2286 else
2287 nmlen = min(size, SMB_MAXFNAMELEN);
2288
2289 /* Allocated f_name in findopen */
2290 ASSERT(nmlen < ctx->f_namesz);
2291 cp = ctx->f_name;
2292
2293 error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
2294 if (error)
2295 goto nodata;
2296 if (next) {
2297 /* How much data to skip? */
2298 cnt = next - nmlen - fxsz;
2299 if (cnt < 0) {
2300 SMBVDEBUG("out of sync\n");
2301 goto nodata;
2302 }
2303 if (cnt > 0)
2304 md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
2305 }
2306 /* Don't count any trailing null in the name. */
2307 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
2308 if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
2309 nmlen -= 2;
2310 } else {
2311 if (nmlen && cp[nmlen - 1] == 0)
2312 nmlen--;
2313 }
2314 if (nmlen == 0)
2315 goto nodata;
2316
2317 /*
2318 * On a find-next we expect that the server will:
2319 * 1) if the continue bit is set, use the server's offset,
2320 * 2) else if the resume key is non-zero, use that offset,
2321 * 3) else if the resume name is set, use that offset,
2322 * 4) else use the server's idea of current offset.
2323 *
2324 * We always set the resume key flag. If the server returns
2325 * a resume key then we should always send it back to them.
2326 */
2327 ctx->f_rkey = resumekey;
2328
2329 next = ctx->f_eofs + recsz;
2330 if (ctx->f_rnameofs &&
2331 ctx->f_rnameofs >= ctx->f_eofs &&
2332 ctx->f_rnameofs < (int)next) {
2333 /*
2334 * This entry is the "resume name".
2335 * Save it for the next request.
2336 */
2337 if (ctx->f_rnamelen != nmlen) {
2338 if (ctx->f_rname)
2339 kmem_free(ctx->f_rname, ctx->f_rnamelen);
2340 ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
2341 ctx->f_rnamelen = nmlen;
2342 }
2343 bcopy(ctx->f_name, ctx->f_rname, nmlen);
2344 }
2345 ctx->f_nmlen = nmlen;
2346 ctx->f_eofs = next;
2347 ctx->f_ecnt--;
2348 ctx->f_left--;
2349
2350 smbfs_fname_tolocal(ctx);
2351 return (0);
2352
2353 nodata:
2354 /*
2355 * Something bad has happened and we ran out of data
2356 * before we could parse all f_ecnt entries expected.
2357 * Force this directory listing closed, otherwise the
2358 * calling process may hang in an infinite loop.
2359 */
2360 SMBVDEBUG("ran out of data\n");
2361 ctx->f_ecnt = 0; /* Force closed. */
2362 ctx->f_flags |= SMBFS_RDD_EOF;
2363 return (EIO);
2364 }
2365
2366 static int
smbfs_smb_findcloseLM2(struct smbfs_fctx * ctx)2367 smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
2368 {
2369 int error = 0;
2370 if (ctx->f_name)
2371 kmem_free(ctx->f_name, ctx->f_namesz);
2372 if (ctx->f_t2)
2373 smb_t2_done(ctx->f_t2);
2374 /*
2375 * If SMBFS_RDD_FINDFIRST is still set, we were opened
2376 * but never saw a findfirst, so we don't have any
2377 * search handle to close.
2378 */
2379 if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
2380 error = smbfs_smb_findclose2(ctx);
2381 return (error);
2382 }
2383
2384 int
smbfs_smb_findopen(struct smbnode * dnp,const char * wild,int wlen,int attr,struct smb_cred * scrp,struct smbfs_fctx ** ctxpp)2385 smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
2386 int attr, struct smb_cred *scrp,
2387 struct smbfs_fctx **ctxpp)
2388 {
2389 struct smbfs_fctx *ctx;
2390 int error;
2391
2392 ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
2393
2394 ctx->f_flags = SMBFS_RDD_FINDFIRST;
2395 ctx->f_dnp = dnp;
2396 ctx->f_scred = scrp;
2397 ctx->f_ssp = dnp->n_mount->smi_share;
2398
2399 if (dnp->n_flag & N_XATTR) {
2400 error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
2401 goto out;
2402 }
2403
2404 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) {
2405 error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr);
2406 } else {
2407 error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
2408 }
2409
2410 out:
2411 if (error)
2412 (void) smbfs_smb_findclose(ctx, scrp);
2413 else
2414 *ctxpp = ctx;
2415 return (error);
2416 }
2417
2418 int
smbfs_smb_findnext(struct smbfs_fctx * ctx,int limit,struct smb_cred * scrp)2419 smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
2420 {
2421 int error;
2422
2423 /*
2424 * Note: "limit" (maxcount) needs to fit in a short!
2425 */
2426 if (limit > 0xffff)
2427 limit = 0xffff;
2428
2429 ctx->f_scred = scrp;
2430 for (;;) {
2431 bzero(&ctx->f_attr, sizeof (ctx->f_attr));
2432 switch (ctx->f_type) {
2433 case ft_LM1:
2434 error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
2435 break;
2436 case ft_LM2:
2437 error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
2438 break;
2439 case ft_XA:
2440 error = smbfs_xa_findnext(ctx, (uint16_t)limit);
2441 break;
2442 default:
2443 ASSERT(0);
2444 error = EINVAL;
2445 break;
2446 }
2447 if (error)
2448 return (error);
2449 /*
2450 * Skip "." or ".." - easy now that ctx->f_name
2451 * has already been converted to utf-8 format.
2452 */
2453 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
2454 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
2455 ctx->f_name[1] == '.'))
2456 continue;
2457 break;
2458 }
2459
2460 /*
2461 * Moved the smbfs_fname_tolocal(ctx) call into
2462 * the ..._findnext functions above.
2463 */
2464
2465 ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
2466 return (0);
2467 }
2468
2469
2470 int
smbfs_smb_findclose(struct smbfs_fctx * ctx,struct smb_cred * scrp)2471 smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
2472 {
2473 int error;
2474
2475 ctx->f_scred = scrp;
2476 switch (ctx->f_type) {
2477 case ft_LM1:
2478 error = smbfs_smb_findcloseLM1(ctx);
2479 break;
2480 case ft_LM2:
2481 error = smbfs_smb_findcloseLM2(ctx);
2482 break;
2483 case ft_XA:
2484 error = smbfs_xa_findclose(ctx);
2485 break;
2486 }
2487 if (ctx->f_rname)
2488 kmem_free(ctx->f_rname, ctx->f_rnamelen);
2489 if (ctx->f_firstnm)
2490 kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
2491 kmem_free(ctx, sizeof (*ctx));
2492 return (error);
2493 }
2494
2495
2496 int
smbfs_smb_lookup(struct smbnode * dnp,const char ** namep,int * nmlenp,struct smbfattr * fap,struct smb_cred * scrp)2497 smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
2498 struct smbfattr *fap, struct smb_cred *scrp)
2499 {
2500 struct smbfs_fctx *ctx;
2501 int error, intr;
2502 const char *name = (namep ? *namep : NULL);
2503 int nmlen = (nmlenp ? *nmlenp : 0);
2504
2505 /* This is no longer called with a null dnp */
2506 ASSERT(dnp);
2507
2508 /*
2509 * Should not get here with "" anymore.
2510 */
2511 if (!name || !nmlen) {
2512 DEBUG_ENTER("smbfs_smb_lookup: name is NULL");
2513 return (EINVAL);
2514 }
2515
2516 /*
2517 * Should not get here with "." or ".." anymore.
2518 */
2519 if ((nmlen == 1 && name[0] == '.') ||
2520 (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
2521 DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
2522 return (EINVAL);
2523 }
2524
2525 /*
2526 * XXX: Should use _qpathinfo here instead.
2527 * (if SMB_CAP_NT_SMBS)
2528 */
2529
2530 /*
2531 * Shared lock for n_fid use (smb_flush).
2532 */
2533 intr = dnp->n_mount->smi_flags & SMI_INT;
2534 if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
2535 return (EINTR);
2536
2537 /*
2538 * This hides a server bug observable in Win98:
2539 * size changes may not show until a CLOSE or a FLUSH op
2540 * XXX: Make this conditional on !NTSMBs
2541 */
2542 error = smbfs_smb_flush(dnp, scrp);
2543 if (error)
2544 goto out;
2545 error = smbfs_smb_findopen(dnp, name, nmlen,
2546 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
2547 if (error)
2548 goto out;
2549 ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
2550 error = smbfs_smb_findnext(ctx, 1, scrp);
2551 if (error == 0) {
2552 *fap = ctx->f_attr;
2553 /*
2554 * Solaris smbfattr doesn't have fa_ino,
2555 * and we don't allow name==NULL in this
2556 * function anymore.
2557 */
2558 if (namep)
2559 *namep = (const char *)smbfs_name_alloc(
2560 ctx->f_name, ctx->f_nmlen);
2561 if (nmlenp)
2562 *nmlenp = ctx->f_nmlen;
2563 }
2564 (void) smbfs_smb_findclose(ctx, scrp);
2565
2566 out:
2567 smbfs_rw_exit(&dnp->r_lkserlock);
2568 return (error);
2569 }
2570
2571 /*
2572 * OTW function to Get a security descriptor (SD).
2573 *
2574 * Note: On success, this fills in mdp->md_top,
2575 * which the caller should free.
2576 */
2577 int
smbfs_smb_getsec_m(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp,uint32_t selector,mblk_t ** res,uint32_t * reslen)2578 smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
2579 struct smb_cred *scrp, uint32_t selector,
2580 mblk_t **res, uint32_t *reslen)
2581 {
2582 struct smb_ntrq *ntp;
2583 struct mbchain *mbp;
2584 struct mdchain *mdp;
2585 int error, len;
2586
2587 error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
2588 scrp, &ntp);
2589 if (error)
2590 return (error);
2591
2592 /* Parameters part */
2593 mbp = &ntp->nt_tparam;
2594 mb_init(mbp);
2595 mb_put_uint16le(mbp, fid);
2596 mb_put_uint16le(mbp, 0); /* reserved */
2597 mb_put_uint32le(mbp, selector);
2598 /* Data part (none) */
2599
2600 /* Max. returned parameters and data. */
2601 ntp->nt_maxpcount = 4;
2602 ntp->nt_maxdcount = *reslen;
2603
2604 error = smb_nt_request(ntp);
2605 if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
2606 goto done;
2607 *res = NULL;
2608
2609 /*
2610 * if there's more data than we said we could receive, here
2611 * is where we pick up the length of it
2612 */
2613 mdp = &ntp->nt_rparam;
2614 md_get_uint32le(mdp, reslen);
2615 if (error)
2616 goto done;
2617
2618 /*
2619 * get the data part.
2620 */
2621 mdp = &ntp->nt_rdata;
2622 if (mdp->md_top == NULL) {
2623 SMBVDEBUG("null md_top? fid 0x%x\n", fid);
2624 error = EBADRPC;
2625 goto done;
2626 }
2627
2628 /*
2629 * The returned parameter SD_length should match
2630 * the length of the returned data. Unfortunately,
2631 * we have to work around server bugs here.
2632 */
2633 len = m_fixhdr(mdp->md_top);
2634 if (len != *reslen) {
2635 SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
2636 len, *reslen, fid);
2637 }
2638
2639 /*
2640 * Actual data provided is < returned SD_length.
2641 *
2642 * The following "if (len < *reslen)" handles a Windows bug
2643 * observed when the underlying filesystem is FAT32. In that
2644 * case a 32 byte security descriptor comes back (S-1-1-0, ie
2645 * "Everyone") but the Parameter Block claims 44 is the length
2646 * of the security descriptor. (The Data Block length
2647 * claimed is 32. This server bug was reported against NT
2648 * first and I've personally observed it with W2K.
2649 */
2650 if (len < *reslen)
2651 *reslen = len;
2652
2653 /*
2654 * Actual data provided is > returned SD_length.
2655 * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
2656 * Narrow work-around for returned SD_length==0.
2657 */
2658 if (len > *reslen) {
2659 /*
2660 * Increase *reslen, but carefully.
2661 */
2662 if (*reslen == 0 && len <= ntp->nt_maxdcount)
2663 *reslen = len;
2664 }
2665 error = md_get_mbuf(mdp, len, res);
2666
2667 done:
2668 if (error == 0 && *res == NULL) {
2669 ASSERT(*res);
2670 error = EBADRPC;
2671 }
2672
2673 smb_nt_done(ntp);
2674 return (error);
2675 }
2676
2677 #ifdef APPLE
2678 /*
2679 * Wrapper for _getsd() compatible with darwin code.
2680 */
2681 int
smbfs_smb_getsec(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp,uint32_t selector,struct ntsecdesc ** res)2682 smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
2683 uint32_t selector, struct ntsecdesc **res)
2684 {
2685 int error;
2686 uint32_t len, olen;
2687 struct mdchain *mdp, md_store;
2688 struct mbuf *m;
2689
2690 bzero(mdp, sizeof (*mdp));
2691 len = 500; /* "overlarge" values => server errors */
2692 again:
2693 olen = len;
2694 error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
2695 /*
2696 * Server may give us an error indicating that we
2697 * need a larger data buffer to receive the SD,
2698 * and the size we'll need. Use the given size,
2699 * but only after a sanity check.
2700 *
2701 * XXX: Check for specific error values here?
2702 * XXX: also ... && len <= MAX_RAW_SD_SIZE
2703 */
2704 if (error && len > olen)
2705 goto again;
2706
2707 if (error)
2708 return (error);
2709
2710 mdp = &md_store;
2711 md_initm(mdp, m);
2712 MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
2713 error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
2714 md_done(mdp);
2715
2716 return (error);
2717 }
2718 #endif /* APPLE */
2719
2720 /*
2721 * OTW function to Set a security descriptor (SD).
2722 * Caller data are carried in an mbchain_t.
2723 *
2724 * Note: This normally consumes mbp->mb_top, and clears
2725 * that pointer when it does.
2726 */
smbfs_smb_setsec_m(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp,uint32_t selector,mblk_t ** mp)2727 int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
2728 struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
2729 {
2730 struct smb_ntrq *ntp;
2731 struct mbchain *mbp;
2732 int error;
2733
2734 error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
2735 scrp, &ntp);
2736 if (error)
2737 return (error);
2738
2739 /* Parameters part */
2740 mbp = &ntp->nt_tparam;
2741 mb_init(mbp);
2742 mb_put_uint16le(mbp, fid);
2743 mb_put_uint16le(mbp, 0); /* reserved */
2744 mb_put_uint32le(mbp, selector);
2745
2746 /* Data part */
2747 mbp = &ntp->nt_tdata;
2748 mb_initm(mbp, *mp);
2749 *mp = NULL; /* consumed */
2750
2751 /* No returned parameters or data. */
2752 ntp->nt_maxpcount = 0;
2753 ntp->nt_maxdcount = 0;
2754
2755 error = smb_nt_request(ntp);
2756 smb_nt_done(ntp);
2757
2758 return (error);
2759 }
2760
2761 #ifdef APPLE
2762 /*
2763 * This function builds the SD given the various parts.
2764 */
2765 int
smbfs_smb_setsec(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp,uint32_t selector,uint16_t flags,struct ntsid * owner,struct ntsid * group,struct ntacl * sacl,struct ntacl * dacl)2766 smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
2767 uint32_t selector, uint16_t flags, struct ntsid *owner,
2768 struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
2769 {
2770 struct mbchain *mbp, mb_store;
2771 struct ntsecdesc ntsd;
2772 int error, off;
2773
2774 /*
2775 * Build the SD as its own mbuf chain and pass it to
2776 * smbfs_smb_setsec_m()
2777 */
2778 mbp = &mb_store;
2779 mb_init(mbp);
2780 bzero(&ntsd, sizeof (ntsd));
2781 wset_sdrevision(&ntsd);
2782 /*
2783 * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
2784 * We set here only those bits we can be sure must be set. The rest
2785 * are up to the caller. In particular, the caller may intentionally
2786 * set an acl PRESENT bit while giving us a null pointer for the
2787 * acl - that sets a null acl, giving access to everyone. Note also
2788 * that the AUTO_INHERITED bits should probably always be set unless
2789 * the server is NT.
2790 */
2791 flags |= SD_SELF_RELATIVE;
2792 off = sizeof (ntsd);
2793 if (owner) {
2794 wset_sdowneroff(&ntsd, off);
2795 off += sidlen(owner);
2796 }
2797 if (group) {
2798 wset_sdgroupoff(&ntsd, off);
2799 off += sidlen(group);
2800 }
2801 if (sacl) {
2802 flags |= SD_SACL_PRESENT;
2803 wset_sdsacloff(&ntsd, off);
2804 off += acllen(sacl);
2805 }
2806 if (dacl) {
2807 flags |= SD_DACL_PRESENT;
2808 wset_sddacloff(&ntsd, off);
2809 }
2810 wset_sdflags(&ntsd, flags);
2811 mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
2812 if (owner)
2813 mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
2814 if (group)
2815 mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
2816 if (sacl)
2817 mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
2818 if (dacl)
2819 mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
2820
2821 /*
2822 * Just pass the mbuf to _setsec_m
2823 * It will clear mb_top if consumed.
2824 */
2825 error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
2826 mb_done(mbp);
2827
2828 return (error);
2829 }
2830
2831 #endif /* APPLE */
2832