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