Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / lib / libsmbfs / smb / rap.c
blob48b2eebe606e57fac45e42e0cb84bf5cdd112686
1 /*
2 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
3 * Copyright (c) 2000, Boris Popov
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Boris Popov.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $
35 * This is very simple implementation of RAP protocol.
38 #include <sys/param.h>
39 #include <sys/errno.h>
40 #include <sys/stat.h>
41 #include <sys/isa_defs.h>
43 #include <ctype.h>
44 #include <stdio.h>
45 #include <unistd.h>
46 #include <strings.h>
47 #include <stdlib.h>
48 #include <libintl.h>
49 #include <sysexits.h>
51 #include <netsmb/mchain.h>
52 #include <netsmb/smb_lib.h>
53 #include <netsmb/smb_rap.h>
54 #include "private.h"
56 static int
57 smb_rap_parserqparam(const char *s, char **next, int *rlen)
59 char *np;
60 int len;
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);
83 if (isdigit(*s)) {
84 len *= strtoul(s, &np, 10);
85 s = np;
87 *rlen = len;
88 *(const char **)next = s;
89 return (0);
92 static int
93 smb_rap_parserpparam(const char *s, char **next, int *rlen)
95 char *np;
96 int len = 0;
98 switch (*s++) {
99 case 'e':
100 case 'h':
101 len = 2;
102 break;
103 case 'i':
104 len = 4;
105 break;
106 case 'g':
107 len = 1;
108 break;
109 default:
110 return (EINVAL);
112 if (isdigit(*s)) {
113 len *= strtoul(s, &np, 10);
114 s = np;
116 *rlen = len;
117 *(const char **)next = s;
118 return (0);
121 static int
122 smb_rap_parserpdata(const char *s, char **next, int *rlen)
124 char *np;
125 int len;
127 switch (*s++) {
128 case 'B':
129 len = 1;
130 break;
131 case 'W':
132 len = 2;
133 break;
134 case 'D':
135 case 'O':
136 case 'z':
137 len = 4;
138 break;
139 default:
140 return (EINVAL);
142 if (isdigit(*s)) {
143 len *= strtoul(s, &np, 10);
144 s = np;
146 *rlen = len;
147 *(const char **)next = s;
148 return (0);
151 static int
152 smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
154 int len = strlen(value) + 1;
156 bcopy(value, rap->r_npbuf, len);
157 rap->r_npbuf += len;
158 rap->r_plen += len;
159 return (0);
163 * Marshal RAP request parameters.
164 * Note: value is in host order.
166 static int
167 smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
169 int len = 0;
170 uint_t uv = (uint_t)value;
171 uint32_t *lp;
172 uint16_t *sp;
173 char *p;
175 switch (ptype) {
176 case 'L':
177 case 'W':
178 /* LINTED */
179 sp = (uint16_t *)rap->r_npbuf;
180 *sp = htoles(uv);
181 len = sizeof (*sp);
182 break;
183 case 'D':
184 /* LINTED */
185 lp = (uint32_t *)rap->r_npbuf;
186 *lp = htolel(uv);
187 len = sizeof (*lp);
188 break;
189 case 'b':
190 p = rap->r_npbuf;
191 memset(p, uv, plen);
192 len = plen;
193 break;
194 default:
195 return (EINVAL);
197 rap->r_npbuf += len;
198 rap->r_plen += len;
199 return (0);
203 smb_rap_create(int fn, const char *param, const char *data,
204 struct smb_rap **rapp)
206 struct smb_rap *rap;
207 char *p;
208 int plen = 0, len = 0;
210 rap = malloc(sizeof (*rap));
211 if (rap == NULL)
212 return (ENOMEM);
213 bzero(rap, sizeof (*rap));
214 p = rap->r_sparam = rap->r_nparam = strdup(param);
215 rap->r_sdata = rap->r_ndata = strdup(data);
218 * Calculate length of request parameter block
220 len = 2 + strlen(param) + 1 + strlen(data) + 1;
221 while (*p) {
222 if (smb_rap_parserqparam(p, &p, &plen) != 0)
223 break;
224 len += plen;
226 rap->r_pbuf = rap->r_npbuf = malloc(len);
227 if (rap->r_pbuf == NULL)
228 return (ENOMEM);
229 (void) smb_rap_rqparam(rap, 'W', 1, fn);
230 (void) smb_rap_rqparam_z(rap, rap->r_sparam);
231 (void) smb_rap_rqparam_z(rap, rap->r_sdata);
232 *rapp = rap;
233 return (0);
236 void
237 smb_rap_done(struct smb_rap *rap)
239 free(rap->r_sparam);
240 free(rap->r_sdata);
241 free(rap->r_pbuf);
242 #ifdef NOTYETDEFINED
243 free(rap->r_npbuf);
244 free(rap->r_dbuf);
245 free(rap->r_rcvbuf);
246 #endif
247 free(rap);
251 smb_rap_setNparam(struct smb_rap *rap, int value)
253 char *p = rap->r_nparam;
254 char ptype = *p;
255 int error, plen;
257 error = smb_rap_parserqparam(p, &p, &plen);
258 if (error)
259 return (error);
260 switch (ptype) {
261 case 'L':
262 rap->r_rcvbuflen = value;
263 /* FALLTHROUGH */
264 case 'W':
265 case 'D':
266 case 'b':
267 error = smb_rap_rqparam(rap, ptype, plen, value);
268 break;
269 default:
270 return (EINVAL);
272 rap->r_nparam = p;
273 return (0);
277 smb_rap_setPparam(struct smb_rap *rap, void *value)
279 char *p = rap->r_nparam;
280 char ptype = *p;
281 int error, plen;
283 error = smb_rap_parserqparam(p, &p, &plen);
284 if (error)
285 return (error);
286 switch (ptype) {
287 case 'r':
288 rap->r_rcvbuf = value;
289 break;
290 default:
291 return (EINVAL);
293 rap->r_nparam = p;
294 return (0);
298 smb_rap_getNparam(struct smb_rap *rap, long *value)
300 char *p = rap->r_nparam;
301 char ptype = *p;
302 int error, plen;
303 uint16_t *te;
305 error = smb_rap_parserpparam(p, &p, &plen);
306 if (error)
307 return (error);
308 switch (ptype) {
309 case 'h':
310 /* LINTED */
311 te = (uint16_t *)rap->r_npbuf;
312 *value = letohs(*te);
313 break;
314 default:
315 return (EINVAL);
317 rap->r_npbuf += plen;
318 rap->r_nparam = p;
319 return (0);
323 smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
325 uint16_t *rp, conv, *tmp;
326 uint32_t *p32;
327 char *dp, *p = rap->r_nparam;
328 char ptype;
329 int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
331 rdatacnt = rap->r_rcvbuflen;
332 rparamcnt = rap->r_plen;
333 error = smb_t2_request(ctx->ct_dev_fd,
334 0, NULL, "\\PIPE\\LANMAN",
335 rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */
336 0, NULL, /* int tdatacnt, void *tdata */
337 &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */
338 &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */
339 &buffer_oflow);
340 if (error)
341 return (error);
343 /* LINTED */
344 rp = (uint16_t *)rap->r_pbuf;
347 * Note: First is a "LanMan API" error code.
348 * See: usr/src/uts/common/smbsrv/lmerr.h
350 if (rparamcnt < 2)
351 return (EBADRPC);
352 rap->r_result = letohs(*rp);
353 rp++; rparamcnt -= 2;
355 if (rap->r_result != 0) {
357 * Could also return zero and let the caller
358 * come get r_result via smb_rap_error(),
359 * but in case they dont...
361 return (rap->r_result | SMB_RAP_ERROR);
364 if (rparamcnt < 2)
365 return (EBADRPC);
366 conv = letohs(*rp);
367 rp++; rparamcnt -= 2;
369 rap->r_npbuf = (char *)rp;
370 rap->r_entries = entries = 0;
371 /* Save the returned data length */
372 rap->r_rcvbuflen = rdatacnt;
373 done = 0;
375 while (!done && *p) {
376 ptype = *p;
377 switch (ptype) {
378 case 'e':
379 if (rparamcnt < 2)
380 return (EBADRPC);
381 /* LINTED */
382 tmp = (uint16_t *)rap->r_npbuf;
383 rap->r_entries = entries = letohs(*tmp);
384 rap->r_npbuf += 2;
385 rparamcnt -= 2;
386 p++;
387 break;
388 default:
389 done = 1;
391 #if 0 /* commented out in Darwin. Why? */
392 error = smb_rap_parserpparam(p, &p, &plen);
393 if (error) {
394 smb_error(dgettext(TEXT_DOMAIN,
395 "reply parameter mismatch %s"), 0, p);
396 return (EBADRPC);
398 #endif
400 rap->r_nparam = p;
402 * In general, unpacking entries we may need to relocate
403 * entries for proper aligning. For now use them as is.
405 dp = rap->r_rcvbuf;
406 while (entries--) {
407 p = rap->r_sdata;
408 while (*p) {
409 ptype = *p;
410 error = smb_rap_parserpdata(p, &p, &dlen);
411 if (error) {
412 smb_error(dgettext(TEXT_DOMAIN,
413 "reply data mismatch %s"), 0, p);
414 return (EBADRPC);
416 if (rdatacnt < dlen)
417 return (EBADRPC);
418 switch (ptype) {
419 case 'z':
420 /* LINTED */
421 p32 = (uint32_t *)dp;
422 *p32 = (letohl(*p32) & 0xffff) - conv;
423 break;
425 dp += dlen;
426 rdatacnt -= dlen;
429 return (error);
433 smb_rap_error(struct smb_rap *rap, int error)
435 if (error)
436 return (error);
437 if (rap->r_result == 0)
438 return (0);
439 return (rap->r_result | SMB_RAP_ERROR);