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