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 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 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 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 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 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 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); 2256007Sthurlow smb_rap_rqparam(rap, 'W', 1, fn); 2266007Sthurlow smb_rap_rqparam_z(rap, rap->r_sparam); 2276007Sthurlow smb_rap_rqparam_z(rap, rap->r_sdata); 2286007Sthurlow *rapp = rap; 2296007Sthurlow return (0); 2306007Sthurlow } 2316007Sthurlow 2326007Sthurlow void 2336007Sthurlow smb_rap_done(struct smb_rap *rap) 2346007Sthurlow { 2356007Sthurlow if (rap->r_sparam) 2366007Sthurlow free(rap->r_sparam); 2376007Sthurlow if (rap->r_sdata) 2386007Sthurlow free(rap->r_sdata); 2396007Sthurlow if (rap->r_pbuf) 2406007Sthurlow free(rap->r_pbuf); 2416007Sthurlow #ifdef NOTYETDEFINED 2426007Sthurlow if (rap->r_npbuf) 2436007Sthurlow free(rap->r_npbuf); 2446007Sthurlow if (rap->r_dbuf) 2456007Sthurlow free(rap->r_dbuf); 2466007Sthurlow if (rap->r_rcvbuf) 2476007Sthurlow free(rap->r_rcvbuf); 2486007Sthurlow #endif 2496007Sthurlow free(rap); 2506007Sthurlow } 2516007Sthurlow 2526007Sthurlow int 2536007Sthurlow smb_rap_setNparam(struct smb_rap *rap, int value) 2546007Sthurlow { 2556007Sthurlow char *p = rap->r_nparam; 2566007Sthurlow char ptype = *p; 2576007Sthurlow int error, plen; 2586007Sthurlow 2596007Sthurlow error = smb_rap_parserqparam(p, &p, &plen); 2606007Sthurlow if (error) 2616007Sthurlow return (error); 2626007Sthurlow switch (ptype) { 2636007Sthurlow case 'L': 2646007Sthurlow rap->r_rcvbuflen = value; 2656007Sthurlow /* FALLTHROUGH */ 2666007Sthurlow case 'W': 2676007Sthurlow case 'D': 2686007Sthurlow case 'b': 2696007Sthurlow error = smb_rap_rqparam(rap, ptype, plen, value); 2706007Sthurlow break; 2716007Sthurlow default: 2726007Sthurlow return (EINVAL); 2736007Sthurlow } 2746007Sthurlow rap->r_nparam = p; 2756007Sthurlow return (0); 2766007Sthurlow } 2776007Sthurlow 2786007Sthurlow int 2796007Sthurlow smb_rap_setPparam(struct smb_rap *rap, void *value) 2806007Sthurlow { 2816007Sthurlow char *p = rap->r_nparam; 2826007Sthurlow char ptype = *p; 2836007Sthurlow int error, plen; 2846007Sthurlow 2856007Sthurlow error = smb_rap_parserqparam(p, &p, &plen); 2866007Sthurlow if (error) 2876007Sthurlow return (error); 2886007Sthurlow switch (ptype) { 2896007Sthurlow case 'r': 2906007Sthurlow rap->r_rcvbuf = value; 2916007Sthurlow break; 2926007Sthurlow default: 2936007Sthurlow return (EINVAL); 2946007Sthurlow } 2956007Sthurlow rap->r_nparam = p; 2966007Sthurlow return (0); 2976007Sthurlow } 2986007Sthurlow 2998271SGordon.Ross@Sun.COM int 3006007Sthurlow smb_rap_getNparam(struct smb_rap *rap, long *value) 3016007Sthurlow { 3026007Sthurlow char *p = rap->r_nparam; 3036007Sthurlow char ptype = *p; 3046007Sthurlow int error, plen; 3056007Sthurlow uint16_t *te; 3066007Sthurlow 3076007Sthurlow error = smb_rap_parserpparam(p, &p, &plen); 3086007Sthurlow if (error) 3096007Sthurlow return (error); 3106007Sthurlow switch (ptype) { 3116007Sthurlow case 'h': 3126007Sthurlow /* LINTED */ 3136007Sthurlow te = (uint16_t *)rap->r_npbuf; 3146007Sthurlow *value = letohs(*te); 3156007Sthurlow break; 3166007Sthurlow default: 3176007Sthurlow return (EINVAL); 3186007Sthurlow } 3196007Sthurlow rap->r_npbuf += plen; 3206007Sthurlow rap->r_nparam = p; 3216007Sthurlow return (0); 3226007Sthurlow } 3236007Sthurlow 3246007Sthurlow int 3256007Sthurlow smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx) 3266007Sthurlow { 3276007Sthurlow uint16_t *rp, conv, *tmp; 328*10023SGordon.Ross@Sun.COM uint32_t *p32; 3296007Sthurlow char *dp, *p = rap->r_nparam; 3306007Sthurlow char ptype; 331*10023SGordon.Ross@Sun.COM int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow; 3326007Sthurlow 3336007Sthurlow rdatacnt = rap->r_rcvbuflen; 3346007Sthurlow rparamcnt = rap->r_plen; 3356007Sthurlow error = smb_t2_request(ctx, 0, NULL, "\\PIPE\\LANMAN", 3366007Sthurlow rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */ 3376007Sthurlow 0, NULL, /* int tdatacnt, void *tdata */ 3386007Sthurlow &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */ 3396007Sthurlow &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */ 3406007Sthurlow &buffer_oflow); 3416007Sthurlow if (error) 3426007Sthurlow return (error); 3436007Sthurlow 3446007Sthurlow /* LINTED */ 3456007Sthurlow rp = (uint16_t *)rap->r_pbuf; 3466007Sthurlow 3476007Sthurlow /* 3486007Sthurlow * Note: First is a "LanMan API" error code. 3496007Sthurlow * See: usr/src/uts/common/smbsrv/lmerr.h 3506007Sthurlow */ 3516007Sthurlow if (rparamcnt < 2) 3526007Sthurlow return (EBADRPC); 3536007Sthurlow rap->r_result = letohs(*rp); 3546007Sthurlow rp++; rparamcnt -= 2; 3556007Sthurlow 3566007Sthurlow if (rap->r_result != 0) { 3576007Sthurlow /* 3586007Sthurlow * Could also return zero and let the caller 3596007Sthurlow * come get r_result via smb_rap_error(), 3606007Sthurlow * but in case they dont... 3616007Sthurlow */ 3626007Sthurlow return (rap->r_result | SMB_RAP_ERROR); 3636007Sthurlow } 3646007Sthurlow 3656007Sthurlow if (rparamcnt < 2) 3666007Sthurlow return (EBADRPC); 3676007Sthurlow conv = letohs(*rp); 3686007Sthurlow rp++; rparamcnt -= 2; 3696007Sthurlow 3706007Sthurlow rap->r_npbuf = (char *)rp; 3716007Sthurlow rap->r_entries = entries = 0; 3726007Sthurlow /* Save the returned data length */ 3736007Sthurlow rap->r_rcvbuflen = rdatacnt; 3746007Sthurlow done = 0; 3756007Sthurlow 3766007Sthurlow while (!done && *p) { 3776007Sthurlow ptype = *p; 3786007Sthurlow switch (ptype) { 3796007Sthurlow case 'e': 3806007Sthurlow if (rparamcnt < 2) 3816007Sthurlow return (EBADRPC); 3826007Sthurlow /* LINTED */ 3836007Sthurlow tmp = (uint16_t *)rap->r_npbuf; 3846007Sthurlow rap->r_entries = entries = letohs(*tmp); 3856007Sthurlow rap->r_npbuf += 2; 3866007Sthurlow rparamcnt -= 2; 3876007Sthurlow p++; 3886007Sthurlow break; 3896007Sthurlow default: 3906007Sthurlow done = 1; 3916007Sthurlow } 3926007Sthurlow #if 0 /* commented out in Darwin. Why? */ 3936007Sthurlow error = smb_rap_parserpparam(p, &p, &plen); 3946007Sthurlow if (error) { 3956007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 3966007Sthurlow "reply parameter mismatch %s"), 0, p); 3976007Sthurlow return (EBADRPC); 3986007Sthurlow } 3996007Sthurlow #endif 4006007Sthurlow } 4016007Sthurlow rap->r_nparam = p; 4026007Sthurlow /* 4036007Sthurlow * In general, unpacking entries we may need to relocate 4046007Sthurlow * entries for proper aligning. For now use them as is. 4056007Sthurlow */ 4066007Sthurlow dp = rap->r_rcvbuf; 4076007Sthurlow while (entries--) { 4086007Sthurlow p = rap->r_sdata; 4096007Sthurlow while (*p) { 4106007Sthurlow ptype = *p; 4116007Sthurlow error = smb_rap_parserpdata(p, &p, &dlen); 4126007Sthurlow if (error) { 4136007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 4146007Sthurlow "reply data mismatch %s"), 0, p); 4156007Sthurlow return (EBADRPC); 4166007Sthurlow } 4176007Sthurlow if (rdatacnt < dlen) 4186007Sthurlow return (EBADRPC); 4196007Sthurlow switch (ptype) { 4206007Sthurlow case 'z': 4216007Sthurlow /* LINTED */ 4226007Sthurlow p32 = (uint32_t *)dp; 4236007Sthurlow *p32 = (letohl(*p32) & 0xffff) - conv; 4246007Sthurlow break; 4256007Sthurlow } 4266007Sthurlow dp += dlen; 4276007Sthurlow rdatacnt -= dlen; 4286007Sthurlow } 4296007Sthurlow } 4306007Sthurlow return (error); 4316007Sthurlow } 4326007Sthurlow 4336007Sthurlow int 4346007Sthurlow smb_rap_error(struct smb_rap *rap, int error) 4356007Sthurlow { 4366007Sthurlow if (error) 4376007Sthurlow return (error); 4386007Sthurlow if (rap->r_result == 0) 4396007Sthurlow return (0); 4406007Sthurlow return (rap->r_result | SMB_RAP_ERROR); 4416007Sthurlow } 442