Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}