xref: /plan9/sys/src/cmd/cifs/trans.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 #include "remsmb.h"
8 #include "apinums.h"
9 
10 static Pkt *
thdr(Session * s,Share * sp)11 thdr(Session *s, Share *sp)
12 {
13 	Pkt *p;
14 
15 	p = cifshdr(s, sp, SMB_COM_TRANSACTION);
16 	p->tbase = pl16(p, 0);	/* 0  Total parameter bytes to be sent, filled later */
17 	pl16(p, 0);		/* 2  Total data bytes to be sent, filled later */
18 	pl16(p, 64);			/* 4  Max parameter to return */
19 	pl16(p, MTU - T2HDRLEN - 128);	/* 6  Max data to return */
20 	pl16(p, 1);			/* 8  Max setup count to return */
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 	pl16(p, 0);			/* 26 Setup count (in words) */
29 	pbytes(p);			/* end of cifs words section */
30 	return p;
31 }
32 
33 static void
ptparam(Pkt * p)34 ptparam(Pkt *p)
35 {
36 	uchar *pos;
37 
38 	if(((p->pos - p->tbase) % 2) != 0)
39 		p8(p, 0);			/* pad to word boundry */
40 	pos = p->pos;
41 	p->pos = p->tbase + 20;
42 	pl16(p, pos - p->buf - NBHDRLEN);	/* param offset */
43 	p->tparam = p->pos = pos;
44 }
45 
46 static void
ptdata(Pkt * p)47 ptdata(Pkt *p)
48 {
49 	uchar *pos = p->pos;
50 
51 	assert(p->tparam != 0);
52 	if(((p->pos - p->tbase) % 2) != 0)
53 		p8(p, 0);		/* pad to word boundry */
54 
55 	p->pos = p->tbase + 0;
56 	pl16(p, pos - p->tparam);	/* total param count */
57 
58 	p->pos = p->tbase + 18;
59 	pl16(p, pos - p->tparam);	/* param count */
60 
61 	p->pos = p->tbase + 24;
62 	pl16(p, pos - p->buf - NBHDRLEN); /* data offset */
63 
64 	p->tdata = p->pos = pos;
65 }
66 
67 static int
trpc(Pkt * p)68 trpc(Pkt *p)
69 {
70 	int got;
71 	uchar *pos = p->pos;
72 
73 	assert(p->tbase != 0);
74 	assert(p->tdata != 0);
75 
76 	p->pos = p->tbase + 2;
77 	pl16(p, pos - p->tdata);	/* total data count */
78 
79 	p->pos = p->tbase + 22;
80 	pl16(p, pos - p->tdata);	/* data count */
81 
82 	p->pos = pos;
83 	if((got = cifsrpc(p)) == -1)
84 		return -1;
85 
86 	gl16(p);			/* Total parameter count */
87 	gl16(p);			/* Total data count */
88 	gl16(p);			/* Reserved */
89 	gl16(p);			/* Parameter count in this buffer */
90 	p->tparam = p->buf + NBHDRLEN + gl16(p); /* Parameter offset */
91 	gl16(p);			/* Parameter displacement */
92 	gl16(p);			/* Data count (this buffer); */
93 	p->tdata = p->buf + NBHDRLEN + gl16(p); /* Data offset */
94 	gl16(p);			/* Data displacement */
95 	g8(p);				/* Setup count */
96 	g8(p);				/* Reserved */
97 	return got;
98 }
99 
100 static void
gtparam(Pkt * p)101 gtparam(Pkt *p)
102 {
103 	p->pos = p->tparam;
104 }
105 
106 static void
gtdata(Pkt * p)107 gtdata(Pkt *p)
108 {
109 	p->pos = p->tdata;
110 }
111 
112 
113 int
RAPshareenum(Session * s,Share * sp,Share ** ent)114 RAPshareenum(Session *s, Share *sp, Share **ent)
115 {
116 	int ngot = 0, err, navail, nret;
117 	char tmp[1024];
118 	Pkt *p;
119 	Share *q;
120 
121 	p = thdr(s, sp);
122 	pstr(p, "\\PIPE\\LANMAN");
123 	ptparam(p);
124 
125 	pl16(p, API_WShareEnum);
126 	pascii(p, REMSmb_NetShareEnum_P);	/* request descriptor */
127 	pascii(p, REMSmb_share_info_0);		/* reply descriptor */
128 	pl16(p, 0);				/* detail level */
129 	pl16(p, MTU - 200);			/* receive buffer length */
130 	ptdata(p);
131 
132 	if(trpc(p) == -1){
133 		free(p);
134 		return -1;
135 	}
136 
137 	gtparam(p);
138 	err = gl16(p);				/* error code */
139 	gl16(p);				/* rx buffer offset */
140 	nret = gl16(p);				/* number of entries returned */
141 	navail = gl16(p);			/* number of entries available */
142 
143 	if(err && err != RAP_ERR_MOREINFO){
144 		werrstr("%s", raperrstr(err));
145 		free(p);
146 		return -1;
147 	}
148 
149 	if(ngot == 0){
150 		*ent = emalloc9p(sizeof(Share) * navail);
151 		memset(*ent, 0, sizeof(Share) * navail);
152 	}
153 
154 	q = *ent + ngot;
155 	for (; ngot < navail && nret--; ngot++){
156 		gmem(p, tmp, 13); 		/* name */
157 		tmp[13] = 0;
158 		q->name = estrdup9p(tmp);
159 		q++;
160 	}
161 
162 	if(ngot < navail)
163 		fprint(2, "%s: %d/%d - share list incomplete\n", argv0, ngot, navail);
164 
165 	free(p);
166 	return ngot;
167 }
168 
169 
170 int
RAPshareinfo(Session * s,Share * sp,char * share,Shareinfo2 * si2p)171 RAPshareinfo(Session *s, Share *sp, char *share, Shareinfo2 *si2p)
172 {
173 	int conv, err;
174 	char tmp[1024];
175 	Pkt *p;
176 
177 	p = thdr(s, sp);
178 	pstr(p, "\\PIPE\\LANMAN");
179 
180 	ptparam(p);
181 	pl16(p, API_WShareGetInfo);
182 	pascii(p, REMSmb_NetShareGetInfo_P);	/* request descriptor */
183 	pascii(p, REMSmb_share_info_2);		/* reply descriptor */
184 	pascii(p, share);
185 	pl16(p, 1);				/* detail level */
186 	pl16(p, MTU - 200);			/* receive buffer length */
187 
188 	ptdata(p);
189 
190 	if(trpc(p) == -1){
191 		free(p);
192 		return -1;
193 	}
194 
195 	gtparam(p);
196 	err = gl16(p);				/* error code */
197 	conv = gl16(p);				/* rx buffer offset */
198 	gl16(p);				/* number of entries returned */
199 	gl16(p);				/* number of entries available */
200 
201 	if(err){
202 		werrstr("%s", raperrstr(err));
203 		free(p);
204 		return -1;
205 	}
206 
207 	memset(si2p, 0, sizeof(Shareinfo2));
208 
209 	gmem(p, tmp, 13);
210 	tmp[13] = 0;
211 	g8(p);					/* padding */
212 	si2p->name = estrdup9p(tmp);
213 	si2p->type = gl16(p);
214 	gconv(p, conv, tmp, sizeof tmp);
215 	si2p->comment = estrdup9p(tmp);
216 	gl16(p);				/* comment offset high (unused) */
217 	si2p->perms = gl16(p);
218 	si2p->maxusrs = gl16(p);
219 	si2p->activeusrs = gl16(p);
220 	gconv(p, conv, tmp, sizeof tmp);
221 	si2p->path = estrdup9p(tmp);
222 	gl16(p);				/* path offset high (unused) */
223 	gmem(p, tmp, 9);
224 	tmp[9] = 0;
225 	si2p->passwd = estrdup9p(tmp);
226 
227 	free(p);
228 	return 0;
229 }
230 
231 /*
232  * Tried to split sessionenum into two passes, one getting the names
233  * of the connected workstations and the other collecting the detailed info,
234  * however API_WSessionGetInfo doesn't seem to work agains win2k3 for infolevel
235  * ten and infolevel one and two are priviledged calls.  This means this code
236  * will work for small numbers of sessions agains win2k3 and fail for samba 3.0
237  * as it supports info levels zero and two only.
238  */
239 int
RAPsessionenum(Session * s,Share * sp,Sessinfo ** sip)240 RAPsessionenum(Session *s, Share *sp, Sessinfo **sip)
241 {
242 	int ngot = 0, conv, err, navail, nret;
243 	char tmp[1024];
244 	Pkt *p;
245 	Sessinfo *q;
246 
247 	p = thdr(s, sp);
248 	pstr(p, "\\PIPE\\LANMAN");
249 	ptparam(p);
250 
251 	pl16(p, API_WSessionEnum);
252 	pascii(p, REMSmb_NetSessionEnum_P);	/* request descriptor */
253 	pascii(p, REMSmb_session_info_10);	/* reply descriptor */
254 	pl16(p, 10);				/* detail level */
255 	pl16(p, MTU - 200);			/* receive buffer length */
256 	ptdata(p);
257 
258 	if(trpc(p) == -1){
259 		free(p);
260 		return -1;
261 	}
262 
263 	gtparam(p);
264 	err = gl16(p);				/* error code */
265 	conv = gl16(p);				/* rx buffer offset */
266 	nret = gl16(p);				/* number of entries returned */
267 	navail = gl16(p);			/* number of entries available */
268 
269 	if(err && err != RAP_ERR_MOREINFO){
270 		werrstr("%s", raperrstr(err));
271 		free(p);
272 		return -1;
273 	}
274 
275 	if(ngot == 0){
276 		*sip = emalloc9p(sizeof(Sessinfo) * navail);
277 		memset(*sip, 0, sizeof(Sessinfo) * navail);
278 	}
279 
280 	q = *sip + ngot;
281 	while(nret-- != 0){
282 		gconv(p, conv, tmp, sizeof tmp);
283 		q->wrkstn = estrdup9p(tmp);
284 		gconv(p, conv, tmp, sizeof tmp);
285 		q->user = estrdup9p(tmp);
286 		q->sesstime = gl32(p);
287 		q->idletime = gl32(p);
288 		ngot++;
289 		q++;
290 	}
291 	if(ngot < navail)
292 		fprint(2, "warning: %d/%d - session list incomplete\n", ngot, navail);
293 	free(p);
294 	return ngot;
295 }
296 
297 
298 int
RAPgroupenum(Session * s,Share * sp,Namelist ** nlp)299 RAPgroupenum(Session *s, Share *sp, Namelist **nlp)
300 {
301 	int ngot, err, navail, nret;
302 	char tmp[1024];
303 	Pkt *p;
304 	Namelist *q;
305 
306 	ngot = 0;
307 	p = thdr(s, sp);
308 	pstr(p, "\\PIPE\\LANMAN");
309 	ptparam(p);
310 
311 	pl16(p, API_WGroupEnum);
312 	pascii(p, REMSmb_NetGroupEnum_P);	/* request descriptor */
313 	pascii(p, REMSmb_group_info_0);		/* reply descriptor */
314 	pl16(p, 0);				/* detail level */
315 	pl16(p, MTU - 200);			/* receive buffer length */
316 	ptdata(p);
317 
318 	if(trpc(p) == -1){
319 		free(p);
320 		return -1;
321 	}
322 
323 	gtparam(p);
324 	err = gl16(p);				/* error code */
325 	gl16(p);				/* rx buffer offset */
326 	nret = gl16(p);				/* number of entries returned */
327 	navail = gl16(p);			/* number of entries available */
328 
329 	if(err && err != RAP_ERR_MOREINFO){
330 		werrstr("%s", raperrstr(err));
331 		free(p);
332 		return -1;
333 	}
334 
335 	*nlp = emalloc9p(sizeof(Namelist) * navail);
336 	memset(*nlp, 0, sizeof(Namelist) * navail);
337 
338 	q = *nlp + ngot;
339 	while(ngot < navail && nret--){
340  		gmem(p, tmp, 21);
341 		tmp[21] = 0;
342 		q->name = estrdup9p(tmp);
343 		ngot++;
344 		q++;
345 		if(p->pos >= p->eop)		/* Windows seems to lie somtimes */
346 			break;
347 	}
348 	free(p);
349 	return ngot;
350 }
351 
352 
353 int
RAPgroupusers(Session * s,Share * sp,char * group,Namelist ** nlp)354 RAPgroupusers(Session *s, Share *sp, char *group, Namelist **nlp)
355 {
356 	int ngot, err, navail, nret;
357 	char tmp[1024];
358 	Pkt *p;
359 	Namelist *q;
360 
361 	ngot = 0;
362 	p = thdr(s, sp);
363 	pstr(p, "\\PIPE\\LANMAN");
364 	ptparam(p);
365 
366 	pl16(p, API_WGroupGetUsers);
367 	pascii(p, REMSmb_NetGroupGetUsers_P);	/* request descriptor */
368 	pascii(p, REMSmb_user_info_0);		/* reply descriptor */
369 	pascii(p, group);			/* group name for list */
370 	pl16(p, 0);				/* detail level */
371 	pl16(p, MTU - 200);			/* receive buffer length */
372 	ptdata(p);
373 
374 	if(trpc(p) == -1){
375 		free(p);
376 		return -1;
377 	}
378 
379 	gtparam(p);
380 	err = gl16(p);				/* error code */
381 	gl16(p);				/* rx buffer offset */
382 	nret = gl16(p);				/* number of entries returned */
383 	navail = gl16(p);			/* number of entries available */
384 
385 	if(err && err != RAP_ERR_MOREINFO){
386 		werrstr("%s", raperrstr(err));
387 		free(p);
388 		return -1;
389 	}
390 
391 	*nlp = emalloc9p(sizeof(Namelist) * navail);
392 	memset(*nlp, 0, sizeof(Namelist) * navail);
393 
394 	q = *nlp + ngot;
395 	while(ngot < navail && nret--){
396  		gmem(p, tmp, 21);
397 		tmp[21] = 0;
398 		q->name = estrdup9p(tmp);
399 		ngot++;
400 		q++;
401 		if(p->pos >= p->eop)		/* Windows seems to lie somtimes */
402 			break;
403 	}
404 	free(p);
405 	return ngot;
406 }
407 
408 int
RAPuserenum(Session * s,Share * sp,Namelist ** nlp)409 RAPuserenum(Session *s, Share *sp, Namelist **nlp)
410 {
411 	int ngot, err, navail, nret;
412 	char tmp[1024];
413 	Pkt *p;
414 	Namelist *q;
415 
416 	ngot = 0;
417 	p = thdr(s, sp);
418 	pstr(p, "\\PIPE\\LANMAN");
419 	ptparam(p);
420 
421 	pl16(p, API_WUserEnum);
422 	pascii(p, REMSmb_NetUserEnum_P);	/* request descriptor */
423 	pascii(p, REMSmb_user_info_0);		/* reply descriptor */
424 	pl16(p, 0);				/* detail level */
425 	pl16(p, MTU - 200);			/* receive buffer length */
426 	ptdata(p);
427 
428 	if(trpc(p) == -1){
429 		free(p);
430 		return -1;
431 	}
432 
433 	gtparam(p);
434 	err = gl16(p);				/* error code */
435 	gl16(p);				/* rx buffer offset */
436 	nret = gl16(p);				/* number of entries returned */
437 	navail = gl16(p);			/* number of entries available */
438 
439 	if(err && err != RAP_ERR_MOREINFO){
440 		werrstr("%s", raperrstr(err));
441 		free(p);
442 		return -1;
443 	}
444 
445 	*nlp = emalloc9p(sizeof(Namelist) * navail);
446 	memset(*nlp, 0, sizeof(Namelist) * navail);
447 
448 	q = *nlp + ngot;
449 	while(ngot < navail && nret--){
450  		gmem(p, tmp, 21);
451 		tmp[21] = 0;
452 		q->name = estrdup9p(tmp);
453 		ngot++;
454 		q++;
455 		if(p->pos >= p->eop)		/* Windows seems to lie somtimes */
456 			break;
457 	}
458 	free(p);
459 	return ngot;
460 }
461 
462 int
RAPuserenum2(Session * s,Share * sp,Namelist ** nlp)463 RAPuserenum2(Session *s, Share *sp, Namelist **nlp)
464 {
465 	int ngot, resume, err, navail, nret;
466 	char tmp[1024];
467 	Pkt *p;
468 	Namelist *q;
469 
470 	ngot = 0;
471 	resume = 0;
472 more:
473 	p = thdr(s, sp);
474 	pstr(p, "\\PIPE\\LANMAN");
475 	ptparam(p);
476 
477 	pl16(p, API_WUserEnum2);
478 	pascii(p, REMSmb_NetUserEnum2_P);	/* request descriptor */
479 	pascii(p, REMSmb_user_info_0);		/* reply descriptor */
480 	pl16(p, 0);				/* detail level */
481 	pl16(p, MTU - 200);			/* receive buffer length */
482 	pl32(p, resume);			/* resume key to allow multiple fetches */
483 	ptdata(p);
484 
485 	if(trpc(p) == -1){
486 		free(p);
487 		return -1;
488 	}
489 
490 	gtparam(p);
491 	err = gl16(p);				/* error code */
492 	gl16(p);				/* rx buffer offset */
493 	resume = gl32(p);			/* resume key returned */
494 	nret = gl16(p);				/* number of entries returned */
495 	navail = gl16(p);			/* number of entries available */
496 
497 	if(err && err != RAP_ERR_MOREINFO){
498 		werrstr("%s", raperrstr(err));
499 		free(p);
500 		return -1;
501 	}
502 
503 	if(ngot == 0){
504 		*nlp = emalloc9p(sizeof(Namelist) * navail);
505 		memset(*nlp, 0, sizeof(Namelist) * navail);
506 	}
507 	q = *nlp + ngot;
508 	while(ngot < navail && nret--){
509  		gmem(p, tmp, 21);
510 		tmp[21] = 0;
511 		q->name = estrdup9p(tmp);
512 		ngot++;
513 		q++;
514 		if(p->pos >= p->eop)		/* Windows seems to lie somtimes */
515 			break;
516 	}
517 	free(p);
518 	if(ngot < navail)
519 		goto more;
520 	return ngot;
521 }
522 
523 int
RAPuserinfo(Session * s,Share * sp,char * user,Userinfo * uip)524 RAPuserinfo(Session *s, Share *sp, char *user, Userinfo *uip)
525 {
526 	int conv, err;
527 	char tmp[1024];
528 	Pkt *p;
529 
530 	p = thdr(s, sp);
531 	pstr(p, "\\PIPE\\LANMAN");
532 	ptparam(p);
533 
534 	pl16(p, API_WUserGetInfo);
535 	pascii(p, REMSmb_NetUserGetInfo_P);	/* request descriptor */
536 	pascii(p, REMSmb_user_info_10);		/* reply descriptor */
537 	pascii(p, user);			/* username */
538 	pl16(p, 10);				/* detail level */
539 	pl16(p, MTU - 200);			/* receive buffer length */
540 	ptdata(p);
541 
542 	if(trpc(p) == -1){
543 		free(p);
544 		return -1;
545 	}
546 
547 	gtparam(p);
548 	err = gl16(p);				/* error code */
549 	conv = gl16(p);				/* rx buffer offset */
550 	gl16(p);				/* number of entries returned */
551 	gl16(p);				/* number of entries available */
552 
553 	if(err && err != RAP_ERR_MOREINFO){
554 		werrstr("%s", raperrstr(err));
555 		free(p);
556 		return -1;
557 	}
558 
559  	gmem(p, tmp, 21);
560 	tmp[21] = 0;
561 	uip->user = estrdup9p(tmp);
562 	g8(p);				/* padding */
563 	gconv(p, conv, tmp, sizeof tmp);
564 	uip->comment = estrdup9p(tmp);
565 	gconv(p, conv, tmp, sizeof tmp);
566 	uip->user_comment = estrdup9p(tmp);
567 	gconv(p, conv, tmp, sizeof tmp);
568 	uip->fullname = estrdup9p(tmp);
569 
570 	free(p);
571 	return 0;
572 }
573 
574 /*
575  * This works agains win2k3 but fails
576  * against XP with the undocumented error 71/0x47
577  */
578 int
RAPServerenum2(Session * s,Share * sp,char * workgroup,int type,int * more,Serverinfo ** si)579 RAPServerenum2(Session *s, Share *sp, char *workgroup, int type, int *more,
580 	Serverinfo **si)
581 {
582 	int ngot = 0, conv, err, nret, navail;
583 	char tmp[1024];
584 	Pkt *p;
585 	Serverinfo *q;
586 
587 	p = thdr(s, sp);
588 	pstr(p, "\\PIPE\\LANMAN");
589 
590 	ptparam(p);
591 	pl16(p, API_NetServerEnum2);
592 	pascii(p, REMSmb_NetServerEnum2_P);	/* request descriptor */
593 	pascii(p, REMSmb_server_info_1);	/* reply descriptor */
594 	pl16(p, 1);				/* detail level */
595 	pl16(p, MTU - 200);			/* receive buffer length */
596 	pl32(p, type);
597 	pascii(p, workgroup);
598 
599 	ptdata(p);
600 
601 	if(trpc(p) == -1){
602 		free(p);
603 		return -1;
604 	}
605 
606 	gtparam(p);
607 	err = gl16(p);				/* error code */
608 	conv = gl16(p);				/* rx buffer offset */
609 	nret = gl16(p);				/* number of entries returned */
610 	navail = gl16(p);			/* number of entries available */
611 
612 	if(err && err != RAP_ERR_MOREINFO){
613 		werrstr("%s", raperrstr(err));
614 		free(p);
615 		return -1;
616 	}
617 
618 	*si = emalloc9p(sizeof(Serverinfo) * navail);
619 	memset(*si, 0, sizeof(Serverinfo) * navail);
620 
621 	q = *si;
622 	for (; nret-- != 0 && ngot < navail; ngot++){
623 		gmem(p, tmp, 16);
624 		tmp[16] = 0;
625 		q->name = estrdup9p(tmp);
626 		q->major = g8(p);
627 		q->minor = g8(p);
628 		q->type = gl32(p);
629 		gconv(p, conv, tmp, sizeof tmp);
630 		q->comment = estrdup9p(tmp);
631 		q++;
632 	}
633 	free(p);
634 	*more = err == RAP_ERR_MOREINFO;
635 	return ngot;
636 }
637 
638 int
RAPServerenum3(Session * s,Share * sp,char * workgroup,int type,int last,Serverinfo * si)639 RAPServerenum3(Session *s, Share *sp, char *workgroup, int type, int last,
640 	Serverinfo *si)
641 {
642 	int conv, err, ngot, nret, navail;
643 	char *first, tmp[1024];
644 	Pkt *p;
645 	Serverinfo *q;
646 
647 	ngot = last +1;
648 	first = si[last].name;
649 more:
650 	p = thdr(s, sp);
651 	pstr(p, "\\PIPE\\LANMAN");
652 
653 	ptparam(p);
654 	pl16(p, API_NetServerEnum3);
655 	pascii(p, REMSmb_NetServerEnum3_P);	/* request descriptor */
656 	pascii(p, REMSmb_server_info_1);	/* reply descriptor */
657 	pl16(p, 1);				/* detail level */
658 	pl16(p, MTU - 200);			/* receive buffer length */
659 	pl32(p, type);
660 	pascii(p, workgroup);
661 	pascii(p, first);
662 
663 	ptdata(p);
664 
665 	if(trpc(p) == -1){
666 		free(p);
667 		return -1;
668 	}
669 
670 	gtparam(p);
671 	err = gl16(p);				/* error code */
672 	conv = gl16(p);				/* rx buffer offset */
673 	nret = gl16(p);				/* number of entries returned */
674 	navail = gl16(p);			/* number of entries available */
675 
676 	if(err && err != RAP_ERR_MOREINFO){
677 		werrstr("%s", raperrstr(err));
678 		free(p);
679 		return -1;
680 	}
681 
682 	if(nret < 2){				/* paranoia */
683 		free(p);
684 		return ngot;
685 	}
686 
687 	q = si+ngot;
688 	while(nret-- != 0 && ngot < navail){
689 		gmem(p, tmp, 16);
690 		tmp[16] = 0;
691 		q->name = estrdup9p(tmp);
692 		q->major = g8(p);
693 		q->minor = g8(p);
694 		q->type = gl32(p);
695 		gconv(p, conv, tmp, sizeof tmp);
696 		tmp[sizeof tmp - 1] = 0;
697 		q->comment = estrdup9p(tmp);
698 		if(strcmp(first, tmp) == 0){ /* 1st one thru _may_ be a repeat */
699 			free(q->name);
700 			free(q->comment);
701 			continue;
702 		}
703 		ngot++;
704 		q++;
705 	}
706 	free(p);
707 	if(ngot < navail)
708 		goto more;
709 	return ngot;
710 }
711 
712 /* Only the Administrator has permission to do this */
713 int
RAPFileenum2(Session * s,Share * sp,char * user,char * path,Fileinfo ** fip)714 RAPFileenum2(Session *s, Share *sp, char *user, char *path, Fileinfo **fip)
715 {
716 	int conv, err, ngot, resume, nret, navail;
717 	char tmp[1024];
718 	Pkt *p;
719 	Fileinfo *q;
720 
721 	ngot = 0;
722 	resume = 0;
723 more:
724 	p = thdr(s, sp);
725 	pstr(p, "\\PIPE\\LANMAN");
726 
727 	ptparam(p);
728 	pl16(p, API_WFileEnum2);
729 	pascii(p, REMSmb_NetFileEnum2_P);	/* request descriptor */
730 	pascii(p, REMSmb_file_info_1);		/* reply descriptor */
731 	pascii(p, path);
732 	pascii(p, user);
733 	pl16(p, 1);				/* detail level */
734 	pl16(p, MTU - 200);			/* receive buffer length */
735 	pl32(p, resume);			/* resume key */
736 /* FIXME: maybe the padding and resume key are the wrong way around? */
737 	pl32(p, 0);				/* padding ? */
738 
739 	ptdata(p);
740 
741 	if(trpc(p) == -1){
742 		free(p);
743 		return -1;
744 	}
745 
746 	gtparam(p);
747 	err = gl16(p);				/* error code */
748 	conv = gl16(p);				/* rx buffer offset */
749 	resume = gl32(p);			/* resume key returned */
750 	nret = gl16(p);				/* number of entries returned */
751 	navail = gl16(p);			/* number of entries available */
752 
753 	if(err && err != RAP_ERR_MOREINFO){
754 		werrstr("%s", raperrstr(err));
755 		free(p);
756 		return -1;
757 	}
758 
759 	if(nret < 2){				/* paranoia */
760 		free(p);
761 		return ngot;
762 	}
763 
764 	if(ngot == 0){
765 		*fip = emalloc9p(sizeof(Fileinfo) * navail);
766 		memset(*fip, 0, sizeof(Fileinfo) * navail);
767 	}
768 	q = *fip + ngot;
769 	for(; nret-- && ngot < navail; ngot++){
770 		q->ident = gl16(p);
771 		q->perms = gl16(p);
772 		q->locks = gl16(p);
773 		gconv(p, conv, tmp, sizeof tmp);
774 		tmp[sizeof tmp - 1] = 0;
775 		q->path = estrdup9p(tmp);
776 		gconv(p, conv, tmp, sizeof tmp);
777 		tmp[sizeof tmp - 1] = 0;
778 		q->user = estrdup9p(tmp);
779 		q++;
780 	}
781 	free(p);
782 	if(ngot < navail)
783 		goto more;
784 	return ngot;
785 }
786