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