16007Sthurlow /*
26007Sthurlow * Copyright (c) 2000, Boris Popov
36007Sthurlow * All rights reserved.
46007Sthurlow *
56007Sthurlow * Redistribution and use in source and binary forms, with or without
66007Sthurlow * modification, are permitted provided that the following conditions
76007Sthurlow * are met:
86007Sthurlow * 1. Redistributions of source code must retain the above copyright
96007Sthurlow * notice, this list of conditions and the following disclaimer.
106007Sthurlow * 2. Redistributions in binary form must reproduce the above copyright
116007Sthurlow * notice, this list of conditions and the following disclaimer in the
126007Sthurlow * documentation and/or other materials provided with the distribution.
136007Sthurlow * 3. All advertising materials mentioning features or use of this software
146007Sthurlow * must display the following acknowledgement:
156007Sthurlow * This product includes software developed by Boris Popov.
166007Sthurlow * 4. Neither the name of the author nor the names of any co-contributors
176007Sthurlow * may be used to endorse or promote products derived from this software
186007Sthurlow * without specific prior written permission.
196007Sthurlow *
206007Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216007Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226007Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236007Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246007Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256007Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266007Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276007Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286007Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296007Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306007Sthurlow * SUCH DAMAGE.
316007Sthurlow *
326007Sthurlow * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $
336007Sthurlow *
346007Sthurlow * This is very simple implementation of RAP protocol.
356007Sthurlow */
366007Sthurlow
376007Sthurlow #include <sys/param.h>
386007Sthurlow #include <sys/errno.h>
396007Sthurlow #include <sys/stat.h>
406007Sthurlow #include <sys/isa_defs.h>
416007Sthurlow
426007Sthurlow #include <ctype.h>
436007Sthurlow #include <stdio.h>
446007Sthurlow #include <unistd.h>
456007Sthurlow #include <strings.h>
466007Sthurlow #include <stdlib.h>
476007Sthurlow #include <libintl.h>
486007Sthurlow #include <sysexits.h>
496007Sthurlow
506007Sthurlow #include <netsmb/mchain.h>
516007Sthurlow #include <netsmb/smb_lib.h>
526007Sthurlow #include <netsmb/smb_rap.h>
538271SGordon.Ross@Sun.COM #include "private.h"
546007Sthurlow
556007Sthurlow static int
smb_rap_parserqparam(const char * s,char ** next,int * rlen)566007Sthurlow smb_rap_parserqparam(const char *s, char **next, int *rlen)
576007Sthurlow {
586007Sthurlow char *np;
596007Sthurlow int len;
606007Sthurlow
616007Sthurlow switch (*s++) {
626007Sthurlow case 'L':
636007Sthurlow case 'T':
646007Sthurlow case 'W':
656007Sthurlow len = 2;
666007Sthurlow break;
676007Sthurlow case 'D':
686007Sthurlow case 'O':
696007Sthurlow len = 4;
706007Sthurlow break;
716007Sthurlow case 'b':
726007Sthurlow case 'F':
736007Sthurlow len = 1;
746007Sthurlow break;
756007Sthurlow case 'r':
766007Sthurlow case 's':
776007Sthurlow len = 0;
786007Sthurlow break;
796007Sthurlow default:
806007Sthurlow return (EINVAL);
816007Sthurlow }
826007Sthurlow if (isdigit(*s)) {
836007Sthurlow len *= strtoul(s, &np, 10);
846007Sthurlow s = np;
856007Sthurlow }
866007Sthurlow *rlen = len;
876007Sthurlow *(const char **)next = s;
886007Sthurlow return (0);
896007Sthurlow }
906007Sthurlow
916007Sthurlow static int
smb_rap_parserpparam(const char * s,char ** next,int * rlen)926007Sthurlow smb_rap_parserpparam(const char *s, char **next, int *rlen)
936007Sthurlow {
946007Sthurlow char *np;
956007Sthurlow int len = 0;
966007Sthurlow
976007Sthurlow switch (*s++) {
986007Sthurlow case 'e':
996007Sthurlow case 'h':
1006007Sthurlow len = 2;
1016007Sthurlow break;
1026007Sthurlow case 'i':
1036007Sthurlow len = 4;
1046007Sthurlow break;
1056007Sthurlow case 'g':
1066007Sthurlow len = 1;
1076007Sthurlow break;
1086007Sthurlow default:
1096007Sthurlow return (EINVAL);
1106007Sthurlow }
1116007Sthurlow if (isdigit(*s)) {
1126007Sthurlow len *= strtoul(s, &np, 10);
1136007Sthurlow s = np;
1146007Sthurlow }
1156007Sthurlow *rlen = len;
1166007Sthurlow *(const char **)next = s;
1176007Sthurlow return (0);
1186007Sthurlow }
1196007Sthurlow
1206007Sthurlow static int
smb_rap_parserpdata(const char * s,char ** next,int * rlen)1216007Sthurlow smb_rap_parserpdata(const char *s, char **next, int *rlen)
1226007Sthurlow {
1236007Sthurlow char *np;
1246007Sthurlow int len;
1256007Sthurlow
1266007Sthurlow switch (*s++) {
1276007Sthurlow case 'B':
1286007Sthurlow len = 1;
1296007Sthurlow break;
1306007Sthurlow case 'W':
1316007Sthurlow len = 2;
1326007Sthurlow break;
1336007Sthurlow case 'D':
1346007Sthurlow case 'O':
1356007Sthurlow case 'z':
1366007Sthurlow len = 4;
1376007Sthurlow break;
1386007Sthurlow default:
1396007Sthurlow return (EINVAL);
1406007Sthurlow }
1416007Sthurlow if (isdigit(*s)) {
1426007Sthurlow len *= strtoul(s, &np, 10);
1436007Sthurlow s = np;
1446007Sthurlow }
1456007Sthurlow *rlen = len;
1466007Sthurlow *(const char **)next = s;
1476007Sthurlow return (0);
1486007Sthurlow }
1496007Sthurlow
1506007Sthurlow static int
smb_rap_rqparam_z(struct smb_rap * rap,const char * value)1516007Sthurlow smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
1526007Sthurlow {
1536007Sthurlow int len = strlen(value) + 1;
1546007Sthurlow
1556007Sthurlow bcopy(value, rap->r_npbuf, len);
1566007Sthurlow rap->r_npbuf += len;
1576007Sthurlow rap->r_plen += len;
1586007Sthurlow return (0);
1596007Sthurlow }
1606007Sthurlow
1616007Sthurlow /*
1626007Sthurlow * Marshal RAP request parameters.
1636007Sthurlow * Note: value is in host order.
1646007Sthurlow */
1656007Sthurlow static int
smb_rap_rqparam(struct smb_rap * rap,char ptype,char plen,int value)1666007Sthurlow smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
1676007Sthurlow {
1686007Sthurlow int len = 0;
1696007Sthurlow uint_t uv = (uint_t)value;
1708271SGordon.Ross@Sun.COM uint32_t *lp;
1718271SGordon.Ross@Sun.COM uint16_t *sp;
1728271SGordon.Ross@Sun.COM char *p;
1736007Sthurlow
1746007Sthurlow switch (ptype) {
1756007Sthurlow case 'L':
1766007Sthurlow case 'W':
1776007Sthurlow /* LINTED */
1788271SGordon.Ross@Sun.COM sp = (uint16_t *)rap->r_npbuf;
1798271SGordon.Ross@Sun.COM *sp = htoles(uv);
1808271SGordon.Ross@Sun.COM len = sizeof (*sp);
1816007Sthurlow break;
1826007Sthurlow case 'D':
1836007Sthurlow /* LINTED */
1848271SGordon.Ross@Sun.COM lp = (uint32_t *)rap->r_npbuf;
1858271SGordon.Ross@Sun.COM *lp = htolel(uv);
1868271SGordon.Ross@Sun.COM len = sizeof (*lp);
1876007Sthurlow break;
1886007Sthurlow case 'b':
1898271SGordon.Ross@Sun.COM p = rap->r_npbuf;
1906007Sthurlow memset(p, uv, plen);
1916007Sthurlow len = plen;
1926007Sthurlow default:
1936007Sthurlow return (EINVAL);
1946007Sthurlow }
1956007Sthurlow rap->r_npbuf += len;
1966007Sthurlow rap->r_plen += len;
1976007Sthurlow return (0);
1986007Sthurlow }
1996007Sthurlow
2006007Sthurlow int
smb_rap_create(int fn,const char * param,const char * data,struct smb_rap ** rapp)2016007Sthurlow smb_rap_create(int fn, const char *param, const char *data,
2026007Sthurlow struct smb_rap **rapp)
2036007Sthurlow {
2046007Sthurlow struct smb_rap *rap;
2056007Sthurlow char *p;
2066007Sthurlow int plen = 0, len = 0;
2076007Sthurlow
2086007Sthurlow rap = malloc(sizeof (*rap));
2096007Sthurlow if (rap == NULL)
2106007Sthurlow return (ENOMEM);
2116007Sthurlow bzero(rap, sizeof (*rap));
2126007Sthurlow p = rap->r_sparam = rap->r_nparam = strdup(param);
2136007Sthurlow rap->r_sdata = rap->r_ndata = strdup(data);
2146007Sthurlow
2156007Sthurlow /*
2166007Sthurlow * Calculate length of request parameter block
2176007Sthurlow */
2186007Sthurlow len = 2 + strlen(param) + 1 + strlen(data) + 1;
2196007Sthurlow while (*p) {
2206007Sthurlow if (smb_rap_parserqparam(p, &p, &plen) != 0)
2216007Sthurlow break;
2226007Sthurlow len += plen;
2236007Sthurlow }
2246007Sthurlow rap->r_pbuf = rap->r_npbuf = malloc(len);
225*11332SGordon.Ross@Sun.COM if (rap->r_pbuf == NULL)
226*11332SGordon.Ross@Sun.COM return (ENOMEM);
227*11332SGordon.Ross@Sun.COM (void) smb_rap_rqparam(rap, 'W', 1, fn);
228*11332SGordon.Ross@Sun.COM (void) smb_rap_rqparam_z(rap, rap->r_sparam);
229*11332SGordon.Ross@Sun.COM (void) smb_rap_rqparam_z(rap, rap->r_sdata);
2306007Sthurlow *rapp = rap;
2316007Sthurlow return (0);
2326007Sthurlow }
2336007Sthurlow
2346007Sthurlow void
smb_rap_done(struct smb_rap * rap)2356007Sthurlow smb_rap_done(struct smb_rap *rap)
2366007Sthurlow {
2376007Sthurlow if (rap->r_sparam)
2386007Sthurlow free(rap->r_sparam);
2396007Sthurlow if (rap->r_sdata)
2406007Sthurlow free(rap->r_sdata);
2416007Sthurlow if (rap->r_pbuf)
2426007Sthurlow free(rap->r_pbuf);
2436007Sthurlow #ifdef NOTYETDEFINED
2446007Sthurlow if (rap->r_npbuf)
2456007Sthurlow free(rap->r_npbuf);
2466007Sthurlow if (rap->r_dbuf)
2476007Sthurlow free(rap->r_dbuf);
2486007Sthurlow if (rap->r_rcvbuf)
2496007Sthurlow free(rap->r_rcvbuf);
2506007Sthurlow #endif
2516007Sthurlow free(rap);
2526007Sthurlow }
2536007Sthurlow
2546007Sthurlow int
smb_rap_setNparam(struct smb_rap * rap,int value)2556007Sthurlow smb_rap_setNparam(struct smb_rap *rap, int value)
2566007Sthurlow {
2576007Sthurlow char *p = rap->r_nparam;
2586007Sthurlow char ptype = *p;
2596007Sthurlow int error, plen;
2606007Sthurlow
2616007Sthurlow error = smb_rap_parserqparam(p, &p, &plen);
2626007Sthurlow if (error)
2636007Sthurlow return (error);
2646007Sthurlow switch (ptype) {
2656007Sthurlow case 'L':
2666007Sthurlow rap->r_rcvbuflen = value;
2676007Sthurlow /* FALLTHROUGH */
2686007Sthurlow case 'W':
2696007Sthurlow case 'D':
2706007Sthurlow case 'b':
2716007Sthurlow error = smb_rap_rqparam(rap, ptype, plen, value);
2726007Sthurlow break;
2736007Sthurlow default:
2746007Sthurlow return (EINVAL);
2756007Sthurlow }
2766007Sthurlow rap->r_nparam = p;
2776007Sthurlow return (0);
2786007Sthurlow }
2796007Sthurlow
2806007Sthurlow int
smb_rap_setPparam(struct smb_rap * rap,void * value)2816007Sthurlow smb_rap_setPparam(struct smb_rap *rap, void *value)
2826007Sthurlow {
2836007Sthurlow char *p = rap->r_nparam;
2846007Sthurlow char ptype = *p;
2856007Sthurlow int error, plen;
2866007Sthurlow
2876007Sthurlow error = smb_rap_parserqparam(p, &p, &plen);
2886007Sthurlow if (error)
2896007Sthurlow return (error);
2906007Sthurlow switch (ptype) {
2916007Sthurlow case 'r':
2926007Sthurlow rap->r_rcvbuf = value;
2936007Sthurlow break;
2946007Sthurlow default:
2956007Sthurlow return (EINVAL);
2966007Sthurlow }
2976007Sthurlow rap->r_nparam = p;
2986007Sthurlow return (0);
2996007Sthurlow }
3006007Sthurlow
3018271SGordon.Ross@Sun.COM int
smb_rap_getNparam(struct smb_rap * rap,long * value)3026007Sthurlow smb_rap_getNparam(struct smb_rap *rap, long *value)
3036007Sthurlow {
3046007Sthurlow char *p = rap->r_nparam;
3056007Sthurlow char ptype = *p;
3066007Sthurlow int error, plen;
3076007Sthurlow uint16_t *te;
3086007Sthurlow
3096007Sthurlow error = smb_rap_parserpparam(p, &p, &plen);
3106007Sthurlow if (error)
3116007Sthurlow return (error);
3126007Sthurlow switch (ptype) {
3136007Sthurlow case 'h':
3146007Sthurlow /* LINTED */
3156007Sthurlow te = (uint16_t *)rap->r_npbuf;
3166007Sthurlow *value = letohs(*te);
3176007Sthurlow break;
3186007Sthurlow default:
3196007Sthurlow return (EINVAL);
3206007Sthurlow }
3216007Sthurlow rap->r_npbuf += plen;
3226007Sthurlow rap->r_nparam = p;
3236007Sthurlow return (0);
3246007Sthurlow }
3256007Sthurlow
3266007Sthurlow int
smb_rap_request(struct smb_rap * rap,struct smb_ctx * ctx)3276007Sthurlow smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
3286007Sthurlow {
3296007Sthurlow uint16_t *rp, conv, *tmp;
33010023SGordon.Ross@Sun.COM uint32_t *p32;
3316007Sthurlow char *dp, *p = rap->r_nparam;
3326007Sthurlow char ptype;
33310023SGordon.Ross@Sun.COM int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
3346007Sthurlow
3356007Sthurlow rdatacnt = rap->r_rcvbuflen;
3366007Sthurlow rparamcnt = rap->r_plen;
3376007Sthurlow error = smb_t2_request(ctx, 0, NULL, "\\PIPE\\LANMAN",
3386007Sthurlow rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */
3396007Sthurlow 0, NULL, /* int tdatacnt, void *tdata */
3406007Sthurlow &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */
3416007Sthurlow &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */
3426007Sthurlow &buffer_oflow);
3436007Sthurlow if (error)
3446007Sthurlow return (error);
3456007Sthurlow
3466007Sthurlow /* LINTED */
3476007Sthurlow rp = (uint16_t *)rap->r_pbuf;
3486007Sthurlow
3496007Sthurlow /*
3506007Sthurlow * Note: First is a "LanMan API" error code.
3516007Sthurlow * See: usr/src/uts/common/smbsrv/lmerr.h
3526007Sthurlow */
3536007Sthurlow if (rparamcnt < 2)
3546007Sthurlow return (EBADRPC);
3556007Sthurlow rap->r_result = letohs(*rp);
3566007Sthurlow rp++; rparamcnt -= 2;
3576007Sthurlow
3586007Sthurlow if (rap->r_result != 0) {
3596007Sthurlow /*
3606007Sthurlow * Could also return zero and let the caller
3616007Sthurlow * come get r_result via smb_rap_error(),
3626007Sthurlow * but in case they dont...
3636007Sthurlow */
3646007Sthurlow return (rap->r_result | SMB_RAP_ERROR);
3656007Sthurlow }
3666007Sthurlow
3676007Sthurlow if (rparamcnt < 2)
3686007Sthurlow return (EBADRPC);
3696007Sthurlow conv = letohs(*rp);
3706007Sthurlow rp++; rparamcnt -= 2;
3716007Sthurlow
3726007Sthurlow rap->r_npbuf = (char *)rp;
3736007Sthurlow rap->r_entries = entries = 0;
3746007Sthurlow /* Save the returned data length */
3756007Sthurlow rap->r_rcvbuflen = rdatacnt;
3766007Sthurlow done = 0;
3776007Sthurlow
3786007Sthurlow while (!done && *p) {
3796007Sthurlow ptype = *p;
3806007Sthurlow switch (ptype) {
3816007Sthurlow case 'e':
3826007Sthurlow if (rparamcnt < 2)
3836007Sthurlow return (EBADRPC);
3846007Sthurlow /* LINTED */
3856007Sthurlow tmp = (uint16_t *)rap->r_npbuf;
3866007Sthurlow rap->r_entries = entries = letohs(*tmp);
3876007Sthurlow rap->r_npbuf += 2;
3886007Sthurlow rparamcnt -= 2;
3896007Sthurlow p++;
3906007Sthurlow break;
3916007Sthurlow default:
3926007Sthurlow done = 1;
3936007Sthurlow }
3946007Sthurlow #if 0 /* commented out in Darwin. Why? */
3956007Sthurlow error = smb_rap_parserpparam(p, &p, &plen);
3966007Sthurlow if (error) {
3976007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
3986007Sthurlow "reply parameter mismatch %s"), 0, p);
3996007Sthurlow return (EBADRPC);
4006007Sthurlow }
4016007Sthurlow #endif
4026007Sthurlow }
4036007Sthurlow rap->r_nparam = p;
4046007Sthurlow /*
4056007Sthurlow * In general, unpacking entries we may need to relocate
4066007Sthurlow * entries for proper aligning. For now use them as is.
4076007Sthurlow */
4086007Sthurlow dp = rap->r_rcvbuf;
4096007Sthurlow while (entries--) {
4106007Sthurlow p = rap->r_sdata;
4116007Sthurlow while (*p) {
4126007Sthurlow ptype = *p;
4136007Sthurlow error = smb_rap_parserpdata(p, &p, &dlen);
4146007Sthurlow if (error) {
4156007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
4166007Sthurlow "reply data mismatch %s"), 0, p);
4176007Sthurlow return (EBADRPC);
4186007Sthurlow }
4196007Sthurlow if (rdatacnt < dlen)
4206007Sthurlow return (EBADRPC);
4216007Sthurlow switch (ptype) {
4226007Sthurlow case 'z':
4236007Sthurlow /* LINTED */
4246007Sthurlow p32 = (uint32_t *)dp;
4256007Sthurlow *p32 = (letohl(*p32) & 0xffff) - conv;
4266007Sthurlow break;
4276007Sthurlow }
4286007Sthurlow dp += dlen;
4296007Sthurlow rdatacnt -= dlen;
4306007Sthurlow }
4316007Sthurlow }
4326007Sthurlow return (error);
4336007Sthurlow }
4346007Sthurlow
4356007Sthurlow int
smb_rap_error(struct smb_rap * rap,int error)4366007Sthurlow smb_rap_error(struct smb_rap *rap, int error)
4376007Sthurlow {
4386007Sthurlow if (error)
4396007Sthurlow return (error);
4406007Sthurlow if (rap->r_result == 0)
4416007Sthurlow return (0);
4426007Sthurlow return (rap->r_result | SMB_RAP_ERROR);
4436007Sthurlow }
444