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
smb_rap_parserqparam(const char * s,char ** next,int * rlen)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
smb_rap_parserpparam(const char * s,char ** next,int * rlen)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
smb_rap_parserpdata(const char * s,char ** next,int * rlen)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
smb_rap_rqparam_z(struct smb_rap * rap,const char * value)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
smb_rap_rqparam(struct smb_rap * rap,char ptype,char plen,long value)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
smb_rap_create(int fn,const char * param,const char * data,struct smb_rap ** rapp)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
smb_rap_done(struct smb_rap * rap)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
smb_rap_setNparam(struct smb_rap * rap,long value)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
smb_rap_setPparam(struct smb_rap * rap,void * value)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
smb_rap_getNparam(struct smb_rap * rap,long * value)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
smb_rap_request(struct smb_rap * rap,struct smb_ctx * ctx)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
smb_rap_error(struct smb_rap * rap,int error)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
smb_rap_NetShareEnum(struct smb_ctx * ctx,int sLevel,void * pbBuffer,int cbBuffer,int * pcEntriesRead,int * pcTotalAvail)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