1/* 2 * Copyright (c) 2000, Boris Popov 3 * All rights reserved. 4 * 5 * Portions Copyright (C) 2001 - 2010 Apple Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Boris Popov. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $Id: rap.c,v 1.6 2005/05/06 23:16:29 lindak Exp $ 35 * 36 * This is very simple implementation of RAP protocol. 37 */ 38#include <sys/param.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 <strings.h> 46#include <stdlib.h> 47#include <sysexits.h> 48 49#include <stdint.h> 50#include <libkern/OSByteOrder.h> 51#include <smbclient/smbclient.h> 52#include <smbclient/smbclient_internal.h> 53#include <smbclient/ntstatus.h> 54 55#include "rap.h" 56 57#define MAX_RAP_SHARE_BUFFER 0xffe0 58 59static int 60smb_rap_parserqparam(const char *s, char **next, int *rlen) 61{ 62 char *np; 63 int len; 64 65 switch (*s++) { 66 case 'L': 67 case 'T': 68 case 'W': 69 len = 2; 70 break; 71 case 'D': 72 case 'O': 73 len = 4; 74 break; 75 case 'b': 76 case 'F': 77 len = 1; 78 break; 79 case 'r': 80 case 's': 81 len = 0; 82 break; 83 default: 84 return EINVAL; 85 } 86 if (isdigit(*s)) { 87 len *= (int)strtoul(s, &np, 10); 88 s = np; 89 } 90 *rlen = len; 91 *(const char**)next = s; 92 return 0; 93} 94 95static int 96smb_rap_parserpparam(const char *s, char **next, int *rlen) 97{ 98 char *np; 99 int len; 100 101 switch (*s++) { 102 case 'e': 103 case 'h': 104 len = 2; 105 break; 106 case 'i': 107 len = 4; 108 break; 109 case 'g': 110 len = 1; 111 break; 112 default: 113 return EINVAL; 114 } 115 if (isdigit(*s)) { 116 len *= (int)strtoul(s, &np, 10); 117 s = np; 118 } 119 *rlen = len; 120 *(const char**)next = s; 121 return 0; 122} 123 124static int 125smb_rap_parserpdata(const char *s, char **next, int *rlen) 126{ 127 char *np; 128 int len; 129 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 *= (int)strtoul(s, &np, 10); 147 s = np; 148 } 149 *rlen = len; 150 *(const char**)next = s; 151 return 0; 152} 153 154static int 155smb_rap_rqparam_z(struct smb_rap *rap, const char *value) 156{ 157 int len = (int)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 165static int 166smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int32_t 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 break; 185 default: 186 return EINVAL; 187 } 188 rap->r_npbuf += len; 189 rap->r_plen += len; 190 return 0; 191} 192 193static int 194smb_rap_create(int fn, const char *param, const char *data, 195 struct smb_rap **rapp) 196{ 197 struct smb_rap *rap; 198 char *p; 199 int plen, len; 200 201 rap = malloc(sizeof(*rap)); 202 if (rap == NULL) 203 return ENOMEM; 204 bzero(rap, sizeof(*rap)); 205 p = rap->r_sparam = rap->r_nparam = strdup(param); 206 rap->r_sdata = rap->r_ndata = strdup(data); 207 /* 208 * Calculate length of request parameter block 209 */ 210 len = 2 + (int)strlen(param) + 1 + (int)strlen(data) + 1; 211 212 while (*p) { 213 if (smb_rap_parserqparam(p, &p, &plen) != 0) 214 break; 215 len += plen; 216 } 217 rap->r_pbuf = rap->r_npbuf = malloc(len); 218 smb_rap_rqparam(rap, 'W', 1, fn); 219 smb_rap_rqparam_z(rap, rap->r_sparam); 220 smb_rap_rqparam_z(rap, rap->r_sdata); 221 *rapp = rap; 222 return 0; 223} 224 225static void 226smb_rap_done(struct smb_rap *rap) 227{ 228 if (rap->r_sparam) 229 free(rap->r_sparam); 230 if (rap->r_sdata) 231 free(rap->r_sdata); 232 if (rap->r_pbuf) 233 free(rap->r_pbuf); 234 if (rap->r_dbuf) 235 free(rap->r_dbuf); 236 free(rap); 237} 238 239static int 240smb_rap_setNparam(struct smb_rap *rap, int32_t value) 241{ 242 char *p = rap->r_nparam; 243 char ptype = *p; 244 int error, plen; 245 246 error = smb_rap_parserqparam(p, &p, &plen); 247 if (error) 248 return error; 249 switch (ptype) { 250 case 'L': 251 rap->r_rcvbuflen = value; 252 /* FALLTHROUGH */ 253 case 'W': 254 case 'D': 255 case 'b': 256 error = smb_rap_rqparam(rap, ptype, plen, value); 257 break; 258 default: 259 return EINVAL; 260 } 261 rap->r_nparam = p; 262 return error; 263} 264 265static int 266smb_rap_setPparam(struct smb_rap *rap, void *value) 267{ 268 char *p = rap->r_nparam; 269 char ptype = *p; 270 int error, plen; 271 272 error = smb_rap_parserqparam(p, &p, &plen); 273 if (error) 274 return error; 275 switch (ptype) { 276 case 'r': 277 rap->r_rcvbuf = value; 278 break; 279 default: 280 return EINVAL; 281 } 282 rap->r_nparam = p; 283 return 0; 284} 285 286static int 287smb_rap_getNparam(struct smb_rap *rap, int32_t *value) 288{ 289 char *p = rap->r_nparam; 290 char ptype = *p; 291 int error, plen; 292 293 error = smb_rap_parserpparam(p, &p, &plen); 294 if (error) 295 return error; 296 switch (ptype) { 297 case 'h': 298 *value = OSSwapLittleToHostInt16(*(uint16_t*)rap->r_npbuf); 299 break; 300 default: 301 return EINVAL; 302 } 303 rap->r_npbuf += plen; 304 rap->r_nparam = p; 305 return 0; 306} 307 308static int 309smb_rap_request(SMBHANDLE inConnection, struct smb_rap *rap) 310{ 311 uint16_t *rp, conv; 312 uint32_t *p32; 313 char *dp, *p = rap->r_nparam; 314 char ptype; 315 int error = 0, entries, done, dlen, status; 316 size_t rdatacnt, rparamcnt; 317 318 rdatacnt = rap->r_rcvbuflen; 319 rparamcnt = rap->r_plen; 320 321 status = SMBTransactMailSlot(inConnection, "\\PIPE\\LANMAN", 322 rap->r_pbuf, rap->r_plen, 323 rap->r_pbuf, &rparamcnt, 324 rap->r_rcvbuf, &rdatacnt); 325 if (!NT_SUCCESS(status)) { 326 /* Should never happen */ 327 return errno; 328 } 329 rp = (uint16_t*)rap->r_pbuf; 330 rap->r_result = OSSwapLittleToHostInt16(*rp++); 331 conv = OSSwapLittleToHostInt16(*rp++); 332 rap->r_npbuf = (char*)rp; 333 rap->r_entries = entries = 0; 334 done = 0; 335 while (!done && *p) { 336 ptype = *p; 337 switch (ptype) { 338 case 'e': 339 rap->r_entries = entries = OSSwapLittleToHostInt16(*(uint16_t*)rap->r_npbuf); 340 rap->r_npbuf += 2; 341 p++; 342 break; 343 default: 344 done = 1; 345 } 346 } 347 rap->r_nparam = p; 348 /* 349 * In general, unpacking entries we may need to relocate 350 * entries for proper aligning. For now use them as is. 351 */ 352 dp = rap->r_rcvbuf; 353 while (entries--) { 354 p = rap->r_sdata; 355 while (*p) { 356 ptype = *p; 357 error = smb_rap_parserpdata(p, &p, &dlen); 358 if (error) { 359 SMBLogInfo("reply data mismatch %s", ASL_LEVEL_ERR, p); 360 return EBADRPC; 361 } 362 switch (ptype) { 363 case 'z': 364 p32 = (uint32_t*)dp; 365 *p32 = (OSSwapLittleToHostInt32(*p32) & 0xffff) - conv; 366 break; 367 } 368 dp += dlen; 369 } 370 } 371 return error; 372} 373 374/* 375 * We could translate these better, but these are the old enumerate rap calls and 376 * we are using them less and less. The old code just passed up the rap errors, now 377 * we convert it to real errno. 378 */ 379static int smb_rap_error(struct smb_rap *rap, int error) 380{ 381 if (error) 382 return error; 383 if ((rap->r_result == 0) || (rap->r_result == SMB_ERROR_MORE_DATA)) 384 return 0; 385 switch (rap->r_result) { 386 case SMB_ERROR_ACCESS_DENIED: 387 case SMB_ERROR_NETWORK_ACCESS_DENIED: 388 error = EACCES; 389 break; 390 default: 391 SMBLogInfo("received an unknown rap enumerate share error %d", 392 ASL_LEVEL_ERR, rap->r_result); 393 error = EIO; 394 break; 395 } 396 return error; 397} 398 399int 400RapNetShareEnum(SMBHANDLE inConnection, int sLevel, void **rBuffer, uint32_t *rBufferSize, 401 uint32_t *entriesRead, uint32_t *totalEntriesRead) 402{ 403 struct smb_rap *rap = NULL; 404 int error; 405 406 if (inConnection == NULL) { 407 /* Should never happen */ 408 return EINVAL; 409 } 410 *rBufferSize = MAX_RAP_SHARE_BUFFER; /* samba notes win2k bug for 65535 */ 411 *rBuffer = malloc(*rBufferSize); 412 if (*rBuffer == NULL) { 413 return errno; 414 } 415 416 error = smb_rap_create(0, "WrLeh", "B13BWz", &rap); 417 if (error) { 418 RapNetApiBufferFree(*rBuffer); 419 *rBuffer = NULL; 420 return error; 421 } 422 smb_rap_setNparam(rap, sLevel); /* W - sLevel */ 423 smb_rap_setPparam(rap, *rBuffer); /* r - pbBuffer */ 424 smb_rap_setNparam(rap, *rBufferSize); /* L - cbBuffer */ 425 error = smb_rap_request(inConnection, rap); 426 427 if (error == 0) { 428 *entriesRead = rap->r_entries; 429 if (totalEntriesRead) { 430 int32_t lval = 0; 431 error = smb_rap_getNparam(rap, &lval); 432 *totalEntriesRead = lval; 433 } 434 } 435 error = smb_rap_error(rap, error); 436 smb_rap_done(rap); 437 return error; 438} 439 440void RapNetApiBufferFree(void * bufptr) 441{ 442 free(bufptr); 443} 444