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: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 */ 39 40 #include <sys/param.h> 41 #include <sys/ioctl.h> 42 #include <sys/time.h> 43 #include <sys/mount.h> 44 #include <sys/types.h> 45 #include <sys/byteorder.h> 46 47 #include <fcntl.h> 48 #include <ctype.h> 49 #include <errno.h> 50 #include <stdio.h> 51 #include <string.h> 52 #include <strings.h> 53 #include <stdlib.h> 54 #include <pwd.h> 55 #include <grp.h> 56 #include <unistd.h> 57 #include <libintl.h> 58 #include <assert.h> 59 #include <nss_dbdefs.h> 60 61 #include <cflib.h> 62 #include <netsmb/smb_lib.h> 63 #include <netsmb/netbios.h> 64 #include <netsmb/nb_lib.h> 65 #include <netsmb/smb_dev.h> 66 67 #include "charsets.h" 68 #include "spnego.h" 69 #include "derparse.h" 70 #include "private.h" 71 #include "ntlm.h" 72 73 #ifndef FALSE 74 #define FALSE 0 75 #endif 76 #ifndef TRUE 77 #define TRUE 1 78 #endif 79 80 81 /* These two may be set by commands. */ 82 int smb_debug, smb_verbose; 83 84 /* 85 * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt 86 */ 87 const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:"; 88 89 /* 90 * Give the RPC library a callback hook that will be 91 * called whenever we destroy or reinit an smb_ctx_t. 92 * The name rpc_cleanup_smbctx() is legacy, and was 93 * originally a direct call into the RPC code. 94 */ 95 static smb_ctx_close_hook_t close_hook; 96 static void 97 rpc_cleanup_smbctx(struct smb_ctx *ctx) 98 { 99 if (close_hook) 100 (*close_hook)(ctx); 101 } 102 void 103 smb_ctx_set_close_hook(smb_ctx_close_hook_t hook) 104 { 105 close_hook = hook; 106 } 107 108 void 109 dump_ctx_flags(int flags) 110 { 111 printf(" Flags: "); 112 if (flags == 0) 113 printf("0"); 114 if (flags & SMBCF_NOPWD) 115 printf("NOPWD "); 116 if (flags & SMBCF_SRIGHTS) 117 printf("SRIGHTS "); 118 if (flags & SMBCF_LOCALE) 119 printf("LOCALE "); 120 if (flags & SMBCF_CMD_DOM) 121 printf("CMD_DOM "); 122 if (flags & SMBCF_CMD_USR) 123 printf("CMD_USR "); 124 if (flags & SMBCF_CMD_PW) 125 printf("CMD_PW "); 126 if (flags & SMBCF_RESOLVED) 127 printf("RESOLVED "); 128 if (flags & SMBCF_KCBAD) 129 printf("KCBAD "); 130 if (flags & SMBCF_KCFOUND) 131 printf("KCFOUND "); 132 if (flags & SMBCF_BROWSEOK) 133 printf("BROWSEOK "); 134 if (flags & SMBCF_AUTHREQ) 135 printf("AUTHREQ "); 136 if (flags & SMBCF_KCSAVE) 137 printf("KCSAVE "); 138 if (flags & SMBCF_XXX) 139 printf("XXX "); 140 if (flags & SMBCF_SSNACTIVE) 141 printf("SSNACTIVE "); 142 if (flags & SMBCF_KCDOMAIN) 143 printf("KCDOMAIN "); 144 printf("\n"); 145 } 146 147 void 148 dump_iod_ssn(smb_iod_ssn_t *is) 149 { 150 static const char zeros[NTLM_HASH_SZ] = {0}; 151 struct smbioc_ossn *ssn = &is->iod_ossn; 152 153 printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname); 154 dump_sockaddr(&ssn->ssn_srvaddr.sa); 155 printf(" dom=\"%s\", user=\"%s\"\n", 156 ssn->ssn_domain, ssn->ssn_user); 157 printf(" ct_vopt=0x%x, ct_owner=%d\n", 158 ssn->ssn_vopt, ssn->ssn_owner); 159 printf(" ct_authflags=0x%x\n", is->iod_authflags); 160 161 printf(" ct_nthash:"); 162 if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ)) 163 smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ); 164 else 165 printf(" {0}\n"); 166 167 printf(" ct_lmhash:"); 168 if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ)) 169 smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ); 170 else 171 printf(" {0}\n"); 172 } 173 174 void 175 dump_ctx(char *where, struct smb_ctx *ctx) 176 { 177 printf("context %s:\n", where); 178 dump_ctx_flags(ctx->ct_flags); 179 180 if (ctx->ct_locname) 181 printf(" localname=\"%s\"", ctx->ct_locname); 182 else 183 printf(" localname=NULL"); 184 185 if (ctx->ct_fullserver) 186 printf(" fullserver=\"%s\"", ctx->ct_fullserver); 187 else 188 printf(" fullserver=NULL"); 189 190 if (ctx->ct_srvaddr_s) 191 printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s); 192 else 193 printf(" srvaddr_s=NULL\n"); 194 195 if (ctx->ct_addrinfo) 196 dump_addrinfo(ctx->ct_addrinfo); 197 else 198 printf(" ct_addrinfo = NULL\n"); 199 200 dump_iod_ssn(&ctx->ct_iod_ssn); 201 202 printf(" share_name=\"%s\", share_type=%d\n", 203 ctx->ct_origshare ? ctx->ct_origshare : "", 204 ctx->ct_shtype_req); 205 206 /* dump_iod_work()? */ 207 } 208 209 int 210 smb_ctx_alloc(struct smb_ctx **ctx_pp) 211 { 212 smb_ctx_t *ctx; 213 int err; 214 215 ctx = malloc(sizeof (*ctx)); 216 if (ctx == NULL) 217 return (ENOMEM); 218 err = smb_ctx_init(ctx); 219 if (err != 0) { 220 free(ctx); 221 return (err); 222 } 223 *ctx_pp = ctx; 224 return (0); 225 } 226 227 /* 228 * Initialize an smb_ctx struct (defaults) 229 */ 230 int 231 smb_ctx_init(struct smb_ctx *ctx) 232 { 233 char pwbuf[NSS_BUFLEN_PASSWD]; 234 struct passwd pw; 235 int error = 0; 236 237 bzero(ctx, sizeof (*ctx)); 238 239 error = nb_ctx_create(&ctx->ct_nb); 240 if (error) 241 return (error); 242 243 ctx->ct_dev_fd = -1; 244 ctx->ct_tran_fd = -1; 245 ctx->ct_parsedlevel = SMBL_NONE; 246 ctx->ct_minlevel = SMBL_NONE; 247 ctx->ct_maxlevel = SMBL_PATH; 248 249 /* Fill in defaults */ 250 ctx->ct_vopt = SMBVOPT_EXT_SEC; 251 ctx->ct_owner = SMBM_ANY_OWNER; 252 ctx->ct_authflags = SMB_AT_DEFAULT; 253 ctx->ct_minauth = SMB_AT_DEFAULT; 254 255 nb_ctx_setscope(ctx->ct_nb, ""); 256 257 /* 258 * if the user name is not specified some other way, 259 * use the current user name (built-in default) 260 */ 261 if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) { 262 smb_ctx_setuser(ctx, pw.pw_name, 0); 263 ctx->ct_home = strdup(pw.pw_name); 264 } 265 266 /* 267 * Set a built-in default domain (workgroup). 268 * Using the Windows/NT default for now. 269 */ 270 smb_ctx_setdomain(ctx, "WORKGROUP", 0); 271 272 return (error); 273 } 274 275 /* 276 * "Scan" the command line args to find the server name, 277 * user name, and share name, as needed. We need these 278 * before reading the RC files and/or sharectl values. 279 * 280 * The sequence for getting all the members filled in 281 * has some tricky aspects. Here's how it works: 282 * 283 * The search order for options is as follows: 284 * command line options 285 * values parsed from UNC path (cmd) 286 * values from RC file (per-user) 287 * values from SMF (system-wide) 288 * built-in defaults 289 * 290 * Normally, one would simply get all the values starting with 291 * the bottom of the above list and working to the top, and 292 * overwriting values as you go. But we need an exception. 293 * 294 * In this function, we parse the UNC path and command line options, 295 * because we need (at least) the server name when we're getting the 296 * SMF and RC file values. However, values we get from the command 297 * should not be overwritten by SMF or RC file parsing, so we mark 298 * values from the command as "from CMD" and the RC file parser 299 * leaves in place any values so marked. See: SMBCF_CMD_* 300 * 301 * The semantics of these flags are: "This value came from the 302 * current command instance, not from sources that may apply to 303 * multiple commands." (Different from the old "FROMUSR" flag.) 304 * 305 * Note that smb_ctx_opt() is called later to handle the 306 * remaining options, which should be ignored here. 307 * The (magic) leading ":" in cf_getopt() makes it 308 * ignore options not in the options string. 309 */ 310 int 311 smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv, 312 int minlevel, int maxlevel, int sharetype) 313 { 314 int ind, opt, error = 0; 315 int aflg = 0, uflg = 0; 316 const char *arg; 317 318 /* 319 * Parse options, if any. Values from here too 320 * are marked as "from CMD". 321 */ 322 if (argv == NULL) 323 return (0); 324 325 ctx->ct_minlevel = minlevel; 326 ctx->ct_maxlevel = maxlevel; 327 ctx->ct_shtype_req = sharetype; 328 329 cf_opt_lock(); 330 /* Careful: no return/goto before cf_opt_unlock! */ 331 while (error == 0) { 332 opt = cf_getopt(argc, argv, STDPARAM_OPT); 333 if (opt == -1) 334 break; 335 arg = cf_optarg; 336 /* NB: handle most in smb_ctx_opt */ 337 switch (opt) { 338 case 'A': 339 aflg = 1; 340 error = smb_ctx_setuser(ctx, "", TRUE); 341 ctx->ct_flags |= SMBCF_NOPWD; 342 break; 343 case 'U': 344 uflg = 1; 345 error = smb_ctx_setuser(ctx, arg, TRUE); 346 break; 347 default: 348 DPRINT("skip opt=%c", opt); 349 break; 350 } 351 } 352 ind = cf_optind; 353 arg = argv[ind]; 354 cf_optind = cf_optreset = 1; 355 cf_opt_unlock(); 356 357 if (error) 358 return (error); 359 360 if (aflg && uflg) { 361 printf(gettext("-A and -U flags are exclusive.\n")); 362 return (EINVAL); 363 } 364 365 /* 366 * Parse the UNC path. Values from here are 367 * marked as "from CMD". 368 */ 369 for (; ind < argc; ind++) { 370 arg = argv[ind]; 371 if (strncmp(arg, "//", 2) != 0) 372 continue; 373 error = smb_ctx_parseunc(ctx, arg, 374 minlevel, maxlevel, sharetype, &arg); 375 if (error) 376 return (error); 377 break; 378 } 379 380 return (error); 381 } 382 383 void 384 smb_ctx_free(smb_ctx_t *ctx) 385 { 386 smb_ctx_done(ctx); 387 free(ctx); 388 } 389 390 void 391 smb_ctx_done(struct smb_ctx *ctx) 392 { 393 394 rpc_cleanup_smbctx(ctx); 395 396 if (ctx->ct_dev_fd != -1) { 397 close(ctx->ct_dev_fd); 398 ctx->ct_dev_fd = -1; 399 } 400 if (ctx->ct_tran_fd != -1) { 401 close(ctx->ct_tran_fd); 402 ctx->ct_tran_fd = -1; 403 } 404 if (ctx->ct_srvaddr_s) { 405 free(ctx->ct_srvaddr_s); 406 ctx->ct_srvaddr_s = NULL; 407 } 408 if (ctx->ct_nb) { 409 nb_ctx_done(ctx->ct_nb); 410 ctx->ct_nb = NULL; 411 } 412 if (ctx->ct_locname) { 413 free(ctx->ct_locname); 414 ctx->ct_locname = NULL; 415 } 416 if (ctx->ct_origshare) { 417 free(ctx->ct_origshare); 418 ctx->ct_origshare = NULL; 419 } 420 if (ctx->ct_fullserver) { 421 free(ctx->ct_fullserver); 422 ctx->ct_fullserver = NULL; 423 } 424 if (ctx->ct_addrinfo) { 425 freeaddrinfo(ctx->ct_addrinfo); 426 ctx->ct_addrinfo = NULL; 427 } 428 if (ctx->ct_home) 429 free(ctx->ct_home); 430 if (ctx->ct_srv_OS) { 431 free(ctx->ct_srv_OS); 432 ctx->ct_srv_OS = NULL; 433 } 434 if (ctx->ct_srv_LM) { 435 free(ctx->ct_srv_LM); 436 ctx->ct_srv_LM = NULL; 437 } 438 if (ctx->ct_mackey) { 439 free(ctx->ct_mackey); 440 ctx->ct_mackey = NULL; 441 } 442 } 443 444 static int 445 getsubstring(const char *p, uchar_t sep, char *dest, int maxlen, 446 const char **next) 447 { 448 int len; 449 450 maxlen--; 451 for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 452 if (*p == 0) 453 return (EINVAL); 454 *dest = *p; 455 } 456 *dest = 0; 457 *next = *p ? p + 1 : p; 458 return (0); 459 } 460 461 /* 462 * Parse the UNC path. Here we expect something like 463 * "//[workgroup;][user[:password]@]host[/share[/path]]" 464 * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 465 * Values found here are marked as "from CMD". 466 */ 467 int 468 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, 469 int minlevel, int maxlevel, int sharetype, 470 const char **next) 471 { 472 const char *p = unc; 473 char *p1, *colon; 474 char tmp[1024]; 475 char tmp2[1024]; 476 int error; 477 478 /* 479 * This may be called outside of _scan_argv, 480 * so make sure these get initialized. 481 */ 482 ctx->ct_minlevel = minlevel; 483 ctx->ct_maxlevel = maxlevel; 484 ctx->ct_shtype_req = sharetype; 485 486 ctx->ct_parsedlevel = SMBL_NONE; 487 if (*p++ != '/' || *p++ != '/') { 488 smb_error(dgettext(TEXT_DOMAIN, 489 "UNC should start with '//'"), 0); 490 error = EINVAL; 491 goto out; 492 } 493 p1 = tmp; 494 error = getsubstring(p, ';', p1, sizeof (tmp), &p); 495 if (!error) { 496 if (*p1 == 0) { 497 smb_error(dgettext(TEXT_DOMAIN, 498 "empty workgroup name"), 0); 499 error = EINVAL; 500 goto out; 501 } 502 nls_str_upper(tmp, tmp); 503 error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE); 504 if (error) 505 goto out; 506 } 507 colon = (char *)p; 508 error = getsubstring(p, '@', p1, sizeof (tmp), &p); 509 if (!error) { 510 if (ctx->ct_maxlevel < SMBL_VC) { 511 smb_error(dgettext(TEXT_DOMAIN, 512 "no user name required"), 0); 513 error = EINVAL; 514 goto out; 515 } 516 p1 = strchr(tmp, ':'); 517 if (p1) { 518 colon += p1 - tmp; 519 *p1++ = (char)0; 520 error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE); 521 if (error) 522 goto out; 523 if (p - colon > 2) 524 memset(colon+1, '*', p - colon - 2); 525 } 526 p1 = tmp; 527 if (*p1 == 0) { 528 smb_error(dgettext(TEXT_DOMAIN, 529 "empty user name"), 0); 530 error = EINVAL; 531 goto out; 532 } 533 error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE); 534 if (error) 535 goto out; 536 ctx->ct_parsedlevel = SMBL_VC; 537 } 538 error = getsubstring(p, '/', p1, sizeof (tmp), &p); 539 if (error) { 540 error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 541 if (error) { 542 smb_error(dgettext(TEXT_DOMAIN, 543 "no server name found"), 0); 544 goto out; 545 } 546 } 547 if (*p1 == 0) { 548 smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0); 549 error = EINVAL; 550 goto out; 551 } 552 553 /* 554 * It's safe to uppercase this string, which 555 * consists of ascii characters that should 556 * be uppercased, %s, and ascii characters representing 557 * hex digits 0-9 and A-F (already uppercased, and 558 * if not uppercased they need to be). However, 559 * it is NOT safe to uppercase after it has been 560 * "unpercent" converted, below! 561 */ 562 nls_str_upper(tmp2, tmp); 563 564 /* 565 * Save ct_fullserver without case conversion. 566 */ 567 if (strchr(tmp, '%')) 568 (void) unpercent(tmp); 569 smb_ctx_setfullserver(ctx, tmp); 570 if (error) 571 goto out; 572 573 #ifdef SMB_ST_NONE 574 if (sharetype == SMB_ST_NONE) { 575 if (next) 576 *next = p; 577 error = 0; 578 goto out; 579 } 580 #endif 581 582 if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 583 smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0); 584 error = EINVAL; 585 goto out; 586 } 587 error = getsubstring(p, '/', p1, sizeof (tmp), &p); 588 if (error) { 589 error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 590 if (error) { 591 smb_error(dgettext(TEXT_DOMAIN, 592 "unexpected end of line"), 0); 593 goto out; 594 } 595 } 596 if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE && 597 !(ctx->ct_flags & SMBCF_BROWSEOK)) { 598 smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0); 599 error = EINVAL; 600 goto out; 601 } 602 if (next) 603 *next = p; 604 if (*p1 == 0) { 605 error = 0; 606 goto out; 607 } 608 error = smb_ctx_setshare(ctx, unpercent(p1), sharetype); 609 610 out: 611 if (error == 0 && smb_debug > 0) 612 dump_ctx("after smb_ctx_parseunc", ctx); 613 614 return (error); 615 } 616 617 #ifdef KICONV_SUPPORT 618 int 619 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 620 { 621 char *cp, *servercs, *localcs; 622 int cslen = sizeof (ctx->ct_ssn.ioc_localcs); 623 int scslen, lcslen, error; 624 625 cp = strchr(arg, ':'); 626 lcslen = cp ? (cp - arg) : 0; 627 if (lcslen == 0 || lcslen >= cslen) { 628 smb_error(dgettext(TEXT_DOMAIN, 629 "invalid local charset specification (%s)"), 0, arg); 630 return (EINVAL); 631 } 632 scslen = (size_t)strlen(++cp); 633 if (scslen == 0 || scslen >= cslen) { 634 smb_error(dgettext(TEXT_DOMAIN, 635 "invalid server charset specification (%s)"), 0, arg); 636 return (EINVAL); 637 } 638 localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 639 localcs[lcslen] = 0; 640 servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 641 error = nls_setrecode(localcs, servercs); 642 if (error == 0) 643 return (0); 644 smb_error(dgettext(TEXT_DOMAIN, 645 "can't initialize iconv support (%s:%s)"), 646 error, localcs, servercs); 647 localcs[0] = 0; 648 servercs[0] = 0; 649 return (error); 650 } 651 #endif /* KICONV_SUPPORT */ 652 653 int 654 smb_ctx_setauthflags(struct smb_ctx *ctx, int flags) 655 { 656 ctx->ct_authflags = flags; 657 return (0); 658 } 659 660 int 661 smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name) 662 { 663 char *p = strdup(name); 664 665 if (p == NULL) 666 return (ENOMEM); 667 if (ctx->ct_fullserver) 668 free(ctx->ct_fullserver); 669 ctx->ct_fullserver = p; 670 return (0); 671 } 672 673 /* this routine does not uppercase the server name */ 674 int 675 smb_ctx_setserver(struct smb_ctx *ctx, const char *name) 676 { 677 /* don't uppercase the server name */ 678 strlcpy(ctx->ct_srvname, name, 679 sizeof (ctx->ct_srvname)); 680 return (0); 681 } 682 683 int 684 smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) 685 { 686 687 if (strlen(name) >= sizeof (ctx->ct_user)) { 688 smb_error(dgettext(TEXT_DOMAIN, 689 "user name '%s' too long"), 0, name); 690 return (ENAMETOOLONG); 691 } 692 693 /* 694 * Don't overwrite a value from the command line 695 * with one from anywhere else. 696 */ 697 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR)) 698 return (0); 699 700 /* don't uppercase the username, just copy it. */ 701 strlcpy(ctx->ct_user, name, 702 sizeof (ctx->ct_user)); 703 704 /* Mark this as "from the command line". */ 705 if (from_cmd) 706 ctx->ct_flags |= SMBCF_CMD_USR; 707 708 return (0); 709 } 710 711 /* 712 * Never uppercase the workgroup 713 * name here, because it might come 714 * from a Windows codepage encoding. 715 * 716 * Don't overwrite a domain name from the 717 * command line with one from anywhere else. 718 * See smb_ctx_init() for notes about this. 719 */ 720 int 721 smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd) 722 { 723 724 if (strlen(name) >= sizeof (ctx->ct_domain)) { 725 smb_error(dgettext(TEXT_DOMAIN, 726 "workgroup name '%s' too long"), 0, name); 727 return (ENAMETOOLONG); 728 } 729 730 /* 731 * Don't overwrite a value from the command line 732 * with one from anywhere else. 733 */ 734 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM)) 735 return (0); 736 737 strlcpy(ctx->ct_domain, name, 738 sizeof (ctx->ct_domain)); 739 740 /* Mark this as "from the command line". */ 741 if (from_cmd) 742 ctx->ct_flags |= SMBCF_CMD_DOM; 743 744 return (0); 745 } 746 747 int 748 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd) 749 { 750 int err; 751 752 if (passwd == NULL) 753 return (EINVAL); 754 if (strlen(passwd) >= sizeof (ctx->ct_password)) { 755 smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0); 756 return (ENAMETOOLONG); 757 } 758 759 /* 760 * If called again after comand line parsing, 761 * don't overwrite a value from the command line 762 * with one from any stored config. 763 */ 764 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW)) 765 return (0); 766 767 memset(ctx->ct_password, 0, sizeof (ctx->ct_password)); 768 if (strncmp(passwd, "$$1", 3) == 0) 769 smb_simpledecrypt(ctx->ct_password, passwd); 770 else 771 strlcpy(ctx->ct_password, passwd, 772 sizeof (ctx->ct_password)); 773 774 /* 775 * Compute LM hash, NT hash. 776 */ 777 if (ctx->ct_password[0]) { 778 err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password); 779 if (err != 0) 780 return (err); 781 err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password); 782 if (err != 0) 783 return (err); 784 } 785 786 /* Mark this as "from the command line". */ 787 if (from_cmd) 788 ctx->ct_flags |= SMBCF_CMD_PW; 789 790 return (0); 791 } 792 793 /* 794 * Use this to set NTLM auth. info (hashes) 795 * when we don't have the password. 796 */ 797 int 798 smb_ctx_setpwhash(smb_ctx_t *ctx, 799 const uchar_t *nthash, const uchar_t *lmhash) 800 { 801 802 /* Need ct_password to be non-null. */ 803 if (ctx->ct_password[0] == '\0') 804 strlcpy(ctx->ct_password, "$HASH", 805 sizeof (ctx->ct_password)); 806 807 /* 808 * Compute LM hash, NT hash. 809 */ 810 memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ); 811 812 /* The LM hash is optional */ 813 if (lmhash) { 814 memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ); 815 } 816 817 return (0); 818 } 819 820 int 821 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 822 { 823 if (strlen(share) >= SMBIOC_MAX_NAME) { 824 smb_error(dgettext(TEXT_DOMAIN, 825 "share name '%s' too long"), 0, share); 826 return (ENAMETOOLONG); 827 } 828 if (ctx->ct_origshare) 829 free(ctx->ct_origshare); 830 if ((ctx->ct_origshare = strdup(share)) == NULL) 831 return (ENOMEM); 832 833 ctx->ct_shtype_req = stype; 834 835 return (0); 836 } 837 838 int 839 smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 840 { 841 if (addr == NULL || addr[0] == 0) 842 return (EINVAL); 843 if (ctx->ct_srvaddr_s) 844 free(ctx->ct_srvaddr_s); 845 if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL) 846 return (ENOMEM); 847 return (0); 848 } 849 850 static int 851 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 852 { 853 struct group gr; 854 struct passwd pw; 855 char buf[NSS_BUFLEN_PASSWD]; 856 char *cp; 857 858 cp = strchr(pair, ':'); 859 if (cp) { 860 *cp++ = '\0'; 861 if (*cp && gid) { 862 if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) { 863 *gid = gr.gr_gid; 864 } else 865 smb_error(dgettext(TEXT_DOMAIN, 866 "Invalid group name %s, ignored"), 0, cp); 867 } 868 } 869 if (*pair) { 870 if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) { 871 *uid = pw.pw_uid; 872 } else 873 smb_error(dgettext(TEXT_DOMAIN, 874 "Invalid user name %s, ignored"), 0, pair); 875 } 876 877 return (0); 878 } 879 880 /* 881 * Commands use this with getopt. See: 882 * STDPARAM_OPT, STDPARAM_ARGS 883 * Called after smb_ctx_readrc(). 884 */ 885 int 886 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 887 { 888 int error = 0; 889 char *p, *cp; 890 char tmp[1024]; 891 892 switch (opt) { 893 case 'A': 894 case 'U': 895 /* Handled in smb_ctx_init() */ 896 break; 897 case 'I': 898 error = smb_ctx_setsrvaddr(ctx, arg); 899 break; 900 case 'M': 901 /* share connect rights - ignored */ 902 ctx->ct_flags |= SMBCF_SRIGHTS; 903 break; 904 case 'N': 905 ctx->ct_flags |= SMBCF_NOPWD; 906 break; 907 case 'O': 908 p = strdup(arg); 909 cp = strchr(p, '/'); 910 if (cp) 911 *cp = '\0'; 912 error = smb_parse_owner(cp, &ctx->ct_owner, NULL); 913 free(p); 914 break; 915 case 'P': 916 /* ctx->ct_vopt |= SMBCOPT_PERMANENT; */ 917 break; 918 case 'R': 919 /* retry count - ignored */ 920 break; 921 case 'T': 922 /* timeout - ignored */ 923 break; 924 case 'D': /* domain */ 925 case 'W': /* workgroup (legacy alias) */ 926 nls_str_upper(tmp, arg); 927 error = smb_ctx_setdomain(ctx, tmp, TRUE); 928 break; 929 } 930 return (error); 931 } 932 933 934 /* 935 * Original code injected iconv tables into the kernel. 936 * Not sure if we'll need this or not... REVISIT 937 */ 938 #ifdef KICONV_SUPPORT 939 static int 940 smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl) 941 { 942 int error = 0; 943 944 error = kiconv_add_xlat_table(to, from, tbl); 945 if (error && error != EEXIST) { 946 smb_error(dgettext(TEXT_DOMAIN, 947 "can not setup kernel iconv table (%s:%s)"), 948 error, from, to); 949 return (error); 950 } 951 return (error); 952 } 953 #endif /* KICONV_SUPPORT */ 954 955 /* 956 * Verify context info. before connect operation(s), 957 * lookup specified server and try to fill all forgotten fields. 958 * Legacy name used by commands. 959 */ 960 int 961 smb_ctx_resolve(struct smb_ctx *ctx) 962 { 963 struct smbioc_ossn *ssn = &ctx->ct_ssn; 964 int error = 0; 965 #ifdef KICONV_SUPPORT 966 uchar_t cstbl[256]; 967 uint_t i; 968 #endif 969 970 ctx->ct_flags &= ~SMBCF_RESOLVED; 971 972 if (ctx->ct_fullserver == NULL) { 973 smb_error(dgettext(TEXT_DOMAIN, 974 "no server name specified"), 0); 975 return (EINVAL); 976 } 977 978 if (ctx->ct_minlevel >= SMBL_SHARE && 979 ctx->ct_origshare == NULL) { 980 smb_error(dgettext(TEXT_DOMAIN, 981 "no share name specified for %s@%s"), 982 0, ssn->ssn_user, ctx->ct_fullserver); 983 return (EINVAL); 984 } 985 error = nb_ctx_resolve(ctx->ct_nb); 986 if (error) 987 return (error); 988 #ifdef KICONV_SUPPORT 989 if (ssn->ioc_localcs[0] == 0) 990 strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ 991 error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 992 if (error) 993 return (error); 994 error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 995 if (error) 996 return (error); 997 if (ssn->ioc_servercs[0] != 0) { 998 for (i = 0; i < sizeof (cstbl); i++) 999 cstbl[i] = i; 1000 nls_mem_toext(cstbl, cstbl, sizeof (cstbl)); 1001 error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, 1002 cstbl); 1003 if (error) 1004 return (error); 1005 for (i = 0; i < sizeof (cstbl); i++) 1006 cstbl[i] = i; 1007 nls_mem_toloc(cstbl, cstbl, sizeof (cstbl)); 1008 error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, 1009 cstbl); 1010 if (error) 1011 return (error); 1012 } 1013 #endif /* KICONV_SUPPORT */ 1014 1015 /* 1016 * Lookup the IP address. 1017 * Puts a list in ct_addrinfo 1018 */ 1019 error = smb_ctx_getaddr(ctx); 1020 if (error) { 1021 smb_error(dgettext(TEXT_DOMAIN, 1022 "can't get server address"), error); 1023 return (error); 1024 } 1025 assert(ctx->ct_addrinfo != NULL); 1026 1027 /* 1028 * If we have a user name but no password, 1029 * check for a keychain entry. 1030 * XXX: Only for auth NTLM? 1031 */ 1032 if (ctx->ct_user[0] == '\0') { 1033 /* 1034 * No user name (anonymous session). 1035 * The minauth checks do not apply. 1036 */ 1037 ctx->ct_authflags = SMB_AT_ANON; 1038 } else { 1039 /* 1040 * Have a user name. 1041 * If we don't have a p/w yet, 1042 * try the keychain. 1043 */ 1044 if (ctx->ct_password[0] == '\0') 1045 (void) smb_get_keychain(ctx); 1046 /* 1047 * If we're doing p/w based auth, 1048 * that means not using Kerberos. 1049 */ 1050 if (ctx->ct_password[0] != '\0') 1051 ctx->ct_authflags &= ~SMB_AT_KRB5; 1052 /* 1053 * Mask out disallowed auth types. 1054 */ 1055 ctx->ct_authflags &= ctx->ct_minauth; 1056 } 1057 if (ctx->ct_authflags == 0) { 1058 smb_error(dgettext(TEXT_DOMAIN, 1059 "no valid auth. types"), 0); 1060 return (ENOTSUP); 1061 } 1062 1063 ctx->ct_flags |= SMBCF_RESOLVED; 1064 if (smb_debug) 1065 dump_ctx("after smb_ctx_resolve", ctx); 1066 1067 return (0); 1068 } 1069 1070 int 1071 smb_open_driver() 1072 { 1073 int err, fd; 1074 uint32_t version; 1075 1076 fd = open("/dev/"NSMB_NAME, O_RDWR); 1077 if (fd < 0) { 1078 err = errno; 1079 smb_error(dgettext(TEXT_DOMAIN, 1080 "failed to open driver"), err); 1081 return (-1); 1082 } 1083 1084 /* 1085 * Check the driver version (paranoia) 1086 * Do this BEFORE any other ioctl calls. 1087 */ 1088 if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) 1089 version = 0; 1090 if (version != NSMB_VERSION) { 1091 smb_error(dgettext(TEXT_DOMAIN, 1092 "incorrect driver version"), 0); 1093 close(fd); 1094 return (-1); 1095 } 1096 1097 /* This handle controls per-process resources. */ 1098 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 1099 1100 return (fd); 1101 } 1102 1103 int 1104 smb_ctx_gethandle(struct smb_ctx *ctx) 1105 { 1106 int fd; 1107 1108 if (ctx->ct_dev_fd != -1) { 1109 rpc_cleanup_smbctx(ctx); 1110 close(ctx->ct_dev_fd); 1111 ctx->ct_dev_fd = -1; 1112 ctx->ct_flags &= ~SMBCF_SSNACTIVE; 1113 } 1114 1115 fd = smb_open_driver(); 1116 if (fd < 0) 1117 return (ENODEV); 1118 1119 ctx->ct_dev_fd = fd; 1120 return (0); 1121 } 1122 1123 1124 /* 1125 * Find or create a connection + logon session 1126 */ 1127 int 1128 smb_ctx_get_ssn(struct smb_ctx *ctx) 1129 { 1130 int err = 0; 1131 1132 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) 1133 return (EINVAL); 1134 1135 if (ctx->ct_dev_fd < 0) { 1136 if ((err = smb_ctx_gethandle(ctx))) 1137 return (err); 1138 } 1139 1140 /* 1141 * Check whether the driver already has a VC 1142 * we can use. If so, we're done! 1143 */ 1144 err = smb_ctx_findvc(ctx); 1145 if (err == 0) { 1146 DPRINT("found an existing VC"); 1147 } else { 1148 /* 1149 * This calls the IOD to create a new session. 1150 */ 1151 DPRINT("setup a new VC"); 1152 err = smb_ctx_newvc(ctx); 1153 if (err != 0) 1154 return (err); 1155 1156 /* 1157 * Call findvc again. The new VC sould be 1158 * found in the driver this time. 1159 */ 1160 err = smb_ctx_findvc(ctx); 1161 } 1162 1163 return (err); 1164 } 1165 1166 /* 1167 * Get the string representation of a share "use" type, 1168 * as needed for the "service" in tree connect. 1169 */ 1170 static const char * 1171 smb_use_type_str(smb_use_shtype_t stype) 1172 { 1173 const char *pp; 1174 1175 switch (stype) { 1176 default: 1177 case USE_WILDCARD: 1178 pp = "?????"; 1179 break; 1180 case USE_DISKDEV: 1181 pp = "A:"; 1182 break; 1183 case USE_SPOOLDEV: 1184 pp = "LPT1:"; 1185 break; 1186 case USE_CHARDEV: 1187 pp = "COMM"; 1188 break; 1189 case USE_IPC: 1190 pp = "IPC"; 1191 break; 1192 } 1193 return (pp); 1194 } 1195 1196 /* 1197 * Find or create a tree connection 1198 */ 1199 int 1200 smb_ctx_get_tree(struct smb_ctx *ctx) 1201 { 1202 smbioc_tcon_t *tcon = NULL; 1203 const char *stype; 1204 int cmd, err = 0; 1205 1206 if (ctx->ct_dev_fd < 0 || 1207 ctx->ct_origshare == NULL) { 1208 return (EINVAL); 1209 } 1210 1211 cmd = SMBIOC_TREE_CONNECT; 1212 tcon = malloc(sizeof (*tcon)); 1213 if (tcon == NULL) 1214 return (ENOMEM); 1215 bzero(tcon, sizeof (*tcon)); 1216 tcon->tc_flags = SMBLK_CREATE; 1217 tcon->tc_opt = 0; 1218 1219 /* The share name */ 1220 strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare, 1221 sizeof (tcon->tc_sh.sh_name)); 1222 1223 /* The share "use" type. */ 1224 stype = smb_use_type_str(ctx->ct_shtype_req); 1225 strlcpy(tcon->tc_sh.sh_type_req, stype, 1226 sizeof (tcon->tc_sh.sh_type_req)); 1227 1228 /* 1229 * Todo: share passwords for share-level security. 1230 * 1231 * The driver does the actual TCON call. 1232 */ 1233 if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) { 1234 err = errno; 1235 goto out; 1236 } 1237 1238 /* 1239 * Check the returned share type 1240 */ 1241 DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret); 1242 if (ctx->ct_shtype_req != USE_WILDCARD && 1243 0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) { 1244 smb_error(dgettext(TEXT_DOMAIN, 1245 "%s: incompatible share type"), 1246 0, ctx->ct_origshare); 1247 err = EINVAL; 1248 } 1249 1250 out: 1251 if (tcon != NULL) 1252 free(tcon); 1253 1254 return (err); 1255 } 1256 1257 /* 1258 * Return the hflags2 word for an smb_ctx. 1259 */ 1260 int 1261 smb_ctx_flags2(struct smb_ctx *ctx) 1262 { 1263 uint16_t flags2; 1264 1265 if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) { 1266 smb_error(dgettext(TEXT_DOMAIN, 1267 "can't get flags2 for a session"), errno); 1268 return (-1); 1269 } 1270 return (flags2); 1271 } 1272 1273 /* 1274 * Get the transport level session key. 1275 * Must already have an active SMB session. 1276 */ 1277 int 1278 smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len) 1279 { 1280 if (len < SMBIOC_HASH_SZ) 1281 return (EINVAL); 1282 1283 if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1) 1284 return (errno); 1285 1286 return (0); 1287 } 1288 1289 1290 /* 1291 * RC file parsing stuff 1292 */ 1293 1294 struct nv { 1295 char *name; 1296 int value; 1297 } minauth_table[] = { 1298 /* Allowed auth. types */ 1299 { "kerberos", SMB_AT_KRB5 }, 1300 { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 }, 1301 { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 }, 1302 { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 }, 1303 { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1| 1304 SMB_AT_ANON }, 1305 { NULL } 1306 }; 1307 1308 1309 /* 1310 * level values: 1311 * 0 - default 1312 * 1 - server 1313 * 2 - server:user 1314 * 3 - server:user:share 1315 */ 1316 static int 1317 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 1318 { 1319 char *p; 1320 int error; 1321 1322 #ifdef KICONV_SUPPORT 1323 if (level > 0) { 1324 rc_getstringptr(smb_rc, sname, "charsets", &p); 1325 if (p) { 1326 error = smb_ctx_setcharset(ctx, p); 1327 if (error) 1328 smb_error(dgettext(TEXT_DOMAIN, 1329 "charset specification in the section '%s' ignored"), 1330 error, sname); 1331 } 1332 } 1333 #endif 1334 1335 if (level <= 1) { 1336 /* Section is: [default] or [server] */ 1337 1338 rc_getstringptr(smb_rc, sname, "minauth", &p); 1339 if (p) { 1340 /* 1341 * "minauth" was set in this section; override 1342 * the current minimum authentication setting. 1343 */ 1344 struct nv *nvp; 1345 for (nvp = minauth_table; nvp->name; nvp++) 1346 if (strcmp(p, nvp->name) == 0) 1347 break; 1348 if (nvp->name) 1349 ctx->ct_minauth = nvp->value; 1350 else { 1351 /* 1352 * Unknown minimum authentication level. 1353 */ 1354 smb_error(dgettext(TEXT_DOMAIN, 1355 "invalid minimum authentication level \"%s\" specified in the section %s"), 1356 0, p, sname); 1357 return (EINVAL); 1358 } 1359 } 1360 1361 rc_getstringptr(smb_rc, sname, "signing", &p); 1362 if (p) { 1363 /* 1364 * "signing" was set in this section; override 1365 * the current signing settings. 1366 */ 1367 ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK; 1368 if (strcmp(p, "disabled") == 0) { 1369 /* leave flags zero (expr for lint) */ 1370 (void) ctx->ct_vopt; 1371 } else if (strcmp(p, "enabled") == 0) { 1372 ctx->ct_vopt |= 1373 SMBVOPT_SIGNING_ENABLED; 1374 } else if (strcmp(p, "required") == 0) { 1375 ctx->ct_vopt |= 1376 SMBVOPT_SIGNING_ENABLED | 1377 SMBVOPT_SIGNING_REQUIRED; 1378 } else { 1379 /* 1380 * Unknown "signing" value. 1381 */ 1382 smb_error(dgettext(TEXT_DOMAIN, 1383 "invalid signing policy \"%s\" specified in the section %s"), 1384 0, p, sname); 1385 return (EINVAL); 1386 } 1387 } 1388 1389 /* 1390 * Domain name. Allow both keywords: 1391 * "workgroup", "domain" 1392 * 1393 * Note: these are NOT marked "from CMD". 1394 * See long comment at smb_ctx_init() 1395 */ 1396 rc_getstringptr(smb_rc, sname, "workgroup", &p); 1397 if (p) { 1398 nls_str_upper(p, p); 1399 error = smb_ctx_setdomain(ctx, p, 0); 1400 if (error) 1401 smb_error(dgettext(TEXT_DOMAIN, 1402 "workgroup specification in the " 1403 "section '%s' ignored"), error, sname); 1404 } 1405 rc_getstringptr(smb_rc, sname, "domain", &p); 1406 if (p) { 1407 nls_str_upper(p, p); 1408 error = smb_ctx_setdomain(ctx, p, 0); 1409 if (error) 1410 smb_error(dgettext(TEXT_DOMAIN, 1411 "domain specification in the " 1412 "section '%s' ignored"), error, sname); 1413 } 1414 1415 rc_getstringptr(smb_rc, sname, "user", &p); 1416 if (p) { 1417 error = smb_ctx_setuser(ctx, p, 0); 1418 if (error) 1419 smb_error(dgettext(TEXT_DOMAIN, 1420 "user specification in the " 1421 "section '%s' ignored"), error, sname); 1422 } 1423 } 1424 1425 if (level == 1) { 1426 /* Section is: [server] */ 1427 rc_getstringptr(smb_rc, sname, "addr", &p); 1428 if (p) { 1429 error = smb_ctx_setsrvaddr(ctx, p); 1430 if (error) { 1431 smb_error(dgettext(TEXT_DOMAIN, 1432 "invalid address specified in section %s"), 1433 0, sname); 1434 return (error); 1435 } 1436 } 1437 } 1438 1439 rc_getstringptr(smb_rc, sname, "password", &p); 1440 if (p) { 1441 error = smb_ctx_setpassword(ctx, p, 0); 1442 if (error) 1443 smb_error(dgettext(TEXT_DOMAIN, 1444 "password specification in the section '%s' ignored"), 1445 error, sname); 1446 } 1447 1448 return (0); 1449 } 1450 1451 /* 1452 * read rc file as follows: 1453 * 0: read [default] section 1454 * 1: override with [server] section 1455 * 2: override with [server:user] section 1456 * 3: override with [server:user:share] section 1457 * Since absence of rcfile is not fatal, silently ignore this fact. 1458 * smb_rc file should be closed by caller. 1459 */ 1460 int 1461 smb_ctx_readrc(struct smb_ctx *ctx) 1462 { 1463 char *home; 1464 char *sname = NULL; 1465 int sname_max; 1466 int err = 0; 1467 1468 if ((home = getenv("HOME")) == NULL) 1469 home = ctx->ct_home; 1470 if ((err = smb_open_rcfile(home)) != 0) { 1471 DPRINT("smb_open_rcfile, err=%d", err); 1472 /* ignore any error here */ 1473 return (0); 1474 } 1475 1476 sname_max = 3 * SMBIOC_MAX_NAME + 4; 1477 sname = malloc(sname_max); 1478 if (sname == NULL) { 1479 err = ENOMEM; 1480 goto done; 1481 } 1482 1483 /* 1484 * default parameters (level=0) 1485 */ 1486 smb_ctx_readrcsection(ctx, "default", 0); 1487 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 1488 1489 /* 1490 * If we don't have a server name, we can't read any of the 1491 * [server...] sections. 1492 */ 1493 if (ctx->ct_fullserver == NULL) 1494 goto done; 1495 /* 1496 * SERVER parameters. 1497 */ 1498 smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1); 1499 1500 /* 1501 * If we don't have a user name, we can't read any of the 1502 * [server:user...] sections. 1503 */ 1504 if (ctx->ct_user[0] == 0) 1505 goto done; 1506 /* 1507 * SERVER:USER parameters 1508 */ 1509 snprintf(sname, sname_max, "%s:%s", 1510 ctx->ct_fullserver, 1511 ctx->ct_user); 1512 smb_ctx_readrcsection(ctx, sname, 2); 1513 1514 1515 /* 1516 * If we don't have a share name, we can't read any of the 1517 * [server:user:share] sections. 1518 */ 1519 if (ctx->ct_origshare == NULL) 1520 goto done; 1521 /* 1522 * SERVER:USER:SHARE parameters 1523 */ 1524 snprintf(sname, sname_max, "%s:%s:%s", 1525 ctx->ct_fullserver, 1526 ctx->ct_user, 1527 ctx->ct_origshare); 1528 smb_ctx_readrcsection(ctx, sname, 3); 1529 1530 done: 1531 if (sname) 1532 free(sname); 1533 smb_close_rcfile(); 1534 if (smb_debug) 1535 dump_ctx("after smb_ctx_readrc", ctx); 1536 if (err) 1537 DPRINT("err=%d\n", err); 1538 1539 return (err); 1540 } 1541