xref: /plan9/sys/src/cmd/aquarela/smbtransaction.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include "headers.h"
2 
3 typedef struct Args Args;
4 
5 struct Args {
6 	ulong pcount;
7 	ulong poffset;
8 	ulong pdisplacement;
9 	ulong dcount;
10 	ulong doffset;
11 	ulong ddisplacement;
12 	uchar scount;
13 };
14 
15 int
_smbtransactiondecodeprimary(SmbTransaction * t,SmbHeader * h,uchar * pdata,SmbBuffer * b,int hasname,char ** errmsgp)16 _smbtransactiondecodeprimary(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, int hasname, char **errmsgp)
17 {
18 	ushort poffset, doffset;
19 
20 	if (h->wordcount < 14) {
21 		smbstringprint(errmsgp, "word count less than 14");
22 		return -1;
23 	}
24 	t->in.scount = pdata[13 * 2];
25 	if (h->wordcount != 14 + t->in.scount) {
26 		smbstringprint(errmsgp, "smbcomtransaction: word count invalid\n");
27 		return -1;
28 	}
29 	t->in.tpcount = smbnhgets(pdata); pdata += 2;
30 	t->in.tdcount = smbnhgets(pdata); pdata += 2;
31 	t->in.maxpcount = smbnhgets(pdata); pdata += 2;
32 	t->in.maxdcount = smbnhgets(pdata); pdata += 2;
33 	t->in.maxscount = *pdata++;
34 	pdata++;
35 	t->in.flags = smbnhgets(pdata); pdata += 2;
36 	pdata += 4; /* timeout */
37 	pdata += 2;
38 	t->in.pcount = smbnhgets(pdata); pdata += 2;
39 	poffset = smbnhgets(pdata); pdata += 2;
40 	t->in.dcount = smbnhgets(pdata); pdata += 2;
41 	doffset = smbnhgets(pdata); pdata += 2;
42 	pdata++; /* scount */
43 	pdata++; /* reserved */
44 	smbfree(&t->in.setup);
45 	if (t->in.scount) {
46 		int x;
47 		t->in.setup = smbemalloc(t->in.scount * sizeof(ushort));
48 		for (x = 0; x < t->in.scount; x++) {
49 			t->in.setup[x] = smbnhgets(pdata);
50 			pdata += 2;
51 		}
52 	}
53 	smbfree(&t->in.name);
54 	if (hasname && !smbbuffergetstring(b, h, SMB_STRING_PATH, &t->in.name)) {
55 		smbstringprint(errmsgp, "not enough bdata for name");
56 		return -1;
57 	}
58 	if (poffset + t->in.pcount > smbbufferwriteoffset(b)) {
59 		smbstringprint(errmsgp, "not enough bdata for parameters");
60 		return -1;
61 	}
62 	if (t->in.pcount > t->in.tpcount) {
63 		smbstringprint(errmsgp, "too many parameters");
64 		return -1;
65 	}
66 	smbfree(&t->in.parameters);
67 	t->in.parameters = smbemalloc(t->in.tpcount);
68 	memcpy(t->in.parameters, smbbufferpointer(b, poffset), t->in.pcount);
69 	if (doffset + t->in.dcount > smbbufferwriteoffset(b)) {
70 		smbstringprint(errmsgp, "not enough bdata for data");
71 		return -1;
72 	}
73 	if (t->in.dcount > t->in.tdcount) {
74 		smbstringprint(errmsgp, "too much data");
75 		return -1;
76 	}
77 	smbfree(&t->in.data);
78 	t->in.data = smbemalloc(t->in.tdcount);
79 	memcpy(t->in.data, smbbufferpointer(b, doffset), t->in.dcount);
80 	if (t->in.dcount < t->in.tdcount || t->in.pcount < t->in.tpcount)
81 		return 0;
82 	return 1;
83 }
84 
85 int
decoderesponse(SmbTransaction * t,Args * a,SmbBuffer * b,char ** errmsgp)86 decoderesponse(SmbTransaction *t, Args *a, SmbBuffer *b, char **errmsgp)
87 {
88 	if (t->out.tpcount > smbbufferwritemaxoffset(t->out.parameters)) {
89 		smbstringprint(errmsgp, "decoderesponse: too many parameters for buffer");
90 		return 0;
91 	}
92 	if (t->out.tdcount > smbbufferwritemaxoffset(t->out.data)) {
93 		smbstringprint(errmsgp, "decoderesponse: too much data for buffer");
94 		return 0;
95 	}
96 	if (a->pdisplacement + a->pcount > t->out.tpcount) {
97 		smbstringprint(errmsgp, "decoderesponse: more parameters than tpcount");
98 		return 0;
99 	}
100 	if (a->pdisplacement != smbbufferwriteoffset(t->out.parameters)) {
101 		smbstringprint(errmsgp, "decoderesponse: parameter displacement inconsistent");
102 		return 0;
103 	}
104 	if (a->ddisplacement + a->dcount > t->out.tdcount) {
105 		smbstringprint(errmsgp, "decoderesponse: more data than tdcount");
106 		return 0;
107 	}
108 	if (a->ddisplacement != smbbufferwriteoffset(t->out.data)) {
109 		smbstringprint(errmsgp, "decoderesponse: data displacement inconsistent");
110 		return 0;
111 	}
112 	assert(a->scount == 0);
113 	if (a->pcount) {
114 		if (!smbbufferreadskipto(b, a->poffset)) {
115 			smbstringprint(errmsgp, "smbtransactiondecoderesponse: invalid parameter offset");
116 			return 0;
117 		}
118 		if (!smbbuffercopy(t->out.parameters, b, a->pcount)) {
119 			smbstringprint(errmsgp, "smbtransactiondecoderesponse: not enough data for parameters");
120 			return 0;
121 		}
122 	}
123 	if (a->dcount) {
124 		if (!smbbufferreadskipto(b, a->doffset)) {
125 			smbstringprint(errmsgp, "smbtransactiondecoderesponse: invalid data offset");
126 			return 0;
127 		}
128 		if (!smbbuffercopy(t->out.data, b, a->dcount)) {
129 			smbstringprint(errmsgp, "smbtransactiondecoderesponse: not enough data for data");
130 			return 0;
131 		}
132 	}
133 	return 1;
134 }
135 
136 int
smbtransactiondecoderesponse(SmbTransaction * t,SmbHeader * h,uchar * pdata,SmbBuffer * b,char ** errmsgp)137 smbtransactiondecoderesponse(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, char **errmsgp)
138 {
139 	Args a;
140 
141 	if (h->command != SMB_COM_TRANSACTION) {
142 		smbstringprint(errmsgp, "smbtransactiondecoderesponse: not an SMB_COM_TRANSACTION");
143 		return 0;
144 	}
145 	if (h->wordcount < 10) {
146 		smbstringprint(errmsgp, "smbtransactiondecoderesponse: word count less than 10");
147 		return -1;
148 	}
149 	t->out.tpcount = smbnhgets(pdata); pdata += 2;
150 	t->out.tdcount = smbnhgets(pdata); pdata += 2;
151 	pdata += 2;
152 	a.pcount = smbnhgets(pdata); pdata += 2;
153 	a.poffset =  smbnhgets(pdata); pdata += 2;
154 	a.pdisplacement = smbnhgets(pdata); pdata += 2;
155 	a.dcount = smbnhgets(pdata); pdata += 2;
156 	a.doffset =  smbnhgets(pdata); pdata += 2;
157 	a.ddisplacement = smbnhgets(pdata); pdata += 2;
158 	a.scount = *pdata;
159 	if (a.scount != h->wordcount - 10) {
160 		smbstringprint(errmsgp, "smbtransactiondecoderesponse: scount inconsistent");
161 		return 0;
162 	}
163 	return decoderesponse(t, &a, b, errmsgp);
164 }
165 
166 int
smbtransactiondecoderesponse2(SmbTransaction * t,SmbHeader * h,uchar * pdata,SmbBuffer * b,char ** errmsgp)167 smbtransactiondecoderesponse2(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, char **errmsgp)
168 {
169 	Args a;
170 
171 	if (h->command != SMB_COM_TRANSACTION2) {
172 		smbstringprint(errmsgp, "smbtransactiondecoderesponse2: not an SMB_COM_TRANSACTION2");
173 		return 0;
174 	}
175 	if (h->wordcount < 10) {
176 		smbstringprint(errmsgp, "smbtransactiondecoderesponse2: word count less than 10");
177 		return -1;
178 	}
179 	t->out.tpcount = smbnhgets(pdata); pdata += 2;
180 	t->out.tdcount = smbnhgets(pdata); pdata += 2;
181 	pdata += 2;
182 	a.pcount = smbnhgets(pdata); pdata += 2;
183 	a.poffset =  smbnhgets(pdata); pdata += 2;
184 	a.pdisplacement = smbnhgets(pdata); pdata += 2;
185 	a.dcount = smbnhgets(pdata); pdata += 2;
186 	a.doffset =  smbnhgets(pdata); pdata += 2;
187 	a.ddisplacement = smbnhgets(pdata); pdata += 2;
188 	a.scount = *pdata;
189 	if (a.scount != h->wordcount - 10) {
190 		smbstringprint(errmsgp, "smbtransactiondecoderesponse2: scount inconsistent");
191 		return 0;
192 	}
193 	return decoderesponse(t, &a, b, errmsgp);
194 }
195 
196 int
smbtransactiondecodeprimary(SmbTransaction * t,SmbHeader * h,uchar * pdata,SmbBuffer * b,char ** errmsgp)197 smbtransactiondecodeprimary(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, char **errmsgp)
198 {
199 	return _smbtransactiondecodeprimary(t, h, pdata, b, 1, errmsgp);
200 }
201 
202 int
smbtransactiondecodeprimary2(SmbTransaction * t,SmbHeader * h,uchar * pdata,SmbBuffer * b,char ** errmsgp)203 smbtransactiondecodeprimary2(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, char **errmsgp)
204 {
205 	return _smbtransactiondecodeprimary(t, h, pdata, b, 0, errmsgp);
206 }
207 
208 void
smbtransactionfree(SmbTransaction * t)209 smbtransactionfree(SmbTransaction *t)
210 {
211 	free(t->in.parameters);
212 	free(t->in.data);
213 	free(t->in.setup);
214 	free(t->in.name);
215 	smbbufferfree(&t->out.parameters);
216 	smbbufferfree(&t->out.data);
217 }
218 
219 static int
_transactionencodeprimary(SmbTransaction * t,uchar cmd,SmbHeader * h,SmbPeerInfo * p,SmbBuffer * ob,uchar * wordcountp,ushort * bytecountp,char ** errmsgp)220 _transactionencodeprimary(SmbTransaction *t, uchar cmd, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob,
221 	uchar *wordcountp, ushort *bytecountp, char **errmsgp)
222 {
223 	SmbHeader mh;
224 	ulong countsfixupoffset, bytecountfixupoffset;
225 	int x;
226 	mh = *h;
227 	*wordcountp = mh.wordcount = 14 + t->in.scount;
228 	mh.flags &= ~SMB_FLAGS_SERVER_TO_REDIR;
229 	mh.command = cmd;
230 	if (!smbbufferputheader(ob, &mh, p)) {
231 	toosmall:
232 		smbstringprint(errmsgp, "output buffer too small");
233 		return 0;
234 	}
235 	if (t->in.tpcount > 65535 || t->in.tdcount > 65535 || t->in.maxpcount > 65535 || t->in.maxdcount > 65535) {
236 		smbstringprint(errmsgp, "counts too big");
237 		return 0;
238 	}
239 	if (!smbbufferputs(ob, t->in.tpcount)
240 		|| !smbbufferputs(ob, t->in.tdcount)
241 		|| !smbbufferputs(ob, t->in.maxpcount)
242 		|| !smbbufferputs(ob, t->in.maxdcount)
243 		|| !smbbufferputb(ob, t->in.maxscount)
244 		|| !smbbufferputb(ob, 0)
245 		|| !smbbufferputs(ob, t->in.flags)
246 		|| !smbbufferputl(ob, 0)
247 		|| !smbbufferputs(ob, 0))
248 		goto toosmall;
249 	countsfixupoffset = smbbufferwriteoffset(ob);
250 	if (!smbbufferputs(ob, 0)
251 		|| !smbbufferputs(ob, 0)
252 		|| !smbbufferputs(ob, 0)
253 		|| !smbbufferputs(ob, 0))
254 		goto toosmall;
255 	if (!smbbufferputb(ob, t->in.scount)
256 		|| !smbbufferputb(ob, 0))
257 		goto toosmall;
258 	for (x = 0; x < t->in.scount; x++)
259 		if (!smbbufferputs(ob, t->in.setup[x]))
260 			goto toosmall;
261 	bytecountfixupoffset = smbbufferwriteoffset(ob);
262 	if (!smbbufferputs(ob, 0))
263 		goto toosmall;
264 	smbbufferwritelimit(ob, smbbufferwriteoffset(ob) + 65535);
265 	if (!smbbufferputstring(ob, p, SMB_STRING_UPCASE, t->in.name))
266 		goto toosmall;
267 	if (t->in.pcount < t->in.tpcount) {
268 		ulong align = smbbufferwriteoffset(ob) & 1;
269 		ulong pthistime;
270 		pthistime = smbbufferwritespace(ob) - align;
271 		if (pthistime > t->in.tpcount - t->in.pcount)
272 			pthistime = t->in.tpcount - t->in.pcount;
273 		if (pthistime > 65535)
274 			pthistime = 65535;
275 		if (smbbufferwriteoffset(ob) > 65535)
276 			pthistime = 0;
277 		if (pthistime) {
278 			assert(smbbufferalignl2(ob, 0));
279 			assert(smbbufferoffsetputs(ob, countsfixupoffset, pthistime));
280 			assert(smbbufferoffsetputs(ob, countsfixupoffset + 2, smbbufferwriteoffset(ob)));
281 			assert(smbbufferputbytes(ob, t->in.parameters + t->in.pcount, pthistime));
282 		}
283 		t->in.pcount += pthistime;
284 	}
285 	if (t->in.dcount < t->in.tdcount) {
286 		ulong align = smbbufferwriteoffset(ob) & 1;
287 		ulong dthistime;
288 		dthistime = smbbufferwritespace(ob) - align;
289 		if (dthistime > t->in.tdcount - t->in.dcount)
290 			dthistime = t->in.tdcount - t->in.dcount;
291 		if (dthistime > 65535)
292 			dthistime = 65535;
293 		if (smbbufferwriteoffset(ob) > 65535)
294 			dthistime = 0;
295 		if (dthistime) {
296 			assert(smbbufferalignl2(ob, 0));
297 			assert(smbbufferoffsetputs(ob, countsfixupoffset + 4, dthistime));
298 			assert(smbbufferoffsetputs(ob, countsfixupoffset + 6, smbbufferwriteoffset(ob)));
299 			assert(smbbufferputbytes(ob, t->in.data + t->in.dcount, dthistime));
300 		}
301 		t->in.dcount += dthistime;
302 	}
303 	*bytecountp = smbbufferwriteoffset(ob) - bytecountfixupoffset - 2;
304 	assert(smbbufferoffsetputs(ob, bytecountfixupoffset, *bytecountp));
305 	return 1;
306 }
307 
308 int
smbtransactionencodeprimary(SmbTransaction * t,SmbHeader * h,SmbPeerInfo * p,SmbBuffer * ob,uchar * wordcountp,ushort * bytecountp,char ** errmsgp)309 smbtransactionencodeprimary(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob,
310 	uchar *wordcountp, ushort *bytecountp, char **errmsgp)
311 {
312 	return _transactionencodeprimary(t, SMB_COM_TRANSACTION, h, p,ob, wordcountp, bytecountp, errmsgp);
313 };
314 
315 int
smbtransactionencodeprimary2(SmbTransaction * t,SmbHeader * h,SmbPeerInfo * p,SmbBuffer * ob,uchar * wordcountp,ushort * bytecountp,char ** errmsgp)316 smbtransactionencodeprimary2(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob,
317 	uchar *wordcountp, ushort *bytecountp, char **errmsgp)
318 {
319 	return _transactionencodeprimary(t, SMB_COM_TRANSACTION2, h, p,ob, wordcountp, bytecountp, errmsgp);
320 };
321 
322 int
_transactionencoderesponse(SmbTransaction * t,SmbHeader * h,SmbPeerInfo * p,SmbBuffer * ob,uchar cmd,char ** errmsgp)323 _transactionencoderesponse(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, uchar cmd,
324 	char **errmsgp)
325 {
326 	SmbHeader mh;
327 	ulong countsfixupoffset, bytecountfixupoffset;
328 	int palign, dalign;
329 	ulong pbytecount, dbytecount;
330 	ulong poffset, doffset;
331 
332 	if (t->in.maxpcount > 65535 || t->in.maxdcount > 65535) {
333 		smbstringprint(errmsgp, "counts too big");
334 		return 0;
335 	}
336 	mh = *h;
337 	mh.wordcount = 10;
338 	mh.flags &= ~SMB_FLAGS_SERVER_TO_REDIR;
339 	mh.command = cmd;
340 	mh.errclass = SUCCESS;
341 	mh.error = SUCCESS;
342 	if (!smbbufferputheader(ob, &mh, p)
343 		|| !smbbufferputs(ob, smbbufferwriteoffset(t->out.parameters))
344 		|| !smbbufferputs(ob, smbbufferwriteoffset(t->out.data))
345 		|| !smbbufferputs(ob, 0)) {
346 	toosmall:
347 		smbstringprint(errmsgp, "output buffer too small");
348 		goto toosmall;
349 	}
350 	countsfixupoffset = smbbufferwriteoffset(ob);
351 	if (!smbbufferputbytes(ob, nil, 6 * sizeof(ushort))
352 		|| !smbbufferputb(ob, 0)	// scount == 0
353 		|| !smbbufferputb(ob, 0))	// reserved2
354 		goto toosmall;
355 	/* now the byte count */
356 	bytecountfixupoffset = smbbufferwriteoffset(ob);
357 	if (!smbbufferputs(ob, 0))
358 		goto toosmall;
359 	smbbufferwritelimit(ob, smbbufferwriteoffset(ob) + 65535);
360 	palign = bytecountfixupoffset & 1;
361 	if (palign && !smbbufferputb(ob, 0))
362 		goto toosmall;
363 	pbytecount = smbbufferreadspace(t->out.parameters);
364 	if (pbytecount > smbbufferwritespace(ob))
365 		pbytecount = smbbufferwritespace(ob);
366 	poffset = smbbufferwriteoffset(ob);
367 	if (poffset > 65535)
368 		goto toosmall;
369 	if (!smbbufferputbytes(ob, smbbufferreadpointer(t->out.parameters), pbytecount))
370 		goto toosmall;
371 	dalign = smbbufferwritespace(ob) > 0 && (smbbufferwriteoffset(ob) & 1) != 0;
372 	if (dalign && !smbbufferputb(ob, 0))
373 		goto toosmall;
374 	dbytecount = smbbufferreadspace(t->out.data);
375 	if (dbytecount > smbbufferwritespace(ob))
376 		dbytecount = smbbufferwritespace(ob);
377 	doffset = smbbufferwriteoffset(ob);
378 	if (doffset > 65535)
379 		goto toosmall;
380 	if (!smbbufferputbytes(ob, smbbufferreadpointer(t->out.data), dbytecount))
381 		goto toosmall;
382 	if (!smbbufferoffsetputs(ob, bytecountfixupoffset, palign + pbytecount + dalign + dbytecount)
383 		|| !smbbufferoffsetputs(ob, countsfixupoffset, pbytecount)
384 		|| !smbbufferoffsetputs(ob, countsfixupoffset + 2, poffset)
385 		|| !smbbufferoffsetputs(ob, countsfixupoffset + 4, smbbufferreadoffset(t->out.parameters))
386 		|| !smbbufferoffsetputs(ob, countsfixupoffset + 6, dbytecount)
387 		|| !smbbufferoffsetputs(ob, countsfixupoffset + 8, doffset)
388 		|| !smbbufferoffsetputs(ob, countsfixupoffset + 10, smbbufferreadoffset(t->out.data)))
389 		goto toosmall;
390 	assert(smbbufferoffsetputs(ob, bytecountfixupoffset, smbbufferwriteoffset(ob) - bytecountfixupoffset - 2));
391 	smbbuffergetbytes(t->out.parameters, nil, pbytecount);
392 	smbbuffergetbytes(t->out.data, nil, dbytecount);
393 	return 1;
394 }
395 
396 int
smbtransactionencoderesponse(SmbTransaction * t,SmbHeader * h,SmbPeerInfo * p,SmbBuffer * ob,char ** errmsgp)397 smbtransactionencoderesponse(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, char **errmsgp)
398 {
399 	return _transactionencoderesponse(t, h, p, ob, SMB_COM_TRANSACTION, errmsgp);
400 }
401 
402 int
smbtransactionencoderesponse2(SmbTransaction * t,SmbHeader * h,SmbPeerInfo * p,SmbBuffer * ob,char ** errmsgp)403 smbtransactionencoderesponse2(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, char **errmsgp)
404 {
405 	return _transactionencoderesponse(t, h, p, ob, SMB_COM_TRANSACTION2, errmsgp);
406 }
407 
408 int
smbtransactionrespond(SmbTransaction * t,SmbHeader * h,SmbPeerInfo * p,SmbBuffer * ob,SmbTransactionMethod * method,void * magic,char ** errmsgp)409 smbtransactionrespond(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, SmbTransactionMethod *method, void *magic, char **errmsgp)
410 {
411 	/* generate one or more responses */
412 	while (smbbufferreadspace(t->out.parameters) || smbbufferreadspace(t->out.data)) {
413 		assert(method->encoderesponse);
414 		if (!(*method->encoderesponse)(t, h, p, ob, errmsgp))
415 			return 0;
416 		assert(method->sendresponse);
417 		if (!(*method->sendresponse)(magic, ob, errmsgp))
418 			return 0;
419 	}
420 	return 1;
421 }
422 
423 int
smbtransactionnbdgramsend(void * magic,SmbBuffer * ob,char ** errmsgp)424 smbtransactionnbdgramsend(void *magic, SmbBuffer *ob, char **errmsgp)
425 {
426 	NbDgramSendParameters *p = magic;
427 //print("sending to %B\n", p->to);
428 //nbdumpdata(smbbufferreadpointer(ob), smbbufferreadspace(ob));
429 	if (!nbdgramsend(p, smbbufferreadpointer(ob), smbbufferreadspace(ob))) {
430 		smbstringprint(errmsgp, "dgram send failed");
431 		return 0;
432 	}
433 	return 1;
434 }
435 
436 SmbTransactionMethod smbtransactionmethoddgram = {
437 	.encodeprimary = smbtransactionencodeprimary,
438 	.sendrequest = smbtransactionnbdgramsend,
439 	.encoderesponse = smbtransactionencoderesponse,
440 };
441 
442 int
smbtransactionexecute(SmbTransaction * t,SmbHeader * h,SmbPeerInfo * p,SmbBuffer * iob,SmbTransactionMethod * method,void * magic,SmbHeader * rhp,char ** errmsgp)443 smbtransactionexecute(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *iob, SmbTransactionMethod *method, void *magic, SmbHeader *rhp, char **errmsgp)
444 {
445 	uchar sentwordcount;
446 	ushort sentbytecount;
447 	SmbHeader rh;
448 	smbbufferreset(iob);
449 	if (!(*method->encodeprimary)(t, h, p, iob, &sentwordcount, &sentbytecount, errmsgp))
450 		return 0;
451 //	smblogprint(-1, "sent...\n");
452 //	smblogdata(-1, smblogprint, smbbufferreadpointer(iob), smbbufferreadspace(iob));
453 	if (!(*method->sendrequest)(magic, iob, errmsgp))
454 		return 0;
455 	if (t->in.pcount < t->in.tpcount || t->in.dcount < t->in.tdcount) {
456 		uchar wordcount;
457 		ushort bytecount;
458 		/* secondary needed */
459 		if (method->encodesecondary == nil || method->receiveintermediate == nil) {
460 			smbstringprint(errmsgp, "buffer too small and secondaries not allowed");
461 			return 0;
462 		}
463 		if (!(*method->receiveintermediate)(magic, &wordcount, &bytecount, errmsgp))
464 			return 0;
465 		if (sentwordcount != wordcount || sentbytecount != bytecount) {
466 			smbstringprint(errmsgp, "server intermediate reply counts differ");
467 			return 0;
468 		}
469 		do {
470 			if (!(*method->encodesecondary)(t, h, iob, errmsgp))
471 				return 0;
472 			if (!(*method->sendrequest)(magic, iob, errmsgp))
473 				return 0;
474 		} while (t->in.pcount < t->in.tpcount || t->in.dcount < t->in.tdcount);
475 	}
476 	if (method->receiveresponse == nil || method->decoderesponse == nil)
477 		return 1;
478 	do {
479 		uchar *pdata;
480 		ushort bytecount;
481 
482 		if (!(*method->receiveresponse)(magic, iob, errmsgp))
483 			return 0;
484 		if (!smbbuffergetheader(iob, &rh, &pdata, &bytecount)) {
485 			smbstringprint(errmsgp, "smbtransactionexecute: invalid response header");
486 			return 0;
487 		}
488 		if (!smbcheckheaderdirection(&rh, 1, errmsgp))
489 			return 0;
490 		if (rh.errclass != SUCCESS) {
491 			smbstringprint(errmsgp, "smbtransactionexecute: remote error %d/%d", rh.errclass, rh.error);
492 			return 0;
493 		}
494 		if (!smbbuffertrimreadlen(iob, bytecount)) {
495 			smbstringprint(errmsgp, "smbtransactionexecute: invalid bytecount");
496 			return 0;
497 		}
498 //		smblogprint(-1, "received...\n");
499 //		smblogdata(-1, smblogprint, smbbufferreadpointer(iob), smbbufferreadspace(iob));
500 		if (!(*method->decoderesponse)(t, &rh, pdata, iob, errmsgp))
501 			return 0;
502 	} while (smbbufferwriteoffset(t->out.parameters) < t->out.tpcount || smbbufferwriteoffset(t->out.data) < t->out.tdcount);
503 	if (rhp)
504 		*rhp = rh;
505 	return 1;
506 }
507 
508