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 2011 Nexenta Systems, Inc. All rights reserved. 37 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 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 "private.h" 69 #include "ntlm.h" 70 71 #ifndef FALSE 72 #define FALSE 0 73 #endif 74 #ifndef TRUE 75 #define TRUE 1 76 #endif 77 78 struct nv { 79 char *name; 80 int value; 81 }; 82 83 /* These two may be set by commands. */ 84 int smb_debug, smb_verbose; 85 86 /* 87 * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt 88 */ 89 const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:"; 90 91 /* 92 * Defaults for new contexts (connections to servers). 93 * These are set by smbfs_set_default_... 94 */ 95 static char default_domain[SMBIOC_MAX_NAME]; 96 static char default_user[SMBIOC_MAX_NAME]; 97 98 99 /* 100 * Give the RPC library a callback hook that will be 101 * called whenever we destroy or reinit an smb_ctx_t. 102 * The name rpc_cleanup_smbctx() is legacy, and was 103 * originally a direct call into the RPC code. 104 */ 105 static smb_ctx_close_hook_t close_hook; 106 static void 107 rpc_cleanup_smbctx(struct smb_ctx *ctx) 108 { 109 if (close_hook) 110 (*close_hook)(ctx); 111 } 112 void 113 smb_ctx_set_close_hook(smb_ctx_close_hook_t hook) 114 { 115 close_hook = hook; 116 } 117 118 void 119 dump_ctx_flags(int flags) 120 { 121 printf(" Flags: "); 122 if (flags == 0) 123 printf("0"); 124 if (flags & SMBCF_NOPWD) 125 printf("NOPWD "); 126 if (flags & SMBCF_SRIGHTS) 127 printf("SRIGHTS "); 128 if (flags & SMBCF_LOCALE) 129 printf("LOCALE "); 130 if (flags & SMBCF_CMD_DOM) 131 printf("CMD_DOM "); 132 if (flags & SMBCF_CMD_USR) 133 printf("CMD_USR "); 134 if (flags & SMBCF_CMD_PW) 135 printf("CMD_PW "); 136 if (flags & SMBCF_RESOLVED) 137 printf("RESOLVED "); 138 if (flags & SMBCF_KCBAD) 139 printf("KCBAD "); 140 if (flags & SMBCF_KCFOUND) 141 printf("KCFOUND "); 142 if (flags & SMBCF_BROWSEOK) 143 printf("BROWSEOK "); 144 if (flags & SMBCF_AUTHREQ) 145 printf("AUTHREQ "); 146 if (flags & SMBCF_KCSAVE) 147 printf("KCSAVE "); 148 if (flags & SMBCF_XXX) 149 printf("XXX "); 150 if (flags & SMBCF_SSNACTIVE) 151 printf("SSNACTIVE "); 152 if (flags & SMBCF_KCDOMAIN) 153 printf("KCDOMAIN "); 154 printf("\n"); 155 } 156 157 void 158 dump_iod_ssn(smb_iod_ssn_t *is) 159 { 160 static const char zeros[NTLM_HASH_SZ] = {0}; 161 struct smbioc_ossn *ssn = &is->iod_ossn; 162 163 printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname); 164 dump_sockaddr(&ssn->ssn_srvaddr.sa); 165 printf(" dom=\"%s\", user=\"%s\"\n", 166 ssn->ssn_domain, ssn->ssn_user); 167 printf(" ct_vopt=0x%x, ct_owner=%d\n", 168 ssn->ssn_vopt, ssn->ssn_owner); 169 printf(" ct_authflags=0x%x\n", is->iod_authflags); 170 171 printf(" ct_nthash:"); 172 if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ)) 173 smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ); 174 else 175 printf(" {0}\n"); 176 177 printf(" ct_lmhash:"); 178 if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ)) 179 smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ); 180 else 181 printf(" {0}\n"); 182 } 183 184 void 185 dump_ctx(char *where, struct smb_ctx *ctx) 186 { 187 printf("context %s:\n", where); 188 dump_ctx_flags(ctx->ct_flags); 189 190 if (ctx->ct_locname) 191 printf(" localname=\"%s\"", ctx->ct_locname); 192 else 193 printf(" localname=NULL"); 194 195 if (ctx->ct_fullserver) 196 printf(" fullserver=\"%s\"", ctx->ct_fullserver); 197 else 198 printf(" fullserver=NULL"); 199 200 if (ctx->ct_srvaddr_s) 201 printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s); 202 else 203 printf(" srvaddr_s=NULL\n"); 204 205 if (ctx->ct_addrinfo) 206 dump_addrinfo(ctx->ct_addrinfo); 207 else 208 printf(" ct_addrinfo = NULL\n"); 209 210 dump_iod_ssn(&ctx->ct_iod_ssn); 211 212 printf(" share_name=\"%s\", share_type=%d\n", 213 ctx->ct_origshare ? ctx->ct_origshare : "", 214 ctx->ct_shtype_req); 215 216 printf(" ct_home=\"%s\"\n", ctx->ct_home); 217 printf(" ct_rpath=\"%s\"\n", ctx->ct_rpath); 218 } 219 220 int 221 smb_ctx_alloc(struct smb_ctx **ctx_pp) 222 { 223 smb_ctx_t *ctx; 224 int err; 225 226 ctx = malloc(sizeof (*ctx)); 227 if (ctx == NULL) 228 return (ENOMEM); 229 err = smb_ctx_init(ctx); 230 if (err != 0) { 231 free(ctx); 232 return (err); 233 } 234 *ctx_pp = ctx; 235 return (0); 236 } 237 238 /* 239 * Initialize an smb_ctx struct (defaults) 240 */ 241 int 242 smb_ctx_init(struct smb_ctx *ctx) 243 { 244 int error; 245 246 bzero(ctx, sizeof (*ctx)); 247 248 error = nb_ctx_create(&ctx->ct_nb); 249 if (error) 250 return (error); 251 252 ctx->ct_dev_fd = -1; 253 ctx->ct_door_fd = -1; 254 ctx->ct_tran_fd = -1; 255 ctx->ct_parsedlevel = SMBL_NONE; 256 ctx->ct_minlevel = SMBL_NONE; 257 ctx->ct_maxlevel = SMBL_PATH; 258 259 /* Fill in defaults */ 260 ctx->ct_vopt = SMBVOPT_EXT_SEC; 261 ctx->ct_owner = SMBM_ANY_OWNER; 262 ctx->ct_authflags = SMB_AT_DEFAULT; 263 ctx->ct_minauth = SMB_AT_DEFAULT; 264 265 /* 266 * Default domain, user, ... 267 */ 268 strlcpy(ctx->ct_domain, default_domain, 269 sizeof (ctx->ct_domain)); 270 strlcpy(ctx->ct_user, default_user, 271 sizeof (ctx->ct_user)); 272 273 return (0); 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 ctx->ct_home = NULL; 436 } 437 if (ctx->ct_rpath) { 438 free(ctx->ct_rpath); 439 ctx->ct_rpath = NULL; 440 } 441 if (ctx->ct_srv_OS) { 442 free(ctx->ct_srv_OS); 443 ctx->ct_srv_OS = NULL; 444 } 445 if (ctx->ct_srv_LM) { 446 free(ctx->ct_srv_LM); 447 ctx->ct_srv_LM = NULL; 448 } 449 if (ctx->ct_mackey) { 450 free(ctx->ct_mackey); 451 ctx->ct_mackey = NULL; 452 } 453 } 454 455 /* 456 * Parse the UNC path. Here we expect something like 457 * "//[[domain;]user[:password]@]host[/share[/path]]" 458 * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 459 * Values found here are marked as "from CMD". 460 */ 461 int 462 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, 463 int minlevel, int maxlevel, int sharetype, 464 const char **next) 465 { 466 char tmp[1024]; 467 char *host, *share, *path; 468 char *dom, *usr, *pw, *p; 469 int error; 470 471 /* 472 * This may be called outside of _scan_argv, 473 * so make sure these get initialized. 474 */ 475 ctx->ct_minlevel = minlevel; 476 ctx->ct_maxlevel = maxlevel; 477 ctx->ct_shtype_req = sharetype; 478 ctx->ct_parsedlevel = SMBL_NONE; 479 480 dom = usr = pw = host = NULL; 481 482 /* Work on a temporary copy, fix back slashes. */ 483 strlcpy(tmp, unc, sizeof (tmp)); 484 for (p = tmp; *p; p++) 485 if (*p == '\\') 486 *p = '/'; 487 488 if (tmp[0] != '/' || tmp[1] != '/') { 489 smb_error(dgettext(TEXT_DOMAIN, 490 "UNC should start with '//'"), 0); 491 error = EINVAL; 492 goto out; 493 } 494 p = tmp + 2; /* user@host... */ 495 496 /* Find the share part, if any. */ 497 share = strchr(p, '/'); 498 if (share) 499 *share = '\0'; 500 (void) unpercent(p); /* host component */ 501 502 /* 503 * Parse the "host" stuff right to left: 504 * 1: trailing "@hostname" (or whole field) 505 * 2: trailing ":password" 506 * 3: trailing "domain;user" (or just user) 507 */ 508 host = strrchr(p, '@'); 509 if (host == NULL) { 510 host = p; /* no user@ prefix */ 511 } else { 512 *host++ = '\0'; 513 514 /* may have [[domain;]user[:passwd]] */ 515 pw = strchr(p, ':'); 516 if (pw) 517 *pw++ = '\0'; 518 usr = strchr(p, ';'); 519 if (usr) { 520 *usr++ = '\0'; 521 dom = p; 522 } else 523 usr = p; 524 } 525 526 if (*host == '\0') { 527 smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0); 528 error = EINVAL; 529 goto out; 530 } 531 error = smb_ctx_setfullserver(ctx, host); 532 if (error) 533 goto out; 534 ctx->ct_parsedlevel = SMBL_VC; 535 536 if (dom != NULL) { 537 error = smb_ctx_setdomain(ctx, dom, TRUE); 538 if (error) 539 goto out; 540 } 541 if (usr != NULL) { 542 if (*usr == '\0') { 543 smb_error(dgettext(TEXT_DOMAIN, 544 "empty user name"), 0); 545 error = EINVAL; 546 goto out; 547 } 548 if (ctx->ct_maxlevel < SMBL_VC) { 549 smb_error(dgettext(TEXT_DOMAIN, 550 "no user name required"), 0); 551 error = EINVAL; 552 goto out; 553 } 554 error = smb_ctx_setuser(ctx, usr, TRUE); 555 if (error) 556 goto out; 557 } 558 if (pw != NULL) { 559 error = smb_ctx_setpassword(ctx, pw, TRUE); 560 if (error) 561 goto out; 562 } 563 564 if (share != NULL) { 565 /* restore the slash */ 566 *share = '/'; 567 p = share + 1; 568 569 /* Find the path part, if any. */ 570 path = strchr(p, '/'); 571 if (path) 572 *path = '\0'; 573 (void) unpercent(p); /* share component */ 574 575 if (*p == '\0') { 576 smb_error(dgettext(TEXT_DOMAIN, 577 "empty share name"), 0); 578 error = EINVAL; 579 goto out; 580 } 581 if (ctx->ct_maxlevel < SMBL_SHARE) { 582 smb_error(dgettext(TEXT_DOMAIN, 583 "no share name required"), 0); 584 error = EINVAL; 585 goto out; 586 } 587 588 /* 589 * Special case UNC names like: 590 * //host/PIPE/endpoint 591 * to have share: IPC$ 592 */ 593 if (strcasecmp(p, "PIPE") == 0) { 594 sharetype = USE_IPC; 595 p = "IPC$"; 596 } 597 error = smb_ctx_setshare(ctx, p, sharetype); 598 if (error) 599 goto out; 600 ctx->ct_parsedlevel = SMBL_SHARE; 601 602 if (path) { 603 /* restore the slash */ 604 *path = '/'; 605 p = path + 1; 606 (void) unpercent(p); /* remainder */ 607 free(ctx->ct_rpath); 608 ctx->ct_rpath = strdup(path); 609 } 610 } else if (ctx->ct_minlevel >= SMBL_SHARE) { 611 smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0); 612 error = EINVAL; 613 goto out; 614 } 615 616 if (next) 617 *next = NULL; 618 619 out: 620 if (error == 0 && smb_debug > 0) 621 dump_ctx("after smb_ctx_parseunc", ctx); 622 623 return (error); 624 } 625 626 #ifdef KICONV_SUPPORT 627 int 628 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 629 { 630 char *cp, *servercs, *localcs; 631 int cslen = sizeof (ctx->ct_ssn.ioc_localcs); 632 int scslen, lcslen, error; 633 634 cp = strchr(arg, ':'); 635 lcslen = cp ? (cp - arg) : 0; 636 if (lcslen == 0 || lcslen >= cslen) { 637 smb_error(dgettext(TEXT_DOMAIN, 638 "invalid local charset specification (%s)"), 0, arg); 639 return (EINVAL); 640 } 641 scslen = (size_t)strlen(++cp); 642 if (scslen == 0 || scslen >= cslen) { 643 smb_error(dgettext(TEXT_DOMAIN, 644 "invalid server charset specification (%s)"), 0, arg); 645 return (EINVAL); 646 } 647 localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 648 localcs[lcslen] = 0; 649 servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 650 error = nls_setrecode(localcs, servercs); 651 if (error == 0) 652 return (0); 653 smb_error(dgettext(TEXT_DOMAIN, 654 "can't initialize iconv support (%s:%s)"), 655 error, localcs, servercs); 656 localcs[0] = 0; 657 servercs[0] = 0; 658 return (error); 659 } 660 #endif /* KICONV_SUPPORT */ 661 662 int 663 smb_ctx_setauthflags(struct smb_ctx *ctx, int flags) 664 { 665 ctx->ct_authflags = flags; 666 return (0); 667 } 668 669 int 670 smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name) 671 { 672 char *p = strdup(name); 673 674 if (p == NULL) 675 return (ENOMEM); 676 if (ctx->ct_fullserver) 677 free(ctx->ct_fullserver); 678 ctx->ct_fullserver = p; 679 return (0); 680 } 681 682 int 683 smb_ctx_setserver(struct smb_ctx *ctx, const char *name) 684 { 685 strlcpy(ctx->ct_srvname, name, 686 sizeof (ctx->ct_srvname)); 687 return (0); 688 } 689 690 int 691 smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) 692 { 693 694 if (strlen(name) >= sizeof (ctx->ct_user)) { 695 smb_error(dgettext(TEXT_DOMAIN, 696 "user name '%s' too long"), 0, name); 697 return (ENAMETOOLONG); 698 } 699 700 /* 701 * Don't overwrite a value from the command line 702 * with one from anywhere else. 703 */ 704 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR)) 705 return (0); 706 707 strlcpy(ctx->ct_user, name, 708 sizeof (ctx->ct_user)); 709 710 /* Mark this as "from the command line". */ 711 if (from_cmd) 712 ctx->ct_flags |= SMBCF_CMD_USR; 713 714 return (0); 715 } 716 717 /* 718 * Don't overwrite a domain name from the 719 * command line with one from anywhere else. 720 * See smb_ctx_init() for notes about this. 721 */ 722 int 723 smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd) 724 { 725 726 if (strlen(name) >= sizeof (ctx->ct_domain)) { 727 smb_error(dgettext(TEXT_DOMAIN, 728 "workgroup name '%s' too long"), 0, name); 729 return (ENAMETOOLONG); 730 } 731 732 /* 733 * Don't overwrite a value from the command line 734 * with one from anywhere else. 735 */ 736 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM)) 737 return (0); 738 739 strlcpy(ctx->ct_domain, name, 740 sizeof (ctx->ct_domain)); 741 742 /* Mark this as "from the command line". */ 743 if (from_cmd) 744 ctx->ct_flags |= SMBCF_CMD_DOM; 745 746 return (0); 747 } 748 749 int 750 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd) 751 { 752 int err; 753 754 if (passwd == NULL) 755 return (EINVAL); 756 if (strlen(passwd) >= sizeof (ctx->ct_password)) { 757 smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0); 758 return (ENAMETOOLONG); 759 } 760 761 /* 762 * If called again after comand line parsing, 763 * don't overwrite a value from the command line 764 * with one from any stored config. 765 */ 766 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW)) 767 return (0); 768 769 memset(ctx->ct_password, 0, sizeof (ctx->ct_password)); 770 if (strncmp(passwd, "$$1", 3) == 0) 771 (void) smb_simpledecrypt(ctx->ct_password, passwd); 772 else 773 strlcpy(ctx->ct_password, passwd, 774 sizeof (ctx->ct_password)); 775 776 /* 777 * Compute LM hash, NT hash. 778 */ 779 if (ctx->ct_password[0]) { 780 err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password); 781 if (err != 0) 782 return (err); 783 err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password); 784 if (err != 0) 785 return (err); 786 } 787 788 /* Mark this as "from the command line". */ 789 if (from_cmd) 790 ctx->ct_flags |= SMBCF_CMD_PW; 791 792 return (0); 793 } 794 795 /* 796 * Use this to set NTLM auth. info (hashes) 797 * when we don't have the password. 798 */ 799 int 800 smb_ctx_setpwhash(smb_ctx_t *ctx, 801 const uchar_t *nthash, const uchar_t *lmhash) 802 { 803 804 /* Need ct_password to be non-null. */ 805 if (ctx->ct_password[0] == '\0') 806 strlcpy(ctx->ct_password, "$HASH", 807 sizeof (ctx->ct_password)); 808 809 /* 810 * Compute LM hash, NT hash. 811 */ 812 memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ); 813 814 /* The LM hash is optional */ 815 if (lmhash) { 816 memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ); 817 } 818 819 return (0); 820 } 821 822 int 823 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 824 { 825 if (strlen(share) >= SMBIOC_MAX_NAME) { 826 smb_error(dgettext(TEXT_DOMAIN, 827 "share name '%s' too long"), 0, share); 828 return (ENAMETOOLONG); 829 } 830 if (ctx->ct_origshare) 831 free(ctx->ct_origshare); 832 if ((ctx->ct_origshare = strdup(share)) == NULL) 833 return (ENOMEM); 834 835 ctx->ct_shtype_req = stype; 836 837 return (0); 838 } 839 840 int 841 smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 842 { 843 if (addr == NULL || addr[0] == 0) 844 return (EINVAL); 845 if (ctx->ct_srvaddr_s) 846 free(ctx->ct_srvaddr_s); 847 if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL) 848 return (ENOMEM); 849 return (0); 850 } 851 852 /* 853 * API for library caller to set signing enabled, required 854 * Note: if not enable, ignore require 855 */ 856 int 857 smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require) 858 { 859 ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK; 860 if (enable) { 861 ctx->ct_vopt |= SMBVOPT_SIGNING_ENABLED; 862 if (require) 863 ctx->ct_vopt |= SMBVOPT_SIGNING_REQUIRED; 864 } 865 return (0); 866 } 867 868 static int 869 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 870 { 871 struct group gr; 872 struct passwd pw; 873 char buf[NSS_BUFLEN_PASSWD]; 874 char *cp; 875 876 cp = strchr(pair, ':'); 877 if (cp) { 878 *cp++ = '\0'; 879 if (*cp && gid) { 880 if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) { 881 *gid = gr.gr_gid; 882 } else 883 smb_error(dgettext(TEXT_DOMAIN, 884 "Invalid group name %s, ignored"), 0, cp); 885 } 886 } 887 if (*pair) { 888 if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) { 889 *uid = pw.pw_uid; 890 } else 891 smb_error(dgettext(TEXT_DOMAIN, 892 "Invalid user name %s, ignored"), 0, pair); 893 } 894 895 return (0); 896 } 897 898 /* 899 * Suport a securty options arg, i.e. -S noext,lm,ntlm 900 * for testing various type of authenticators. 901 */ 902 static struct nv 903 sectype_table[] = { 904 /* noext - handled below */ 905 { "anon", SMB_AT_ANON }, 906 { "lm", SMB_AT_LM1 }, 907 { "ntlm", SMB_AT_NTLM1 }, 908 { "ntlm2", SMB_AT_NTLM2 }, 909 { "krb5", SMB_AT_KRB5 }, 910 { NULL, 0 }, 911 }; 912 int 913 smb_parse_secopts(struct smb_ctx *ctx, const char *arg) 914 { 915 const char *sep = ":;,"; 916 const char *p = arg; 917 struct nv *nv; 918 int nlen, tlen; 919 int authflags = 0; 920 921 for (;;) { 922 /* skip separators */ 923 tlen = strspn(p, sep); 924 p += tlen; 925 926 nlen = strcspn(p, sep); 927 if (nlen == 0) 928 break; 929 930 if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) { 931 /* Don't offer extended security. */ 932 ctx->ct_vopt &= ~SMBVOPT_EXT_SEC; 933 p += nlen; 934 continue; 935 } 936 937 /* This is rarely called, so not optimized. */ 938 for (nv = sectype_table; nv->name; nv++) { 939 tlen = strlen(nv->name); 940 if (tlen == nlen && 0 == strncmp(p, nv->name, tlen)) 941 break; 942 } 943 if (nv->name == NULL) { 944 smb_error(dgettext(TEXT_DOMAIN, 945 "%s: invalid security options"), 0, p); 946 return (EINVAL); 947 } 948 authflags |= nv->value; 949 p += nlen; 950 } 951 952 if (authflags) 953 ctx->ct_authflags = authflags; 954 955 return (0); 956 } 957 958 /* 959 * Commands use this with getopt. See: 960 * STDPARAM_OPT, STDPARAM_ARGS 961 * Called after smb_ctx_readrc(). 962 */ 963 int 964 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 965 { 966 int error = 0; 967 char *p, *cp; 968 char tmp[1024]; 969 970 switch (opt) { 971 case 'A': 972 case 'U': 973 /* Handled in smb_ctx_init() */ 974 break; 975 case 'I': 976 error = smb_ctx_setsrvaddr(ctx, arg); 977 break; 978 case 'M': 979 /* share connect rights - ignored */ 980 ctx->ct_flags |= SMBCF_SRIGHTS; 981 break; 982 case 'N': 983 ctx->ct_flags |= SMBCF_NOPWD; 984 break; 985 case 'O': 986 p = strdup(arg); 987 cp = strchr(p, '/'); 988 if (cp) 989 *cp = '\0'; 990 error = smb_parse_owner(cp, &ctx->ct_owner, NULL); 991 free(p); 992 break; 993 case 'P': 994 /* ctx->ct_vopt |= SMBCOPT_PERMANENT; */ 995 break; 996 case 'R': 997 /* retry count - ignored */ 998 break; 999 case 'S': 1000 /* Security options (undocumented, just for tests) */ 1001 error = smb_parse_secopts(ctx, arg); 1002 break; 1003 case 'T': 1004 /* timeout - ignored */ 1005 break; 1006 case 'D': /* domain */ 1007 case 'W': /* workgroup (legacy alias) */ 1008 error = smb_ctx_setdomain(ctx, tmp, TRUE); 1009 break; 1010 } 1011 return (error); 1012 } 1013 1014 1015 /* 1016 * Original code injected iconv tables into the kernel. 1017 * Not sure if we'll need this or not... REVISIT 1018 */ 1019 #ifdef KICONV_SUPPORT 1020 static int 1021 smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl) 1022 { 1023 int error = 0; 1024 1025 error = kiconv_add_xlat_table(to, from, tbl); 1026 if (error && error != EEXIST) { 1027 smb_error(dgettext(TEXT_DOMAIN, 1028 "can not setup kernel iconv table (%s:%s)"), 1029 error, from, to); 1030 return (error); 1031 } 1032 return (error); 1033 } 1034 #endif /* KICONV_SUPPORT */ 1035 1036 /* 1037 * Verify context info. before connect operation(s), 1038 * lookup specified server and try to fill all forgotten fields. 1039 * Legacy name used by commands. 1040 */ 1041 int 1042 smb_ctx_resolve(struct smb_ctx *ctx) 1043 { 1044 struct smbioc_ossn *ssn = &ctx->ct_ssn; 1045 int error = 0; 1046 #ifdef KICONV_SUPPORT 1047 uchar_t cstbl[256]; 1048 uint_t i; 1049 #endif 1050 1051 if (smb_debug) 1052 dump_ctx("before smb_ctx_resolve", ctx); 1053 1054 ctx->ct_flags &= ~SMBCF_RESOLVED; 1055 1056 if (ctx->ct_fullserver == NULL) { 1057 smb_error(dgettext(TEXT_DOMAIN, 1058 "no server name specified"), 0); 1059 return (EINVAL); 1060 } 1061 1062 if (ctx->ct_minlevel >= SMBL_SHARE && 1063 ctx->ct_origshare == NULL) { 1064 smb_error(dgettext(TEXT_DOMAIN, 1065 "no share name specified for %s@%s"), 1066 0, ssn->ssn_user, ctx->ct_fullserver); 1067 return (EINVAL); 1068 } 1069 error = nb_ctx_resolve(ctx->ct_nb); 1070 if (error) 1071 return (error); 1072 #ifdef KICONV_SUPPORT 1073 if (ssn->ioc_localcs[0] == 0) 1074 strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ 1075 error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 1076 if (error) 1077 return (error); 1078 error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 1079 if (error) 1080 return (error); 1081 if (ssn->ioc_servercs[0] != 0) { 1082 for (i = 0; i < sizeof (cstbl); i++) 1083 cstbl[i] = i; 1084 nls_mem_toext(cstbl, cstbl, sizeof (cstbl)); 1085 error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, 1086 cstbl); 1087 if (error) 1088 return (error); 1089 for (i = 0; i < sizeof (cstbl); i++) 1090 cstbl[i] = i; 1091 nls_mem_toloc(cstbl, cstbl, sizeof (cstbl)); 1092 error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, 1093 cstbl); 1094 if (error) 1095 return (error); 1096 } 1097 #endif /* KICONV_SUPPORT */ 1098 1099 /* 1100 * Lookup the IP address and fill in ct_addrinfo. 1101 * 1102 * Note: smb_ctx_getaddr() returns a EAI_xxx 1103 * error value like getaddrinfo(3), but this 1104 * function needs to return an errno value. 1105 */ 1106 error = smb_ctx_getaddr(ctx); 1107 if (error) { 1108 const char *ais = gai_strerror(error); 1109 smb_error(dgettext(TEXT_DOMAIN, 1110 "can't resolve name\"%s\", %s"), 1111 0, ctx->ct_fullserver, ais); 1112 return (ENODATA); 1113 } 1114 assert(ctx->ct_addrinfo != NULL); 1115 1116 /* 1117 * If we have a user name but no password, 1118 * check for a keychain entry. 1119 * XXX: Only for auth NTLM? 1120 */ 1121 if (ctx->ct_user[0] == '\0') { 1122 /* 1123 * No user name (anonymous session). 1124 * The minauth checks do not apply. 1125 */ 1126 ctx->ct_authflags = SMB_AT_ANON; 1127 } else { 1128 /* 1129 * Have a user name. 1130 * If we don't have a p/w yet, 1131 * try the keychain. 1132 */ 1133 if (ctx->ct_password[0] == '\0') 1134 (void) smb_get_keychain(ctx); 1135 /* 1136 * Mask out disallowed auth types. 1137 */ 1138 ctx->ct_authflags &= ctx->ct_minauth; 1139 } 1140 if (ctx->ct_authflags == 0) { 1141 smb_error(dgettext(TEXT_DOMAIN, 1142 "no valid auth. types"), 0); 1143 return (ENOTSUP); 1144 } 1145 1146 ctx->ct_flags |= SMBCF_RESOLVED; 1147 if (smb_debug) 1148 dump_ctx("after smb_ctx_resolve", ctx); 1149 1150 return (0); 1151 } 1152 1153 int 1154 smb_open_driver() 1155 { 1156 int fd; 1157 1158 fd = open("/dev/"NSMB_NAME, O_RDWR); 1159 if (fd < 0) { 1160 return (-1); 1161 } 1162 1163 /* This handle controls per-process resources. */ 1164 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 1165 1166 return (fd); 1167 } 1168 1169 int 1170 smb_ctx_gethandle(struct smb_ctx *ctx) 1171 { 1172 int fd, err; 1173 uint32_t version; 1174 1175 if (ctx->ct_dev_fd != -1) { 1176 rpc_cleanup_smbctx(ctx); 1177 close(ctx->ct_dev_fd); 1178 ctx->ct_dev_fd = -1; 1179 ctx->ct_flags &= ~SMBCF_SSNACTIVE; 1180 } 1181 1182 fd = smb_open_driver(); 1183 if (fd < 0) { 1184 err = errno; 1185 smb_error(dgettext(TEXT_DOMAIN, 1186 "failed to open driver"), err); 1187 return (err); 1188 } 1189 1190 /* 1191 * Check the driver version (paranoia) 1192 */ 1193 if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) 1194 version = 0; 1195 if (version != NSMB_VERSION) { 1196 smb_error(dgettext(TEXT_DOMAIN, 1197 "incorrect driver version"), 0); 1198 close(fd); 1199 return (ENODEV); 1200 } 1201 1202 ctx->ct_dev_fd = fd; 1203 return (0); 1204 } 1205 1206 1207 /* 1208 * Find or create a connection + logon session 1209 */ 1210 int 1211 smb_ctx_get_ssn(struct smb_ctx *ctx) 1212 { 1213 int err = 0; 1214 1215 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) 1216 return (EINVAL); 1217 1218 if (ctx->ct_dev_fd < 0) { 1219 if ((err = smb_ctx_gethandle(ctx))) 1220 return (err); 1221 } 1222 1223 /* 1224 * Check whether the driver already has a VC 1225 * we can use. If so, we're done! 1226 */ 1227 err = smb_ctx_findvc(ctx); 1228 if (err == 0) { 1229 DPRINT("found an existing VC"); 1230 } else { 1231 /* 1232 * This calls the IOD to create a new session. 1233 */ 1234 DPRINT("setup a new VC"); 1235 err = smb_ctx_newvc(ctx); 1236 if (err != 0) 1237 return (err); 1238 1239 /* 1240 * Call findvc again. The new VC sould be 1241 * found in the driver this time. 1242 */ 1243 err = smb_ctx_findvc(ctx); 1244 } 1245 1246 return (err); 1247 } 1248 1249 /* 1250 * Find or create a tree connection 1251 */ 1252 int 1253 smb_ctx_get_tree(struct smb_ctx *ctx) 1254 { 1255 smbioc_tcon_t *tcon = NULL; 1256 int cmd, err = 0; 1257 1258 if (ctx->ct_dev_fd < 0 || 1259 ctx->ct_origshare == NULL) { 1260 return (EINVAL); 1261 } 1262 1263 cmd = SMBIOC_TREE_CONNECT; 1264 tcon = malloc(sizeof (*tcon)); 1265 if (tcon == NULL) 1266 return (ENOMEM); 1267 bzero(tcon, sizeof (*tcon)); 1268 tcon->tc_flags = SMBLK_CREATE; 1269 tcon->tc_opt = 0; 1270 1271 /* The share name */ 1272 strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare, 1273 sizeof (tcon->tc_sh.sh_name)); 1274 1275 /* The share "use" type. */ 1276 tcon->tc_sh.sh_use = ctx->ct_shtype_req; 1277 1278 /* 1279 * Todo: share passwords for share-level security. 1280 * 1281 * The driver does the actual TCON call. 1282 */ 1283 if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) { 1284 err = errno; 1285 goto out; 1286 } 1287 1288 /* 1289 * Check the returned share type 1290 */ 1291 DPRINT("ret. sh_type: \"%d\"", tcon->tc_sh.sh_type); 1292 if (ctx->ct_shtype_req != USE_WILDCARD && 1293 ctx->ct_shtype_req != tcon->tc_sh.sh_type) { 1294 smb_error(dgettext(TEXT_DOMAIN, 1295 "%s: incompatible share type"), 1296 0, ctx->ct_origshare); 1297 } 1298 1299 out: 1300 if (tcon != NULL) 1301 free(tcon); 1302 1303 return (err); 1304 } 1305 1306 /* 1307 * Return the hflags2 word for an smb_ctx. 1308 */ 1309 int 1310 smb_ctx_flags2(struct smb_ctx *ctx) 1311 { 1312 uint16_t flags2; 1313 1314 if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) { 1315 smb_error(dgettext(TEXT_DOMAIN, 1316 "can't get flags2 for a session"), errno); 1317 return (-1); 1318 } 1319 return (flags2); 1320 } 1321 1322 /* 1323 * Get the transport level session key. 1324 * Must already have an active SMB session. 1325 */ 1326 int 1327 smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len) 1328 { 1329 if (len < SMBIOC_HASH_SZ) 1330 return (EINVAL); 1331 1332 if (ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1) 1333 return (errno); 1334 1335 return (0); 1336 } 1337 1338 /* 1339 * RC file parsing stuff 1340 */ 1341 1342 static struct nv 1343 minauth_table[] = { 1344 /* Allowed auth. types */ 1345 { "kerberos", SMB_AT_KRB5 }, 1346 { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 }, 1347 { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 }, 1348 { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 }, 1349 { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1| 1350 SMB_AT_ANON }, 1351 { NULL } 1352 }; 1353 1354 1355 /* 1356 * level values: 1357 * 0 - default 1358 * 1 - server 1359 * 2 - server:user 1360 * 3 - server:user:share 1361 */ 1362 static int 1363 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 1364 { 1365 char *p; 1366 int error; 1367 1368 #ifdef KICONV_SUPPORT 1369 if (level > 0) { 1370 rc_getstringptr(smb_rc, sname, "charsets", &p); 1371 if (p) { 1372 error = smb_ctx_setcharset(ctx, p); 1373 if (error) 1374 smb_error(dgettext(TEXT_DOMAIN, 1375 "charset specification in the section '%s' ignored"), 1376 error, sname); 1377 } 1378 } 1379 #endif 1380 1381 if (level <= 1) { 1382 /* Section is: [default] or [server] */ 1383 1384 rc_getstringptr(smb_rc, sname, "minauth", &p); 1385 if (p) { 1386 /* 1387 * "minauth" was set in this section; override 1388 * the current minimum authentication setting. 1389 */ 1390 struct nv *nvp; 1391 for (nvp = minauth_table; nvp->name; nvp++) 1392 if (strcmp(p, nvp->name) == 0) 1393 break; 1394 if (nvp->name) 1395 ctx->ct_minauth = nvp->value; 1396 else { 1397 /* 1398 * Unknown minimum authentication level. 1399 */ 1400 smb_error(dgettext(TEXT_DOMAIN, 1401 "invalid minimum authentication level \"%s\" specified in the section %s"), 1402 0, p, sname); 1403 return (EINVAL); 1404 } 1405 } 1406 1407 rc_getstringptr(smb_rc, sname, "signing", &p); 1408 if (p) { 1409 /* 1410 * "signing" was set in this section; override 1411 * the current signing settings. Note: 1412 * setsigning flags are: enable, require 1413 */ 1414 if (strcmp(p, "disabled") == 0) { 1415 (void) smb_ctx_setsigning(ctx, FALSE, FALSE); 1416 } else if (strcmp(p, "enabled") == 0) { 1417 (void) smb_ctx_setsigning(ctx, TRUE, FALSE); 1418 } else if (strcmp(p, "required") == 0) { 1419 (void) smb_ctx_setsigning(ctx, TRUE, TRUE); 1420 } else { 1421 /* 1422 * Unknown "signing" value. 1423 */ 1424 smb_error(dgettext(TEXT_DOMAIN, 1425 "invalid signing policy \"%s\" specified in the section %s"), 1426 0, p, sname); 1427 return (EINVAL); 1428 } 1429 } 1430 1431 /* 1432 * Domain name. Allow both keywords: 1433 * "workgroup", "domain" 1434 * 1435 * Note: these are NOT marked "from CMD". 1436 * See long comment at smb_ctx_init() 1437 */ 1438 rc_getstringptr(smb_rc, sname, "workgroup", &p); 1439 if (p) { 1440 error = smb_ctx_setdomain(ctx, p, 0); 1441 if (error) 1442 smb_error(dgettext(TEXT_DOMAIN, 1443 "workgroup specification in the " 1444 "section '%s' ignored"), error, sname); 1445 } 1446 rc_getstringptr(smb_rc, sname, "domain", &p); 1447 if (p) { 1448 error = smb_ctx_setdomain(ctx, p, 0); 1449 if (error) 1450 smb_error(dgettext(TEXT_DOMAIN, 1451 "domain specification in the " 1452 "section '%s' ignored"), error, sname); 1453 } 1454 1455 rc_getstringptr(smb_rc, sname, "user", &p); 1456 if (p) { 1457 error = smb_ctx_setuser(ctx, p, 0); 1458 if (error) 1459 smb_error(dgettext(TEXT_DOMAIN, 1460 "user specification in the " 1461 "section '%s' ignored"), error, sname); 1462 } 1463 } 1464 1465 if (level == 1) { 1466 /* Section is: [server] */ 1467 rc_getstringptr(smb_rc, sname, "addr", &p); 1468 if (p) { 1469 error = smb_ctx_setsrvaddr(ctx, p); 1470 if (error) { 1471 smb_error(dgettext(TEXT_DOMAIN, 1472 "invalid address specified in section %s"), 1473 0, sname); 1474 return (error); 1475 } 1476 } 1477 } 1478 1479 rc_getstringptr(smb_rc, sname, "password", &p); 1480 if (p) { 1481 error = smb_ctx_setpassword(ctx, p, 0); 1482 if (error) 1483 smb_error(dgettext(TEXT_DOMAIN, 1484 "password specification in the section '%s' ignored"), 1485 error, sname); 1486 } 1487 1488 return (0); 1489 } 1490 1491 /* 1492 * read rc file as follows: 1493 * 0: read [default] section 1494 * 1: override with [server] section 1495 * 2: override with [server:user] section 1496 * 3: override with [server:user:share] section 1497 * Since absence of rcfile is not fatal, silently ignore this fact. 1498 * smb_rc file should be closed by caller. 1499 */ 1500 int 1501 smb_ctx_readrc(struct smb_ctx *ctx) 1502 { 1503 char pwbuf[NSS_BUFLEN_PASSWD]; 1504 struct passwd pw; 1505 char *sname = NULL; 1506 int sname_max; 1507 int err = 0; 1508 1509 /* 1510 * If the user name is not specified some other way, 1511 * use the current user name. Also save the homedir. 1512 * NB: ct_home=NULL is allowed, and we don't want to 1513 * bail out with an error for a missing ct_home. 1514 */ 1515 if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) { 1516 if (ctx->ct_user[0] == 0) 1517 (void) smb_ctx_setuser(ctx, pw.pw_name, B_FALSE); 1518 if (ctx->ct_home == NULL) 1519 ctx->ct_home = strdup(pw.pw_dir); 1520 } 1521 1522 if ((err = smb_open_rcfile(ctx->ct_home)) != 0) { 1523 DPRINT("smb_open_rcfile, err=%d", err); 1524 /* ignore any error here */ 1525 return (0); 1526 } 1527 1528 sname_max = 3 * SMBIOC_MAX_NAME + 4; 1529 sname = malloc(sname_max); 1530 if (sname == NULL) { 1531 err = ENOMEM; 1532 goto done; 1533 } 1534 1535 /* 1536 * default parameters (level=0) 1537 */ 1538 smb_ctx_readrcsection(ctx, "default", 0); 1539 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 1540 1541 /* 1542 * If we don't have a server name, we can't read any of the 1543 * [server...] sections. 1544 */ 1545 if (ctx->ct_fullserver == NULL) 1546 goto done; 1547 /* 1548 * SERVER parameters. 1549 */ 1550 smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1); 1551 1552 /* 1553 * If we don't have a user name, we can't read any of the 1554 * [server:user...] sections. 1555 */ 1556 if (ctx->ct_user[0] == 0) 1557 goto done; 1558 /* 1559 * SERVER:USER parameters 1560 */ 1561 snprintf(sname, sname_max, "%s:%s", 1562 ctx->ct_fullserver, 1563 ctx->ct_user); 1564 smb_ctx_readrcsection(ctx, sname, 2); 1565 1566 1567 /* 1568 * If we don't have a share name, we can't read any of the 1569 * [server:user:share] sections. 1570 */ 1571 if (ctx->ct_origshare == NULL) 1572 goto done; 1573 /* 1574 * SERVER:USER:SHARE parameters 1575 */ 1576 snprintf(sname, sname_max, "%s:%s:%s", 1577 ctx->ct_fullserver, 1578 ctx->ct_user, 1579 ctx->ct_origshare); 1580 smb_ctx_readrcsection(ctx, sname, 3); 1581 1582 done: 1583 if (sname) 1584 free(sname); 1585 smb_close_rcfile(); 1586 if (smb_debug) 1587 dump_ctx("after smb_ctx_readrc", ctx); 1588 if (err) 1589 DPRINT("err=%d\n", err); 1590 1591 return (err); 1592 } 1593 1594 void 1595 smbfs_set_default_domain(const char *domain) 1596 { 1597 strlcpy(default_domain, domain, sizeof (default_domain)); 1598 } 1599 1600 void 1601 smbfs_set_default_user(const char *user) 1602 { 1603 strlcpy(default_user, user, sizeof (default_user)); 1604 } 1605