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