xref: /dragonfly/contrib/smbfs/lib/smb/rap.c (revision c69bf40f)
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  *
34  * This is very simple implementation of RAP protocol.
35  */
36 #include <sys/param.h>
37 #include <sys/errno.h>
38 #include <sys/stat.h>
39 #include <ctype.h>
40 #include <err.h>
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <strings.h>
45 #include <stdlib.h>
46 #include <sysexits.h>
47 
48 #include <sys/endian.h>
49 
50 #include <netsmb/smb_lib.h>
51 #include <netsmb/smb_conn.h>
52 #include <netsmb/smb_rap.h>
53 
54 /*#include <sys/ioctl.h>*/
55 
56 static int
57 smb_rap_parserqparam(const char *s, char **next, int *rlen)
58 {
59 	char *np;
60 	int len, m;
61 
62 	m = 1;
63 	switch (*s++) {
64 	    case 'L':
65 	    case 'T':
66 	    case 'W':
67 		len = 2;
68 		break;
69 	    case 'D':
70 	    case 'O':
71 		len = 4;
72 		break;
73 	    case 'b':
74 	    case 'F':
75 		len = 1;
76 		break;
77 	    case 'r':
78 	    case 's':
79 		len = 0;
80 		break;
81 	    default:
82 		return EINVAL;
83 	}
84 	if (isdigit(*s)) {
85 		len *= strtoul(s, &np, 10);
86 		s = np;
87 	}
88 	*rlen = len;
89 	*(const char**)next = s;
90 	return 0;
91 }
92 
93 static int
94 smb_rap_parserpparam(const char *s, char **next, int *rlen)
95 {
96 	char *np;
97 	int len, m;
98 
99 	m = 1;
100 	switch (*s++) {
101 	    case 'e':
102 	    case 'h':
103 		len = 2;
104 		break;
105 	    case 'i':
106 		len = 4;
107 		break;
108 	    case 'g':
109 		len = 1;
110 		break;
111 	    default:
112 		return EINVAL;
113 	}
114 	if (isdigit(*s)) {
115 		len *= strtoul(s, &np, 10);
116 		s = np;
117 	}
118 	*rlen = len;
119 	*(const char**)next = s;
120 	return 0;
121 }
122 
123 static int
124 smb_rap_parserpdata(const char *s, char **next, int *rlen)
125 {
126 	char *np;
127 	int len, m;
128 
129 	m = 1;
130 	switch (*s++) {
131 	    case 'B':
132 		len = 1;
133 		break;
134 	    case 'W':
135 		len = 2;
136 		break;
137 	    case 'D':
138 	    case 'O':
139 	    case 'z':
140 		len = 4;
141 		break;
142 	    default:
143 		return EINVAL;
144 	}
145 	if (isdigit(*s)) {
146 		len *= strtoul(s, &np, 10);
147 		s = np;
148 	}
149 	*rlen = len;
150 	*(const char**)next = s;
151 	return 0;
152 }
153 
154 static int
155 smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
156 {
157 	int len = strlen(value) + 1;
158 
159 	bcopy(value, rap->r_npbuf, len);
160 	rap->r_npbuf += len;
161 	rap->r_plen += len;
162 	return 0;
163 }
164 
165 static int
166 smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, long value)
167 {
168 	char *p = rap->r_npbuf;
169 	int len;
170 
171 	switch (ptype) {
172 	    case 'L':
173 	    case 'W':
174 		setwle(p, 0, value);
175 		len = 2;
176 		break;
177 	    case 'D':
178 		setdle(p, 0, value);
179 		len = 4;
180 		break;
181 	    case 'b':
182 		memset(p, value, plen);
183 		len = plen;
184 	    default:
185 		return EINVAL;
186 	}
187 	rap->r_npbuf += len;
188 	rap->r_plen += len;
189 	return 0;
190 }
191 
192 int
193 smb_rap_create(int fn, const char *param, const char *data,
194 	struct smb_rap **rapp)
195 {
196 	struct smb_rap *rap;
197 	char *p;
198 	int plen, len;
199 
200 	rap = malloc(sizeof(*rap));
201 	if (rap == NULL)
202 		return ENOMEM;
203 	bzero(rap, sizeof(*rap));
204 	p = rap->r_sparam = rap->r_nparam = strdup(param);
205 	rap->r_sdata = rap->r_ndata = strdup(data);
206 	/*
207 	 * Calculate length of request parameter block
208 	 */
209 	len = 2 + strlen(param) + 1 + strlen(data) + 1;
210 
211 	while (*p) {
212 		if (smb_rap_parserqparam(p, &p, &plen) != 0)
213 			break;
214 		len += plen;
215 	}
216 	rap->r_pbuf = rap->r_npbuf = malloc(len);
217 	smb_rap_rqparam(rap, 'W', 1, fn);
218 	smb_rap_rqparam_z(rap, rap->r_sparam);
219 	smb_rap_rqparam_z(rap, rap->r_sdata);
220 	*rapp = rap;
221 	return 0;
222 }
223 
224 void
225 smb_rap_done(struct smb_rap *rap)
226 {
227 	if (rap->r_sparam)
228 		free(rap->r_sparam);
229 	if (rap->r_sdata)
230 		free(rap->r_sdata);
231 	free(rap);
232 }
233 
234 int
235 smb_rap_setNparam(struct smb_rap *rap, long value)
236 {
237 	char *p = rap->r_nparam;
238 	char ptype = *p;
239 	int error, plen;
240 
241 	error = smb_rap_parserqparam(p, &p, &plen);
242 	if (error)
243 		return error;
244 	switch (ptype) {
245 	    case 'L':
246 		rap->r_rcvbuflen = value;
247 		/* FALLTHROUGH */
248 	    case 'W':
249 	    case 'D':
250 	    case 'b':
251 		error = smb_rap_rqparam(rap, ptype, plen, value);
252 		break;
253 	    default:
254 		return EINVAL;
255 	}
256 	rap->r_nparam = p;
257 	return 0;
258 }
259 
260 int
261 smb_rap_setPparam(struct smb_rap *rap, void *value)
262 {
263 	char *p = rap->r_nparam;
264 	char ptype = *p;
265 	int error, plen;
266 
267 	error = smb_rap_parserqparam(p, &p, &plen);
268 	if (error)
269 		return error;
270 	switch (ptype) {
271 	    case 'r':
272 		rap->r_rcvbuf = value;
273 		break;
274 	    default:
275 		return EINVAL;
276 	}
277 	rap->r_nparam = p;
278 	return 0;
279 }
280 
281 static int
282 smb_rap_getNparam(struct smb_rap *rap, long *value)
283 {
284 	char *p = rap->r_nparam;
285 	char ptype = *p;
286 	int error, plen;
287 
288 	error = smb_rap_parserpparam(p, &p, &plen);
289 	if (error)
290 		return error;
291 	switch (ptype) {
292 	    case 'h':
293 		*value = le16toh(*(u_int16_t*)rap->r_npbuf);
294 		break;
295 	    default:
296 		return EINVAL;
297 	}
298 	rap->r_npbuf += plen;
299 	rap->r_nparam = p;
300 	return 0;
301 }
302 
303 int
304 smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
305 {
306 	u_int16_t *rp, conv;
307 	u_int32_t *p32;
308 	char *dp, *p = rap->r_nparam;
309 	char ptype;
310 	int error, rdatacnt, rparamcnt, entries, done, dlen;
311 
312 	rdatacnt = rap->r_rcvbuflen;
313 	rparamcnt = rap->r_plen;
314 	error = smb_t2_request(ctx, 0, 0, "\\PIPE\\LANMAN",
315 	    rap->r_plen, rap->r_pbuf,		/* int tparamcnt, void *tparam */
316 	    0, NULL,				/* int tdatacnt, void *tdata */
317 	    &rparamcnt, rap->r_pbuf,		/* rparamcnt, void *rparam */
318 	    &rdatacnt, rap->r_rcvbuf		/* int *rdatacnt, void *rdata */
319 	);
320 	if (error)
321 		return error;
322 	rp = (u_int16_t*)rap->r_pbuf;
323 	rap->r_result = le16toh(*rp++);
324 	conv = le16toh(*rp++);
325 	rap->r_npbuf = (char*)rp;
326 	rap->r_entries = entries = 0;
327 	done = 0;
328 	while (!done && *p) {
329 		ptype = *p;
330 		switch (ptype) {
331 		    case 'e':
332 			rap->r_entries = entries = le16toh(*(u_int16_t*)rap->r_npbuf);
333 			rap->r_npbuf += 2;
334 			p++;
335 			break;
336 		    default:
337 			done = 1;
338 		}
339 /*		error = smb_rap_parserpparam(p, &p, &plen);
340 		if (error) {
341 			smb_error("reply parameter mismath %s", 0, p);
342 			return EBADRPC;
343 		}*/
344 	}
345 	rap->r_nparam = p;
346 	/*
347 	 * In general, unpacking entries we may need to relocate
348 	 * entries for proper alingning. For now use them as is.
349 	 */
350 	dp = rap->r_rcvbuf;
351 	while (entries--) {
352 		p = rap->r_sdata;
353 		while (*p) {
354 			ptype = *p;
355 			error = smb_rap_parserpdata(p, &p, &dlen);
356 			if (error) {
357 				smb_error("reply data mismath %s", 0, p);
358 				return EBADRPC;
359 			}
360 			switch (ptype) {
361 			    case 'z':
362 				p32 = (u_int32_t*)dp;
363 				*p32 = (*p32 & 0xffff) - conv;
364 				break;
365 			}
366 			dp += dlen;
367 		}
368 	}
369 	return error;
370 }
371 
372 int
373 smb_rap_error(struct smb_rap *rap, int error)
374 {
375 	if (error)
376 		return error;
377 	if (rap->r_result == 0)
378 		return 0;
379 	return rap->r_result | SMB_RAP_ERROR;
380 }
381 
382 int
383 smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
384 	int cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
385 {
386 	struct smb_rap *rap;
387 	long lval;
388 	int error;
389 
390 	error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
391 	if (error)
392 		return error;
393 	smb_rap_setNparam(rap, sLevel);		/* W - sLevel */
394 	smb_rap_setPparam(rap, pbBuffer);	/* r - pbBuffer */
395 	smb_rap_setNparam(rap, cbBuffer);	/* L - cbBuffer */
396 	error = smb_rap_request(rap, ctx);
397 	if (error == 0) {
398 		*pcEntriesRead = rap->r_entries;
399 		error = smb_rap_getNparam(rap, &lval);
400 		*pcTotalAvail = lval;
401 	}
402 	error = smb_rap_error(rap, error);
403 	smb_rap_done(rap);
404 	return error;
405 }
406