xref: /onnv-gate/usr/src/lib/libsmbfs/smb/rap.c (revision 6007:d57e38e8fdd1)
1*6007Sthurlow /*
2*6007Sthurlow  * Copyright (c) 2000, Boris Popov
3*6007Sthurlow  * All rights reserved.
4*6007Sthurlow  *
5*6007Sthurlow  * Redistribution and use in source and binary forms, with or without
6*6007Sthurlow  * modification, are permitted provided that the following conditions
7*6007Sthurlow  * are met:
8*6007Sthurlow  * 1. Redistributions of source code must retain the above copyright
9*6007Sthurlow  *    notice, this list of conditions and the following disclaimer.
10*6007Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
11*6007Sthurlow  *    notice, this list of conditions and the following disclaimer in the
12*6007Sthurlow  *    documentation and/or other materials provided with the distribution.
13*6007Sthurlow  * 3. All advertising materials mentioning features or use of this software
14*6007Sthurlow  *    must display the following acknowledgement:
15*6007Sthurlow  *    This product includes software developed by Boris Popov.
16*6007Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
17*6007Sthurlow  *    may be used to endorse or promote products derived from this software
18*6007Sthurlow  *    without specific prior written permission.
19*6007Sthurlow  *
20*6007Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21*6007Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*6007Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*6007Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24*6007Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*6007Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*6007Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*6007Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*6007Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*6007Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*6007Sthurlow  * SUCH DAMAGE.
31*6007Sthurlow  *
32*6007Sthurlow  * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $
33*6007Sthurlow  *
34*6007Sthurlow  * This is very simple implementation of RAP protocol.
35*6007Sthurlow  */
36*6007Sthurlow 
37*6007Sthurlow #pragma ident	"%Z%%M%	%I%	%E% SMI"
38*6007Sthurlow 
39*6007Sthurlow #include <sys/param.h>
40*6007Sthurlow #include <sys/errno.h>
41*6007Sthurlow #include <sys/stat.h>
42*6007Sthurlow #include <sys/isa_defs.h>
43*6007Sthurlow 
44*6007Sthurlow #include <ctype.h>
45*6007Sthurlow #include <stdio.h>
46*6007Sthurlow #include <unistd.h>
47*6007Sthurlow #include <strings.h>
48*6007Sthurlow #include <stdlib.h>
49*6007Sthurlow #include <libintl.h>
50*6007Sthurlow #include <sysexits.h>
51*6007Sthurlow 
52*6007Sthurlow #include <netsmb/mchain.h>
53*6007Sthurlow #include <netsmb/smb_lib.h>
54*6007Sthurlow #include <netsmb/smb_rap.h>
55*6007Sthurlow 
56*6007Sthurlow static int
57*6007Sthurlow smb_rap_parserqparam(const char *s, char **next, int *rlen)
58*6007Sthurlow {
59*6007Sthurlow 	char *np;
60*6007Sthurlow 	int len;
61*6007Sthurlow 
62*6007Sthurlow 	switch (*s++) {
63*6007Sthurlow 	case 'L':
64*6007Sthurlow 	case 'T':
65*6007Sthurlow 	case 'W':
66*6007Sthurlow 		len = 2;
67*6007Sthurlow 		break;
68*6007Sthurlow 	case 'D':
69*6007Sthurlow 	case 'O':
70*6007Sthurlow 		len = 4;
71*6007Sthurlow 		break;
72*6007Sthurlow 	case 'b':
73*6007Sthurlow 	case 'F':
74*6007Sthurlow 		len = 1;
75*6007Sthurlow 		break;
76*6007Sthurlow 	case 'r':
77*6007Sthurlow 	case 's':
78*6007Sthurlow 		len = 0;
79*6007Sthurlow 		break;
80*6007Sthurlow 	default:
81*6007Sthurlow 		return (EINVAL);
82*6007Sthurlow 	}
83*6007Sthurlow 	if (isdigit(*s)) {
84*6007Sthurlow 		len *= strtoul(s, &np, 10);
85*6007Sthurlow 		s = np;
86*6007Sthurlow 	}
87*6007Sthurlow 	*rlen = len;
88*6007Sthurlow 	*(const char **)next = s;
89*6007Sthurlow 	return (0);
90*6007Sthurlow }
91*6007Sthurlow 
92*6007Sthurlow static int
93*6007Sthurlow smb_rap_parserpparam(const char *s, char **next, int *rlen)
94*6007Sthurlow {
95*6007Sthurlow 	char *np;
96*6007Sthurlow 	int len = 0;
97*6007Sthurlow 
98*6007Sthurlow 	switch (*s++) {
99*6007Sthurlow 	case 'e':
100*6007Sthurlow 	case 'h':
101*6007Sthurlow 		len = 2;
102*6007Sthurlow 		break;
103*6007Sthurlow 	case 'i':
104*6007Sthurlow 		len = 4;
105*6007Sthurlow 		break;
106*6007Sthurlow 	case 'g':
107*6007Sthurlow 		len = 1;
108*6007Sthurlow 		break;
109*6007Sthurlow 	default:
110*6007Sthurlow 		return (EINVAL);
111*6007Sthurlow 	}
112*6007Sthurlow 	if (isdigit(*s)) {
113*6007Sthurlow 		len *= strtoul(s, &np, 10);
114*6007Sthurlow 		s = np;
115*6007Sthurlow 	}
116*6007Sthurlow 	*rlen = len;
117*6007Sthurlow 	*(const char **)next = s;
118*6007Sthurlow 	return (0);
119*6007Sthurlow }
120*6007Sthurlow 
121*6007Sthurlow static int
122*6007Sthurlow smb_rap_parserpdata(const char *s, char **next, int *rlen)
123*6007Sthurlow {
124*6007Sthurlow 	char *np;
125*6007Sthurlow 	int len;
126*6007Sthurlow 
127*6007Sthurlow 	switch (*s++) {
128*6007Sthurlow 	case 'B':
129*6007Sthurlow 		len = 1;
130*6007Sthurlow 		break;
131*6007Sthurlow 	case 'W':
132*6007Sthurlow 		len = 2;
133*6007Sthurlow 		break;
134*6007Sthurlow 	case 'D':
135*6007Sthurlow 	case 'O':
136*6007Sthurlow 	case 'z':
137*6007Sthurlow 		len = 4;
138*6007Sthurlow 		break;
139*6007Sthurlow 	default:
140*6007Sthurlow 		return (EINVAL);
141*6007Sthurlow 	}
142*6007Sthurlow 	if (isdigit(*s)) {
143*6007Sthurlow 		len *= strtoul(s, &np, 10);
144*6007Sthurlow 		s = np;
145*6007Sthurlow 	}
146*6007Sthurlow 	*rlen = len;
147*6007Sthurlow 	*(const char **)next = s;
148*6007Sthurlow 	return (0);
149*6007Sthurlow }
150*6007Sthurlow 
151*6007Sthurlow static int
152*6007Sthurlow smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
153*6007Sthurlow {
154*6007Sthurlow 	int len = strlen(value) + 1;
155*6007Sthurlow 
156*6007Sthurlow 	bcopy(value, rap->r_npbuf, len);
157*6007Sthurlow 	rap->r_npbuf += len;
158*6007Sthurlow 	rap->r_plen += len;
159*6007Sthurlow 	return (0);
160*6007Sthurlow }
161*6007Sthurlow 
162*6007Sthurlow /*
163*6007Sthurlow  * Marshal RAP request parameters.
164*6007Sthurlow  * Note: value is in host order.
165*6007Sthurlow  */
166*6007Sthurlow static int
167*6007Sthurlow smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
168*6007Sthurlow {
169*6007Sthurlow 	char *p = rap->r_npbuf;
170*6007Sthurlow 	int len = 0;
171*6007Sthurlow 	uint_t uv = (uint_t)value;
172*6007Sthurlow 
173*6007Sthurlow 	switch (ptype) {
174*6007Sthurlow 	case 'L':
175*6007Sthurlow 	case 'W':
176*6007Sthurlow 		/* LINTED */
177*6007Sthurlow 		setwle(p, 0, uv);
178*6007Sthurlow 		len = 2;
179*6007Sthurlow 		break;
180*6007Sthurlow 	case 'D':
181*6007Sthurlow 		/* LINTED */
182*6007Sthurlow 		setdle(p, 0, uv);
183*6007Sthurlow 		len = 4;
184*6007Sthurlow 		break;
185*6007Sthurlow 	case 'b':
186*6007Sthurlow 		memset(p, uv, plen);
187*6007Sthurlow 		len = plen;
188*6007Sthurlow 	default:
189*6007Sthurlow 		return (EINVAL);
190*6007Sthurlow 	}
191*6007Sthurlow 	rap->r_npbuf += len;
192*6007Sthurlow 	rap->r_plen += len;
193*6007Sthurlow 	return (0);
194*6007Sthurlow }
195*6007Sthurlow 
196*6007Sthurlow int
197*6007Sthurlow smb_rap_create(int fn, const char *param, const char *data,
198*6007Sthurlow 	struct smb_rap **rapp)
199*6007Sthurlow {
200*6007Sthurlow 	struct smb_rap *rap;
201*6007Sthurlow 	char *p;
202*6007Sthurlow 	int plen = 0, len = 0;
203*6007Sthurlow 	int i;
204*6007Sthurlow 
205*6007Sthurlow 	rap = malloc(sizeof (*rap));
206*6007Sthurlow 	if (rap == NULL)
207*6007Sthurlow 		return (ENOMEM);
208*6007Sthurlow 	bzero(rap, sizeof (*rap));
209*6007Sthurlow 	p = rap->r_sparam = rap->r_nparam = strdup(param);
210*6007Sthurlow 	rap->r_sdata = rap->r_ndata = strdup(data);
211*6007Sthurlow 
212*6007Sthurlow 	/*
213*6007Sthurlow 	 * Calculate length of request parameter block
214*6007Sthurlow 	 */
215*6007Sthurlow 	len = 2 + strlen(param) + 1 + strlen(data) + 1;
216*6007Sthurlow 	while (*p) {
217*6007Sthurlow 		if (smb_rap_parserqparam(p, &p, &plen) != 0)
218*6007Sthurlow 			break;
219*6007Sthurlow 		len += plen;
220*6007Sthurlow 	}
221*6007Sthurlow 	rap->r_pbuf = rap->r_npbuf = malloc(len);
222*6007Sthurlow 	smb_rap_rqparam(rap, 'W', 1, fn);
223*6007Sthurlow 	smb_rap_rqparam_z(rap, rap->r_sparam);
224*6007Sthurlow 	smb_rap_rqparam_z(rap, rap->r_sdata);
225*6007Sthurlow 	*rapp = rap;
226*6007Sthurlow 	return (0);
227*6007Sthurlow }
228*6007Sthurlow 
229*6007Sthurlow void
230*6007Sthurlow smb_rap_done(struct smb_rap *rap)
231*6007Sthurlow {
232*6007Sthurlow 	if (rap->r_sparam)
233*6007Sthurlow 		free(rap->r_sparam);
234*6007Sthurlow 	if (rap->r_sdata)
235*6007Sthurlow 		free(rap->r_sdata);
236*6007Sthurlow 	if (rap->r_pbuf)
237*6007Sthurlow 		free(rap->r_pbuf);
238*6007Sthurlow #ifdef NOTYETDEFINED
239*6007Sthurlow 	if (rap->r_npbuf)
240*6007Sthurlow 		free(rap->r_npbuf);
241*6007Sthurlow 	if (rap->r_dbuf)
242*6007Sthurlow 		free(rap->r_dbuf);
243*6007Sthurlow 	if (rap->r_rcvbuf)
244*6007Sthurlow 		free(rap->r_rcvbuf);
245*6007Sthurlow #endif
246*6007Sthurlow 	free(rap);
247*6007Sthurlow }
248*6007Sthurlow 
249*6007Sthurlow int
250*6007Sthurlow smb_rap_setNparam(struct smb_rap *rap, int value)
251*6007Sthurlow {
252*6007Sthurlow 	char *p = rap->r_nparam;
253*6007Sthurlow 	char ptype = *p;
254*6007Sthurlow 	int error, plen;
255*6007Sthurlow 
256*6007Sthurlow 	error = smb_rap_parserqparam(p, &p, &plen);
257*6007Sthurlow 	if (error)
258*6007Sthurlow 		return (error);
259*6007Sthurlow 	switch (ptype) {
260*6007Sthurlow 	case 'L':
261*6007Sthurlow 		rap->r_rcvbuflen = value;
262*6007Sthurlow 		/* FALLTHROUGH */
263*6007Sthurlow 	case 'W':
264*6007Sthurlow 	case 'D':
265*6007Sthurlow 	case 'b':
266*6007Sthurlow 		error = smb_rap_rqparam(rap, ptype, plen, value);
267*6007Sthurlow 		break;
268*6007Sthurlow 	default:
269*6007Sthurlow 		return (EINVAL);
270*6007Sthurlow 	}
271*6007Sthurlow 	rap->r_nparam = p;
272*6007Sthurlow 	return (0);
273*6007Sthurlow }
274*6007Sthurlow 
275*6007Sthurlow int
276*6007Sthurlow smb_rap_setPparam(struct smb_rap *rap, void *value)
277*6007Sthurlow {
278*6007Sthurlow 	char *p = rap->r_nparam;
279*6007Sthurlow 	char ptype = *p;
280*6007Sthurlow 	int error, plen;
281*6007Sthurlow 
282*6007Sthurlow 	error = smb_rap_parserqparam(p, &p, &plen);
283*6007Sthurlow 	if (error)
284*6007Sthurlow 		return (error);
285*6007Sthurlow 	switch (ptype) {
286*6007Sthurlow 	case 'r':
287*6007Sthurlow 		rap->r_rcvbuf = value;
288*6007Sthurlow 		break;
289*6007Sthurlow 	default:
290*6007Sthurlow 		return (EINVAL);
291*6007Sthurlow 	}
292*6007Sthurlow 	rap->r_nparam = p;
293*6007Sthurlow 	return (0);
294*6007Sthurlow }
295*6007Sthurlow 
296*6007Sthurlow static int
297*6007Sthurlow smb_rap_getNparam(struct smb_rap *rap, long *value)
298*6007Sthurlow {
299*6007Sthurlow 	char *p = rap->r_nparam;
300*6007Sthurlow 	char ptype = *p;
301*6007Sthurlow 	int error, plen;
302*6007Sthurlow 	uint16_t	*te;
303*6007Sthurlow 
304*6007Sthurlow 	error = smb_rap_parserpparam(p, &p, &plen);
305*6007Sthurlow 	if (error)
306*6007Sthurlow 		return (error);
307*6007Sthurlow 	switch (ptype) {
308*6007Sthurlow 	case 'h':
309*6007Sthurlow 		/* LINTED */
310*6007Sthurlow 		te = (uint16_t *)rap->r_npbuf;
311*6007Sthurlow 		*value = letohs(*te);
312*6007Sthurlow 		break;
313*6007Sthurlow 	default:
314*6007Sthurlow 		return (EINVAL);
315*6007Sthurlow 	}
316*6007Sthurlow 	rap->r_npbuf += plen;
317*6007Sthurlow 	rap->r_nparam = p;
318*6007Sthurlow 	return (0);
319*6007Sthurlow }
320*6007Sthurlow 
321*6007Sthurlow int
322*6007Sthurlow smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
323*6007Sthurlow {
324*6007Sthurlow 	uint16_t *rp, conv, *tmp;
325*6007Sthurlow 	uint32_t *p32, ps1;
326*6007Sthurlow 	char *dp, *p = rap->r_nparam;
327*6007Sthurlow 	char ptype;
328*6007Sthurlow 	int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow, i;
329*6007Sthurlow 
330*6007Sthurlow 	rdatacnt = rap->r_rcvbuflen;
331*6007Sthurlow 	rparamcnt = rap->r_plen;
332*6007Sthurlow 	error = smb_t2_request(ctx, 0, NULL, "\\PIPE\\LANMAN",
333*6007Sthurlow 	    rap->r_plen, rap->r_pbuf,		/* int tparamcnt,void *tparam */
334*6007Sthurlow 	    0, NULL,				/* int tdatacnt, void *tdata */
335*6007Sthurlow 	    &rparamcnt, rap->r_pbuf,		/* rparamcnt, void *rparam */
336*6007Sthurlow 	    &rdatacnt, rap->r_rcvbuf,		/* int *rdatacnt, void *rdata */
337*6007Sthurlow 	    &buffer_oflow);
338*6007Sthurlow 	if (error)
339*6007Sthurlow 		return (error);
340*6007Sthurlow 
341*6007Sthurlow 	/* LINTED */
342*6007Sthurlow 	rp = (uint16_t *)rap->r_pbuf;
343*6007Sthurlow 
344*6007Sthurlow 	/*
345*6007Sthurlow 	 * Note: First is a "LanMan API" error code.
346*6007Sthurlow 	 * See: usr/src/uts/common/smbsrv/lmerr.h
347*6007Sthurlow 	 */
348*6007Sthurlow 	if (rparamcnt < 2)
349*6007Sthurlow 		return (EBADRPC);
350*6007Sthurlow 	rap->r_result = letohs(*rp);
351*6007Sthurlow 	rp++; rparamcnt -= 2;
352*6007Sthurlow 
353*6007Sthurlow 	if (rap->r_result != 0) {
354*6007Sthurlow 		/*
355*6007Sthurlow 		 * Could also return zero and let the caller
356*6007Sthurlow 		 * come get r_result via smb_rap_error(),
357*6007Sthurlow 		 * but in case they dont...
358*6007Sthurlow 		 */
359*6007Sthurlow 		return (rap->r_result | SMB_RAP_ERROR);
360*6007Sthurlow 	}
361*6007Sthurlow 
362*6007Sthurlow 	if (rparamcnt < 2)
363*6007Sthurlow 		return (EBADRPC);
364*6007Sthurlow 	conv = letohs(*rp);
365*6007Sthurlow 	rp++; rparamcnt -= 2;
366*6007Sthurlow 
367*6007Sthurlow 	rap->r_npbuf = (char *)rp;
368*6007Sthurlow 	rap->r_entries = entries = 0;
369*6007Sthurlow 	/* Save the returned data length */
370*6007Sthurlow 	rap->r_rcvbuflen = rdatacnt;
371*6007Sthurlow 	done = 0;
372*6007Sthurlow 
373*6007Sthurlow 	while (!done && *p) {
374*6007Sthurlow 		ptype = *p;
375*6007Sthurlow 		switch (ptype) {
376*6007Sthurlow 		case 'e':
377*6007Sthurlow 			if (rparamcnt < 2)
378*6007Sthurlow 				return (EBADRPC);
379*6007Sthurlow 			/* LINTED */
380*6007Sthurlow 			tmp = (uint16_t *)rap->r_npbuf;
381*6007Sthurlow 			rap->r_entries = entries = letohs(*tmp);
382*6007Sthurlow 			rap->r_npbuf += 2;
383*6007Sthurlow 			rparamcnt -= 2;
384*6007Sthurlow 			p++;
385*6007Sthurlow 			break;
386*6007Sthurlow 		default:
387*6007Sthurlow 			done = 1;
388*6007Sthurlow 		}
389*6007Sthurlow #if 0	/* commented out in Darwin. Why? */
390*6007Sthurlow 		error = smb_rap_parserpparam(p, &p, &plen);
391*6007Sthurlow 		if (error) {
392*6007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
393*6007Sthurlow 			    "reply parameter mismatch %s"), 0, p);
394*6007Sthurlow 			return (EBADRPC);
395*6007Sthurlow 		}
396*6007Sthurlow #endif
397*6007Sthurlow 	}
398*6007Sthurlow 	rap->r_nparam = p;
399*6007Sthurlow 	/*
400*6007Sthurlow 	 * In general, unpacking entries we may need to relocate
401*6007Sthurlow 	 * entries for proper aligning. For now use them as is.
402*6007Sthurlow 	 */
403*6007Sthurlow 	dp = rap->r_rcvbuf;
404*6007Sthurlow 	while (entries--) {
405*6007Sthurlow 		p = rap->r_sdata;
406*6007Sthurlow 		while (*p) {
407*6007Sthurlow 			ptype = *p;
408*6007Sthurlow 			error = smb_rap_parserpdata(p, &p, &dlen);
409*6007Sthurlow 			if (error) {
410*6007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
411*6007Sthurlow 				    "reply data mismatch %s"), 0, p);
412*6007Sthurlow 				return (EBADRPC);
413*6007Sthurlow 			}
414*6007Sthurlow 			if (rdatacnt < dlen)
415*6007Sthurlow 				return (EBADRPC);
416*6007Sthurlow 			switch (ptype) {
417*6007Sthurlow 			case 'z':
418*6007Sthurlow 				/* LINTED */
419*6007Sthurlow 				p32 = (uint32_t *)dp;
420*6007Sthurlow 				*p32 = (letohl(*p32) & 0xffff) - conv;
421*6007Sthurlow 				break;
422*6007Sthurlow 			}
423*6007Sthurlow 			dp += dlen;
424*6007Sthurlow 			rdatacnt -= dlen;
425*6007Sthurlow 		}
426*6007Sthurlow 	}
427*6007Sthurlow 	return (error);
428*6007Sthurlow }
429*6007Sthurlow 
430*6007Sthurlow int
431*6007Sthurlow smb_rap_error(struct smb_rap *rap, int error)
432*6007Sthurlow {
433*6007Sthurlow 	if (error)
434*6007Sthurlow 		return (error);
435*6007Sthurlow 	if (rap->r_result == 0)
436*6007Sthurlow 		return (0);
437*6007Sthurlow 	return (rap->r_result | SMB_RAP_ERROR);
438*6007Sthurlow }
439*6007Sthurlow 
440*6007Sthurlow /* todo: move this function to libnetapi */
441*6007Sthurlow int
442*6007Sthurlow smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
443*6007Sthurlow 	int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
444*6007Sthurlow {
445*6007Sthurlow 	struct smb_rap *rap;
446*6007Sthurlow 	long lval = -1;
447*6007Sthurlow 	int error;
448*6007Sthurlow 	char *pass;
449*6007Sthurlow 	int i;
450*6007Sthurlow 
451*6007Sthurlow 	error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
452*6007Sthurlow 	if (error)
453*6007Sthurlow 		return (error);
454*6007Sthurlow 	smb_rap_setNparam(rap, sLevel);		/* W - sLevel */
455*6007Sthurlow 	smb_rap_setPparam(rap, pbBuffer);	/* r - pbBuffer */
456*6007Sthurlow 	smb_rap_setNparam(rap, *cbBuffer);	/* L - cbBuffer */
457*6007Sthurlow 	error = smb_rap_request(rap, ctx);
458*6007Sthurlow 	if (error == 0) {
459*6007Sthurlow 		*pcEntriesRead = rap->r_entries;
460*6007Sthurlow 		error = smb_rap_getNparam(rap, &lval);
461*6007Sthurlow 		*pcTotalAvail = lval;
462*6007Sthurlow 		/* Copy the data length into the IN/OUT variable. */
463*6007Sthurlow 		*cbBuffer = rap->r_rcvbuflen;
464*6007Sthurlow 	}
465*6007Sthurlow 	error = smb_rap_error(rap, error);
466*6007Sthurlow 	smb_rap_done(rap);
467*6007Sthurlow 	return (error);
468*6007Sthurlow }
469