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