xref: /plan9/sys/src/cmd/cifs/cifs.c (revision 976d3a687802c08e9dea20e32392e7a12b1f3502)
1671dfc47SDavid du Colombier #include <u.h>
2671dfc47SDavid du Colombier #include <libc.h>
3671dfc47SDavid du Colombier #include <fcall.h>
4671dfc47SDavid du Colombier #include <thread.h>
5671dfc47SDavid du Colombier #include <9p.h>
6671dfc47SDavid du Colombier #include "cifs.h"
7671dfc47SDavid du Colombier 
8671dfc47SDavid du Colombier static char magic[] = { 0xff, 'S', 'M', 'B' };
9671dfc47SDavid du Colombier 
10671dfc47SDavid du Colombier Session *
cifsdial(char * host,char * called,char * sysname)11671dfc47SDavid du Colombier cifsdial(char *host, char *called, char *sysname)
12671dfc47SDavid du Colombier {
13671dfc47SDavid du Colombier 	int nbt, fd;
14671dfc47SDavid du Colombier 	char *addr;
15671dfc47SDavid du Colombier 	Session *s;
16671dfc47SDavid du Colombier 
17671dfc47SDavid du Colombier 	if(Debug)
18671dfc47SDavid du Colombier 		fprint(2, "cifsdial: host=%s called=%s sysname=%s\n", host, called, sysname);
19671dfc47SDavid du Colombier 
20671dfc47SDavid du Colombier 	if((addr = netmkaddr(host, "tcp", "cifs")) == nil)
21671dfc47SDavid du Colombier 		return nil;
22671dfc47SDavid du Colombier 
23671dfc47SDavid du Colombier 	nbt = 0;
24671dfc47SDavid du Colombier 	if((fd = dial(addr, nil, nil, nil)) == -1){
25671dfc47SDavid du Colombier 		nbt = 1;
26671dfc47SDavid du Colombier 		if((fd = nbtdial(host, called, sysname)) == -1)
27671dfc47SDavid du Colombier 			return nil;
28671dfc47SDavid du Colombier 	}
29671dfc47SDavid du Colombier 
30671dfc47SDavid du Colombier 	s = emalloc9p(sizeof(Session));
31671dfc47SDavid du Colombier 	memset(s, 0, sizeof(Session));
32671dfc47SDavid du Colombier 
33671dfc47SDavid du Colombier 	s->fd = fd;
34671dfc47SDavid du Colombier 	s->nbt = nbt;
35671dfc47SDavid du Colombier 	s->mtu = MTU;
36671dfc47SDavid du Colombier 	s->pid = getpid();
37671dfc47SDavid du Colombier 	s->mid = time(nil) ^ getpid();
38671dfc47SDavid du Colombier 	s->uid = NO_UID;
39671dfc47SDavid du Colombier 	s->seq = 0;
40671dfc47SDavid du Colombier 	s->seqrun = 0;
41671dfc47SDavid du Colombier 	s->secmode = SECMODE_SIGN_ENABLED;	/* hope for the best */
42671dfc47SDavid du Colombier 	s->flags2 = FL2_KNOWS_LONG_NAMES | FL2_HAS_LONG_NAMES | FL2_PAGEING_IO;
43671dfc47SDavid du Colombier 	s->macidx = -1;
44671dfc47SDavid du Colombier 
45671dfc47SDavid du Colombier 	return s;
46671dfc47SDavid du Colombier }
47671dfc47SDavid du Colombier 
48671dfc47SDavid du Colombier void
cifsclose(Session * s)49671dfc47SDavid du Colombier cifsclose(Session *s)
50671dfc47SDavid du Colombier {
51671dfc47SDavid du Colombier 	if(s->fd)
52671dfc47SDavid du Colombier 		close(s->fd);
53671dfc47SDavid du Colombier 	free(s);
54671dfc47SDavid du Colombier }
55671dfc47SDavid du Colombier 
56671dfc47SDavid du Colombier Pkt *
cifshdr(Session * s,Share * sp,int cmd)57671dfc47SDavid du Colombier cifshdr(Session *s, Share *sp, int cmd)
58671dfc47SDavid du Colombier {
59671dfc47SDavid du Colombier 	Pkt *p;
60671dfc47SDavid du Colombier 	int sign, tid, dfs;
61671dfc47SDavid du Colombier 
62671dfc47SDavid du Colombier 	dfs = 0;
63671dfc47SDavid du Colombier 	tid = NO_TID;
64671dfc47SDavid du Colombier 	Active = IDLE_TIME;
65*976d3a68SDavid du Colombier 	werrstr("");
66671dfc47SDavid du Colombier 	sign = s->secmode & SECMODE_SIGN_ENABLED? FL2_PACKET_SIGNATURES: 0;
67671dfc47SDavid du Colombier 
68671dfc47SDavid du Colombier 	if(sp){
69671dfc47SDavid du Colombier 		tid = sp->tid;
70671dfc47SDavid du Colombier // FIXME!		if(sp->options & SMB_SHARE_IS_IN_DFS)
71671dfc47SDavid du Colombier // FIXME!			dfs = FL2_DFS;
72671dfc47SDavid du Colombier 	}
73671dfc47SDavid du Colombier 
74671dfc47SDavid du Colombier 	p = emalloc9p(sizeof(Pkt) + MTU);
75671dfc47SDavid du Colombier 	memset(p, 0, sizeof(Pkt) +MTU);
76671dfc47SDavid du Colombier 
77671dfc47SDavid du Colombier 	p->buf = (uchar *)p + sizeof(Pkt);
78671dfc47SDavid du Colombier 	p->s = s;
79671dfc47SDavid du Colombier 
80671dfc47SDavid du Colombier 	qlock(&s->seqlock);
81671dfc47SDavid du Colombier 	if(s->seqrun){
82671dfc47SDavid du Colombier 		p->seq = s->seq;
83671dfc47SDavid du Colombier 		s->seq = (s->seq + 2) % 0x10000;
84671dfc47SDavid du Colombier 	}
85671dfc47SDavid du Colombier 	qunlock(&s->seqlock);
86671dfc47SDavid du Colombier 
87671dfc47SDavid du Colombier 	nbthdr(p);
88671dfc47SDavid du Colombier 	pmem(p, magic, nelem(magic));
89671dfc47SDavid du Colombier 	p8(p, cmd);
90671dfc47SDavid du Colombier 	pl32(p, 0);				/* status (error) */
91671dfc47SDavid du Colombier 	p8(p, FL_CASELESS_NAMES | FL_CANNONICAL_NAMES); /* flags */
92671dfc47SDavid du Colombier 	pl16(p, s->flags2 | dfs | sign);	/* flags2 */
93671dfc47SDavid du Colombier 	pl16(p, (s->pid >> 16) & 0xffff);	/* PID MS bits */
94671dfc47SDavid du Colombier 	pl32(p, p->seq);			/* MAC / sequence number */
95671dfc47SDavid du Colombier 	pl32(p, 0);				/* MAC */
96671dfc47SDavid du Colombier 	pl16(p, 0);				/* padding */
97671dfc47SDavid du Colombier 
98671dfc47SDavid du Colombier 	pl16(p, tid);
99671dfc47SDavid du Colombier 	pl16(p, s->pid & 0xffff);
100671dfc47SDavid du Colombier 	pl16(p, s->uid);
101671dfc47SDavid du Colombier 	pl16(p, s->mid);
102671dfc47SDavid du Colombier 
103671dfc47SDavid du Colombier 	p->wordbase = p8(p, 0);		/* filled in by pbytes() */
104671dfc47SDavid du Colombier 
105671dfc47SDavid du Colombier 	return p;
106671dfc47SDavid du Colombier }
107671dfc47SDavid du Colombier 
108671dfc47SDavid du Colombier void
pbytes(Pkt * p)109671dfc47SDavid du Colombier pbytes(Pkt *p)
110671dfc47SDavid du Colombier {
111671dfc47SDavid du Colombier 	int n;
112671dfc47SDavid du Colombier 
113671dfc47SDavid du Colombier 	assert(p->wordbase != nil);	/* cifshdr not called */
114671dfc47SDavid du Colombier 	assert(p->bytebase == nil);	/* called twice */
115671dfc47SDavid du Colombier 
116671dfc47SDavid du Colombier 	n = p->pos - p->wordbase;
117671dfc47SDavid du Colombier 	assert(n % 2 != 0);		/* even addr */
118671dfc47SDavid du Colombier 	*p->wordbase = n / 2;
119671dfc47SDavid du Colombier 
120671dfc47SDavid du Colombier 	p->bytebase = pl16(p, 0);	/* filled in by cifsrpc() */
121671dfc47SDavid du Colombier }
122671dfc47SDavid du Colombier 
123671dfc47SDavid du Colombier static void
dmp(int seq,uchar * buf)124671dfc47SDavid du Colombier dmp(int seq, uchar *buf)
125671dfc47SDavid du Colombier {
126671dfc47SDavid du Colombier 	int i;
127671dfc47SDavid du Colombier 
128671dfc47SDavid du Colombier 	if(seq == 99)
129671dfc47SDavid du Colombier 		print("\n   ");
130671dfc47SDavid du Colombier 	else
131671dfc47SDavid du Colombier 		print("%+2d ", seq);
132671dfc47SDavid du Colombier 	for(i = 0; i < 8; i++)
133671dfc47SDavid du Colombier 		print("%02x ", buf[i] & 0xff);
134671dfc47SDavid du Colombier 	print("\n");
135671dfc47SDavid du Colombier }
136671dfc47SDavid du Colombier 
137671dfc47SDavid du Colombier int
cifsrpc(Pkt * p)138671dfc47SDavid du Colombier cifsrpc(Pkt *p)
139671dfc47SDavid du Colombier {
140671dfc47SDavid du Colombier 	int flags2, got, err;
141671dfc47SDavid du Colombier 	uint tid, uid, seq;
142671dfc47SDavid du Colombier 	uchar *pos;
143671dfc47SDavid du Colombier 	char m[nelem(magic)];
144671dfc47SDavid du Colombier 
145671dfc47SDavid du Colombier 	pos = p->pos;
146671dfc47SDavid du Colombier 	if(p->bytebase){
147671dfc47SDavid du Colombier 		p->pos = p->bytebase;
148671dfc47SDavid du Colombier 		pl16(p, pos - (p->bytebase + 2)); /* 2 = sizeof bytecount */
149671dfc47SDavid du Colombier 	}
150671dfc47SDavid du Colombier 	p->pos = pos;
151671dfc47SDavid du Colombier 
152671dfc47SDavid du Colombier 	if(p->s->secmode & SECMODE_SIGN_ENABLED)
153671dfc47SDavid du Colombier 		macsign(p, p->seq);
154671dfc47SDavid du Colombier 
155671dfc47SDavid du Colombier 	qlock(&p->s->rpclock);
156671dfc47SDavid du Colombier 	got = nbtrpc(p);
157671dfc47SDavid du Colombier 	qunlock(&p->s->rpclock);
158671dfc47SDavid du Colombier 	if(got == -1)
159671dfc47SDavid du Colombier 		return -1;
160671dfc47SDavid du Colombier 
161671dfc47SDavid du Colombier 	gmem(p, m, nelem(magic));
162671dfc47SDavid du Colombier 	if(memcmp(m, magic, nelem(magic)) != 0){
163671dfc47SDavid du Colombier 		werrstr("cifsrpc: bad magic number in packet %20ux%02ux%02ux%02ux",
164671dfc47SDavid du Colombier 			m[0], m[1], m[2], m[3]);
165671dfc47SDavid du Colombier 		return -1;
166671dfc47SDavid du Colombier 	}
167671dfc47SDavid du Colombier 
168671dfc47SDavid du Colombier 	g8(p);				/* cmd */
169671dfc47SDavid du Colombier 	err = gl32(p);			/* errcode */
170671dfc47SDavid du Colombier 	g8(p);				/* flags */
171671dfc47SDavid du Colombier 	flags2 = gl16(p);		/* flags2 */
172671dfc47SDavid du Colombier 	gl16(p);			/* PID MS bits */
173671dfc47SDavid du Colombier 	seq = gl32(p);			/* reserved */
174671dfc47SDavid du Colombier 	gl32(p);			/* MAC (if in use) */
175671dfc47SDavid du Colombier 	gl16(p);			/* Padding */
176671dfc47SDavid du Colombier 	tid = gl16(p);			/* TID */
177671dfc47SDavid du Colombier 	gl16(p);			/* PID lsbs */
178671dfc47SDavid du Colombier 	uid = gl16(p);			/* UID */
179671dfc47SDavid du Colombier 	gl16(p);			/* mid */
180671dfc47SDavid du Colombier 	g8(p);				/* word count */
181671dfc47SDavid du Colombier 
182671dfc47SDavid du Colombier 	if(p->s->secmode & SECMODE_SIGN_ENABLED){
183671dfc47SDavid du Colombier 		if(macsign(p, p->seq+1) != 0 && p->s->seqrun){
184671dfc47SDavid du Colombier 			werrstr("cifsrpc: invalid packet signature");
185671dfc47SDavid du Colombier print("MAC signature bad\n");
186671dfc47SDavid du Colombier // FIXME: for debug only			return -1;
187671dfc47SDavid du Colombier 		}
188671dfc47SDavid du Colombier 	}else{
189671dfc47SDavid du Colombier 		/*
190671dfc47SDavid du Colombier 		 * We allow the sequence number of zero as some old samba
191671dfc47SDavid du Colombier 		 * servers seem to fall back to this unexpectedly
192671dfc47SDavid du Colombier 		 * after reporting sequence numbers correctly for a while.
193671dfc47SDavid du Colombier 		 *
194671dfc47SDavid du Colombier 		 * Some other samba servers seem to always report a sequence
195671dfc47SDavid du Colombier 		 * number of zero if MAC signing is disabled, so we have to
196671dfc47SDavid du Colombier 		 * catch that too.
197671dfc47SDavid du Colombier 		 */
198671dfc47SDavid du Colombier 		if(p->s->seqrun && seq != p->seq && seq != 0){
199*976d3a68SDavid du Colombier 			print("%ux != %ux bad sequence number\n", seq, p->seq);
200671dfc47SDavid du Colombier 			return -1;
201671dfc47SDavid du Colombier 		}
202671dfc47SDavid du Colombier 	}
203671dfc47SDavid du Colombier 
204671dfc47SDavid du Colombier 	p->tid = tid;
205671dfc47SDavid du Colombier 	if(p->s->uid == NO_UID)
206671dfc47SDavid du Colombier 		p->s->uid = uid;
207671dfc47SDavid du Colombier 
208671dfc47SDavid du Colombier 	if(flags2 & FL2_NT_ERRCODES){
209*976d3a68SDavid du Colombier 		/* is it a real error rather than info/warning/chatter? */
210671dfc47SDavid du Colombier 		if((err & 0xF0000000) == 0xC0000000){
211671dfc47SDavid du Colombier 			werrstr("%s", nterrstr(err));
212671dfc47SDavid du Colombier 			return -1;
213671dfc47SDavid du Colombier 		}
214671dfc47SDavid du Colombier 	}else{
215671dfc47SDavid du Colombier 		if(err){
216671dfc47SDavid du Colombier 			werrstr("%s", doserrstr(err));
217671dfc47SDavid du Colombier 			return -1;
218671dfc47SDavid du Colombier 		}
219671dfc47SDavid du Colombier 	}
220671dfc47SDavid du Colombier 	return got;
221671dfc47SDavid du Colombier }
222671dfc47SDavid du Colombier 
223671dfc47SDavid du Colombier 
224671dfc47SDavid du Colombier /*
225671dfc47SDavid du Colombier  * Some older servers (old samba) prefer to talk older
226671dfc47SDavid du Colombier  * dialects but if given no choice they will talk the
227671dfc47SDavid du Colombier  * more modern ones, so we don't give them the choice.
228671dfc47SDavid du Colombier  */
229671dfc47SDavid du Colombier int
CIFSnegotiate(Session * s,long * svrtime,char * domain,int domlen,char * cname,int cnamlen)230*976d3a68SDavid du Colombier CIFSnegotiate(Session *s, long *svrtime, char *domain, int domlen, char *cname,
231*976d3a68SDavid du Colombier 	int cnamlen)
232671dfc47SDavid du Colombier {
233671dfc47SDavid du Colombier 	int d, i;
234671dfc47SDavid du Colombier 	char *ispeak = "NT LM 0.12";
235*976d3a68SDavid du Colombier 	static char *dialects[] = {
236671dfc47SDavid du Colombier //		{ "PC NETWORK PROGRAM 1.0"},
237671dfc47SDavid du Colombier //		{ "MICROSOFT NETWORKS 1.03"},
238671dfc47SDavid du Colombier //		{ "MICROSOFT NETWORKS 3.0"},
239671dfc47SDavid du Colombier //		{ "LANMAN1.0"},
240671dfc47SDavid du Colombier //		{ "LM1.2X002"},
241671dfc47SDavid du Colombier //		{ "NT LANMAN 1.0"},
242671dfc47SDavid du Colombier 		{ "NT LM 0.12" },
243671dfc47SDavid du Colombier 	};
244671dfc47SDavid du Colombier 	Pkt *p;
245671dfc47SDavid du Colombier 
246671dfc47SDavid du Colombier 	p = cifshdr(s, nil, SMB_COM_NEGOTIATE);
247671dfc47SDavid du Colombier 	pbytes(p);
248671dfc47SDavid du Colombier 	for(i = 0; i < nelem(dialects); i++){
249671dfc47SDavid du Colombier 		p8(p, STR_DIALECT);
250671dfc47SDavid du Colombier 		pstr(p, dialects[i]);
251671dfc47SDavid du Colombier 	}
252671dfc47SDavid du Colombier 
253671dfc47SDavid du Colombier 	if(cifsrpc(p) == -1){
254671dfc47SDavid du Colombier 		free(p);
255671dfc47SDavid du Colombier 		return -1;
256671dfc47SDavid du Colombier 	}
257671dfc47SDavid du Colombier 
258671dfc47SDavid du Colombier 	d = gl16(p);
259671dfc47SDavid du Colombier 	if(d < 0 || d > nelem(dialects)){
260671dfc47SDavid du Colombier 		werrstr("no CIFS dialect in common");
261671dfc47SDavid du Colombier 		free(p);
262671dfc47SDavid du Colombier 		return -1;
263671dfc47SDavid du Colombier 	}
264671dfc47SDavid du Colombier 
265671dfc47SDavid du Colombier 	if(strcmp(dialects[d], ispeak) != 0){
266671dfc47SDavid du Colombier 		werrstr("%s dialect unsupported", dialects[d]);
267671dfc47SDavid du Colombier 		free(p);
268671dfc47SDavid du Colombier 		return -1;
269671dfc47SDavid du Colombier 	}
270671dfc47SDavid du Colombier 
271671dfc47SDavid du Colombier 	s->secmode = g8(p);			/* Security mode */
272671dfc47SDavid du Colombier 
273671dfc47SDavid du Colombier 	gl16(p);				/* Max outstanding requests */
274671dfc47SDavid du Colombier 	gl16(p);				/* Max VCs */
275671dfc47SDavid du Colombier 	s->mtu = gl32(p);			/* Max buffer size */
276671dfc47SDavid du Colombier 	gl32(p);				/* Max raw buffer size (depricated) */
277671dfc47SDavid du Colombier 	gl32(p);				/* Session key */
278671dfc47SDavid du Colombier 	s->caps = gl32(p);			/* Server capabilities */
279671dfc47SDavid du Colombier 	*svrtime = gvtime(p);			/* fileserver time */
280671dfc47SDavid du Colombier 	s->tz = (short)gl16(p) * 60; /* TZ in mins, is signed (SNIA doc is wrong) */
281671dfc47SDavid du Colombier 	s->challen = g8(p);			/* Encryption key length */
282671dfc47SDavid du Colombier 	gl16(p);
283671dfc47SDavid du Colombier 	gmem(p, s->chal, s->challen);		/* Get the challenge */
284671dfc47SDavid du Colombier 	gstr(p, domain, domlen);		/* source domain */
285671dfc47SDavid du Colombier 
286671dfc47SDavid du Colombier 	{		/* NetApp Filer seem not to report its called name */
287671dfc47SDavid du Colombier 		char *cn = emalloc9p(cnamlen);
288671dfc47SDavid du Colombier 
289671dfc47SDavid du Colombier 		gstr(p, cn, cnamlen);		/* their name */
290671dfc47SDavid du Colombier 		if(strlen(cn) > 0)
291671dfc47SDavid du Colombier 			memcpy(cname, cn, cnamlen);
292671dfc47SDavid du Colombier 		free(cn);
293671dfc47SDavid du Colombier 	}
294671dfc47SDavid du Colombier 
295671dfc47SDavid du Colombier 	if(s->caps & CAP_UNICODE)
296671dfc47SDavid du Colombier 		s->flags2 |= FL2_UNICODE;
297671dfc47SDavid du Colombier 
298671dfc47SDavid du Colombier 	free(p);
299671dfc47SDavid du Colombier 	return 0;
300671dfc47SDavid du Colombier }
301671dfc47SDavid du Colombier 
302671dfc47SDavid du Colombier int
CIFSsession(Session * s)303671dfc47SDavid du Colombier CIFSsession(Session *s)
304671dfc47SDavid du Colombier {
305671dfc47SDavid du Colombier 	char os[64], *q;
306671dfc47SDavid du Colombier 	Rune r;
307671dfc47SDavid du Colombier 	Pkt *p;
308671dfc47SDavid du Colombier 	enum {
309671dfc47SDavid du Colombier 		mycaps = CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
310671dfc47SDavid du Colombier 			CAP_NT_FIND | CAP_STATUS32,
311671dfc47SDavid du Colombier 	};
312671dfc47SDavid du Colombier 
313671dfc47SDavid du Colombier 	s->seqrun = 1;	/* activate the sequence number generation/checking */
314671dfc47SDavid du Colombier 
315671dfc47SDavid du Colombier 	p = cifshdr(s, nil, SMB_COM_SESSION_SETUP_ANDX);
316671dfc47SDavid du Colombier 	p8(p, 0xFF);			/* No secondary command */
317671dfc47SDavid du Colombier 	p8(p, 0);			/* Reserved (must be zero) */
318671dfc47SDavid du Colombier 	pl16(p, 0);			/* Offset to next command */
319671dfc47SDavid du Colombier 	pl16(p, MTU);			/* my max buffer size */
320671dfc47SDavid du Colombier 	pl16(p, 1);			/* my max multiplexed pending requests */
321671dfc47SDavid du Colombier 	pl16(p, 0);			/* Virtual connection # */
322671dfc47SDavid du Colombier 	pl32(p, 0);			/* Session key (if vc != 0) */
323671dfc47SDavid du Colombier 
324671dfc47SDavid du Colombier 
325671dfc47SDavid du Colombier 	if((s->secmode & SECMODE_PW_ENCRYPT) == 0) {
326671dfc47SDavid du Colombier 		pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size */
327671dfc47SDavid du Colombier 		pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size (UPPER CASE) */
328671dfc47SDavid du Colombier 		pl32(p, 0);			/* Reserved */
329671dfc47SDavid du Colombier 		pl32(p, mycaps);
330671dfc47SDavid du Colombier 		pbytes(p);
331671dfc47SDavid du Colombier 
332671dfc47SDavid du Colombier 		for(q = Sess->auth->resp[0]; *q; ){
333671dfc47SDavid du Colombier 			q += chartorune(&r, q);
334671dfc47SDavid du Colombier 			pl16(p, toupperrune(r));
335671dfc47SDavid du Colombier 		}
336671dfc47SDavid du Colombier 		pl16(p, 0);
337671dfc47SDavid du Colombier 
338671dfc47SDavid du Colombier 		for(q = Sess->auth->resp[0]; *q; ){
339671dfc47SDavid du Colombier 			q += chartorune(&r, q);
340671dfc47SDavid du Colombier 			pl16(p, r);
341671dfc47SDavid du Colombier 		}
342671dfc47SDavid du Colombier 		pl16(p, 0);
343671dfc47SDavid du Colombier 	}else{
344671dfc47SDavid du Colombier 		pl16(p, Sess->auth->len[0]);	/* LM passwd size */
345671dfc47SDavid du Colombier 		pl16(p, Sess->auth->len[1]);	/* NTLM passwd size */
346671dfc47SDavid du Colombier 		pl32(p, 0);			/* Reserved  */
347671dfc47SDavid du Colombier 		pl32(p, mycaps);
348671dfc47SDavid du Colombier 		pbytes(p);
349671dfc47SDavid du Colombier 
350671dfc47SDavid du Colombier 		pmem(p, Sess->auth->resp[0], Sess->auth->len[0]);
351671dfc47SDavid du Colombier 		pmem(p, Sess->auth->resp[1], Sess->auth->len[1]);
352671dfc47SDavid du Colombier 	}
353671dfc47SDavid du Colombier 
354671dfc47SDavid du Colombier 	pstr(p, Sess->auth->user);	/* Account name */
355671dfc47SDavid du Colombier 	pstr(p, Sess->auth->windom);	/* Primary domain */
356671dfc47SDavid du Colombier 	pstr(p, "plan9");		/* Client OS */
357671dfc47SDavid du Colombier 	pstr(p, argv0);			/* Client LAN Manager type */
358671dfc47SDavid du Colombier 
359671dfc47SDavid du Colombier 	if(cifsrpc(p) == -1){
360671dfc47SDavid du Colombier 		free(p);
361671dfc47SDavid du Colombier 		return -1;
362671dfc47SDavid du Colombier 	}
363671dfc47SDavid du Colombier 
364671dfc47SDavid du Colombier 	g8(p);				/* Reserved (0) */
365671dfc47SDavid du Colombier 	gl16(p);			/* Offset to next command wordcount */
366671dfc47SDavid du Colombier 	Sess->isguest = gl16(p) & 1;	/* logged in as guest */
367671dfc47SDavid du Colombier 
368671dfc47SDavid du Colombier 	gl16(p);
369671dfc47SDavid du Colombier 	gl16(p);
370671dfc47SDavid du Colombier 	/* no security blob here - we don't understand extended security anyway */
371671dfc47SDavid du Colombier 	gstr(p, os, sizeof(os));
372671dfc47SDavid du Colombier 	s->remos = estrdup9p(os);
373671dfc47SDavid du Colombier 
374671dfc47SDavid du Colombier 	free(p);
375671dfc47SDavid du Colombier 	return 0;
376671dfc47SDavid du Colombier }
377671dfc47SDavid du Colombier 
378671dfc47SDavid du Colombier 
CIFStreeconnect(Session * s,char * cname,char * tree,Share * sp)379671dfc47SDavid du Colombier CIFStreeconnect(Session *s, char *cname, char *tree, Share *sp)
380671dfc47SDavid du Colombier {
381671dfc47SDavid du Colombier 	int len;
382671dfc47SDavid du Colombier 	char *resp, *path;
383671dfc47SDavid du Colombier 	char zeros[24];
384671dfc47SDavid du Colombier 	Pkt *p;
385671dfc47SDavid du Colombier 
386671dfc47SDavid du Colombier 	resp = Sess->auth->resp[0];
387671dfc47SDavid du Colombier 	len  = Sess->auth->len[0];
388671dfc47SDavid du Colombier 	if((s->secmode & SECMODE_USER) != SECMODE_USER){
389671dfc47SDavid du Colombier 		memset(zeros, 0, sizeof(zeros));
390671dfc47SDavid du Colombier 		resp = zeros;
391671dfc47SDavid du Colombier 		len = sizeof(zeros);
392671dfc47SDavid du Colombier 	}
393671dfc47SDavid du Colombier 
394671dfc47SDavid du Colombier 	p = cifshdr(s, nil, SMB_COM_TREE_CONNECT_ANDX);
395671dfc47SDavid du Colombier 	p8(p, 0xFF);			/* Secondary command */
396671dfc47SDavid du Colombier 	p8(p, 0);			/* Reserved */
397671dfc47SDavid du Colombier 	pl16(p, 0);			/* Offset to next Word Count */
398671dfc47SDavid du Colombier 	pl16(p, 0);			/* Flags */
399671dfc47SDavid du Colombier 
400671dfc47SDavid du Colombier 	if((s->secmode & SECMODE_PW_ENCRYPT) == 0){
401671dfc47SDavid du Colombier 		pl16(p, len+1);		/* password len, including null */
402671dfc47SDavid du Colombier 		pbytes(p);
403671dfc47SDavid du Colombier 		pascii(p, resp);
404671dfc47SDavid du Colombier 	}else{
405671dfc47SDavid du Colombier 		pl16(p, len);
406671dfc47SDavid du Colombier 		pbytes(p);
407671dfc47SDavid du Colombier 		pmem(p, resp, len);
408671dfc47SDavid du Colombier 	}
409671dfc47SDavid du Colombier 
410671dfc47SDavid du Colombier 	path = smprint("//%s/%s", cname, tree);
411671dfc47SDavid du Colombier 	strupr(path);
412671dfc47SDavid du Colombier 	ppath(p, path);			/* path */
413671dfc47SDavid du Colombier 	free(path);
414671dfc47SDavid du Colombier 
415671dfc47SDavid du Colombier 	pascii(p, "?????");	/* service type any (so we can do RAP calls) */
416671dfc47SDavid du Colombier 
417671dfc47SDavid du Colombier 	if(cifsrpc(p) == -1){
418671dfc47SDavid du Colombier 		free(p);
419671dfc47SDavid du Colombier 		return -1;
420671dfc47SDavid du Colombier 	}
421671dfc47SDavid du Colombier 	g8(p);				/* Secondary command */
422671dfc47SDavid du Colombier 	g8(p);				/* Reserved */
423671dfc47SDavid du Colombier 	gl16(p);			/* Offset to next command */
424671dfc47SDavid du Colombier 	sp->options = g8(p);		/* options supported */
425671dfc47SDavid du Colombier 	sp->tid = p->tid;		/* get received TID from packet header */
426671dfc47SDavid du Colombier 	free(p);
427671dfc47SDavid du Colombier 	return 0;
428671dfc47SDavid du Colombier }
429671dfc47SDavid du Colombier 
430671dfc47SDavid du Colombier int
CIFSlogoff(Session * s)431671dfc47SDavid du Colombier CIFSlogoff(Session *s)
432671dfc47SDavid du Colombier {
433671dfc47SDavid du Colombier 	int rc;
434671dfc47SDavid du Colombier 	Pkt *p;
435671dfc47SDavid du Colombier 
436671dfc47SDavid du Colombier 	p = cifshdr(s, nil, SMB_COM_LOGOFF_ANDX);
437671dfc47SDavid du Colombier 	p8(p, 0xFF);			/* No ANDX command */
438671dfc47SDavid du Colombier 	p8(p, 0);			/* Reserved (must be zero) */
439671dfc47SDavid du Colombier 	pl16(p, 0);			/* offset ot ANDX */
440671dfc47SDavid du Colombier 	pbytes(p);
441671dfc47SDavid du Colombier 	rc = cifsrpc(p);
442671dfc47SDavid du Colombier 
443671dfc47SDavid du Colombier 	free(p);
444671dfc47SDavid du Colombier 	return rc;
445671dfc47SDavid du Colombier }
446671dfc47SDavid du Colombier 
447671dfc47SDavid du Colombier int
CIFStreedisconnect(Session * s,Share * sp)448671dfc47SDavid du Colombier CIFStreedisconnect(Session *s, Share *sp)
449671dfc47SDavid du Colombier {
450671dfc47SDavid du Colombier 	int rc;
451671dfc47SDavid du Colombier 	Pkt *p;
452671dfc47SDavid du Colombier 
453671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_TREE_DISCONNECT);
454671dfc47SDavid du Colombier 	pbytes(p);
455671dfc47SDavid du Colombier 	rc = cifsrpc(p);
456671dfc47SDavid du Colombier 
457671dfc47SDavid du Colombier 	free(p);
458671dfc47SDavid du Colombier 	return rc;
459671dfc47SDavid du Colombier }
460671dfc47SDavid du Colombier 
461671dfc47SDavid du Colombier 
462671dfc47SDavid du Colombier int
CIFSdeletefile(Session * s,Share * sp,char * name)463671dfc47SDavid du Colombier CIFSdeletefile(Session *s, Share *sp, char *name)
464671dfc47SDavid du Colombier {
465671dfc47SDavid du Colombier 	int rc;
466671dfc47SDavid du Colombier 	Pkt *p;
467671dfc47SDavid du Colombier 
468671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_DELETE);
469671dfc47SDavid du Colombier 	pl16(p, ATTR_HIDDEN|ATTR_SYSTEM);	/* search attributes */
470671dfc47SDavid du Colombier 	pbytes(p);
471671dfc47SDavid du Colombier 	p8(p, STR_ASCII);			/* buffer format */
472671dfc47SDavid du Colombier 	ppath(p, name);
473671dfc47SDavid du Colombier 	rc = cifsrpc(p);
474671dfc47SDavid du Colombier 
475671dfc47SDavid du Colombier 	free(p);
476671dfc47SDavid du Colombier 	return rc;
477671dfc47SDavid du Colombier }
478671dfc47SDavid du Colombier 
479671dfc47SDavid du Colombier int
CIFSdeletedirectory(Session * s,Share * sp,char * name)480671dfc47SDavid du Colombier CIFSdeletedirectory(Session *s, Share *sp, char *name)
481671dfc47SDavid du Colombier {
482671dfc47SDavid du Colombier 	int rc;
483671dfc47SDavid du Colombier 	Pkt *p;
484671dfc47SDavid du Colombier 
485671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_DELETE_DIRECTORY);
486671dfc47SDavid du Colombier 	pbytes(p);
487671dfc47SDavid du Colombier 	p8(p, STR_ASCII);		/* buffer format */
488671dfc47SDavid du Colombier 	ppath(p, name);
489671dfc47SDavid du Colombier 	rc = cifsrpc(p);
490671dfc47SDavid du Colombier 
491671dfc47SDavid du Colombier 	free(p);
492671dfc47SDavid du Colombier 	return rc;
493671dfc47SDavid du Colombier }
494671dfc47SDavid du Colombier 
495671dfc47SDavid du Colombier int
CIFScreatedirectory(Session * s,Share * sp,char * name)496671dfc47SDavid du Colombier CIFScreatedirectory(Session *s, Share *sp, char *name)
497671dfc47SDavid du Colombier {
498671dfc47SDavid du Colombier 	int rc;
499671dfc47SDavid du Colombier 	Pkt *p;
500671dfc47SDavid du Colombier 
501671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_CREATE_DIRECTORY);
502671dfc47SDavid du Colombier 	pbytes(p);
503671dfc47SDavid du Colombier 	p8(p, STR_ASCII);
504671dfc47SDavid du Colombier 	ppath(p, name);
505671dfc47SDavid du Colombier 	rc = cifsrpc(p);
506671dfc47SDavid du Colombier 
507671dfc47SDavid du Colombier 	free(p);
508671dfc47SDavid du Colombier 	return rc;
509671dfc47SDavid du Colombier }
510671dfc47SDavid du Colombier 
511671dfc47SDavid du Colombier int
CIFSrename(Session * s,Share * sp,char * old,char * new)512671dfc47SDavid du Colombier CIFSrename(Session *s, Share *sp, char *old, char *new)
513671dfc47SDavid du Colombier {
514671dfc47SDavid du Colombier 	int rc;
515671dfc47SDavid du Colombier 	Pkt *p;
516671dfc47SDavid du Colombier 
517671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_RENAME);
518671dfc47SDavid du Colombier 	pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* search attributes */
519671dfc47SDavid du Colombier 	pbytes(p);
520671dfc47SDavid du Colombier 	p8(p, STR_ASCII);
521671dfc47SDavid du Colombier 	ppath(p, old);
522671dfc47SDavid du Colombier 	p8(p, STR_ASCII);
523671dfc47SDavid du Colombier 	ppath(p, new);
524671dfc47SDavid du Colombier 	rc = cifsrpc(p);
525671dfc47SDavid du Colombier 
526671dfc47SDavid du Colombier 	free(p);
527671dfc47SDavid du Colombier 	return rc;
528671dfc47SDavid du Colombier }
529671dfc47SDavid du Colombier 
530671dfc47SDavid du Colombier 
531671dfc47SDavid du Colombier /* for NT4/Win2k/XP */
532671dfc47SDavid du Colombier 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)533671dfc47SDavid du Colombier CIFS_NT_opencreate(Session *s, Share *sp, char *name, int flags, int options,
534671dfc47SDavid du Colombier 	int attrs, int access, int share, int action, int *result, FInfo *fi)
535671dfc47SDavid du Colombier {
536671dfc47SDavid du Colombier 	Pkt *p;
537671dfc47SDavid du Colombier 	int fh;
538671dfc47SDavid du Colombier 
539671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_NT_CREATE_ANDX);
540671dfc47SDavid du Colombier 	p8(p, 0xFF);			/* Secondary command */
541671dfc47SDavid du Colombier 	p8(p, 0);			/* Reserved */
542671dfc47SDavid du Colombier 	pl16(p, 0);			/* Offset to next command */
543671dfc47SDavid du Colombier 	p8(p, 0);			/* Reserved */
544671dfc47SDavid du Colombier 	pl16(p, utflen(name) *2);	/* file name len */
545671dfc47SDavid du Colombier 	pl32(p, flags);			/* Flags */
546671dfc47SDavid du Colombier 	pl32(p, 0);			/* fid of cwd, if relative path */
547671dfc47SDavid du Colombier 	pl32(p, access);		/* access desired */
548671dfc47SDavid du Colombier 	pl64(p, 0);			/* initial allocation size */
549671dfc47SDavid du Colombier 	pl32(p, attrs);			/* Extended attributes */
550671dfc47SDavid du Colombier 	pl32(p, share);			/* Share Access */
551671dfc47SDavid du Colombier 	pl32(p, action);		/* What to do on success/failure */
552671dfc47SDavid du Colombier 	pl32(p, options);		/* Options */
553671dfc47SDavid du Colombier 	pl32(p, SECURITY_IMPERSONATION); /* Impersonation level */
554671dfc47SDavid du Colombier 	p8(p, SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY); /* security flags */
555671dfc47SDavid du Colombier 	pbytes(p);
556671dfc47SDavid du Colombier 	p8(p, 0);			/* FIXME: padding? */
557671dfc47SDavid du Colombier 	ppath(p, name);			/* filename */
558671dfc47SDavid du Colombier 
559671dfc47SDavid du Colombier 	if(cifsrpc(p) == -1){
560671dfc47SDavid du Colombier 		free(p);
561671dfc47SDavid du Colombier 		return -1;
562671dfc47SDavid du Colombier 	}
563671dfc47SDavid du Colombier 
564671dfc47SDavid du Colombier 	memset(fi, 0, sizeof(FInfo));
565671dfc47SDavid du Colombier 	g8(p);				/* Secondary command */
566671dfc47SDavid du Colombier 	g8(p);				/* Reserved */
567671dfc47SDavid du Colombier 	gl16(p);			/* Offset to next command */
568671dfc47SDavid du Colombier 	g8(p);				/* oplock granted */
569671dfc47SDavid du Colombier 	fh = gl16(p);			/* FID for opened object */
570671dfc47SDavid du Colombier 	*result = gl32(p);		/* create action taken */
571671dfc47SDavid du Colombier 	gl64(p);			/* creation time */
572671dfc47SDavid du Colombier 	fi->accessed = gvtime(p);	/* last access time */
573671dfc47SDavid du Colombier 	fi->written = gvtime(p);	/* last written time */
574671dfc47SDavid du Colombier 	fi->changed = gvtime(p);	/* change time */
575671dfc47SDavid du Colombier 	fi->attribs = gl32(p);		/* extended attributes */
576671dfc47SDavid du Colombier 	gl64(p);			/* bytes allocated */
577671dfc47SDavid du Colombier 	fi->size = gl64(p);		/* file size */
578671dfc47SDavid du Colombier 
579671dfc47SDavid du Colombier 	free(p);
580671dfc47SDavid du Colombier 	return fh;
581671dfc47SDavid du Colombier }
582671dfc47SDavid du Colombier 
583671dfc47SDavid du Colombier /* for Win95/98/ME */
CIFS_SMB_opencreate(Session * s,Share * sp,char * name,int access,int attrs,int action,int * result)584671dfc47SDavid du Colombier CIFS_SMB_opencreate(Session *s, Share *sp, char *name, int access,
585671dfc47SDavid du Colombier 	int attrs, int action, int *result)
586671dfc47SDavid du Colombier {
587671dfc47SDavid du Colombier 	Pkt *p;
588671dfc47SDavid du Colombier 	int fh;
589671dfc47SDavid du Colombier 
590671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_OPEN_ANDX);
591671dfc47SDavid du Colombier 	p8(p, 0xFF);			/* Secondary command */
592671dfc47SDavid du Colombier 	p8(p, 0);			/* Reserved */
593671dfc47SDavid du Colombier 	pl16(p, 0);			/* Offset to next command */
594671dfc47SDavid du Colombier 	pl16(p, 0);			/* Flags (0 == no stat(2) info) */
595671dfc47SDavid du Colombier 	pl16(p, access);		/* desired access */
596671dfc47SDavid du Colombier 	pl16(p, ATTR_HIDDEN|ATTR_SYSTEM);/* search attributes */
597671dfc47SDavid du Colombier 	pl16(p, attrs);			/* file attribytes */
598671dfc47SDavid du Colombier 	pdatetime(p, 0);		/* creation time (0 == now) */
599671dfc47SDavid du Colombier 	pl16(p, action);		/* What to do on success/failure */
600671dfc47SDavid du Colombier 	pl32(p, 0);			/* allocation size */
601671dfc47SDavid du Colombier 	pl32(p, 0);			/* reserved */
602671dfc47SDavid du Colombier 	pl32(p, 0);			/* reserved */
603671dfc47SDavid du Colombier 	pbytes(p);
604671dfc47SDavid du Colombier 	ppath(p, name);			/* filename */
605671dfc47SDavid du Colombier 
606671dfc47SDavid du Colombier 	if(cifsrpc(p) == -1){
607671dfc47SDavid du Colombier 		free(p);
608671dfc47SDavid du Colombier 		return -1;
609671dfc47SDavid du Colombier 	}
610671dfc47SDavid du Colombier 
611671dfc47SDavid du Colombier 	g8(p);				/* Secondary command */
612671dfc47SDavid du Colombier 	g8(p);				/* Reserved */
613671dfc47SDavid du Colombier 	gl16(p);			/* Offset to next command */
614671dfc47SDavid du Colombier 	fh = gl16(p);			/* FID for opened object */
615671dfc47SDavid du Colombier 	gl16(p);			/* extended attributes */
616671dfc47SDavid du Colombier 	gvtime(p);			/* last written time */
617671dfc47SDavid du Colombier 	gl32(p);			/* file size */
618671dfc47SDavid du Colombier 	gl16(p);			/* file type (disk/fifo/printer etc) */
619671dfc47SDavid du Colombier 	gl16(p);			/* device status (for fifos) */
620671dfc47SDavid du Colombier 	*result = gl16(p);		/* access granted */
621671dfc47SDavid du Colombier 
622671dfc47SDavid du Colombier 	free(p);
623671dfc47SDavid du Colombier 	return fh;
624671dfc47SDavid du Colombier }
625671dfc47SDavid du Colombier 
626671dfc47SDavid du Colombier vlong
CIFSwrite(Session * s,Share * sp,int fh,uvlong off,void * buf,vlong n)627671dfc47SDavid du Colombier CIFSwrite(Session *s, Share *sp, int fh, uvlong off, void *buf, vlong n)
628671dfc47SDavid du Colombier {
629671dfc47SDavid du Colombier 	Pkt *p;
630671dfc47SDavid du Colombier 	vlong got;
631671dfc47SDavid du Colombier 
632671dfc47SDavid du Colombier 	/* FIXME: Payload should be padded to long boundary */
633671dfc47SDavid du Colombier 	assert((n   & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
634671dfc47SDavid du Colombier 	assert((off & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
635671dfc47SDavid du Colombier 	assert(n < s->mtu - T2HDRLEN || s->caps & CAP_LARGE_WRITEX);
636671dfc47SDavid du Colombier 
637671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_WRITE_ANDX);
638671dfc47SDavid du Colombier 	p8(p, 0xFF);			/* Secondary command */
639671dfc47SDavid du Colombier 	p8(p, 0);			/* Reserved */
640671dfc47SDavid du Colombier 	pl16(p, 0);			/* Offset to next command */
641671dfc47SDavid du Colombier 	pl16(p, fh);			/* File handle */
642671dfc47SDavid du Colombier 	pl32(p, off & 0xffffffff);	/* LSBs of Offset */
643671dfc47SDavid du Colombier 	pl32(p, 0);			/* Reserved (0) */
644671dfc47SDavid du Colombier 	pl16(p, s->nocache);		/* Write mode (0 - write through) */
645671dfc47SDavid du Colombier 	pl16(p, 0);			/* Bytes remaining */
646671dfc47SDavid du Colombier 	pl16(p, n >> 16);		/* MSBs of length */
647671dfc47SDavid du Colombier 	pl16(p, n & 0xffffffff);	/* LSBs of length */
648671dfc47SDavid du Colombier 	pl16(p, T2HDRLEN);		/* Offset to data, in bytes */
649671dfc47SDavid du Colombier 	pl32(p, off >> 32);		/* MSBs of offset */
650671dfc47SDavid du Colombier 	pbytes(p);
651671dfc47SDavid du Colombier 
652671dfc47SDavid du Colombier 	p->pos = p->buf +T2HDRLEN +NBHDRLEN;
653671dfc47SDavid du Colombier 	pmem(p, buf, n);		/* Data */
654671dfc47SDavid du Colombier 
655671dfc47SDavid du Colombier 	if(cifsrpc(p) == -1){
656671dfc47SDavid du Colombier 		free(p);
657671dfc47SDavid du Colombier 		return -1;
658671dfc47SDavid du Colombier 	}
659671dfc47SDavid du Colombier 
660671dfc47SDavid du Colombier 	g8(p);				/* Secondary command */
661671dfc47SDavid du Colombier 	g8(p);				/* Reserved */
662671dfc47SDavid du Colombier 	gl16(p);			/* Offset to next command */
663671dfc47SDavid du Colombier 	got = gl16(p);			/* LSWs of bytes written */
664671dfc47SDavid du Colombier 	gl16(p);			/* remaining (space ?) */
665671dfc47SDavid du Colombier 	got |= (gl16(p) << 16);		/* MSWs of bytes written */
666671dfc47SDavid du Colombier 
667671dfc47SDavid du Colombier 	free(p);
668671dfc47SDavid du Colombier 	return got;
669671dfc47SDavid du Colombier }
670671dfc47SDavid du Colombier 
671671dfc47SDavid du Colombier vlong
CIFSread(Session * s,Share * sp,int fh,uvlong off,void * buf,vlong n,vlong minlen)672671dfc47SDavid du Colombier CIFSread(Session *s, Share *sp, int fh, uvlong off, void *buf, vlong n,
673671dfc47SDavid du Colombier 	vlong minlen)
674671dfc47SDavid du Colombier {
675671dfc47SDavid du Colombier 	int doff;
676671dfc47SDavid du Colombier 	vlong got;
677671dfc47SDavid du Colombier 	Pkt *p;
678671dfc47SDavid du Colombier 
679671dfc47SDavid du Colombier 	assert((n   & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
680671dfc47SDavid du Colombier 	assert((off & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
681671dfc47SDavid du Colombier 	assert(n < s->mtu - T2HDRLEN || s->caps & CAP_LARGE_READX);
682671dfc47SDavid du Colombier 
683671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_READ_ANDX);
684671dfc47SDavid du Colombier 	p8(p, 0xFF);			/* Secondary command */
685671dfc47SDavid du Colombier 	p8(p, 0);			/* Reserved */
686671dfc47SDavid du Colombier 	pl16(p, 0);			/* Offset to next command */
687671dfc47SDavid du Colombier 	pl16(p, fh);			/* File handle */
688671dfc47SDavid du Colombier 	pl32(p, off & 0xffffffff);	/* Offset to beginning of write */
689671dfc47SDavid du Colombier 	pl16(p, n);			/* Maximum number of bytes to return */
690671dfc47SDavid du Colombier 	pl16(p, minlen);		/* Minimum number of bytes to return */
691671dfc47SDavid du Colombier 	pl32(p, (uint)n >> 16);		/* MSBs of maxlen */
692671dfc47SDavid du Colombier 	pl16(p, 0);			/* Bytes remaining to satisfy request */
693671dfc47SDavid du Colombier 	pl32(p, off >> 32);		/* MS 32 bits of offset */
694671dfc47SDavid du Colombier 	pbytes(p);
695671dfc47SDavid du Colombier 
696671dfc47SDavid du Colombier 	if(cifsrpc(p) == -1){
697671dfc47SDavid du Colombier 		free(p);
698671dfc47SDavid du Colombier 		return -1;
699671dfc47SDavid du Colombier 	}
700671dfc47SDavid du Colombier 
701671dfc47SDavid du Colombier 	g8(p);				/* Secondary command */
702671dfc47SDavid du Colombier 	g8(p);				/* Reserved */
703671dfc47SDavid du Colombier 	gl16(p);			/* Offset to next command */
704671dfc47SDavid du Colombier 	gl16(p);			/* Remaining */
705671dfc47SDavid du Colombier 	gl16(p);			/* Compression mode */
706671dfc47SDavid du Colombier 	gl16(p);			/* Reserved */
707671dfc47SDavid du Colombier 	got = gl16(p);			/* length */
708671dfc47SDavid du Colombier 	doff = gl16(p);			/* Offset from header to data */
709671dfc47SDavid du Colombier 	got |= gl16(p) << 16;
710671dfc47SDavid du Colombier 
711671dfc47SDavid du Colombier 	p->pos = p->buf + doff + NBHDRLEN;
712671dfc47SDavid du Colombier 
713671dfc47SDavid du Colombier 	gmem(p, buf, got);		 /* data */
714671dfc47SDavid du Colombier 	free(p);
715671dfc47SDavid du Colombier 	return got;
716671dfc47SDavid du Colombier }
717671dfc47SDavid du Colombier 
718671dfc47SDavid du Colombier int
CIFSflush(Session * s,Share * sp,int fh)719671dfc47SDavid du Colombier CIFSflush(Session *s, Share *sp, int fh)
720671dfc47SDavid du Colombier {
721671dfc47SDavid du Colombier 	int rc;
722671dfc47SDavid du Colombier 	Pkt *p;
723671dfc47SDavid du Colombier 
724671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_FLUSH);
725671dfc47SDavid du Colombier 	pl16(p, fh);			/* fid */
726671dfc47SDavid du Colombier 	pbytes(p);
727671dfc47SDavid du Colombier 	rc = cifsrpc(p);
728671dfc47SDavid du Colombier 
729671dfc47SDavid du Colombier 	free(p);
730671dfc47SDavid du Colombier 	return rc;
731671dfc47SDavid du Colombier }
732671dfc47SDavid du Colombier 
733671dfc47SDavid du Colombier /*
734671dfc47SDavid du Colombier  * Setting the time of last write to -1 gives "now" if the file
735671dfc47SDavid du Colombier  * was written and leaves it the same if the file wasn't written.
736671dfc47SDavid du Colombier  */
737671dfc47SDavid du Colombier int
CIFSclose(Session * s,Share * sp,int fh)738671dfc47SDavid du Colombier CIFSclose(Session *s, Share *sp, int fh)
739671dfc47SDavid du Colombier {
740671dfc47SDavid du Colombier 	int rc;
741671dfc47SDavid du Colombier 	Pkt *p;
742671dfc47SDavid du Colombier 
743671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_CLOSE);
744671dfc47SDavid du Colombier 	pl16(p, fh);			/* fid */
745671dfc47SDavid du Colombier 	pl32(p, ~0L);			/* Time of last write (none) */
746671dfc47SDavid du Colombier 	pbytes(p);
747671dfc47SDavid du Colombier 	rc = cifsrpc(p);
748671dfc47SDavid du Colombier 
749671dfc47SDavid du Colombier 	free(p);
750671dfc47SDavid du Colombier 	return rc;
751671dfc47SDavid du Colombier }
752671dfc47SDavid du Colombier 
753671dfc47SDavid du Colombier 
754671dfc47SDavid du Colombier int
CIFSfindclose2(Session * s,Share * sp,int sh)755671dfc47SDavid du Colombier CIFSfindclose2(Session *s, Share *sp, int sh)
756671dfc47SDavid du Colombier {
757671dfc47SDavid du Colombier 	int rc;
758671dfc47SDavid du Colombier 	Pkt *p;
759671dfc47SDavid du Colombier 
760671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_FIND_CLOSE2);
761671dfc47SDavid du Colombier 	pl16(p, sh);			/* sid */
762671dfc47SDavid du Colombier 	pbytes(p);
763671dfc47SDavid du Colombier 	rc = cifsrpc(p);
764671dfc47SDavid du Colombier 
765671dfc47SDavid du Colombier 	free(p);
766671dfc47SDavid du Colombier 	return rc;
767671dfc47SDavid du Colombier }
768671dfc47SDavid du Colombier 
769671dfc47SDavid du Colombier 
770671dfc47SDavid du Colombier int
CIFSecho(Session * s)771671dfc47SDavid du Colombier CIFSecho(Session *s)
772671dfc47SDavid du Colombier {
773671dfc47SDavid du Colombier 	Pkt *p;
774671dfc47SDavid du Colombier 	int rc;
775671dfc47SDavid du Colombier 
776671dfc47SDavid du Colombier 	p = cifshdr(s, nil, SMB_COM_ECHO);
777671dfc47SDavid du Colombier 	pl16(p, 1);				/* number of replies */
778671dfc47SDavid du Colombier 	pbytes(p);
779671dfc47SDavid du Colombier 	pascii(p, "abcdefghijklmnopqrstuvwxyz"); /* data */
780671dfc47SDavid du Colombier 
781671dfc47SDavid du Colombier 	rc = cifsrpc(p);
782671dfc47SDavid du Colombier 	free(p);
783671dfc47SDavid du Colombier 	return rc;
784671dfc47SDavid du Colombier }
785671dfc47SDavid du Colombier 
786671dfc47SDavid du Colombier 
787671dfc47SDavid du Colombier int
CIFSsetinfo(Session * s,Share * sp,char * path,FInfo * fip)788671dfc47SDavid du Colombier CIFSsetinfo(Session *s, Share *sp, char *path, FInfo *fip)
789671dfc47SDavid du Colombier {
790671dfc47SDavid du Colombier 	int rc;
791671dfc47SDavid du Colombier 	Pkt *p;
792671dfc47SDavid du Colombier 
793671dfc47SDavid du Colombier 	p = cifshdr(s, sp, SMB_COM_SET_INFORMATION);
794671dfc47SDavid du Colombier 	pl16(p, fip->attribs);
795671dfc47SDavid du Colombier 	pl32(p, time(nil) - s->tz);	/* modified time */
796671dfc47SDavid du Colombier 	pl64(p, 0);			/* reserved */
797671dfc47SDavid du Colombier 	pl16(p, 0);			/* reserved */
798671dfc47SDavid du Colombier 
799671dfc47SDavid du Colombier 	pbytes(p);
800671dfc47SDavid du Colombier 	p8(p, STR_ASCII);		/* buffer format */
801671dfc47SDavid du Colombier 	ppath(p, path);
802671dfc47SDavid du Colombier 
803671dfc47SDavid du Colombier 	rc = cifsrpc(p);
804671dfc47SDavid du Colombier 	free(p);
805671dfc47SDavid du Colombier 	return rc;
806671dfc47SDavid du Colombier }
807