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