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.5 2004/12/13 00:25:23 lindak Exp $
33 *
34 * This is very simple implementation of RAP protocol.
35 */
36
37 #include <sys/param.h>
38 #include <sys/errno.h>
39 #include <sys/stat.h>
40 #include <sys/isa_defs.h>
41
42 #include <ctype.h>
43 #include <stdio.h>
44 #include <unistd.h>
45 #include <strings.h>
46 #include <stdlib.h>
47 #include <libintl.h>
48 #include <sysexits.h>
49
50 #include <netsmb/mchain.h>
51 #include <netsmb/smb_lib.h>
52 #include <netsmb/smb_rap.h>
53 #include "private.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;
60
61 switch (*s++) {
62 case 'L':
63 case 'T':
64 case 'W':
65 len = 2;
66 break;
67 case 'D':
68 case 'O':
69 len = 4;
70 break;
71 case 'b':
72 case 'F':
73 len = 1;
74 break;
75 case 'r':
76 case 's':
77 len = 0;
78 break;
79 default:
80 return (EINVAL);
81 }
82 if (isdigit(*s)) {
83 len *= strtoul(s, &np, 10);
84 s = np;
85 }
86 *rlen = len;
87 *(const char **)next = s;
88 return (0);
89 }
90
91 static int
smb_rap_parserpparam(const char * s,char ** next,int * rlen)92 smb_rap_parserpparam(const char *s, char **next, int *rlen)
93 {
94 char *np;
95 int len = 0;
96
97 switch (*s++) {
98 case 'e':
99 case 'h':
100 len = 2;
101 break;
102 case 'i':
103 len = 4;
104 break;
105 case 'g':
106 len = 1;
107 break;
108 default:
109 return (EINVAL);
110 }
111 if (isdigit(*s)) {
112 len *= strtoul(s, &np, 10);
113 s = np;
114 }
115 *rlen = len;
116 *(const char **)next = s;
117 return (0);
118 }
119
120 static int
smb_rap_parserpdata(const char * s,char ** next,int * rlen)121 smb_rap_parserpdata(const char *s, char **next, int *rlen)
122 {
123 char *np;
124 int len;
125
126 switch (*s++) {
127 case 'B':
128 len = 1;
129 break;
130 case 'W':
131 len = 2;
132 break;
133 case 'D':
134 case 'O':
135 case 'z':
136 len = 4;
137 break;
138 default:
139 return (EINVAL);
140 }
141 if (isdigit(*s)) {
142 len *= strtoul(s, &np, 10);
143 s = np;
144 }
145 *rlen = len;
146 *(const char **)next = s;
147 return (0);
148 }
149
150 static int
smb_rap_rqparam_z(struct smb_rap * rap,const char * value)151 smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
152 {
153 int len = strlen(value) + 1;
154
155 bcopy(value, rap->r_npbuf, len);
156 rap->r_npbuf += len;
157 rap->r_plen += len;
158 return (0);
159 }
160
161 /*
162 * Marshal RAP request parameters.
163 * Note: value is in host order.
164 */
165 static int
smb_rap_rqparam(struct smb_rap * rap,char ptype,char plen,int value)166 smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
167 {
168 int len = 0;
169 uint_t uv = (uint_t)value;
170 uint32_t *lp;
171 uint16_t *sp;
172 char *p;
173
174 switch (ptype) {
175 case 'L':
176 case 'W':
177 /* LINTED */
178 sp = (uint16_t *)rap->r_npbuf;
179 *sp = htoles(uv);
180 len = sizeof (*sp);
181 break;
182 case 'D':
183 /* LINTED */
184 lp = (uint32_t *)rap->r_npbuf;
185 *lp = htolel(uv);
186 len = sizeof (*lp);
187 break;
188 case 'b':
189 p = rap->r_npbuf;
190 memset(p, uv, plen);
191 len = plen;
192 default:
193 return (EINVAL);
194 }
195 rap->r_npbuf += len;
196 rap->r_plen += len;
197 return (0);
198 }
199
200 int
smb_rap_create(int fn,const char * param,const char * data,struct smb_rap ** rapp)201 smb_rap_create(int fn, const char *param, const char *data,
202 struct smb_rap **rapp)
203 {
204 struct smb_rap *rap;
205 char *p;
206 int plen = 0, len = 0;
207
208 rap = malloc(sizeof (*rap));
209 if (rap == NULL)
210 return (ENOMEM);
211 bzero(rap, sizeof (*rap));
212 p = rap->r_sparam = rap->r_nparam = strdup(param);
213 rap->r_sdata = rap->r_ndata = strdup(data);
214
215 /*
216 * Calculate length of request parameter block
217 */
218 len = 2 + strlen(param) + 1 + strlen(data) + 1;
219 while (*p) {
220 if (smb_rap_parserqparam(p, &p, &plen) != 0)
221 break;
222 len += plen;
223 }
224 rap->r_pbuf = rap->r_npbuf = malloc(len);
225 if (rap->r_pbuf == NULL)
226 return (ENOMEM);
227 (void) smb_rap_rqparam(rap, 'W', 1, fn);
228 (void) smb_rap_rqparam_z(rap, rap->r_sparam);
229 (void) smb_rap_rqparam_z(rap, rap->r_sdata);
230 *rapp = rap;
231 return (0);
232 }
233
234 void
smb_rap_done(struct smb_rap * rap)235 smb_rap_done(struct smb_rap *rap)
236 {
237 if (rap->r_sparam)
238 free(rap->r_sparam);
239 if (rap->r_sdata)
240 free(rap->r_sdata);
241 if (rap->r_pbuf)
242 free(rap->r_pbuf);
243 #ifdef NOTYETDEFINED
244 if (rap->r_npbuf)
245 free(rap->r_npbuf);
246 if (rap->r_dbuf)
247 free(rap->r_dbuf);
248 if (rap->r_rcvbuf)
249 free(rap->r_rcvbuf);
250 #endif
251 free(rap);
252 }
253
254 int
smb_rap_setNparam(struct smb_rap * rap,int value)255 smb_rap_setNparam(struct smb_rap *rap, int value)
256 {
257 char *p = rap->r_nparam;
258 char ptype = *p;
259 int error, plen;
260
261 error = smb_rap_parserqparam(p, &p, &plen);
262 if (error)
263 return (error);
264 switch (ptype) {
265 case 'L':
266 rap->r_rcvbuflen = value;
267 /* FALLTHROUGH */
268 case 'W':
269 case 'D':
270 case 'b':
271 error = smb_rap_rqparam(rap, ptype, plen, value);
272 break;
273 default:
274 return (EINVAL);
275 }
276 rap->r_nparam = p;
277 return (0);
278 }
279
280 int
smb_rap_setPparam(struct smb_rap * rap,void * value)281 smb_rap_setPparam(struct smb_rap *rap, void *value)
282 {
283 char *p = rap->r_nparam;
284 char ptype = *p;
285 int error, plen;
286
287 error = smb_rap_parserqparam(p, &p, &plen);
288 if (error)
289 return (error);
290 switch (ptype) {
291 case 'r':
292 rap->r_rcvbuf = value;
293 break;
294 default:
295 return (EINVAL);
296 }
297 rap->r_nparam = p;
298 return (0);
299 }
300
301 int
smb_rap_getNparam(struct smb_rap * rap,long * value)302 smb_rap_getNparam(struct smb_rap *rap, long *value)
303 {
304 char *p = rap->r_nparam;
305 char ptype = *p;
306 int error, plen;
307 uint16_t *te;
308
309 error = smb_rap_parserpparam(p, &p, &plen);
310 if (error)
311 return (error);
312 switch (ptype) {
313 case 'h':
314 /* LINTED */
315 te = (uint16_t *)rap->r_npbuf;
316 *value = letohs(*te);
317 break;
318 default:
319 return (EINVAL);
320 }
321 rap->r_npbuf += plen;
322 rap->r_nparam = p;
323 return (0);
324 }
325
326 int
smb_rap_request(struct smb_rap * rap,struct smb_ctx * ctx)327 smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
328 {
329 uint16_t *rp, conv, *tmp;
330 uint32_t *p32;
331 char *dp, *p = rap->r_nparam;
332 char ptype;
333 int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
334
335 rdatacnt = rap->r_rcvbuflen;
336 rparamcnt = rap->r_plen;
337 error = smb_t2_request(ctx, 0, NULL, "\\PIPE\\LANMAN",
338 rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */
339 0, NULL, /* int tdatacnt, void *tdata */
340 &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */
341 &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */
342 &buffer_oflow);
343 if (error)
344 return (error);
345
346 /* LINTED */
347 rp = (uint16_t *)rap->r_pbuf;
348
349 /*
350 * Note: First is a "LanMan API" error code.
351 * See: usr/src/uts/common/smbsrv/lmerr.h
352 */
353 if (rparamcnt < 2)
354 return (EBADRPC);
355 rap->r_result = letohs(*rp);
356 rp++; rparamcnt -= 2;
357
358 if (rap->r_result != 0) {
359 /*
360 * Could also return zero and let the caller
361 * come get r_result via smb_rap_error(),
362 * but in case they dont...
363 */
364 return (rap->r_result | SMB_RAP_ERROR);
365 }
366
367 if (rparamcnt < 2)
368 return (EBADRPC);
369 conv = letohs(*rp);
370 rp++; rparamcnt -= 2;
371
372 rap->r_npbuf = (char *)rp;
373 rap->r_entries = entries = 0;
374 /* Save the returned data length */
375 rap->r_rcvbuflen = rdatacnt;
376 done = 0;
377
378 while (!done && *p) {
379 ptype = *p;
380 switch (ptype) {
381 case 'e':
382 if (rparamcnt < 2)
383 return (EBADRPC);
384 /* LINTED */
385 tmp = (uint16_t *)rap->r_npbuf;
386 rap->r_entries = entries = letohs(*tmp);
387 rap->r_npbuf += 2;
388 rparamcnt -= 2;
389 p++;
390 break;
391 default:
392 done = 1;
393 }
394 #if 0 /* commented out in Darwin. Why? */
395 error = smb_rap_parserpparam(p, &p, &plen);
396 if (error) {
397 smb_error(dgettext(TEXT_DOMAIN,
398 "reply parameter mismatch %s"), 0, p);
399 return (EBADRPC);
400 }
401 #endif
402 }
403 rap->r_nparam = p;
404 /*
405 * In general, unpacking entries we may need to relocate
406 * entries for proper aligning. For now use them as is.
407 */
408 dp = rap->r_rcvbuf;
409 while (entries--) {
410 p = rap->r_sdata;
411 while (*p) {
412 ptype = *p;
413 error = smb_rap_parserpdata(p, &p, &dlen);
414 if (error) {
415 smb_error(dgettext(TEXT_DOMAIN,
416 "reply data mismatch %s"), 0, p);
417 return (EBADRPC);
418 }
419 if (rdatacnt < dlen)
420 return (EBADRPC);
421 switch (ptype) {
422 case 'z':
423 /* LINTED */
424 p32 = (uint32_t *)dp;
425 *p32 = (letohl(*p32) & 0xffff) - conv;
426 break;
427 }
428 dp += dlen;
429 rdatacnt -= dlen;
430 }
431 }
432 return (error);
433 }
434
435 int
smb_rap_error(struct smb_rap * rap,int error)436 smb_rap_error(struct smb_rap *rap, int error)
437 {
438 if (error)
439 return (error);
440 if (rap->r_result == 0)
441 return (0);
442 return (rap->r_result | SMB_RAP_ERROR);
443 }
444