xref: /plan9/sys/src/cmd/cifs/trans2.c (revision 912e5f5442636b48aaa52937edbb904e279d1987)
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 Pkt *
t2hdr(Session * s,Share * sp,int cmd)9 t2hdr(Session *s, Share *sp, int cmd)
10 {
11 	Pkt *p;
12 
13 	p = cifshdr(s, sp, SMB_COM_TRANSACTION2);
14 
15 	p->tbase = pl16(p, 0);	/* 0  Total parameter bytes to be sent, filled later */
16 	pl16(p, 0);		/* 2  Total data bytes to be sent, filled later */
17 	pl16(p, 64);			/* 4  Max parameter to return */
18 	pl16(p, (MTU - T2HDRLEN)-64);	/* 6  Max data to return */
19 	p8(p, 0);			/* 8  Max setup count to return */
20 	p8(p, 0);			/* 9  Reserved */
21 	pl16(p, 0);			/* 10 Flags */
22 	pl32(p, 1000);			/* 12 Timeout (ms) */
23 	pl16(p, 0);			/* 16 Reserved */
24 	pl16(p, 0);			/* 18 Parameter count, filled later */
25 	pl16(p, 0);			/* 20 Parameter offset, filled later */
26 	pl16(p, 0);			/* 22 Data count, filled later */
27 	pl16(p, 0);			/* 24 Data offset, filled later */
28 	p8(p, 1);			/* 26 Setup count (in words) */
29 	p8(p, 0);			/* 27 Reserved */
30 	pl16(p, cmd);			/* setup[0] */
31 	pbytes(p);
32 	p8(p, 0);			/* padding ??!?!? */
33 
34 	return p;
35 }
36 
37 static void
pt2param(Pkt * p)38 pt2param(Pkt *p)
39 {
40 	uchar *pos = p->pos;
41 
42 	assert(p->tbase != 0);
43 	p->pos = p->tbase + 20;
44 	pl16(p, (pos - p->buf) - NBHDRLEN); /* param offset */
45 
46 	p->tparam = p->pos = pos;
47 }
48 
49 static void
pt2data(Pkt * p)50 pt2data(Pkt *p)
51 {
52 	uchar *pos = p->pos;
53 
54 	assert(p->tbase != 0);
55 	assert(p->tparam != 0);
56 
57 	p->pos = p->tbase +0;
58 	pl16(p, pos - p->tparam);		/* total param count */
59 
60 	p->pos = p->tbase +18;
61 	pl16(p, pos - p->tparam);		/* param count */
62 
63 	p->pos = p->tbase +24;
64 	pl16(p, (pos - p->buf) - NBHDRLEN);	/* data offset */
65 
66 	p->tdata = p->pos = pos;
67 }
68 
69 static int
t2rpc(Pkt * p)70 t2rpc(Pkt *p)
71 {
72 	int got;
73 	uchar *pos;
74 
75 	assert(p->tbase != 0);
76 	assert(p->tdata != 0);
77 
78 	pos = p->pos;
79 
80 	p->pos = p->tbase +2;
81 	pl16(p, pos - p->tdata);		/* total data count */
82 
83 	p->pos = p->tbase +22;
84 	pl16(p, pos - p->tdata);		/* data count */
85 
86 	p->pos = pos;
87 	if((got = cifsrpc(p)) == -1)
88 		return -1;
89 
90 	gl16(p);			/* Total parameter count */
91 	gl16(p);			/* Total data count */
92 	gl16(p);			/* Reserved */
93 	gl16(p);			/* Parameter count in this buffer */
94 	p->tparam = p->buf +NBHDRLEN +gl16(p); /* Parameter offset */
95 	gl16(p);			/* Parameter displacement */
96 	gl16(p);			/* Data count (this buffer); */
97 	p->tdata = p->buf +NBHDRLEN +gl16(p); /* Data offset */
98 	gl16(p);			/* Data displacement */
99 	g8(p);				/* Setup count */
100 	g8(p);				/* Reserved */
101 
102 	return got;
103 }
104 
105 static void
gt2param(Pkt * p)106 gt2param(Pkt *p)
107 {
108 	p->pos = p->tparam;
109 }
110 
111 static void
gt2data(Pkt * p)112 gt2data(Pkt *p)
113 {
114 	p->pos = p->tdata;
115 }
116 
117 
118 int
T2findfirst(Session * s,Share * sp,int slots,char * path,int * got,long * resume,FInfo * fip)119 T2findfirst(Session *s, Share *sp, int slots, char *path, int *got,
120 	long *resume, FInfo *fip)
121 {
122 	int pktlen, i, n, sh;
123 	uchar *next;
124 	Pkt *p;
125 
126 	p = t2hdr(s, sp, TRANS2_FIND_FIRST2);
127 	p8(p, 'D');			/* OS/2 */
128 	p8(p, ' ');			/* OS/2 */
129 
130 	pt2param(p);
131 	pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* Search attributes */
132 	pl16(p, slots);			/* Search count */
133 	pl16(p, CIFS_SEARCH_RETURN_RESUME); /* Flags */
134 	pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
135 	pl32(p, 0);			/* SearchStorage type (?) */
136 	ppath(p, path);			/* path */
137 
138 	pt2data(p);
139 	if((pktlen = t2rpc(p)) == -1){
140 		free(p);
141 		return -1;
142 	}
143 
144 	s->lastfind = nsec();
145 	gt2param(p);
146 
147 	sh = gl16(p);			/* Sid (search handle) */
148 	*got = gl16(p);			/* number of slots received */
149 	gl16(p);			/* End of search flag */
150 	gl16(p);			/* Offset into EA list if EA error */
151 	gl16(p);			/* Offset into data to file name of last entry */
152 
153 	gt2data(p);
154 	memset(fip, 0, slots * sizeof(FInfo));
155 	for(i = 0; i < *got; i++){
156 		next = p->pos;
157 		next += gl32(p);	/* offset to next entry */
158 		/*
159 		 * bug in Windows - somtimes it lies about how many
160 		 * directory entries it has put in the packet
161 		 */
162 		if(next - p->buf > pktlen){
163 			*got = i;
164 			break;
165 		}
166 
167 		*resume = gl32(p);		/* resume key for search */
168 		fip[i].created = gvtime(p);	/* creation time */
169 		fip[i].accessed = gvtime(p);	/* last access time */
170 		fip[i].written = gvtime(p);	/* last written time */
171 		fip[i].changed = gvtime(p);	/* change time */
172 		fip[i].size = gl64(p);		/* file size */
173 		gl64(p);			/* bytes allocated */
174 		fip[i].attribs = gl32(p);	/* extended attributes */
175 		n = gl32(p);			/* name length */
176 		gl32(p);			/* EA size */
177 		gstr(p, fip[i].name, n); 	/* name */
178 		p->pos = next;
179 	}
180 
181 	free(p);
182 	return sh;
183 
184 }
185 
186 int
T2findnext(Session * s,Share * sp,int slots,char * path,int * got,long * resume,FInfo * fip,int sh)187 T2findnext(Session *s, Share *sp, int slots, char *path, int *got,
188 	long *resume, FInfo *fip, int sh)
189 {
190 	Pkt *p;
191 	int i, n;
192 	uchar *next;
193 
194 	/*
195 	 * So I believe from comp.protocols.smb if you send
196 	 * TRANS2_FIND_NEXT2 requests too quickly to windows 95, it can
197 	 * get confused and fail to reply, so we slow up a bit in these
198 	 * circumstances.
199 	 */
200 	if(!(s->caps & CAP_NT_SMBS) && nsec() - s->lastfind < 200000000LL)
201 		sleep(200);
202 
203 	p = t2hdr(s, sp, TRANS2_FIND_NEXT2);
204 	p8(p, 'D');			/* OS/2 */
205 	p8(p, ' ');			/* OS/2 */
206 
207 	pt2param(p);
208 	pl16(p, sh);				/* search handle */
209 	pl16(p, slots);				/* Search count */
210 	pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
211 	pl32(p, *resume);			/* resume key */
212 	pl16(p, CIFS_SEARCH_CONTINUE_FROM_LAST); /* Flags */
213 	ppath(p, path);				/* file+path to resume */
214 
215 	pt2data(p);
216 	if(t2rpc(p) == -1){
217 		free(p);
218 		return -1;
219 	}
220 
221 	s->lastfind = nsec();
222 
223 	gt2param(p);
224 	*got = gl16(p);		/* number of slots received */
225 	gl16(p);		/* End of search flag */
226 	gl16(p);		/* Offset into EA list if EA error */
227 	gl16(p);		/* Offset into data to file name of last entry */
228 
229 	gt2data(p);
230 	memset(fip, 0, slots * sizeof(FInfo));
231 	for(i = 0; i < *got; i++){
232 		next = p->pos;
233 		next += gl32(p);		/* offset to next entry */
234 		*resume = gl32(p);		/* resume key for search */
235 		fip[i].created = gvtime(p);	/* creation time */
236 		fip[i].accessed = gvtime(p);	/* last access time */
237 		fip[i].written = gvtime(p);	/* last written time */
238 		fip[i].changed = gvtime(p);	/* change time */
239 		fip[i].size = gl64(p);		/* file size */
240 		gl64(p);			/* bytes allocated */
241 		fip[i].attribs = gl32(p);	/* extended attributes */
242 		n = gl32(p);			/* name length */
243 		gl32(p);			/* EA size */
244 		gstr(p, fip[i].name, n); 	/* name */
245 		p->pos = next;
246 	}
247 	free(p);
248 	return 0;
249 }
250 
251 
252 /* supported by 2k/XP/NT4 */
253 int
T2queryall(Session * s,Share * sp,char * path,FInfo * fip)254 T2queryall(Session *s, Share *sp, char *path, FInfo *fip)
255 {
256 	int n;
257 	Pkt *p;
258 
259 	p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
260 	pt2param(p);
261 	pl16(p, SMB_QUERY_FILE_ALL_INFO); /* Information level	 */
262 	pl32(p, 0);			/* reserved */
263 	ppath(p, path);			/* path */
264 
265 	pt2data(p);
266 	if(t2rpc(p) == -1){
267 		free(p);
268 		return -1;
269 	}
270 	gt2data(p);
271 
272 	/*
273 	 * The layout of this struct is wrong in the SINA
274 	 * document, this layout gained by inspection.
275 	 */
276 	memset(fip, 0, sizeof(FInfo));
277 	fip->created = gvtime(p);	/* creation time */
278 	fip->accessed = gvtime(p);	/* last access time */
279 	fip->written = gvtime(p);	/* last written time */
280 	fip->changed = gvtime(p);	/* change time */
281 	fip->attribs = gl32(p);		/* attributes */
282 	gl32(p);			/* reserved */
283 	gl64(p);			/* bytes allocated */
284 	fip->size = gl64(p);		/* file size */
285 	gl32(p);			/* number of hard links */
286 	g8(p);				/* delete pending */
287 	g8(p);				/* is a directory */
288 	gl16(p);			/* reserved */
289 	gl32(p);			/* EA size */
290 
291 	n = gl32(p);
292 	if(n >= sizeof fip->name)
293 		n = sizeof fip->name - 1;
294 	gstr(p, fip->name, n);
295 
296 	free(p);
297 	return 0;
298 }
299 
300 /* supported by 95/98/ME */
301 int
T2querystandard(Session * s,Share * sp,char * path,FInfo * fip)302 T2querystandard(Session *s, Share *sp, char *path, FInfo *fip)
303 {
304 	Pkt *p;
305 
306 	p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
307 	pt2param(p);
308 	pl16(p, SMB_INFO_STANDARD);	/* Information level */
309 	pl32(p, 0);			/* reserved */
310 	ppath(p, path);			/* path */
311 
312 	pt2data(p);
313 	if(t2rpc(p) == -1){
314 		free(p);
315 		return -1;
316 	}
317 	gt2data(p);
318 	memset(fip, 0, sizeof(FInfo));
319 	fip->created = gdatetime(p);	/* creation time */
320 	fip->accessed = gdatetime(p);	/* last access time */
321 	fip->written = gdatetime(p);	/* last written time */
322 	fip->changed = fip->written;	/* change time */
323 	fip->size = gl32(p);		/* file size */
324 	gl32(p);			/* bytes allocated */
325 	fip->attribs = gl16(p);		/* attributes */
326 	gl32(p);			/* EA size */
327 
328 	free(p);
329 	return 0;
330 }
331 
332 int
T2setpathinfo(Session * s,Share * sp,char * path,FInfo * fip)333 T2setpathinfo(Session *s, Share *sp, char *path, FInfo *fip)
334 {
335 	int rc;
336 	Pkt *p;
337 
338 	p = t2hdr(s, sp, TRANS2_SET_PATH_INFORMATION);
339 	pt2param(p);
340 	pl16(p, SMB_INFO_STANDARD);	/* Information level */
341 	pl32(p, 0);			/* reserved */
342 	ppath(p, path);			/* path */
343 
344 	pt2data(p);
345 	pdatetime(p, fip->created);	/* created */
346 	pdatetime(p, fip->accessed);	/* accessed */
347 	pdatetime(p, fip->written);	/* written */
348 	pl32(p, fip->size);		/* size */
349 	pl32(p, 0);			/* allocated */
350 	pl16(p, fip->attribs);		/* attributes */
351 	pl32(p, 0);			/* EA size */
352 	pl16(p, 0);			/* reserved */
353 
354 	rc = t2rpc(p);
355 	free(p);
356 	return rc;
357 
358 }
359 
360 int
T2setfilelength(Session * s,Share * sp,int fh,FInfo * fip)361 T2setfilelength(Session *s, Share *sp, int fh, FInfo *fip) /* FIXME: maybe broken, needs testing */
362 {
363 	int rc;
364 	Pkt *p;
365 
366 	p = t2hdr(s, sp, TRANS2_SET_FILE_INFORMATION);
367 	pt2param(p);
368 	pl16(p, fh);			/* file handle */
369 	pl16(p, SMB_SET_FILE_END_OF_FILE_INFO); /* Information level */
370 	pl16(p, 0);			/* reserved */
371 
372 	pt2data(p);
373 	pl64(p, fip->size);
374 	pl32(p, 0);			/* padding ?! */
375 	pl16(p, 0);
376 
377 	rc = t2rpc(p);
378 	free(p);
379 	return rc;
380 }
381 
382 
383 int
T2fsvolumeinfo(Session * s,Share * sp,long * created,long * serialno,char * label,int labellen)384 T2fsvolumeinfo(Session *s, Share *sp, long *created, long *serialno,
385 	char *label, int labellen)
386 {
387 	Pkt *p;
388 	long ct, sn, n;
389 
390 	p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
391 	pt2param(p);
392 	pl16(p, SMB_QUERY_FS_VOLUME_INFO);	/* Information level */
393 
394 	pt2data(p);
395 
396 	if(t2rpc(p) == -1){
397 		free(p);
398 		return -1;
399 	}
400 
401 	gt2data(p);
402 	ct = gvtime(p);			/* creation time */
403 	sn = gl32(p);			/* serial number */
404 	n = gl32(p);			/* label name length */
405 	g8(p);				/* reserved */
406 	g8(p);				/* reserved */
407 
408 	memset(label, 0, labellen);
409 	if(n < labellen && n > 0)
410 		gstr(p, label, n);	/* file system label */
411 	if(created)
412 		*created = ct;
413 	if(serialno)
414 		*serialno = sn;
415 
416 	free(p);
417 	return 0;
418 }
419 
420 int
T2fssizeinfo(Session * s,Share * sp,uvlong * total,uvlong * unused)421 T2fssizeinfo(Session *s, Share *sp, uvlong *total, uvlong *unused)
422 {
423 	Pkt *p;
424 	uvlong t, f, n, b;
425 
426 	p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
427 	pt2param(p);
428 	pl16(p, SMB_QUERY_FS_SIZE_INFO);	/* Information level */
429 
430 	pt2data(p);
431 
432 	if(t2rpc(p) == -1){
433 		free(p);
434 		return -1;
435 	}
436 
437 	gt2data(p);
438 	t = gl64(p);		/* total blocks */
439 	f = gl64(p);		/* free blocks */
440 	n = gl32(p);		/* sectors per block */
441 	b = gl32(p);		/* bytes per sector */
442 
443 	if(free)
444 		*unused = f * n * b;
445 	if(total)
446 		*total = t * n * b;
447 
448 	free(p);
449 	return 0;
450 }
451 
452 int
T2getdfsreferral(Session * s,Share * sp,char * path,int * gflags,int * used,Refer * re,int nent)453 T2getdfsreferral(Session *s, Share *sp, char *path, int *gflags, int *used,
454 	Refer *re, int nent)
455 {
456 	int i, vers, nret, len;
457 	char tmp[1024];
458 	uchar *base;
459 	Pkt *p;
460 
461 	p = t2hdr(s, sp, TRANS2_GET_DFS_REFERRAL);
462 	pt2param(p);
463 	pl16(p, 3); /* max info level we understand, must be >= 3 for domain requests */
464 	ppath(p, path);
465 
466 	pt2data(p);
467 
468 	if(t2rpc(p) == -1){
469 		free(p);
470 		return -1;
471 	}
472 
473 	memset(re, 0, sizeof *re * nent);
474 	gt2data(p);
475 
476 	*used = gl16(p) / 2;	/* length used (/2 as Windows counts in runes) */
477 	nret = gl16(p);		/* number of referrals returned */
478 	*gflags = gl32(p);	/* global flags */
479 
480 	for(i = 0; i < nret && i < nent && i < 16; i++){
481 		base = p->pos;
482 		vers = gl16(p);		/* version of records */
483 		len = gl16(p);		/* length of records */
484 		re[i].type = gl16(p);	/* server type */
485 		re[i].flags = gl16(p);	/* referal flags */
486 		switch(vers){
487 		case 1:
488 			re[i].prox = 0;	/* nearby */
489 			re[i].ttl = 5*60;	/* 5 mins */
490 			gstr(p, tmp, sizeof tmp);
491 			re[i].addr = estrdup9p(tmp);
492 			re[i].path = estrdup9p(tmp);
493 			break;
494 		case 2:
495 			re[i].prox = gl32(p);	/* not implemented in v2 */
496 			re[i].ttl = gl32(p);
497 			goff(p, base, re[i].path, sizeof tmp);
498 			re[i].path = estrdup9p(tmp);
499 			goff(p, base, re[i].path, sizeof tmp);/* spurious 8.3 path */
500 			goff(p, base, tmp, sizeof tmp);
501 			re[i].addr = estrdup9p(tmp);
502 			break;
503 		case 3:
504 			if(re[i].flags & DFS_REFERAL_LIST){
505 				re[i].prox = 0;
506 				re[i].ttl = gl32(p);
507 				goff(p, base, tmp, sizeof tmp);
508 				re[i].path = estrdup9p(tmp);
509 				gl16(p);
510 				goff(p, base, tmp, sizeof tmp);
511 				re[i].addr = estrdup9p(tmp);
512 			}
513 			else{
514 				re[i].prox = 0;
515 				re[i].ttl = gl32(p);
516 				goff(p, base, tmp, sizeof tmp);
517 				re[i].path = estrdup9p(tmp);
518 				gl16(p);	/* spurious 8.3 path */
519 				goff(p, base, tmp, sizeof tmp);
520 				re[i].addr = estrdup9p(tmp);
521 				gl16(p);	/* GUID (historic) */
522 			}
523 			break;
524 		default:
525 			/*
526 			 * this should never happen as we specify our maximum
527 			 * understood level in the request (above)
528 			 */
529 			fprint(2, "%d - unsupported DFS infolevel\n", vers);
530 			re[i].path = estrdup9p(tmp);
531 			re[i].addr = estrdup9p(tmp);
532 			break;
533 		}
534 		p->pos = base+len;
535 	}
536 
537 	free(p);
538 	return i;
539 }
540