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