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 /* 856 * API for library caller to set signing enabled, required 857 * Note: if not enable, ignore require 858 */ 859 int 860 smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require) 861 { 862 ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK; 863 if (enable) { 864 ctx->ct_vopt |= SMBVOPT_SIGNING_ENABLED; 865 if (require) 866 ctx->ct_vopt |= SMBVOPT_SIGNING_REQUIRED; 867 } 868 return (0); 869 } 870 871 static int 872 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 873 { 874 struct group gr; 875 struct passwd pw; 876 char buf[NSS_BUFLEN_PASSWD]; 877 char *cp; 878 879 cp = strchr(pair, ':'); 880 if (cp) { 881 *cp++ = '\0'; 882 if (*cp && gid) { 883 if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) { 884 *gid = gr.gr_gid; 885 } else 886 smb_error(dgettext(TEXT_DOMAIN, 887 "Invalid group name %s, ignored"), 0, cp); 888 } 889 } 890 if (*pair) { 891 if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) { 892 *uid = pw.pw_uid; 893 } else 894 smb_error(dgettext(TEXT_DOMAIN, 895 "Invalid user name %s, ignored"), 0, pair); 896 } 897 898 return (0); 899 } 900 901 /* 902 * Commands use this with getopt. See: 903 * STDPARAM_OPT, STDPARAM_ARGS 904 * Called after smb_ctx_readrc(). 905 */ 906 int 907 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 908 { 909 int error = 0; 910 char *p, *cp; 911 char tmp[1024]; 912 913 switch (opt) { 914 case 'A': 915 case 'U': 916 /* Handled in smb_ctx_init() */ 917 break; 918 case 'I': 919 error = smb_ctx_setsrvaddr(ctx, arg); 920 break; 921 case 'M': 922 /* share connect rights - ignored */ 923 ctx->ct_flags |= SMBCF_SRIGHTS; 924 break; 925 case 'N': 926 ctx->ct_flags |= SMBCF_NOPWD; 927 break; 928 case 'O': 929 p = strdup(arg); 930 cp = strchr(p, '/'); 931 if (cp) 932 *cp = '\0'; 933 error = smb_parse_owner(cp, &ctx->ct_owner, NULL); 934 free(p); 935 break; 936 case 'P': 937 /* ctx->ct_vopt |= SMBCOPT_PERMANENT; */ 938 break; 939 case 'R': 940 /* retry count - ignored */ 941 break; 942 case 'T': 943 /* timeout - ignored */ 944 break; 945 case 'D': /* domain */ 946 case 'W': /* workgroup (legacy alias) */ 947 nls_str_upper(tmp, arg); 948 error = smb_ctx_setdomain(ctx, tmp, TRUE); 949 break; 950 } 951 return (error); 952 } 953 954 955 /* 956 * Original code injected iconv tables into the kernel. 957 * Not sure if we'll need this or not... REVISIT 958 */ 959 #ifdef KICONV_SUPPORT 960 static int 961 smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl) 962 { 963 int error = 0; 964 965 error = kiconv_add_xlat_table(to, from, tbl); 966 if (error && error != EEXIST) { 967 smb_error(dgettext(TEXT_DOMAIN, 968 "can not setup kernel iconv table (%s:%s)"), 969 error, from, to); 970 return (error); 971 } 972 return (error); 973 } 974 #endif /* KICONV_SUPPORT */ 975 976 /* 977 * Verify context info. before connect operation(s), 978 * lookup specified server and try to fill all forgotten fields. 979 * Legacy name used by commands. 980 */ 981 int 982 smb_ctx_resolve(struct smb_ctx *ctx) 983 { 984 struct smbioc_ossn *ssn = &ctx->ct_ssn; 985 int error = 0; 986 #ifdef KICONV_SUPPORT 987 uchar_t cstbl[256]; 988 uint_t i; 989 #endif 990 991 ctx->ct_flags &= ~SMBCF_RESOLVED; 992 993 if (ctx->ct_fullserver == NULL) { 994 smb_error(dgettext(TEXT_DOMAIN, 995 "no server name specified"), 0); 996 return (EINVAL); 997 } 998 999 if (ctx->ct_minlevel >= SMBL_SHARE && 1000 ctx->ct_origshare == NULL) { 1001 smb_error(dgettext(TEXT_DOMAIN, 1002 "no share name specified for %s@%s"), 1003 0, ssn->ssn_user, ctx->ct_fullserver); 1004 return (EINVAL); 1005 } 1006 error = nb_ctx_resolve(ctx->ct_nb); 1007 if (error) 1008 return (error); 1009 #ifdef KICONV_SUPPORT 1010 if (ssn->ioc_localcs[0] == 0) 1011 strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ 1012 error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 1013 if (error) 1014 return (error); 1015 error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 1016 if (error) 1017 return (error); 1018 if (ssn->ioc_servercs[0] != 0) { 1019 for (i = 0; i < sizeof (cstbl); i++) 1020 cstbl[i] = i; 1021 nls_mem_toext(cstbl, cstbl, sizeof (cstbl)); 1022 error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, 1023 cstbl); 1024 if (error) 1025 return (error); 1026 for (i = 0; i < sizeof (cstbl); i++) 1027 cstbl[i] = i; 1028 nls_mem_toloc(cstbl, cstbl, sizeof (cstbl)); 1029 error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, 1030 cstbl); 1031 if (error) 1032 return (error); 1033 } 1034 #endif /* KICONV_SUPPORT */ 1035 1036 /* 1037 * Lookup the IP address and fill in ct_addrinfo. 1038 * 1039 * Note: smb_ctx_getaddr() returns a EAI_xxx 1040 * error value like getaddrinfo(3), but this 1041 * function needs to return an errno value. 1042 */ 1043 error = smb_ctx_getaddr(ctx); 1044 if (error) { 1045 const char *ais = gai_strerror(error); 1046 smb_error(dgettext(TEXT_DOMAIN, 1047 "can't get server address, %s"), 0, ais); 1048 return (ENODATA); 1049 } 1050 assert(ctx->ct_addrinfo != NULL); 1051 1052 /* 1053 * If we have a user name but no password, 1054 * check for a keychain entry. 1055 * XXX: Only for auth NTLM? 1056 */ 1057 if (ctx->ct_user[0] == '\0') { 1058 /* 1059 * No user name (anonymous session). 1060 * The minauth checks do not apply. 1061 */ 1062 ctx->ct_authflags = SMB_AT_ANON; 1063 } else { 1064 /* 1065 * Have a user name. 1066 * If we don't have a p/w yet, 1067 * try the keychain. 1068 */ 1069 if (ctx->ct_password[0] == '\0') 1070 (void) smb_get_keychain(ctx); 1071 /* 1072 * If we're doing p/w based auth, 1073 * that means not using Kerberos. 1074 */ 1075 if (ctx->ct_password[0] != '\0') 1076 ctx->ct_authflags &= ~SMB_AT_KRB5; 1077 /* 1078 * Mask out disallowed auth types. 1079 */ 1080 ctx->ct_authflags &= ctx->ct_minauth; 1081 } 1082 if (ctx->ct_authflags == 0) { 1083 smb_error(dgettext(TEXT_DOMAIN, 1084 "no valid auth. types"), 0); 1085 return (ENOTSUP); 1086 } 1087 1088 ctx->ct_flags |= SMBCF_RESOLVED; 1089 if (smb_debug) 1090 dump_ctx("after smb_ctx_resolve", ctx); 1091 1092 return (0); 1093 } 1094 1095 int 1096 smb_open_driver() 1097 { 1098 int err, fd; 1099 uint32_t version; 1100 1101 fd = open("/dev/"NSMB_NAME, O_RDWR); 1102 if (fd < 0) { 1103 err = errno; 1104 smb_error(dgettext(TEXT_DOMAIN, 1105 "failed to open driver"), err); 1106 return (-1); 1107 } 1108 1109 /* 1110 * Check the driver version (paranoia) 1111 * Do this BEFORE any other ioctl calls. 1112 */ 1113 if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) 1114 version = 0; 1115 if (version != NSMB_VERSION) { 1116 smb_error(dgettext(TEXT_DOMAIN, 1117 "incorrect driver version"), 0); 1118 close(fd); 1119 return (-1); 1120 } 1121 1122 /* This handle controls per-process resources. */ 1123 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 1124 1125 return (fd); 1126 } 1127 1128 int 1129 smb_ctx_gethandle(struct smb_ctx *ctx) 1130 { 1131 int fd; 1132 1133 if (ctx->ct_dev_fd != -1) { 1134 rpc_cleanup_smbctx(ctx); 1135 close(ctx->ct_dev_fd); 1136 ctx->ct_dev_fd = -1; 1137 ctx->ct_flags &= ~SMBCF_SSNACTIVE; 1138 } 1139 1140 fd = smb_open_driver(); 1141 if (fd < 0) 1142 return (ENODEV); 1143 1144 ctx->ct_dev_fd = fd; 1145 return (0); 1146 } 1147 1148 1149 /* 1150 * Find or create a connection + logon session 1151 */ 1152 int 1153 smb_ctx_get_ssn(struct smb_ctx *ctx) 1154 { 1155 int err = 0; 1156 1157 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) 1158 return (EINVAL); 1159 1160 if (ctx->ct_dev_fd < 0) { 1161 if ((err = smb_ctx_gethandle(ctx))) 1162 return (err); 1163 } 1164 1165 /* 1166 * Check whether the driver already has a VC 1167 * we can use. If so, we're done! 1168 */ 1169 err = smb_ctx_findvc(ctx); 1170 if (err == 0) { 1171 DPRINT("found an existing VC"); 1172 } else { 1173 /* 1174 * This calls the IOD to create a new session. 1175 */ 1176 DPRINT("setup a new VC"); 1177 err = smb_ctx_newvc(ctx); 1178 if (err != 0) 1179 return (err); 1180 1181 /* 1182 * Call findvc again. The new VC sould be 1183 * found in the driver this time. 1184 */ 1185 err = smb_ctx_findvc(ctx); 1186 } 1187 1188 return (err); 1189 } 1190 1191 /* 1192 * Get the string representation of a share "use" type, 1193 * as needed for the "service" in tree connect. 1194 */ 1195 static const char * 1196 smb_use_type_str(smb_use_shtype_t stype) 1197 { 1198 const char *pp; 1199 1200 switch (stype) { 1201 default: 1202 case USE_WILDCARD: 1203 pp = "?????"; 1204 break; 1205 case USE_DISKDEV: 1206 pp = "A:"; 1207 break; 1208 case USE_SPOOLDEV: 1209 pp = "LPT1:"; 1210 break; 1211 case USE_CHARDEV: 1212 pp = "COMM"; 1213 break; 1214 case USE_IPC: 1215 pp = "IPC"; 1216 break; 1217 } 1218 return (pp); 1219 } 1220 1221 /* 1222 * Find or create a tree connection 1223 */ 1224 int 1225 smb_ctx_get_tree(struct smb_ctx *ctx) 1226 { 1227 smbioc_tcon_t *tcon = NULL; 1228 const char *stype; 1229 int cmd, err = 0; 1230 1231 if (ctx->ct_dev_fd < 0 || 1232 ctx->ct_origshare == NULL) { 1233 return (EINVAL); 1234 } 1235 1236 cmd = SMBIOC_TREE_CONNECT; 1237 tcon = malloc(sizeof (*tcon)); 1238 if (tcon == NULL) 1239 return (ENOMEM); 1240 bzero(tcon, sizeof (*tcon)); 1241 tcon->tc_flags = SMBLK_CREATE; 1242 tcon->tc_opt = 0; 1243 1244 /* The share name */ 1245 strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare, 1246 sizeof (tcon->tc_sh.sh_name)); 1247 1248 /* The share "use" type. */ 1249 stype = smb_use_type_str(ctx->ct_shtype_req); 1250 strlcpy(tcon->tc_sh.sh_type_req, stype, 1251 sizeof (tcon->tc_sh.sh_type_req)); 1252 1253 /* 1254 * Todo: share passwords for share-level security. 1255 * 1256 * The driver does the actual TCON call. 1257 */ 1258 if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) { 1259 err = errno; 1260 goto out; 1261 } 1262 1263 /* 1264 * Check the returned share type 1265 */ 1266 DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret); 1267 if (ctx->ct_shtype_req != USE_WILDCARD && 1268 0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) { 1269 smb_error(dgettext(TEXT_DOMAIN, 1270 "%s: incompatible share type"), 1271 0, ctx->ct_origshare); 1272 err = EINVAL; 1273 } 1274 1275 out: 1276 if (tcon != NULL) 1277 free(tcon); 1278 1279 return (err); 1280 } 1281 1282 /* 1283 * Return the hflags2 word for an smb_ctx. 1284 */ 1285 int 1286 smb_ctx_flags2(struct smb_ctx *ctx) 1287 { 1288 uint16_t flags2; 1289 1290 if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) { 1291 smb_error(dgettext(TEXT_DOMAIN, 1292 "can't get flags2 for a session"), errno); 1293 return (-1); 1294 } 1295 return (flags2); 1296 } 1297 1298 /* 1299 * Get the transport level session key. 1300 * Must already have an active SMB session. 1301 */ 1302 int 1303 smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len) 1304 { 1305 if (len < SMBIOC_HASH_SZ) 1306 return (EINVAL); 1307 1308 if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1) 1309 return (errno); 1310 1311 return (0); 1312 } 1313 1314 1315 /* 1316 * RC file parsing stuff 1317 */ 1318 1319 struct nv { 1320 char *name; 1321 int value; 1322 } minauth_table[] = { 1323 /* Allowed auth. types */ 1324 { "kerberos", SMB_AT_KRB5 }, 1325 { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 }, 1326 { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 }, 1327 { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 }, 1328 { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1| 1329 SMB_AT_ANON }, 1330 { NULL } 1331 }; 1332 1333 1334 /* 1335 * level values: 1336 * 0 - default 1337 * 1 - server 1338 * 2 - server:user 1339 * 3 - server:user:share 1340 */ 1341 static int 1342 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 1343 { 1344 char *p; 1345 int error; 1346 1347 #ifdef KICONV_SUPPORT 1348 if (level > 0) { 1349 rc_getstringptr(smb_rc, sname, "charsets", &p); 1350 if (p) { 1351 error = smb_ctx_setcharset(ctx, p); 1352 if (error) 1353 smb_error(dgettext(TEXT_DOMAIN, 1354 "charset specification in the section '%s' ignored"), 1355 error, sname); 1356 } 1357 } 1358 #endif 1359 1360 if (level <= 1) { 1361 /* Section is: [default] or [server] */ 1362 1363 rc_getstringptr(smb_rc, sname, "minauth", &p); 1364 if (p) { 1365 /* 1366 * "minauth" was set in this section; override 1367 * the current minimum authentication setting. 1368 */ 1369 struct nv *nvp; 1370 for (nvp = minauth_table; nvp->name; nvp++) 1371 if (strcmp(p, nvp->name) == 0) 1372 break; 1373 if (nvp->name) 1374 ctx->ct_minauth = nvp->value; 1375 else { 1376 /* 1377 * Unknown minimum authentication level. 1378 */ 1379 smb_error(dgettext(TEXT_DOMAIN, 1380 "invalid minimum authentication level \"%s\" specified in the section %s"), 1381 0, p, sname); 1382 return (EINVAL); 1383 } 1384 } 1385 1386 rc_getstringptr(smb_rc, sname, "signing", &p); 1387 if (p) { 1388 /* 1389 * "signing" was set in this section; override 1390 * the current signing settings. 1391 */ 1392 if (strcmp(p, "disabled") == 0) { 1393 smb_ctx_setsigning(ctx, FALSE, FALSE); 1394 } else if (strcmp(p, "enabled") == 0) { 1395 smb_ctx_setsigning(ctx, TRUE, FALSE); 1396 } else if (strcmp(p, "required") == 0) { 1397 smb_ctx_setsigning(ctx, TRUE, TRUE); 1398 } else { 1399 /* 1400 * Unknown "signing" value. 1401 */ 1402 smb_error(dgettext(TEXT_DOMAIN, 1403 "invalid signing policy \"%s\" specified in the section %s"), 1404 0, p, sname); 1405 return (EINVAL); 1406 } 1407 } 1408 1409 /* 1410 * Domain name. Allow both keywords: 1411 * "workgroup", "domain" 1412 * 1413 * Note: these are NOT marked "from CMD". 1414 * See long comment at smb_ctx_init() 1415 */ 1416 rc_getstringptr(smb_rc, sname, "workgroup", &p); 1417 if (p) { 1418 nls_str_upper(p, p); 1419 error = smb_ctx_setdomain(ctx, p, 0); 1420 if (error) 1421 smb_error(dgettext(TEXT_DOMAIN, 1422 "workgroup specification in the " 1423 "section '%s' ignored"), error, sname); 1424 } 1425 rc_getstringptr(smb_rc, sname, "domain", &p); 1426 if (p) { 1427 nls_str_upper(p, p); 1428 error = smb_ctx_setdomain(ctx, p, 0); 1429 if (error) 1430 smb_error(dgettext(TEXT_DOMAIN, 1431 "domain specification in the " 1432 "section '%s' ignored"), error, sname); 1433 } 1434 1435 rc_getstringptr(smb_rc, sname, "user", &p); 1436 if (p) { 1437 error = smb_ctx_setuser(ctx, p, 0); 1438 if (error) 1439 smb_error(dgettext(TEXT_DOMAIN, 1440 "user specification in the " 1441 "section '%s' ignored"), error, sname); 1442 } 1443 } 1444 1445 if (level == 1) { 1446 /* Section is: [server] */ 1447 rc_getstringptr(smb_rc, sname, "addr", &p); 1448 if (p) { 1449 error = smb_ctx_setsrvaddr(ctx, p); 1450 if (error) { 1451 smb_error(dgettext(TEXT_DOMAIN, 1452 "invalid address specified in section %s"), 1453 0, sname); 1454 return (error); 1455 } 1456 } 1457 } 1458 1459 rc_getstringptr(smb_rc, sname, "password", &p); 1460 if (p) { 1461 error = smb_ctx_setpassword(ctx, p, 0); 1462 if (error) 1463 smb_error(dgettext(TEXT_DOMAIN, 1464 "password specification in the section '%s' ignored"), 1465 error, sname); 1466 } 1467 1468 return (0); 1469 } 1470 1471 /* 1472 * read rc file as follows: 1473 * 0: read [default] section 1474 * 1: override with [server] section 1475 * 2: override with [server:user] section 1476 * 3: override with [server:user:share] section 1477 * Since absence of rcfile is not fatal, silently ignore this fact. 1478 * smb_rc file should be closed by caller. 1479 */ 1480 int 1481 smb_ctx_readrc(struct smb_ctx *ctx) 1482 { 1483 char *home; 1484 char *sname = NULL; 1485 int sname_max; 1486 int err = 0; 1487 1488 if ((home = getenv("HOME")) == NULL) 1489 home = ctx->ct_home; 1490 if ((err = smb_open_rcfile(home)) != 0) { 1491 DPRINT("smb_open_rcfile, err=%d", err); 1492 /* ignore any error here */ 1493 return (0); 1494 } 1495 1496 sname_max = 3 * SMBIOC_MAX_NAME + 4; 1497 sname = malloc(sname_max); 1498 if (sname == NULL) { 1499 err = ENOMEM; 1500 goto done; 1501 } 1502 1503 /* 1504 * default parameters (level=0) 1505 */ 1506 smb_ctx_readrcsection(ctx, "default", 0); 1507 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 1508 1509 /* 1510 * If we don't have a server name, we can't read any of the 1511 * [server...] sections. 1512 */ 1513 if (ctx->ct_fullserver == NULL) 1514 goto done; 1515 /* 1516 * SERVER parameters. 1517 */ 1518 smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1); 1519 1520 /* 1521 * If we don't have a user name, we can't read any of the 1522 * [server:user...] sections. 1523 */ 1524 if (ctx->ct_user[0] == 0) 1525 goto done; 1526 /* 1527 * SERVER:USER parameters 1528 */ 1529 snprintf(sname, sname_max, "%s:%s", 1530 ctx->ct_fullserver, 1531 ctx->ct_user); 1532 smb_ctx_readrcsection(ctx, sname, 2); 1533 1534 1535 /* 1536 * If we don't have a share name, we can't read any of the 1537 * [server:user:share] sections. 1538 */ 1539 if (ctx->ct_origshare == NULL) 1540 goto done; 1541 /* 1542 * SERVER:USER:SHARE parameters 1543 */ 1544 snprintf(sname, sname_max, "%s:%s:%s", 1545 ctx->ct_fullserver, 1546 ctx->ct_user, 1547 ctx->ct_origshare); 1548 smb_ctx_readrcsection(ctx, sname, 3); 1549 1550 done: 1551 if (sname) 1552 free(sname); 1553 smb_close_rcfile(); 1554 if (smb_debug) 1555 dump_ctx("after smb_ctx_readrc", ctx); 1556 if (err) 1557 DPRINT("err=%d\n", err); 1558 1559 return (err); 1560 } 1561