Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/cifs/trans.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <fcall.h>
4
#include <thread.h>
5
#include <9p.h>
6
#include "cifs.h"
7
#include "remsmb.h"
8
#include "apinums.h"
9
 
10
static Pkt *
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
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
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
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
101
gtparam(Pkt *p)
102
{
103
	p->pos = p->tparam;
104
}
105
 
106
static void
107
gtdata(Pkt *p)
108
{
109
	p->pos = p->tdata;
110
}
111
 
112
 
113
int
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
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
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
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
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
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
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
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
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
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
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
}