xref: /illumos-gate/usr/src/lib/libsmbfs/smb/ctx.c (revision 686670eacbe137c7a9e6c85fef8763f8627a27b5)
14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000, Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
359c9af259SGordon Ross /*
3615359501SGordon Ross  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
3740c0e231SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
389c9af259SGordon Ross  */
394bff34e3Sthurlow 
404bff34e3Sthurlow #include <sys/param.h>
414bff34e3Sthurlow #include <sys/ioctl.h>
424bff34e3Sthurlow #include <sys/time.h>
434bff34e3Sthurlow #include <sys/mount.h>
444bff34e3Sthurlow #include <sys/types.h>
454bff34e3Sthurlow #include <sys/byteorder.h>
464bff34e3Sthurlow 
474bff34e3Sthurlow #include <fcntl.h>
484bff34e3Sthurlow #include <ctype.h>
494bff34e3Sthurlow #include <errno.h>
504bff34e3Sthurlow #include <stdio.h>
514bff34e3Sthurlow #include <string.h>
524bff34e3Sthurlow #include <strings.h>
534bff34e3Sthurlow #include <stdlib.h>
544bff34e3Sthurlow #include <pwd.h>
554bff34e3Sthurlow #include <grp.h>
564bff34e3Sthurlow #include <unistd.h>
574bff34e3Sthurlow #include <libintl.h>
584bff34e3Sthurlow #include <assert.h>
594bff34e3Sthurlow #include <nss_dbdefs.h>
604bff34e3Sthurlow 
61613a2f6bSGordon Ross #include <cflib.h>
624bff34e3Sthurlow #include <netsmb/smb_lib.h>
634bff34e3Sthurlow #include <netsmb/netbios.h>
644bff34e3Sthurlow #include <netsmb/nb_lib.h>
654bff34e3Sthurlow #include <netsmb/smb_dev.h>
664bff34e3Sthurlow 
67613a2f6bSGordon Ross #include "charsets.h"
689c9af259SGordon Ross #include "private.h"
69613a2f6bSGordon Ross #include "ntlm.h"
704bff34e3Sthurlow 
71613a2f6bSGordon Ross #ifndef FALSE
72613a2f6bSGordon Ross #define	FALSE	0
73613a2f6bSGordon Ross #endif
74613a2f6bSGordon Ross #ifndef TRUE
75613a2f6bSGordon Ross #define	TRUE	1
76613a2f6bSGordon Ross #endif
774bff34e3Sthurlow 
78fd75ca8dSGordon Ross #define	SMB_AT_DEFAULT	(SMB_AT_KRB5 | SMB_AT_NTLM2)
79fd75ca8dSGordon Ross #define	SMB_AT_MINAUTH	(SMB_AT_KRB5 | SMB_AT_NTLM2 | SMB_AT_NTLM1)
80fd75ca8dSGordon Ross 
8115359501SGordon Ross struct nv {
8215359501SGordon Ross 	char *name;
8315359501SGordon Ross 	int value;
8415359501SGordon Ross };
854bff34e3Sthurlow 
864bff34e3Sthurlow /* These two may be set by commands. */
874bff34e3Sthurlow int smb_debug, smb_verbose;
884bff34e3Sthurlow 
894bff34e3Sthurlow /*
90613a2f6bSGordon Ross  * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
91613a2f6bSGordon Ross  */
92613a2f6bSGordon Ross const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
93613a2f6bSGordon Ross 
94613a2f6bSGordon Ross /*
95430b4c46SGordon Ross  * Defaults for new contexts (connections to servers).
96430b4c46SGordon Ross  * These are set by smbfs_set_default_...
97430b4c46SGordon Ross  */
98430b4c46SGordon Ross static char default_domain[SMBIOC_MAX_NAME];
99430b4c46SGordon Ross static char default_user[SMBIOC_MAX_NAME];
100430b4c46SGordon Ross 
101430b4c46SGordon Ross 
102430b4c46SGordon Ross /*
1039c9af259SGordon Ross  * Give the RPC library a callback hook that will be
1049c9af259SGordon Ross  * called whenever we destroy or reinit an smb_ctx_t.
1059c9af259SGordon Ross  * The name rpc_cleanup_smbctx() is legacy, and was
1069c9af259SGordon Ross  * originally a direct call into the RPC code.
1074bff34e3Sthurlow  */
1089c9af259SGordon Ross static smb_ctx_close_hook_t close_hook;
1094bff34e3Sthurlow static void
rpc_cleanup_smbctx(struct smb_ctx * ctx)1104bff34e3Sthurlow rpc_cleanup_smbctx(struct smb_ctx *ctx)
1114bff34e3Sthurlow {
1129c9af259SGordon Ross 	if (close_hook)
1139c9af259SGordon Ross 		(*close_hook)(ctx);
1144bff34e3Sthurlow }
1159c9af259SGordon Ross void
smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)1169c9af259SGordon Ross smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
1179c9af259SGordon Ross {
1189c9af259SGordon Ross 	close_hook = hook;
1199c9af259SGordon Ross }
1204bff34e3Sthurlow 
1214bff34e3Sthurlow void
dump_ctx_flags(int flags)1224bff34e3Sthurlow dump_ctx_flags(int flags)
1234bff34e3Sthurlow {
1244bff34e3Sthurlow 	printf(" Flags: ");
1254bff34e3Sthurlow 	if (flags == 0)
1264bff34e3Sthurlow 		printf("0");
1274bff34e3Sthurlow 	if (flags & SMBCF_NOPWD)
1284bff34e3Sthurlow 		printf("NOPWD ");
1294bff34e3Sthurlow 	if (flags & SMBCF_SRIGHTS)
1304bff34e3Sthurlow 		printf("SRIGHTS ");
1314bff34e3Sthurlow 	if (flags & SMBCF_LOCALE)
1324bff34e3Sthurlow 		printf("LOCALE ");
1334bff34e3Sthurlow 	if (flags & SMBCF_CMD_DOM)
1344bff34e3Sthurlow 		printf("CMD_DOM ");
1354bff34e3Sthurlow 	if (flags & SMBCF_CMD_USR)
1364bff34e3Sthurlow 		printf("CMD_USR ");
1374bff34e3Sthurlow 	if (flags & SMBCF_CMD_PW)
1384bff34e3Sthurlow 		printf("CMD_PW ");
1394bff34e3Sthurlow 	if (flags & SMBCF_RESOLVED)
1404bff34e3Sthurlow 		printf("RESOLVED ");
1414bff34e3Sthurlow 	if (flags & SMBCF_KCBAD)
1424bff34e3Sthurlow 		printf("KCBAD ");
1434bff34e3Sthurlow 	if (flags & SMBCF_KCFOUND)
1444bff34e3Sthurlow 		printf("KCFOUND ");
1454bff34e3Sthurlow 	if (flags & SMBCF_BROWSEOK)
1464bff34e3Sthurlow 		printf("BROWSEOK ");
1474bff34e3Sthurlow 	if (flags & SMBCF_AUTHREQ)
1484bff34e3Sthurlow 		printf("AUTHREQ ");
1494bff34e3Sthurlow 	if (flags & SMBCF_KCSAVE)
1504bff34e3Sthurlow 		printf("KCSAVE  ");
1514bff34e3Sthurlow 	if (flags & SMBCF_KCDOMAIN)
1524bff34e3Sthurlow 		printf("KCDOMAIN ");
1534bff34e3Sthurlow 	printf("\n");
1544bff34e3Sthurlow }
1554bff34e3Sthurlow 
1564bff34e3Sthurlow void
dump_iod_ssn(smb_iod_ssn_t * is)157613a2f6bSGordon Ross dump_iod_ssn(smb_iod_ssn_t *is)
1584bff34e3Sthurlow {
159613a2f6bSGordon Ross 	static const char zeros[NTLM_HASH_SZ] = {0};
160613a2f6bSGordon Ross 	struct smbioc_ossn *ssn = &is->iod_ossn;
1614bff34e3Sthurlow 
162613a2f6bSGordon Ross 	printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
163613a2f6bSGordon Ross 	dump_sockaddr(&ssn->ssn_srvaddr.sa);
164613a2f6bSGordon Ross 	printf(" dom=\"%s\", user=\"%s\"\n",
165613a2f6bSGordon Ross 	    ssn->ssn_domain, ssn->ssn_user);
166613a2f6bSGordon Ross 	printf(" ct_vopt=0x%x, ct_owner=%d\n",
167613a2f6bSGordon Ross 	    ssn->ssn_vopt, ssn->ssn_owner);
168adee6784SGordon Ross 	printf(" ct_minver=0x%x, ct_maxver=0x%x\n",
169adee6784SGordon Ross 	    ssn->ssn_minver, ssn->ssn_maxver);
170613a2f6bSGordon Ross 	printf(" ct_authflags=0x%x\n", is->iod_authflags);
171613a2f6bSGordon Ross 
172613a2f6bSGordon Ross 	printf(" ct_nthash:");
173613a2f6bSGordon Ross 	if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
174613a2f6bSGordon Ross 		smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
175613a2f6bSGordon Ross 	else
176613a2f6bSGordon Ross 		printf(" {0}\n");
177613a2f6bSGordon Ross 
178613a2f6bSGordon Ross 	printf(" ct_lmhash:");
179613a2f6bSGordon Ross 	if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
180613a2f6bSGordon Ross 		smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
181613a2f6bSGordon Ross 	else
182613a2f6bSGordon Ross 		printf(" {0}\n");
1834bff34e3Sthurlow }
1844bff34e3Sthurlow 
1854bff34e3Sthurlow void
dump_ctx(char * where,struct smb_ctx * ctx)1864bff34e3Sthurlow dump_ctx(char *where, struct smb_ctx *ctx)
1874bff34e3Sthurlow {
1884bff34e3Sthurlow 	printf("context %s:\n", where);
1894bff34e3Sthurlow 	dump_ctx_flags(ctx->ct_flags);
1904bff34e3Sthurlow 
191613a2f6bSGordon Ross 	if (ctx->ct_locname)
1924bff34e3Sthurlow 		printf(" localname=\"%s\"", ctx->ct_locname);
193613a2f6bSGordon Ross 	else
194613a2f6bSGordon Ross 		printf(" localname=NULL");
1954bff34e3Sthurlow 
1964bff34e3Sthurlow 	if (ctx->ct_fullserver)
1974bff34e3Sthurlow 		printf(" fullserver=\"%s\"", ctx->ct_fullserver);
1984bff34e3Sthurlow 	else
1994bff34e3Sthurlow 		printf(" fullserver=NULL");
2004bff34e3Sthurlow 
201613a2f6bSGordon Ross 	if (ctx->ct_srvaddr_s)
202613a2f6bSGordon Ross 		printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
2034bff34e3Sthurlow 	else
204613a2f6bSGordon Ross 		printf(" srvaddr_s=NULL\n");
2054bff34e3Sthurlow 
206613a2f6bSGordon Ross 	if (ctx->ct_addrinfo)
207613a2f6bSGordon Ross 		dump_addrinfo(ctx->ct_addrinfo);
208613a2f6bSGordon Ross 	else
209613a2f6bSGordon Ross 		printf(" ct_addrinfo = NULL\n");
210613a2f6bSGordon Ross 
211613a2f6bSGordon Ross 	dump_iod_ssn(&ctx->ct_iod_ssn);
212613a2f6bSGordon Ross 
213613a2f6bSGordon Ross 	printf(" share_name=\"%s\", share_type=%d\n",
214613a2f6bSGordon Ross 	    ctx->ct_origshare ? ctx->ct_origshare : "",
215613a2f6bSGordon Ross 	    ctx->ct_shtype_req);
216613a2f6bSGordon Ross 
217430b4c46SGordon Ross 	printf(" ct_home=\"%s\"\n", ctx->ct_home);
218430b4c46SGordon Ross 	printf(" ct_rpath=\"%s\"\n", ctx->ct_rpath);
219613a2f6bSGordon Ross }
220613a2f6bSGordon Ross 
221613a2f6bSGordon Ross int
smb_ctx_alloc(struct smb_ctx ** ctx_pp)222613a2f6bSGordon Ross smb_ctx_alloc(struct smb_ctx **ctx_pp)
223613a2f6bSGordon Ross {
224613a2f6bSGordon Ross 	smb_ctx_t *ctx;
225613a2f6bSGordon Ross 	int err;
226613a2f6bSGordon Ross 
227613a2f6bSGordon Ross 	ctx = malloc(sizeof (*ctx));
228613a2f6bSGordon Ross 	if (ctx == NULL)
229613a2f6bSGordon Ross 		return (ENOMEM);
230613a2f6bSGordon Ross 	err = smb_ctx_init(ctx);
231613a2f6bSGordon Ross 	if (err != 0) {
232613a2f6bSGordon Ross 		free(ctx);
233613a2f6bSGordon Ross 		return (err);
234613a2f6bSGordon Ross 	}
235613a2f6bSGordon Ross 	*ctx_pp = ctx;
236613a2f6bSGordon Ross 	return (0);
2374bff34e3Sthurlow }
2384bff34e3Sthurlow 
2394bff34e3Sthurlow /*
240613a2f6bSGordon Ross  * Initialize an smb_ctx struct (defaults)
241613a2f6bSGordon Ross  */
242613a2f6bSGordon Ross int
smb_ctx_init(struct smb_ctx * ctx)243613a2f6bSGordon Ross smb_ctx_init(struct smb_ctx *ctx)
244613a2f6bSGordon Ross {
245430b4c46SGordon Ross 	int error;
246613a2f6bSGordon Ross 
247613a2f6bSGordon Ross 	bzero(ctx, sizeof (*ctx));
248613a2f6bSGordon Ross 
249613a2f6bSGordon Ross 	error = nb_ctx_create(&ctx->ct_nb);
250613a2f6bSGordon Ross 	if (error)
251613a2f6bSGordon Ross 		return (error);
252613a2f6bSGordon Ross 
253613a2f6bSGordon Ross 	ctx->ct_dev_fd = -1;
2546b2bcd8eSGordon Ross 	ctx->ct_door_fd = -1;
255613a2f6bSGordon Ross 	ctx->ct_parsedlevel = SMBL_NONE;
256613a2f6bSGordon Ross 	ctx->ct_minlevel = SMBL_NONE;
257613a2f6bSGordon Ross 	ctx->ct_maxlevel = SMBL_PATH;
258613a2f6bSGordon Ross 
259613a2f6bSGordon Ross 	/* Fill in defaults */
26040c0e231SGordon Ross 	ctx->ct_vopt = SMBVOPT_SIGNING_ENABLED;
261613a2f6bSGordon Ross 	ctx->ct_owner = SMBM_ANY_OWNER;
262613a2f6bSGordon Ross 	ctx->ct_authflags = SMB_AT_DEFAULT;
263fd75ca8dSGordon Ross 	ctx->ct_minauth = SMB_AT_MINAUTH;
264adee6784SGordon Ross 	ctx->ct_maxver = SMB2_DIALECT_MAX;
265613a2f6bSGordon Ross 
266613a2f6bSGordon Ross 	/*
267430b4c46SGordon Ross 	 * Default domain, user, ...
268613a2f6bSGordon Ross 	 */
269430b4c46SGordon Ross 	strlcpy(ctx->ct_domain, default_domain,
270430b4c46SGordon Ross 	    sizeof (ctx->ct_domain));
271430b4c46SGordon Ross 	strlcpy(ctx->ct_user, default_user,
272430b4c46SGordon Ross 	    sizeof (ctx->ct_user));
273613a2f6bSGordon Ross 
274430b4c46SGordon Ross 	return (0);
275613a2f6bSGordon Ross }
276613a2f6bSGordon Ross 
277613a2f6bSGordon Ross /*
278613a2f6bSGordon Ross  * "Scan" the command line args to find the server name,
279613a2f6bSGordon Ross  * user name, and share name, as needed.  We need these
280613a2f6bSGordon Ross  * before reading the RC files and/or sharectl values.
2814bff34e3Sthurlow  *
2824bff34e3Sthurlow  * The sequence for getting all the members filled in
2834bff34e3Sthurlow  * has some tricky aspects.  Here's how it works:
2844bff34e3Sthurlow  *
2854bff34e3Sthurlow  * The search order for options is as follows:
2864bff34e3Sthurlow  *   command line options
2874bff34e3Sthurlow  *   values parsed from UNC path (cmd)
2884bff34e3Sthurlow  *   values from RC file (per-user)
2894bff34e3Sthurlow  *   values from SMF (system-wide)
2904bff34e3Sthurlow  *   built-in defaults
2914bff34e3Sthurlow  *
2924bff34e3Sthurlow  * Normally, one would simply get all the values starting with
2934bff34e3Sthurlow  * the bottom of the above list and working to the top, and
2944bff34e3Sthurlow  * overwriting values as you go.  But we need an exception.
2954bff34e3Sthurlow  *
2964bff34e3Sthurlow  * In this function, we parse the UNC path and command line options,
2974bff34e3Sthurlow  * because we need (at least) the server name when we're getting the
2984bff34e3Sthurlow  * SMF and RC file values.  However, values we get from the command
2994bff34e3Sthurlow  * should not be overwritten by SMF or RC file parsing, so we mark
3004bff34e3Sthurlow  * values from the command as "from CMD" and the RC file parser
3014bff34e3Sthurlow  * leaves in place any values so marked.  See: SMBCF_CMD_*
3024bff34e3Sthurlow  *
3034bff34e3Sthurlow  * The semantics of these flags are: "This value came from the
3044bff34e3Sthurlow  * current command instance, not from sources that may apply to
3054bff34e3Sthurlow  * multiple commands."  (Different from the old "FROMUSR" flag.)
3064bff34e3Sthurlow  *
3074bff34e3Sthurlow  * Note that smb_ctx_opt() is called later to handle the
3084bff34e3Sthurlow  * remaining options, which should be ignored here.
3094bff34e3Sthurlow  * The (magic) leading ":" in cf_getopt() makes it
3104bff34e3Sthurlow  * ignore options not in the options string.
3114bff34e3Sthurlow  */
3124bff34e3Sthurlow int
smb_ctx_scan_argv(struct smb_ctx * ctx,int argc,char ** argv,int minlevel,int maxlevel,int sharetype)313613a2f6bSGordon Ross smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
3144bff34e3Sthurlow 	int minlevel, int maxlevel, int sharetype)
3154bff34e3Sthurlow {
316613a2f6bSGordon Ross 	int  ind, opt, error = 0;
3174bff34e3Sthurlow 	int aflg = 0, uflg = 0;
318613a2f6bSGordon Ross 	const char *arg;
3194bff34e3Sthurlow 
3204bff34e3Sthurlow 	/*
3214bff34e3Sthurlow 	 * Parse options, if any.  Values from here too
3224bff34e3Sthurlow 	 * are marked as "from CMD".
3234bff34e3Sthurlow 	 */
324613a2f6bSGordon Ross 	if (argv == NULL)
325613a2f6bSGordon Ross 		return (0);
326613a2f6bSGordon Ross 
327613a2f6bSGordon Ross 	ctx->ct_minlevel = minlevel;
328613a2f6bSGordon Ross 	ctx->ct_maxlevel = maxlevel;
329613a2f6bSGordon Ross 	ctx->ct_shtype_req = sharetype;
330613a2f6bSGordon Ross 
331613a2f6bSGordon Ross 	cf_opt_lock();
332613a2f6bSGordon Ross 	/* Careful: no return/goto before cf_opt_unlock! */
333613a2f6bSGordon Ross 	while (error == 0) {
3348329232eSGordon Ross 		/*
3358329232eSGordon Ross 		 * Leading ':' tells this to skip unknown opts.
3368329232eSGordon Ross 		 * Just get -A and -U here so we know the user
3378329232eSGordon Ross 		 * for config file parsing.
3388329232eSGordon Ross 		 */
3398329232eSGordon Ross 		opt = cf_getopt(argc, argv, ":AU:");
340613a2f6bSGordon Ross 		if (opt == -1)
341613a2f6bSGordon Ross 			break;
3424bff34e3Sthurlow 		arg = cf_optarg;
343613a2f6bSGordon Ross 		/* NB: handle most in smb_ctx_opt */
3444bff34e3Sthurlow 		switch (opt) {
3454bff34e3Sthurlow 		case 'A':
3464bff34e3Sthurlow 			aflg = 1;
3474bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, "", TRUE);
3484bff34e3Sthurlow 			ctx->ct_flags |= SMBCF_NOPWD;
3494bff34e3Sthurlow 			break;
3504bff34e3Sthurlow 		case 'U':
3514bff34e3Sthurlow 			uflg = 1;
3524bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, arg, TRUE);
3534bff34e3Sthurlow 			break;
354613a2f6bSGordon Ross 		default:
355613a2f6bSGordon Ross 			DPRINT("skip opt=%c", opt);
356613a2f6bSGordon Ross 			break;
3574bff34e3Sthurlow 		}
3584bff34e3Sthurlow 	}
359613a2f6bSGordon Ross 	ind = cf_optind;
360613a2f6bSGordon Ross 	arg = argv[ind];
361613a2f6bSGordon Ross 	cf_optind = cf_optreset = 1;
362613a2f6bSGordon Ross 	cf_opt_unlock();
363613a2f6bSGordon Ross 
364613a2f6bSGordon Ross 	if (error)
365613a2f6bSGordon Ross 		return (error);
366613a2f6bSGordon Ross 
3674bff34e3Sthurlow 	if (aflg && uflg)  {
3684bff34e3Sthurlow 		printf(gettext("-A and -U flags are exclusive.\n"));
369613a2f6bSGordon Ross 		return (EINVAL);
3704bff34e3Sthurlow 	}
3714bff34e3Sthurlow 
372613a2f6bSGordon Ross 	/*
373613a2f6bSGordon Ross 	 * Parse the UNC path.  Values from here are
374613a2f6bSGordon Ross 	 * marked as "from CMD".
375613a2f6bSGordon Ross 	 */
376613a2f6bSGordon Ross 	for (; ind < argc; ind++) {
377613a2f6bSGordon Ross 		arg = argv[ind];
378613a2f6bSGordon Ross 		if (strncmp(arg, "//", 2) != 0)
379613a2f6bSGordon Ross 			continue;
380613a2f6bSGordon Ross 		error = smb_ctx_parseunc(ctx, arg,
381613a2f6bSGordon Ross 		    minlevel, maxlevel, sharetype, &arg);
382613a2f6bSGordon Ross 		if (error)
383613a2f6bSGordon Ross 			return (error);
384613a2f6bSGordon Ross 		break;
385613a2f6bSGordon Ross 	}
3864bff34e3Sthurlow 
3874bff34e3Sthurlow 	return (error);
3884bff34e3Sthurlow }
3894bff34e3Sthurlow 
3904bff34e3Sthurlow void
smb_ctx_free(smb_ctx_t * ctx)391613a2f6bSGordon Ross smb_ctx_free(smb_ctx_t *ctx)
392613a2f6bSGordon Ross {
393613a2f6bSGordon Ross 	smb_ctx_done(ctx);
394613a2f6bSGordon Ross 	free(ctx);
395613a2f6bSGordon Ross }
396613a2f6bSGordon Ross 
397613a2f6bSGordon Ross void
smb_ctx_done(struct smb_ctx * ctx)3984bff34e3Sthurlow smb_ctx_done(struct smb_ctx *ctx)
3994bff34e3Sthurlow {
4004bff34e3Sthurlow 
4014bff34e3Sthurlow 	rpc_cleanup_smbctx(ctx);
4024bff34e3Sthurlow 
403613a2f6bSGordon Ross 	if (ctx->ct_dev_fd != -1) {
4048329232eSGordon Ross 		nsmb_close(ctx->ct_dev_fd);
405613a2f6bSGordon Ross 		ctx->ct_dev_fd = -1;
4064bff34e3Sthurlow 	}
4076b2bcd8eSGordon Ross 	if (ctx->ct_door_fd != -1) {
4086b2bcd8eSGordon Ross 		close(ctx->ct_door_fd);
4096b2bcd8eSGordon Ross 		ctx->ct_door_fd = -1;
4106b2bcd8eSGordon Ross 	}
411613a2f6bSGordon Ross 	if (ctx->ct_srvaddr_s) {
412613a2f6bSGordon Ross 		free(ctx->ct_srvaddr_s);
413613a2f6bSGordon Ross 		ctx->ct_srvaddr_s = NULL;
414613a2f6bSGordon Ross 	}
415613a2f6bSGordon Ross 	if (ctx->ct_nb) {
4164bff34e3Sthurlow 		nb_ctx_done(ctx->ct_nb);
417613a2f6bSGordon Ross 		ctx->ct_nb = NULL;
418613a2f6bSGordon Ross 	}
419613a2f6bSGordon Ross 	if (ctx->ct_locname) {
420613a2f6bSGordon Ross 		free(ctx->ct_locname);
421613a2f6bSGordon Ross 		ctx->ct_locname = NULL;
422613a2f6bSGordon Ross 	}
423613a2f6bSGordon Ross 	if (ctx->ct_origshare) {
4244bff34e3Sthurlow 		free(ctx->ct_origshare);
425613a2f6bSGordon Ross 		ctx->ct_origshare = NULL;
426613a2f6bSGordon Ross 	}
427613a2f6bSGordon Ross 	if (ctx->ct_fullserver) {
4284bff34e3Sthurlow 		free(ctx->ct_fullserver);
429613a2f6bSGordon Ross 		ctx->ct_fullserver = NULL;
430613a2f6bSGordon Ross 	}
431613a2f6bSGordon Ross 	if (ctx->ct_addrinfo) {
432613a2f6bSGordon Ross 		freeaddrinfo(ctx->ct_addrinfo);
433613a2f6bSGordon Ross 		ctx->ct_addrinfo = NULL;
434613a2f6bSGordon Ross 	}
435430b4c46SGordon Ross 	if (ctx->ct_home) {
436613a2f6bSGordon Ross 		free(ctx->ct_home);
437430b4c46SGordon Ross 		ctx->ct_home = NULL;
438430b4c46SGordon Ross 	}
439430b4c46SGordon Ross 	if (ctx->ct_rpath) {
440430b4c46SGordon Ross 		free(ctx->ct_rpath);
441430b4c46SGordon Ross 		ctx->ct_rpath = NULL;
442430b4c46SGordon Ross 	}
44340c0e231SGordon Ross 	if (ctx->ct_ssnkey_buf) {
44440c0e231SGordon Ross 		free(ctx->ct_ssnkey_buf);
44540c0e231SGordon Ross 		ctx->ct_ssnkey_buf = NULL;
446613a2f6bSGordon Ross 	}
4474bff34e3Sthurlow }
4484bff34e3Sthurlow 
4494bff34e3Sthurlow /*
4504bff34e3Sthurlow  * Parse the UNC path.  Here we expect something like
451430b4c46SGordon Ross  *   "//[[domain;]user[:password]@]host[/share[/path]]"
4524bff34e3Sthurlow  * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
4534bff34e3Sthurlow  * Values found here are marked as "from CMD".
4544bff34e3Sthurlow  */
4554bff34e3Sthurlow int
smb_ctx_parseunc(struct smb_ctx * ctx,const char * unc,int minlevel,int maxlevel,int sharetype,const char ** next)456613a2f6bSGordon Ross smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
457613a2f6bSGordon Ross 	int minlevel, int maxlevel, int sharetype,
4584bff34e3Sthurlow 	const char **next)
4594bff34e3Sthurlow {
4604bff34e3Sthurlow 	char tmp[1024];
461430b4c46SGordon Ross 	char *host, *share, *path;
462430b4c46SGordon Ross 	char *dom, *usr, *pw, *p;
4634bff34e3Sthurlow 	int error;
4644bff34e3Sthurlow 
465613a2f6bSGordon Ross 	/*
466613a2f6bSGordon Ross 	 * This may be called outside of _scan_argv,
467613a2f6bSGordon Ross 	 * so make sure these get initialized.
468613a2f6bSGordon Ross 	 */
469613a2f6bSGordon Ross 	ctx->ct_minlevel = minlevel;
470613a2f6bSGordon Ross 	ctx->ct_maxlevel = maxlevel;
471613a2f6bSGordon Ross 	ctx->ct_shtype_req = sharetype;
4724bff34e3Sthurlow 	ctx->ct_parsedlevel = SMBL_NONE;
473430b4c46SGordon Ross 
474430b4c46SGordon Ross 	dom = usr = pw = host = NULL;
475430b4c46SGordon Ross 
476430b4c46SGordon Ross 	/* Work on a temporary copy, fix back slashes. */
477430b4c46SGordon Ross 	strlcpy(tmp, unc, sizeof (tmp));
478430b4c46SGordon Ross 	for (p = tmp; *p; p++)
479430b4c46SGordon Ross 		if (*p == '\\')
480430b4c46SGordon Ross 			*p = '/';
481430b4c46SGordon Ross 
482430b4c46SGordon Ross 	if (tmp[0] != '/' || tmp[1] != '/') {
4834bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
4844bff34e3Sthurlow 		    "UNC should start with '//'"), 0);
485613a2f6bSGordon Ross 		error = EINVAL;
486613a2f6bSGordon Ross 		goto out;
4874bff34e3Sthurlow 	}
488430b4c46SGordon Ross 	p = tmp + 2;	/* user@host... */
489430b4c46SGordon Ross 
490430b4c46SGordon Ross 	/* Find the share part, if any. */
491430b4c46SGordon Ross 	share = strchr(p, '/');
492430b4c46SGordon Ross 	if (share)
493430b4c46SGordon Ross 		*share = '\0';
494430b4c46SGordon Ross 	(void) unpercent(p);	/* host component */
495430b4c46SGordon Ross 
496430b4c46SGordon Ross 	/*
497430b4c46SGordon Ross 	 * Parse the "host" stuff right to left:
498430b4c46SGordon Ross 	 * 1: trailing "@hostname" (or whole field)
499430b4c46SGordon Ross 	 * 2: trailing ":password"
500430b4c46SGordon Ross 	 * 3: trailing "domain;user" (or just user)
501430b4c46SGordon Ross 	 */
502430b4c46SGordon Ross 	host = strrchr(p, '@');
503430b4c46SGordon Ross 	if (host == NULL) {
504430b4c46SGordon Ross 		host = p;	/* no user@ prefix */
505430b4c46SGordon Ross 	} else {
506430b4c46SGordon Ross 		*host++ = '\0';
507430b4c46SGordon Ross 
508430b4c46SGordon Ross 		/* may have [[domain;]user[:passwd]] */
509430b4c46SGordon Ross 		pw = strchr(p, ':');
510430b4c46SGordon Ross 		if (pw)
511430b4c46SGordon Ross 			*pw++ = '\0';
512430b4c46SGordon Ross 		usr = strchr(p, ';');
513430b4c46SGordon Ross 		if (usr) {
514430b4c46SGordon Ross 			*usr++ = '\0';
515430b4c46SGordon Ross 			dom = p;
516430b4c46SGordon Ross 		} else
517430b4c46SGordon Ross 			usr = p;
518430b4c46SGordon Ross 	}
519430b4c46SGordon Ross 
520430b4c46SGordon Ross 	if (*host == '\0') {
521430b4c46SGordon Ross 		smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
522613a2f6bSGordon Ross 		error = EINVAL;
523613a2f6bSGordon Ross 		goto out;
5244bff34e3Sthurlow 	}
525430b4c46SGordon Ross 	error = smb_ctx_setfullserver(ctx, host);
526430b4c46SGordon Ross 	if (error)
527430b4c46SGordon Ross 		goto out;
528430b4c46SGordon Ross 	ctx->ct_parsedlevel = SMBL_VC;
529430b4c46SGordon Ross 
530430b4c46SGordon Ross 	if (dom != NULL) {
531430b4c46SGordon Ross 		error = smb_ctx_setdomain(ctx, dom, TRUE);
5324bff34e3Sthurlow 		if (error)
533613a2f6bSGordon Ross 			goto out;
5344bff34e3Sthurlow 	}
535430b4c46SGordon Ross 	if (usr != NULL) {
536430b4c46SGordon Ross 		if (*usr == '\0') {
537430b4c46SGordon Ross 			smb_error(dgettext(TEXT_DOMAIN,
538430b4c46SGordon Ross 			    "empty user name"), 0);
539430b4c46SGordon Ross 			error = EINVAL;
540430b4c46SGordon Ross 			goto out;
541430b4c46SGordon Ross 		}
5424bff34e3Sthurlow 		if (ctx->ct_maxlevel < SMBL_VC) {
5434bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5444bff34e3Sthurlow 			    "no user name required"), 0);
545613a2f6bSGordon Ross 			error = EINVAL;
546613a2f6bSGordon Ross 			goto out;
5474bff34e3Sthurlow 		}
548430b4c46SGordon Ross 		error = smb_ctx_setuser(ctx, usr, TRUE);
5494bff34e3Sthurlow 		if (error)
550613a2f6bSGordon Ross 			goto out;
5514bff34e3Sthurlow 	}
552430b4c46SGordon Ross 	if (pw != NULL) {
553430b4c46SGordon Ross 		error = smb_ctx_setpassword(ctx, pw, TRUE);
554430b4c46SGordon Ross 		if (error)
555430b4c46SGordon Ross 			goto out;
556430b4c46SGordon Ross 	}
557430b4c46SGordon Ross 
558430b4c46SGordon Ross 	if (share != NULL) {
559430b4c46SGordon Ross 		/* restore the slash */
560430b4c46SGordon Ross 		*share = '/';
561430b4c46SGordon Ross 		p = share + 1;
562430b4c46SGordon Ross 
563430b4c46SGordon Ross 		/* Find the path part, if any. */
564430b4c46SGordon Ross 		path = strchr(p, '/');
565430b4c46SGordon Ross 		if (path)
566430b4c46SGordon Ross 			*path = '\0';
567430b4c46SGordon Ross 		(void) unpercent(p);	/* share component */
568430b4c46SGordon Ross 
569430b4c46SGordon Ross 		if (*p == '\0') {
5704bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
571430b4c46SGordon Ross 			    "empty share name"), 0);
572613a2f6bSGordon Ross 			error = EINVAL;
573613a2f6bSGordon Ross 			goto out;
5744bff34e3Sthurlow 		}
575430b4c46SGordon Ross 		if (ctx->ct_maxlevel < SMBL_SHARE) {
5764bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
577430b4c46SGordon Ross 			    "no share name required"), 0);
578613a2f6bSGordon Ross 			error = EINVAL;
579613a2f6bSGordon Ross 			goto out;
5804bff34e3Sthurlow 		}
5814bff34e3Sthurlow 
5824bff34e3Sthurlow 		/*
583430b4c46SGordon Ross 		 * Special case UNC names like:
584430b4c46SGordon Ross 		 *	//host/PIPE/endpoint
585430b4c46SGordon Ross 		 * to have share: IPC$
5864bff34e3Sthurlow 		 */
587430b4c46SGordon Ross 		if (strcasecmp(p, "PIPE") == 0) {
588430b4c46SGordon Ross 			sharetype = USE_IPC;
589430b4c46SGordon Ross 			p = "IPC$";
590430b4c46SGordon Ross 		}
591430b4c46SGordon Ross 		error = smb_ctx_setshare(ctx, p, sharetype);
5924bff34e3Sthurlow 		if (error)
593613a2f6bSGordon Ross 			goto out;
594430b4c46SGordon Ross 		ctx->ct_parsedlevel = SMBL_SHARE;
595613a2f6bSGordon Ross 
596430b4c46SGordon Ross 		if (path) {
597430b4c46SGordon Ross 			/* restore the slash */
598430b4c46SGordon Ross 			*path = '/';
599430b4c46SGordon Ross 			p = path + 1;
600430b4c46SGordon Ross 			(void) unpercent(p);	/* remainder */
601430b4c46SGordon Ross 			free(ctx->ct_rpath);
602430b4c46SGordon Ross 			ctx->ct_rpath = strdup(path);
6034bff34e3Sthurlow 		}
604430b4c46SGordon Ross 	} else if (ctx->ct_minlevel >= SMBL_SHARE) {
6054bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
606613a2f6bSGordon Ross 		error = EINVAL;
607613a2f6bSGordon Ross 		goto out;
6084bff34e3Sthurlow 	}
609430b4c46SGordon Ross 
610613a2f6bSGordon Ross 	if (next)
611430b4c46SGordon Ross 		*next = NULL;
612613a2f6bSGordon Ross 
613613a2f6bSGordon Ross out:
614613a2f6bSGordon Ross 	if (error == 0 && smb_debug > 0)
615613a2f6bSGordon Ross 		dump_ctx("after smb_ctx_parseunc", ctx);
616613a2f6bSGordon Ross 
6174bff34e3Sthurlow 	return (error);
6184bff34e3Sthurlow }
6194bff34e3Sthurlow 
620613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
6214bff34e3Sthurlow int
smb_ctx_setcharset(struct smb_ctx * ctx,const char * arg)6224bff34e3Sthurlow smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
6234bff34e3Sthurlow {
6244bff34e3Sthurlow 	char *cp, *servercs, *localcs;
6254bff34e3Sthurlow 	int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
6264bff34e3Sthurlow 	int scslen, lcslen, error;
6274bff34e3Sthurlow 
6284bff34e3Sthurlow 	cp = strchr(arg, ':');
6294bff34e3Sthurlow 	lcslen = cp ? (cp - arg) : 0;
6304bff34e3Sthurlow 	if (lcslen == 0 || lcslen >= cslen) {
6314bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
6324bff34e3Sthurlow 		    "invalid local charset specification (%s)"), 0, arg);
6334bff34e3Sthurlow 		return (EINVAL);
6344bff34e3Sthurlow 	}
6354bff34e3Sthurlow 	scslen = (size_t)strlen(++cp);
6364bff34e3Sthurlow 	if (scslen == 0 || scslen >= cslen) {
6374bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
6384bff34e3Sthurlow 		    "invalid server charset specification (%s)"), 0, arg);
6394bff34e3Sthurlow 		return (EINVAL);
6404bff34e3Sthurlow 	}
6414bff34e3Sthurlow 	localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
6424bff34e3Sthurlow 	localcs[lcslen] = 0;
6434bff34e3Sthurlow 	servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
6444bff34e3Sthurlow 	error = nls_setrecode(localcs, servercs);
6454bff34e3Sthurlow 	if (error == 0)
6464bff34e3Sthurlow 		return (0);
6474bff34e3Sthurlow 	smb_error(dgettext(TEXT_DOMAIN,
6484bff34e3Sthurlow 	    "can't initialize iconv support (%s:%s)"),
6494bff34e3Sthurlow 	    error, localcs, servercs);
6504bff34e3Sthurlow 	localcs[0] = 0;
6514bff34e3Sthurlow 	servercs[0] = 0;
6524bff34e3Sthurlow 	return (error);
6534bff34e3Sthurlow }
654613a2f6bSGordon Ross #endif /* KICONV_SUPPORT */
655613a2f6bSGordon Ross 
656613a2f6bSGordon Ross int
smb_ctx_setauthflags(struct smb_ctx * ctx,int flags)657613a2f6bSGordon Ross smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
658613a2f6bSGordon Ross {
659613a2f6bSGordon Ross 	ctx->ct_authflags = flags;
660613a2f6bSGordon Ross 	return (0);
661613a2f6bSGordon Ross }
6624bff34e3Sthurlow 
6634bff34e3Sthurlow int
smb_ctx_setfullserver(struct smb_ctx * ctx,const char * name)6644bff34e3Sthurlow smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
6654bff34e3Sthurlow {
666613a2f6bSGordon Ross 	char *p = strdup(name);
667613a2f6bSGordon Ross 
668613a2f6bSGordon Ross 	if (p == NULL)
6694bff34e3Sthurlow 		return (ENOMEM);
670613a2f6bSGordon Ross 	if (ctx->ct_fullserver)
671613a2f6bSGordon Ross 		free(ctx->ct_fullserver);
672613a2f6bSGordon Ross 	ctx->ct_fullserver = p;
6734bff34e3Sthurlow 	return (0);
6744bff34e3Sthurlow }
6754bff34e3Sthurlow 
676613a2f6bSGordon Ross int
smb_ctx_setserver(struct smb_ctx * ctx,const char * name)6774bff34e3Sthurlow smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
6784bff34e3Sthurlow {
679613a2f6bSGordon Ross 	strlcpy(ctx->ct_srvname, name,
680613a2f6bSGordon Ross 	    sizeof (ctx->ct_srvname));
681613a2f6bSGordon Ross 	return (0);
6824bff34e3Sthurlow }
6834bff34e3Sthurlow 
6844bff34e3Sthurlow int
smb_ctx_setuser(struct smb_ctx * ctx,const char * name,int from_cmd)6854bff34e3Sthurlow smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
6864bff34e3Sthurlow {
6874bff34e3Sthurlow 
688613a2f6bSGordon Ross 	if (strlen(name) >= sizeof (ctx->ct_user)) {
6894bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
6904bff34e3Sthurlow 		    "user name '%s' too long"), 0, name);
6914bff34e3Sthurlow 		return (ENAMETOOLONG);
6924bff34e3Sthurlow 	}
6934bff34e3Sthurlow 
6944bff34e3Sthurlow 	/*
6954bff34e3Sthurlow 	 * Don't overwrite a value from the command line
6964bff34e3Sthurlow 	 * with one from anywhere else.
6974bff34e3Sthurlow 	 */
6984bff34e3Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
6994bff34e3Sthurlow 		return (0);
7004bff34e3Sthurlow 
701613a2f6bSGordon Ross 	strlcpy(ctx->ct_user, name,
702613a2f6bSGordon Ross 	    sizeof (ctx->ct_user));
7034bff34e3Sthurlow 
7044bff34e3Sthurlow 	/* Mark this as "from the command line". */
7054bff34e3Sthurlow 	if (from_cmd)
7064bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_CMD_USR;
7074bff34e3Sthurlow 
7084bff34e3Sthurlow 	return (0);
7094bff34e3Sthurlow }
7104bff34e3Sthurlow 
7114bff34e3Sthurlow /*
7124bff34e3Sthurlow  * Don't overwrite a domain name from the
7134bff34e3Sthurlow  * command line with one from anywhere else.
7144bff34e3Sthurlow  * See smb_ctx_init() for notes about this.
7154bff34e3Sthurlow  */
7164bff34e3Sthurlow int
smb_ctx_setdomain(struct smb_ctx * ctx,const char * name,int from_cmd)717613a2f6bSGordon Ross smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd)
7184bff34e3Sthurlow {
7194bff34e3Sthurlow 
720613a2f6bSGordon Ross 	if (strlen(name) >= sizeof (ctx->ct_domain)) {
7214bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
7224bff34e3Sthurlow 		    "workgroup name '%s' too long"), 0, name);
7234bff34e3Sthurlow 		return (ENAMETOOLONG);
7244bff34e3Sthurlow 	}
7254bff34e3Sthurlow 
7264bff34e3Sthurlow 	/*
7274bff34e3Sthurlow 	 * Don't overwrite a value from the command line
7284bff34e3Sthurlow 	 * with one from anywhere else.
7294bff34e3Sthurlow 	 */
7304bff34e3Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
7314bff34e3Sthurlow 		return (0);
7324bff34e3Sthurlow 
733613a2f6bSGordon Ross 	strlcpy(ctx->ct_domain, name,
734613a2f6bSGordon Ross 	    sizeof (ctx->ct_domain));
7354bff34e3Sthurlow 
7364bff34e3Sthurlow 	/* Mark this as "from the command line". */
7374bff34e3Sthurlow 	if (from_cmd)
7384bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_CMD_DOM;
7394bff34e3Sthurlow 
7404bff34e3Sthurlow 	return (0);
7414bff34e3Sthurlow }
7424bff34e3Sthurlow 
7434bff34e3Sthurlow int
smb_ctx_setpassword(struct smb_ctx * ctx,const char * passwd,int from_cmd)7444bff34e3Sthurlow smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
7454bff34e3Sthurlow {
746613a2f6bSGordon Ross 	int err;
7474bff34e3Sthurlow 
748613a2f6bSGordon Ross 	if (passwd == NULL)
7494bff34e3Sthurlow 		return (EINVAL);
750613a2f6bSGordon Ross 	if (strlen(passwd) >= sizeof (ctx->ct_password)) {
7514bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
7524bff34e3Sthurlow 		return (ENAMETOOLONG);
7534bff34e3Sthurlow 	}
7544bff34e3Sthurlow 
7554bff34e3Sthurlow 	/*
756613a2f6bSGordon Ross 	 * If called again after comand line parsing,
757613a2f6bSGordon Ross 	 * don't overwrite a value from the command line
758613a2f6bSGordon Ross 	 * with one from any stored config.
7594bff34e3Sthurlow 	 */
7604bff34e3Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
7614bff34e3Sthurlow 		return (0);
7624bff34e3Sthurlow 
763613a2f6bSGordon Ross 	memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
7644bff34e3Sthurlow 	if (strncmp(passwd, "$$1", 3) == 0)
76502d09e03SGordon Ross 		(void) smb_simpledecrypt(ctx->ct_password, passwd);
7664bff34e3Sthurlow 	else
767613a2f6bSGordon Ross 		strlcpy(ctx->ct_password, passwd,
768613a2f6bSGordon Ross 		    sizeof (ctx->ct_password));
769613a2f6bSGordon Ross 
770613a2f6bSGordon Ross 	/*
771613a2f6bSGordon Ross 	 * Compute LM hash, NT hash.
772613a2f6bSGordon Ross 	 */
773613a2f6bSGordon Ross 	if (ctx->ct_password[0]) {
774613a2f6bSGordon Ross 		err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
775613a2f6bSGordon Ross 		if (err != 0)
776613a2f6bSGordon Ross 			return (err);
777613a2f6bSGordon Ross 		err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
778613a2f6bSGordon Ross 		if (err != 0)
779613a2f6bSGordon Ross 			return (err);
780613a2f6bSGordon Ross 	}
7814bff34e3Sthurlow 
7824bff34e3Sthurlow 	/* Mark this as "from the command line". */
7834bff34e3Sthurlow 	if (from_cmd)
7844bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_CMD_PW;
7854bff34e3Sthurlow 
7864bff34e3Sthurlow 	return (0);
7874bff34e3Sthurlow }
7884bff34e3Sthurlow 
789613a2f6bSGordon Ross /*
790613a2f6bSGordon Ross  * Use this to set NTLM auth. info (hashes)
791613a2f6bSGordon Ross  * when we don't have the password.
792613a2f6bSGordon Ross  */
793613a2f6bSGordon Ross int
smb_ctx_setpwhash(smb_ctx_t * ctx,const uchar_t * nthash,const uchar_t * lmhash)794613a2f6bSGordon Ross smb_ctx_setpwhash(smb_ctx_t *ctx,
795613a2f6bSGordon Ross     const uchar_t *nthash, const uchar_t *lmhash)
796613a2f6bSGordon Ross {
797613a2f6bSGordon Ross 
798613a2f6bSGordon Ross 	/* Need ct_password to be non-null. */
799613a2f6bSGordon Ross 	if (ctx->ct_password[0] == '\0')
800613a2f6bSGordon Ross 		strlcpy(ctx->ct_password, "$HASH",
801613a2f6bSGordon Ross 		    sizeof (ctx->ct_password));
802613a2f6bSGordon Ross 
803613a2f6bSGordon Ross 	/*
804613a2f6bSGordon Ross 	 * Compute LM hash, NT hash.
805613a2f6bSGordon Ross 	 */
806613a2f6bSGordon Ross 	memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
807613a2f6bSGordon Ross 
808613a2f6bSGordon Ross 	/* The LM hash is optional */
809613a2f6bSGordon Ross 	if (lmhash) {
810613a2f6bSGordon Ross 		memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
811613a2f6bSGordon Ross 	}
812613a2f6bSGordon Ross 
813613a2f6bSGordon Ross 	return (0);
814613a2f6bSGordon Ross }
815613a2f6bSGordon Ross 
8164bff34e3Sthurlow int
smb_ctx_setshare(struct smb_ctx * ctx,const char * share,int stype)8174bff34e3Sthurlow smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
8184bff34e3Sthurlow {
819613a2f6bSGordon Ross 	if (strlen(share) >= SMBIOC_MAX_NAME) {
8204bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
8214bff34e3Sthurlow 		    "share name '%s' too long"), 0, share);
8224bff34e3Sthurlow 		return (ENAMETOOLONG);
8234bff34e3Sthurlow 	}
8244bff34e3Sthurlow 	if (ctx->ct_origshare)
8254bff34e3Sthurlow 		free(ctx->ct_origshare);
8264bff34e3Sthurlow 	if ((ctx->ct_origshare = strdup(share)) == NULL)
8274bff34e3Sthurlow 		return (ENOMEM);
828613a2f6bSGordon Ross 
829613a2f6bSGordon Ross 	ctx->ct_shtype_req = stype;
830613a2f6bSGordon Ross 
8314bff34e3Sthurlow 	return (0);
8324bff34e3Sthurlow }
8334bff34e3Sthurlow 
8344bff34e3Sthurlow int
smb_ctx_setsrvaddr(struct smb_ctx * ctx,const char * addr)8354bff34e3Sthurlow smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
8364bff34e3Sthurlow {
8374bff34e3Sthurlow 	if (addr == NULL || addr[0] == 0)
8384bff34e3Sthurlow 		return (EINVAL);
839613a2f6bSGordon Ross 	if (ctx->ct_srvaddr_s)
840613a2f6bSGordon Ross 		free(ctx->ct_srvaddr_s);
841613a2f6bSGordon Ross 	if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL)
8424bff34e3Sthurlow 		return (ENOMEM);
8434bff34e3Sthurlow 	return (0);
8444bff34e3Sthurlow }
8454bff34e3Sthurlow 
8468eb99b82SGordon Ross /*
8478eb99b82SGordon Ross  * API for library caller to set signing enabled, required
8488eb99b82SGordon Ross  * Note: if not enable, ignore require
8498eb99b82SGordon Ross  */
8508eb99b82SGordon Ross int
smb_ctx_setsigning(struct smb_ctx * ctx,int enable,int require)8518eb99b82SGordon Ross smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
8528eb99b82SGordon Ross {
8538eb99b82SGordon Ross 	ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
8548eb99b82SGordon Ross 	if (enable) {
8558eb99b82SGordon Ross 		ctx->ct_vopt |=	SMBVOPT_SIGNING_ENABLED;
8568eb99b82SGordon Ross 		if (require)
8578eb99b82SGordon Ross 			ctx->ct_vopt |=	SMBVOPT_SIGNING_REQUIRED;
8588eb99b82SGordon Ross 	}
8598eb99b82SGordon Ross 	return (0);
8608eb99b82SGordon Ross }
8618eb99b82SGordon Ross 
862adee6784SGordon Ross /*
863adee6784SGordon Ross  * Handle .nsmbrc "minver" option.
864adee6784SGordon Ross  * Must be <= maxver
865adee6784SGordon Ross  */
866adee6784SGordon Ross int
smb_ctx_setminver(struct smb_ctx * ctx,int ver)867adee6784SGordon Ross smb_ctx_setminver(struct smb_ctx *ctx, int ver)
868adee6784SGordon Ross {
869adee6784SGordon Ross 	if (ver < 0 || ver > ctx->ct_maxver)
870adee6784SGordon Ross 		return (EINVAL);
871adee6784SGordon Ross 	ctx->ct_minver = (uint16_t)ver;
872adee6784SGordon Ross 	return (0);
873adee6784SGordon Ross }
874adee6784SGordon Ross 
875adee6784SGordon Ross /*
876adee6784SGordon Ross  * Handle .nsmbrc "maxver" option.
877adee6784SGordon Ross  * Must be >= minver
878adee6784SGordon Ross  *
879adee6784SGordon Ross  * Any "too high" value is just clamped, so the caller
880adee6784SGordon Ross  * doesn't need to know what's the highest we support.
881adee6784SGordon Ross  */
882adee6784SGordon Ross int
smb_ctx_setmaxver(struct smb_ctx * ctx,int ver)883adee6784SGordon Ross smb_ctx_setmaxver(struct smb_ctx *ctx, int ver)
884adee6784SGordon Ross {
885adee6784SGordon Ross 	if (ver < 1 || ver < ctx->ct_minver)
886adee6784SGordon Ross 		return (EINVAL);
887adee6784SGordon Ross 	if (ver > SMB2_DIALECT_MAX)
888adee6784SGordon Ross 		ver = SMB2_DIALECT_MAX;
889adee6784SGordon Ross 	ctx->ct_maxver = (uint16_t)ver;
890adee6784SGordon Ross 	return (0);
891adee6784SGordon Ross }
892adee6784SGordon Ross 
8934bff34e3Sthurlow static int
smb_parse_owner(char * pair,uid_t * uid,gid_t * gid)8944bff34e3Sthurlow smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
8954bff34e3Sthurlow {
8964bff34e3Sthurlow 	struct group gr;
8974bff34e3Sthurlow 	struct passwd pw;
8984bff34e3Sthurlow 	char buf[NSS_BUFLEN_PASSWD];
8994bff34e3Sthurlow 	char *cp;
9004bff34e3Sthurlow 
9014bff34e3Sthurlow 	cp = strchr(pair, ':');
9024bff34e3Sthurlow 	if (cp) {
9034bff34e3Sthurlow 		*cp++ = '\0';
904613a2f6bSGordon Ross 		if (*cp && gid) {
9054bff34e3Sthurlow 			if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
9064bff34e3Sthurlow 				*gid = gr.gr_gid;
9074bff34e3Sthurlow 			} else
9084bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
9094bff34e3Sthurlow 				    "Invalid group name %s, ignored"), 0, cp);
9104bff34e3Sthurlow 		}
9114bff34e3Sthurlow 	}
9124bff34e3Sthurlow 	if (*pair) {
9134bff34e3Sthurlow 		if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
9144bff34e3Sthurlow 			*uid = pw.pw_uid;
9154bff34e3Sthurlow 		} else
9164bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
9174bff34e3Sthurlow 			    "Invalid user name %s, ignored"), 0, pair);
9184bff34e3Sthurlow 	}
9194bff34e3Sthurlow 
9204bff34e3Sthurlow 	return (0);
9214bff34e3Sthurlow }
9224bff34e3Sthurlow 
9234bff34e3Sthurlow /*
92440c0e231SGordon Ross  * Suport a securty options arg, i.e. -S lm,ntlm
92515359501SGordon Ross  * for testing various type of authenticators.
92615359501SGordon Ross  */
92715359501SGordon Ross static struct nv
92815359501SGordon Ross sectype_table[] = {
92915359501SGordon Ross 	{ "anon",	SMB_AT_ANON },
93015359501SGordon Ross 	{ "lm",		SMB_AT_LM1 },
93115359501SGordon Ross 	{ "ntlm",	SMB_AT_NTLM1 },
93215359501SGordon Ross 	{ "ntlm2",	SMB_AT_NTLM2 },
93315359501SGordon Ross 	{ "krb5",	SMB_AT_KRB5 },
93415359501SGordon Ross 	{ NULL,		0 },
93515359501SGordon Ross };
93615359501SGordon Ross int
smb_parse_secopts(struct smb_ctx * ctx,const char * arg)93715359501SGordon Ross smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
93815359501SGordon Ross {
93915359501SGordon Ross 	const char *sep = ":;,";
94015359501SGordon Ross 	const char *p = arg;
94115359501SGordon Ross 	struct nv *nv;
94215359501SGordon Ross 	int nlen, tlen;
94315359501SGordon Ross 	int authflags = 0;
94415359501SGordon Ross 
94515359501SGordon Ross 	for (;;) {
94615359501SGordon Ross 		/* skip separators */
94715359501SGordon Ross 		tlen = strspn(p, sep);
94815359501SGordon Ross 		p += tlen;
94915359501SGordon Ross 
95015359501SGordon Ross 		nlen = strcspn(p, sep);
95115359501SGordon Ross 		if (nlen == 0)
95215359501SGordon Ross 			break;
95315359501SGordon Ross 
95415359501SGordon Ross 		/* This is rarely called, so not optimized. */
95515359501SGordon Ross 		for (nv = sectype_table; nv->name; nv++) {
95615359501SGordon Ross 			tlen = strlen(nv->name);
95715359501SGordon Ross 			if (tlen == nlen && 0 == strncmp(p, nv->name, tlen))
95815359501SGordon Ross 				break;
95915359501SGordon Ross 		}
96015359501SGordon Ross 		if (nv->name == NULL) {
96115359501SGordon Ross 			smb_error(dgettext(TEXT_DOMAIN,
96215359501SGordon Ross 			    "%s: invalid security options"), 0, p);
96315359501SGordon Ross 			return (EINVAL);
96415359501SGordon Ross 		}
96515359501SGordon Ross 		authflags |= nv->value;
96615359501SGordon Ross 		p += nlen;
96715359501SGordon Ross 	}
96815359501SGordon Ross 
96915359501SGordon Ross 	if (authflags)
97015359501SGordon Ross 		ctx->ct_authflags = authflags;
97115359501SGordon Ross 
97215359501SGordon Ross 	return (0);
97315359501SGordon Ross }
97415359501SGordon Ross 
97515359501SGordon Ross /*
9764bff34e3Sthurlow  * Commands use this with getopt.  See:
9774bff34e3Sthurlow  *   STDPARAM_OPT, STDPARAM_ARGS
9784bff34e3Sthurlow  * Called after smb_ctx_readrc().
9794bff34e3Sthurlow  */
9804bff34e3Sthurlow int
smb_ctx_opt(struct smb_ctx * ctx,int opt,const char * arg)9814bff34e3Sthurlow smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
9824bff34e3Sthurlow {
9834bff34e3Sthurlow 	int error = 0;
9844bff34e3Sthurlow 	char *p, *cp;
9854bff34e3Sthurlow 	char tmp[1024];
9864bff34e3Sthurlow 
9874bff34e3Sthurlow 	switch (opt) {
9884bff34e3Sthurlow 	case 'A':
9894bff34e3Sthurlow 	case 'U':
9904bff34e3Sthurlow 		/* Handled in smb_ctx_init() */
9914bff34e3Sthurlow 		break;
9924bff34e3Sthurlow 	case 'I':
9934bff34e3Sthurlow 		error = smb_ctx_setsrvaddr(ctx, arg);
9944bff34e3Sthurlow 		break;
9954bff34e3Sthurlow 	case 'M':
996613a2f6bSGordon Ross 		/* share connect rights - ignored */
9974bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_SRIGHTS;
9984bff34e3Sthurlow 		break;
9994bff34e3Sthurlow 	case 'N':
10004bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_NOPWD;
10014bff34e3Sthurlow 		break;
10024bff34e3Sthurlow 	case 'O':
10034bff34e3Sthurlow 		p = strdup(arg);
10044bff34e3Sthurlow 		cp = strchr(p, '/');
1005613a2f6bSGordon Ross 		if (cp)
1006613a2f6bSGordon Ross 			*cp = '\0';
1007613a2f6bSGordon Ross 		error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
10084bff34e3Sthurlow 		free(p);
10094bff34e3Sthurlow 		break;
10104bff34e3Sthurlow 	case 'P':
1011613a2f6bSGordon Ross /*		ctx->ct_vopt |= SMBCOPT_PERMANENT; */
10124bff34e3Sthurlow 		break;
10134bff34e3Sthurlow 	case 'R':
1014613a2f6bSGordon Ross 		/* retry count - ignored */
10154bff34e3Sthurlow 		break;
101615359501SGordon Ross 	case 'S':
101715359501SGordon Ross 		/* Security options (undocumented, just for tests) */
101815359501SGordon Ross 		error = smb_parse_secopts(ctx, arg);
101915359501SGordon Ross 		break;
10204bff34e3Sthurlow 	case 'T':
1021613a2f6bSGordon Ross 		/* timeout - ignored */
10224bff34e3Sthurlow 		break;
1023613a2f6bSGordon Ross 	case 'D':	/* domain */
1024613a2f6bSGordon Ross 	case 'W':	/* workgroup (legacy alias) */
1025613a2f6bSGordon Ross 		error = smb_ctx_setdomain(ctx, tmp, TRUE);
10264bff34e3Sthurlow 		break;
10274bff34e3Sthurlow 	}
10284bff34e3Sthurlow 	return (error);
10294bff34e3Sthurlow }
10304bff34e3Sthurlow 
10314bff34e3Sthurlow 
1032613a2f6bSGordon Ross /*
1033613a2f6bSGordon Ross  * Original code injected iconv tables into the kernel.
1034613a2f6bSGordon Ross  * Not sure if we'll need this or not...  REVISIT
1035613a2f6bSGordon Ross  */
1036613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
10374bff34e3Sthurlow static int
smb_addiconvtbl(const char * to,const char * from,const uchar_t * tbl)10384bff34e3Sthurlow smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
10394bff34e3Sthurlow {
1040613a2f6bSGordon Ross 	int error = 0;
10414bff34e3Sthurlow 
10424bff34e3Sthurlow 	error = kiconv_add_xlat_table(to, from, tbl);
10434bff34e3Sthurlow 	if (error && error != EEXIST) {
10444bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10454bff34e3Sthurlow 		    "can not setup kernel iconv table (%s:%s)"),
10464bff34e3Sthurlow 		    error, from, to);
10474bff34e3Sthurlow 		return (error);
10484bff34e3Sthurlow 	}
1049613a2f6bSGordon Ross 	return (error);
10504bff34e3Sthurlow }
1051613a2f6bSGordon Ross #endif	/* KICONV_SUPPORT */
10524bff34e3Sthurlow 
10534bff34e3Sthurlow /*
1054613a2f6bSGordon Ross  * Verify context info. before connect operation(s),
10554bff34e3Sthurlow  * lookup specified server and try to fill all forgotten fields.
1056613a2f6bSGordon Ross  * Legacy name used by commands.
10574bff34e3Sthurlow  */
10584bff34e3Sthurlow int
smb_ctx_resolve(struct smb_ctx * ctx)10594bff34e3Sthurlow smb_ctx_resolve(struct smb_ctx *ctx)
10604bff34e3Sthurlow {
10614bff34e3Sthurlow 	struct smbioc_ossn *ssn = &ctx->ct_ssn;
1062613a2f6bSGordon Ross 	int error = 0;
1063613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
10644bff34e3Sthurlow 	uchar_t cstbl[256];
10654bff34e3Sthurlow 	uint_t i;
1066613a2f6bSGordon Ross #endif
10674bff34e3Sthurlow 
106815359501SGordon Ross 	if (smb_debug)
106915359501SGordon Ross 		dump_ctx("before smb_ctx_resolve", ctx);
107015359501SGordon Ross 
10714bff34e3Sthurlow 	ctx->ct_flags &= ~SMBCF_RESOLVED;
1072613a2f6bSGordon Ross 
1073613a2f6bSGordon Ross 	if (ctx->ct_fullserver == NULL) {
10744bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10754bff34e3Sthurlow 		    "no server name specified"), 0);
10764bff34e3Sthurlow 		return (EINVAL);
10774bff34e3Sthurlow 	}
1078613a2f6bSGordon Ross 
1079613a2f6bSGordon Ross 	if (ctx->ct_minlevel >= SMBL_SHARE &&
1080613a2f6bSGordon Ross 	    ctx->ct_origshare == NULL) {
10814bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10824bff34e3Sthurlow 		    "no share name specified for %s@%s"),
1083613a2f6bSGordon Ross 		    0, ssn->ssn_user, ctx->ct_fullserver);
10844bff34e3Sthurlow 		return (EINVAL);
10854bff34e3Sthurlow 	}
10864bff34e3Sthurlow 	error = nb_ctx_resolve(ctx->ct_nb);
10874bff34e3Sthurlow 	if (error)
10884bff34e3Sthurlow 		return (error);
1089613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
10904bff34e3Sthurlow 	if (ssn->ioc_localcs[0] == 0)
10914bff34e3Sthurlow 		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
10924bff34e3Sthurlow 	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
10934bff34e3Sthurlow 	if (error)
10944bff34e3Sthurlow 		return (error);
10954bff34e3Sthurlow 	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
10964bff34e3Sthurlow 	if (error)
10974bff34e3Sthurlow 		return (error);
10984bff34e3Sthurlow 	if (ssn->ioc_servercs[0] != 0) {
10994bff34e3Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
11004bff34e3Sthurlow 			cstbl[i] = i;
11014bff34e3Sthurlow 		nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
11024bff34e3Sthurlow 		error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
11034bff34e3Sthurlow 		    cstbl);
11044bff34e3Sthurlow 		if (error)
11054bff34e3Sthurlow 			return (error);
11064bff34e3Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
11074bff34e3Sthurlow 			cstbl[i] = i;
11084bff34e3Sthurlow 		nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
11094bff34e3Sthurlow 		error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
11104bff34e3Sthurlow 		    cstbl);
11114bff34e3Sthurlow 		if (error)
11124bff34e3Sthurlow 			return (error);
11134bff34e3Sthurlow 	}
1114613a2f6bSGordon Ross #endif	/* KICONV_SUPPORT */
11154bff34e3Sthurlow 
11164bff34e3Sthurlow 	/*
11176b2bcd8eSGordon Ross 	 * Lookup the IP address and fill in ct_addrinfo.
11186b2bcd8eSGordon Ross 	 *
11196b2bcd8eSGordon Ross 	 * Note: smb_ctx_getaddr() returns a EAI_xxx
11206b2bcd8eSGordon Ross 	 * error value like getaddrinfo(3), but this
11216b2bcd8eSGordon Ross 	 * function needs to return an errno value.
11224bff34e3Sthurlow 	 */
1123613a2f6bSGordon Ross 	error = smb_ctx_getaddr(ctx);
11244bff34e3Sthurlow 	if (error) {
11256b2bcd8eSGordon Ross 		const char *ais = gai_strerror(error);
11264bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1127ae3d7f90SGordon Ross 		    "can't resolve name\"%s\", %s"),
1128ae3d7f90SGordon Ross 		    0, ctx->ct_fullserver, ais);
11296b2bcd8eSGordon Ross 		return (ENODATA);
11304bff34e3Sthurlow 	}
1131613a2f6bSGordon Ross 	assert(ctx->ct_addrinfo != NULL);
11324bff34e3Sthurlow 
11334bff34e3Sthurlow 	/*
113440c0e231SGordon Ross 	 * Empty user name means an explicit request for
113540c0e231SGordon Ross 	 * NULL session setup, which is a special case.
113640c0e231SGordon Ross 	 * (No SMB signing, per [MS-SMB] 3.3.5.3)
113740c0e231SGordon Ross 	 */
113840c0e231SGordon Ross 	if (ctx->ct_user[0] == '\0') {
113940c0e231SGordon Ross 		/* Null user should have null domain too. */
114040c0e231SGordon Ross 		ctx->ct_domain[0] = '\0';
114140c0e231SGordon Ross 		ctx->ct_authflags = SMB_AT_ANON;
114240c0e231SGordon Ross 		ctx->ct_vopt |= SMBVOPT_ANONYMOUS;
114340c0e231SGordon Ross 		ctx->ct_vopt &= ~SMBVOPT_SIGNING_REQUIRED;
114440c0e231SGordon Ross 	}
114540c0e231SGordon Ross 
114640c0e231SGordon Ross 	/*
1147613a2f6bSGordon Ross 	 * If we have a user name but no password,
1148613a2f6bSGordon Ross 	 * check for a keychain entry.
1149613a2f6bSGordon Ross 	 * XXX: Only for auth NTLM?
11504bff34e3Sthurlow 	 */
115185e6b674SGordon Ross 	if (ctx->ct_user[0] != '\0') {
11524bff34e3Sthurlow 		/*
1153613a2f6bSGordon Ross 		 * Have a user name.
1154613a2f6bSGordon Ross 		 * If we don't have a p/w yet,
1155613a2f6bSGordon Ross 		 * try the keychain.
11564bff34e3Sthurlow 		 */
1157adee6784SGordon Ross 		if (ctx->ct_password[0] == '\0' &&
1158adee6784SGordon Ross 		    smb_get_keychain(ctx) == 0) {
1159adee6784SGordon Ross 			strlcpy(ctx->ct_password, "$HASH",
1160adee6784SGordon Ross 			    sizeof (ctx->ct_password));
1161adee6784SGordon Ross 		}
1162adee6784SGordon Ross 
1163613a2f6bSGordon Ross 		/*
1164613a2f6bSGordon Ross 		 * Mask out disallowed auth types.
1165613a2f6bSGordon Ross 		 */
1166613a2f6bSGordon Ross 		ctx->ct_authflags &= ctx->ct_minauth;
11674bff34e3Sthurlow 	}
116840c0e231SGordon Ross 
1169613a2f6bSGordon Ross 	if (ctx->ct_authflags == 0) {
11704bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1171613a2f6bSGordon Ross 		    "no valid auth. types"), 0);
1172613a2f6bSGordon Ross 		return (ENOTSUP);
11734bff34e3Sthurlow 	}
1174613a2f6bSGordon Ross 
11754bff34e3Sthurlow 	ctx->ct_flags |= SMBCF_RESOLVED;
11764bff34e3Sthurlow 	if (smb_debug)
11774bff34e3Sthurlow 		dump_ctx("after smb_ctx_resolve", ctx);
11784bff34e3Sthurlow 
11794bff34e3Sthurlow 	return (0);
11804bff34e3Sthurlow }
11814bff34e3Sthurlow 
11828329232eSGordon Ross /*
11838329232eSGordon Ross  * Note: The next three have NODIRECT binding so the
11848329232eSGordon Ross  * "fksmbcl" development tool can provide its own.
11858329232eSGordon Ross  */
11864bff34e3Sthurlow int
smb_open_driver()11874bff34e3Sthurlow smb_open_driver()
11884bff34e3Sthurlow {
1189430b4c46SGordon Ross 	int fd;
11904bff34e3Sthurlow 
11914bff34e3Sthurlow 	fd = open("/dev/"NSMB_NAME, O_RDWR);
1192613a2f6bSGordon Ross 	if (fd < 0) {
11934bff34e3Sthurlow 		return (-1);
11944bff34e3Sthurlow 	}
11954bff34e3Sthurlow 
1196613a2f6bSGordon Ross 	/* This handle controls per-process resources. */
1197613a2f6bSGordon Ross 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1198613a2f6bSGordon Ross 
11994bff34e3Sthurlow 	return (fd);
12004bff34e3Sthurlow }
12014bff34e3Sthurlow 
1202613a2f6bSGordon Ross int
nsmb_close(int fd)12038329232eSGordon Ross nsmb_close(int fd)
12048329232eSGordon Ross {
12058329232eSGordon Ross 	return (close(fd));
12068329232eSGordon Ross }
12078329232eSGordon Ross 
12088329232eSGordon Ross int
nsmb_ioctl(int fd,int cmd,void * arg)12098329232eSGordon Ross nsmb_ioctl(int fd, int cmd, void *arg)
12108329232eSGordon Ross {
12118329232eSGordon Ross 	return (ioctl(fd, cmd, arg));
12128329232eSGordon Ross }
12138329232eSGordon Ross 
12148329232eSGordon Ross 
12158329232eSGordon Ross int
smb_ctx_gethandle(struct smb_ctx * ctx)12164bff34e3Sthurlow smb_ctx_gethandle(struct smb_ctx *ctx)
12174bff34e3Sthurlow {
1218430b4c46SGordon Ross 	int fd, err;
1219430b4c46SGordon Ross 	uint32_t version;
12204bff34e3Sthurlow 
1221613a2f6bSGordon Ross 	if (ctx->ct_dev_fd != -1) {
12224bff34e3Sthurlow 		rpc_cleanup_smbctx(ctx);
12238329232eSGordon Ross 		nsmb_close(ctx->ct_dev_fd);
1224613a2f6bSGordon Ross 		ctx->ct_dev_fd = -1;
12254bff34e3Sthurlow 	}
12264bff34e3Sthurlow 
12274bff34e3Sthurlow 	fd = smb_open_driver();
1228430b4c46SGordon Ross 	if (fd < 0) {
1229430b4c46SGordon Ross 		err = errno;
1230430b4c46SGordon Ross 		smb_error(dgettext(TEXT_DOMAIN,
1231430b4c46SGordon Ross 		    "failed to open driver"), err);
1232430b4c46SGordon Ross 		return (err);
1233430b4c46SGordon Ross 	}
1234430b4c46SGordon Ross 
1235430b4c46SGordon Ross 	/*
1236430b4c46SGordon Ross 	 * Check the driver version (paranoia)
1237430b4c46SGordon Ross 	 */
12388329232eSGordon Ross 	if (nsmb_ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1239430b4c46SGordon Ross 		version = 0;
1240430b4c46SGordon Ross 	if (version != NSMB_VERSION) {
1241430b4c46SGordon Ross 		smb_error(dgettext(TEXT_DOMAIN,
1242430b4c46SGordon Ross 		    "incorrect driver version"), 0);
12438329232eSGordon Ross 		nsmb_close(fd);
12444bff34e3Sthurlow 		return (ENODEV);
1245430b4c46SGordon Ross 	}
12464bff34e3Sthurlow 
1247613a2f6bSGordon Ross 	ctx->ct_dev_fd = fd;
12484bff34e3Sthurlow 	return (0);
12494bff34e3Sthurlow }
12504bff34e3Sthurlow 
1251613a2f6bSGordon Ross 
1252613a2f6bSGordon Ross /*
1253613a2f6bSGordon Ross  * Find or create a connection + logon session
1254613a2f6bSGordon Ross  */
12554bff34e3Sthurlow int
smb_ctx_get_ssn(struct smb_ctx * ctx)1256613a2f6bSGordon Ross smb_ctx_get_ssn(struct smb_ctx *ctx)
12574bff34e3Sthurlow {
1258613a2f6bSGordon Ross 	int err = 0;
12594bff34e3Sthurlow 
1260613a2f6bSGordon Ross 	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
12614bff34e3Sthurlow 		return (EINVAL);
12624bff34e3Sthurlow 
12634bff34e3Sthurlow 	/*
1264613a2f6bSGordon Ross 	 * Check whether the driver already has a VC
1265613a2f6bSGordon Ross 	 * we can use.  If so, we're done!
12664bff34e3Sthurlow 	 */
1267613a2f6bSGordon Ross 	err = smb_ctx_findvc(ctx);
1268613a2f6bSGordon Ross 	if (err == 0) {
1269613a2f6bSGordon Ross 		DPRINT("found an existing VC");
12704bff34e3Sthurlow 	} else {
1271613a2f6bSGordon Ross 		/*
12728329232eSGordon Ross 		 * If we're authenticating (real user, not NULL session)
12738329232eSGordon Ross 		 * and we don't yet have a password, return EAUTH and
12748329232eSGordon Ross 		 * the caller will prompt for it and call again.
12758329232eSGordon Ross 		 */
12768329232eSGordon Ross 		if (ctx->ct_user[0] != '\0' &&
12778329232eSGordon Ross 		    ctx->ct_password[0] == '\0')
12788329232eSGordon Ross 			return (EAUTH);
12798329232eSGordon Ross 
12808329232eSGordon Ross 		/*
1281613a2f6bSGordon Ross 		 * This calls the IOD to create a new session.
1282613a2f6bSGordon Ross 		 */
1283613a2f6bSGordon Ross 		DPRINT("setup a new VC");
1284613a2f6bSGordon Ross 		err = smb_ctx_newvc(ctx);
1285613a2f6bSGordon Ross 		if (err != 0)
1286613a2f6bSGordon Ross 			return (err);
1287613a2f6bSGordon Ross 
1288613a2f6bSGordon Ross 		/*
1289613a2f6bSGordon Ross 		 * Call findvc again.  The new VC sould be
1290613a2f6bSGordon Ross 		 * found in the driver this time.
1291613a2f6bSGordon Ross 		 */
1292613a2f6bSGordon Ross 		err = smb_ctx_findvc(ctx);
12934bff34e3Sthurlow 	}
1294613a2f6bSGordon Ross 
1295613a2f6bSGordon Ross 	return (err);
12964bff34e3Sthurlow }
12974bff34e3Sthurlow 
12984bff34e3Sthurlow /*
1299613a2f6bSGordon Ross  * Find or create a tree connection
13004bff34e3Sthurlow  */
1301613a2f6bSGordon Ross int
smb_ctx_get_tree(struct smb_ctx * ctx)1302613a2f6bSGordon Ross smb_ctx_get_tree(struct smb_ctx *ctx)
1303613a2f6bSGordon Ross {
1304613a2f6bSGordon Ross 	smbioc_tcon_t *tcon = NULL;
1305613a2f6bSGordon Ross 	int cmd, err = 0;
1306613a2f6bSGordon Ross 
1307613a2f6bSGordon Ross 	if (ctx->ct_dev_fd < 0 ||
1308613a2f6bSGordon Ross 	    ctx->ct_origshare == NULL) {
1309613a2f6bSGordon Ross 		return (EINVAL);
1310613a2f6bSGordon Ross 	}
1311613a2f6bSGordon Ross 
1312613a2f6bSGordon Ross 	cmd = SMBIOC_TREE_CONNECT;
1313613a2f6bSGordon Ross 	tcon = malloc(sizeof (*tcon));
1314613a2f6bSGordon Ross 	if (tcon == NULL)
1315613a2f6bSGordon Ross 		return (ENOMEM);
1316613a2f6bSGordon Ross 	bzero(tcon, sizeof (*tcon));
1317613a2f6bSGordon Ross 	tcon->tc_flags = SMBLK_CREATE;
1318613a2f6bSGordon Ross 	tcon->tc_opt = 0;
1319613a2f6bSGordon Ross 
1320613a2f6bSGordon Ross 	/* The share name */
1321613a2f6bSGordon Ross 	strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
1322613a2f6bSGordon Ross 	    sizeof (tcon->tc_sh.sh_name));
1323613a2f6bSGordon Ross 
1324613a2f6bSGordon Ross 	/* The share "use" type. */
1325430b4c46SGordon Ross 	tcon->tc_sh.sh_use = ctx->ct_shtype_req;
1326613a2f6bSGordon Ross 
1327613a2f6bSGordon Ross 	/*
1328613a2f6bSGordon Ross 	 * Todo: share passwords for share-level security.
1329613a2f6bSGordon Ross 	 *
1330613a2f6bSGordon Ross 	 * The driver does the actual TCON call.
1331613a2f6bSGordon Ross 	 */
13328329232eSGordon Ross 	if (nsmb_ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1333613a2f6bSGordon Ross 		err = errno;
13344bff34e3Sthurlow 		goto out;
13354bff34e3Sthurlow 	}
1336613a2f6bSGordon Ross 
1337613a2f6bSGordon Ross 	/*
1338613a2f6bSGordon Ross 	 * Check the returned share type
1339613a2f6bSGordon Ross 	 */
1340430b4c46SGordon Ross 	DPRINT("ret. sh_type: \"%d\"", tcon->tc_sh.sh_type);
1341613a2f6bSGordon Ross 	if (ctx->ct_shtype_req != USE_WILDCARD &&
1342430b4c46SGordon Ross 	    ctx->ct_shtype_req != tcon->tc_sh.sh_type) {
1343613a2f6bSGordon Ross 		smb_error(dgettext(TEXT_DOMAIN,
1344613a2f6bSGordon Ross 		    "%s: incompatible share type"),
1345613a2f6bSGordon Ross 		    0, ctx->ct_origshare);
13464bff34e3Sthurlow 	}
13474bff34e3Sthurlow 
13484bff34e3Sthurlow out:
1349613a2f6bSGordon Ross 	if (tcon != NULL)
1350613a2f6bSGordon Ross 		free(tcon);
1351613a2f6bSGordon Ross 
1352613a2f6bSGordon Ross 	return (err);
13534bff34e3Sthurlow }
13544bff34e3Sthurlow 
13554bff34e3Sthurlow /*
13564bff34e3Sthurlow  * Return the hflags2 word for an smb_ctx.
13574bff34e3Sthurlow  */
13584bff34e3Sthurlow int
smb_ctx_flags2(struct smb_ctx * ctx)13594bff34e3Sthurlow smb_ctx_flags2(struct smb_ctx *ctx)
13604bff34e3Sthurlow {
13614bff34e3Sthurlow 	uint16_t flags2;
13624bff34e3Sthurlow 
13638329232eSGordon Ross 	if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
13644bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
13654bff34e3Sthurlow 		    "can't get flags2 for a session"), errno);
13664bff34e3Sthurlow 		return (-1);
13674bff34e3Sthurlow 	}
13684bff34e3Sthurlow 	return (flags2);
13694bff34e3Sthurlow }
13704bff34e3Sthurlow 
13714bff34e3Sthurlow /*
1372613a2f6bSGordon Ross  * Get the transport level session key.
1373613a2f6bSGordon Ross  * Must already have an active SMB session.
1374613a2f6bSGordon Ross  */
1375613a2f6bSGordon Ross int
smb_fh_getssnkey(int dev_fd,uchar_t * key,size_t len)1376430b4c46SGordon Ross smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len)
1377613a2f6bSGordon Ross {
1378613a2f6bSGordon Ross 	if (len < SMBIOC_HASH_SZ)
1379613a2f6bSGordon Ross 		return (EINVAL);
1380613a2f6bSGordon Ross 
13818329232eSGordon Ross 	if (nsmb_ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1382613a2f6bSGordon Ross 		return (errno);
1383613a2f6bSGordon Ross 
1384613a2f6bSGordon Ross 	return (0);
1385613a2f6bSGordon Ross }
1386613a2f6bSGordon Ross 
1387613a2f6bSGordon Ross /*
1388613a2f6bSGordon Ross  * RC file parsing stuff
1389613a2f6bSGordon Ross  */
1390613a2f6bSGordon Ross 
139115359501SGordon Ross static struct nv
139215359501SGordon Ross minauth_table[] = {
1393613a2f6bSGordon Ross 	/* Allowed auth. types */
1394613a2f6bSGordon Ross 	{ "kerberos",	SMB_AT_KRB5 },
1395613a2f6bSGordon Ross 	{ "ntlmv2",	SMB_AT_KRB5|SMB_AT_NTLM2 },
1396613a2f6bSGordon Ross 	{ "ntlm",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
1397613a2f6bSGordon Ross 	{ "lm",		SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
1398613a2f6bSGordon Ross 	{ "none",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
1399613a2f6bSGordon Ross 			SMB_AT_ANON },
1400613a2f6bSGordon Ross 	{ NULL }
1401613a2f6bSGordon Ross };
1402613a2f6bSGordon Ross 
1403adee6784SGordon Ross int
smb_cf_minauth_from_str(char * str)1404adee6784SGordon Ross smb_cf_minauth_from_str(char *str)
1405adee6784SGordon Ross {
1406adee6784SGordon Ross 	struct nv *nvp;
1407adee6784SGordon Ross 
1408adee6784SGordon Ross 	for (nvp = minauth_table; nvp->name; nvp++)
1409adee6784SGordon Ross 		if (strcmp(nvp->name, str) == 0)
1410adee6784SGordon Ross 			return (nvp->value);
1411adee6784SGordon Ross 	return (-1);
1412adee6784SGordon Ross }
1413adee6784SGordon Ross 
1414*686670eaSGordon Ross /*
1415*686670eaSGordon Ross  * SMB 2.1 is the oldest SMB2 dialect implemented (we skipped SMB 2.002)
1416*686670eaSGordon Ross  * so if we see a_protocol value of just "2" assume they meant 2.1
1417*686670eaSGordon Ross  */
1418adee6784SGordon Ross static struct nv
1419adee6784SGordon Ross smbver_table[] = {
1420*686670eaSGordon Ross 	{ "3.02",	SMB2_DIALECT_0302 },
1421*686670eaSGordon Ross 	{ "3.0",	SMB2_DIALECT_0300 },
1422adee6784SGordon Ross 	{ "2.1",	SMB2_DIALECT_0210 },
1423*686670eaSGordon Ross 	{ "2",		SMB2_DIALECT_0210 },
1424adee6784SGordon Ross 	{ "1",		1 },
1425adee6784SGordon Ross 	{ NULL,		0 }
1426adee6784SGordon Ross };
1427adee6784SGordon Ross 
1428adee6784SGordon Ross int
smb_cf_version_from_str(char * str)1429adee6784SGordon Ross smb_cf_version_from_str(char *str)
1430adee6784SGordon Ross {
1431adee6784SGordon Ross 	struct nv *nvp;
1432adee6784SGordon Ross 
1433adee6784SGordon Ross 	for (nvp = smbver_table; nvp->name; nvp++)
1434adee6784SGordon Ross 		if (strcmp(nvp->name, str) == 0)
1435adee6784SGordon Ross 			return (nvp->value);
1436adee6784SGordon Ross 	return (-1);
1437adee6784SGordon Ross }
1438613a2f6bSGordon Ross 
1439613a2f6bSGordon Ross /*
14404bff34e3Sthurlow  * level values:
14414bff34e3Sthurlow  * 0 - default
14424bff34e3Sthurlow  * 1 - server
14434bff34e3Sthurlow  * 2 - server:user
14444bff34e3Sthurlow  * 3 - server:user:share
14454bff34e3Sthurlow  */
14464bff34e3Sthurlow static int
smb_ctx_readrcsection(struct smb_ctx * ctx,const char * sname,int level)14474bff34e3Sthurlow smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
14484bff34e3Sthurlow {
14494bff34e3Sthurlow 	char *p;
1450adee6784SGordon Ross 	int ival;
14514bff34e3Sthurlow 	int error;
1452adee6784SGordon Ross 	int minver, maxver;
14534bff34e3Sthurlow 
1454613a2f6bSGordon Ross #ifdef	KICONV_SUPPORT
14554bff34e3Sthurlow 	if (level > 0) {
14564bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "charsets", &p);
14574bff34e3Sthurlow 		if (p) {
14584bff34e3Sthurlow 			error = smb_ctx_setcharset(ctx, p);
14594bff34e3Sthurlow 			if (error)
14604bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14614bff34e3Sthurlow 	"charset specification in the section '%s' ignored"),
14624bff34e3Sthurlow 				    error, sname);
14634bff34e3Sthurlow 		}
14644bff34e3Sthurlow 	}
14654bff34e3Sthurlow #endif
14664bff34e3Sthurlow 
14674bff34e3Sthurlow 	if (level <= 1) {
14684bff34e3Sthurlow 		/* Section is: [default] or [server] */
14694bff34e3Sthurlow 
1470adee6784SGordon Ross 		/*
1471adee6784SGordon Ross 		 * Handle min_protocol, max_protocol
1472adee6784SGordon Ross 		 * (SMB protocol versions)
1473adee6784SGordon Ross 		 */
1474adee6784SGordon Ross 		minver = -1;
1475adee6784SGordon Ross 		rc_getstringptr(smb_rc, sname, "min_protocol", &p);
1476adee6784SGordon Ross 		if (p != NULL) {
1477adee6784SGordon Ross 			minver = smb_cf_version_from_str(p);
1478adee6784SGordon Ross 			if (minver == -1) {
1479adee6784SGordon Ross 				smb_error(dgettext(TEXT_DOMAIN,
1480adee6784SGordon Ross "invalid min_protocol value \"%s\" specified in the section %s"),
1481adee6784SGordon Ross 				    0, p, sname);
1482adee6784SGordon Ross 			}
1483adee6784SGordon Ross 		}
1484adee6784SGordon Ross 		maxver = -1;
1485adee6784SGordon Ross 		rc_getstringptr(smb_rc, sname, "max_protocol", &p);
1486adee6784SGordon Ross 		if (p != NULL) {
1487adee6784SGordon Ross 			maxver = smb_cf_version_from_str(p);
1488adee6784SGordon Ross 			if (maxver == -1) {
1489adee6784SGordon Ross 				smb_error(dgettext(TEXT_DOMAIN,
1490adee6784SGordon Ross "invalid max_protocol value \"%s\" specified in the section %s"),
1491adee6784SGordon Ross 				    0, p, sname);
1492adee6784SGordon Ross 			}
1493adee6784SGordon Ross 		}
1494adee6784SGordon Ross 
1495adee6784SGordon Ross 		/*
1496adee6784SGordon Ross 		 * If setting both min/max protocol,
1497adee6784SGordon Ross 		 * validate against each other
1498adee6784SGordon Ross 		 */
1499adee6784SGordon Ross 		if (minver != -1 && maxver != -1) {
1500adee6784SGordon Ross 			if (minver > maxver) {
1501adee6784SGordon Ross 				smb_error(dgettext(TEXT_DOMAIN,
1502adee6784SGordon Ross "invalid min/max protocol combination in the section %s"),
1503adee6784SGordon Ross 				    0, sname);
1504adee6784SGordon Ross 			} else {
1505adee6784SGordon Ross 				ctx->ct_minver = minver;
1506adee6784SGordon Ross 				ctx->ct_maxver = maxver;
1507adee6784SGordon Ross 			}
1508adee6784SGordon Ross 		}
1509adee6784SGordon Ross 
1510adee6784SGordon Ross 		/*
1511adee6784SGordon Ross 		 * Setting just min or max, validate against
1512adee6784SGordon Ross 		 * current settings
1513adee6784SGordon Ross 		 */
1514adee6784SGordon Ross 		if (minver != -1) {
1515adee6784SGordon Ross 			if (minver > ctx->ct_maxver) {
1516adee6784SGordon Ross 				smb_error(dgettext(TEXT_DOMAIN,
1517adee6784SGordon Ross "invalid min/max protocol combination in the section %s"),
1518adee6784SGordon Ross 				    0, sname);
1519adee6784SGordon Ross 			} else {
1520adee6784SGordon Ross 				ctx->ct_minver = minver;
1521adee6784SGordon Ross 			}
1522adee6784SGordon Ross 		}
1523adee6784SGordon Ross 		if (maxver != -1) {
1524adee6784SGordon Ross 			if (maxver < ctx->ct_minver) {
1525adee6784SGordon Ross 				smb_error(dgettext(TEXT_DOMAIN,
1526adee6784SGordon Ross "invalid min/max protocol combination in the section %s"),
1527adee6784SGordon Ross 				    0, sname);
1528adee6784SGordon Ross 			} else {
1529adee6784SGordon Ross 				ctx->ct_maxver = maxver;
1530adee6784SGordon Ross 			}
1531adee6784SGordon Ross 		}
1532adee6784SGordon Ross 
15334bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "minauth", &p);
15344bff34e3Sthurlow 		if (p) {
15354bff34e3Sthurlow 			/*
15364bff34e3Sthurlow 			 * "minauth" was set in this section; override
15374bff34e3Sthurlow 			 * the current minimum authentication setting.
15384bff34e3Sthurlow 			 */
1539adee6784SGordon Ross 			ival = smb_cf_minauth_from_str(p);
1540adee6784SGordon Ross 			if (ival != -1) {
1541adee6784SGordon Ross 				ctx->ct_minauth = ival;
1542adee6784SGordon Ross 			} else {
15434bff34e3Sthurlow 				/*
15444bff34e3Sthurlow 				 * Unknown minimum authentication level.
15454bff34e3Sthurlow 				 */
15464bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
15474bff34e3Sthurlow "invalid minimum authentication level \"%s\" specified in the section %s"),
15484bff34e3Sthurlow 				    0, p, sname);
15494bff34e3Sthurlow 				return (EINVAL);
15504bff34e3Sthurlow 			}
15514bff34e3Sthurlow 		}
15524bff34e3Sthurlow 
15539c9af259SGordon Ross 		rc_getstringptr(smb_rc, sname, "signing", &p);
15549c9af259SGordon Ross 		if (p) {
15559c9af259SGordon Ross 			/*
15569c9af259SGordon Ross 			 * "signing" was set in this section; override
155702d09e03SGordon Ross 			 * the current signing settings.  Note:
155802d09e03SGordon Ross 			 * setsigning flags are: enable, require
15599c9af259SGordon Ross 			 */
15609c9af259SGordon Ross 			if (strcmp(p, "disabled") == 0) {
156102d09e03SGordon Ross 				(void) smb_ctx_setsigning(ctx, FALSE, FALSE);
15629c9af259SGordon Ross 			} else if (strcmp(p, "enabled") == 0) {
156302d09e03SGordon Ross 				(void) smb_ctx_setsigning(ctx, TRUE, FALSE);
15649c9af259SGordon Ross 			} else if (strcmp(p, "required") == 0) {
156502d09e03SGordon Ross 				(void) smb_ctx_setsigning(ctx, TRUE, TRUE);
15669c9af259SGordon Ross 			} else {
15679c9af259SGordon Ross 				/*
15689c9af259SGordon Ross 				 * Unknown "signing" value.
15699c9af259SGordon Ross 				 */
15709c9af259SGordon Ross 				smb_error(dgettext(TEXT_DOMAIN,
15719c9af259SGordon Ross "invalid signing policy \"%s\" specified in the section %s"),
15729c9af259SGordon Ross 				    0, p, sname);
15739c9af259SGordon Ross 				return (EINVAL);
15749c9af259SGordon Ross 			}
15759c9af259SGordon Ross 		}
15769c9af259SGordon Ross 
15774bff34e3Sthurlow 		/*
15784bff34e3Sthurlow 		 * Domain name.  Allow both keywords:
15794bff34e3Sthurlow 		 * "workgroup", "domain"
15804bff34e3Sthurlow 		 *
15814bff34e3Sthurlow 		 * Note: these are NOT marked "from CMD".
15824bff34e3Sthurlow 		 * See long comment at smb_ctx_init()
15834bff34e3Sthurlow 		 */
15844bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "workgroup", &p);
15854bff34e3Sthurlow 		if (p) {
1586613a2f6bSGordon Ross 			error = smb_ctx_setdomain(ctx, p, 0);
15874bff34e3Sthurlow 			if (error)
15884bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
15894bff34e3Sthurlow 				    "workgroup specification in the "
15904bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
15914bff34e3Sthurlow 		}
15924bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "domain", &p);
15934bff34e3Sthurlow 		if (p) {
1594613a2f6bSGordon Ross 			error = smb_ctx_setdomain(ctx, p, 0);
15954bff34e3Sthurlow 			if (error)
15964bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
15974bff34e3Sthurlow 				    "domain specification in the "
15984bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
15994bff34e3Sthurlow 		}
16004bff34e3Sthurlow 
16014bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "user", &p);
16024bff34e3Sthurlow 		if (p) {
16034bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, p, 0);
16044bff34e3Sthurlow 			if (error)
16054bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
16064bff34e3Sthurlow 				    "user specification in the "
16074bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
16084bff34e3Sthurlow 		}
16094bff34e3Sthurlow 	}
16104bff34e3Sthurlow 
16114bff34e3Sthurlow 	if (level == 1) {
16124bff34e3Sthurlow 		/* Section is: [server] */
16134bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "addr", &p);
16144bff34e3Sthurlow 		if (p) {
16154bff34e3Sthurlow 			error = smb_ctx_setsrvaddr(ctx, p);
16164bff34e3Sthurlow 			if (error) {
16174bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
16184bff34e3Sthurlow 				    "invalid address specified in section %s"),
16194bff34e3Sthurlow 				    0, sname);
16204bff34e3Sthurlow 				return (error);
16214bff34e3Sthurlow 			}
16224bff34e3Sthurlow 		}
16234bff34e3Sthurlow 	}
16244bff34e3Sthurlow 
16254bff34e3Sthurlow 	rc_getstringptr(smb_rc, sname, "password", &p);
16264bff34e3Sthurlow 	if (p) {
16274bff34e3Sthurlow 		error = smb_ctx_setpassword(ctx, p, 0);
16284bff34e3Sthurlow 		if (error)
16294bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
16304bff34e3Sthurlow 	    "password specification in the section '%s' ignored"),
16314bff34e3Sthurlow 			    error, sname);
16324bff34e3Sthurlow 	}
16334bff34e3Sthurlow 
16344bff34e3Sthurlow 	return (0);
16354bff34e3Sthurlow }
16364bff34e3Sthurlow 
16374bff34e3Sthurlow /*
16384bff34e3Sthurlow  * read rc file as follows:
16394bff34e3Sthurlow  * 0: read [default] section
16404bff34e3Sthurlow  * 1: override with [server] section
16414bff34e3Sthurlow  * 2: override with [server:user] section
16424bff34e3Sthurlow  * 3: override with [server:user:share] section
16434bff34e3Sthurlow  * Since absence of rcfile is not fatal, silently ignore this fact.
16444bff34e3Sthurlow  * smb_rc file should be closed by caller.
16454bff34e3Sthurlow  */
16464bff34e3Sthurlow int
smb_ctx_readrc(struct smb_ctx * ctx)16474bff34e3Sthurlow smb_ctx_readrc(struct smb_ctx *ctx)
16484bff34e3Sthurlow {
1649430b4c46SGordon Ross 	char pwbuf[NSS_BUFLEN_PASSWD];
1650430b4c46SGordon Ross 	struct passwd pw;
1651613a2f6bSGordon Ross 	char *sname = NULL;
1652613a2f6bSGordon Ross 	int sname_max;
1653613a2f6bSGordon Ross 	int err = 0;
16544bff34e3Sthurlow 
1655430b4c46SGordon Ross 	/*
1656430b4c46SGordon Ross 	 * If the user name is not specified some other way,
1657430b4c46SGordon Ross 	 * use the current user name.  Also save the homedir.
1658430b4c46SGordon Ross 	 * NB: ct_home=NULL is allowed, and we don't want to
1659430b4c46SGordon Ross 	 * bail out with an error for a missing ct_home.
1660430b4c46SGordon Ross 	 */
1661430b4c46SGordon Ross 	if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
1662430b4c46SGordon Ross 		if (ctx->ct_user[0] == 0)
1663430b4c46SGordon Ross 			(void) smb_ctx_setuser(ctx, pw.pw_name, B_FALSE);
1664430b4c46SGordon Ross 		if (ctx->ct_home == NULL)
1665430b4c46SGordon Ross 			ctx->ct_home = strdup(pw.pw_dir);
1666430b4c46SGordon Ross 	}
1667430b4c46SGordon Ross 
1668430b4c46SGordon Ross 	if ((err = smb_open_rcfile(ctx->ct_home)) != 0) {
1669613a2f6bSGordon Ross 		DPRINT("smb_open_rcfile, err=%d", err);
1670613a2f6bSGordon Ross 		/* ignore any error here */
1671613a2f6bSGordon Ross 		return (0);
1672613a2f6bSGordon Ross 	}
1673613a2f6bSGordon Ross 
1674613a2f6bSGordon Ross 	sname_max = 3 * SMBIOC_MAX_NAME + 4;
1675613a2f6bSGordon Ross 	sname = malloc(sname_max);
1676613a2f6bSGordon Ross 	if (sname == NULL) {
1677613a2f6bSGordon Ross 		err = ENOMEM;
16784bff34e3Sthurlow 		goto done;
1679613a2f6bSGordon Ross 	}
16804bff34e3Sthurlow 
16814bff34e3Sthurlow 	/*
16824bff34e3Sthurlow 	 * default parameters (level=0)
16834bff34e3Sthurlow 	 */
16844bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, "default", 0);
16854bff34e3Sthurlow 	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
16864bff34e3Sthurlow 
16874bff34e3Sthurlow 	/*
16884bff34e3Sthurlow 	 * If we don't have a server name, we can't read any of the
16894bff34e3Sthurlow 	 * [server...] sections.
16904bff34e3Sthurlow 	 */
1691613a2f6bSGordon Ross 	if (ctx->ct_fullserver == NULL)
16924bff34e3Sthurlow 		goto done;
16934bff34e3Sthurlow 	/*
16944bff34e3Sthurlow 	 * SERVER parameters.
16954bff34e3Sthurlow 	 */
1696613a2f6bSGordon Ross 	smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
16974bff34e3Sthurlow 
16984bff34e3Sthurlow 	/*
16994bff34e3Sthurlow 	 * If we don't have a user name, we can't read any of the
17004bff34e3Sthurlow 	 * [server:user...] sections.
17014bff34e3Sthurlow 	 */
1702613a2f6bSGordon Ross 	if (ctx->ct_user[0] == 0)
17034bff34e3Sthurlow 		goto done;
17044bff34e3Sthurlow 	/*
17054bff34e3Sthurlow 	 * SERVER:USER parameters
17064bff34e3Sthurlow 	 */
1707613a2f6bSGordon Ross 	snprintf(sname, sname_max, "%s:%s",
1708613a2f6bSGordon Ross 	    ctx->ct_fullserver,
1709613a2f6bSGordon Ross 	    ctx->ct_user);
17104bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, sname, 2);
17114bff34e3Sthurlow 
1712613a2f6bSGordon Ross 
17134bff34e3Sthurlow 	/*
17144bff34e3Sthurlow 	 * If we don't have a share name, we can't read any of the
17154bff34e3Sthurlow 	 * [server:user:share] sections.
17164bff34e3Sthurlow 	 */
1717613a2f6bSGordon Ross 	if (ctx->ct_origshare == NULL)
1718613a2f6bSGordon Ross 		goto done;
17194bff34e3Sthurlow 	/*
17204bff34e3Sthurlow 	 * SERVER:USER:SHARE parameters
17214bff34e3Sthurlow 	 */
1722613a2f6bSGordon Ross 	snprintf(sname, sname_max, "%s:%s:%s",
1723613a2f6bSGordon Ross 	    ctx->ct_fullserver,
1724613a2f6bSGordon Ross 	    ctx->ct_user,
1725613a2f6bSGordon Ross 	    ctx->ct_origshare);
17264bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, sname, 3);
17274bff34e3Sthurlow 
17284bff34e3Sthurlow done:
1729613a2f6bSGordon Ross 	if (sname)
1730613a2f6bSGordon Ross 		free(sname);
1731613a2f6bSGordon Ross 	smb_close_rcfile();
17324bff34e3Sthurlow 	if (smb_debug)
17334bff34e3Sthurlow 		dump_ctx("after smb_ctx_readrc", ctx);
1734613a2f6bSGordon Ross 	if (err)
1735613a2f6bSGordon Ross 		DPRINT("err=%d\n", err);
17364bff34e3Sthurlow 
1737613a2f6bSGordon Ross 	return (err);
17384bff34e3Sthurlow }
1739430b4c46SGordon Ross 
1740430b4c46SGordon Ross void
smbfs_set_default_domain(const char * domain)1741430b4c46SGordon Ross smbfs_set_default_domain(const char *domain)
1742430b4c46SGordon Ross {
1743430b4c46SGordon Ross 	strlcpy(default_domain, domain, sizeof (default_domain));
1744430b4c46SGordon Ross }
1745430b4c46SGordon Ross 
1746430b4c46SGordon Ross void
smbfs_set_default_user(const char * user)1747430b4c46SGordon Ross smbfs_set_default_user(const char *user)
1748430b4c46SGordon Ross {
1749430b4c46SGordon Ross 	strlcpy(default_user, user, sizeof (default_user));
1750430b4c46SGordon Ross }
1751