Merge from vendor branch TCPDUMP:
[dragonfly.git] / contrib / smbfs / lib / smb / rap.c
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 <strings.h>
44 #include <stdlib.h>
45 #include <sysexits.h>
46
47 #include <sys/mchain.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 NULL;
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 = letohs(*(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 = letohs(*rp++);
323         conv = letohs(*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 = letohs(*(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 }