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/errno.h> 39 #include <sys/stat.h> 40 #include <ctype.h> 41 #include <err.h> 42 #include <stdio.h> 43 #include <unistd.h> 44 #include <string.h> 45 #include <stdlib.h> 46 #include <sysexits.h> 47 48 #include <sys/mchain.h> 49 50 #include <netsmb/smb_lib.h> 51 #include <netsmb/smb_conn.h> 52 #include <netsmb/smb_rap.h> 53 54 /*#include <sys/ioctl.h>*/ 55 56 static int 57 smb_rap_parserqparam(const char *s, char **next, int *rlen) 58 { 59 char *np; 60 int len, m; 61 62 m = 1; 63 switch (*s++) { 64 case 'L': 65 case 'T': 66 case 'W': 67 len = 2; 68 break; 69 case 'D': 70 case 'O': 71 len = 4; 72 break; 73 case 'b': 74 case 'F': 75 len = 1; 76 break; 77 case 'r': 78 case 's': 79 len = 0; 80 break; 81 default: 82 return EINVAL; 83 } 84 if (isdigit(*s)) { 85 len *= strtoul(s, &np, 10); 86 s = np; 87 } 88 *rlen = len; 89 *(const char**)next = s; 90 return 0; 91 } 92 93 static int 94 smb_rap_parserpparam(const char *s, char **next, int *rlen) 95 { 96 char *np; 97 int len, m; 98 99 m = 1; 100 switch (*s++) { 101 case 'e': 102 case 'h': 103 len = 2; 104 break; 105 case 'i': 106 len = 4; 107 break; 108 case 'g': 109 len = 1; 110 break; 111 default: 112 return EINVAL; 113 } 114 if (isdigit(*s)) { 115 len *= strtoul(s, &np, 10); 116 s = np; 117 } 118 *rlen = len; 119 *(const char**)next = s; 120 return 0; 121 } 122 123 static int 124 smb_rap_parserpdata(const char *s, char **next, int *rlen) 125 { 126 char *np; 127 int len, m; 128 129 m = 1; 130 switch (*s++) { 131 case 'B': 132 len = 1; 133 break; 134 case 'W': 135 len = 2; 136 break; 137 case 'D': 138 case 'O': 139 case 'z': 140 len = 4; 141 break; 142 default: 143 return EINVAL; 144 } 145 if (isdigit(*s)) { 146 len *= strtoul(s, &np, 10); 147 s = np; 148 } 149 *rlen = len; 150 *(const char**)next = s; 151 return 0; 152 } 153 154 static int 155 smb_rap_rqparam_z(struct smb_rap *rap, const char *value) 156 { 157 int len = strlen(value) + 1; 158 159 bcopy(value, rap->r_npbuf, len); 160 rap->r_npbuf += len; 161 rap->r_plen += len; 162 return 0; 163 } 164 165 static int 166 smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, long value) 167 { 168 char *p = rap->r_npbuf; 169 int len; 170 171 switch (ptype) { 172 case 'L': 173 case 'W': 174 setwle(p, 0, value); 175 len = 2; 176 break; 177 case 'D': 178 setdle(p, 0, value); 179 len = 4; 180 break; 181 case 'b': 182 memset(p, value, plen); 183 len = plen; 184 default: 185 return EINVAL; 186 } 187 rap->r_npbuf += len; 188 rap->r_plen += len; 189 return 0; 190 } 191 192 int 193 smb_rap_create(int fn, const char *param, const char *data, 194 struct smb_rap **rapp) 195 { 196 struct smb_rap *rap; 197 char *p; 198 int plen, len; 199 200 rap = malloc(sizeof(*rap)); 201 if (rap == NULL) 202 return ENOMEM; 203 bzero(rap, sizeof(*rap)); 204 p = rap->r_sparam = rap->r_nparam = strdup(param); 205 rap->r_sdata = rap->r_ndata = strdup(data); 206 /* 207 * Calculate length of request parameter block 208 */ 209 len = 2 + strlen(param) + 1 + strlen(data) + 1; 210 211 while (*p) { 212 if (smb_rap_parserqparam(p, &p, &plen) != 0) 213 break; 214 len += plen; 215 } 216 rap->r_pbuf = rap->r_npbuf = malloc(len); 217 smb_rap_rqparam(rap, 'W', 1, fn); 218 smb_rap_rqparam_z(rap, rap->r_sparam); 219 smb_rap_rqparam_z(rap, rap->r_sdata); 220 *rapp = rap; 221 return 0; 222 } 223 224 void 225 smb_rap_done(struct smb_rap *rap) 226 { 227 if (rap->r_sparam) 228 free(rap->r_sparam); 229 if (rap->r_sdata) 230 free(rap->r_sdata); 231 free(rap); 232 } 233 234 int 235 smb_rap_setNparam(struct smb_rap *rap, long value) 236 { 237 char *p = rap->r_nparam; 238 char ptype = *p; 239 int error, plen; 240 241 error = smb_rap_parserqparam(p, &p, &plen); 242 if (error) 243 return error; 244 switch (ptype) { 245 case 'L': 246 rap->r_rcvbuflen = value; 247 /* FALLTHROUGH */ 248 case 'W': 249 case 'D': 250 case 'b': 251 error = smb_rap_rqparam(rap, ptype, plen, value); 252 break; 253 default: 254 return EINVAL; 255 } 256 rap->r_nparam = p; 257 return 0; 258 } 259 260 int 261 smb_rap_setPparam(struct smb_rap *rap, void *value) 262 { 263 char *p = rap->r_nparam; 264 char ptype = *p; 265 int error, plen; 266 267 error = smb_rap_parserqparam(p, &p, &plen); 268 if (error) 269 return error; 270 switch (ptype) { 271 case 'r': 272 rap->r_rcvbuf = value; 273 break; 274 default: 275 return EINVAL; 276 } 277 rap->r_nparam = p; 278 return 0; 279 } 280 281 static int 282 smb_rap_getNparam(struct smb_rap *rap, long *value) 283 { 284 char *p = rap->r_nparam; 285 char ptype = *p; 286 int error, plen; 287 288 error = smb_rap_parserpparam(p, &p, &plen); 289 if (error) 290 return error; 291 switch (ptype) { 292 case 'h': 293 *value = letohs(*(u_int16_t*)rap->r_npbuf); 294 break; 295 default: 296 return EINVAL; 297 } 298 rap->r_npbuf += plen; 299 rap->r_nparam = p; 300 return 0; 301 } 302 303 int 304 smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx) 305 { 306 u_int16_t *rp, conv; 307 u_int32_t *p32; 308 char *dp, *p = rap->r_nparam; 309 char ptype; 310 int error, rdatacnt, rparamcnt, entries, done, dlen; 311 312 rdatacnt = rap->r_rcvbuflen; 313 rparamcnt = rap->r_plen; 314 error = smb_t2_request(ctx, 0, 0, "\\PIPE\\LANMAN", 315 rap->r_plen, rap->r_pbuf, /* int tparamcnt, void *tparam */ 316 0, NULL, /* int tdatacnt, void *tdata */ 317 &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */ 318 &rdatacnt, rap->r_rcvbuf /* int *rdatacnt, void *rdata */ 319 ); 320 if (error) 321 return error; 322 rp = (u_int16_t*)rap->r_pbuf; 323 rap->r_result = letohs(*rp++); 324 conv = letohs(*rp++); 325 rap->r_npbuf = (char*)rp; 326 rap->r_entries = entries = 0; 327 done = 0; 328 while (!done && *p) { 329 ptype = *p; 330 switch (ptype) { 331 case 'e': 332 rap->r_entries = entries = letohs(*(u_int16_t*)rap->r_npbuf); 333 rap->r_npbuf += 2; 334 p++; 335 break; 336 default: 337 done = 1; 338 } 339 /* error = smb_rap_parserpparam(p, &p, &plen); 340 if (error) { 341 smb_error("reply parameter mismath %s", 0, p); 342 return EBADRPC; 343 }*/ 344 } 345 rap->r_nparam = p; 346 /* 347 * In general, unpacking entries we may need to relocate 348 * entries for proper alingning. For now use them as is. 349 */ 350 dp = rap->r_rcvbuf; 351 while (entries--) { 352 p = rap->r_sdata; 353 while (*p) { 354 ptype = *p; 355 error = smb_rap_parserpdata(p, &p, &dlen); 356 if (error) { 357 smb_error("reply data mismath %s", 0, p); 358 return EBADRPC; 359 } 360 switch (ptype) { 361 case 'z': 362 p32 = (u_int32_t*)dp; 363 *p32 = (*p32 & 0xffff) - conv; 364 break; 365 } 366 dp += dlen; 367 } 368 } 369 return error; 370 } 371 372 int 373 smb_rap_error(struct smb_rap *rap, int error) 374 { 375 if (error) 376 return error; 377 if (rap->r_result == 0) 378 return 0; 379 return rap->r_result | SMB_RAP_ERROR; 380 } 381 382 int 383 smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer, 384 int cbBuffer, int *pcEntriesRead, int *pcTotalAvail) 385 { 386 struct smb_rap *rap; 387 long lval; 388 int error; 389 390 error = smb_rap_create(0, "WrLeh", "B13BWz", &rap); 391 if (error) 392 return error; 393 smb_rap_setNparam(rap, sLevel); /* W - sLevel */ 394 smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */ 395 smb_rap_setNparam(rap, cbBuffer); /* L - cbBuffer */ 396 error = smb_rap_request(rap, ctx); 397 if (error == 0) { 398 *pcEntriesRead = rap->r_entries; 399 error = smb_rap_getNparam(rap, &lval); 400 *pcTotalAvail = lval; 401 } 402 error = smb_rap_error(rap, error); 403 smb_rap_done(rap); 404 return error; 405 } 406