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