1/* $NetBSD: smbfs_smb.c,v 1.42.8.1 2012/11/29 00:04:37 riz Exp $ */ 2 3/*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jaromir Dolecek. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * Copyright (c) 2000-2001 Boris Popov 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by Boris Popov. 47 * 4. Neither the name of the author nor the names of any co-contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 * 63 * FreeBSD: src/sys/fs/smbfs/smbfs_smb.c,v 1.3 2001/12/10 08:09:46 obrien Exp 64 */ 65 66#include <sys/cdefs.h> 67__KERNEL_RCSID(0, "$NetBSD: smbfs_smb.c,v 1.42.8.1 2012/11/29 00:04:37 riz Exp $"); 68 69#include <sys/param.h> 70#include <sys/systm.h> 71#include <sys/kernel.h> 72#include <sys/malloc.h> 73#include <sys/proc.h> 74#include <sys/lock.h> 75#include <sys/vnode.h> 76#include <sys/mbuf.h> 77#include <sys/mount.h> 78 79#ifdef USE_MD5_HASH 80#include <sys/md5.h> 81#endif 82 83#include <netsmb/smb.h> 84#include <netsmb/smb_subr.h> 85#include <netsmb/smb_rq.h> 86#include <netsmb/smb_conn.h> 87 88#include <fs/smbfs/smbfs.h> 89#include <fs/smbfs/smbfs_node.h> 90#include <fs/smbfs/smbfs_subr.h> 91 92/* 93 * Lack of inode numbers leads us to the problem of generating them. 94 * Partially this problem can be solved by having a dir/file cache 95 * with inode numbers generated from the incremented by one counter. 96 * However this way will require too much kernel memory, gives all 97 * sorts of locking and consistency problems, not to mentinon counter overflows. 98 * So, I'm decided to use a hash function to generate pseudo random (and unique) 99 * inode numbers. 100 */ 101static long 102smbfs_getino(struct smbnode *dnp, const char *name, int nmlen) 103{ 104#ifdef USE_MD5_HASH 105 MD5_CTX md5; 106 u_int32_t state[4]; 107 long ino; 108 int i; 109 110 MD5Init(&md5); 111 MD5Update(&md5, name, nmlen); 112 MD5Final((u_char *)state, &md5); 113 for (i = 0, ino = 0; i < 4; i++) 114 ino += state[i]; 115 return dnp->n_ino + ino; 116#endif 117 u_int32_t ino; 118 119 ino = dnp->n_ino + smbfs_hash(name, nmlen); 120 if (ino <= 2) 121 ino += 3; 122 return ino; 123} 124 125static int 126smbfs_smb_lockandx(struct smbnode *np, int op, void *id, off_t start, off_t end, 127 struct smb_cred *scred) 128{ 129 struct smb_share *ssp = np->n_mount->sm_share; 130 struct smb_rq *rqp; 131 struct mbchain *mbp; 132 u_char ltype = 0; 133 int error; 134 135 if (op == SMB_LOCK_SHARED) 136 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; 137 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred, &rqp); 138 if (error) 139 return error; 140 smb_rq_getrequest(rqp, &mbp); 141 smb_rq_wstart(rqp); 142 mb_put_uint8(mbp, 0xff); /* secondary command */ 143 mb_put_uint8(mbp, 0); /* MBZ */ 144 mb_put_uint16le(mbp, 0); 145 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM); 146 mb_put_uint8(mbp, ltype); /* locktype */ 147 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ 148 mb_put_uint32le(mbp, 0); /* timeout - break immediately */ 149 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); 150 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); 151 smb_rq_wend(rqp); 152 smb_rq_bstart(rqp); 153 mb_put_uint16le(mbp, (((long) id) & 0xffff)); /* process ID */ 154 mb_put_uint32le(mbp, start); 155 mb_put_uint32le(mbp, end - start); 156 smb_rq_bend(rqp); 157 error = smb_rq_simple(rqp); 158 smb_rq_done(rqp); 159 return error; 160} 161 162int 163smbfs_smb_lock(struct smbnode *np, int op, void *id, 164 off_t start, off_t end, struct smb_cred *scred) 165{ 166 struct smb_share *ssp = np->n_mount->sm_share; 167 168 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) 169 /* 170 * TODO: use LOCK_BYTE_RANGE here. 171 */ 172 return EINVAL; 173 else 174 return smbfs_smb_lockandx(np, op, id, start, end, scred); 175} 176 177int 178smbfs_smb_statvfs(struct smb_share *ssp, struct statvfs *sbp, 179 struct smb_cred *scred) 180{ 181 unsigned long bsize; /* Block (allocation unit) size */ 182 unsigned long bavail, bfree; 183 184 /* 185 * The SMB request work with notion of sector size and 186 * allocation units. Allocation unit is what 'block' 187 * means in Unix context, sector size might be HW sector size. 188 */ 189 190 if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) { 191 struct smb_t2rq *t2p; 192 struct mbchain *mbp; 193 struct mdchain *mdp; 194 u_int16_t secsz; 195 u_int32_t units, bpu, funits; 196 int error; 197 198 error = smb_t2_alloc(SSTOCP(ssp), 199 SMB_TRANS2_QUERY_FS_INFORMATION, scred, &t2p); 200 if (error) 201 return error; 202 mbp = &t2p->t2_tparam; 203 mb_init(mbp); 204 mb_put_uint16le(mbp, SMB_INFO_ALLOCATION); 205 t2p->t2_maxpcount = 4; 206 t2p->t2_maxdcount = 4 * 4 + 2; 207 error = smb_t2_request(t2p); 208 if (error) { 209 smb_t2_done(t2p); 210 return error; 211 } 212 mdp = &t2p->t2_rdata; 213 md_get_uint32(mdp, NULL); /* fs id */ 214 md_get_uint32le(mdp, &bpu); /* Number of sectors per unit */ 215 md_get_uint32le(mdp, &units); /* Total number of units */ 216 md_get_uint32le(mdp, &funits); /* Number of available units */ 217 md_get_uint16le(mdp, &secsz); /* Number of bytes per sector */ 218 smb_t2_done(t2p); 219 220 bsize = bpu * secsz; 221 bavail = units; 222 bfree = funits; 223 } else { 224 struct smb_rq *rqp; 225 struct mdchain *mdp; 226 u_int16_t units, bpu, secsz, funits; 227 int error; 228 229 error = smb_rq_alloc(SSTOCP(ssp), 230 SMB_COM_QUERY_INFORMATION_DISK, 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); /* Total units per server */ 244 md_get_uint16le(mdp, &bpu); /* Blocks per allocation unit */ 245 md_get_uint16le(mdp, &secsz); /* Block size (in bytes) */ 246 md_get_uint16le(mdp, &funits); /* Number of free units */ 247 smb_rq_done(rqp); 248 249 bsize = bpu * secsz; 250 bavail = units; 251 bfree = funits; 252 } 253 254 sbp->f_bsize = bsize; /* fundamental file system block size */ 255 sbp->f_frsize = bsize; /* fundamental file system frag size */ 256 sbp->f_iosize = bsize; /* optimal I/O size */ 257 sbp->f_blocks = bavail; /* total data blocks in file system */ 258 sbp->f_bfree = bfree; /* free blocks in fs */ 259 sbp->f_bresvd = 0; /* reserved blocks in fs */ 260 sbp->f_bavail= bfree; /* free blocks avail to non-superuser */ 261 sbp->f_files = 0xffff; /* total file nodes in file system */ 262 sbp->f_ffree = 0xffff; /* free file nodes to non-superuser */ 263 sbp->f_favail = 0xffff; /* free file nodes in fs */ 264 sbp->f_fresvd = 0; /* reserved file nodes in fs */ 265 return 0; 266} 267 268static int 269smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred) 270{ 271 struct smb_t2rq *t2p; 272 struct smb_share *ssp = np->n_mount->sm_share; 273 struct mbchain *mbp; 274 int error; 275 276 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 277 scred, &t2p); 278 if (error) 279 return error; 280 mbp = &t2p->t2_tparam; 281 mb_init(mbp); 282 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM); 283 mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO); 284 mb_put_uint32le(mbp, 0); 285 mbp = &t2p->t2_tdata; 286 mb_init(mbp); 287 mb_put_int64le(mbp, newsize); 288 mb_put_uint32le(mbp, 0); /* padding */ 289 mb_put_uint16le(mbp, 0); 290 t2p->t2_maxpcount = 2; 291 t2p->t2_maxdcount = 0; 292 error = smb_t2_request(t2p); 293 smb_t2_done(t2p); 294 return error; 295} 296 297int 298smbfs_smb_setfsize(struct smbnode *np, u_quad_t newsize, 299 struct smb_cred *scred) 300{ 301 struct smb_share *ssp = np->n_mount->sm_share; 302 struct smb_rq *rqp; 303 struct mbchain *mbp; 304 int error; 305 306 if (newsize >= (1LL << 32)) { 307 if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_FILES)) 308 return EFBIG; 309 return smbfs_smb_seteof(np, (int64_t)newsize, scred); 310 } 311 312 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); 313 if (error) 314 return error; 315 smb_rq_getrequest(rqp, &mbp); 316 smb_rq_wstart(rqp); 317 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM); 318 mb_put_uint16le(mbp, 0); 319 mb_put_uint32le(mbp, newsize); 320 mb_put_uint16le(mbp, 0); 321 smb_rq_wend(rqp); 322 smb_rq_bstart(rqp); 323 mb_put_uint8(mbp, SMB_DT_DATA); 324 mb_put_uint16le(mbp, 0); 325 smb_rq_bend(rqp); 326 error = smb_rq_simple(rqp); 327 smb_rq_done(rqp); 328 return error; 329} 330 331 332/* 333 * Set DOS file attributes. mtime should be NULL for dialects above lm10 334 */ 335int 336smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 337 struct smb_cred *scred) 338{ 339 struct smb_rq *rqp; 340 struct smb_share *ssp = np->n_mount->sm_share; 341 struct mbchain *mbp; 342 u_long xtime; 343 int error, svtz; 344 345 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred, &rqp); 346 if (error) 347 return error; 348 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 349 smb_rq_getrequest(rqp, &mbp); 350 smb_rq_wstart(rqp); 351 mb_put_uint16le(mbp, attr); 352 if (mtime) { 353 smb_time_local2server(mtime, svtz, &xtime); 354 } else 355 xtime = 0; 356 mb_put_uint32le(mbp, xtime); /* mtime */ 357 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); 358 smb_rq_wend(rqp); 359 smb_rq_bstart(rqp); 360 mb_put_uint8(mbp, SMB_DT_ASCII); 361 do { 362 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 363 if (error) 364 break; 365 mb_put_uint8(mbp, SMB_DT_ASCII); 366 mb_put_uint8(mbp, 0); 367 smb_rq_bend(rqp); 368 error = smb_rq_simple(rqp); 369 if (error) 370 break; 371 } while(0); 372 smb_rq_done(rqp); 373 return error; 374} 375 376/* 377 * Note, win95 doesn't support this call. 378 */ 379int 380smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime, 381 struct timespec *atime, int attr, struct smb_cred *scred) 382{ 383 struct smb_t2rq *t2p; 384 struct smb_share *ssp = np->n_mount->sm_share; 385 struct smb_vc *vcp = SSTOVC(ssp); 386 struct mbchain *mbp; 387 u_int16_t xdate, xtime; 388 int error, tzoff; 389 390 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 391 scred, &t2p); 392 if (error) 393 return error; 394 mbp = &t2p->t2_tparam; 395 mb_init(mbp); 396 mb_put_uint16le(mbp, SMB_INFO_STANDARD); 397 mb_put_uint32le(mbp, 0); /* MBZ */ 398 error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 399 if (error) { 400 smb_t2_done(t2p); 401 return error; 402 } 403 tzoff = vcp->vc_sopt.sv_tz; 404 mbp = &t2p->t2_tdata; 405 mb_init(mbp); 406 mb_put_uint32le(mbp, 0); /* creation time */ 407 if (atime) 408 smb_time_unix2dos(atime, tzoff, &xdate, &xtime, NULL); 409 else 410 xtime = xdate = 0; 411 mb_put_uint16le(mbp, xdate); 412 mb_put_uint16le(mbp, xtime); 413 if (mtime) 414 smb_time_unix2dos(mtime, tzoff, &xdate, &xtime, NULL); 415 else 416 xtime = xdate = 0; 417 mb_put_uint16le(mbp, xdate); 418 mb_put_uint16le(mbp, xtime); 419 mb_put_uint32le(mbp, 0); /* file size */ 420 mb_put_uint32le(mbp, 0); /* allocation unit size */ 421 mb_put_uint16le(mbp, attr); /* DOS attr */ 422 mb_put_uint32le(mbp, 0); /* EA size */ 423 t2p->t2_maxpcount = 5 * 2; 424 t2p->t2_maxdcount = vcp->vc_txmax; 425 error = smb_t2_request(t2p); 426 smb_t2_done(t2p); 427 return error; 428} 429 430/* 431 * NT level. Specially for win9x 432 */ 433int 434smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime, 435 struct timespec *atime, struct smb_cred *scred) 436{ 437 struct smb_t2rq *t2p; 438 struct smb_share *ssp = np->n_mount->sm_share; 439 struct smb_vc *vcp = SSTOVC(ssp); 440 struct mbchain *mbp; 441 int64_t tm; 442 int error, tzoff; 443 444 /* 445 * SMB_SET_FILE_BASIC_INFO isn't supported for 446 * SMB_TRANS2_SET_PATH_INFORMATION, 447 * so use SMB_SET_FILE_BASIC_INFORMATION instead, 448 * but it requires SMB_CAP_INFOLEVEL_PASSTHRU capability. 449 */ 450 if ((SMB_CAPS(vcp) & SMB_CAP_INFOLEVEL_PASSTHRU) == 0) 451 return smbfs_smb_setptime2(np, mtime, atime, attr, scred); 452 453 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 454 scred, &t2p); 455 if (error) 456 return error; 457 mbp = &t2p->t2_tparam; 458 mb_init(mbp); 459 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFORMATION); 460 mb_put_uint32le(mbp, 0); /* MBZ */ 461 error = smbfs_fullpath(mbp, vcp, np, NULL, 0); 462 if (error) { 463 smb_t2_done(t2p); 464 return error; 465 } 466 tzoff = vcp->vc_sopt.sv_tz; 467 mbp = &t2p->t2_tdata; 468 mb_init(mbp); 469 mb_put_int64le(mbp, 0); /* creation time */ 470 if (atime) { 471 smb_time_local2NT(atime, tzoff, &tm); 472 } else 473 tm = 0; 474 mb_put_int64le(mbp, tm); 475 if (mtime) { 476 smb_time_local2NT(mtime, tzoff, &tm); 477 } else 478 tm = 0; 479 mb_put_int64le(mbp, tm); 480 mb_put_int64le(mbp, tm); /* change time */ 481 mb_put_uint32le(mbp, attr); /* attr */ 482 mb_put_uint32le(mbp, 0); /* padding */ 483 t2p->t2_maxpcount = 2; 484 t2p->t2_maxdcount = 0; 485 error = smb_t2_request(t2p); 486 smb_t2_done(t2p); 487 return error; 488} 489 490/* 491 * Set file atime and mtime. Doesn't supported by core dialect. 492 */ 493int 494smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime, 495 struct timespec *atime, struct smb_cred *scred) 496{ 497 struct smb_rq *rqp; 498 struct smb_share *ssp = np->n_mount->sm_share; 499 struct mbchain *mbp; 500 u_int16_t xdate, xtime; 501 int error, tzoff; 502 503 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred, &rqp); 504 if (error) 505 return error; 506 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 507 smb_rq_getrequest(rqp, &mbp); 508 smb_rq_wstart(rqp); 509 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM); 510 mb_put_uint32le(mbp, 0); /* creation time */ 511 512 if (atime) 513 smb_time_unix2dos(atime, tzoff, &xdate, &xtime, NULL); 514 else 515 xtime = xdate = 0; 516 mb_put_uint16le(mbp, xdate); 517 mb_put_uint16le(mbp, xtime); 518 if (mtime) 519 smb_time_unix2dos(mtime, tzoff, &xdate, &xtime, NULL); 520 else 521 xtime = xdate = 0; 522 mb_put_uint16le(mbp, xdate); 523 mb_put_uint16le(mbp, xtime); 524 smb_rq_wend(rqp); 525 smb_rq_bstart(rqp); 526 smb_rq_bend(rqp); 527 error = smb_rq_simple(rqp); 528 SMBSDEBUG(("%d\n", error)); 529 smb_rq_done(rqp); 530 return error; 531} 532 533/* 534 * Set DOS file attributes. 535 * Looks like this call can be used only if CAP_NT_SMBS bit is on. 536 */ 537int 538smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime, 539 struct timespec *atime, struct smb_cred *scred) 540{ 541 struct smb_t2rq *t2p; 542 struct smb_share *ssp = np->n_mount->sm_share; 543 struct mbchain *mbp; 544 int64_t tm; 545 int error, svtz; 546 547 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 548 scred, &t2p); 549 if (error) 550 return error; 551 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 552 mbp = &t2p->t2_tparam; 553 mb_init(mbp); 554 mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM); /* FID */ 555 mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO); /* info level */ 556 mb_put_uint32le(mbp, 0); /* reserved */ 557 mbp = &t2p->t2_tdata; 558 mb_init(mbp); 559 mb_put_int64le(mbp, 0); /* creation time */ 560 if (atime) { 561 smb_time_local2NT(atime, svtz, &tm); 562 } else 563 tm = 0; 564 mb_put_int64le(mbp, tm); 565 if (mtime) { 566 smb_time_local2NT(mtime, svtz, &tm); 567 } else 568 tm = 0; 569 mb_put_int64le(mbp, tm); 570 mb_put_int64le(mbp, tm); /* change time */ 571 mb_put_uint32le(mbp, attr); /* attr */ 572 mb_put_uint32le(mbp, 0); /* padding */ 573 t2p->t2_maxpcount = 2; 574 t2p->t2_maxdcount = 0; 575 error = smb_t2_request(t2p); 576 smb_t2_done(t2p); 577 return error; 578} 579 580 581int 582smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred) 583{ 584 struct smb_rq *rqp; 585 struct smb_share *ssp = np->n_mount->sm_share; 586 struct mbchain *mbp; 587 struct mdchain *mdp; 588 u_int8_t wc; 589 u_int16_t fid, wattr, grantedmode; 590 int error; 591 592 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_OPEN, scred, &rqp); 593 if (error) 594 return error; 595 smb_rq_getrequest(rqp, &mbp); 596 smb_rq_wstart(rqp); 597 mb_put_uint16le(mbp, accmode); 598 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 599 smb_rq_wend(rqp); 600 smb_rq_bstart(rqp); 601 mb_put_uint8(mbp, SMB_DT_ASCII); 602 do { 603 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 604 if (error) 605 break; 606 smb_rq_bend(rqp); 607 error = smb_rq_simple(rqp); 608 if (error) 609 break; 610 smb_rq_getreply(rqp, &mdp); 611 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) { 612 error = EBADRPC; 613 break; 614 } 615 md_get_uint16(mdp, &fid); 616 md_get_uint16le(mdp, &wattr); 617 md_get_uint32(mdp, NULL); /* mtime */ 618 md_get_uint32(mdp, NULL); /* fsize */ 619 md_get_uint16le(mdp, &grantedmode); 620 /* 621 * TODO: refresh attributes from this reply 622 */ 623 } while(0); 624 smb_rq_done(rqp); 625 if (error) 626 return error; 627 np->n_fid = fid; 628 np->n_rwstate = grantedmode; 629 return 0; 630} 631 632 633int 634smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime, 635 struct smb_cred *scred) 636{ 637 struct smb_rq *rqp; 638 struct mbchain *mbp; 639 u_long xtime; 640 int error; 641 642 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CLOSE, scred, &rqp); 643 if (error) 644 return error; 645 smb_rq_getrequest(rqp, &mbp); 646 smb_rq_wstart(rqp); 647 mb_put_mem(mbp, (void *)&fid, sizeof(fid), MB_MSYSTEM); 648 if (mtime) { 649 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &xtime); 650 } else 651 xtime = 0; 652 mb_put_uint32le(mbp, xtime); 653 smb_rq_wend(rqp); 654 smb_rq_bstart(rqp); 655 smb_rq_bend(rqp); 656 error = smb_rq_simple(rqp); 657 smb_rq_done(rqp); 658 return error; 659} 660 661int 662smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, 663 struct smb_cred *scred) 664{ 665 struct smb_rq *rqp; 666 struct smb_share *ssp = dnp->n_mount->sm_share; 667 struct mbchain *mbp; 668 struct mdchain *mdp; 669 struct timespec ctime; 670 u_int8_t wc; 671 u_int16_t fid; 672 u_long tm; 673 int error; 674 675 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_NEW, scred, &rqp); 676 if (error) 677 return error; 678 smb_rq_getrequest(rqp, &mbp); 679 680 /* get current time */ 681 getnanotime(&ctime); 682 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 683 684 smb_rq_wstart(rqp); 685 mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */ 686 mb_put_uint32le(mbp, tm); 687 smb_rq_wend(rqp); 688 689 smb_rq_bstart(rqp); 690 mb_put_uint8(mbp, SMB_DT_ASCII); 691 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen); 692 if (!error) { 693 smb_rq_bend(rqp); 694 error = smb_rq_simple(rqp); 695 if (!error) { 696 smb_rq_getreply(rqp, &mdp); 697 md_get_uint8(mdp, &wc); 698 if (wc == 1) 699 md_get_uint16(mdp, &fid); 700 else 701 error = EBADRPC; 702 } 703 } 704 705 smb_rq_done(rqp); 706 if (!error) 707 smbfs_smb_close(ssp, fid, &ctime, scred); 708 709 return (error); 710} 711 712int 713smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred) 714{ 715 struct smb_rq *rqp; 716 struct smb_share *ssp = np->n_mount->sm_share; 717 struct mbchain *mbp; 718 int error; 719 720 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE, scred, &rqp); 721 if (error) 722 return error; 723 smb_rq_getrequest(rqp, &mbp); 724 smb_rq_wstart(rqp); 725 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 726 smb_rq_wend(rqp); 727 smb_rq_bstart(rqp); 728 mb_put_uint8(mbp, SMB_DT_ASCII); 729 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 730 if (!error) { 731 smb_rq_bend(rqp); 732 error = smb_rq_simple(rqp); 733 } 734 smb_rq_done(rqp); 735 return error; 736} 737 738int 739smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 740 const char *tname, int tnmlen, struct smb_cred *scred) 741{ 742 struct smb_rq *rqp; 743 struct smb_share *ssp = src->n_mount->sm_share; 744 struct mbchain *mbp; 745 int error; 746 747 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_RENAME, scred, &rqp); 748 if (error) 749 return error; 750 smb_rq_getrequest(rqp, &mbp); 751 smb_rq_wstart(rqp); 752 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 753 smb_rq_wend(rqp); 754 smb_rq_bstart(rqp); 755 mb_put_uint8(mbp, SMB_DT_ASCII); 756 do { 757 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 758 if (error) 759 break; 760 mb_put_uint8(mbp, SMB_DT_ASCII); 761 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 762 if (error) 763 break; 764 smb_rq_bend(rqp); 765 error = smb_rq_simple(rqp); 766 } while(0); 767 smb_rq_done(rqp); 768 return error; 769} 770 771#ifdef notnow 772int 773smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 774 const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred) 775{ 776 struct smb_rq *rqp; 777 struct smb_share *ssp = src->n_mount->sm_share; 778 struct mbchain *mbp; 779 int error; 780 781 error = smb_rq_alloc(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred, &rqp); 782 if (error) 783 return error; 784 smb_rq_getrequest(rqp, &mbp); 785 smb_rq_wstart(rqp); 786 mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 787 mb_put_uint16le(mbp, 0x20); /* delete target file */ 788 mb_put_uint16le(mbp, flags); 789 smb_rq_wend(rqp); 790 smb_rq_bstart(rqp); 791 mb_put_uint8(mbp, SMB_DT_ASCII); 792 do { 793 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0); 794 if (error) 795 break; 796 mb_put_uint8(mbp, SMB_DT_ASCII); 797 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen); 798 if (error) 799 break; 800 smb_rq_bend(rqp); 801 error = smb_rq_simple(rqp); 802 } while(0); 803 smb_rq_done(rqp); 804 return error; 805} 806#endif 807 808int 809smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, 810 struct smb_cred *scred) 811{ 812 struct smb_rq *rqp; 813 struct smb_share *ssp = dnp->n_mount->sm_share; 814 struct mbchain *mbp; 815 int error; 816 817 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred, &rqp); 818 if (error) 819 return error; 820 smb_rq_getrequest(rqp, &mbp); 821 smb_rq_wstart(rqp); 822 smb_rq_wend(rqp); 823 smb_rq_bstart(rqp); 824 mb_put_uint8(mbp, SMB_DT_ASCII); 825 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len); 826 if (!error) { 827 smb_rq_bend(rqp); 828 error = smb_rq_simple(rqp); 829 } 830 smb_rq_done(rqp); 831 return error; 832} 833 834int 835smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred) 836{ 837 struct smb_rq *rqp; 838 struct smb_share *ssp = np->n_mount->sm_share; 839 struct mbchain *mbp; 840 int error; 841 842 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred, &rqp); 843 if (error) 844 return error; 845 smb_rq_getrequest(rqp, &mbp); 846 smb_rq_wstart(rqp); 847 smb_rq_wend(rqp); 848 smb_rq_bstart(rqp); 849 mb_put_uint8(mbp, SMB_DT_ASCII); 850 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 851 if (!error) { 852 smb_rq_bend(rqp); 853 error = smb_rq_simple(rqp); 854 } 855 smb_rq_done(rqp); 856 return error; 857} 858 859static int 860smbfs_smb_search(struct smbfs_fctx *ctx) 861{ 862 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 863 struct smb_rq *rqp; 864 struct mbchain *mbp; 865 struct mdchain *mdp; 866 u_int8_t wc, bt; 867 u_int16_t ec, dlen, bc; 868 int maxent, error; 869 870 maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN); 871 if (ctx->f_rq) { 872 smb_rq_done(ctx->f_rq); 873 ctx->f_rq = NULL; 874 } 875 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp); 876 if (error) 877 return error; 878 ctx->f_rq = rqp; 879 smb_rq_getrequest(rqp, &mbp); 880 smb_rq_wstart(rqp); 881 mb_put_uint16le(mbp, maxent); /* max entries to return */ 882 mb_put_uint16le(mbp, ctx->f_attrmask); 883 smb_rq_wend(rqp); 884 smb_rq_bstart(rqp); 885 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 886 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 887 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 888 if (error) 889 return error; 890 mb_put_uint8(mbp, SMB_DT_VARIABLE); 891 mb_put_uint16le(mbp, 0); /* context length */ 892 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 893 } else { 894 mb_put_uint8(mbp, 0); /* file name length */ 895 mb_put_uint8(mbp, SMB_DT_VARIABLE); 896 mb_put_uint16le(mbp, SMB_SKEYLEN); 897 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 898 } 899 smb_rq_bend(rqp); 900 error = smb_rq_simple(rqp); 901 if (error) { 902 if (error == ENOENT) 903 ctx->f_flags |= SMBFS_RDD_EOF; 904 905 return error; 906 } 907 smb_rq_getreply(rqp, &mdp); 908 md_get_uint8(mdp, &wc); 909 if (wc != 1) 910 return EBADRPC; 911 md_get_uint16le(mdp, &ec); 912 if (ec == 0) 913 return ENOENT; 914 ctx->f_ecnt = ec; 915 md_get_uint16le(mdp, &bc); 916 if (bc < 3) 917 return EBADRPC; 918 bc -= 3; 919 md_get_uint8(mdp, &bt); 920 if (bt != SMB_DT_VARIABLE) 921 return EBADRPC; 922 md_get_uint16le(mdp, &dlen); 923 if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 924 return EBADRPC; 925 return 0; 926} 927 928static int 929smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 930 const char *wildcard, int wclen, int attr, struct smb_cred *scred) 931{ 932 ctx->f_attrmask = attr; 933 if (wildcard) { 934 if (wclen == 1 && wildcard[0] == '*') { 935 ctx->f_wildcard = "*.*"; 936 ctx->f_wclen = 3; 937 } else { 938 ctx->f_wildcard = wildcard; 939 ctx->f_wclen = wclen; 940 } 941 } else { 942 ctx->f_wildcard = NULL; 943 ctx->f_wclen = 0; 944 } 945 ctx->f_name = ctx->f_fname; 946 return 0; 947} 948 949static int 950smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit) 951{ 952 struct mdchain *mbp; 953 struct smb_rq *rqp; 954 char *cp; 955 u_int8_t battr; 956 u_int16_t xdate, xtime; 957 u_int32_t size; 958 int error; 959 960 if (ctx->f_ecnt == 0) { 961 if (ctx->f_flags & SMBFS_RDD_EOF) 962 return ENOENT; 963 ctx->f_left = ctx->f_limit = limit; 964 error = smbfs_smb_search(ctx); 965 if (error) 966 return error; 967 } 968 rqp = ctx->f_rq; 969 smb_rq_getreply(rqp, &mbp); 970 md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 971 md_get_uint8(mbp, &battr); 972 md_get_uint16le(mbp, &xtime); 973 md_get_uint16le(mbp, &xdate); 974 md_get_uint32le(mbp, &size); 975 KASSERT(ctx->f_name == ctx->f_fname); 976 cp = ctx->f_name; 977 md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM); 978 cp[sizeof(ctx->f_fname) - 1] = '\0'; 979 cp += strlen(cp) - 1; 980 while(*cp == ' ' && cp > ctx->f_name) 981 *cp-- = '\0'; 982 ctx->f_attr.fa_attr = battr; 983 smb_dos2unixtime(xdate, xtime, 0, rqp->sr_vc->vc_sopt.sv_tz, 984 &ctx->f_attr.fa_mtime); 985 ctx->f_attr.fa_size = size; 986 ctx->f_nmlen = strlen(ctx->f_name); 987 ctx->f_ecnt--; 988 ctx->f_left--; 989 return 0; 990} 991 992static int 993smbfs_findcloseLM1(struct smbfs_fctx *ctx) 994{ 995 if (ctx->f_rq) 996 smb_rq_done(ctx->f_rq); 997 return 0; 998} 999 1000/* 1001 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect 1002 */ 1003static int 1004smbfs_smb_trans2find2(struct smbfs_fctx *ctx) 1005{ 1006 struct smb_t2rq *t2p; 1007 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 1008 struct mbchain *mbp; 1009 struct mdchain *mdp; 1010 u_int16_t tw, flags; 1011 int error; 1012 1013 if (ctx->f_t2) { 1014 smb_t2_done(ctx->f_t2); 1015 ctx->f_t2 = NULL; 1016 } 1017 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 1018 flags = 8 | 2; /* <resume> | <close if EOS> */ 1019 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 1020 flags |= 1; /* close search after this request */ 1021 ctx->f_flags |= SMBFS_RDD_NOCLOSE; 1022 } 1023 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1024 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, 1025 ctx->f_scred, &t2p); 1026 if (error) 1027 return error; 1028 ctx->f_t2 = t2p; 1029 mbp = &t2p->t2_tparam; 1030 mb_init(mbp); 1031 mb_put_uint16le(mbp, ctx->f_attrmask); 1032 mb_put_uint16le(mbp, ctx->f_limit); 1033 mb_put_uint16le(mbp, flags); 1034 mb_put_uint16le(mbp, ctx->f_infolevel); 1035 mb_put_uint32le(mbp, 0); 1036 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen); 1037 if (error) 1038 return error; 1039 } else { 1040 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, 1041 ctx->f_scred, &t2p); 1042 if (error) 1043 return error; 1044 ctx->f_t2 = t2p; 1045 mbp = &t2p->t2_tparam; 1046 mb_init(mbp); 1047 mb_put_mem(mbp, (void *)&ctx->f_Sid, 2, MB_MSYSTEM); 1048 mb_put_uint16le(mbp, ctx->f_limit); 1049 mb_put_uint16le(mbp, ctx->f_infolevel); 1050 mb_put_uint32le(mbp, 0); /* resume key */ 1051 mb_put_uint16le(mbp, flags); 1052 if (ctx->f_rname) 1053 mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM); 1054 else 1055 mb_put_uint8(mbp, 0); /* resume file name */ 1056#if 0 1057 struct timeval tv; 1058 tv.tv_sec = 0; 1059 tv.tv_usec = 200 * 1000; /* 200ms */ 1060 if (vcp->vc_flags & SMBC_WIN95) { 1061 /* 1062 * some implementations suggests to sleep here 1063 * for 200ms, due to the bug in the Win95. 1064 * I've didn't notice any problem, but put code 1065 * for it. 1066 */ 1067 tsleep(&flags, PVFS, "fix95", tvtohz(&tv)); 1068 } 1069#endif 1070 } 1071 t2p->t2_maxpcount = 5 * 2; 1072 t2p->t2_maxdcount = vcp->vc_txmax; 1073 error = smb_t2_request(t2p); 1074 if (error) 1075 return error; 1076 mdp = &t2p->t2_rparam; 1077 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1078 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) 1079 return error; 1080 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 1081 } 1082 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1083 return error; 1084 ctx->f_ecnt = tw; 1085 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1086 return error; 1087 if (tw) 1088 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1089 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1090 return error; 1091 if ((error = md_get_uint16le(mdp, &tw)) != 0) 1092 return error; 1093 if (ctx->f_ecnt == 0) { 1094 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 1095 return ENOENT; 1096 } 1097 ctx->f_rnameofs = tw; 1098 mdp = &t2p->t2_rdata; 1099 1100 KASSERT(mdp->md_top != NULL); 1101 KASSERT(mdp->md_top->m_len != 0); 1102 1103 ctx->f_eofs = 0; 1104 return 0; 1105} 1106 1107static int 1108smbfs_smb_findclose2(struct smbfs_fctx *ctx) 1109{ 1110 struct smb_rq *rqp; 1111 struct mbchain *mbp; 1112 int error; 1113 1114 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred, &rqp); 1115 if (error) 1116 return error; 1117 smb_rq_getrequest(rqp, &mbp); 1118 smb_rq_wstart(rqp); 1119 mb_put_mem(mbp, (void *)&ctx->f_Sid, 2, MB_MSYSTEM); 1120 smb_rq_wend(rqp); 1121 smb_rq_bstart(rqp); 1122 smb_rq_bend(rqp); 1123 error = smb_rq_simple(rqp); 1124 smb_rq_done(rqp); 1125 return error; 1126} 1127 1128static int 1129smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, 1130 const char *wildcard, int wclen, int attr, struct smb_cred *scred) 1131{ 1132 ctx->f_name = malloc(SMB_MAXNAMLEN, M_SMBFSDATA, M_WAITOK); 1133 if (ctx->f_name == NULL) 1134 return ENOMEM; 1135 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? 1136 SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO; 1137 ctx->f_attrmask = attr; 1138 ctx->f_wildcard = wildcard; 1139 ctx->f_wclen = wclen; 1140 return 0; 1141} 1142 1143static int 1144smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) 1145{ 1146 struct mdchain *mbp; 1147 struct smb_t2rq *t2p; 1148 char *cp; 1149 u_int8_t tb; 1150 u_int16_t xdate, xtime, wattr; 1151 u_int32_t size, next, dattr; 1152 int64_t tmp; 1153 int error, svtz, cnt, fxsz, nmlen, recsz; 1154 1155 if (ctx->f_ecnt == 0) { 1156 if (ctx->f_flags & SMBFS_RDD_EOF) 1157 return ENOENT; 1158 ctx->f_left = ctx->f_limit = limit; 1159 error = smbfs_smb_trans2find2(ctx); 1160 if (error) 1161 return error; 1162 } 1163 t2p = ctx->f_t2; 1164 mbp = &t2p->t2_rdata; 1165 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; 1166 switch (ctx->f_infolevel) { 1167 case SMB_INFO_STANDARD: 1168 next = 0; 1169 fxsz = 0; 1170 md_get_uint16le(mbp, &xdate); 1171 md_get_uint16le(mbp, &xtime); /* creation time */ 1172 md_get_uint16le(mbp, &xdate); 1173 md_get_uint16le(mbp, &xtime); /* access time */ 1174 smb_dos2unixtime(xdate, xtime, 0, svtz, &ctx->f_attr.fa_atime); 1175 md_get_uint16le(mbp, &xdate); 1176 md_get_uint16le(mbp, &xtime); /* access time */ 1177 smb_dos2unixtime(xdate, xtime, 0, svtz, &ctx->f_attr.fa_mtime); 1178 md_get_uint32le(mbp, &size); 1179 ctx->f_attr.fa_size = size; 1180 md_get_uint32(mbp, NULL); /* allocation size */ 1181 md_get_uint16le(mbp, &wattr); 1182 ctx->f_attr.fa_attr = wattr; 1183 md_get_uint8(mbp, &tb); 1184 size = nmlen = tb; 1185 fxsz = 23; 1186 recsz = next = 24 + nmlen; /* docs misses zero byte at end */ 1187 break; 1188 case SMB_FIND_FILE_DIRECTORY_INFO: 1189 md_get_uint32le(mbp, &next); 1190 md_get_uint32(mbp, NULL); /* file index */ 1191 md_get_int64(mbp, NULL); /* creation time */ 1192 md_get_int64le(mbp, &tmp); 1193 smb_time_NT2local(tmp, svtz, &ctx->f_attr.fa_atime); 1194 md_get_int64le(mbp, &tmp); 1195 smb_time_NT2local(tmp, svtz, &ctx->f_attr.fa_mtime); 1196 md_get_int64le(mbp, &tmp); 1197 smb_time_NT2local(tmp, svtz, &ctx->f_attr.fa_ctime); 1198 md_get_int64le(mbp, &tmp); /* file size */ 1199 ctx->f_attr.fa_size = tmp; 1200 md_get_int64(mbp, NULL); /* real size (should use) */ 1201 md_get_uint32le(mbp, &dattr); /* EA */ 1202 ctx->f_attr.fa_attr = dattr; 1203 md_get_uint32le(mbp, &size); /* name len */ 1204 fxsz = 64; 1205 recsz = next ? next : fxsz + size; 1206 break; 1207 default: 1208#ifdef DIAGNOSTIC 1209 panic("smbfs_findnextLM2: unexpected info level %d\n", 1210 ctx->f_infolevel); 1211#else 1212 return EINVAL; 1213#endif 1214 } 1215 nmlen = min(size, SMB_MAXNAMLEN); 1216 cp = ctx->f_name; 1217 error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); 1218 if (error) 1219 return error; 1220 if (next) { 1221 cnt = next - nmlen - fxsz; 1222 if (cnt > 0) 1223 md_get_mem(mbp, NULL, cnt, MB_MSYSTEM); 1224#ifdef DIAGNOSTIC 1225 else if (cnt < 0) 1226 panic("smbfs_findnextLM2: out of sync"); 1227#endif 1228 } 1229 if (nmlen && cp[nmlen - 1] == 0) 1230 nmlen--; 1231 if (nmlen == 0) 1232 return EBADRPC; 1233 1234 next = ctx->f_eofs + recsz; 1235 if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && 1236 (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) { 1237 /* 1238 * Server needs a resume filename. 1239 */ 1240 if (ctx->f_rnamelen <= nmlen) { 1241 if (ctx->f_rname) 1242 free(ctx->f_rname, M_SMBFSDATA); 1243 ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK); 1244 ctx->f_rnamelen = nmlen; 1245 } 1246 memcpy(ctx->f_rname, ctx->f_name, nmlen); 1247 ctx->f_rname[nmlen] = 0; 1248 ctx->f_flags |= SMBFS_RDD_GOTRNAME; 1249 } 1250 ctx->f_nmlen = nmlen; 1251 ctx->f_eofs = next; 1252 ctx->f_ecnt--; 1253 ctx->f_left--; 1254 return 0; 1255} 1256 1257static int 1258smbfs_findcloseLM2(struct smbfs_fctx *ctx) 1259{ 1260 if (ctx->f_name) 1261 free(ctx->f_name, M_SMBFSDATA); 1262 if (ctx->f_t2) 1263 smb_t2_done(ctx->f_t2); 1264 if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) 1265 smbfs_smb_findclose2(ctx); 1266 return 0; 1267} 1268 1269int 1270smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr, 1271 struct smb_cred *scred, struct smbfs_fctx **ctxpp) 1272{ 1273 struct smbfs_fctx *ctx; 1274 int error; 1275 1276 ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK|M_ZERO); 1277 ctx->f_ssp = dnp->n_mount->sm_share; 1278 ctx->f_dnp = dnp; 1279 ctx->f_flags = SMBFS_RDD_FINDFIRST; 1280 ctx->f_scred = scred; 1281 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || 1282 (dnp->n_mount->sm_args.flags & SMBFS_MOUNT_NO_LONG)) { 1283 ctx->f_flags |= SMBFS_RDD_USESEARCH; 1284 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred); 1285 } else 1286 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred); 1287 if (error) 1288 smbfs_findclose(ctx, scred); 1289 else 1290 *ctxpp = ctx; 1291 return error; 1292} 1293 1294int 1295smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) 1296{ 1297 int error; 1298 1299 if (limit == 0) 1300 limit = 1000000; 1301 else if (limit > 1) 1302 limit *= 4; /* empirical */ 1303 ctx->f_scred = scred; 1304 for (;;) { 1305 if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1306 error = smbfs_findnextLM1(ctx, limit); 1307 } else 1308 error = smbfs_findnextLM2(ctx, limit); 1309 if (error) 1310 return error; 1311 1312 /* Skip '.' and '..' */ 1313 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || 1314 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && 1315 ctx->f_name[1] == '.')) 1316 continue; 1317 break; 1318 } 1319 smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, ctx->f_nmlen, 1320 ctx->f_dnp->n_mount->sm_caseopt); 1321 ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); 1322 return 0; 1323} 1324 1325int 1326smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred) 1327{ 1328 ctx->f_scred = scred; 1329 if (ctx->f_flags & SMBFS_RDD_USESEARCH) { 1330 smbfs_findcloseLM1(ctx); 1331 } else 1332 smbfs_findcloseLM2(ctx); 1333 if (ctx->f_rname) 1334 free(ctx->f_rname, M_SMBFSDATA); 1335 free(ctx, M_SMBFSDATA); 1336 return 0; 1337} 1338 1339int 1340smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, 1341 struct smbfattr *fap, struct smb_cred *scred) 1342{ 1343 struct smbfs_fctx *ctx; 1344 int error; 1345 1346 if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { 1347 memset(fap, 0, sizeof(*fap)); 1348 fap->fa_attr = SMB_FA_DIR; 1349 fap->fa_ino = 2; 1350 return 0; 1351 } 1352 if (nmlen == 1 && name[0] == '.') { 1353 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 1354 return error; 1355 } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 1356 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, 1357 fap, scred); 1358 printf("%s: knows NOTHING about '..'\n", __func__); 1359 return error; 1360 } 1361 error = smbfs_findopen(dnp, name, nmlen, 1362 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); 1363 if (error) 1364 return error; 1365 ctx->f_flags |= SMBFS_RDD_FINDSINGLE; 1366 error = smbfs_findnext(ctx, 1, scred); 1367 if (error == 0) { 1368 *fap = ctx->f_attr; 1369 if (name == NULL) 1370 fap->fa_ino = dnp->n_ino; 1371 1372 /* 1373 * Check the returned file name case exactly 1374 * matches requested file name. ctx->f_nmlen is 1375 * guaranteed to always match nmlen. 1376 */ 1377 if (nmlen > 0 && strncmp(name, ctx->f_name, nmlen) != 0) 1378 error = ENOENT; 1379 } 1380 smbfs_findclose(ctx, scred); 1381 return error; 1382} 1383 1384/* 1385 * This call is used to fetch FID for directories. For normal files, 1386 * SMB_COM_OPEN is used. 1387 */ 1388int 1389smbfs_smb_ntcreatex(struct smbnode *np, int accmode, 1390 struct smb_cred *scred) 1391{ 1392 struct smb_rq *rqp; 1393 struct smb_share *ssp = np->n_mount->sm_share; 1394 struct mbchain *mbp; 1395 struct mdchain *mdp; 1396 int error; 1397 u_int8_t wc; 1398 u_int8_t *nmlen; 1399 u_int16_t flen; 1400 1401 KASSERT(SMBTOV(np)->v_type == VDIR); 1402 1403 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scred, &rqp); 1404 if (error) 1405 return error; 1406 smb_rq_getrequest(rqp, &mbp); 1407 smb_rq_wstart(rqp); 1408 mb_put_uint8(mbp, 0xff); /* Secondary command; 0xFF = None */ 1409 mb_put_uint8(mbp, 0); /* Reserved (must be 0) */ 1410 mb_put_uint16le(mbp, 0); /* Off to next cmd WordCount */ 1411 mb_put_uint8(mbp, 0); /* Reserved (must be 0) */ 1412 nmlen = mb_reserve(mbp, sizeof(u_int16_t)); 1413 /* Length of Name[] in bytes */ 1414 mb_put_uint32le(mbp, SMB_FL_CANONICAL_PATHNAMES); 1415 /* Flags - Create bit set */ 1416 mb_put_uint32le(mbp, 0); /* If nonzero, open relative to this */ 1417 mb_put_uint32le(mbp, NT_FILE_LIST_DIRECTORY); /* Access mask */ 1418 mb_put_uint32le(mbp, 0); /* Low 32bit */ 1419 mb_put_uint32le(mbp, 0); /* Hi 32bit */ 1420 /* Initial allocation size */ 1421 mb_put_uint32le(mbp, 0); /* File attributes */ 1422 mb_put_uint32le(mbp, NT_FILE_SHARE_READ|NT_FILE_SHARE_WRITE); 1423 /* Type of share access */ 1424 mb_put_uint32le(mbp, NT_OPEN_EXISTING); 1425 /* Create disposition - just open */ 1426 mb_put_uint32le(mbp, NT_FILE_DIRECTORY_FILE); 1427 /* Options to use if creating a file */ 1428 mb_put_uint32le(mbp, 0); /* Security QOS information */ 1429 mb_put_uint8(mbp, 0); /* Security tracking mode flags */ 1430 smb_rq_wend(rqp); 1431 smb_rq_bstart(rqp); 1432 1433 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0); 1434 if (error) 1435 return error; 1436 1437 /* Windows XP seems to include the final zero. Better do that too. */ 1438 mb_put_uint8(mbp, 0); 1439 1440 flen = mbp->mb_count; 1441 SMBRQ_PUTLE16(nmlen, flen); 1442 1443 smb_rq_bend(rqp); 1444 error = smb_rq_simple(rqp); 1445 if (error) 1446 goto bad; 1447 1448 smb_rq_getreply(rqp, &mdp); 1449 md_get_uint8(mdp, &wc); /* WordCount - check? */ 1450 md_get_uint8(mdp, NULL); /* AndXCommand */ 1451 md_get_uint8(mdp, NULL); /* Reserved - must be zero */ 1452 md_get_uint16(mdp, NULL); /* Offset to next cmd WordCount */ 1453 md_get_uint8(mdp, NULL); /* Oplock level granted */ 1454 md_get_uint16(mdp, &np->n_fid); /* FID */ 1455 /* ignore rest */ 1456 1457bad: 1458 smb_rq_done(rqp); 1459 return (error); 1460} 1461 1462/* 1463 * Setup a request for NT DIRECTORY CHANGE NOTIFY. 1464 */ 1465int 1466smbfs_smb_nt_dirnotify_setup(struct smbnode *dnp, struct smb_rq **rqpp, struct smb_cred *scred, void (*notifyhook)(void *), void *notifyarg) 1467{ 1468 struct smb_rq *rqp; 1469 struct smb_share *ssp = dnp->n_mount->sm_share; 1470 struct mbchain *mbp; 1471 int error; 1472 1473 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_TRANSACT, scred, &rqp); 1474 if (error) 1475 return error; 1476 smb_rq_getrequest(rqp, &mbp); 1477 smb_rq_wstart(rqp); 1478 mb_put_uint8(mbp, 0xff); /* Max setup words to return */ 1479 mb_put_uint16le(mbp, 0); /* Flags (according to Samba) */ 1480 mb_put_uint32le(mbp, 0); /* Total parameter bytes being sent*/ 1481 mb_put_uint32le(mbp, 0); /* Total data bytes being sent */ 1482 mb_put_uint32le(mbp, 10*1024); /* Max parameter bytes to return */ 1483 mb_put_uint32le(mbp, 0); /* Max data bytes to return */ 1484 mb_put_uint32le(mbp, 0); /* Parameter bytes sent this buffer */ 1485 mb_put_uint32le(mbp, 0); /* Offset (from h. start) to Param */ 1486 mb_put_uint32le(mbp, 0); /* Data bytes sent this buffer */ 1487 mb_put_uint32le(mbp, 0); /* Offset (from h. start) to Data */ 1488 mb_put_uint8(mbp, 4); /* Count of setup words */ 1489 mb_put_uint16le(mbp, SMB_NTTRANS_NOTIFY_CHANGE); /* Trans func code */ 1490 1491 /* NT TRANSACT NOTIFY CHANGE: Request Change Notification */ 1492 mb_put_uint32le(mbp, 1493 FILE_NOTIFY_CHANGE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES| 1494 FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE| 1495 FILE_NOTIFY_CHANGE_CREATION); /* CompletionFilter */ 1496 mb_put_mem(mbp, (void *)&dnp->n_fid, 2, MB_MSYSTEM); /* FID */ 1497 mb_put_uint8(mbp, 0); /* WatchTree - Watch all subdirs too */ 1498 mb_put_uint8(mbp, 0); /* Reserved - must be zero */ 1499 smb_rq_wend(rqp); 1500 smb_rq_bstart(rqp); 1501 smb_rq_bend(rqp); 1502 1503 /* No timeout */ 1504 rqp->sr_timo = -1; 1505 smb_rq_setcallback(rqp, notifyhook, notifyarg); 1506 1507 error = smb_rq_enqueue(rqp); 1508 if (!error) 1509 *rqpp = rqp; 1510 else 1511 smb_rq_done(rqp); 1512 1513 return (error); 1514} 1515 1516int 1517smbfs_smb_nt_dirnotify_fetch(struct smb_rq *rqp, int *hint) 1518{ 1519 int error; 1520 struct mdchain *mdp; 1521 u_int8_t sc; 1522 u_int32_t nextentry; 1523 1524 error = smb_rq_reply(rqp); 1525 if (error) { 1526 /* 1527 * If we get EMSGSIZE, there is already too many notifications 1528 * available for the directory, and the internal buffer 1529 * overflew. Just flag any possible relevant change. 1530 */ 1531 if (error == EMSGSIZE) { 1532 *hint = NOTE_ATTRIB | NOTE_WRITE; 1533 error = 0; 1534 } 1535 1536 goto bad; 1537 } 1538 1539 smb_rq_getreply(rqp, &mdp); 1540 1541 /* Parse reply */ 1542 error = md_get_mem(mdp, NULL, 4 + (8*4), MB_MZERO); /* skip */ 1543 if (error) 1544 goto bad; 1545 1546 md_get_uint8(mdp, &sc); /* SetupCount */ 1547 if (sc > 0) 1548 md_get_mem(mdp, NULL, sc * sizeof(u_int16_t), MB_MZERO); 1549 md_get_uint16(mdp, NULL); /* ByteCount */ 1550 md_get_mem(mdp, NULL, 1 + (sc % 2) * 2, MB_MZERO); /* Pad */ 1551 1552 /* 1553 * The notify data are blocks of 1554 * ULONG nextentry - offset of next entry from start of this one 1555 * ULONG action - type of notification 1556 * ULONG filenamelen - length of filename in bytes 1557 * WCHAR filename[filenamelen/2] - Unicode filename 1558 * nexentry == 0 means last notification, filename is in 16bit LE 1559 * unicode 1560 */ 1561 *hint = 0; 1562 do { 1563 u_int32_t action; 1564#if 0 1565 u_int32_t fnlen; 1566 u_int16_t fnc; 1567#endif 1568 1569 md_get_uint32le(mdp, &nextentry); 1570 md_get_uint32le(mdp, &action); 1571 if (nextentry) 1572 md_get_mem(mdp, NULL, nextentry - 2 * 4, MB_MZERO); 1573#if 0 1574 md_get_uint32le(mdp, &fnlen); 1575 1576 printf("notify: next %u act %u fnlen %u fname '", 1577 nextentry, action, fnlen); 1578 for(; fnlen > 0; fnlen -= 2) { 1579 md_get_uint16le(mdp, &fnc); 1580 printf("%c", fnc&0xff); 1581 } 1582 printf("'\n"); 1583#endif 1584 1585 switch(action) { 1586 case FILE_ACTION_ADDED: 1587 case FILE_ACTION_REMOVED: 1588 case FILE_ACTION_RENAMED_OLD_NAME: 1589 case FILE_ACTION_RENAMED_NEW_NAME: 1590 *hint |= NOTE_ATTRIB | NOTE_WRITE; 1591 break; 1592 1593 case FILE_ACTION_MODIFIED: 1594 *hint |= NOTE_ATTRIB; 1595 break; 1596 } 1597 } while(nextentry > 0); 1598 1599bad: 1600 smb_rq_done(rqp); 1601 return error; 1602} 1603 1604/* 1605 * Cancel previous SMB, with message ID mid. No reply is generated 1606 * to this one (only the previous message returns with error). 1607 */ 1608int 1609smbfs_smb_ntcancel(struct smb_connobj *layer, u_int16_t mid, struct smb_cred *scred) 1610{ 1611 struct smb_rq *rqp; 1612 struct mbchain *mbp; 1613 struct mbuf *m; 1614 u_int8_t *mp; 1615 int error; 1616 1617 error = smb_rq_alloc(layer, SMB_COM_NT_CANCEL, scred, &rqp); 1618 if (error) 1619 return (error); 1620 rqp->sr_flags |= SMBR_NOWAIT; /* do not wait for reply */ 1621 smb_rq_getrequest(rqp, &mbp); 1622 1623 /* 1624 * This is nonstandard. We need to rewrite the just written 1625 * mid to different one. Access underlying mbuf directly. 1626 * We assume mid is the last thing written smb_rq_alloc() 1627 * to request buffer. 1628 */ 1629 m = mbp->mb_cur; 1630 mp = mtod(m, u_int8_t *) + m->m_len - 2; 1631 SMBRQ_PUTLE16(mp, mid); 1632 rqp->sr_mid = mid; 1633 1634 smb_rq_wstart(rqp); 1635 smb_rq_wend(rqp); 1636 smb_rq_bstart(rqp); 1637 smb_rq_bend(rqp); 1638 1639 error = (smb_rq_simple(rqp)); 1640 1641 /* Discard, there is no real reply */ 1642 smb_rq_done(rqp); 1643 1644 return (error); 1645} 1646