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