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