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 *
cifsdial(char * host,char * called,char * sysname)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
cifsclose(Session * s)49 cifsclose(Session *s)
50 {
51 if(s->fd)
52 close(s->fd);
53 free(s);
54 }
55
56 Pkt *
cifshdr(Session * s,Share * sp,int cmd)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
pbytes(Pkt * p)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
dmp(int seq,uchar * buf)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
cifsrpc(Pkt * p)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
CIFSnegotiate(Session * s,long * svrtime,char * domain,int domlen,char * cname,int cnamlen)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
CIFSsession(Session * s)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
CIFStreeconnect(Session * s,char * cname,char * tree,Share * sp)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
CIFSlogoff(Session * s)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
CIFStreedisconnect(Session * s,Share * sp)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
CIFSdeletefile(Session * s,Share * sp,char * name)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
CIFSdeletedirectory(Session * s,Share * sp,char * name)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
CIFScreatedirectory(Session * s,Share * sp,char * name)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
CIFSrename(Session * s,Share * sp,char * old,char * new)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
CIFS_NT_opencreate(Session * s,Share * sp,char * name,int flags,int options,int attrs,int access,int share,int action,int * result,FInfo * fi)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 */
CIFS_SMB_opencreate(Session * s,Share * sp,char * name,int access,int attrs,int action,int * result)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
CIFSwrite(Session * s,Share * sp,int fh,uvlong off,void * buf,vlong n)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
CIFSread(Session * s,Share * sp,int fh,uvlong off,void * buf,vlong n,vlong minlen)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
CIFSflush(Session * s,Share * sp,int fh)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
CIFSclose(Session * s,Share * sp,int fh)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
CIFSfindclose2(Session * s,Share * sp,int sh)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
CIFSecho(Session * s)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
CIFSsetinfo(Session * s,Share * sp,char * path,FInfo * fip)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