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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/kernel.h> 31#include <sys/malloc.h> 32#include <sys/proc.h> 33#include <sys/lock.h> 34#include <sys/vnode.h> 35#include <sys/mbuf.h> 36#include <sys/mount.h> 37#include <sys/endian.h> 38 39#ifdef USE_MD5_HASH 40#include <sys/md5.h> 41#endif 42 43#include <netsmb/smb.h> 44#include <netsmb/smb_subr.h> 45#include <netsmb/smb_rq.h> 46#include <netsmb/smb_conn.h> 47 48#include <fs/smbfs/smbfs.h> 49#include <fs/smbfs/smbfs_node.h> 50#include <fs/smbfs/smbfs_subr.h> 51 52/* 53 * Lack of inode numbers leads us to the problem of generating them. 54 * Partially this problem can be solved by having a dir/file cache 55 * with inode numbers generated from the incremented by one counter. 56 * However this way will require too much kernel memory, gives all 57 * sorts of locking and consistency problems, not to mentinon counter overflows. 58 * So, I'm decided to use a hash function to generate pseudo random (and unique) 59 * inode numbers. 60 */ 61static long 62smbfs_getino(struct smbnode *dnp, const char *name, int nmlen) 63{ 64#ifdef USE_MD5_HASH 65 MD5_CTX md5; 66 u_int32_t state[4]; 67 long ino; 68 int i; 69 70 MD5Init(&md5); 71 MD5Update(&md5, name, nmlen); 72 MD5Final((u_char *)state, &md5); 73 for (i = 0, ino = 0; i < 4; i++) 74 ino += state[i]; 75 return dnp->n_ino + ino; 76#endif 77 u_int32_t ino; 78 79 ino = dnp->n_ino + smbfs_hash(name, nmlen); 80 if (ino <= 2) 81 ino += 3; 82 return ino; 83} 84 85static int 86smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end, 87 struct smb_cred *scred) 88{ 89 struct smb_share *ssp = np->n_mount->sm_share; 90 struct smb_rq rq, *rqp = &rq; 91 struct mbchain *mbp; 92 u_char ltype = 0; 93 int error; 94 95 if (op == SMB_LOCK_SHARED) 96 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; 97 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred); 98 if (error) 99 return error; 100 smb_rq_getrequest(rqp, &mbp); 101 smb_rq_wstart(rqp); 102 mb_put_uint8(mbp, 0xff); /* secondary command */ 103 mb_put_uint8(mbp, 0); /* MBZ */ 104 mb_put_uint16le(mbp, 0); 105 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 106 mb_put_uint8(mbp, ltype); /* locktype */ 107 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ 108 mb_put_uint32le(mbp, 0); /* timeout - break immediately */ 109 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); 110 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); 111 smb_rq_wend(rqp); 112 smb_rq_bstart(rqp); 113 mb_put_uint16le(mbp, pid); 114 mb_put_uint32le(mbp, start); 115 mb_put_uint32le(mbp, end - start); 116 smb_rq_bend(rqp); 117 error = smb_rq_simple(rqp); 118 smb_rq_done(rqp); 119 return error; 120} 121 122int 123smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, 124 off_t start, off_t end, struct smb_cred *scred) 125{ 126 struct smb_share *ssp = np->n_mount->sm_share; 127 128 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) 129 /* 130 * TODO: use LOCK_BYTE_RANGE here. 131 */ 132 return EINVAL; 133 else 134 return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred); 135} 136 137static int 138smbfs_query_info_fs(struct smb_share *ssp, struct statfs *sbp, 139 struct smb_cred *scred) 140{ 141 struct smb_t2rq *t2p; 142 struct mbchain *mbp; 143 struct mdchain *mdp; 144 uint32_t bsize, bpu; 145 int64_t units, funits; 146 int error; 147 148 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 149 scred, &t2p); 150 if (error) 151 return (error); 152 mbp = &t2p->t2_tparam; 153 mb_init(mbp); 154 mb_put_uint16le(mbp, SMB_QUERY_FS_SIZE_INFO); 155 t2p->t2_maxpcount = 2; 156 t2p->t2_maxdcount = sizeof(int64_t) * 2 + sizeof(uint32_t) * 2; 157 error = smb_t2_request(t2p); 158 if (error) { 159 smb_t2_done(t2p); 160 return (error); 161 } 162 mdp = &t2p->t2_rdata; 163 md_get_int64le(mdp, &units); 164 md_get_int64le(mdp, &funits); 165 md_get_uint32le(mdp, &bpu); 166 md_get_uint32le(mdp, &bsize); 167 sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 168 sbp->f_blocks= (uint64_t)units; /* total data blocks in filesystem */ 169 sbp->f_bfree = (uint64_t)funits;/* free blocks in fs */ 170 sbp->f_bavail= (uint64_t)funits;/* free blocks avail to non-superuser */ 171 sbp->f_files = 0xffff; /* total file nodes in filesystem */ 172 sbp->f_ffree = 0xffff; /* free file nodes in fs */ 173 smb_t2_done(t2p); 174 return (0); 175} 176 177 178static int 179smbfs_query_info_alloc(struct smb_share *ssp, struct statfs *sbp, 180 struct smb_cred *scred) 181{ 182 struct smb_t2rq *t2p; 183 struct mbchain *mbp; 184 struct mdchain *mdp; 185 u_int16_t bsize; 186 u_int32_t units, bpu, funits; 187 int error; 188 189 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 190 scred, &t2p); 191 if (error) 192 return error; 193 mbp = &t2p->t2_tparam; 194 mb_init(mbp); 195 mb_put_uint16le(mbp, SMB_INFO_ALLOCATION); 196 t2p->t2_maxpcount = 4; 197 t2p->t2_maxdcount = 4 * 4 + 2; 198 error = smb_t2_request(t2p); 199 if (error) { 200 smb_t2_done(t2p); 201 return error; 202 } 203 mdp = &t2p->t2_rdata; 204 md_get_uint32(mdp, NULL); /* fs id */ 205 md_get_uint32le(mdp, &bpu); 206 md_get_uint32le(mdp, &units); 207 md_get_uint32le(mdp, &funits); 208 md_get_uint16le(mdp, &bsize); 209 sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 210 sbp->f_blocks= units; /* total data blocks in filesystem */ 211 sbp->f_bfree = funits; /* free blocks in fs */ 212 sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 213 sbp->f_files = 0xffff; /* total file nodes in filesystem */ 214 sbp->f_ffree = 0xffff; /* free file nodes in fs */ 215 smb_t2_done(t2p); 216 return 0; 217} 218 219static int 220smbfs_query_info_disk(struct smb_share *ssp, struct statfs *sbp, 221 struct smb_cred *scred) 222{ 223 struct smb_rq rq, *rqp = &rq; 224 struct mdchain *mdp; 225 u_int16_t units, bpu, bsize, funits; 226 int error; 227 228 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred); 229 if (error) 230 return error; 231 smb_rq_wstart(rqp); 232 smb_rq_wend(rqp); 233 smb_rq_bstart(rqp); 234 smb_rq_bend(rqp); 235 error = smb_rq_simple(rqp); 236 if (error) { 237 smb_rq_done(rqp); 238 return error; 239 } 240 smb_rq_getreply(rqp, &mdp); 241 md_get_uint16le(mdp, &units); 242 md_get_uint16le(mdp, &bpu); 243 md_get_uint16le(mdp, &bsize); 244 md_get_uint16le(mdp, &funits); 245 sbp->f_bsize = bpu * bsize; /* fundamental filesystem block size */ 246 sbp->f_blocks= units; /* total data blocks in filesystem */ 247 sbp->f_bfree = funits; /* free blocks in fs */ 248 sbp->f_bavail= funits; /* free blocks avail to non-superuser */ 249 sbp->f_files = 0xffff; /* total file nodes in filesystem */ 250 sbp->f_ffree = 0xffff; /* free file nodes in fs */ 251 smb_rq_done(rqp); 252 return 0; 253} 254 255int 256smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, 257 struct smb_cred *scred) 258{ 259 260 if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) { 261 if (smbfs_query_info_fs(ssp, sbp, scred) == 0) 262 return (0); 263 if (smbfs_query_info_alloc(ssp, sbp, scred) == 0) 264 return (0); 265 } 266 return (smbfs_query_info_disk(ssp, sbp, scred)); 267} 268 269static int 270smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred) 271{ 272 struct smb_t2rq *t2p; 273 struct smb_share *ssp = np->n_mount->sm_share; 274 struct mbchain *mbp; 275 int error; 276 277 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 278 scred, &t2p); 279 if (error) 280 return error; 281 mbp = &t2p->t2_tparam; 282 mb_init(mbp); 283 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 284 mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO); 285 mb_put_uint32le(mbp, 0); 286 mbp = &t2p->t2_tdata; 287 mb_init(mbp); 288 mb_put_int64le(mbp, newsize); 289 mb_put_uint32le(mbp, 0); /* padding */ 290 mb_put_uint16le(mbp, 0); 291 t2p->t2_maxpcount = 2; 292 t2p->t2_maxdcount = 0; 293 error = smb_t2_request(t2p); 294 smb_t2_done(t2p); 295 return error; 296} 297 298static int 299smb_smb_flush(struct smbnode *np, struct smb_cred *scred) 300{ 301 struct smb_share *ssp = np->n_mount->sm_share; 302 struct smb_rq rq, *rqp = &rq; 303 struct mbchain *mbp; 304 int error; 305 306 if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) || 307 SMBTOV(np)->v_type != VREG) 308 return 0; /* not a regular open file */ 309 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred); 310 if (error) 311 return (error); 312 smb_rq_getrequest(rqp, &mbp); 313 smb_rq_wstart(rqp); 314 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 315 smb_rq_wend(rqp); 316 smb_rq_bstart(rqp); 317 smb_rq_bend(rqp); 318 error = smb_rq_simple(rqp); 319 smb_rq_done(rqp); 320 if (!error) 321 np->n_flag &= ~NFLUSHWIRE; 322 return (error); 323} 324 325int 326smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred) 327{ 328 if (np->n_flag & NFLUSHWIRE) 329 return (smb_smb_flush(np, scred)); 330 return (0); 331} 332 333int 334smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) 335{ 336 struct smb_share *ssp = np->n_mount->sm_share; 337 struct smb_rq rq, *rqp = &rq; 338 struct mbchain *mbp; 339 int error; 340 341 if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) { 342 np->n_flag |= NFLUSHWIRE; 343 return (0); 344 } 345 346 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred); 347 if (error) 348 return error; 349 smb_rq_getrequest(rqp, &mbp); 350 smb_rq_wstart(rqp); 351 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 352 mb_put_uint16le(mbp, 0); 353 mb_put_uint32le(mbp, newsize); 354 mb_put_uint16le(mbp, 0); 355 smb_rq_wend(rqp); 356 smb_rq_bstart(rqp); 357 mb_put_uint8(mbp, SMB_DT_DATA); 358 mb_put_uint16le(mbp, 0); 359 smb_rq_bend(rqp); 360 error = smb_rq_simple(rqp); 361 smb_rq_done(rqp); 362 return error; 363} 364 365int 366smbfs_smb_query_info(struct smbnode *np, const char *name, int len, 367 struct smbfattr *fap, struct smb_cred *scred) 368{ 369 struct smb_rq rq, *rqp = &rq; 370 struct smb_share *ssp = np->n_mount->sm_share; 371 struct mbchain *mbp; 372 struct mdchain *mdp; 373 u_int8_t wc; 374 int error; 375 u_int16_t wattr; 376 u_int32_t lint; 377 378 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred); 379 if (error) 380 return error; 381 smb_rq_getrequest(rqp, &mbp); 382 smb_rq_wstart(rqp); 383 smb_rq_wend(rqp); 384 smb_rq_bstart(rqp); 385 mb_put_uint8(mbp, SMB_DT_ASCII); 386 do { 387 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len); 388 if (error) 389 break; 390 smb_rq_bend(rqp); 391 error = smb_rq_simple(rqp); 392 if (error) 393 break; 394 smb_rq_getreply(rqp, &mdp); 395 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) { 396 error = EBADRPC; 397 break; 398 } 399 md_get_uint16le(mdp, &wattr); 400 fap->fa_attr = wattr; 401 /* 402 * Be careful using the time returned here, as 403 * with FAT on NT4SP6, at least, the time returned is low 404 * 32 bits of 100s of nanoseconds (since 1601) so it rolls 405 * over about every seven minutes! 406 */ 407 md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */ 408 if (lint) /* avoid bogus zero returns */ 409 smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz, 410 &fap->fa_mtime); 411 md_get_uint32le(mdp, &lint); 412 fap->fa_size = lint; 413 } while(0); 414 smb_rq_done(rqp); 415 return error; 416} 417 418/* 419 * Set DOS file attributes. mtime should be NULL for dialects above lm10 420 */ 421int 422smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 423 struct smb_cred *scred) 424{ 425 struct smb_rq rq, *rqp = &rq; 426 struct smb_share *ssp = np->n_mount->sm_share; 427 struct mbchain *mbp; 428 u_long time; 429 int error, svtz; 430 431 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred); 432 if (error) 433 return error; 434 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 435 smb_rq_getrequest(rqp, &mbp); 436 smb_rq_wstart(rqp); 437 mb_put_uint16le(mbp, attr); 438 if (mtime) { 439 smb_time_local2server(mtime, svtz, &time); 440 } else 441 time = 0; 442 mb_put_uint32le(mbp, time); /* mtime */ 443 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); 444 smb_rq_wend(rqp); 445 smb_rq_bstart(rqp); 446 mb_put_uint8(mbp, SMB_DT_ASCII); 447 do { 448 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 449 if (error) 450 break; 451 mb_put_uint8(mbp, SMB_DT_ASCII); 452 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { 453 mb_put_padbyte(mbp); 454 mb_put_uint8(mbp, 0); /* 1st byte of NULL Unicode char */ 455 } 456 mb_put_uint8(mbp, 0); 457 smb_rq_bend(rqp); 458 error = smb_rq_simple(rqp); 459 if (error) { 460 SMBERROR("smb_rq_simple(rqp) => error %d\n", error); 461 break; 462 } 463 } while(0); 464 smb_rq_done(rqp); 465 return error; 466} 467 468/* 469 * Note, win95 doesn't support this call. 470 */ 471int 472smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, 473 struct timespec *atime, int attr, struct smb_cred *scred) 474{ 475 struct smb_t2rq *t2p; 476 struct smb_share *ssp = np->n_mount->sm_share; 477 struct smb_vc *vcp = SSTOVC(ssp); 478 struct mbchain *mbp; 479 u_int16_t date, time; 480 int error, tzoff; 481 482 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 483 scred, &t2p); 484 if (error) 485 return error; 486 mbp = &t2p->t2_tparam; 487 mb_init(mbp); 488 mb_put_uint16le(mbp, SMB_INFO_STANDARD); 489 mb_put_uint32le(mbp, 0); /* MBZ */ 490 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 491 error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 492 if (error) { 493 smb_t2_done(t2p); 494 return error; 495 } 496 tzoff = vcp->vc_sopt.sv_tz; 497 mbp = &t2p->t2_tdata; 498 mb_init(mbp); 499 mb_put_uint32le(mbp, 0); /* creation time */ 500 if (atime) 501 smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 502 else 503 time = date = 0; 504 mb_put_uint16le(mbp, date); 505 mb_put_uint16le(mbp, time); 506 if (mtime) 507 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 508 else 509 time = date = 0; 510 mb_put_uint16le(mbp, date); 511 mb_put_uint16le(mbp, time); 512 mb_put_uint32le(mbp, 0); /* file size */ 513 mb_put_uint32le(mbp, 0); /* allocation unit size */ 514 mb_put_uint16le(mbp, attr); /* DOS attr */ 515 mb_put_uint32le(mbp, 0); /* EA size */ 516 t2p->t2_maxpcount = 5 * 2; 517 t2p->t2_maxdcount = vcp->vc_txmax; 518 error = smb_t2_request(t2p); 519 smb_t2_done(t2p); 520 return error; 521} 522 523/* 524 * NT level. Specially for win9x 525 */ 526int 527smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, 528 struct timespec *atime, struct smb_cred *scred) 529{ 530 struct smb_t2rq *t2p; 531 struct smb_share *ssp = np->n_mount->sm_share; 532 struct smb_vc *vcp = SSTOVC(ssp); 533 struct mbchain *mbp; 534 int64_t tm; 535 int error, tzoff; 536 537 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 538 scred, &t2p); 539 if (error) 540 return error; 541 mbp = &t2p->t2_tparam; 542 mb_init(mbp); 543 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 544 mb_put_uint32le(mbp, 0); /* MBZ */ 545 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 546 error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 547 if (error) { 548 smb_t2_done(t2p); 549 return error; 550 } 551 tzoff = vcp->vc_sopt.sv_tz; 552 mbp = &t2p->t2_tdata; 553 mb_init(mbp); 554 mb_put_int64le(mbp, 0); /* creation time */ 555 if (atime) { 556 smb_time_local2NT(atime, tzoff, &tm); 557 } else 558 tm = 0; 559 mb_put_int64le(mbp, tm); 560 if (mtime) { 561 smb_time_local2NT(mtime, tzoff, &tm); 562 } else 563 tm = 0; 564 mb_put_int64le(mbp, tm); 565 mb_put_int64le(mbp, tm); /* change time */ 566 mb_put_uint32le(mbp, attr); /* attr */ 567 t2p->t2_maxpcount = 24; 568 t2p->t2_maxdcount = 56; 569 error = smb_t2_request(t2p); 570 smb_t2_done(t2p); 571 return error; 572} 573 574/* 575 * Set file atime and mtime. Doesn't supported by core dialect. 576 */ 577int 578smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime, 579 struct timespec *atime, struct smb_cred *scred) 580{ 581 struct smb_rq rq, *rqp = &rq; 582 struct smb_share *ssp = np->n_mount->sm_share; 583 struct mbchain *mbp; 584 u_int16_t date, time; 585 int error, tzoff; 586 587 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred); 588 if (error) 589 return error; 590 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 591 smb_rq_getrequest(rqp, &mbp); 592 smb_rq_wstart(rqp); 593 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 594 mb_put_uint32le(mbp, 0); /* creation time */ 595 596 if (atime) 597 smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 598 else 599 time = date = 0; 600 mb_put_uint16le(mbp, date); 601 mb_put_uint16le(mbp, time); 602 if (mtime) 603 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 604 else 605 time = date = 0; 606 mb_put_uint16le(mbp, date); 607 mb_put_uint16le(mbp, time); 608 smb_rq_wend(rqp); 609 smb_rq_bstart(rqp); 610 smb_rq_bend(rqp); 611 error = smb_rq_simple(rqp); 612 SMBSDEBUG("%d\n", error); 613 smb_rq_done(rqp); 614 return error; 615} 616 617/* 618 * Set DOS file attributes. 619 * Looks like this call can be used only if SMB_CAP_NT_SMBS bit is on. 620 */ 621int 622smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 623 struct timespec *atime, struct smb_cred *scred) 624{ 625 struct smb_t2rq *t2p; 626 struct smb_share *ssp = np->n_mount->sm_share; 627 struct mbchain *mbp; 628 int64_t tm; 629 int error, svtz; 630 631 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 632 scred, &t2p); 633 if (error) 634 return error; 635 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 636 mbp = &t2p->t2_tparam; 637 mb_init(mbp); 638 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 639 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); 640 mb_put_uint32le(mbp, 0); 641 mbp = &t2p->t2_tdata; 642 mb_init(mbp); 643 mb_put_int64le(mbp, 0); /* creation time */ 644 if (atime) { 645 smb_time_local2NT(atime, svtz, &tm); 646 } else 647 tm = 0; 648 mb_put_int64le(mbp, tm); 649 if (mtime) { 650 smb_time_local2NT(mtime, svtz, &tm); 651 } else 652 tm = 0; 653 mb_put_int64le(mbp, tm); 654 mb_put_int64le(mbp, tm); /* change time */ 655 mb_put_uint16le(mbp, attr); 656 mb_put_uint32le(mbp, 0); /* padding */ 657 mb_put_uint16le(mbp, 0); 658 t2p->t2_maxpcount = 2; 659 t2p->t2_maxdcount = 0; 660 error = smb_t2_request(t2p); 661 smb_t2_done(t2p); 662 return error; 663} 664 665 666int 667smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) 668{ 669 struct smb_rq rq, *rqp = &rq; 670 struct smb_share *ssp = np->n_mount->sm_share; 671 struct mbchain *mbp; 672 struct mdchain *mdp; 673 u_int8_t wc; 674 u_int16_t fid, wattr, grantedmode; 675 int error; 676 677 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred); 678 if (error) 679 return error; 680 smb_rq_getrequest(rqp, &mbp); 681 smb_rq_wstart(rqp); 682 mb_put_uint16le(mbp, accmode); 683 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 684 smb_rq_wend(rqp); 685 smb_rq_bstart(rqp); 686 mb_put_uint8(mbp, SMB_DT_ASCII); 687 do { 688 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 689 if (error) 690 break; 691 smb_rq_bend(rqp); 692 error = smb_rq_simple(rqp); 693 if (error) 694 break; 695 smb_rq_getreply(rqp, &mdp); 696 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { 697 error = EBADRPC; 698 break; 699 } 700 md_get_uint16(mdp, &fid); 701 md_get_uint16le(mdp, &wattr); 702 md_get_uint32(mdp, NULL); /* mtime */ 703 md_get_uint32(mdp, NULL); /* fsize */ 704 md_get_uint16le(mdp, &grantedmode); 705 /* 706 * TODO: refresh attributes from this reply 707 */ 708 } while(0); 709 smb_rq_done(rqp); 710 if (error) 711 return error; 712 np->n_fid = fid; 713 np->n_rwstate = grantedmode; 714 return 0; 715} 716 717 718int 719smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, 720 struct smb_cred *scred) 721{ 722 struct smb_rq rq, *rqp = &rq; 723 struct mbchain *mbp; 724 u_long time; 725 int error; 726 727 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred); 728 if (error) 729 return error; 730 smb_rq_getrequest(rqp, &mbp); 731 smb_rq_wstart(rqp); 732 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 733 if (mtime) { 734 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); 735 } else 736 time = 0; 737 mb_put_uint32le(mbp, time); 738 smb_rq_wend(rqp); 739 smb_rq_bstart(rqp); 740 smb_rq_bend(rqp); 741 error = smb_rq_simple(rqp); 742 smb_rq_done(rqp); 743 return error; 744} 745 746int 747smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, 748 struct smb_cred *scred) 749{ 750 struct smb_rq rq, *rqp = &rq; 751 struct smb_share *ssp = dnp->n_mount->sm_share; 752 struct mbchain *mbp; 753 struct mdchain *mdp; 754 struct timespec ctime; 755 u_int8_t wc; 756 u_int16_t fid; 757 u_long tm; 758 int error; 759 760 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred); 761 if (error) 762 return error; 763 smb_rq_getrequest(rqp, &mbp); 764 smb_rq_wstart(rqp); 765 mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ 766 nanotime(&ctime); 767 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 768 mb_put_uint32le(mbp, tm); 769 smb_rq_wend(rqp); 770 smb_rq_bstart(rqp); 771 mb_put_uint8(mbp, SMB_DT_ASCII); 772 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); 773 if (!error) { 774 smb_rq_bend(rqp); 775 error = smb_rq_simple(rqp); 776 if (!error) { 777 smb_rq_getreply(rqp, &mdp); 778 md_get_uint8(mdp, &wc); 779 if (wc == 1) 780 md_get_uint16(mdp, &fid); 781 else 782 error = EBADRPC; 783 } 784 } 785 smb_rq_done(rqp); 786 if (error) 787 return error; 788 smbfs_smb_close(ssp, fid, &ctime, scred); 789 return error; 790} 791 792int 793smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred) 794{ 795 struct smb_rq rq, *rqp = &rq; 796 struct smb_share *ssp = np->n_mount->sm_share; 797 struct mbchain *mbp; 798 int error; 799 800 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred); 801 if (error) 802 return error; 803 smb_rq_getrequest(rqp, &mbp); 804 smb_rq_wstart(rqp); 805 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 806 smb_rq_wend(rqp); 807 smb_rq_bstart(rqp); 808 mb_put_uint8(mbp, SMB_DT_ASCII); 809 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 810 if (!error) { 811 smb_rq_bend(rqp); 812 error = smb_rq_simple(rqp); 813 } 814 smb_rq_done(rqp); 815 return error; 816} 817 818int 819smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 820 const char *tname, int tnmlen, struct smb_cred *scred) 821{ 822 struct smb_rq rq, *rqp = &rq; 823 struct smb_share *ssp = src->n_mount->sm_share; 824 struct mbchain *mbp; 825 int error; 826 827 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred); 828 if (error) 829 return error; 830 smb_rq_getrequest(rqp, &mbp); 831 smb_rq_wstart(rqp); 832 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 833 smb_rq_wend(rqp); 834 smb_rq_bstart(rqp); 835 mb_put_uint8(mbp, SMB_DT_ASCII); 836 do { 837 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 838 if (error) 839 break; 840 mb_put_uint8(mbp, SMB_DT_ASCII); 841 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 842 if (error) 843 break; 844 smb_rq_bend(rqp); 845 error = smb_rq_simple(rqp); 846 } while(0); 847 smb_rq_done(rqp); 848 return error; 849} 850 851int 852smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 853 const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred) 854{ 855 struct smb_rq rq, *rqp = &rq; 856 struct smb_share *ssp = src->n_mount->sm_share; 857 struct mbchain *mbp; 858 int error; 859 860 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred); 861 if (error) 862 return error; 863 smb_rq_getrequest(rqp, &mbp); 864 smb_rq_wstart(rqp); 865 mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 866 mb_put_uint16le(mbp, 0x20); /* delete target file */ 867 mb_put_uint16le(mbp, flags); 868 smb_rq_wend(rqp); 869 smb_rq_bstart(rqp); 870 mb_put_uint8(mbp, SMB_DT_ASCII); 871 do { 872 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 873 if (error) 874 break; 875 mb_put_uint8(mbp, SMB_DT_ASCII); 876 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 877 if (error) 878 break; 879 smb_rq_bend(rqp); 880 error = smb_rq_simple(rqp); 881 } while(0); 882 smb_rq_done(rqp); 883 return error; 884} 885 886int 887smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, 888 struct smb_cred *scred) 889{ 890 struct smb_rq rq, *rqp = &rq; 891 struct smb_share *ssp = dnp->n_mount->sm_share; 892 struct mbchain *mbp; 893 int error; 894 895 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred); 896 if (error) 897 return error; 898 smb_rq_getrequest(rqp, &mbp); 899 smb_rq_wstart(rqp); 900 smb_rq_wend(rqp); 901 smb_rq_bstart(rqp); 902 mb_put_uint8(mbp, SMB_DT_ASCII); 903 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len); 904 if (!error) { 905 smb_rq_bend(rqp); 906 error = smb_rq_simple(rqp); 907 } 908 smb_rq_done(rqp); 909 return error; 910} 911 912int 913smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred) 914{ 915 struct smb_rq rq, *rqp = &rq; 916 struct smb_share *ssp = np->n_mount->sm_share; 917 struct mbchain *mbp; 918 int error; 919 920 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred); 921 if (error) 922 return error; 923 smb_rq_getrequest(rqp, &mbp); 924 smb_rq_wstart(rqp); 925 smb_rq_wend(rqp); 926 smb_rq_bstart(rqp); 927 mb_put_uint8(mbp, SMB_DT_ASCII); 928 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 929 if (!error) { 930 smb_rq_bend(rqp); 931 error = smb_rq_simple(rqp); 932 } 933 smb_rq_done(rqp); 934 return error; 935} 936 937static int 938smbfs_smb_search(struct smbfs_fctx *ctx) 939{ 940 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 941 struct smb_rq *rqp; 942 struct mbchain *mbp; 943 struct mdchain *mdp; 944 u_int8_t wc, bt; 945 u_int16_t ec, dlen, bc; 946 int maxent, error, iseof = 0; 947 948 maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); 949 if (ctx->f_rq) { 950 smb_rq_done(ctx->f_rq); 951 ctx->f_rq = NULL; 952 } 953 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); 954 if (error) 955 return error; 956 ctx->f_rq = rqp; 957 smb_rq_getrequest(rqp, &mbp); 958 smb_rq_wstart(rqp); 959 mb_put_uint16le(mbp, maxent); /* max entries to return */ 960 mb_put_uint16le(mbp, ctx->f_attrmask); 961 smb_rq_wend(rqp); 962 smb_rq_bstart(rqp); 963 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 964 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 965 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 966 if (error) 967 return error; 968 mb_put_uint8(mbp, SMB_DT_VARIABLE); 969 mb_put_uint16le(mbp, 0); /* context length */ 970 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 971 } else { 972 if (SMB_UNICODE_STRINGS(vcp)) { 973 mb_put_padbyte(mbp); 974 mb_put_uint8(mbp, 0); 975 } 976 mb_put_uint8(mbp, 0); /* file name length */ 977 mb_put_uint8(mbp, SMB_DT_VARIABLE); 978 mb_put_uint16le(mbp, SMB_SKEYLEN); 979 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 980 } 981 smb_rq_bend(rqp); 982 error = smb_rq_simple(rqp); 983 if (error) { 984 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { 985 error = 0; 986 iseof = 1; 987 ctx->f_flags |= SMBFS_RDD_EOF; 988 } else 989 return error; 990 } 991 smb_rq_getreply(rqp, &mdp); 992 md_get_uint8(mdp, &wc); 993 if (wc != 1) 994 return iseof ? ENOENT : EBADRPC; 995 md_get_uint16le(mdp, &ec); 996 if (ec == 0) 997 return ENOENT; 998 ctx->f_ecnt = ec; 999 md_get_uint16le(mdp, &bc); 1000 if (bc < 3) 1001 return EBADRPC; 1002 bc -= 3; 1003 md_get_uint8(mdp, &bt); 1004 if (bt != SMB_DT_VARIABLE) 1005 return EBADRPC; 1006 md_get_uint16le(mdp, &dlen); 1007 if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 1008 return EBADRPC; 1009 return 0; 1010} 1011 1012static int 1013smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 1014 const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1015{ 1016 ctx->f_attrmask = attr; 1017 if (wildcard) { 1018 if (wclen == 1 && wildcard[0] == '*') { 1019 ctx->f_wildcard = "*.*"; 1020 ctx->f_wclen = 3; 1021 } else { 1022 ctx->f_wildcard = wildcard; 1023 ctx->f_wclen = wclen; 1024 } 1025 } else { 1026 ctx->f_wildcard = NULL; 1027 ctx->f_wclen = 0; 1028 } 1029 ctx->f_name = ctx->f_fname; 1030 return 0; 1031} 1032 1033static int 1034smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) 1035{ 1036 struct mdchain *mbp; 1037 struct smb_rq *rqp; 1038 char *cp; 1039 u_int8_t battr; 1040 u_int16_t date, time; 1041 u_int32_t size; 1042 int error; 1043 1044 if (ctx->f_ecnt == 0) { 1045 if (ctx->f_flags & SMBFS_RDD_EOF) 1046 return ENOENT; 1047 ctx->f_left = ctx->f_limit = limit; 1048 error = smbfs_smb_search(ctx); 1049 if (error) 1050 return error; 1051 } 1052 rqp = ctx->f_rq; 1053 smb_rq_getreply(rqp, &mbp); 1054 md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 1055 md_get_uint8(mbp, &battr); 1056 md_get_uint16le(mbp, &time); 1057 md_get_uint16le(mbp, &date); 1058 md_get_uint32le(mbp, &size); 1059 cp = ctx->f_name; 1060 md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); 1061 cp[sizeof(ctx->f_fname) - 1] = 0; 1062 cp += strlen(cp) - 1; 1063 while (*cp == ' ' && cp >= ctx->f_name) 1064 *cp-- = 0; 1065 ctx->f_attr.fa_attr = battr; 1066 smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, 1067 &ctx->f_attr.fa_mtime); 1068 ctx->f_attr.fa_size = size; 1069 ctx->f_nmlen = strlen(ctx->f_name); 1070 ctx->f_ecnt--; 1071 ctx->f_left--; 1072 return 0; 1073} 1074 1075static int 1076smbfs_findcloseLM1(struct smbfs_fctx *ctx) 1077{ 1078 if (ctx->f_rq) 1079 smb_rq_done(ctx->f_rq); 1080 return 0; 1081} 1082 1083/* 1084 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect 1085 */ 1086static int 1087smbfs_smb_trans2find2(struct smbfs_fctx *ctx) 1088{ 1089 struct smb_t2rq *t2p; 1090 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 1091 struct mbchain *mbp; 1092 struct mdchain *mdp; 1093 u_int16_t tw, flags; 1094 int error; 1095 1096 if (ctx->f_t2) { 1097 smb_t2_done(ctx->f_t2); 1098 ctx->f_t2 = NULL; 1099 } 1100 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 1101 flags = 8 | 2; /* <resume> | <close if EOS> */ 1102 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 1103 flags |= 1; /* close search after this request */ 1104 ctx->f_flags |= SMBFS_RDD_NOCLOSE; 1105 } 1106 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1107 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, 1108 ctx->f_scred, &t2p); 1109 if (error) 1110 return error; 1111 ctx->f_t2 = t2p; 1112 mbp = &t2p->t2_tparam; 1113 mb_init(mbp); 1114 mb_put_uint16le(mbp, ctx->f_attrmask); 1115 mb_put_uint16le(mbp, ctx->f_limit); 1116 mb_put_uint16le(mbp, flags); 1117 mb_put_uint16le(mbp, ctx->f_infolevel); 1118 mb_put_uint32le(mbp, 0); 1119 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 1120 if (error) 1121 return error; 1122 } else { 1123 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, 1124 ctx->f_scred, &t2p); 1125 if (error) 1126 return error; 1127 ctx->f_t2 = t2p; 1128 mbp = &t2p->t2_tparam; 1129 mb_init(mbp); 1130 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 1131 mb_put_uint16le(mbp, ctx->f_limit); 1132 mb_put_uint16le(mbp, ctx->f_infolevel); 1133 mb_put_uint32le(mbp, 0); /* resume key */ 1134 mb_put_uint16le(mbp, flags); 1135 if (ctx->f_rname) 1136 mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM); 1137 else 1138 mb_put_uint8(mbp, 0); /* resume file name */ 1139#if 0 1140 struct timeval tv; 1141 tv.tv_sec = 0; 1142 tv.tv_usec = 200 * 1000; /* 200ms */ 1143 if (vcp->vc_flags & SMBC_WIN95) { 1144 /* 1145 * some implementations suggests to sleep here 1146 * for 200ms, due to the bug in the Win95. 1147 * I've didn't notice any problem, but put code 1148 * for it. 1149 */ 1150 pause("fix95", tvtohz(&tv)); 1151 } 1152#endif 1153 } 1154 t2p->t2_maxpcount = 5 * 2; 1155 t2p->t2_maxdcount = vcp->vc_txmax; 1156 error = smb_t2_request(t2p); 1157 if (error) 1158 return error; 1159 mdp = &t2p->t2_rparam; 1160 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1161 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) 1162 return error; 1163 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 1164 } 1165 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1166 return error; 1167 ctx->f_ecnt = tw; 1168 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1169 return error; 1170 if (tw) 1171 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1172 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1173 return error; 1174 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1175 return error; 1176 if (ctx->f_ecnt == 0) { 1177 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1178 return ENOENT; 1179 } 1180 ctx->f_rnameofs = tw; 1181 mdp = &t2p->t2_rdata; 1182 if (mdp->md_top == NULL) { 1183 printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt); 1184 return ENOENT; 1185 } 1186 if (mdp->md_top->m_len == 0) { 1187 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next); 1188 return ENOENT; 1189 } 1190 ctx->f_eofs = 0; 1191 return 0; 1192} 1193 1194static int 1195smbfs_smb_findclose2(struct smbfs_fctx *ctx) 1196{ 1197 struct smb_rq rq, *rqp = &rq; 1198 struct mbchain *mbp; 1199 int error; 1200 1201 error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred); 1202 if (error) 1203 return error; 1204 smb_rq_getrequest(rqp, &mbp); 1205 smb_rq_wstart(rqp); 1206 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 1207 smb_rq_wend(rqp); 1208 smb_rq_bstart(rqp); 1209 smb_rq_bend(rqp); 1210 error = smb_rq_simple(rqp); 1211 smb_rq_done(rqp); 1212 return error; 1213} 1214 1215static int 1216smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, 1217 const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1218{ 1219 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 1220 ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK); 1221 } else 1222 ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); 1223 if (ctx->f_name == NULL) 1224 return ENOMEM; 1225 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? 1226 SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO; 1227 ctx->f_attrmask = attr; 1228 ctx->f_wildcard = wildcard; 1229 ctx->f_wclen = wclen; 1230 return 0; 1231} 1232 1233static int 1234smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) 1235{ 1236 struct mdchain *mbp; 1237 struct smb_t2rq *t2p; 1238 char *cp; 1239 u_int8_t tb; 1240 u_int16_t date, time, wattr; 1241 u_int32_t size, next, dattr; 1242 int64_t lint; 1243 int error, svtz, cnt, fxsz, nmlen, recsz; 1244 1245 if (ctx->f_ecnt == 0) { 1246 if (ctx->f_flags & SMBFS_RDD_EOF) 1247 return ENOENT; 1248 ctx->f_left = ctx->f_limit = limit; 1249 error = smbfs_smb_trans2find2(ctx); 1250 if (error) 1251 return error; 1252 } 1253 t2p = ctx->f_t2; 1254 mbp = &t2p->t2_rdata; 1255 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; 1256 switch (ctx->f_infolevel) { 1257 case SMB_INFO_STANDARD: 1258 next = 0; 1259 fxsz = 0; 1260 md_get_uint16le(mbp, &date); 1261 md_get_uint16le(mbp, &time); /* creation time */ 1262 md_get_uint16le(mbp, &date); 1263 md_get_uint16le(mbp, &time); /* access time */ 1264 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); 1265 md_get_uint16le(mbp, &date); 1266 md_get_uint16le(mbp, &time); /* access time */ 1267 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); 1268 md_get_uint32le(mbp, &size); 1269 ctx->f_attr.fa_size = size; 1270 md_get_uint32(mbp, NULL); /* allocation size */ 1271 md_get_uint16le(mbp, &wattr); 1272 ctx->f_attr.fa_attr = wattr; 1273 md_get_uint8(mbp, &tb); 1274 size = nmlen = tb; 1275 fxsz = 23; 1276 recsz = next = 24 + nmlen; /* docs misses zero byte at end */ 1277 break; 1278 case SMB_FIND_FILE_DIRECTORY_INFO: 1279 md_get_uint32le(mbp, &next); 1280 md_get_uint32(mbp, NULL); /* file index */ 1281 md_get_int64(mbp, NULL); /* creation time */ 1282 md_get_int64le(mbp, &lint); 1283 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime); 1284 md_get_int64le(mbp, &lint); 1285 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime); 1286 md_get_int64le(mbp, &lint); 1287 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime); 1288 md_get_int64le(mbp, &lint); /* file size */ 1289 ctx->f_attr.fa_size = lint; 1290 md_get_int64(mbp, NULL); /* real size (should use) */ 1291 md_get_uint32le(mbp, &dattr); /* EA */ 1292 ctx->f_attr.fa_attr = dattr; 1293 md_get_uint32le(mbp, &size); /* name len */ 1294 fxsz = 64; 1295 recsz = next ? next : fxsz + size; 1296 break; 1297 default: 1298 SMBERROR("unexpected info level %d\n", ctx->f_infolevel); 1299 return EINVAL; 1300 } 1301 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 1302 nmlen = min(size, SMB_MAXFNAMELEN * 2); 1303 } else 1304 nmlen = min(size, SMB_MAXFNAMELEN); 1305 cp = ctx->f_name; 1306 error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); 1307 if (error) 1308 return error; 1309 if (next) { 1310 cnt = next - nmlen - fxsz; 1311 if (cnt > 0) 1312 md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); 1313 else if (cnt < 0) { 1314 SMBERROR("out of sync\n"); 1315 return EBADRPC; 1316 } 1317 } 1318 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 1319 if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0) 1320 nmlen -= 2; 1321 } else 1322 if (nmlen && cp[nmlen - 1] == 0) 1323 nmlen--; 1324 if (nmlen == 0) 1325 return EBADRPC; 1326 1327 next = ctx->f_eofs + recsz; 1328 if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && 1329 (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { 1330 /* 1331 * Server needs a resume filename. 1332 */ 1333 if (ctx->f_rnamelen <= nmlen) { 1334 if (ctx->f_rname) 1335 free(ctx->f_rname, M_SMBFSDATA); 1336 ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); 1337 ctx->f_rnamelen = nmlen; 1338 } 1339 bcopy(ctx->f_name, ctx->f_rname, nmlen); 1340 ctx->f_rname[nmlen] = 0; 1341 ctx->f_flags |= SMBFS_RDD_GOTRNAME; 1342 } 1343 ctx->f_nmlen = nmlen; 1344 ctx->f_eofs = next; 1345 ctx->f_ecnt--; 1346 ctx->f_left--; 1347 return 0; 1348} 1349 1350static int 1351smbfs_findcloseLM2(struct smbfs_fctx *ctx) 1352{ 1353 if (ctx->f_name) 1354 free(ctx->f_name, M_SMBFSDATA); 1355 if (ctx->f_t2) 1356 smb_t2_done(ctx->f_t2); 1357 if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) 1358 smbfs_smb_findclose2(ctx); 1359 return 0; 1360} 1361 1362int 1363smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr, 1364 struct smb_cred *scred, struct smbfs_fctx **ctxpp) 1365{ 1366 struct smbfs_fctx *ctx; 1367 int error; 1368 1369 ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK); 1370 if (ctx == NULL) 1371 return ENOMEM; 1372 bzero(ctx, sizeof(*ctx)); 1373 ctx->f_ssp = dnp->n_mount->sm_share; 1374 ctx->f_dnp = dnp; 1375 ctx->f_flags = SMBFS_RDD_FINDFIRST; 1376 ctx->f_scred = scred; 1377 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || 1378 (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) { 1379 ctx->f_flags |= SMBFS_RDD_USESEARCH; 1380 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred); 1381 } else 1382 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred); 1383 if (error) 1384 smbfs_findclose(ctx, scred); 1385 else 1386 *ctxpp = ctx; 1387 return error; 1388} 1389 1390int 1391smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) 1392{ 1393 int error; 1394 1395 if (limit == 0) 1396 limit = 1000000; 1397 else if (limit > 1) 1398 limit *= 4; /* imperical */ 1399 ctx->f_scred = scred; 1400 for (;;) { 1401 if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1402 error = smbfs_findnextLM1(ctx, limit); 1403 } else 1404 error = smbfs_findnextLM2(ctx, limit); 1405 if (error) 1406 return error; 1407 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 1408 if ((ctx->f_nmlen == 2 && 1409 *(u_int16_t *)ctx->f_name == htole16(0x002e)) || 1410 (ctx->f_nmlen == 4 && 1411 *(u_int32_t *)ctx->f_name == htole32(0x002e002e))) 1412 continue; 1413 } else 1414 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || 1415 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && 1416 ctx->f_name[1] == '.')) 1417 continue; 1418 break; 1419 } 1420 smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen, 1421 ctx->f_dnp->n_mount->sm_caseopt); 1422 ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); 1423 return 0; 1424} 1425 1426int 1427smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred) 1428{ 1429 ctx->f_scred = scred; 1430 if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1431 smbfs_findcloseLM1(ctx); 1432 } else 1433 smbfs_findcloseLM2(ctx); 1434 if (ctx->f_rname) 1435 free(ctx->f_rname, M_SMBFSDATA); 1436 free(ctx, M_SMBFSDATA); 1437 return 0; 1438} 1439 1440int 1441smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, 1442 struct smbfattr *fap, struct smb_cred *scred) 1443{ 1444 struct smbfs_fctx *ctx; 1445 int error; 1446 1447 if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { 1448 bzero(fap, sizeof(*fap)); 1449 fap->fa_attr = SMB_FA_DIR; 1450 fap->fa_ino = 2; 1451 return 0; 1452 } 1453 if (nmlen == 1 && name[0] == '.') { 1454 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 1455 return error; 1456 } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 1457 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 1458 scred); 1459 printf("%s: knows NOTHING about '..'\n", __func__); 1460 return error; 1461 } 1462 error = smbfs_findopen(dnp, name, nmlen, 1463 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); 1464 if (error) 1465 return error; 1466 ctx->f_flags |= SMBFS_RDD_FINDSINGLE; 1467 error = smbfs_findnext(ctx, 1, scred); 1468 if (error == 0) { 1469 *fap = ctx->f_attr; 1470 if (name == NULL) 1471 fap->fa_ino = dnp->n_ino; 1472 } 1473 smbfs_findclose(ctx, scred); 1474 return error; 1475} 1476