import less(1)
[unleashed/tickless.git] / usr / src / lib / libsmbfs / smb / rap.c
blobf10929dfb421ab9756c3f983320ee3b44be34ddc
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 default:
194 return (EINVAL);
196 rap->r_npbuf += len;
197 rap->r_plen += len;
198 return (0);
202 smb_rap_create(int fn, const char *param, const char *data,
203 struct smb_rap **rapp)
205 struct smb_rap *rap;
206 char *p;
207 int plen = 0, len = 0;
209 rap = malloc(sizeof (*rap));
210 if (rap == NULL)
211 return (ENOMEM);
212 bzero(rap, sizeof (*rap));
213 p = rap->r_sparam = rap->r_nparam = strdup(param);
214 rap->r_sdata = rap->r_ndata = strdup(data);
217 * Calculate length of request parameter block
219 len = 2 + strlen(param) + 1 + strlen(data) + 1;
220 while (*p) {
221 if (smb_rap_parserqparam(p, &p, &plen) != 0)
222 break;
223 len += plen;
225 rap->r_pbuf = rap->r_npbuf = malloc(len);
226 if (rap->r_pbuf == NULL)
227 return (ENOMEM);
228 (void) smb_rap_rqparam(rap, 'W', 1, fn);
229 (void) smb_rap_rqparam_z(rap, rap->r_sparam);
230 (void) smb_rap_rqparam_z(rap, rap->r_sdata);
231 *rapp = rap;
232 return (0);
235 void
236 smb_rap_done(struct smb_rap *rap)
238 free(rap->r_sparam);
239 free(rap->r_sdata);
240 free(rap->r_pbuf);
241 #ifdef NOTYETDEFINED
242 free(rap->r_npbuf);
243 free(rap->r_dbuf);
244 free(rap->r_rcvbuf);
245 #endif
246 free(rap);
250 smb_rap_setNparam(struct smb_rap *rap, int value)
252 char *p = rap->r_nparam;
253 char ptype = *p;
254 int error, plen;
256 error = smb_rap_parserqparam(p, &p, &plen);
257 if (error)
258 return (error);
259 switch (ptype) {
260 case 'L':
261 rap->r_rcvbuflen = value;
262 /* FALLTHROUGH */
263 case 'W':
264 case 'D':
265 case 'b':
266 error = smb_rap_rqparam(rap, ptype, plen, value);
267 break;
268 default:
269 return (EINVAL);
271 rap->r_nparam = p;
272 return (0);
276 smb_rap_setPparam(struct smb_rap *rap, void *value)
278 char *p = rap->r_nparam;
279 char ptype = *p;
280 int error, plen;
282 error = smb_rap_parserqparam(p, &p, &plen);
283 if (error)
284 return (error);
285 switch (ptype) {
286 case 'r':
287 rap->r_rcvbuf = value;
288 break;
289 default:
290 return (EINVAL);
292 rap->r_nparam = p;
293 return (0);
297 smb_rap_getNparam(struct smb_rap *rap, long *value)
299 char *p = rap->r_nparam;
300 char ptype = *p;
301 int error, plen;
302 uint16_t *te;
304 error = smb_rap_parserpparam(p, &p, &plen);
305 if (error)
306 return (error);
307 switch (ptype) {
308 case 'h':
309 /* LINTED */
310 te = (uint16_t *)rap->r_npbuf;
311 *value = letohs(*te);
312 break;
313 default:
314 return (EINVAL);
316 rap->r_npbuf += plen;
317 rap->r_nparam = p;
318 return (0);
322 smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
324 uint16_t *rp, conv, *tmp;
325 uint32_t *p32;
326 char *dp, *p = rap->r_nparam;
327 char ptype;
328 int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
330 rdatacnt = rap->r_rcvbuflen;
331 rparamcnt = rap->r_plen;
332 error = smb_t2_request(ctx->ct_dev_fd,
333 0, NULL, "\\PIPE\\LANMAN",
334 rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */
335 0, NULL, /* int tdatacnt, void *tdata */
336 &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */
337 &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */
338 &buffer_oflow);
339 if (error)
340 return (error);
342 /* LINTED */
343 rp = (uint16_t *)rap->r_pbuf;
346 * Note: First is a "LanMan API" error code.
347 * See: usr/src/uts/common/smbsrv/lmerr.h
349 if (rparamcnt < 2)
350 return (EBADRPC);
351 rap->r_result = letohs(*rp);
352 rp++; rparamcnt -= 2;
354 if (rap->r_result != 0) {
356 * Could also return zero and let the caller
357 * come get r_result via smb_rap_error(),
358 * but in case they dont...
360 return (rap->r_result | SMB_RAP_ERROR);
363 if (rparamcnt < 2)
364 return (EBADRPC);
365 conv = letohs(*rp);
366 rp++; rparamcnt -= 2;
368 rap->r_npbuf = (char *)rp;
369 rap->r_entries = entries = 0;
370 /* Save the returned data length */
371 rap->r_rcvbuflen = rdatacnt;
372 done = 0;
374 while (!done && *p) {
375 ptype = *p;
376 switch (ptype) {
377 case 'e':
378 if (rparamcnt < 2)
379 return (EBADRPC);
380 /* LINTED */
381 tmp = (uint16_t *)rap->r_npbuf;
382 rap->r_entries = entries = letohs(*tmp);
383 rap->r_npbuf += 2;
384 rparamcnt -= 2;
385 p++;
386 break;
387 default:
388 done = 1;
390 #if 0 /* commented out in Darwin. Why? */
391 error = smb_rap_parserpparam(p, &p, &plen);
392 if (error) {
393 smb_error(dgettext(TEXT_DOMAIN,
394 "reply parameter mismatch %s"), 0, p);
395 return (EBADRPC);
397 #endif
399 rap->r_nparam = p;
401 * In general, unpacking entries we may need to relocate
402 * entries for proper aligning. For now use them as is.
404 dp = rap->r_rcvbuf;
405 while (entries--) {
406 p = rap->r_sdata;
407 while (*p) {
408 ptype = *p;
409 error = smb_rap_parserpdata(p, &p, &dlen);
410 if (error) {
411 smb_error(dgettext(TEXT_DOMAIN,
412 "reply data mismatch %s"), 0, p);
413 return (EBADRPC);
415 if (rdatacnt < dlen)
416 return (EBADRPC);
417 switch (ptype) {
418 case 'z':
419 /* LINTED */
420 p32 = (uint32_t *)dp;
421 *p32 = (letohl(*p32) & 0xffff) - conv;
422 break;
424 dp += dlen;
425 rdatacnt -= dlen;
428 return (error);
432 smb_rap_error(struct smb_rap *rap, int error)
434 if (error)
435 return (error);
436 if (rap->r_result == 0)
437 return (0);
438 return (rap->r_result | SMB_RAP_ERROR);