187866Ssheldonh/*
287866Ssheldonh * Copyright (c) 2000, Boris Popov
387866Ssheldonh * All rights reserved.
487866Ssheldonh *
587866Ssheldonh * Redistribution and use in source and binary forms, with or without
687866Ssheldonh * modification, are permitted provided that the following conditions
787866Ssheldonh * are met:
887866Ssheldonh * 1. Redistributions of source code must retain the above copyright
987866Ssheldonh *    notice, this list of conditions and the following disclaimer.
1087866Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright
1187866Ssheldonh *    notice, this list of conditions and the following disclaimer in the
1287866Ssheldonh *    documentation and/or other materials provided with the distribution.
1387866Ssheldonh * 3. All advertising materials mentioning features or use of this software
1487866Ssheldonh *    must display the following acknowledgement:
1587866Ssheldonh *    This product includes software developed by Boris Popov.
1687866Ssheldonh * 4. Neither the name of the author nor the names of any co-contributors
1787866Ssheldonh *    may be used to endorse or promote products derived from this software
1887866Ssheldonh *    without specific prior written permission.
1987866Ssheldonh *
2087866Ssheldonh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2187866Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2287866Ssheldonh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2387866Ssheldonh * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2487866Ssheldonh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2587866Ssheldonh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2687866Ssheldonh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2787866Ssheldonh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2887866Ssheldonh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2987866Ssheldonh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3087866Ssheldonh * SUCH DAMAGE.
3187866Ssheldonh *
3287866Ssheldonh * $Id: rap.c,v 1.8 2001/02/24 15:56:05 bp Exp $
33118041Speter * $FreeBSD$
3487866Ssheldonh *
3587866Ssheldonh * This is very simple implementation of RAP protocol.
3687866Ssheldonh */
3787866Ssheldonh#include <sys/param.h>
38150312Simura#include <sys/endian.h>
3987866Ssheldonh#include <sys/errno.h>
4087866Ssheldonh#include <sys/stat.h>
4187866Ssheldonh#include <ctype.h>
4287866Ssheldonh#include <err.h>
4387866Ssheldonh#include <stdio.h>
4487866Ssheldonh#include <unistd.h>
45118041Speter#include <string.h>
4687866Ssheldonh#include <stdlib.h>
4787866Ssheldonh#include <sysexits.h>
4887866Ssheldonh
4987866Ssheldonh#include <netsmb/smb_lib.h>
5087866Ssheldonh#include <netsmb/smb_conn.h>
5187866Ssheldonh#include <netsmb/smb_rap.h>
5287866Ssheldonh
5387866Ssheldonh/*#include <sys/ioctl.h>*/
5487866Ssheldonh
5587866Ssheldonhstatic int
5687866Ssheldonhsmb_rap_parserqparam(const char *s, char **next, int *rlen)
5787866Ssheldonh{
5887866Ssheldonh	char *np;
5987866Ssheldonh	int len, m;
6087866Ssheldonh
6187866Ssheldonh	m = 1;
6287866Ssheldonh	switch (*s++) {
6387866Ssheldonh	    case 'L':
6487866Ssheldonh	    case 'T':
6587866Ssheldonh	    case 'W':
6687866Ssheldonh		len = 2;
6787866Ssheldonh		break;
6887866Ssheldonh	    case 'D':
6987866Ssheldonh	    case 'O':
7087866Ssheldonh		len = 4;
7187866Ssheldonh		break;
7287866Ssheldonh	    case 'b':
7387866Ssheldonh	    case 'F':
7487866Ssheldonh		len = 1;
7587866Ssheldonh		break;
7687866Ssheldonh	    case 'r':
7787866Ssheldonh	    case 's':
7887866Ssheldonh		len = 0;
7987866Ssheldonh		break;
8087866Ssheldonh	    default:
8187866Ssheldonh		return EINVAL;
8287866Ssheldonh	}
8387866Ssheldonh	if (isdigit(*s)) {
8487866Ssheldonh		len *= strtoul(s, &np, 10);
8587866Ssheldonh		s = np;
8687866Ssheldonh	}
8787866Ssheldonh	*rlen = len;
8887866Ssheldonh	*(const char**)next = s;
8987866Ssheldonh	return 0;
9087866Ssheldonh}
9187866Ssheldonh
9287866Ssheldonhstatic int
9387866Ssheldonhsmb_rap_parserpparam(const char *s, char **next, int *rlen)
9487866Ssheldonh{
9587866Ssheldonh	char *np;
9687866Ssheldonh	int len, m;
9787866Ssheldonh
9887866Ssheldonh	m = 1;
9987866Ssheldonh	switch (*s++) {
10087866Ssheldonh	    case 'e':
10187866Ssheldonh	    case 'h':
10287866Ssheldonh		len = 2;
10387866Ssheldonh		break;
10487866Ssheldonh	    case 'i':
10587866Ssheldonh		len = 4;
10687866Ssheldonh		break;
10787866Ssheldonh	    case 'g':
10887866Ssheldonh		len = 1;
10987866Ssheldonh		break;
11087866Ssheldonh	    default:
11187866Ssheldonh		return EINVAL;
11287866Ssheldonh	}
11387866Ssheldonh	if (isdigit(*s)) {
11487866Ssheldonh		len *= strtoul(s, &np, 10);
11587866Ssheldonh		s = np;
11687866Ssheldonh	}
11787866Ssheldonh	*rlen = len;
11887866Ssheldonh	*(const char**)next = s;
11987866Ssheldonh	return 0;
12087866Ssheldonh}
12187866Ssheldonh
12287866Ssheldonhstatic int
12387866Ssheldonhsmb_rap_parserpdata(const char *s, char **next, int *rlen)
12487866Ssheldonh{
12587866Ssheldonh	char *np;
12687866Ssheldonh	int len, m;
12787866Ssheldonh
12887866Ssheldonh	m = 1;
12987866Ssheldonh	switch (*s++) {
13087866Ssheldonh	    case 'B':
13187866Ssheldonh		len = 1;
13287866Ssheldonh		break;
13387866Ssheldonh	    case 'W':
13487866Ssheldonh		len = 2;
13587866Ssheldonh		break;
13687866Ssheldonh	    case 'D':
13787866Ssheldonh	    case 'O':
13887866Ssheldonh	    case 'z':
13987866Ssheldonh		len = 4;
14087866Ssheldonh		break;
14187866Ssheldonh	    default:
14287866Ssheldonh		return EINVAL;
14387866Ssheldonh	}
14487866Ssheldonh	if (isdigit(*s)) {
14587866Ssheldonh		len *= strtoul(s, &np, 10);
14687866Ssheldonh		s = np;
14787866Ssheldonh	}
14887866Ssheldonh	*rlen = len;
14987866Ssheldonh	*(const char**)next = s;
15087866Ssheldonh	return 0;
15187866Ssheldonh}
15287866Ssheldonh
15387866Ssheldonhstatic int
15487866Ssheldonhsmb_rap_rqparam_z(struct smb_rap *rap, const char *value)
15587866Ssheldonh{
15687866Ssheldonh	int len = strlen(value) + 1;
15787866Ssheldonh
15887866Ssheldonh	bcopy(value, rap->r_npbuf, len);
15987866Ssheldonh	rap->r_npbuf += len;
16087866Ssheldonh	rap->r_plen += len;
16187866Ssheldonh	return 0;
16287866Ssheldonh}
16387866Ssheldonh
16487866Ssheldonhstatic int
16587866Ssheldonhsmb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, long value)
16687866Ssheldonh{
16787866Ssheldonh	char *p = rap->r_npbuf;
16887866Ssheldonh	int len;
16987866Ssheldonh
17087866Ssheldonh	switch (ptype) {
17187866Ssheldonh	    case 'L':
17287866Ssheldonh	    case 'W':
17387866Ssheldonh		setwle(p, 0, value);
17487866Ssheldonh		len = 2;
17587866Ssheldonh		break;
17687866Ssheldonh	    case 'D':
17787866Ssheldonh		setdle(p, 0, value);
17887866Ssheldonh		len = 4;
17987866Ssheldonh		break;
18087866Ssheldonh	    case 'b':
18187866Ssheldonh		memset(p, value, plen);
18287866Ssheldonh		len = plen;
18387866Ssheldonh	    default:
18487866Ssheldonh		return EINVAL;
18587866Ssheldonh	}
18687866Ssheldonh	rap->r_npbuf += len;
18787866Ssheldonh	rap->r_plen += len;
18887866Ssheldonh	return 0;
18987866Ssheldonh}
19087866Ssheldonh
19187866Ssheldonhint
19287866Ssheldonhsmb_rap_create(int fn, const char *param, const char *data,
19387866Ssheldonh	struct smb_rap **rapp)
19487866Ssheldonh{
19587866Ssheldonh	struct smb_rap *rap;
19687866Ssheldonh	char *p;
19787866Ssheldonh	int plen, len;
19887866Ssheldonh
19987866Ssheldonh	rap = malloc(sizeof(*rap));
20087866Ssheldonh	if (rap == NULL)
201130737Sle		return ENOMEM;
20287866Ssheldonh	bzero(rap, sizeof(*rap));
20387866Ssheldonh	p = rap->r_sparam = rap->r_nparam = strdup(param);
20487866Ssheldonh	rap->r_sdata = rap->r_ndata = strdup(data);
20587866Ssheldonh	/*
20687866Ssheldonh	 * Calculate length of request parameter block
20787866Ssheldonh	 */
20887866Ssheldonh	len = 2 + strlen(param) + 1 + strlen(data) + 1;
20987866Ssheldonh
21087866Ssheldonh	while (*p) {
21187866Ssheldonh		if (smb_rap_parserqparam(p, &p, &plen) != 0)
21287866Ssheldonh			break;
21387866Ssheldonh		len += plen;
21487866Ssheldonh	}
21587866Ssheldonh	rap->r_pbuf = rap->r_npbuf = malloc(len);
21687866Ssheldonh	smb_rap_rqparam(rap, 'W', 1, fn);
21787866Ssheldonh	smb_rap_rqparam_z(rap, rap->r_sparam);
21887866Ssheldonh	smb_rap_rqparam_z(rap, rap->r_sdata);
21987866Ssheldonh	*rapp = rap;
22087866Ssheldonh	return 0;
22187866Ssheldonh}
22287866Ssheldonh
22387866Ssheldonhvoid
22487866Ssheldonhsmb_rap_done(struct smb_rap *rap)
22587866Ssheldonh{
22687866Ssheldonh	if (rap->r_sparam)
22787866Ssheldonh		free(rap->r_sparam);
22887866Ssheldonh	if (rap->r_sdata)
22987866Ssheldonh		free(rap->r_sdata);
23087866Ssheldonh	free(rap);
23187866Ssheldonh}
23287866Ssheldonh
23387866Ssheldonhint
23487866Ssheldonhsmb_rap_setNparam(struct smb_rap *rap, long value)
23587866Ssheldonh{
23687866Ssheldonh	char *p = rap->r_nparam;
23787866Ssheldonh	char ptype = *p;
23887866Ssheldonh	int error, plen;
23987866Ssheldonh
24087866Ssheldonh	error = smb_rap_parserqparam(p, &p, &plen);
24187866Ssheldonh	if (error)
24287866Ssheldonh		return error;
24387866Ssheldonh	switch (ptype) {
24487866Ssheldonh	    case 'L':
24587866Ssheldonh		rap->r_rcvbuflen = value;
24687866Ssheldonh		/* FALLTHROUGH */
24787866Ssheldonh	    case 'W':
24887866Ssheldonh	    case 'D':
24987866Ssheldonh	    case 'b':
25087866Ssheldonh		error = smb_rap_rqparam(rap, ptype, plen, value);
25187866Ssheldonh		break;
25287866Ssheldonh	    default:
25387866Ssheldonh		return EINVAL;
25487866Ssheldonh	}
25587866Ssheldonh	rap->r_nparam = p;
25687866Ssheldonh	return 0;
25787866Ssheldonh}
25887866Ssheldonh
25987866Ssheldonhint
26087866Ssheldonhsmb_rap_setPparam(struct smb_rap *rap, void *value)
26187866Ssheldonh{
26287866Ssheldonh	char *p = rap->r_nparam;
26387866Ssheldonh	char ptype = *p;
26487866Ssheldonh	int error, plen;
26587866Ssheldonh
26687866Ssheldonh	error = smb_rap_parserqparam(p, &p, &plen);
26787866Ssheldonh	if (error)
26887866Ssheldonh		return error;
26987866Ssheldonh	switch (ptype) {
27087866Ssheldonh	    case 'r':
27187866Ssheldonh		rap->r_rcvbuf = value;
27287866Ssheldonh		break;
27387866Ssheldonh	    default:
27487866Ssheldonh		return EINVAL;
27587866Ssheldonh	}
27687866Ssheldonh	rap->r_nparam = p;
27787866Ssheldonh	return 0;
27887866Ssheldonh}
27987866Ssheldonh
28087866Ssheldonhstatic int
28187866Ssheldonhsmb_rap_getNparam(struct smb_rap *rap, long *value)
28287866Ssheldonh{
28387866Ssheldonh	char *p = rap->r_nparam;
28487866Ssheldonh	char ptype = *p;
28587866Ssheldonh	int error, plen;
28687866Ssheldonh
28787866Ssheldonh	error = smb_rap_parserpparam(p, &p, &plen);
28887866Ssheldonh	if (error)
28987866Ssheldonh		return error;
29087866Ssheldonh	switch (ptype) {
29187866Ssheldonh	    case 'h':
292150312Simura		*value = le16toh(*(u_int16_t*)rap->r_npbuf);
29387866Ssheldonh		break;
29487866Ssheldonh	    default:
29587866Ssheldonh		return EINVAL;
29687866Ssheldonh	}
29787866Ssheldonh	rap->r_npbuf += plen;
29887866Ssheldonh	rap->r_nparam = p;
29987866Ssheldonh	return 0;
30087866Ssheldonh}
30187866Ssheldonh
30287866Ssheldonhint
30387866Ssheldonhsmb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
30487866Ssheldonh{
30587866Ssheldonh	u_int16_t *rp, conv;
30687866Ssheldonh	u_int32_t *p32;
30787866Ssheldonh	char *dp, *p = rap->r_nparam;
30887866Ssheldonh	char ptype;
30987866Ssheldonh	int error, rdatacnt, rparamcnt, entries, done, dlen;
31087866Ssheldonh
31187866Ssheldonh	rdatacnt = rap->r_rcvbuflen;
31287866Ssheldonh	rparamcnt = rap->r_plen;
31387866Ssheldonh	error = smb_t2_request(ctx, 0, 0, "\\PIPE\\LANMAN",
31487866Ssheldonh	    rap->r_plen, rap->r_pbuf,		/* int tparamcnt, void *tparam */
31587866Ssheldonh	    0, NULL,				/* int tdatacnt, void *tdata */
31687866Ssheldonh	    &rparamcnt, rap->r_pbuf,		/* rparamcnt, void *rparam */
31787866Ssheldonh	    &rdatacnt, rap->r_rcvbuf		/* int *rdatacnt, void *rdata */
31887866Ssheldonh	);
31987866Ssheldonh	if (error)
32087866Ssheldonh		return error;
32187866Ssheldonh	rp = (u_int16_t*)rap->r_pbuf;
322150312Simura	rap->r_result = le16toh(*rp++);
323150312Simura	conv = le16toh(*rp++);
32487866Ssheldonh	rap->r_npbuf = (char*)rp;
32587866Ssheldonh	rap->r_entries = entries = 0;
32687866Ssheldonh	done = 0;
32787866Ssheldonh	while (!done && *p) {
32887866Ssheldonh		ptype = *p;
32987866Ssheldonh		switch (ptype) {
33087866Ssheldonh		    case 'e':
331150312Simura			rap->r_entries = entries = le16toh(*(u_int16_t*)rap->r_npbuf);
33287866Ssheldonh			rap->r_npbuf += 2;
33387866Ssheldonh			p++;
33487866Ssheldonh			break;
33587866Ssheldonh		    default:
33687866Ssheldonh			done = 1;
33787866Ssheldonh		}
33887866Ssheldonh/*		error = smb_rap_parserpparam(p, &p, &plen);
33987866Ssheldonh		if (error) {
34087866Ssheldonh			smb_error("reply parameter mismath %s", 0, p);
34187866Ssheldonh			return EBADRPC;
34287866Ssheldonh		}*/
34387866Ssheldonh	}
34487866Ssheldonh	rap->r_nparam = p;
34587866Ssheldonh	/*
34687866Ssheldonh	 * In general, unpacking entries we may need to relocate
34787866Ssheldonh	 * entries for proper alingning. For now use them as is.
34887866Ssheldonh	 */
34987866Ssheldonh	dp = rap->r_rcvbuf;
35087866Ssheldonh	while (entries--) {
35187866Ssheldonh		p = rap->r_sdata;
35287866Ssheldonh		while (*p) {
35387866Ssheldonh			ptype = *p;
35487866Ssheldonh			error = smb_rap_parserpdata(p, &p, &dlen);
35587866Ssheldonh			if (error) {
35687866Ssheldonh				smb_error("reply data mismath %s", 0, p);
35787866Ssheldonh				return EBADRPC;
35887866Ssheldonh			}
35987866Ssheldonh			switch (ptype) {
36087866Ssheldonh			    case 'z':
36187866Ssheldonh				p32 = (u_int32_t*)dp;
36287866Ssheldonh				*p32 = (*p32 & 0xffff) - conv;
36387866Ssheldonh				break;
36487866Ssheldonh			}
36587866Ssheldonh			dp += dlen;
36687866Ssheldonh		}
36787866Ssheldonh	}
36887866Ssheldonh	return error;
36987866Ssheldonh}
37087866Ssheldonh
37187866Ssheldonhint
37287866Ssheldonhsmb_rap_error(struct smb_rap *rap, int error)
37387866Ssheldonh{
37487866Ssheldonh	if (error)
37587866Ssheldonh		return error;
37687866Ssheldonh	if (rap->r_result == 0)
37787866Ssheldonh		return 0;
37887866Ssheldonh	return rap->r_result | SMB_RAP_ERROR;
37987866Ssheldonh}
38087866Ssheldonh
38187866Ssheldonhint
38287866Ssheldonhsmb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
38387866Ssheldonh	int cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
38487866Ssheldonh{
38587866Ssheldonh	struct smb_rap *rap;
38687866Ssheldonh	long lval;
38787866Ssheldonh	int error;
38887866Ssheldonh
38987866Ssheldonh	error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
39087866Ssheldonh	if (error)
39187866Ssheldonh		return error;
39287866Ssheldonh	smb_rap_setNparam(rap, sLevel);		/* W - sLevel */
39387866Ssheldonh	smb_rap_setPparam(rap, pbBuffer);	/* r - pbBuffer */
39487866Ssheldonh	smb_rap_setNparam(rap, cbBuffer);	/* L - cbBuffer */
39587866Ssheldonh	error = smb_rap_request(rap, ctx);
39687866Ssheldonh	if (error == 0) {
39787866Ssheldonh		*pcEntriesRead = rap->r_entries;
39887866Ssheldonh		error = smb_rap_getNparam(rap, &lval);
39987866Ssheldonh		*pcTotalAvail = lval;
40087866Ssheldonh	}
40187866Ssheldonh	error = smb_rap_error(rap, error);
40287866Ssheldonh	smb_rap_done(rap);
40387866Ssheldonh	return error;
40487866Ssheldonh}
405