1*6007Sthurlow /* 2*6007Sthurlow * Copyright (c) 2000, Boris Popov 3*6007Sthurlow * All rights reserved. 4*6007Sthurlow * 5*6007Sthurlow * Redistribution and use in source and binary forms, with or without 6*6007Sthurlow * modification, are permitted provided that the following conditions 7*6007Sthurlow * are met: 8*6007Sthurlow * 1. Redistributions of source code must retain the above copyright 9*6007Sthurlow * notice, this list of conditions and the following disclaimer. 10*6007Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 11*6007Sthurlow * notice, this list of conditions and the following disclaimer in the 12*6007Sthurlow * documentation and/or other materials provided with the distribution. 13*6007Sthurlow * 3. All advertising materials mentioning features or use of this software 14*6007Sthurlow * must display the following acknowledgement: 15*6007Sthurlow * This product includes software developed by Boris Popov. 16*6007Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 17*6007Sthurlow * may be used to endorse or promote products derived from this software 18*6007Sthurlow * without specific prior written permission. 19*6007Sthurlow * 20*6007Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21*6007Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22*6007Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23*6007Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24*6007Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25*6007Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26*6007Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27*6007Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28*6007Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29*6007Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30*6007Sthurlow * SUCH DAMAGE. 31*6007Sthurlow * 32*6007Sthurlow * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $ 33*6007Sthurlow * 34*6007Sthurlow * This is very simple implementation of RAP protocol. 35*6007Sthurlow */ 36*6007Sthurlow 37*6007Sthurlow #pragma ident "%Z%%M% %I% %E% SMI" 38*6007Sthurlow 39*6007Sthurlow #include <sys/param.h> 40*6007Sthurlow #include <sys/errno.h> 41*6007Sthurlow #include <sys/stat.h> 42*6007Sthurlow #include <sys/isa_defs.h> 43*6007Sthurlow 44*6007Sthurlow #include <ctype.h> 45*6007Sthurlow #include <stdio.h> 46*6007Sthurlow #include <unistd.h> 47*6007Sthurlow #include <strings.h> 48*6007Sthurlow #include <stdlib.h> 49*6007Sthurlow #include <libintl.h> 50*6007Sthurlow #include <sysexits.h> 51*6007Sthurlow 52*6007Sthurlow #include <netsmb/mchain.h> 53*6007Sthurlow #include <netsmb/smb_lib.h> 54*6007Sthurlow #include <netsmb/smb_rap.h> 55*6007Sthurlow 56*6007Sthurlow static int 57*6007Sthurlow smb_rap_parserqparam(const char *s, char **next, int *rlen) 58*6007Sthurlow { 59*6007Sthurlow char *np; 60*6007Sthurlow int len; 61*6007Sthurlow 62*6007Sthurlow switch (*s++) { 63*6007Sthurlow case 'L': 64*6007Sthurlow case 'T': 65*6007Sthurlow case 'W': 66*6007Sthurlow len = 2; 67*6007Sthurlow break; 68*6007Sthurlow case 'D': 69*6007Sthurlow case 'O': 70*6007Sthurlow len = 4; 71*6007Sthurlow break; 72*6007Sthurlow case 'b': 73*6007Sthurlow case 'F': 74*6007Sthurlow len = 1; 75*6007Sthurlow break; 76*6007Sthurlow case 'r': 77*6007Sthurlow case 's': 78*6007Sthurlow len = 0; 79*6007Sthurlow break; 80*6007Sthurlow default: 81*6007Sthurlow return (EINVAL); 82*6007Sthurlow } 83*6007Sthurlow if (isdigit(*s)) { 84*6007Sthurlow len *= strtoul(s, &np, 10); 85*6007Sthurlow s = np; 86*6007Sthurlow } 87*6007Sthurlow *rlen = len; 88*6007Sthurlow *(const char **)next = s; 89*6007Sthurlow return (0); 90*6007Sthurlow } 91*6007Sthurlow 92*6007Sthurlow static int 93*6007Sthurlow smb_rap_parserpparam(const char *s, char **next, int *rlen) 94*6007Sthurlow { 95*6007Sthurlow char *np; 96*6007Sthurlow int len = 0; 97*6007Sthurlow 98*6007Sthurlow switch (*s++) { 99*6007Sthurlow case 'e': 100*6007Sthurlow case 'h': 101*6007Sthurlow len = 2; 102*6007Sthurlow break; 103*6007Sthurlow case 'i': 104*6007Sthurlow len = 4; 105*6007Sthurlow break; 106*6007Sthurlow case 'g': 107*6007Sthurlow len = 1; 108*6007Sthurlow break; 109*6007Sthurlow default: 110*6007Sthurlow return (EINVAL); 111*6007Sthurlow } 112*6007Sthurlow if (isdigit(*s)) { 113*6007Sthurlow len *= strtoul(s, &np, 10); 114*6007Sthurlow s = np; 115*6007Sthurlow } 116*6007Sthurlow *rlen = len; 117*6007Sthurlow *(const char **)next = s; 118*6007Sthurlow return (0); 119*6007Sthurlow } 120*6007Sthurlow 121*6007Sthurlow static int 122*6007Sthurlow smb_rap_parserpdata(const char *s, char **next, int *rlen) 123*6007Sthurlow { 124*6007Sthurlow char *np; 125*6007Sthurlow int len; 126*6007Sthurlow 127*6007Sthurlow switch (*s++) { 128*6007Sthurlow case 'B': 129*6007Sthurlow len = 1; 130*6007Sthurlow break; 131*6007Sthurlow case 'W': 132*6007Sthurlow len = 2; 133*6007Sthurlow break; 134*6007Sthurlow case 'D': 135*6007Sthurlow case 'O': 136*6007Sthurlow case 'z': 137*6007Sthurlow len = 4; 138*6007Sthurlow break; 139*6007Sthurlow default: 140*6007Sthurlow return (EINVAL); 141*6007Sthurlow } 142*6007Sthurlow if (isdigit(*s)) { 143*6007Sthurlow len *= strtoul(s, &np, 10); 144*6007Sthurlow s = np; 145*6007Sthurlow } 146*6007Sthurlow *rlen = len; 147*6007Sthurlow *(const char **)next = s; 148*6007Sthurlow return (0); 149*6007Sthurlow } 150*6007Sthurlow 151*6007Sthurlow static int 152*6007Sthurlow smb_rap_rqparam_z(struct smb_rap *rap, const char *value) 153*6007Sthurlow { 154*6007Sthurlow int len = strlen(value) + 1; 155*6007Sthurlow 156*6007Sthurlow bcopy(value, rap->r_npbuf, len); 157*6007Sthurlow rap->r_npbuf += len; 158*6007Sthurlow rap->r_plen += len; 159*6007Sthurlow return (0); 160*6007Sthurlow } 161*6007Sthurlow 162*6007Sthurlow /* 163*6007Sthurlow * Marshal RAP request parameters. 164*6007Sthurlow * Note: value is in host order. 165*6007Sthurlow */ 166*6007Sthurlow static int 167*6007Sthurlow smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value) 168*6007Sthurlow { 169*6007Sthurlow char *p = rap->r_npbuf; 170*6007Sthurlow int len = 0; 171*6007Sthurlow uint_t uv = (uint_t)value; 172*6007Sthurlow 173*6007Sthurlow switch (ptype) { 174*6007Sthurlow case 'L': 175*6007Sthurlow case 'W': 176*6007Sthurlow /* LINTED */ 177*6007Sthurlow setwle(p, 0, uv); 178*6007Sthurlow len = 2; 179*6007Sthurlow break; 180*6007Sthurlow case 'D': 181*6007Sthurlow /* LINTED */ 182*6007Sthurlow setdle(p, 0, uv); 183*6007Sthurlow len = 4; 184*6007Sthurlow break; 185*6007Sthurlow case 'b': 186*6007Sthurlow memset(p, uv, plen); 187*6007Sthurlow len = plen; 188*6007Sthurlow default: 189*6007Sthurlow return (EINVAL); 190*6007Sthurlow } 191*6007Sthurlow rap->r_npbuf += len; 192*6007Sthurlow rap->r_plen += len; 193*6007Sthurlow return (0); 194*6007Sthurlow } 195*6007Sthurlow 196*6007Sthurlow int 197*6007Sthurlow smb_rap_create(int fn, const char *param, const char *data, 198*6007Sthurlow struct smb_rap **rapp) 199*6007Sthurlow { 200*6007Sthurlow struct smb_rap *rap; 201*6007Sthurlow char *p; 202*6007Sthurlow int plen = 0, len = 0; 203*6007Sthurlow int i; 204*6007Sthurlow 205*6007Sthurlow rap = malloc(sizeof (*rap)); 206*6007Sthurlow if (rap == NULL) 207*6007Sthurlow return (ENOMEM); 208*6007Sthurlow bzero(rap, sizeof (*rap)); 209*6007Sthurlow p = rap->r_sparam = rap->r_nparam = strdup(param); 210*6007Sthurlow rap->r_sdata = rap->r_ndata = strdup(data); 211*6007Sthurlow 212*6007Sthurlow /* 213*6007Sthurlow * Calculate length of request parameter block 214*6007Sthurlow */ 215*6007Sthurlow len = 2 + strlen(param) + 1 + strlen(data) + 1; 216*6007Sthurlow while (*p) { 217*6007Sthurlow if (smb_rap_parserqparam(p, &p, &plen) != 0) 218*6007Sthurlow break; 219*6007Sthurlow len += plen; 220*6007Sthurlow } 221*6007Sthurlow rap->r_pbuf = rap->r_npbuf = malloc(len); 222*6007Sthurlow smb_rap_rqparam(rap, 'W', 1, fn); 223*6007Sthurlow smb_rap_rqparam_z(rap, rap->r_sparam); 224*6007Sthurlow smb_rap_rqparam_z(rap, rap->r_sdata); 225*6007Sthurlow *rapp = rap; 226*6007Sthurlow return (0); 227*6007Sthurlow } 228*6007Sthurlow 229*6007Sthurlow void 230*6007Sthurlow smb_rap_done(struct smb_rap *rap) 231*6007Sthurlow { 232*6007Sthurlow if (rap->r_sparam) 233*6007Sthurlow free(rap->r_sparam); 234*6007Sthurlow if (rap->r_sdata) 235*6007Sthurlow free(rap->r_sdata); 236*6007Sthurlow if (rap->r_pbuf) 237*6007Sthurlow free(rap->r_pbuf); 238*6007Sthurlow #ifdef NOTYETDEFINED 239*6007Sthurlow if (rap->r_npbuf) 240*6007Sthurlow free(rap->r_npbuf); 241*6007Sthurlow if (rap->r_dbuf) 242*6007Sthurlow free(rap->r_dbuf); 243*6007Sthurlow if (rap->r_rcvbuf) 244*6007Sthurlow free(rap->r_rcvbuf); 245*6007Sthurlow #endif 246*6007Sthurlow free(rap); 247*6007Sthurlow } 248*6007Sthurlow 249*6007Sthurlow int 250*6007Sthurlow smb_rap_setNparam(struct smb_rap *rap, int value) 251*6007Sthurlow { 252*6007Sthurlow char *p = rap->r_nparam; 253*6007Sthurlow char ptype = *p; 254*6007Sthurlow int error, plen; 255*6007Sthurlow 256*6007Sthurlow error = smb_rap_parserqparam(p, &p, &plen); 257*6007Sthurlow if (error) 258*6007Sthurlow return (error); 259*6007Sthurlow switch (ptype) { 260*6007Sthurlow case 'L': 261*6007Sthurlow rap->r_rcvbuflen = value; 262*6007Sthurlow /* FALLTHROUGH */ 263*6007Sthurlow case 'W': 264*6007Sthurlow case 'D': 265*6007Sthurlow case 'b': 266*6007Sthurlow error = smb_rap_rqparam(rap, ptype, plen, value); 267*6007Sthurlow break; 268*6007Sthurlow default: 269*6007Sthurlow return (EINVAL); 270*6007Sthurlow } 271*6007Sthurlow rap->r_nparam = p; 272*6007Sthurlow return (0); 273*6007Sthurlow } 274*6007Sthurlow 275*6007Sthurlow int 276*6007Sthurlow smb_rap_setPparam(struct smb_rap *rap, void *value) 277*6007Sthurlow { 278*6007Sthurlow char *p = rap->r_nparam; 279*6007Sthurlow char ptype = *p; 280*6007Sthurlow int error, plen; 281*6007Sthurlow 282*6007Sthurlow error = smb_rap_parserqparam(p, &p, &plen); 283*6007Sthurlow if (error) 284*6007Sthurlow return (error); 285*6007Sthurlow switch (ptype) { 286*6007Sthurlow case 'r': 287*6007Sthurlow rap->r_rcvbuf = value; 288*6007Sthurlow break; 289*6007Sthurlow default: 290*6007Sthurlow return (EINVAL); 291*6007Sthurlow } 292*6007Sthurlow rap->r_nparam = p; 293*6007Sthurlow return (0); 294*6007Sthurlow } 295*6007Sthurlow 296*6007Sthurlow static int 297*6007Sthurlow smb_rap_getNparam(struct smb_rap *rap, long *value) 298*6007Sthurlow { 299*6007Sthurlow char *p = rap->r_nparam; 300*6007Sthurlow char ptype = *p; 301*6007Sthurlow int error, plen; 302*6007Sthurlow uint16_t *te; 303*6007Sthurlow 304*6007Sthurlow error = smb_rap_parserpparam(p, &p, &plen); 305*6007Sthurlow if (error) 306*6007Sthurlow return (error); 307*6007Sthurlow switch (ptype) { 308*6007Sthurlow case 'h': 309*6007Sthurlow /* LINTED */ 310*6007Sthurlow te = (uint16_t *)rap->r_npbuf; 311*6007Sthurlow *value = letohs(*te); 312*6007Sthurlow break; 313*6007Sthurlow default: 314*6007Sthurlow return (EINVAL); 315*6007Sthurlow } 316*6007Sthurlow rap->r_npbuf += plen; 317*6007Sthurlow rap->r_nparam = p; 318*6007Sthurlow return (0); 319*6007Sthurlow } 320*6007Sthurlow 321*6007Sthurlow int 322*6007Sthurlow smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx) 323*6007Sthurlow { 324*6007Sthurlow uint16_t *rp, conv, *tmp; 325*6007Sthurlow uint32_t *p32, ps1; 326*6007Sthurlow char *dp, *p = rap->r_nparam; 327*6007Sthurlow char ptype; 328*6007Sthurlow int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow, i; 329*6007Sthurlow 330*6007Sthurlow rdatacnt = rap->r_rcvbuflen; 331*6007Sthurlow rparamcnt = rap->r_plen; 332*6007Sthurlow error = smb_t2_request(ctx, 0, NULL, "\\PIPE\\LANMAN", 333*6007Sthurlow rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */ 334*6007Sthurlow 0, NULL, /* int tdatacnt, void *tdata */ 335*6007Sthurlow &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */ 336*6007Sthurlow &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */ 337*6007Sthurlow &buffer_oflow); 338*6007Sthurlow if (error) 339*6007Sthurlow return (error); 340*6007Sthurlow 341*6007Sthurlow /* LINTED */ 342*6007Sthurlow rp = (uint16_t *)rap->r_pbuf; 343*6007Sthurlow 344*6007Sthurlow /* 345*6007Sthurlow * Note: First is a "LanMan API" error code. 346*6007Sthurlow * See: usr/src/uts/common/smbsrv/lmerr.h 347*6007Sthurlow */ 348*6007Sthurlow if (rparamcnt < 2) 349*6007Sthurlow return (EBADRPC); 350*6007Sthurlow rap->r_result = letohs(*rp); 351*6007Sthurlow rp++; rparamcnt -= 2; 352*6007Sthurlow 353*6007Sthurlow if (rap->r_result != 0) { 354*6007Sthurlow /* 355*6007Sthurlow * Could also return zero and let the caller 356*6007Sthurlow * come get r_result via smb_rap_error(), 357*6007Sthurlow * but in case they dont... 358*6007Sthurlow */ 359*6007Sthurlow return (rap->r_result | SMB_RAP_ERROR); 360*6007Sthurlow } 361*6007Sthurlow 362*6007Sthurlow if (rparamcnt < 2) 363*6007Sthurlow return (EBADRPC); 364*6007Sthurlow conv = letohs(*rp); 365*6007Sthurlow rp++; rparamcnt -= 2; 366*6007Sthurlow 367*6007Sthurlow rap->r_npbuf = (char *)rp; 368*6007Sthurlow rap->r_entries = entries = 0; 369*6007Sthurlow /* Save the returned data length */ 370*6007Sthurlow rap->r_rcvbuflen = rdatacnt; 371*6007Sthurlow done = 0; 372*6007Sthurlow 373*6007Sthurlow while (!done && *p) { 374*6007Sthurlow ptype = *p; 375*6007Sthurlow switch (ptype) { 376*6007Sthurlow case 'e': 377*6007Sthurlow if (rparamcnt < 2) 378*6007Sthurlow return (EBADRPC); 379*6007Sthurlow /* LINTED */ 380*6007Sthurlow tmp = (uint16_t *)rap->r_npbuf; 381*6007Sthurlow rap->r_entries = entries = letohs(*tmp); 382*6007Sthurlow rap->r_npbuf += 2; 383*6007Sthurlow rparamcnt -= 2; 384*6007Sthurlow p++; 385*6007Sthurlow break; 386*6007Sthurlow default: 387*6007Sthurlow done = 1; 388*6007Sthurlow } 389*6007Sthurlow #if 0 /* commented out in Darwin. Why? */ 390*6007Sthurlow error = smb_rap_parserpparam(p, &p, &plen); 391*6007Sthurlow if (error) { 392*6007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 393*6007Sthurlow "reply parameter mismatch %s"), 0, p); 394*6007Sthurlow return (EBADRPC); 395*6007Sthurlow } 396*6007Sthurlow #endif 397*6007Sthurlow } 398*6007Sthurlow rap->r_nparam = p; 399*6007Sthurlow /* 400*6007Sthurlow * In general, unpacking entries we may need to relocate 401*6007Sthurlow * entries for proper aligning. For now use them as is. 402*6007Sthurlow */ 403*6007Sthurlow dp = rap->r_rcvbuf; 404*6007Sthurlow while (entries--) { 405*6007Sthurlow p = rap->r_sdata; 406*6007Sthurlow while (*p) { 407*6007Sthurlow ptype = *p; 408*6007Sthurlow error = smb_rap_parserpdata(p, &p, &dlen); 409*6007Sthurlow if (error) { 410*6007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 411*6007Sthurlow "reply data mismatch %s"), 0, p); 412*6007Sthurlow return (EBADRPC); 413*6007Sthurlow } 414*6007Sthurlow if (rdatacnt < dlen) 415*6007Sthurlow return (EBADRPC); 416*6007Sthurlow switch (ptype) { 417*6007Sthurlow case 'z': 418*6007Sthurlow /* LINTED */ 419*6007Sthurlow p32 = (uint32_t *)dp; 420*6007Sthurlow *p32 = (letohl(*p32) & 0xffff) - conv; 421*6007Sthurlow break; 422*6007Sthurlow } 423*6007Sthurlow dp += dlen; 424*6007Sthurlow rdatacnt -= dlen; 425*6007Sthurlow } 426*6007Sthurlow } 427*6007Sthurlow return (error); 428*6007Sthurlow } 429*6007Sthurlow 430*6007Sthurlow int 431*6007Sthurlow smb_rap_error(struct smb_rap *rap, int error) 432*6007Sthurlow { 433*6007Sthurlow if (error) 434*6007Sthurlow return (error); 435*6007Sthurlow if (rap->r_result == 0) 436*6007Sthurlow return (0); 437*6007Sthurlow return (rap->r_result | SMB_RAP_ERROR); 438*6007Sthurlow } 439*6007Sthurlow 440*6007Sthurlow /* todo: move this function to libnetapi */ 441*6007Sthurlow int 442*6007Sthurlow smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer, 443*6007Sthurlow int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail) 444*6007Sthurlow { 445*6007Sthurlow struct smb_rap *rap; 446*6007Sthurlow long lval = -1; 447*6007Sthurlow int error; 448*6007Sthurlow char *pass; 449*6007Sthurlow int i; 450*6007Sthurlow 451*6007Sthurlow error = smb_rap_create(0, "WrLeh", "B13BWz", &rap); 452*6007Sthurlow if (error) 453*6007Sthurlow return (error); 454*6007Sthurlow smb_rap_setNparam(rap, sLevel); /* W - sLevel */ 455*6007Sthurlow smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */ 456*6007Sthurlow smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */ 457*6007Sthurlow error = smb_rap_request(rap, ctx); 458*6007Sthurlow if (error == 0) { 459*6007Sthurlow *pcEntriesRead = rap->r_entries; 460*6007Sthurlow error = smb_rap_getNparam(rap, &lval); 461*6007Sthurlow *pcTotalAvail = lval; 462*6007Sthurlow /* Copy the data length into the IN/OUT variable. */ 463*6007Sthurlow *cbBuffer = rap->r_rcvbuflen; 464*6007Sthurlow } 465*6007Sthurlow error = smb_rap_error(rap, error); 466*6007Sthurlow smb_rap_done(rap); 467*6007Sthurlow return (error); 468*6007Sthurlow } 469