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.5 2004/12/13 00:25:23 lindak Exp $ 33 * 34 * This is very simple implementation of RAP protocol. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/errno.h> 39 #include <sys/stat.h> 40 #include <sys/isa_defs.h> 41 42 #include <ctype.h> 43 #include <stdio.h> 44 #include <unistd.h> 45 #include <strings.h> 46 #include <stdlib.h> 47 #include <libintl.h> 48 #include <sysexits.h> 49 50 #include <netsmb/mchain.h> 51 #include <netsmb/smb_lib.h> 52 #include <netsmb/smb_rap.h> 53 #include "private.h" 54 55 static int 56 smb_rap_parserqparam(const char *s, char **next, int *rlen) 57 { 58 char *np; 59 int len; 60 61 switch (*s++) { 62 case 'L': 63 case 'T': 64 case 'W': 65 len = 2; 66 break; 67 case 'D': 68 case 'O': 69 len = 4; 70 break; 71 case 'b': 72 case 'F': 73 len = 1; 74 break; 75 case 'r': 76 case 's': 77 len = 0; 78 break; 79 default: 80 return (EINVAL); 81 } 82 if (isdigit(*s)) { 83 len *= strtoul(s, &np, 10); 84 s = np; 85 } 86 *rlen = len; 87 *(const char **)next = s; 88 return (0); 89 } 90 91 static int 92 smb_rap_parserpparam(const char *s, char **next, int *rlen) 93 { 94 char *np; 95 int len = 0; 96 97 switch (*s++) { 98 case 'e': 99 case 'h': 100 len = 2; 101 break; 102 case 'i': 103 len = 4; 104 break; 105 case 'g': 106 len = 1; 107 break; 108 default: 109 return (EINVAL); 110 } 111 if (isdigit(*s)) { 112 len *= strtoul(s, &np, 10); 113 s = np; 114 } 115 *rlen = len; 116 *(const char **)next = s; 117 return (0); 118 } 119 120 static int 121 smb_rap_parserpdata(const char *s, char **next, int *rlen) 122 { 123 char *np; 124 int len; 125 126 switch (*s++) { 127 case 'B': 128 len = 1; 129 break; 130 case 'W': 131 len = 2; 132 break; 133 case 'D': 134 case 'O': 135 case 'z': 136 len = 4; 137 break; 138 default: 139 return (EINVAL); 140 } 141 if (isdigit(*s)) { 142 len *= strtoul(s, &np, 10); 143 s = np; 144 } 145 *rlen = len; 146 *(const char **)next = s; 147 return (0); 148 } 149 150 static int 151 smb_rap_rqparam_z(struct smb_rap *rap, const char *value) 152 { 153 int len = strlen(value) + 1; 154 155 bcopy(value, rap->r_npbuf, len); 156 rap->r_npbuf += len; 157 rap->r_plen += len; 158 return (0); 159 } 160 161 /* 162 * Marshal RAP request parameters. 163 * Note: value is in host order. 164 */ 165 static int 166 smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value) 167 { 168 int len = 0; 169 uint_t uv = (uint_t)value; 170 uint32_t *lp; 171 uint16_t *sp; 172 char *p; 173 174 switch (ptype) { 175 case 'L': 176 case 'W': 177 /* LINTED */ 178 sp = (uint16_t *)rap->r_npbuf; 179 *sp = htoles(uv); 180 len = sizeof (*sp); 181 break; 182 case 'D': 183 /* LINTED */ 184 lp = (uint32_t *)rap->r_npbuf; 185 *lp = htolel(uv); 186 len = sizeof (*lp); 187 break; 188 case 'b': 189 p = rap->r_npbuf; 190 memset(p, uv, plen); 191 len = plen; 192 default: 193 return (EINVAL); 194 } 195 rap->r_npbuf += len; 196 rap->r_plen += len; 197 return (0); 198 } 199 200 int 201 smb_rap_create(int fn, const char *param, const char *data, 202 struct smb_rap **rapp) 203 { 204 struct smb_rap *rap; 205 char *p; 206 int plen = 0, len = 0; 207 208 rap = malloc(sizeof (*rap)); 209 if (rap == NULL) 210 return (ENOMEM); 211 bzero(rap, sizeof (*rap)); 212 p = rap->r_sparam = rap->r_nparam = strdup(param); 213 rap->r_sdata = rap->r_ndata = strdup(data); 214 215 /* 216 * Calculate length of request parameter block 217 */ 218 len = 2 + strlen(param) + 1 + strlen(data) + 1; 219 while (*p) { 220 if (smb_rap_parserqparam(p, &p, &plen) != 0) 221 break; 222 len += plen; 223 } 224 rap->r_pbuf = rap->r_npbuf = malloc(len); 225 if (rap->r_pbuf == NULL) 226 return (ENOMEM); 227 (void) smb_rap_rqparam(rap, 'W', 1, fn); 228 (void) smb_rap_rqparam_z(rap, rap->r_sparam); 229 (void) smb_rap_rqparam_z(rap, rap->r_sdata); 230 *rapp = rap; 231 return (0); 232 } 233 234 void 235 smb_rap_done(struct smb_rap *rap) 236 { 237 if (rap->r_sparam) 238 free(rap->r_sparam); 239 if (rap->r_sdata) 240 free(rap->r_sdata); 241 if (rap->r_pbuf) 242 free(rap->r_pbuf); 243 #ifdef NOTYETDEFINED 244 if (rap->r_npbuf) 245 free(rap->r_npbuf); 246 if (rap->r_dbuf) 247 free(rap->r_dbuf); 248 if (rap->r_rcvbuf) 249 free(rap->r_rcvbuf); 250 #endif 251 free(rap); 252 } 253 254 int 255 smb_rap_setNparam(struct smb_rap *rap, int value) 256 { 257 char *p = rap->r_nparam; 258 char ptype = *p; 259 int error, plen; 260 261 error = smb_rap_parserqparam(p, &p, &plen); 262 if (error) 263 return (error); 264 switch (ptype) { 265 case 'L': 266 rap->r_rcvbuflen = value; 267 /* FALLTHROUGH */ 268 case 'W': 269 case 'D': 270 case 'b': 271 error = smb_rap_rqparam(rap, ptype, plen, value); 272 break; 273 default: 274 return (EINVAL); 275 } 276 rap->r_nparam = p; 277 return (0); 278 } 279 280 int 281 smb_rap_setPparam(struct smb_rap *rap, void *value) 282 { 283 char *p = rap->r_nparam; 284 char ptype = *p; 285 int error, plen; 286 287 error = smb_rap_parserqparam(p, &p, &plen); 288 if (error) 289 return (error); 290 switch (ptype) { 291 case 'r': 292 rap->r_rcvbuf = value; 293 break; 294 default: 295 return (EINVAL); 296 } 297 rap->r_nparam = p; 298 return (0); 299 } 300 301 int 302 smb_rap_getNparam(struct smb_rap *rap, long *value) 303 { 304 char *p = rap->r_nparam; 305 char ptype = *p; 306 int error, plen; 307 uint16_t *te; 308 309 error = smb_rap_parserpparam(p, &p, &plen); 310 if (error) 311 return (error); 312 switch (ptype) { 313 case 'h': 314 /* LINTED */ 315 te = (uint16_t *)rap->r_npbuf; 316 *value = letohs(*te); 317 break; 318 default: 319 return (EINVAL); 320 } 321 rap->r_npbuf += plen; 322 rap->r_nparam = p; 323 return (0); 324 } 325 326 int 327 smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx) 328 { 329 uint16_t *rp, conv, *tmp; 330 uint32_t *p32; 331 char *dp, *p = rap->r_nparam; 332 char ptype; 333 int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow; 334 335 rdatacnt = rap->r_rcvbuflen; 336 rparamcnt = rap->r_plen; 337 error = smb_t2_request(ctx, 0, NULL, "\\PIPE\\LANMAN", 338 rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */ 339 0, NULL, /* int tdatacnt, void *tdata */ 340 &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */ 341 &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */ 342 &buffer_oflow); 343 if (error) 344 return (error); 345 346 /* LINTED */ 347 rp = (uint16_t *)rap->r_pbuf; 348 349 /* 350 * Note: First is a "LanMan API" error code. 351 * See: usr/src/uts/common/smbsrv/lmerr.h 352 */ 353 if (rparamcnt < 2) 354 return (EBADRPC); 355 rap->r_result = letohs(*rp); 356 rp++; rparamcnt -= 2; 357 358 if (rap->r_result != 0) { 359 /* 360 * Could also return zero and let the caller 361 * come get r_result via smb_rap_error(), 362 * but in case they dont... 363 */ 364 return (rap->r_result | SMB_RAP_ERROR); 365 } 366 367 if (rparamcnt < 2) 368 return (EBADRPC); 369 conv = letohs(*rp); 370 rp++; rparamcnt -= 2; 371 372 rap->r_npbuf = (char *)rp; 373 rap->r_entries = entries = 0; 374 /* Save the returned data length */ 375 rap->r_rcvbuflen = rdatacnt; 376 done = 0; 377 378 while (!done && *p) { 379 ptype = *p; 380 switch (ptype) { 381 case 'e': 382 if (rparamcnt < 2) 383 return (EBADRPC); 384 /* LINTED */ 385 tmp = (uint16_t *)rap->r_npbuf; 386 rap->r_entries = entries = letohs(*tmp); 387 rap->r_npbuf += 2; 388 rparamcnt -= 2; 389 p++; 390 break; 391 default: 392 done = 1; 393 } 394 #if 0 /* commented out in Darwin. Why? */ 395 error = smb_rap_parserpparam(p, &p, &plen); 396 if (error) { 397 smb_error(dgettext(TEXT_DOMAIN, 398 "reply parameter mismatch %s"), 0, p); 399 return (EBADRPC); 400 } 401 #endif 402 } 403 rap->r_nparam = p; 404 /* 405 * In general, unpacking entries we may need to relocate 406 * entries for proper aligning. For now use them as is. 407 */ 408 dp = rap->r_rcvbuf; 409 while (entries--) { 410 p = rap->r_sdata; 411 while (*p) { 412 ptype = *p; 413 error = smb_rap_parserpdata(p, &p, &dlen); 414 if (error) { 415 smb_error(dgettext(TEXT_DOMAIN, 416 "reply data mismatch %s"), 0, p); 417 return (EBADRPC); 418 } 419 if (rdatacnt < dlen) 420 return (EBADRPC); 421 switch (ptype) { 422 case 'z': 423 /* LINTED */ 424 p32 = (uint32_t *)dp; 425 *p32 = (letohl(*p32) & 0xffff) - conv; 426 break; 427 } 428 dp += dlen; 429 rdatacnt -= dlen; 430 } 431 } 432 return (error); 433 } 434 435 int 436 smb_rap_error(struct smb_rap *rap, int error) 437 { 438 if (error) 439 return (error); 440 if (rap->r_result == 0) 441 return (0); 442 return (rap->r_result | SMB_RAP_ERROR); 443 } 444