1 #include <u.h> 2 #include <libc.h> 3 #include <fcall.h> 4 #include <thread.h> 5 #include <9p.h> 6 #include "cifs.h" 7 8 static char magic[] = { 0xff, 'S', 'M', 'B' }; 9 10 Session * 11 cifsdial(char *host, char *called, char *sysname) 12 { 13 int nbt, fd; 14 char *addr; 15 Session *s; 16 17 if(Debug) 18 fprint(2, "cifsdial: host=%s called=%s sysname=%s\n", host, called, sysname); 19 20 if((addr = netmkaddr(host, "tcp", "cifs")) == nil) 21 return nil; 22 23 nbt = 0; 24 if((fd = dial(addr, nil, nil, nil)) == -1){ 25 nbt = 1; 26 if((fd = nbtdial(host, called, sysname)) == -1) 27 return nil; 28 } 29 30 s = emalloc9p(sizeof(Session)); 31 memset(s, 0, sizeof(Session)); 32 33 s->fd = fd; 34 s->nbt = nbt; 35 s->mtu = MTU; 36 s->pid = getpid(); 37 s->mid = time(nil) ^ getpid(); 38 s->uid = NO_UID; 39 s->seq = 0; 40 s->seqrun = 0; 41 s->secmode = SECMODE_SIGN_ENABLED; /* hope for the best */ 42 s->flags2 = FL2_KNOWS_LONG_NAMES | FL2_HAS_LONG_NAMES | FL2_PAGEING_IO; 43 s->macidx = -1; 44 45 return s; 46 } 47 48 void 49 cifsclose(Session *s) 50 { 51 if(s->fd) 52 close(s->fd); 53 free(s); 54 } 55 56 Pkt * 57 cifshdr(Session *s, Share *sp, int cmd) 58 { 59 Pkt *p; 60 int sign, tid, dfs; 61 62 dfs = 0; 63 tid = NO_TID; 64 Active = IDLE_TIME; 65 werrstr(""); 66 sign = s->secmode & SECMODE_SIGN_ENABLED? FL2_PACKET_SIGNATURES: 0; 67 68 if(sp){ 69 tid = sp->tid; 70 // FIXME! if(sp->options & SMB_SHARE_IS_IN_DFS) 71 // FIXME! dfs = FL2_DFS; 72 } 73 74 p = emalloc9p(sizeof(Pkt) + MTU); 75 memset(p, 0, sizeof(Pkt) +MTU); 76 77 p->buf = (uchar *)p + sizeof(Pkt); 78 p->s = s; 79 80 qlock(&s->seqlock); 81 if(s->seqrun){ 82 p->seq = s->seq; 83 s->seq = (s->seq + 2) % 0x10000; 84 } 85 qunlock(&s->seqlock); 86 87 nbthdr(p); 88 pmem(p, magic, nelem(magic)); 89 p8(p, cmd); 90 pl32(p, 0); /* status (error) */ 91 p8(p, FL_CASELESS_NAMES | FL_CANNONICAL_NAMES); /* flags */ 92 pl16(p, s->flags2 | dfs | sign); /* flags2 */ 93 pl16(p, (s->pid >> 16) & 0xffff); /* PID MS bits */ 94 pl32(p, p->seq); /* MAC / sequence number */ 95 pl32(p, 0); /* MAC */ 96 pl16(p, 0); /* padding */ 97 98 pl16(p, tid); 99 pl16(p, s->pid & 0xffff); 100 pl16(p, s->uid); 101 pl16(p, s->mid); 102 103 p->wordbase = p8(p, 0); /* filled in by pbytes() */ 104 105 return p; 106 } 107 108 void 109 pbytes(Pkt *p) 110 { 111 int n; 112 113 assert(p->wordbase != nil); /* cifshdr not called */ 114 assert(p->bytebase == nil); /* called twice */ 115 116 n = p->pos - p->wordbase; 117 assert(n % 2 != 0); /* even addr */ 118 *p->wordbase = n / 2; 119 120 p->bytebase = pl16(p, 0); /* filled in by cifsrpc() */ 121 } 122 123 static void 124 dmp(int seq, uchar *buf) 125 { 126 int i; 127 128 if(seq == 99) 129 print("\n "); 130 else 131 print("%+2d ", seq); 132 for(i = 0; i < 8; i++) 133 print("%02x ", buf[i] & 0xff); 134 print("\n"); 135 } 136 137 int 138 cifsrpc(Pkt *p) 139 { 140 int flags2, got, err; 141 uint tid, uid, seq; 142 uchar *pos; 143 char m[nelem(magic)]; 144 145 pos = p->pos; 146 if(p->bytebase){ 147 p->pos = p->bytebase; 148 pl16(p, pos - (p->bytebase + 2)); /* 2 = sizeof bytecount */ 149 } 150 p->pos = pos; 151 152 if(p->s->secmode & SECMODE_SIGN_ENABLED) 153 macsign(p, p->seq); 154 155 qlock(&p->s->rpclock); 156 got = nbtrpc(p); 157 qunlock(&p->s->rpclock); 158 if(got == -1) 159 return -1; 160 161 gmem(p, m, nelem(magic)); 162 if(memcmp(m, magic, nelem(magic)) != 0){ 163 werrstr("cifsrpc: bad magic number in packet %20ux%02ux%02ux%02ux", 164 m[0], m[1], m[2], m[3]); 165 return -1; 166 } 167 168 g8(p); /* cmd */ 169 err = gl32(p); /* errcode */ 170 g8(p); /* flags */ 171 flags2 = gl16(p); /* flags2 */ 172 gl16(p); /* PID MS bits */ 173 seq = gl32(p); /* reserved */ 174 gl32(p); /* MAC (if in use) */ 175 gl16(p); /* Padding */ 176 tid = gl16(p); /* TID */ 177 gl16(p); /* PID lsbs */ 178 uid = gl16(p); /* UID */ 179 gl16(p); /* mid */ 180 g8(p); /* word count */ 181 182 if(p->s->secmode & SECMODE_SIGN_ENABLED){ 183 if(macsign(p, p->seq+1) != 0 && p->s->seqrun){ 184 werrstr("cifsrpc: invalid packet signature"); 185 print("MAC signature bad\n"); 186 // FIXME: for debug only return -1; 187 } 188 }else{ 189 /* 190 * We allow the sequence number of zero as some old samba 191 * servers seem to fall back to this unexpectedly 192 * after reporting sequence numbers correctly for a while. 193 * 194 * Some other samba servers seem to always report a sequence 195 * number of zero if MAC signing is disabled, so we have to 196 * catch that too. 197 */ 198 if(p->s->seqrun && seq != p->seq && seq != 0){ 199 print("%ux != %ux bad sequence number\n", seq, p->seq); 200 return -1; 201 } 202 } 203 204 p->tid = tid; 205 if(p->s->uid == NO_UID) 206 p->s->uid = uid; 207 208 if(flags2 & FL2_NT_ERRCODES){ 209 /* is it a real error rather than info/warning/chatter? */ 210 if((err & 0xF0000000) == 0xC0000000){ 211 werrstr("%s", nterrstr(err)); 212 return -1; 213 } 214 }else{ 215 if(err){ 216 werrstr("%s", doserrstr(err)); 217 return -1; 218 } 219 } 220 return got; 221 } 222 223 224 /* 225 * Some older servers (old samba) prefer to talk older 226 * dialects but if given no choice they will talk the 227 * more modern ones, so we don't give them the choice. 228 */ 229 int 230 CIFSnegotiate(Session *s, long *svrtime, char *domain, int domlen, char *cname, 231 int cnamlen) 232 { 233 int d, i; 234 char *ispeak = "NT LM 0.12"; 235 static char *dialects[] = { 236 // { "PC NETWORK PROGRAM 1.0"}, 237 // { "MICROSOFT NETWORKS 1.03"}, 238 // { "MICROSOFT NETWORKS 3.0"}, 239 // { "LANMAN1.0"}, 240 // { "LM1.2X002"}, 241 // { "NT LANMAN 1.0"}, 242 { "NT LM 0.12" }, 243 }; 244 Pkt *p; 245 246 p = cifshdr(s, nil, SMB_COM_NEGOTIATE); 247 pbytes(p); 248 for(i = 0; i < nelem(dialects); i++){ 249 p8(p, STR_DIALECT); 250 pstr(p, dialects[i]); 251 } 252 253 if(cifsrpc(p) == -1){ 254 free(p); 255 return -1; 256 } 257 258 d = gl16(p); 259 if(d < 0 || d > nelem(dialects)){ 260 werrstr("no CIFS dialect in common"); 261 free(p); 262 return -1; 263 } 264 265 if(strcmp(dialects[d], ispeak) != 0){ 266 werrstr("%s dialect unsupported", dialects[d]); 267 free(p); 268 return -1; 269 } 270 271 s->secmode = g8(p); /* Security mode */ 272 273 gl16(p); /* Max outstanding requests */ 274 gl16(p); /* Max VCs */ 275 s->mtu = gl32(p); /* Max buffer size */ 276 gl32(p); /* Max raw buffer size (depricated) */ 277 gl32(p); /* Session key */ 278 s->caps = gl32(p); /* Server capabilities */ 279 *svrtime = gvtime(p); /* fileserver time */ 280 s->tz = (short)gl16(p) * 60; /* TZ in mins, is signed (SNIA doc is wrong) */ 281 s->challen = g8(p); /* Encryption key length */ 282 gl16(p); 283 gmem(p, s->chal, s->challen); /* Get the challenge */ 284 gstr(p, domain, domlen); /* source domain */ 285 286 { /* NetApp Filer seem not to report its called name */ 287 char *cn = emalloc9p(cnamlen); 288 289 gstr(p, cn, cnamlen); /* their name */ 290 if(strlen(cn) > 0) 291 memcpy(cname, cn, cnamlen); 292 free(cn); 293 } 294 295 if(s->caps & CAP_UNICODE) 296 s->flags2 |= FL2_UNICODE; 297 298 free(p); 299 return 0; 300 } 301 302 int 303 CIFSsession(Session *s) 304 { 305 char os[64], *q; 306 Rune r; 307 Pkt *p; 308 enum { 309 mycaps = CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS | 310 CAP_NT_FIND | CAP_STATUS32, 311 }; 312 313 s->seqrun = 1; /* activate the sequence number generation/checking */ 314 315 p = cifshdr(s, nil, SMB_COM_SESSION_SETUP_ANDX); 316 p8(p, 0xFF); /* No secondary command */ 317 p8(p, 0); /* Reserved (must be zero) */ 318 pl16(p, 0); /* Offset to next command */ 319 pl16(p, MTU); /* my max buffer size */ 320 pl16(p, 1); /* my max multiplexed pending requests */ 321 pl16(p, 0); /* Virtual connection # */ 322 pl32(p, 0); /* Session key (if vc != 0) */ 323 324 325 if((s->secmode & SECMODE_PW_ENCRYPT) == 0) { 326 pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size */ 327 pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size (UPPER CASE) */ 328 pl32(p, 0); /* Reserved */ 329 pl32(p, mycaps); 330 pbytes(p); 331 332 for(q = Sess->auth->resp[0]; *q; ){ 333 q += chartorune(&r, q); 334 pl16(p, toupperrune(r)); 335 } 336 pl16(p, 0); 337 338 for(q = Sess->auth->resp[0]; *q; ){ 339 q += chartorune(&r, q); 340 pl16(p, r); 341 } 342 pl16(p, 0); 343 }else{ 344 pl16(p, Sess->auth->len[0]); /* LM passwd size */ 345 pl16(p, Sess->auth->len[1]); /* NTLM passwd size */ 346 pl32(p, 0); /* Reserved */ 347 pl32(p, mycaps); 348 pbytes(p); 349 350 pmem(p, Sess->auth->resp[0], Sess->auth->len[0]); 351 pmem(p, Sess->auth->resp[1], Sess->auth->len[1]); 352 } 353 354 pstr(p, Sess->auth->user); /* Account name */ 355 pstr(p, Sess->auth->windom); /* Primary domain */ 356 pstr(p, "plan9"); /* Client OS */ 357 pstr(p, argv0); /* Client LAN Manager type */ 358 359 if(cifsrpc(p) == -1){ 360 free(p); 361 return -1; 362 } 363 364 g8(p); /* Reserved (0) */ 365 gl16(p); /* Offset to next command wordcount */ 366 Sess->isguest = gl16(p) & 1; /* logged in as guest */ 367 368 gl16(p); 369 gl16(p); 370 /* no security blob here - we don't understand extended security anyway */ 371 gstr(p, os, sizeof(os)); 372 s->remos = estrdup9p(os); 373 374 free(p); 375 return 0; 376 } 377 378 379 CIFStreeconnect(Session *s, char *cname, char *tree, Share *sp) 380 { 381 int len; 382 char *resp, *path; 383 char zeros[24]; 384 Pkt *p; 385 386 resp = Sess->auth->resp[0]; 387 len = Sess->auth->len[0]; 388 if((s->secmode & SECMODE_USER) != SECMODE_USER){ 389 memset(zeros, 0, sizeof(zeros)); 390 resp = zeros; 391 len = sizeof(zeros); 392 } 393 394 p = cifshdr(s, nil, SMB_COM_TREE_CONNECT_ANDX); 395 p8(p, 0xFF); /* Secondary command */ 396 p8(p, 0); /* Reserved */ 397 pl16(p, 0); /* Offset to next Word Count */ 398 pl16(p, 0); /* Flags */ 399 400 if((s->secmode & SECMODE_PW_ENCRYPT) == 0){ 401 pl16(p, len+1); /* password len, including null */ 402 pbytes(p); 403 pascii(p, resp); 404 }else{ 405 pl16(p, len); 406 pbytes(p); 407 pmem(p, resp, len); 408 } 409 410 path = smprint("//%s/%s", cname, tree); 411 strupr(path); 412 ppath(p, path); /* path */ 413 free(path); 414 415 pascii(p, "?????"); /* service type any (so we can do RAP calls) */ 416 417 if(cifsrpc(p) == -1){ 418 free(p); 419 return -1; 420 } 421 g8(p); /* Secondary command */ 422 g8(p); /* Reserved */ 423 gl16(p); /* Offset to next command */ 424 sp->options = g8(p); /* options supported */ 425 sp->tid = p->tid; /* get received TID from packet header */ 426 free(p); 427 return 0; 428 } 429 430 int 431 CIFSlogoff(Session *s) 432 { 433 int rc; 434 Pkt *p; 435 436 p = cifshdr(s, nil, SMB_COM_LOGOFF_ANDX); 437 p8(p, 0xFF); /* No ANDX command */ 438 p8(p, 0); /* Reserved (must be zero) */ 439 pl16(p, 0); /* offset ot ANDX */ 440 pbytes(p); 441 rc = cifsrpc(p); 442 443 free(p); 444 return rc; 445 } 446 447 int 448 CIFStreedisconnect(Session *s, Share *sp) 449 { 450 int rc; 451 Pkt *p; 452 453 p = cifshdr(s, sp, SMB_COM_TREE_DISCONNECT); 454 pbytes(p); 455 rc = cifsrpc(p); 456 457 free(p); 458 return rc; 459 } 460 461 462 int 463 CIFSdeletefile(Session *s, Share *sp, char *name) 464 { 465 int rc; 466 Pkt *p; 467 468 p = cifshdr(s, sp, SMB_COM_DELETE); 469 pl16(p, ATTR_HIDDEN|ATTR_SYSTEM); /* search attributes */ 470 pbytes(p); 471 p8(p, STR_ASCII); /* buffer format */ 472 ppath(p, name); 473 rc = cifsrpc(p); 474 475 free(p); 476 return rc; 477 } 478 479 int 480 CIFSdeletedirectory(Session *s, Share *sp, char *name) 481 { 482 int rc; 483 Pkt *p; 484 485 p = cifshdr(s, sp, SMB_COM_DELETE_DIRECTORY); 486 pbytes(p); 487 p8(p, STR_ASCII); /* buffer format */ 488 ppath(p, name); 489 rc = cifsrpc(p); 490 491 free(p); 492 return rc; 493 } 494 495 int 496 CIFScreatedirectory(Session *s, Share *sp, char *name) 497 { 498 int rc; 499 Pkt *p; 500 501 p = cifshdr(s, sp, SMB_COM_CREATE_DIRECTORY); 502 pbytes(p); 503 p8(p, STR_ASCII); 504 ppath(p, name); 505 rc = cifsrpc(p); 506 507 free(p); 508 return rc; 509 } 510 511 int 512 CIFSrename(Session *s, Share *sp, char *old, char *new) 513 { 514 int rc; 515 Pkt *p; 516 517 p = cifshdr(s, sp, SMB_COM_RENAME); 518 pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* search attributes */ 519 pbytes(p); 520 p8(p, STR_ASCII); 521 ppath(p, old); 522 p8(p, STR_ASCII); 523 ppath(p, new); 524 rc = cifsrpc(p); 525 526 free(p); 527 return rc; 528 } 529 530 531 /* for NT4/Win2k/XP */ 532 int 533 CIFS_NT_opencreate(Session *s, Share *sp, char *name, int flags, int options, 534 int attrs, int access, int share, int action, int *result, FInfo *fi) 535 { 536 Pkt *p; 537 int fh; 538 539 p = cifshdr(s, sp, SMB_COM_NT_CREATE_ANDX); 540 p8(p, 0xFF); /* Secondary command */ 541 p8(p, 0); /* Reserved */ 542 pl16(p, 0); /* Offset to next command */ 543 p8(p, 0); /* Reserved */ 544 pl16(p, utflen(name) *2); /* file name len */ 545 pl32(p, flags); /* Flags */ 546 pl32(p, 0); /* fid of cwd, if relative path */ 547 pl32(p, access); /* access desired */ 548 pl64(p, 0); /* initial allocation size */ 549 pl32(p, attrs); /* Extended attributes */ 550 pl32(p, share); /* Share Access */ 551 pl32(p, action); /* What to do on success/failure */ 552 pl32(p, options); /* Options */ 553 pl32(p, SECURITY_IMPERSONATION); /* Impersonation level */ 554 p8(p, SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY); /* security flags */ 555 pbytes(p); 556 p8(p, 0); /* FIXME: padding? */ 557 ppath(p, name); /* filename */ 558 559 if(cifsrpc(p) == -1){ 560 free(p); 561 return -1; 562 } 563 564 memset(fi, 0, sizeof(FInfo)); 565 g8(p); /* Secondary command */ 566 g8(p); /* Reserved */ 567 gl16(p); /* Offset to next command */ 568 g8(p); /* oplock granted */ 569 fh = gl16(p); /* FID for opened object */ 570 *result = gl32(p); /* create action taken */ 571 gl64(p); /* creation time */ 572 fi->accessed = gvtime(p); /* last access time */ 573 fi->written = gvtime(p); /* last written time */ 574 fi->changed = gvtime(p); /* change time */ 575 fi->attribs = gl32(p); /* extended attributes */ 576 gl64(p); /* bytes allocated */ 577 fi->size = gl64(p); /* file size */ 578 579 free(p); 580 return fh; 581 } 582 583 /* for Win95/98/ME */ 584 CIFS_SMB_opencreate(Session *s, Share *sp, char *name, int access, 585 int attrs, int action, int *result) 586 { 587 Pkt *p; 588 int fh; 589 590 p = cifshdr(s, sp, SMB_COM_OPEN_ANDX); 591 p8(p, 0xFF); /* Secondary command */ 592 p8(p, 0); /* Reserved */ 593 pl16(p, 0); /* Offset to next command */ 594 pl16(p, 0); /* Flags (0 == no stat(2) info) */ 595 pl16(p, access); /* desired access */ 596 pl16(p, ATTR_HIDDEN|ATTR_SYSTEM);/* search attributes */ 597 pl16(p, attrs); /* file attribytes */ 598 pdatetime(p, 0); /* creation time (0 == now) */ 599 pl16(p, action); /* What to do on success/failure */ 600 pl32(p, 0); /* allocation size */ 601 pl32(p, 0); /* reserved */ 602 pl32(p, 0); /* reserved */ 603 pbytes(p); 604 ppath(p, name); /* filename */ 605 606 if(cifsrpc(p) == -1){ 607 free(p); 608 return -1; 609 } 610 611 g8(p); /* Secondary command */ 612 g8(p); /* Reserved */ 613 gl16(p); /* Offset to next command */ 614 fh = gl16(p); /* FID for opened object */ 615 gl16(p); /* extended attributes */ 616 gvtime(p); /* last written time */ 617 gl32(p); /* file size */ 618 gl16(p); /* file type (disk/fifo/printer etc) */ 619 gl16(p); /* device status (for fifos) */ 620 *result = gl16(p); /* access granted */ 621 622 free(p); 623 return fh; 624 } 625 626 vlong 627 CIFSwrite(Session *s, Share *sp, int fh, uvlong off, void *buf, vlong n) 628 { 629 Pkt *p; 630 vlong got; 631 632 /* FIXME: Payload should be padded to long boundary */ 633 assert((n & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES); 634 assert((off & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES); 635 assert(n < s->mtu - T2HDRLEN || s->caps & CAP_LARGE_WRITEX); 636 637 p = cifshdr(s, sp, SMB_COM_WRITE_ANDX); 638 p8(p, 0xFF); /* Secondary command */ 639 p8(p, 0); /* Reserved */ 640 pl16(p, 0); /* Offset to next command */ 641 pl16(p, fh); /* File handle */ 642 pl32(p, off & 0xffffffff); /* LSBs of Offset */ 643 pl32(p, 0); /* Reserved (0) */ 644 pl16(p, s->nocache); /* Write mode (0 - write through) */ 645 pl16(p, 0); /* Bytes remaining */ 646 pl16(p, n >> 16); /* MSBs of length */ 647 pl16(p, n & 0xffffffff); /* LSBs of length */ 648 pl16(p, T2HDRLEN); /* Offset to data, in bytes */ 649 pl32(p, off >> 32); /* MSBs of offset */ 650 pbytes(p); 651 652 p->pos = p->buf +T2HDRLEN +NBHDRLEN; 653 pmem(p, buf, n); /* Data */ 654 655 if(cifsrpc(p) == -1){ 656 free(p); 657 return -1; 658 } 659 660 g8(p); /* Secondary command */ 661 g8(p); /* Reserved */ 662 gl16(p); /* Offset to next command */ 663 got = gl16(p); /* LSWs of bytes written */ 664 gl16(p); /* remaining (space ?) */ 665 got |= (gl16(p) << 16); /* MSWs of bytes written */ 666 667 free(p); 668 return got; 669 } 670 671 vlong 672 CIFSread(Session *s, Share *sp, int fh, uvlong off, void *buf, vlong n, 673 vlong minlen) 674 { 675 int doff; 676 vlong got; 677 Pkt *p; 678 679 assert((n & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES); 680 assert((off & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES); 681 assert(n < s->mtu - T2HDRLEN || s->caps & CAP_LARGE_READX); 682 683 p = cifshdr(s, sp, SMB_COM_READ_ANDX); 684 p8(p, 0xFF); /* Secondary command */ 685 p8(p, 0); /* Reserved */ 686 pl16(p, 0); /* Offset to next command */ 687 pl16(p, fh); /* File handle */ 688 pl32(p, off & 0xffffffff); /* Offset to beginning of write */ 689 pl16(p, n); /* Maximum number of bytes to return */ 690 pl16(p, minlen); /* Minimum number of bytes to return */ 691 pl32(p, (uint)n >> 16); /* MSBs of maxlen */ 692 pl16(p, 0); /* Bytes remaining to satisfy request */ 693 pl32(p, off >> 32); /* MS 32 bits of offset */ 694 pbytes(p); 695 696 if(cifsrpc(p) == -1){ 697 free(p); 698 return -1; 699 } 700 701 g8(p); /* Secondary command */ 702 g8(p); /* Reserved */ 703 gl16(p); /* Offset to next command */ 704 gl16(p); /* Remaining */ 705 gl16(p); /* Compression mode */ 706 gl16(p); /* Reserved */ 707 got = gl16(p); /* length */ 708 doff = gl16(p); /* Offset from header to data */ 709 got |= gl16(p) << 16; 710 711 p->pos = p->buf + doff + NBHDRLEN; 712 713 gmem(p, buf, got); /* data */ 714 free(p); 715 return got; 716 } 717 718 int 719 CIFSflush(Session *s, Share *sp, int fh) 720 { 721 int rc; 722 Pkt *p; 723 724 p = cifshdr(s, sp, SMB_COM_FLUSH); 725 pl16(p, fh); /* fid */ 726 pbytes(p); 727 rc = cifsrpc(p); 728 729 free(p); 730 return rc; 731 } 732 733 /* 734 * Setting the time of last write to -1 gives "now" if the file 735 * was written and leaves it the same if the file wasn't written. 736 */ 737 int 738 CIFSclose(Session *s, Share *sp, int fh) 739 { 740 int rc; 741 Pkt *p; 742 743 p = cifshdr(s, sp, SMB_COM_CLOSE); 744 pl16(p, fh); /* fid */ 745 pl32(p, ~0L); /* Time of last write (none) */ 746 pbytes(p); 747 rc = cifsrpc(p); 748 749 free(p); 750 return rc; 751 } 752 753 754 int 755 CIFSfindclose2(Session *s, Share *sp, int sh) 756 { 757 int rc; 758 Pkt *p; 759 760 p = cifshdr(s, sp, SMB_COM_FIND_CLOSE2); 761 pl16(p, sh); /* sid */ 762 pbytes(p); 763 rc = cifsrpc(p); 764 765 free(p); 766 return rc; 767 } 768 769 770 int 771 CIFSecho(Session *s) 772 { 773 Pkt *p; 774 int rc; 775 776 p = cifshdr(s, nil, SMB_COM_ECHO); 777 pl16(p, 1); /* number of replies */ 778 pbytes(p); 779 pascii(p, "abcdefghijklmnopqrstuvwxyz"); /* data */ 780 781 rc = cifsrpc(p); 782 free(p); 783 return rc; 784 } 785 786 787 int 788 CIFSsetinfo(Session *s, Share *sp, char *path, FInfo *fip) 789 { 790 int rc; 791 Pkt *p; 792 793 p = cifshdr(s, sp, SMB_COM_SET_INFORMATION); 794 pl16(p, fip->attribs); 795 pl32(p, time(nil) - s->tz); /* modified time */ 796 pl64(p, 0); /* reserved */ 797 pl16(p, 0); /* reserved */ 798 799 pbytes(p); 800 p8(p, STR_ASCII); /* buffer format */ 801 ppath(p, path); 802 803 rc = cifsrpc(p); 804 free(p); 805 return rc; 806 } 807