xref: /onnv-gate/usr/src/lib/libsmbfs/smb/rap.c (revision 10023:71bf38dba3d6)
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