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