Merge branch 'vendor/LIBARCHIVE' into HEAD
[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 <string.h>
44 #include <strings.h>
45 #include <stdlib.h>
46 #include <sysexits.h>
47
48 #include <sys/mchain.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 = letohs(*(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 = letohs(*rp++);
324         conv = letohs(*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 = letohs(*(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 }