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