Unbreak buildworld.
[dragonfly.git] / contrib / smbfs / lib / smb / rap.c
CommitLineData
984263bc
MD
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>
a276dc6b 43#include <string.h>
984263bc
MD
44#include <strings.h>
45#include <stdlib.h>
46#include <sysexits.h>
47
0ce716ae 48#include <sys/endian.h>
984263bc
MD
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
56static int
57smb_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
93static int
94smb_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
123static int
124smb_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
154static int
155smb_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
165static int
166smb_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
192int
193smb_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)
a276dc6b 202 return ENOMEM;
984263bc
MD
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
224void
225smb_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
234int
235smb_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
260int
261smb_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
281static int
282smb_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':
0ce716ae 293 *value = le16toh(*(u_int16_t*)rap->r_npbuf);
984263bc
MD
294 break;
295 default:
296 return EINVAL;
297 }
298 rap->r_npbuf += plen;
299 rap->r_nparam = p;
300 return 0;
301}
302
303int
304smb_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;
0ce716ae
SW
323 rap->r_result = le16toh(*rp++);
324 conv = le16toh(*rp++);
984263bc
MD
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':
0ce716ae 332 rap->r_entries = entries = le16toh(*(u_int16_t*)rap->r_npbuf);
984263bc
MD
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
372int
373smb_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
382int
383smb_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}