xref: /onnv-gate/usr/src/lib/libsmbfs/smb/ctx.c (revision 12925:12cf927830ab)
16007Sthurlow /*
26007Sthurlow  * Copyright (c) 2000, Boris Popov
36007Sthurlow  * All rights reserved.
46007Sthurlow  *
56007Sthurlow  * Redistribution and use in source and binary forms, with or without
66007Sthurlow  * modification, are permitted provided that the following conditions
76007Sthurlow  * are met:
86007Sthurlow  * 1. Redistributions of source code must retain the above copyright
96007Sthurlow  *    notice, this list of conditions and the following disclaimer.
106007Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
116007Sthurlow  *    notice, this list of conditions and the following disclaimer in the
126007Sthurlow  *    documentation and/or other materials provided with the distribution.
136007Sthurlow  * 3. All advertising materials mentioning features or use of this software
146007Sthurlow  *    must display the following acknowledgement:
156007Sthurlow  *    This product includes software developed by Boris Popov.
166007Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
176007Sthurlow  *    may be used to endorse or promote products derived from this software
186007Sthurlow  *    without specific prior written permission.
196007Sthurlow  *
206007Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216007Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226007Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236007Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246007Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256007Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266007Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276007Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286007Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296007Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306007Sthurlow  * SUCH DAMAGE.
316007Sthurlow  *
326007Sthurlow  * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $
336007Sthurlow  */
346007Sthurlow 
358271SGordon.Ross@Sun.COM /*
3612140SGordon.Ross@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
378271SGordon.Ross@Sun.COM  */
386007Sthurlow 
396007Sthurlow #include <sys/param.h>
406007Sthurlow #include <sys/ioctl.h>
416007Sthurlow #include <sys/time.h>
426007Sthurlow #include <sys/mount.h>
436007Sthurlow #include <sys/types.h>
446007Sthurlow #include <sys/byteorder.h>
456007Sthurlow 
466007Sthurlow #include <fcntl.h>
476007Sthurlow #include <ctype.h>
486007Sthurlow #include <errno.h>
496007Sthurlow #include <stdio.h>
506007Sthurlow #include <string.h>
516007Sthurlow #include <strings.h>
526007Sthurlow #include <stdlib.h>
536007Sthurlow #include <pwd.h>
546007Sthurlow #include <grp.h>
556007Sthurlow #include <unistd.h>
566007Sthurlow #include <libintl.h>
576007Sthurlow #include <assert.h>
586007Sthurlow #include <nss_dbdefs.h>
596007Sthurlow 
6010023SGordon.Ross@Sun.COM #include <cflib.h>
616007Sthurlow #include <netsmb/smb_lib.h>
626007Sthurlow #include <netsmb/netbios.h>
636007Sthurlow #include <netsmb/nb_lib.h>
646007Sthurlow #include <netsmb/smb_dev.h>
656007Sthurlow 
6610023SGordon.Ross@Sun.COM #include "charsets.h"
6710023SGordon.Ross@Sun.COM #include "spnego.h"
686007Sthurlow #include "derparse.h"
698271SGordon.Ross@Sun.COM #include "private.h"
7010023SGordon.Ross@Sun.COM #include "ntlm.h"
716007Sthurlow 
7210023SGordon.Ross@Sun.COM #ifndef FALSE
7310023SGordon.Ross@Sun.COM #define	FALSE	0
7410023SGordon.Ross@Sun.COM #endif
7510023SGordon.Ross@Sun.COM #ifndef TRUE
7610023SGordon.Ross@Sun.COM #define	TRUE	1
7710023SGordon.Ross@Sun.COM #endif
786007Sthurlow 
7912140SGordon.Ross@Sun.COM struct nv {
8012140SGordon.Ross@Sun.COM 	char *name;
8112140SGordon.Ross@Sun.COM 	int value;
8212140SGordon.Ross@Sun.COM };
836007Sthurlow 
846007Sthurlow /* These two may be set by commands. */
856007Sthurlow int smb_debug, smb_verbose;
866007Sthurlow 
876007Sthurlow /*
8810023SGordon.Ross@Sun.COM  * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
8910023SGordon.Ross@Sun.COM  */
9010023SGordon.Ross@Sun.COM const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
9110023SGordon.Ross@Sun.COM 
9210023SGordon.Ross@Sun.COM /*
938271SGordon.Ross@Sun.COM  * Give the RPC library a callback hook that will be
948271SGordon.Ross@Sun.COM  * called whenever we destroy or reinit an smb_ctx_t.
958271SGordon.Ross@Sun.COM  * The name rpc_cleanup_smbctx() is legacy, and was
968271SGordon.Ross@Sun.COM  * originally a direct call into the RPC code.
976007Sthurlow  */
988271SGordon.Ross@Sun.COM static smb_ctx_close_hook_t close_hook;
996007Sthurlow static void
rpc_cleanup_smbctx(struct smb_ctx * ctx)1006007Sthurlow rpc_cleanup_smbctx(struct smb_ctx *ctx)
1016007Sthurlow {
1028271SGordon.Ross@Sun.COM 	if (close_hook)
1038271SGordon.Ross@Sun.COM 		(*close_hook)(ctx);
1046007Sthurlow }
1058271SGordon.Ross@Sun.COM void
smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)1068271SGordon.Ross@Sun.COM smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
1078271SGordon.Ross@Sun.COM {
1088271SGordon.Ross@Sun.COM 	close_hook = hook;
1098271SGordon.Ross@Sun.COM }
1106007Sthurlow 
1116007Sthurlow void
dump_ctx_flags(int flags)1126007Sthurlow dump_ctx_flags(int flags)
1136007Sthurlow {
1146007Sthurlow 	printf(" Flags: ");
1156007Sthurlow 	if (flags == 0)
1166007Sthurlow 		printf("0");
1176007Sthurlow 	if (flags & SMBCF_NOPWD)
1186007Sthurlow 		printf("NOPWD ");
1196007Sthurlow 	if (flags & SMBCF_SRIGHTS)
1206007Sthurlow 		printf("SRIGHTS ");
1216007Sthurlow 	if (flags & SMBCF_LOCALE)
1226007Sthurlow 		printf("LOCALE ");
1236007Sthurlow 	if (flags & SMBCF_CMD_DOM)
1246007Sthurlow 		printf("CMD_DOM ");
1256007Sthurlow 	if (flags & SMBCF_CMD_USR)
1266007Sthurlow 		printf("CMD_USR ");
1276007Sthurlow 	if (flags & SMBCF_CMD_PW)
1286007Sthurlow 		printf("CMD_PW ");
1296007Sthurlow 	if (flags & SMBCF_RESOLVED)
1306007Sthurlow 		printf("RESOLVED ");
1316007Sthurlow 	if (flags & SMBCF_KCBAD)
1326007Sthurlow 		printf("KCBAD ");
1336007Sthurlow 	if (flags & SMBCF_KCFOUND)
1346007Sthurlow 		printf("KCFOUND ");
1356007Sthurlow 	if (flags & SMBCF_BROWSEOK)
1366007Sthurlow 		printf("BROWSEOK ");
1376007Sthurlow 	if (flags & SMBCF_AUTHREQ)
1386007Sthurlow 		printf("AUTHREQ ");
1396007Sthurlow 	if (flags & SMBCF_KCSAVE)
1406007Sthurlow 		printf("KCSAVE  ");
1416007Sthurlow 	if (flags & SMBCF_XXX)
1426007Sthurlow 		printf("XXX ");
1436007Sthurlow 	if (flags & SMBCF_SSNACTIVE)
1446007Sthurlow 		printf("SSNACTIVE ");
1456007Sthurlow 	if (flags & SMBCF_KCDOMAIN)
1466007Sthurlow 		printf("KCDOMAIN ");
1476007Sthurlow 	printf("\n");
1486007Sthurlow }
1496007Sthurlow 
1506007Sthurlow void
dump_iod_ssn(smb_iod_ssn_t * is)15110023SGordon.Ross@Sun.COM dump_iod_ssn(smb_iod_ssn_t *is)
1526007Sthurlow {
15310023SGordon.Ross@Sun.COM 	static const char zeros[NTLM_HASH_SZ] = {0};
15410023SGordon.Ross@Sun.COM 	struct smbioc_ossn *ssn = &is->iod_ossn;
15510023SGordon.Ross@Sun.COM 
15610023SGordon.Ross@Sun.COM 	printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
15710023SGordon.Ross@Sun.COM 	dump_sockaddr(&ssn->ssn_srvaddr.sa);
15810023SGordon.Ross@Sun.COM 	printf(" dom=\"%s\", user=\"%s\"\n",
15910023SGordon.Ross@Sun.COM 	    ssn->ssn_domain, ssn->ssn_user);
16010023SGordon.Ross@Sun.COM 	printf(" ct_vopt=0x%x, ct_owner=%d\n",
16110023SGordon.Ross@Sun.COM 	    ssn->ssn_vopt, ssn->ssn_owner);
16210023SGordon.Ross@Sun.COM 	printf(" ct_authflags=0x%x\n", is->iod_authflags);
1636007Sthurlow 
16410023SGordon.Ross@Sun.COM 	printf(" ct_nthash:");
16510023SGordon.Ross@Sun.COM 	if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
16610023SGordon.Ross@Sun.COM 		smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
16710023SGordon.Ross@Sun.COM 	else
16810023SGordon.Ross@Sun.COM 		printf(" {0}\n");
16910023SGordon.Ross@Sun.COM 
17010023SGordon.Ross@Sun.COM 	printf(" ct_lmhash:");
17110023SGordon.Ross@Sun.COM 	if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
17210023SGordon.Ross@Sun.COM 		smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
17310023SGordon.Ross@Sun.COM 	else
17410023SGordon.Ross@Sun.COM 		printf(" {0}\n");
1756007Sthurlow }
1766007Sthurlow 
1776007Sthurlow void
dump_ctx(char * where,struct smb_ctx * ctx)1786007Sthurlow dump_ctx(char *where, struct smb_ctx *ctx)
1796007Sthurlow {
1806007Sthurlow 	printf("context %s:\n", where);
1816007Sthurlow 	dump_ctx_flags(ctx->ct_flags);
1826007Sthurlow 
18310023SGordon.Ross@Sun.COM 	if (ctx->ct_locname)
18410023SGordon.Ross@Sun.COM 		printf(" localname=\"%s\"", ctx->ct_locname);
18510023SGordon.Ross@Sun.COM 	else
18610023SGordon.Ross@Sun.COM 		printf(" localname=NULL");
1876007Sthurlow 
1886007Sthurlow 	if (ctx->ct_fullserver)
1896007Sthurlow 		printf(" fullserver=\"%s\"", ctx->ct_fullserver);
1906007Sthurlow 	else
1916007Sthurlow 		printf(" fullserver=NULL");
1926007Sthurlow 
19310023SGordon.Ross@Sun.COM 	if (ctx->ct_srvaddr_s)
19410023SGordon.Ross@Sun.COM 		printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
19510023SGordon.Ross@Sun.COM 	else
19610023SGordon.Ross@Sun.COM 		printf(" srvaddr_s=NULL\n");
19710023SGordon.Ross@Sun.COM 
19810023SGordon.Ross@Sun.COM 	if (ctx->ct_addrinfo)
19910023SGordon.Ross@Sun.COM 		dump_addrinfo(ctx->ct_addrinfo);
2006007Sthurlow 	else
20110023SGordon.Ross@Sun.COM 		printf(" ct_addrinfo = NULL\n");
20210023SGordon.Ross@Sun.COM 
20310023SGordon.Ross@Sun.COM 	dump_iod_ssn(&ctx->ct_iod_ssn);
20410023SGordon.Ross@Sun.COM 
20510023SGordon.Ross@Sun.COM 	printf(" share_name=\"%s\", share_type=%d\n",
20610023SGordon.Ross@Sun.COM 	    ctx->ct_origshare ? ctx->ct_origshare : "",
20710023SGordon.Ross@Sun.COM 	    ctx->ct_shtype_req);
20810023SGordon.Ross@Sun.COM 
20910023SGordon.Ross@Sun.COM 	/* dump_iod_work()? */
21010023SGordon.Ross@Sun.COM }
2116007Sthurlow 
21210023SGordon.Ross@Sun.COM int
smb_ctx_alloc(struct smb_ctx ** ctx_pp)21310023SGordon.Ross@Sun.COM smb_ctx_alloc(struct smb_ctx **ctx_pp)
21410023SGordon.Ross@Sun.COM {
21510023SGordon.Ross@Sun.COM 	smb_ctx_t *ctx;
21610023SGordon.Ross@Sun.COM 	int err;
21710023SGordon.Ross@Sun.COM 
21810023SGordon.Ross@Sun.COM 	ctx = malloc(sizeof (*ctx));
21910023SGordon.Ross@Sun.COM 	if (ctx == NULL)
22010023SGordon.Ross@Sun.COM 		return (ENOMEM);
22110023SGordon.Ross@Sun.COM 	err = smb_ctx_init(ctx);
22210023SGordon.Ross@Sun.COM 	if (err != 0) {
22310023SGordon.Ross@Sun.COM 		free(ctx);
22410023SGordon.Ross@Sun.COM 		return (err);
22510023SGordon.Ross@Sun.COM 	}
22610023SGordon.Ross@Sun.COM 	*ctx_pp = ctx;
22710023SGordon.Ross@Sun.COM 	return (0);
2286007Sthurlow }
2296007Sthurlow 
2306007Sthurlow /*
23110023SGordon.Ross@Sun.COM  * Initialize an smb_ctx struct (defaults)
23210023SGordon.Ross@Sun.COM  */
23310023SGordon.Ross@Sun.COM int
smb_ctx_init(struct smb_ctx * ctx)23410023SGordon.Ross@Sun.COM smb_ctx_init(struct smb_ctx *ctx)
23510023SGordon.Ross@Sun.COM {
23610023SGordon.Ross@Sun.COM 	char pwbuf[NSS_BUFLEN_PASSWD];
23710023SGordon.Ross@Sun.COM 	struct passwd pw;
23810023SGordon.Ross@Sun.COM 	int error = 0;
23910023SGordon.Ross@Sun.COM 
24010023SGordon.Ross@Sun.COM 	bzero(ctx, sizeof (*ctx));
24110023SGordon.Ross@Sun.COM 
24210023SGordon.Ross@Sun.COM 	error = nb_ctx_create(&ctx->ct_nb);
24310023SGordon.Ross@Sun.COM 	if (error)
24410023SGordon.Ross@Sun.COM 		return (error);
24510023SGordon.Ross@Sun.COM 
24610023SGordon.Ross@Sun.COM 	ctx->ct_dev_fd = -1;
24710367SGordon.Ross@Sun.COM 	ctx->ct_door_fd = -1;
24810023SGordon.Ross@Sun.COM 	ctx->ct_tran_fd = -1;
24910023SGordon.Ross@Sun.COM 	ctx->ct_parsedlevel = SMBL_NONE;
25010023SGordon.Ross@Sun.COM 	ctx->ct_minlevel = SMBL_NONE;
25110023SGordon.Ross@Sun.COM 	ctx->ct_maxlevel = SMBL_PATH;
25210023SGordon.Ross@Sun.COM 
25310023SGordon.Ross@Sun.COM 	/* Fill in defaults */
25410023SGordon.Ross@Sun.COM 	ctx->ct_vopt = SMBVOPT_EXT_SEC;
25510023SGordon.Ross@Sun.COM 	ctx->ct_owner = SMBM_ANY_OWNER;
25610023SGordon.Ross@Sun.COM 	ctx->ct_authflags = SMB_AT_DEFAULT;
25710023SGordon.Ross@Sun.COM 	ctx->ct_minauth = SMB_AT_DEFAULT;
25810023SGordon.Ross@Sun.COM 
25911332SGordon.Ross@Sun.COM 	error = nb_ctx_setscope(ctx->ct_nb, "");
26011332SGordon.Ross@Sun.COM 	if (error)
26111332SGordon.Ross@Sun.COM 		return (error);
26210023SGordon.Ross@Sun.COM 
26310023SGordon.Ross@Sun.COM 	/*
26410023SGordon.Ross@Sun.COM 	 * if the user name is not specified some other way,
26510023SGordon.Ross@Sun.COM 	 * use the current user name (built-in default)
26610023SGordon.Ross@Sun.COM 	 */
26710023SGordon.Ross@Sun.COM 	if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
26811332SGordon.Ross@Sun.COM 		error = smb_ctx_setuser(ctx, pw.pw_name, 0);
26911332SGordon.Ross@Sun.COM 		if (error)
27011332SGordon.Ross@Sun.COM 			return (error);
27110023SGordon.Ross@Sun.COM 		ctx->ct_home = strdup(pw.pw_name);
27211332SGordon.Ross@Sun.COM 		if (ctx->ct_home == NULL)
27311332SGordon.Ross@Sun.COM 			return (ENOMEM);
27410023SGordon.Ross@Sun.COM 	}
27510023SGordon.Ross@Sun.COM 
27610023SGordon.Ross@Sun.COM 	/*
27710023SGordon.Ross@Sun.COM 	 * Set a built-in default domain (workgroup).
27810023SGordon.Ross@Sun.COM 	 * Using the Windows/NT default for now.
27910023SGordon.Ross@Sun.COM 	 */
28011332SGordon.Ross@Sun.COM 	error = smb_ctx_setdomain(ctx, "WORKGROUP", 0);
28111332SGordon.Ross@Sun.COM 	if (error)
28211332SGordon.Ross@Sun.COM 		return (error);
28310023SGordon.Ross@Sun.COM 
28410023SGordon.Ross@Sun.COM 	return (error);
28510023SGordon.Ross@Sun.COM }
28610023SGordon.Ross@Sun.COM 
28710023SGordon.Ross@Sun.COM /*
28810023SGordon.Ross@Sun.COM  * "Scan" the command line args to find the server name,
28910023SGordon.Ross@Sun.COM  * user name, and share name, as needed.  We need these
29010023SGordon.Ross@Sun.COM  * before reading the RC files and/or sharectl values.
2916007Sthurlow  *
2926007Sthurlow  * The sequence for getting all the members filled in
2936007Sthurlow  * has some tricky aspects.  Here's how it works:
2946007Sthurlow  *
2956007Sthurlow  * The search order for options is as follows:
2966007Sthurlow  *   command line options
2976007Sthurlow  *   values parsed from UNC path (cmd)
2986007Sthurlow  *   values from RC file (per-user)
2996007Sthurlow  *   values from SMF (system-wide)
3006007Sthurlow  *   built-in defaults
3016007Sthurlow  *
3026007Sthurlow  * Normally, one would simply get all the values starting with
3036007Sthurlow  * the bottom of the above list and working to the top, and
3046007Sthurlow  * overwriting values as you go.  But we need an exception.
3056007Sthurlow  *
3066007Sthurlow  * In this function, we parse the UNC path and command line options,
3076007Sthurlow  * because we need (at least) the server name when we're getting the
3086007Sthurlow  * SMF and RC file values.  However, values we get from the command
3096007Sthurlow  * should not be overwritten by SMF or RC file parsing, so we mark
3106007Sthurlow  * values from the command as "from CMD" and the RC file parser
3116007Sthurlow  * leaves in place any values so marked.  See: SMBCF_CMD_*
3126007Sthurlow  *
3136007Sthurlow  * The semantics of these flags are: "This value came from the
3146007Sthurlow  * current command instance, not from sources that may apply to
3156007Sthurlow  * multiple commands."  (Different from the old "FROMUSR" flag.)
3166007Sthurlow  *
3176007Sthurlow  * Note that smb_ctx_opt() is called later to handle the
3186007Sthurlow  * remaining options, which should be ignored here.
3196007Sthurlow  * The (magic) leading ":" in cf_getopt() makes it
3206007Sthurlow  * ignore options not in the options string.
3216007Sthurlow  */
3226007Sthurlow int
smb_ctx_scan_argv(struct smb_ctx * ctx,int argc,char ** argv,int minlevel,int maxlevel,int sharetype)32310023SGordon.Ross@Sun.COM smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
3246007Sthurlow 	int minlevel, int maxlevel, int sharetype)
3256007Sthurlow {
32610023SGordon.Ross@Sun.COM 	int  ind, opt, error = 0;
3276007Sthurlow 	int aflg = 0, uflg = 0;
32810023SGordon.Ross@Sun.COM 	const char *arg;
3296007Sthurlow 
33010023SGordon.Ross@Sun.COM 	/*
33110023SGordon.Ross@Sun.COM 	 * Parse options, if any.  Values from here too
33210023SGordon.Ross@Sun.COM 	 * are marked as "from CMD".
33310023SGordon.Ross@Sun.COM 	 */
33410023SGordon.Ross@Sun.COM 	if (argv == NULL)
33510023SGordon.Ross@Sun.COM 		return (0);
33610023SGordon.Ross@Sun.COM 
33710023SGordon.Ross@Sun.COM 	ctx->ct_minlevel = minlevel;
33810023SGordon.Ross@Sun.COM 	ctx->ct_maxlevel = maxlevel;
33910023SGordon.Ross@Sun.COM 	ctx->ct_shtype_req = sharetype;
34010023SGordon.Ross@Sun.COM 
34110023SGordon.Ross@Sun.COM 	cf_opt_lock();
34210023SGordon.Ross@Sun.COM 	/* Careful: no return/goto before cf_opt_unlock! */
34310023SGordon.Ross@Sun.COM 	while (error == 0) {
34410023SGordon.Ross@Sun.COM 		opt = cf_getopt(argc, argv, STDPARAM_OPT);
34510023SGordon.Ross@Sun.COM 		if (opt == -1)
34610023SGordon.Ross@Sun.COM 			break;
34710023SGordon.Ross@Sun.COM 		arg = cf_optarg;
34810023SGordon.Ross@Sun.COM 		/* NB: handle most in smb_ctx_opt */
34910023SGordon.Ross@Sun.COM 		switch (opt) {
35010023SGordon.Ross@Sun.COM 		case 'A':
35110023SGordon.Ross@Sun.COM 			aflg = 1;
35210023SGordon.Ross@Sun.COM 			error = smb_ctx_setuser(ctx, "", TRUE);
35310023SGordon.Ross@Sun.COM 			ctx->ct_flags |= SMBCF_NOPWD;
35410023SGordon.Ross@Sun.COM 			break;
35510023SGordon.Ross@Sun.COM 		case 'U':
35610023SGordon.Ross@Sun.COM 			uflg = 1;
35710023SGordon.Ross@Sun.COM 			error = smb_ctx_setuser(ctx, arg, TRUE);
35810023SGordon.Ross@Sun.COM 			break;
35910023SGordon.Ross@Sun.COM 		default:
36010023SGordon.Ross@Sun.COM 			DPRINT("skip opt=%c", opt);
36110023SGordon.Ross@Sun.COM 			break;
36210023SGordon.Ross@Sun.COM 		}
36310023SGordon.Ross@Sun.COM 	}
36410023SGordon.Ross@Sun.COM 	ind = cf_optind;
36510023SGordon.Ross@Sun.COM 	arg = argv[ind];
36610023SGordon.Ross@Sun.COM 	cf_optind = cf_optreset = 1;
36710023SGordon.Ross@Sun.COM 	cf_opt_unlock();
36810023SGordon.Ross@Sun.COM 
3696007Sthurlow 	if (error)
3706007Sthurlow 		return (error);
3716007Sthurlow 
37210023SGordon.Ross@Sun.COM 	if (aflg && uflg)  {
37310023SGordon.Ross@Sun.COM 		printf(gettext("-A and -U flags are exclusive.\n"));
37410023SGordon.Ross@Sun.COM 		return (EINVAL);
37510023SGordon.Ross@Sun.COM 	}
3766007Sthurlow 
3776007Sthurlow 	/*
3786007Sthurlow 	 * Parse the UNC path.  Values from here are
3796007Sthurlow 	 * marked as "from CMD".
3806007Sthurlow 	 */
38110023SGordon.Ross@Sun.COM 	for (; ind < argc; ind++) {
38210023SGordon.Ross@Sun.COM 		arg = argv[ind];
38310023SGordon.Ross@Sun.COM 		if (strncmp(arg, "//", 2) != 0)
3846007Sthurlow 			continue;
38510023SGordon.Ross@Sun.COM 		error = smb_ctx_parseunc(ctx, arg,
38610023SGordon.Ross@Sun.COM 		    minlevel, maxlevel, sharetype, &arg);
3876007Sthurlow 		if (error)
3886007Sthurlow 			return (error);
3896007Sthurlow 		break;
3906007Sthurlow 	}
3916007Sthurlow 
39210023SGordon.Ross@Sun.COM 	return (error);
39310023SGordon.Ross@Sun.COM }
3946007Sthurlow 
39510023SGordon.Ross@Sun.COM void
smb_ctx_free(smb_ctx_t * ctx)39610023SGordon.Ross@Sun.COM smb_ctx_free(smb_ctx_t *ctx)
39710023SGordon.Ross@Sun.COM {
39810023SGordon.Ross@Sun.COM 	smb_ctx_done(ctx);
39910023SGordon.Ross@Sun.COM 	free(ctx);
4006007Sthurlow }
4016007Sthurlow 
4026007Sthurlow void
smb_ctx_done(struct smb_ctx * ctx)4036007Sthurlow smb_ctx_done(struct smb_ctx *ctx)
4046007Sthurlow {
4056007Sthurlow 
4066007Sthurlow 	rpc_cleanup_smbctx(ctx);
4076007Sthurlow 
40810023SGordon.Ross@Sun.COM 	if (ctx->ct_dev_fd != -1) {
40910023SGordon.Ross@Sun.COM 		close(ctx->ct_dev_fd);
41010023SGordon.Ross@Sun.COM 		ctx->ct_dev_fd = -1;
41110023SGordon.Ross@Sun.COM 	}
41210367SGordon.Ross@Sun.COM 	if (ctx->ct_door_fd != -1) {
41310367SGordon.Ross@Sun.COM 		close(ctx->ct_door_fd);
41410367SGordon.Ross@Sun.COM 		ctx->ct_door_fd = -1;
41510367SGordon.Ross@Sun.COM 	}
41610023SGordon.Ross@Sun.COM 	if (ctx->ct_tran_fd != -1) {
41710023SGordon.Ross@Sun.COM 		close(ctx->ct_tran_fd);
41810023SGordon.Ross@Sun.COM 		ctx->ct_tran_fd = -1;
41910023SGordon.Ross@Sun.COM 	}
42010023SGordon.Ross@Sun.COM 	if (ctx->ct_srvaddr_s) {
42110023SGordon.Ross@Sun.COM 		free(ctx->ct_srvaddr_s);
42210023SGordon.Ross@Sun.COM 		ctx->ct_srvaddr_s = NULL;
42310023SGordon.Ross@Sun.COM 	}
42410023SGordon.Ross@Sun.COM 	if (ctx->ct_nb) {
42510023SGordon.Ross@Sun.COM 		nb_ctx_done(ctx->ct_nb);
42610023SGordon.Ross@Sun.COM 		ctx->ct_nb = NULL;
42710023SGordon.Ross@Sun.COM 	}
42810023SGordon.Ross@Sun.COM 	if (ctx->ct_locname) {
42910023SGordon.Ross@Sun.COM 		free(ctx->ct_locname);
43010023SGordon.Ross@Sun.COM 		ctx->ct_locname = NULL;
4316007Sthurlow 	}
43210023SGordon.Ross@Sun.COM 	if (ctx->ct_origshare) {
4336007Sthurlow 		free(ctx->ct_origshare);
43410023SGordon.Ross@Sun.COM 		ctx->ct_origshare = NULL;
43510023SGordon.Ross@Sun.COM 	}
43610023SGordon.Ross@Sun.COM 	if (ctx->ct_fullserver) {
4376007Sthurlow 		free(ctx->ct_fullserver);
43810023SGordon.Ross@Sun.COM 		ctx->ct_fullserver = NULL;
43910023SGordon.Ross@Sun.COM 	}
44010023SGordon.Ross@Sun.COM 	if (ctx->ct_addrinfo) {
44110023SGordon.Ross@Sun.COM 		freeaddrinfo(ctx->ct_addrinfo);
44210023SGordon.Ross@Sun.COM 		ctx->ct_addrinfo = NULL;
44310023SGordon.Ross@Sun.COM 	}
44410023SGordon.Ross@Sun.COM 	if (ctx->ct_home)
44510023SGordon.Ross@Sun.COM 		free(ctx->ct_home);
44610023SGordon.Ross@Sun.COM 	if (ctx->ct_srv_OS) {
44710023SGordon.Ross@Sun.COM 		free(ctx->ct_srv_OS);
44810023SGordon.Ross@Sun.COM 		ctx->ct_srv_OS = NULL;
44910023SGordon.Ross@Sun.COM 	}
45010023SGordon.Ross@Sun.COM 	if (ctx->ct_srv_LM) {
45110023SGordon.Ross@Sun.COM 		free(ctx->ct_srv_LM);
45210023SGordon.Ross@Sun.COM 		ctx->ct_srv_LM = NULL;
45310023SGordon.Ross@Sun.COM 	}
45410023SGordon.Ross@Sun.COM 	if (ctx->ct_mackey) {
45510023SGordon.Ross@Sun.COM 		free(ctx->ct_mackey);
45610023SGordon.Ross@Sun.COM 		ctx->ct_mackey = NULL;
45710023SGordon.Ross@Sun.COM 	}
4586007Sthurlow }
4596007Sthurlow 
4606007Sthurlow static int
getsubstring(const char * p,uchar_t sep,char * dest,int maxlen,const char ** next)4616007Sthurlow getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
4626007Sthurlow     const char **next)
4636007Sthurlow {
4646007Sthurlow 	int len;
4656007Sthurlow 
4666007Sthurlow 	maxlen--;
4676007Sthurlow 	for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
4686007Sthurlow 		if (*p == 0)
4696007Sthurlow 			return (EINVAL);
4706007Sthurlow 		*dest = *p;
4716007Sthurlow 	}
4726007Sthurlow 	*dest = 0;
4736007Sthurlow 	*next = *p ? p + 1 : p;
4746007Sthurlow 	return (0);
4756007Sthurlow }
4766007Sthurlow 
4776007Sthurlow /*
4786007Sthurlow  * Parse the UNC path.  Here we expect something like
4796007Sthurlow  *   "//[workgroup;][user[:password]@]host[/share[/path]]"
4806007Sthurlow  * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
4816007Sthurlow  * Values found here are marked as "from CMD".
4826007Sthurlow  */
4836007Sthurlow int
smb_ctx_parseunc(struct smb_ctx * ctx,const char * unc,int minlevel,int maxlevel,int sharetype,const char ** next)48410023SGordon.Ross@Sun.COM smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
48510023SGordon.Ross@Sun.COM 	int minlevel, int maxlevel, int sharetype,
4866007Sthurlow 	const char **next)
4876007Sthurlow {
4886007Sthurlow 	const char *p = unc;
48910023SGordon.Ross@Sun.COM 	char *p1, *colon;
4906007Sthurlow 	char tmp[1024];
4916007Sthurlow 	int error;
4926007Sthurlow 
49310023SGordon.Ross@Sun.COM 	/*
49410023SGordon.Ross@Sun.COM 	 * This may be called outside of _scan_argv,
49510023SGordon.Ross@Sun.COM 	 * so make sure these get initialized.
49610023SGordon.Ross@Sun.COM 	 */
49710023SGordon.Ross@Sun.COM 	ctx->ct_minlevel = minlevel;
49810023SGordon.Ross@Sun.COM 	ctx->ct_maxlevel = maxlevel;
49910023SGordon.Ross@Sun.COM 	ctx->ct_shtype_req = sharetype;
50010023SGordon.Ross@Sun.COM 
5016007Sthurlow 	ctx->ct_parsedlevel = SMBL_NONE;
5026007Sthurlow 	if (*p++ != '/' || *p++ != '/') {
5036007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
5046007Sthurlow 		    "UNC should start with '//'"), 0);
50510023SGordon.Ross@Sun.COM 		error = EINVAL;
50610023SGordon.Ross@Sun.COM 		goto out;
5076007Sthurlow 	}
5086007Sthurlow 	p1 = tmp;
5096007Sthurlow 	error = getsubstring(p, ';', p1, sizeof (tmp), &p);
5106007Sthurlow 	if (!error) {
5116007Sthurlow 		if (*p1 == 0) {
5126007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5136007Sthurlow 			    "empty workgroup name"), 0);
51410023SGordon.Ross@Sun.COM 			error = EINVAL;
51510023SGordon.Ross@Sun.COM 			goto out;
5166007Sthurlow 		}
51710023SGordon.Ross@Sun.COM 		error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE);
5186007Sthurlow 		if (error)
51910023SGordon.Ross@Sun.COM 			goto out;
5206007Sthurlow 	}
5216007Sthurlow 	colon = (char *)p;
5226007Sthurlow 	error = getsubstring(p, '@', p1, sizeof (tmp), &p);
5236007Sthurlow 	if (!error) {
5246007Sthurlow 		if (ctx->ct_maxlevel < SMBL_VC) {
5256007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5266007Sthurlow 			    "no user name required"), 0);
52710023SGordon.Ross@Sun.COM 			error = EINVAL;
52810023SGordon.Ross@Sun.COM 			goto out;
5296007Sthurlow 		}
5306007Sthurlow 		p1 = strchr(tmp, ':');
5316007Sthurlow 		if (p1) {
5326007Sthurlow 			colon += p1 - tmp;
5336007Sthurlow 			*p1++ = (char)0;
5346007Sthurlow 			error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
5356007Sthurlow 			if (error)
53610023SGordon.Ross@Sun.COM 				goto out;
5376007Sthurlow 			if (p - colon > 2)
5386007Sthurlow 				memset(colon+1, '*', p - colon - 2);
5396007Sthurlow 		}
5406007Sthurlow 		p1 = tmp;
5416007Sthurlow 		if (*p1 == 0) {
5426007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5436007Sthurlow 			    "empty user name"), 0);
54410023SGordon.Ross@Sun.COM 			error = EINVAL;
54510023SGordon.Ross@Sun.COM 			goto out;
5466007Sthurlow 		}
5476007Sthurlow 		error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
5486007Sthurlow 		if (error)
54910023SGordon.Ross@Sun.COM 			goto out;
5506007Sthurlow 		ctx->ct_parsedlevel = SMBL_VC;
5516007Sthurlow 	}
5526007Sthurlow 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
5536007Sthurlow 	if (error) {
5546007Sthurlow 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
5556007Sthurlow 		if (error) {
5566007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5576007Sthurlow 			    "no server name found"), 0);
55810023SGordon.Ross@Sun.COM 			goto out;
5596007Sthurlow 		}
5606007Sthurlow 	}
5616007Sthurlow 	if (*p1 == 0) {
5626007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
56310023SGordon.Ross@Sun.COM 		error = EINVAL;
56410023SGordon.Ross@Sun.COM 		goto out;
5656007Sthurlow 	}
5666007Sthurlow 
5676007Sthurlow 	/*
56810023SGordon.Ross@Sun.COM 	 * Save ct_fullserver without case conversion.
5696007Sthurlow 	 */
57010023SGordon.Ross@Sun.COM 	if (strchr(tmp, '%'))
57110023SGordon.Ross@Sun.COM 		(void) unpercent(tmp);
57211332SGordon.Ross@Sun.COM 	error = smb_ctx_setfullserver(ctx, tmp);
57310023SGordon.Ross@Sun.COM 	if (error)
57410023SGordon.Ross@Sun.COM 		goto out;
5756007Sthurlow 
57610023SGordon.Ross@Sun.COM #ifdef	SMB_ST_NONE
57710023SGordon.Ross@Sun.COM 	if (sharetype == SMB_ST_NONE) {
57810023SGordon.Ross@Sun.COM 		if (next)
57910023SGordon.Ross@Sun.COM 			*next = p;
58010023SGordon.Ross@Sun.COM 		error = 0;
58110023SGordon.Ross@Sun.COM 		goto out;
58210023SGordon.Ross@Sun.COM 	}
58310023SGordon.Ross@Sun.COM #endif
5846007Sthurlow 
5856007Sthurlow 	if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
5866007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
58710023SGordon.Ross@Sun.COM 		error = EINVAL;
58810023SGordon.Ross@Sun.COM 		goto out;
5896007Sthurlow 	}
5906007Sthurlow 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
5916007Sthurlow 	if (error) {
5926007Sthurlow 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
5936007Sthurlow 		if (error) {
5946007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5956007Sthurlow 			    "unexpected end of line"), 0);
59610023SGordon.Ross@Sun.COM 			goto out;
5976007Sthurlow 		}
5986007Sthurlow 	}
5996007Sthurlow 	if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
6006007Sthurlow 	    !(ctx->ct_flags & SMBCF_BROWSEOK)) {
6016007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
60210023SGordon.Ross@Sun.COM 		error = EINVAL;
60310023SGordon.Ross@Sun.COM 		goto out;
6046007Sthurlow 	}
60510023SGordon.Ross@Sun.COM 	if (next)
60610023SGordon.Ross@Sun.COM 		*next = p;
60710023SGordon.Ross@Sun.COM 	if (*p1 == 0) {
60810023SGordon.Ross@Sun.COM 		error = 0;
60910023SGordon.Ross@Sun.COM 		goto out;
61010023SGordon.Ross@Sun.COM 	}
6116007Sthurlow 	error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
61210023SGordon.Ross@Sun.COM 
61310023SGordon.Ross@Sun.COM out:
61410023SGordon.Ross@Sun.COM 	if (error == 0 && smb_debug > 0)
61510023SGordon.Ross@Sun.COM 		dump_ctx("after smb_ctx_parseunc", ctx);
61610023SGordon.Ross@Sun.COM 
6176007Sthurlow 	return (error);
6186007Sthurlow }
6196007Sthurlow 
62010023SGordon.Ross@Sun.COM #ifdef KICONV_SUPPORT
6216007Sthurlow int
smb_ctx_setcharset(struct smb_ctx * ctx,const char * arg)6226007Sthurlow smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
6236007Sthurlow {
6246007Sthurlow 	char *cp, *servercs, *localcs;
6256007Sthurlow 	int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
6266007Sthurlow 	int scslen, lcslen, error;
6276007Sthurlow 
6286007Sthurlow 	cp = strchr(arg, ':');
6296007Sthurlow 	lcslen = cp ? (cp - arg) : 0;
6306007Sthurlow 	if (lcslen == 0 || lcslen >= cslen) {
6316007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
6326007Sthurlow 		    "invalid local charset specification (%s)"), 0, arg);
6336007Sthurlow 		return (EINVAL);
6346007Sthurlow 	}
6356007Sthurlow 	scslen = (size_t)strlen(++cp);
6366007Sthurlow 	if (scslen == 0 || scslen >= cslen) {
6376007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
6386007Sthurlow 		    "invalid server charset specification (%s)"), 0, arg);
6396007Sthurlow 		return (EINVAL);
6406007Sthurlow 	}
6416007Sthurlow 	localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
6426007Sthurlow 	localcs[lcslen] = 0;
6436007Sthurlow 	servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
6446007Sthurlow 	error = nls_setrecode(localcs, servercs);
6456007Sthurlow 	if (error == 0)
6466007Sthurlow 		return (0);
6476007Sthurlow 	smb_error(dgettext(TEXT_DOMAIN,
6486007Sthurlow 	    "can't initialize iconv support (%s:%s)"),
6496007Sthurlow 	    error, localcs, servercs);
6506007Sthurlow 	localcs[0] = 0;
6516007Sthurlow 	servercs[0] = 0;
6526007Sthurlow 	return (error);
6536007Sthurlow }
65410023SGordon.Ross@Sun.COM #endif /* KICONV_SUPPORT */
65510023SGordon.Ross@Sun.COM 
65610023SGordon.Ross@Sun.COM int
smb_ctx_setauthflags(struct smb_ctx * ctx,int flags)65710023SGordon.Ross@Sun.COM smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
65810023SGordon.Ross@Sun.COM {
65910023SGordon.Ross@Sun.COM 	ctx->ct_authflags = flags;
66010023SGordon.Ross@Sun.COM 	return (0);
66110023SGordon.Ross@Sun.COM }
6626007Sthurlow 
6636007Sthurlow int
smb_ctx_setfullserver(struct smb_ctx * ctx,const char * name)6646007Sthurlow smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
6656007Sthurlow {
66610023SGordon.Ross@Sun.COM 	char *p = strdup(name);
66710023SGordon.Ross@Sun.COM 
66810023SGordon.Ross@Sun.COM 	if (p == NULL)
6696007Sthurlow 		return (ENOMEM);
67010023SGordon.Ross@Sun.COM 	if (ctx->ct_fullserver)
67110023SGordon.Ross@Sun.COM 		free(ctx->ct_fullserver);
67210023SGordon.Ross@Sun.COM 	ctx->ct_fullserver = p;
6736007Sthurlow 	return (0);
6746007Sthurlow }
6756007Sthurlow 
6766007Sthurlow int
smb_ctx_setserver(struct smb_ctx * ctx,const char * name)6776007Sthurlow smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
6786007Sthurlow {
67910023SGordon.Ross@Sun.COM 	strlcpy(ctx->ct_srvname, name,
68010023SGordon.Ross@Sun.COM 	    sizeof (ctx->ct_srvname));
68110023SGordon.Ross@Sun.COM 	return (0);
6826007Sthurlow }
6836007Sthurlow 
6846007Sthurlow int
smb_ctx_setuser(struct smb_ctx * ctx,const char * name,int from_cmd)6856007Sthurlow smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
6866007Sthurlow {
6876007Sthurlow 
68810023SGordon.Ross@Sun.COM 	if (strlen(name) >= sizeof (ctx->ct_user)) {
6896007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
6906007Sthurlow 		    "user name '%s' too long"), 0, name);
6916007Sthurlow 		return (ENAMETOOLONG);
6926007Sthurlow 	}
6936007Sthurlow 
6946007Sthurlow 	/*
6956007Sthurlow 	 * Don't overwrite a value from the command line
6966007Sthurlow 	 * with one from anywhere else.
6976007Sthurlow 	 */
6986007Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
6996007Sthurlow 		return (0);
7006007Sthurlow 
70110023SGordon.Ross@Sun.COM 	strlcpy(ctx->ct_user, name,
70210023SGordon.Ross@Sun.COM 	    sizeof (ctx->ct_user));
7036007Sthurlow 
7046007Sthurlow 	/* Mark this as "from the command line". */
7056007Sthurlow 	if (from_cmd)
7066007Sthurlow 		ctx->ct_flags |= SMBCF_CMD_USR;
7076007Sthurlow 
7086007Sthurlow 	return (0);
7096007Sthurlow }
7106007Sthurlow 
7116007Sthurlow /*
7126007Sthurlow  * Don't overwrite a domain name from the
7136007Sthurlow  * command line with one from anywhere else.
7146007Sthurlow  * See smb_ctx_init() for notes about this.
7156007Sthurlow  */
7166007Sthurlow int
smb_ctx_setdomain(struct smb_ctx * ctx,const char * name,int from_cmd)71710023SGordon.Ross@Sun.COM smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd)
7186007Sthurlow {
7196007Sthurlow 
72010023SGordon.Ross@Sun.COM 	if (strlen(name) >= sizeof (ctx->ct_domain)) {
7216007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
7226007Sthurlow 		    "workgroup name '%s' too long"), 0, name);
7236007Sthurlow 		return (ENAMETOOLONG);
7246007Sthurlow 	}
7256007Sthurlow 
7266007Sthurlow 	/*
7276007Sthurlow 	 * Don't overwrite a value from the command line
7286007Sthurlow 	 * with one from anywhere else.
7296007Sthurlow 	 */
7306007Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
7316007Sthurlow 		return (0);
7326007Sthurlow 
73310023SGordon.Ross@Sun.COM 	strlcpy(ctx->ct_domain, name,
73410023SGordon.Ross@Sun.COM 	    sizeof (ctx->ct_domain));
7356007Sthurlow 
7366007Sthurlow 	/* Mark this as "from the command line". */
7376007Sthurlow 	if (from_cmd)
7386007Sthurlow 		ctx->ct_flags |= SMBCF_CMD_DOM;
7396007Sthurlow 
7406007Sthurlow 	return (0);
7416007Sthurlow }
7426007Sthurlow 
7436007Sthurlow int
smb_ctx_setpassword(struct smb_ctx * ctx,const char * passwd,int from_cmd)7446007Sthurlow smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
7456007Sthurlow {
74610023SGordon.Ross@Sun.COM 	int err;
7476007Sthurlow 
74810023SGordon.Ross@Sun.COM 	if (passwd == NULL)
7496007Sthurlow 		return (EINVAL);
75010023SGordon.Ross@Sun.COM 	if (strlen(passwd) >= sizeof (ctx->ct_password)) {
7516007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
7526007Sthurlow 		return (ENAMETOOLONG);
7536007Sthurlow 	}
7546007Sthurlow 
7556007Sthurlow 	/*
75610023SGordon.Ross@Sun.COM 	 * If called again after comand line parsing,
75710023SGordon.Ross@Sun.COM 	 * don't overwrite a value from the command line
75810023SGordon.Ross@Sun.COM 	 * with one from any stored config.
7596007Sthurlow 	 */
7606007Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
7616007Sthurlow 		return (0);
7626007Sthurlow 
76310023SGordon.Ross@Sun.COM 	memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
7646007Sthurlow 	if (strncmp(passwd, "$$1", 3) == 0)
76511332SGordon.Ross@Sun.COM 		(void) smb_simpledecrypt(ctx->ct_password, passwd);
7666007Sthurlow 	else
76710023SGordon.Ross@Sun.COM 		strlcpy(ctx->ct_password, passwd,
76810023SGordon.Ross@Sun.COM 		    sizeof (ctx->ct_password));
76910023SGordon.Ross@Sun.COM 
77010023SGordon.Ross@Sun.COM 	/*
77110023SGordon.Ross@Sun.COM 	 * Compute LM hash, NT hash.
77210023SGordon.Ross@Sun.COM 	 */
77310023SGordon.Ross@Sun.COM 	if (ctx->ct_password[0]) {
77410023SGordon.Ross@Sun.COM 		err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
77510023SGordon.Ross@Sun.COM 		if (err != 0)
77610023SGordon.Ross@Sun.COM 			return (err);
77710023SGordon.Ross@Sun.COM 		err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
77810023SGordon.Ross@Sun.COM 		if (err != 0)
77910023SGordon.Ross@Sun.COM 			return (err);
78010023SGordon.Ross@Sun.COM 	}
7816007Sthurlow 
7826007Sthurlow 	/* Mark this as "from the command line". */
7836007Sthurlow 	if (from_cmd)
7846007Sthurlow 		ctx->ct_flags |= SMBCF_CMD_PW;
7856007Sthurlow 
7866007Sthurlow 	return (0);
7876007Sthurlow }
7886007Sthurlow 
78910023SGordon.Ross@Sun.COM /*
79010023SGordon.Ross@Sun.COM  * Use this to set NTLM auth. info (hashes)
79110023SGordon.Ross@Sun.COM  * when we don't have the password.
79210023SGordon.Ross@Sun.COM  */
79310023SGordon.Ross@Sun.COM int
smb_ctx_setpwhash(smb_ctx_t * ctx,const uchar_t * nthash,const uchar_t * lmhash)79410023SGordon.Ross@Sun.COM smb_ctx_setpwhash(smb_ctx_t *ctx,
79510023SGordon.Ross@Sun.COM     const uchar_t *nthash, const uchar_t *lmhash)
79610023SGordon.Ross@Sun.COM {
79710023SGordon.Ross@Sun.COM 
79810023SGordon.Ross@Sun.COM 	/* Need ct_password to be non-null. */
79910023SGordon.Ross@Sun.COM 	if (ctx->ct_password[0] == '\0')
80010023SGordon.Ross@Sun.COM 		strlcpy(ctx->ct_password, "$HASH",
80110023SGordon.Ross@Sun.COM 		    sizeof (ctx->ct_password));
80210023SGordon.Ross@Sun.COM 
80310023SGordon.Ross@Sun.COM 	/*
80410023SGordon.Ross@Sun.COM 	 * Compute LM hash, NT hash.
80510023SGordon.Ross@Sun.COM 	 */
80610023SGordon.Ross@Sun.COM 	memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
80710023SGordon.Ross@Sun.COM 
80810023SGordon.Ross@Sun.COM 	/* The LM hash is optional */
80910023SGordon.Ross@Sun.COM 	if (lmhash) {
81010023SGordon.Ross@Sun.COM 		memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
81110023SGordon.Ross@Sun.COM 	}
81210023SGordon.Ross@Sun.COM 
81310023SGordon.Ross@Sun.COM 	return (0);
81410023SGordon.Ross@Sun.COM }
81510023SGordon.Ross@Sun.COM 
8166007Sthurlow int
smb_ctx_setshare(struct smb_ctx * ctx,const char * share,int stype)8176007Sthurlow smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
8186007Sthurlow {
81910023SGordon.Ross@Sun.COM 	if (strlen(share) >= SMBIOC_MAX_NAME) {
8206007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
8216007Sthurlow 		    "share name '%s' too long"), 0, share);
8226007Sthurlow 		return (ENAMETOOLONG);
8236007Sthurlow 	}
8246007Sthurlow 	if (ctx->ct_origshare)
8256007Sthurlow 		free(ctx->ct_origshare);
8266007Sthurlow 	if ((ctx->ct_origshare = strdup(share)) == NULL)
8276007Sthurlow 		return (ENOMEM);
82810023SGordon.Ross@Sun.COM 
82910023SGordon.Ross@Sun.COM 	ctx->ct_shtype_req = stype;
83010023SGordon.Ross@Sun.COM 
8316007Sthurlow 	return (0);
8326007Sthurlow }
8336007Sthurlow 
8346007Sthurlow int
smb_ctx_setsrvaddr(struct smb_ctx * ctx,const char * addr)8356007Sthurlow smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
8366007Sthurlow {
8376007Sthurlow 	if (addr == NULL || addr[0] == 0)
8386007Sthurlow 		return (EINVAL);
83910023SGordon.Ross@Sun.COM 	if (ctx->ct_srvaddr_s)
84010023SGordon.Ross@Sun.COM 		free(ctx->ct_srvaddr_s);
84110023SGordon.Ross@Sun.COM 	if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL)
8426007Sthurlow 		return (ENOMEM);
8436007Sthurlow 	return (0);
8446007Sthurlow }
8456007Sthurlow 
84610419SGordon.Ross@Sun.COM /*
84710419SGordon.Ross@Sun.COM  * API for library caller to set signing enabled, required
84810419SGordon.Ross@Sun.COM  * Note: if not enable, ignore require
84910419SGordon.Ross@Sun.COM  */
85010419SGordon.Ross@Sun.COM int
smb_ctx_setsigning(struct smb_ctx * ctx,int enable,int require)85110419SGordon.Ross@Sun.COM smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
85210419SGordon.Ross@Sun.COM {
85310419SGordon.Ross@Sun.COM 	ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
85410419SGordon.Ross@Sun.COM 	if (enable) {
85510419SGordon.Ross@Sun.COM 		ctx->ct_vopt |=	SMBVOPT_SIGNING_ENABLED;
85610419SGordon.Ross@Sun.COM 		if (require)
85710419SGordon.Ross@Sun.COM 			ctx->ct_vopt |=	SMBVOPT_SIGNING_REQUIRED;
85810419SGordon.Ross@Sun.COM 	}
85910419SGordon.Ross@Sun.COM 	return (0);
86010419SGordon.Ross@Sun.COM }
86110419SGordon.Ross@Sun.COM 
8626007Sthurlow static int
smb_parse_owner(char * pair,uid_t * uid,gid_t * gid)8636007Sthurlow smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
8646007Sthurlow {
8656007Sthurlow 	struct group gr;
8666007Sthurlow 	struct passwd pw;
8676007Sthurlow 	char buf[NSS_BUFLEN_PASSWD];
8686007Sthurlow 	char *cp;
8696007Sthurlow 
8706007Sthurlow 	cp = strchr(pair, ':');
8716007Sthurlow 	if (cp) {
8726007Sthurlow 		*cp++ = '\0';
87310023SGordon.Ross@Sun.COM 		if (*cp && gid) {
8746007Sthurlow 			if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
8756007Sthurlow 				*gid = gr.gr_gid;
8766007Sthurlow 			} else
8776007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
8786007Sthurlow 				    "Invalid group name %s, ignored"), 0, cp);
8796007Sthurlow 		}
8806007Sthurlow 	}
8816007Sthurlow 	if (*pair) {
8826007Sthurlow 		if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
8836007Sthurlow 			*uid = pw.pw_uid;
8846007Sthurlow 		} else
8856007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
8866007Sthurlow 			    "Invalid user name %s, ignored"), 0, pair);
8876007Sthurlow 	}
8886007Sthurlow 
8896007Sthurlow 	return (0);
8906007Sthurlow }
8916007Sthurlow 
8926007Sthurlow /*
89312140SGordon.Ross@Sun.COM  * Suport a securty options arg, i.e. -S noext,lm,ntlm
89412140SGordon.Ross@Sun.COM  * for testing various type of authenticators.
89512140SGordon.Ross@Sun.COM  */
89612140SGordon.Ross@Sun.COM static struct nv
89712140SGordon.Ross@Sun.COM sectype_table[] = {
89812140SGordon.Ross@Sun.COM 	/* noext - handled below */
89912140SGordon.Ross@Sun.COM 	{ "anon",	SMB_AT_ANON },
90012140SGordon.Ross@Sun.COM 	{ "lm",		SMB_AT_LM1 },
90112140SGordon.Ross@Sun.COM 	{ "ntlm",	SMB_AT_NTLM1 },
90212140SGordon.Ross@Sun.COM 	{ "ntlm2",	SMB_AT_NTLM2 },
90312140SGordon.Ross@Sun.COM 	{ "krb5",	SMB_AT_KRB5 },
90412140SGordon.Ross@Sun.COM 	{ NULL, 	0 },
90512140SGordon.Ross@Sun.COM };
90612140SGordon.Ross@Sun.COM int
smb_parse_secopts(struct smb_ctx * ctx,const char * arg)90712140SGordon.Ross@Sun.COM smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
90812140SGordon.Ross@Sun.COM {
90912140SGordon.Ross@Sun.COM 	const char *sep = ":;,";
91012140SGordon.Ross@Sun.COM 	const char *p = arg;
91112140SGordon.Ross@Sun.COM 	struct nv *nv;
91212140SGordon.Ross@Sun.COM 	int nlen, tlen;
91312140SGordon.Ross@Sun.COM 	int authflags = 0;
91412140SGordon.Ross@Sun.COM 
91512140SGordon.Ross@Sun.COM 	for (;;) {
91612140SGordon.Ross@Sun.COM 		/* skip separators */
91712140SGordon.Ross@Sun.COM 		tlen = strspn(p, sep);
91812140SGordon.Ross@Sun.COM 		p += tlen;
91912140SGordon.Ross@Sun.COM 
92012140SGordon.Ross@Sun.COM 		nlen = strcspn(p, sep);
92112140SGordon.Ross@Sun.COM 		if (nlen == 0)
92212140SGordon.Ross@Sun.COM 			break;
92312140SGordon.Ross@Sun.COM 
92412140SGordon.Ross@Sun.COM 		if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
92512140SGordon.Ross@Sun.COM 			/* Don't offer extended security. */
92612140SGordon.Ross@Sun.COM 			ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
92712140SGordon.Ross@Sun.COM 			p += nlen;
92812140SGordon.Ross@Sun.COM 			continue;
92912140SGordon.Ross@Sun.COM 		}
93012140SGordon.Ross@Sun.COM 
93112140SGordon.Ross@Sun.COM 		/* This is rarely called, so not optimized. */
93212140SGordon.Ross@Sun.COM 		for (nv = sectype_table; nv->name; nv++) {
93312140SGordon.Ross@Sun.COM 			tlen = strlen(nv->name);
93412140SGordon.Ross@Sun.COM 			if (tlen == nlen && 0 == strncmp(p, nv->name, tlen))
93512140SGordon.Ross@Sun.COM 				break;
93612140SGordon.Ross@Sun.COM 		}
93712140SGordon.Ross@Sun.COM 		if (nv->name == NULL) {
93812140SGordon.Ross@Sun.COM 			smb_error(dgettext(TEXT_DOMAIN,
93912140SGordon.Ross@Sun.COM 			    "%s: invalid security options"), 0, p);
94012140SGordon.Ross@Sun.COM 			return (EINVAL);
94112140SGordon.Ross@Sun.COM 		}
94212140SGordon.Ross@Sun.COM 		authflags |= nv->value;
94312140SGordon.Ross@Sun.COM 		p += nlen;
94412140SGordon.Ross@Sun.COM 	}
94512140SGordon.Ross@Sun.COM 
94612140SGordon.Ross@Sun.COM 	if (authflags)
94712140SGordon.Ross@Sun.COM 		ctx->ct_authflags = authflags;
94812140SGordon.Ross@Sun.COM 
94912140SGordon.Ross@Sun.COM 	return (0);
95012140SGordon.Ross@Sun.COM }
95112140SGordon.Ross@Sun.COM 
95212140SGordon.Ross@Sun.COM /*
9536007Sthurlow  * Commands use this with getopt.  See:
9546007Sthurlow  *   STDPARAM_OPT, STDPARAM_ARGS
9556007Sthurlow  * Called after smb_ctx_readrc().
9566007Sthurlow  */
9576007Sthurlow int
smb_ctx_opt(struct smb_ctx * ctx,int opt,const char * arg)9586007Sthurlow smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
9596007Sthurlow {
9606007Sthurlow 	int error = 0;
9616007Sthurlow 	char *p, *cp;
9626007Sthurlow 	char tmp[1024];
9636007Sthurlow 
9646007Sthurlow 	switch (opt) {
9656007Sthurlow 	case 'A':
9666007Sthurlow 	case 'U':
9676007Sthurlow 		/* Handled in smb_ctx_init() */
9686007Sthurlow 		break;
9696007Sthurlow 	case 'I':
9706007Sthurlow 		error = smb_ctx_setsrvaddr(ctx, arg);
9716007Sthurlow 		break;
9726007Sthurlow 	case 'M':
97310023SGordon.Ross@Sun.COM 		/* share connect rights - ignored */
97410023SGordon.Ross@Sun.COM 		ctx->ct_flags |= SMBCF_SRIGHTS;
9756007Sthurlow 		break;
9766007Sthurlow 	case 'N':
9776007Sthurlow 		ctx->ct_flags |= SMBCF_NOPWD;
9786007Sthurlow 		break;
9796007Sthurlow 	case 'O':
9806007Sthurlow 		p = strdup(arg);
9816007Sthurlow 		cp = strchr(p, '/');
98210023SGordon.Ross@Sun.COM 		if (cp)
98310023SGordon.Ross@Sun.COM 			*cp = '\0';
98410023SGordon.Ross@Sun.COM 		error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
9856007Sthurlow 		free(p);
9866007Sthurlow 		break;
9876007Sthurlow 	case 'P':
98810023SGordon.Ross@Sun.COM /*		ctx->ct_vopt |= SMBCOPT_PERMANENT; */
9896007Sthurlow 		break;
9906007Sthurlow 	case 'R':
99110023SGordon.Ross@Sun.COM 		/* retry count - ignored */
9926007Sthurlow 		break;
99312140SGordon.Ross@Sun.COM 	case 'S':
99412140SGordon.Ross@Sun.COM 		/* Security options (undocumented, just for tests) */
99512140SGordon.Ross@Sun.COM 		error = smb_parse_secopts(ctx, arg);
99612140SGordon.Ross@Sun.COM 		break;
9976007Sthurlow 	case 'T':
99810023SGordon.Ross@Sun.COM 		/* timeout - ignored */
9996007Sthurlow 		break;
100010023SGordon.Ross@Sun.COM 	case 'D':	/* domain */
100110023SGordon.Ross@Sun.COM 	case 'W':	/* workgroup (legacy alias) */
100210023SGordon.Ross@Sun.COM 		error = smb_ctx_setdomain(ctx, tmp, TRUE);
10036007Sthurlow 		break;
10046007Sthurlow 	}
10056007Sthurlow 	return (error);
10066007Sthurlow }
10076007Sthurlow 
10086007Sthurlow 
100910023SGordon.Ross@Sun.COM /*
101010023SGordon.Ross@Sun.COM  * Original code injected iconv tables into the kernel.
101110023SGordon.Ross@Sun.COM  * Not sure if we'll need this or not...  REVISIT
101210023SGordon.Ross@Sun.COM  */
101310023SGordon.Ross@Sun.COM #ifdef KICONV_SUPPORT
10146007Sthurlow static int
smb_addiconvtbl(const char * to,const char * from,const uchar_t * tbl)10156007Sthurlow smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
10166007Sthurlow {
101710023SGordon.Ross@Sun.COM 	int error = 0;
10186007Sthurlow 
10196007Sthurlow 	error = kiconv_add_xlat_table(to, from, tbl);
10206007Sthurlow 	if (error && error != EEXIST) {
10216007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10226007Sthurlow 		    "can not setup kernel iconv table (%s:%s)"),
10236007Sthurlow 		    error, from, to);
10246007Sthurlow 		return (error);
10256007Sthurlow 	}
102610023SGordon.Ross@Sun.COM 	return (error);
10276007Sthurlow }
102810023SGordon.Ross@Sun.COM #endif	/* KICONV_SUPPORT */
10296007Sthurlow 
10306007Sthurlow /*
103110023SGordon.Ross@Sun.COM  * Verify context info. before connect operation(s),
10326007Sthurlow  * lookup specified server and try to fill all forgotten fields.
103310023SGordon.Ross@Sun.COM  * Legacy name used by commands.
10346007Sthurlow  */
10356007Sthurlow int
smb_ctx_resolve(struct smb_ctx * ctx)10366007Sthurlow smb_ctx_resolve(struct smb_ctx *ctx)
10376007Sthurlow {
10386007Sthurlow 	struct smbioc_ossn *ssn = &ctx->ct_ssn;
103910023SGordon.Ross@Sun.COM 	int error = 0;
104010023SGordon.Ross@Sun.COM #ifdef KICONV_SUPPORT
10416007Sthurlow 	uchar_t cstbl[256];
10426007Sthurlow 	uint_t i;
104310023SGordon.Ross@Sun.COM #endif
10446007Sthurlow 
104512140SGordon.Ross@Sun.COM 	if (smb_debug)
104612140SGordon.Ross@Sun.COM 		dump_ctx("before smb_ctx_resolve", ctx);
104712140SGordon.Ross@Sun.COM 
10486007Sthurlow 	ctx->ct_flags &= ~SMBCF_RESOLVED;
104910023SGordon.Ross@Sun.COM 
105010023SGordon.Ross@Sun.COM 	if (ctx->ct_fullserver == NULL) {
10516007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10526007Sthurlow 		    "no server name specified"), 0);
10536007Sthurlow 		return (EINVAL);
10546007Sthurlow 	}
105510023SGordon.Ross@Sun.COM 
105610023SGordon.Ross@Sun.COM 	if (ctx->ct_minlevel >= SMBL_SHARE &&
105710023SGordon.Ross@Sun.COM 	    ctx->ct_origshare == NULL) {
10586007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10596007Sthurlow 		    "no share name specified for %s@%s"),
106010023SGordon.Ross@Sun.COM 		    0, ssn->ssn_user, ctx->ct_fullserver);
10616007Sthurlow 		return (EINVAL);
10626007Sthurlow 	}
10636007Sthurlow 	error = nb_ctx_resolve(ctx->ct_nb);
10646007Sthurlow 	if (error)
10656007Sthurlow 		return (error);
106610023SGordon.Ross@Sun.COM #ifdef KICONV_SUPPORT
10676007Sthurlow 	if (ssn->ioc_localcs[0] == 0)
10686007Sthurlow 		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
10696007Sthurlow 	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
10706007Sthurlow 	if (error)
10716007Sthurlow 		return (error);
10726007Sthurlow 	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
10736007Sthurlow 	if (error)
10746007Sthurlow 		return (error);
10756007Sthurlow 	if (ssn->ioc_servercs[0] != 0) {
10766007Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
10776007Sthurlow 			cstbl[i] = i;
10786007Sthurlow 		nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
10796007Sthurlow 		error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
10806007Sthurlow 		    cstbl);
10816007Sthurlow 		if (error)
10826007Sthurlow 			return (error);
10836007Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
10846007Sthurlow 			cstbl[i] = i;
10856007Sthurlow 		nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
10866007Sthurlow 		error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
10876007Sthurlow 		    cstbl);
10886007Sthurlow 		if (error)
10896007Sthurlow 			return (error);
10906007Sthurlow 	}
109110023SGordon.Ross@Sun.COM #endif	/* KICONV_SUPPORT */
10926007Sthurlow 
10936007Sthurlow 	/*
109410367SGordon.Ross@Sun.COM 	 * Lookup the IP address and fill in ct_addrinfo.
109510367SGordon.Ross@Sun.COM 	 *
109610367SGordon.Ross@Sun.COM 	 * Note: smb_ctx_getaddr() returns a EAI_xxx
109710367SGordon.Ross@Sun.COM 	 * error value like getaddrinfo(3), but this
109810367SGordon.Ross@Sun.COM 	 * function needs to return an errno value.
10996007Sthurlow 	 */
110010023SGordon.Ross@Sun.COM 	error = smb_ctx_getaddr(ctx);
11016007Sthurlow 	if (error) {
110210367SGordon.Ross@Sun.COM 		const char *ais = gai_strerror(error);
11036007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1104*12925SGordon.Ross@Sun.COM 		    "can't resolve name\"%s\", %s"),
1105*12925SGordon.Ross@Sun.COM 		    0, ctx->ct_fullserver, ais);
110610367SGordon.Ross@Sun.COM 		return (ENODATA);
11076007Sthurlow 	}
110810023SGordon.Ross@Sun.COM 	assert(ctx->ct_addrinfo != NULL);
11096007Sthurlow 
111010023SGordon.Ross@Sun.COM 	/*
111110023SGordon.Ross@Sun.COM 	 * If we have a user name but no password,
111210023SGordon.Ross@Sun.COM 	 * check for a keychain entry.
111310023SGordon.Ross@Sun.COM 	 * XXX: Only for auth NTLM?
111410023SGordon.Ross@Sun.COM 	 */
111510023SGordon.Ross@Sun.COM 	if (ctx->ct_user[0] == '\0') {
111610023SGordon.Ross@Sun.COM 		/*
111710023SGordon.Ross@Sun.COM 		 * No user name (anonymous session).
111810023SGordon.Ross@Sun.COM 		 * The minauth checks do not apply.
111910023SGordon.Ross@Sun.COM 		 */
112010023SGordon.Ross@Sun.COM 		ctx->ct_authflags = SMB_AT_ANON;
112110023SGordon.Ross@Sun.COM 	} else {
112210023SGordon.Ross@Sun.COM 		/*
112310023SGordon.Ross@Sun.COM 		 * Have a user name.
112410023SGordon.Ross@Sun.COM 		 * If we don't have a p/w yet,
112510023SGordon.Ross@Sun.COM 		 * try the keychain.
112610023SGordon.Ross@Sun.COM 		 */
112710023SGordon.Ross@Sun.COM 		if (ctx->ct_password[0] == '\0')
112810023SGordon.Ross@Sun.COM 			(void) smb_get_keychain(ctx);
112910023SGordon.Ross@Sun.COM 		/*
113010023SGordon.Ross@Sun.COM 		 * Mask out disallowed auth types.
113110023SGordon.Ross@Sun.COM 		 */
113210023SGordon.Ross@Sun.COM 		ctx->ct_authflags &= ctx->ct_minauth;
11336007Sthurlow 	}
113410023SGordon.Ross@Sun.COM 	if (ctx->ct_authflags == 0) {
11356007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
113610023SGordon.Ross@Sun.COM 		    "no valid auth. types"), 0);
113710023SGordon.Ross@Sun.COM 		return (ENOTSUP);
11386294Sbs135383 	}
11396294Sbs135383 
11406007Sthurlow 	ctx->ct_flags |= SMBCF_RESOLVED;
11416007Sthurlow 	if (smb_debug)
11426007Sthurlow 		dump_ctx("after smb_ctx_resolve", ctx);
11436007Sthurlow 
11446007Sthurlow 	return (0);
11456007Sthurlow }
11466007Sthurlow 
11476007Sthurlow int
smb_open_driver()11486007Sthurlow smb_open_driver()
11496007Sthurlow {
115010023SGordon.Ross@Sun.COM 	int err, fd;
11516007Sthurlow 	uint32_t version;
11526007Sthurlow 
11536007Sthurlow 	fd = open("/dev/"NSMB_NAME, O_RDWR);
115410023SGordon.Ross@Sun.COM 	if (fd < 0) {
115510023SGordon.Ross@Sun.COM 		err = errno;
115610023SGordon.Ross@Sun.COM 		smb_error(dgettext(TEXT_DOMAIN,
115710023SGordon.Ross@Sun.COM 		    "failed to open driver"), err);
115810023SGordon.Ross@Sun.COM 		return (-1);
115910023SGordon.Ross@Sun.COM 	}
11606007Sthurlow 
11616007Sthurlow 	/*
11626007Sthurlow 	 * Check the driver version (paranoia)
11636007Sthurlow 	 * Do this BEFORE any other ioctl calls.
11646007Sthurlow 	 */
116510023SGordon.Ross@Sun.COM 	if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
116610023SGordon.Ross@Sun.COM 		version = 0;
11676007Sthurlow 	if (version != NSMB_VERSION) {
11686007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
11696007Sthurlow 		    "incorrect driver version"), 0);
11706007Sthurlow 		close(fd);
11716007Sthurlow 		return (-1);
11726007Sthurlow 	}
11736007Sthurlow 
117410023SGordon.Ross@Sun.COM 	/* This handle controls per-process resources. */
117510023SGordon.Ross@Sun.COM 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
117610023SGordon.Ross@Sun.COM 
11776007Sthurlow 	return (fd);
11786007Sthurlow }
11796007Sthurlow 
118010023SGordon.Ross@Sun.COM int
smb_ctx_gethandle(struct smb_ctx * ctx)11816007Sthurlow smb_ctx_gethandle(struct smb_ctx *ctx)
11826007Sthurlow {
118310023SGordon.Ross@Sun.COM 	int fd;
11846007Sthurlow 
118510023SGordon.Ross@Sun.COM 	if (ctx->ct_dev_fd != -1) {
11866007Sthurlow 		rpc_cleanup_smbctx(ctx);
118710023SGordon.Ross@Sun.COM 		close(ctx->ct_dev_fd);
118810023SGordon.Ross@Sun.COM 		ctx->ct_dev_fd = -1;
11896007Sthurlow 		ctx->ct_flags &= ~SMBCF_SSNACTIVE;
11906007Sthurlow 	}
11916007Sthurlow 
11926007Sthurlow 	fd = smb_open_driver();
11936007Sthurlow 	if (fd < 0)
11946007Sthurlow 		return (ENODEV);
11956007Sthurlow 
119610023SGordon.Ross@Sun.COM 	ctx->ct_dev_fd = fd;
11976007Sthurlow 	return (0);
11986007Sthurlow }
11996007Sthurlow 
12006007Sthurlow 
12016007Sthurlow /*
120210023SGordon.Ross@Sun.COM  * Find or create a connection + logon session
12036007Sthurlow  */
120410023SGordon.Ross@Sun.COM int
smb_ctx_get_ssn(struct smb_ctx * ctx)120510023SGordon.Ross@Sun.COM smb_ctx_get_ssn(struct smb_ctx *ctx)
12066007Sthurlow {
120710023SGordon.Ross@Sun.COM 	int err = 0;
12086007Sthurlow 
120910023SGordon.Ross@Sun.COM 	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
121010023SGordon.Ross@Sun.COM 		return (EINVAL);
12116007Sthurlow 
121210023SGordon.Ross@Sun.COM 	if (ctx->ct_dev_fd < 0) {
121310023SGordon.Ross@Sun.COM 		if ((err = smb_ctx_gethandle(ctx)))
121410023SGordon.Ross@Sun.COM 			return (err);
12156007Sthurlow 	}
12166007Sthurlow 
12176007Sthurlow 	/*
121810023SGordon.Ross@Sun.COM 	 * Check whether the driver already has a VC
121910023SGordon.Ross@Sun.COM 	 * we can use.  If so, we're done!
12206007Sthurlow 	 */
122110023SGordon.Ross@Sun.COM 	err = smb_ctx_findvc(ctx);
122210023SGordon.Ross@Sun.COM 	if (err == 0) {
122310023SGordon.Ross@Sun.COM 		DPRINT("found an existing VC");
122410023SGordon.Ross@Sun.COM 	} else {
122510023SGordon.Ross@Sun.COM 		/*
122610023SGordon.Ross@Sun.COM 		 * This calls the IOD to create a new session.
122710023SGordon.Ross@Sun.COM 		 */
122810023SGordon.Ross@Sun.COM 		DPRINT("setup a new VC");
122910023SGordon.Ross@Sun.COM 		err = smb_ctx_newvc(ctx);
123010023SGordon.Ross@Sun.COM 		if (err != 0)
123110023SGordon.Ross@Sun.COM 			return (err);
123210023SGordon.Ross@Sun.COM 
123310023SGordon.Ross@Sun.COM 		/*
123410023SGordon.Ross@Sun.COM 		 * Call findvc again.  The new VC sould be
123510023SGordon.Ross@Sun.COM 		 * found in the driver this time.
123610023SGordon.Ross@Sun.COM 		 */
123710023SGordon.Ross@Sun.COM 		err = smb_ctx_findvc(ctx);
12386007Sthurlow 	}
12396007Sthurlow 
124010023SGordon.Ross@Sun.COM 	return (err);
12416007Sthurlow }
12426007Sthurlow 
124310023SGordon.Ross@Sun.COM /*
124410023SGordon.Ross@Sun.COM  * Get the string representation of a share "use" type,
124510023SGordon.Ross@Sun.COM  * as needed for the "service" in tree connect.
124610023SGordon.Ross@Sun.COM  */
124710023SGordon.Ross@Sun.COM static const char *
smb_use_type_str(smb_use_shtype_t stype)124810023SGordon.Ross@Sun.COM smb_use_type_str(smb_use_shtype_t stype)
12496007Sthurlow {
125010023SGordon.Ross@Sun.COM 	const char *pp;
12516007Sthurlow 
125210023SGordon.Ross@Sun.COM 	switch (stype) {
125310023SGordon.Ross@Sun.COM 	default:
125410023SGordon.Ross@Sun.COM 	case USE_WILDCARD:
125510023SGordon.Ross@Sun.COM 		pp = "?????";
125610023SGordon.Ross@Sun.COM 		break;
125710023SGordon.Ross@Sun.COM 	case USE_DISKDEV:
125810023SGordon.Ross@Sun.COM 		pp = "A:";
125910023SGordon.Ross@Sun.COM 		break;
126010023SGordon.Ross@Sun.COM 	case USE_SPOOLDEV:
126110023SGordon.Ross@Sun.COM 		pp = "LPT1:";
126210023SGordon.Ross@Sun.COM 		break;
126310023SGordon.Ross@Sun.COM 	case USE_CHARDEV:
126410023SGordon.Ross@Sun.COM 		pp = "COMM";
126510023SGordon.Ross@Sun.COM 		break;
126610023SGordon.Ross@Sun.COM 	case USE_IPC:
126710023SGordon.Ross@Sun.COM 		pp = "IPC";
126810023SGordon.Ross@Sun.COM 		break;
12696007Sthurlow 	}
127010023SGordon.Ross@Sun.COM 	return (pp);
12716007Sthurlow }
12726007Sthurlow 
12736007Sthurlow /*
127410023SGordon.Ross@Sun.COM  * Find or create a tree connection
12756007Sthurlow  */
127610023SGordon.Ross@Sun.COM int
smb_ctx_get_tree(struct smb_ctx * ctx)127710023SGordon.Ross@Sun.COM smb_ctx_get_tree(struct smb_ctx *ctx)
12786007Sthurlow {
127910023SGordon.Ross@Sun.COM 	smbioc_tcon_t *tcon = NULL;
128010023SGordon.Ross@Sun.COM 	const char *stype;
128110023SGordon.Ross@Sun.COM 	int cmd, err = 0;
12826007Sthurlow 
128310023SGordon.Ross@Sun.COM 	if (ctx->ct_dev_fd < 0 ||
128410023SGordon.Ross@Sun.COM 	    ctx->ct_origshare == NULL) {
128510023SGordon.Ross@Sun.COM 		return (EINVAL);
128610023SGordon.Ross@Sun.COM 	}
12876007Sthurlow 
128810023SGordon.Ross@Sun.COM 	cmd = SMBIOC_TREE_CONNECT;
128910023SGordon.Ross@Sun.COM 	tcon = malloc(sizeof (*tcon));
129010023SGordon.Ross@Sun.COM 	if (tcon == NULL)
129110023SGordon.Ross@Sun.COM 		return (ENOMEM);
129210023SGordon.Ross@Sun.COM 	bzero(tcon, sizeof (*tcon));
129310023SGordon.Ross@Sun.COM 	tcon->tc_flags = SMBLK_CREATE;
129410023SGordon.Ross@Sun.COM 	tcon->tc_opt = 0;
12956007Sthurlow 
129610023SGordon.Ross@Sun.COM 	/* The share name */
129710023SGordon.Ross@Sun.COM 	strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
129810023SGordon.Ross@Sun.COM 	    sizeof (tcon->tc_sh.sh_name));
12996007Sthurlow 
130012019SGordon.Ross@Sun.COM 	/*
130112019SGordon.Ross@Sun.COM 	 * Share password (unused - no share-level security)
130212019SGordon.Ross@Sun.COM 	 * MS-SMB 2.2.6 says this should be null terminated,
130312019SGordon.Ross@Sun.COM 	 * and the length includes the null.  Did bzero above,
130412019SGordon.Ross@Sun.COM 	 * so just set length for the null.
130512019SGordon.Ross@Sun.COM 	 */
130612019SGordon.Ross@Sun.COM 	tcon->tc_sh.sh_pwlen = 1;
130712019SGordon.Ross@Sun.COM 
130810023SGordon.Ross@Sun.COM 	/* The share "use" type. */
130910023SGordon.Ross@Sun.COM 	stype = smb_use_type_str(ctx->ct_shtype_req);
131010023SGordon.Ross@Sun.COM 	strlcpy(tcon->tc_sh.sh_type_req, stype,
131110023SGordon.Ross@Sun.COM 	    sizeof (tcon->tc_sh.sh_type_req));
13126007Sthurlow 
13136007Sthurlow 	/*
131410023SGordon.Ross@Sun.COM 	 * Todo: share passwords for share-level security.
131510023SGordon.Ross@Sun.COM 	 *
131610023SGordon.Ross@Sun.COM 	 * The driver does the actual TCON call.
13176007Sthurlow 	 */
131810023SGordon.Ross@Sun.COM 	if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
131910023SGordon.Ross@Sun.COM 		err = errno;
13206007Sthurlow 		goto out;
13216007Sthurlow 	}
13226007Sthurlow 
13236007Sthurlow 	/*
132410023SGordon.Ross@Sun.COM 	 * Check the returned share type
13256007Sthurlow 	 */
132610023SGordon.Ross@Sun.COM 	DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret);
132710023SGordon.Ross@Sun.COM 	if (ctx->ct_shtype_req != USE_WILDCARD &&
132810023SGordon.Ross@Sun.COM 	    0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) {
13296007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
133010023SGordon.Ross@Sun.COM 		    "%s: incompatible share type"),
133110023SGordon.Ross@Sun.COM 		    0, ctx->ct_origshare);
133210023SGordon.Ross@Sun.COM 		err = EINVAL;
13336007Sthurlow 	}
13346007Sthurlow 
13356007Sthurlow out:
133610023SGordon.Ross@Sun.COM 	if (tcon != NULL)
133710023SGordon.Ross@Sun.COM 		free(tcon);
133810023SGordon.Ross@Sun.COM 
133910023SGordon.Ross@Sun.COM 	return (err);
13406007Sthurlow }
13416007Sthurlow 
13426007Sthurlow /*
13436007Sthurlow  * Return the hflags2 word for an smb_ctx.
13446007Sthurlow  */
13456007Sthurlow int
smb_ctx_flags2(struct smb_ctx * ctx)13466007Sthurlow smb_ctx_flags2(struct smb_ctx *ctx)
13476007Sthurlow {
13486007Sthurlow 	uint16_t flags2;
13496007Sthurlow 
135010023SGordon.Ross@Sun.COM 	if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
13516007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
13526007Sthurlow 		    "can't get flags2 for a session"), errno);
13536007Sthurlow 		return (-1);
13546007Sthurlow 	}
13556007Sthurlow 	return (flags2);
13566007Sthurlow }
13576007Sthurlow 
13586007Sthurlow /*
135910023SGordon.Ross@Sun.COM  * Get the transport level session key.
136010023SGordon.Ross@Sun.COM  * Must already have an active SMB session.
136110023SGordon.Ross@Sun.COM  */
136210023SGordon.Ross@Sun.COM int
smb_ctx_get_ssnkey(struct smb_ctx * ctx,uchar_t * key,size_t len)136310023SGordon.Ross@Sun.COM smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len)
136410023SGordon.Ross@Sun.COM {
136510023SGordon.Ross@Sun.COM 	if (len < SMBIOC_HASH_SZ)
136610023SGordon.Ross@Sun.COM 		return (EINVAL);
136710023SGordon.Ross@Sun.COM 
136810023SGordon.Ross@Sun.COM 	if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1)
136910023SGordon.Ross@Sun.COM 		return (errno);
137010023SGordon.Ross@Sun.COM 
137110023SGordon.Ross@Sun.COM 	return (0);
137210023SGordon.Ross@Sun.COM }
137310023SGordon.Ross@Sun.COM 
137410023SGordon.Ross@Sun.COM /*
137510023SGordon.Ross@Sun.COM  * RC file parsing stuff
137610023SGordon.Ross@Sun.COM  */
137710023SGordon.Ross@Sun.COM 
137812140SGordon.Ross@Sun.COM static struct nv
137912140SGordon.Ross@Sun.COM minauth_table[] = {
138010023SGordon.Ross@Sun.COM 	/* Allowed auth. types */
138110023SGordon.Ross@Sun.COM 	{ "kerberos",	SMB_AT_KRB5 },
138210023SGordon.Ross@Sun.COM 	{ "ntlmv2",	SMB_AT_KRB5|SMB_AT_NTLM2 },
138310023SGordon.Ross@Sun.COM 	{ "ntlm",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
138410023SGordon.Ross@Sun.COM 	{ "lm",		SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
138510023SGordon.Ross@Sun.COM 	{ "none",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
138610023SGordon.Ross@Sun.COM 			SMB_AT_ANON },
138710023SGordon.Ross@Sun.COM 	{ NULL }
138810023SGordon.Ross@Sun.COM };
138910023SGordon.Ross@Sun.COM 
139010023SGordon.Ross@Sun.COM 
139110023SGordon.Ross@Sun.COM /*
13926007Sthurlow  * level values:
13936007Sthurlow  * 0 - default
13946007Sthurlow  * 1 - server
13956007Sthurlow  * 2 - server:user
13966007Sthurlow  * 3 - server:user:share
13976007Sthurlow  */
13986007Sthurlow static int
smb_ctx_readrcsection(struct smb_ctx * ctx,const char * sname,int level)13996007Sthurlow smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
14006007Sthurlow {
14016007Sthurlow 	char *p;
14026007Sthurlow 	int error;
14036007Sthurlow 
140410023SGordon.Ross@Sun.COM #ifdef	KICONV_SUPPORT
14056007Sthurlow 	if (level > 0) {
14066007Sthurlow 		rc_getstringptr(smb_rc, sname, "charsets", &p);
14076007Sthurlow 		if (p) {
14086007Sthurlow 			error = smb_ctx_setcharset(ctx, p);
14096007Sthurlow 			if (error)
14106007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14116007Sthurlow 	"charset specification in the section '%s' ignored"),
14126007Sthurlow 				    error, sname);
14136007Sthurlow 		}
14146007Sthurlow 	}
14156007Sthurlow #endif
14166007Sthurlow 
14176007Sthurlow 	if (level <= 1) {
14186007Sthurlow 		/* Section is: [default] or [server] */
14196007Sthurlow 
14206007Sthurlow 		rc_getstringptr(smb_rc, sname, "minauth", &p);
14216007Sthurlow 		if (p) {
14226007Sthurlow 			/*
14236007Sthurlow 			 * "minauth" was set in this section; override
14246007Sthurlow 			 * the current minimum authentication setting.
14256007Sthurlow 			 */
142610023SGordon.Ross@Sun.COM 			struct nv *nvp;
142710023SGordon.Ross@Sun.COM 			for (nvp = minauth_table; nvp->name; nvp++)
142810023SGordon.Ross@Sun.COM 				if (strcmp(p, nvp->name) == 0)
142910023SGordon.Ross@Sun.COM 					break;
143010023SGordon.Ross@Sun.COM 			if (nvp->name)
143110023SGordon.Ross@Sun.COM 				ctx->ct_minauth = nvp->value;
143210023SGordon.Ross@Sun.COM 			else {
14336007Sthurlow 				/*
14346007Sthurlow 				 * Unknown minimum authentication level.
14356007Sthurlow 				 */
14366007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14376007Sthurlow "invalid minimum authentication level \"%s\" specified in the section %s"),
14386007Sthurlow 				    0, p, sname);
14396007Sthurlow 				return (EINVAL);
14406007Sthurlow 			}
14416007Sthurlow 		}
14426007Sthurlow 
14438271SGordon.Ross@Sun.COM 		rc_getstringptr(smb_rc, sname, "signing", &p);
14448271SGordon.Ross@Sun.COM 		if (p) {
14458271SGordon.Ross@Sun.COM 			/*
14468271SGordon.Ross@Sun.COM 			 * "signing" was set in this section; override
144711332SGordon.Ross@Sun.COM 			 * the current signing settings.  Note:
144811332SGordon.Ross@Sun.COM 			 * setsigning flags are: enable, require
14498271SGordon.Ross@Sun.COM 			 */
14508271SGordon.Ross@Sun.COM 			if (strcmp(p, "disabled") == 0) {
145111332SGordon.Ross@Sun.COM 				(void) smb_ctx_setsigning(ctx, FALSE, FALSE);
14528271SGordon.Ross@Sun.COM 			} else if (strcmp(p, "enabled") == 0) {
145311332SGordon.Ross@Sun.COM 				(void) smb_ctx_setsigning(ctx, TRUE, FALSE);
14548271SGordon.Ross@Sun.COM 			} else if (strcmp(p, "required") == 0) {
145511332SGordon.Ross@Sun.COM 				(void) smb_ctx_setsigning(ctx, TRUE, TRUE);
14568271SGordon.Ross@Sun.COM 			} else {
14578271SGordon.Ross@Sun.COM 				/*
14588271SGordon.Ross@Sun.COM 				 * Unknown "signing" value.
14598271SGordon.Ross@Sun.COM 				 */
14608271SGordon.Ross@Sun.COM 				smb_error(dgettext(TEXT_DOMAIN,
14618271SGordon.Ross@Sun.COM "invalid signing policy \"%s\" specified in the section %s"),
14628271SGordon.Ross@Sun.COM 				    0, p, sname);
14638271SGordon.Ross@Sun.COM 				return (EINVAL);
14648271SGordon.Ross@Sun.COM 			}
14658271SGordon.Ross@Sun.COM 		}
14668271SGordon.Ross@Sun.COM 
14676007Sthurlow 		/*
14686007Sthurlow 		 * Domain name.  Allow both keywords:
14696007Sthurlow 		 * "workgroup", "domain"
14706007Sthurlow 		 *
14716007Sthurlow 		 * Note: these are NOT marked "from CMD".
14726007Sthurlow 		 * See long comment at smb_ctx_init()
14736007Sthurlow 		 */
14746007Sthurlow 		rc_getstringptr(smb_rc, sname, "workgroup", &p);
14756007Sthurlow 		if (p) {
147610023SGordon.Ross@Sun.COM 			error = smb_ctx_setdomain(ctx, p, 0);
14776007Sthurlow 			if (error)
14786007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14796007Sthurlow 				    "workgroup specification in the "
14806007Sthurlow 				    "section '%s' ignored"), error, sname);
14816007Sthurlow 		}
14826007Sthurlow 		rc_getstringptr(smb_rc, sname, "domain", &p);
14836007Sthurlow 		if (p) {
148410023SGordon.Ross@Sun.COM 			error = smb_ctx_setdomain(ctx, p, 0);
14856007Sthurlow 			if (error)
14866007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14876007Sthurlow 				    "domain specification in the "
14886007Sthurlow 				    "section '%s' ignored"), error, sname);
14896007Sthurlow 		}
14906007Sthurlow 
14916007Sthurlow 		rc_getstringptr(smb_rc, sname, "user", &p);
14926007Sthurlow 		if (p) {
14936007Sthurlow 			error = smb_ctx_setuser(ctx, p, 0);
14946007Sthurlow 			if (error)
14956007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14966007Sthurlow 				    "user specification in the "
14976007Sthurlow 				    "section '%s' ignored"), error, sname);
14986007Sthurlow 		}
14996007Sthurlow 	}
15006007Sthurlow 
15016007Sthurlow 	if (level == 1) {
15026007Sthurlow 		/* Section is: [server] */
15036007Sthurlow 		rc_getstringptr(smb_rc, sname, "addr", &p);
15046007Sthurlow 		if (p) {
15056007Sthurlow 			error = smb_ctx_setsrvaddr(ctx, p);
15066007Sthurlow 			if (error) {
15076007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
15086007Sthurlow 				    "invalid address specified in section %s"),
15096007Sthurlow 				    0, sname);
15106007Sthurlow 				return (error);
15116007Sthurlow 			}
15126007Sthurlow 		}
15136007Sthurlow 	}
15146007Sthurlow 
15156007Sthurlow 	rc_getstringptr(smb_rc, sname, "password", &p);
15166007Sthurlow 	if (p) {
15176007Sthurlow 		error = smb_ctx_setpassword(ctx, p, 0);
15186007Sthurlow 		if (error)
15196007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
15206007Sthurlow 	    "password specification in the section '%s' ignored"),
15216007Sthurlow 			    error, sname);
15226007Sthurlow 	}
15236007Sthurlow 
15246007Sthurlow 	return (0);
15256007Sthurlow }
15266007Sthurlow 
15276007Sthurlow /*
15286007Sthurlow  * read rc file as follows:
15296007Sthurlow  * 0: read [default] section
15306007Sthurlow  * 1: override with [server] section
15316007Sthurlow  * 2: override with [server:user] section
15326007Sthurlow  * 3: override with [server:user:share] section
15336007Sthurlow  * Since absence of rcfile is not fatal, silently ignore this fact.
15346007Sthurlow  * smb_rc file should be closed by caller.
15356007Sthurlow  */
15366007Sthurlow int
smb_ctx_readrc(struct smb_ctx * ctx)15376007Sthurlow smb_ctx_readrc(struct smb_ctx *ctx)
15386007Sthurlow {
153910023SGordon.Ross@Sun.COM 	char *home;
154010023SGordon.Ross@Sun.COM 	char *sname = NULL;
154110023SGordon.Ross@Sun.COM 	int sname_max;
154210023SGordon.Ross@Sun.COM 	int err = 0;
15436007Sthurlow 
154410023SGordon.Ross@Sun.COM 	if ((home = getenv("HOME")) == NULL)
154510023SGordon.Ross@Sun.COM 		home = ctx->ct_home;
154610023SGordon.Ross@Sun.COM 	if ((err = smb_open_rcfile(home)) != 0) {
154710023SGordon.Ross@Sun.COM 		DPRINT("smb_open_rcfile, err=%d", err);
154810023SGordon.Ross@Sun.COM 		/* ignore any error here */
154910023SGordon.Ross@Sun.COM 		return (0);
155010023SGordon.Ross@Sun.COM 	}
155110023SGordon.Ross@Sun.COM 
155210023SGordon.Ross@Sun.COM 	sname_max = 3 * SMBIOC_MAX_NAME + 4;
155310023SGordon.Ross@Sun.COM 	sname = malloc(sname_max);
155410023SGordon.Ross@Sun.COM 	if (sname == NULL) {
155510023SGordon.Ross@Sun.COM 		err = ENOMEM;
15566007Sthurlow 		goto done;
155710023SGordon.Ross@Sun.COM 	}
15586007Sthurlow 
15596007Sthurlow 	/*
15606007Sthurlow 	 * default parameters (level=0)
15616007Sthurlow 	 */
15626007Sthurlow 	smb_ctx_readrcsection(ctx, "default", 0);
15636007Sthurlow 	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
15646007Sthurlow 
15656007Sthurlow 	/*
15666007Sthurlow 	 * If we don't have a server name, we can't read any of the
15676007Sthurlow 	 * [server...] sections.
15686007Sthurlow 	 */
156910023SGordon.Ross@Sun.COM 	if (ctx->ct_fullserver == NULL)
15706007Sthurlow 		goto done;
15716007Sthurlow 	/*
15726007Sthurlow 	 * SERVER parameters.
15736007Sthurlow 	 */
157410023SGordon.Ross@Sun.COM 	smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
15756007Sthurlow 
15766007Sthurlow 	/*
15776007Sthurlow 	 * If we don't have a user name, we can't read any of the
15786007Sthurlow 	 * [server:user...] sections.
15796007Sthurlow 	 */
158010023SGordon.Ross@Sun.COM 	if (ctx->ct_user[0] == 0)
15816007Sthurlow 		goto done;
15826007Sthurlow 	/*
15836007Sthurlow 	 * SERVER:USER parameters
15846007Sthurlow 	 */
158510023SGordon.Ross@Sun.COM 	snprintf(sname, sname_max, "%s:%s",
158610023SGordon.Ross@Sun.COM 	    ctx->ct_fullserver,
158710023SGordon.Ross@Sun.COM 	    ctx->ct_user);
15886007Sthurlow 	smb_ctx_readrcsection(ctx, sname, 2);
15896007Sthurlow 
159010023SGordon.Ross@Sun.COM 
15916007Sthurlow 	/*
15926007Sthurlow 	 * If we don't have a share name, we can't read any of the
15936007Sthurlow 	 * [server:user:share] sections.
15946007Sthurlow 	 */
159510023SGordon.Ross@Sun.COM 	if (ctx->ct_origshare == NULL)
159610023SGordon.Ross@Sun.COM 		goto done;
159710023SGordon.Ross@Sun.COM 	/*
159810023SGordon.Ross@Sun.COM 	 * SERVER:USER:SHARE parameters
159910023SGordon.Ross@Sun.COM 	 */
160010023SGordon.Ross@Sun.COM 	snprintf(sname, sname_max, "%s:%s:%s",
160110023SGordon.Ross@Sun.COM 	    ctx->ct_fullserver,
160210023SGordon.Ross@Sun.COM 	    ctx->ct_user,
160310023SGordon.Ross@Sun.COM 	    ctx->ct_origshare);
160410023SGordon.Ross@Sun.COM 	smb_ctx_readrcsection(ctx, sname, 3);
16056007Sthurlow 
16066007Sthurlow done:
160710023SGordon.Ross@Sun.COM 	if (sname)
160810023SGordon.Ross@Sun.COM 		free(sname);
160910023SGordon.Ross@Sun.COM 	smb_close_rcfile();
16106007Sthurlow 	if (smb_debug)
16116007Sthurlow 		dump_ctx("after smb_ctx_readrc", ctx);
161210023SGordon.Ross@Sun.COM 	if (err)
161310023SGordon.Ross@Sun.COM 		DPRINT("err=%d\n", err);
16146007Sthurlow 
161510023SGordon.Ross@Sun.COM 	return (err);
16166007Sthurlow }
1617