xref: /titanic_50/usr/src/lib/libsmbfs/smb/ctx.c (revision ae3d7f90695ef456a6da4f7bdccd448ebe0b99e1)
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.
379c9af259SGordon Ross  */
384bff34e3Sthurlow 
394bff34e3Sthurlow #include <sys/param.h>
404bff34e3Sthurlow #include <sys/ioctl.h>
414bff34e3Sthurlow #include <sys/time.h>
424bff34e3Sthurlow #include <sys/mount.h>
434bff34e3Sthurlow #include <sys/types.h>
444bff34e3Sthurlow #include <sys/byteorder.h>
454bff34e3Sthurlow 
464bff34e3Sthurlow #include <fcntl.h>
474bff34e3Sthurlow #include <ctype.h>
484bff34e3Sthurlow #include <errno.h>
494bff34e3Sthurlow #include <stdio.h>
504bff34e3Sthurlow #include <string.h>
514bff34e3Sthurlow #include <strings.h>
524bff34e3Sthurlow #include <stdlib.h>
534bff34e3Sthurlow #include <pwd.h>
544bff34e3Sthurlow #include <grp.h>
554bff34e3Sthurlow #include <unistd.h>
564bff34e3Sthurlow #include <libintl.h>
574bff34e3Sthurlow #include <assert.h>
584bff34e3Sthurlow #include <nss_dbdefs.h>
594bff34e3Sthurlow 
60613a2f6bSGordon Ross #include <cflib.h>
614bff34e3Sthurlow #include <netsmb/smb_lib.h>
624bff34e3Sthurlow #include <netsmb/netbios.h>
634bff34e3Sthurlow #include <netsmb/nb_lib.h>
644bff34e3Sthurlow #include <netsmb/smb_dev.h>
654bff34e3Sthurlow 
66613a2f6bSGordon Ross #include "charsets.h"
67613a2f6bSGordon Ross #include "spnego.h"
684bff34e3Sthurlow #include "derparse.h"
699c9af259SGordon Ross #include "private.h"
70613a2f6bSGordon Ross #include "ntlm.h"
714bff34e3Sthurlow 
72613a2f6bSGordon Ross #ifndef FALSE
73613a2f6bSGordon Ross #define	FALSE	0
74613a2f6bSGordon Ross #endif
75613a2f6bSGordon Ross #ifndef TRUE
76613a2f6bSGordon Ross #define	TRUE	1
77613a2f6bSGordon Ross #endif
784bff34e3Sthurlow 
7915359501SGordon Ross struct nv {
8015359501SGordon Ross 	char *name;
8115359501SGordon Ross 	int value;
8215359501SGordon Ross };
834bff34e3Sthurlow 
844bff34e3Sthurlow /* These two may be set by commands. */
854bff34e3Sthurlow int smb_debug, smb_verbose;
864bff34e3Sthurlow 
874bff34e3Sthurlow /*
88613a2f6bSGordon Ross  * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
89613a2f6bSGordon Ross  */
90613a2f6bSGordon Ross const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
91613a2f6bSGordon Ross 
92613a2f6bSGordon Ross /*
939c9af259SGordon Ross  * Give the RPC library a callback hook that will be
949c9af259SGordon Ross  * called whenever we destroy or reinit an smb_ctx_t.
959c9af259SGordon Ross  * The name rpc_cleanup_smbctx() is legacy, and was
969c9af259SGordon Ross  * originally a direct call into the RPC code.
974bff34e3Sthurlow  */
989c9af259SGordon Ross static smb_ctx_close_hook_t close_hook;
994bff34e3Sthurlow static void
1004bff34e3Sthurlow rpc_cleanup_smbctx(struct smb_ctx *ctx)
1014bff34e3Sthurlow {
1029c9af259SGordon Ross 	if (close_hook)
1039c9af259SGordon Ross 		(*close_hook)(ctx);
1044bff34e3Sthurlow }
1059c9af259SGordon Ross void
1069c9af259SGordon Ross smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
1079c9af259SGordon Ross {
1089c9af259SGordon Ross 	close_hook = hook;
1099c9af259SGordon Ross }
1104bff34e3Sthurlow 
1114bff34e3Sthurlow void
1124bff34e3Sthurlow dump_ctx_flags(int flags)
1134bff34e3Sthurlow {
1144bff34e3Sthurlow 	printf(" Flags: ");
1154bff34e3Sthurlow 	if (flags == 0)
1164bff34e3Sthurlow 		printf("0");
1174bff34e3Sthurlow 	if (flags & SMBCF_NOPWD)
1184bff34e3Sthurlow 		printf("NOPWD ");
1194bff34e3Sthurlow 	if (flags & SMBCF_SRIGHTS)
1204bff34e3Sthurlow 		printf("SRIGHTS ");
1214bff34e3Sthurlow 	if (flags & SMBCF_LOCALE)
1224bff34e3Sthurlow 		printf("LOCALE ");
1234bff34e3Sthurlow 	if (flags & SMBCF_CMD_DOM)
1244bff34e3Sthurlow 		printf("CMD_DOM ");
1254bff34e3Sthurlow 	if (flags & SMBCF_CMD_USR)
1264bff34e3Sthurlow 		printf("CMD_USR ");
1274bff34e3Sthurlow 	if (flags & SMBCF_CMD_PW)
1284bff34e3Sthurlow 		printf("CMD_PW ");
1294bff34e3Sthurlow 	if (flags & SMBCF_RESOLVED)
1304bff34e3Sthurlow 		printf("RESOLVED ");
1314bff34e3Sthurlow 	if (flags & SMBCF_KCBAD)
1324bff34e3Sthurlow 		printf("KCBAD ");
1334bff34e3Sthurlow 	if (flags & SMBCF_KCFOUND)
1344bff34e3Sthurlow 		printf("KCFOUND ");
1354bff34e3Sthurlow 	if (flags & SMBCF_BROWSEOK)
1364bff34e3Sthurlow 		printf("BROWSEOK ");
1374bff34e3Sthurlow 	if (flags & SMBCF_AUTHREQ)
1384bff34e3Sthurlow 		printf("AUTHREQ ");
1394bff34e3Sthurlow 	if (flags & SMBCF_KCSAVE)
1404bff34e3Sthurlow 		printf("KCSAVE  ");
1414bff34e3Sthurlow 	if (flags & SMBCF_XXX)
1424bff34e3Sthurlow 		printf("XXX ");
1434bff34e3Sthurlow 	if (flags & SMBCF_SSNACTIVE)
1444bff34e3Sthurlow 		printf("SSNACTIVE ");
1454bff34e3Sthurlow 	if (flags & SMBCF_KCDOMAIN)
1464bff34e3Sthurlow 		printf("KCDOMAIN ");
1474bff34e3Sthurlow 	printf("\n");
1484bff34e3Sthurlow }
1494bff34e3Sthurlow 
1504bff34e3Sthurlow void
151613a2f6bSGordon Ross dump_iod_ssn(smb_iod_ssn_t *is)
1524bff34e3Sthurlow {
153613a2f6bSGordon Ross 	static const char zeros[NTLM_HASH_SZ] = {0};
154613a2f6bSGordon Ross 	struct smbioc_ossn *ssn = &is->iod_ossn;
1554bff34e3Sthurlow 
156613a2f6bSGordon Ross 	printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
157613a2f6bSGordon Ross 	dump_sockaddr(&ssn->ssn_srvaddr.sa);
158613a2f6bSGordon Ross 	printf(" dom=\"%s\", user=\"%s\"\n",
159613a2f6bSGordon Ross 	    ssn->ssn_domain, ssn->ssn_user);
160613a2f6bSGordon Ross 	printf(" ct_vopt=0x%x, ct_owner=%d\n",
161613a2f6bSGordon Ross 	    ssn->ssn_vopt, ssn->ssn_owner);
162613a2f6bSGordon Ross 	printf(" ct_authflags=0x%x\n", is->iod_authflags);
163613a2f6bSGordon Ross 
164613a2f6bSGordon Ross 	printf(" ct_nthash:");
165613a2f6bSGordon Ross 	if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
166613a2f6bSGordon Ross 		smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
167613a2f6bSGordon Ross 	else
168613a2f6bSGordon Ross 		printf(" {0}\n");
169613a2f6bSGordon Ross 
170613a2f6bSGordon Ross 	printf(" ct_lmhash:");
171613a2f6bSGordon Ross 	if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
172613a2f6bSGordon Ross 		smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
173613a2f6bSGordon Ross 	else
174613a2f6bSGordon Ross 		printf(" {0}\n");
1754bff34e3Sthurlow }
1764bff34e3Sthurlow 
1774bff34e3Sthurlow void
1784bff34e3Sthurlow dump_ctx(char *where, struct smb_ctx *ctx)
1794bff34e3Sthurlow {
1804bff34e3Sthurlow 	printf("context %s:\n", where);
1814bff34e3Sthurlow 	dump_ctx_flags(ctx->ct_flags);
1824bff34e3Sthurlow 
183613a2f6bSGordon Ross 	if (ctx->ct_locname)
1844bff34e3Sthurlow 		printf(" localname=\"%s\"", ctx->ct_locname);
185613a2f6bSGordon Ross 	else
186613a2f6bSGordon Ross 		printf(" localname=NULL");
1874bff34e3Sthurlow 
1884bff34e3Sthurlow 	if (ctx->ct_fullserver)
1894bff34e3Sthurlow 		printf(" fullserver=\"%s\"", ctx->ct_fullserver);
1904bff34e3Sthurlow 	else
1914bff34e3Sthurlow 		printf(" fullserver=NULL");
1924bff34e3Sthurlow 
193613a2f6bSGordon Ross 	if (ctx->ct_srvaddr_s)
194613a2f6bSGordon Ross 		printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
1954bff34e3Sthurlow 	else
196613a2f6bSGordon Ross 		printf(" srvaddr_s=NULL\n");
1974bff34e3Sthurlow 
198613a2f6bSGordon Ross 	if (ctx->ct_addrinfo)
199613a2f6bSGordon Ross 		dump_addrinfo(ctx->ct_addrinfo);
200613a2f6bSGordon Ross 	else
201613a2f6bSGordon Ross 		printf(" ct_addrinfo = NULL\n");
202613a2f6bSGordon Ross 
203613a2f6bSGordon Ross 	dump_iod_ssn(&ctx->ct_iod_ssn);
204613a2f6bSGordon Ross 
205613a2f6bSGordon Ross 	printf(" share_name=\"%s\", share_type=%d\n",
206613a2f6bSGordon Ross 	    ctx->ct_origshare ? ctx->ct_origshare : "",
207613a2f6bSGordon Ross 	    ctx->ct_shtype_req);
208613a2f6bSGordon Ross 
209613a2f6bSGordon Ross 	/* dump_iod_work()? */
210613a2f6bSGordon Ross }
211613a2f6bSGordon Ross 
212613a2f6bSGordon Ross int
213613a2f6bSGordon Ross smb_ctx_alloc(struct smb_ctx **ctx_pp)
214613a2f6bSGordon Ross {
215613a2f6bSGordon Ross 	smb_ctx_t *ctx;
216613a2f6bSGordon Ross 	int err;
217613a2f6bSGordon Ross 
218613a2f6bSGordon Ross 	ctx = malloc(sizeof (*ctx));
219613a2f6bSGordon Ross 	if (ctx == NULL)
220613a2f6bSGordon Ross 		return (ENOMEM);
221613a2f6bSGordon Ross 	err = smb_ctx_init(ctx);
222613a2f6bSGordon Ross 	if (err != 0) {
223613a2f6bSGordon Ross 		free(ctx);
224613a2f6bSGordon Ross 		return (err);
225613a2f6bSGordon Ross 	}
226613a2f6bSGordon Ross 	*ctx_pp = ctx;
227613a2f6bSGordon Ross 	return (0);
2284bff34e3Sthurlow }
2294bff34e3Sthurlow 
2304bff34e3Sthurlow /*
231613a2f6bSGordon Ross  * Initialize an smb_ctx struct (defaults)
232613a2f6bSGordon Ross  */
233613a2f6bSGordon Ross int
234613a2f6bSGordon Ross smb_ctx_init(struct smb_ctx *ctx)
235613a2f6bSGordon Ross {
236613a2f6bSGordon Ross 	char pwbuf[NSS_BUFLEN_PASSWD];
237613a2f6bSGordon Ross 	struct passwd pw;
238613a2f6bSGordon Ross 	int error = 0;
239613a2f6bSGordon Ross 
240613a2f6bSGordon Ross 	bzero(ctx, sizeof (*ctx));
241613a2f6bSGordon Ross 
242613a2f6bSGordon Ross 	error = nb_ctx_create(&ctx->ct_nb);
243613a2f6bSGordon Ross 	if (error)
244613a2f6bSGordon Ross 		return (error);
245613a2f6bSGordon Ross 
246613a2f6bSGordon Ross 	ctx->ct_dev_fd = -1;
2476b2bcd8eSGordon Ross 	ctx->ct_door_fd = -1;
248613a2f6bSGordon Ross 	ctx->ct_tran_fd = -1;
249613a2f6bSGordon Ross 	ctx->ct_parsedlevel = SMBL_NONE;
250613a2f6bSGordon Ross 	ctx->ct_minlevel = SMBL_NONE;
251613a2f6bSGordon Ross 	ctx->ct_maxlevel = SMBL_PATH;
252613a2f6bSGordon Ross 
253613a2f6bSGordon Ross 	/* Fill in defaults */
254613a2f6bSGordon Ross 	ctx->ct_vopt = SMBVOPT_EXT_SEC;
255613a2f6bSGordon Ross 	ctx->ct_owner = SMBM_ANY_OWNER;
256613a2f6bSGordon Ross 	ctx->ct_authflags = SMB_AT_DEFAULT;
257613a2f6bSGordon Ross 	ctx->ct_minauth = SMB_AT_DEFAULT;
258613a2f6bSGordon Ross 
25902d09e03SGordon Ross 	error = nb_ctx_setscope(ctx->ct_nb, "");
26002d09e03SGordon Ross 	if (error)
26102d09e03SGordon Ross 		return (error);
262613a2f6bSGordon Ross 
263613a2f6bSGordon Ross 	/*
264613a2f6bSGordon Ross 	 * if the user name is not specified some other way,
265613a2f6bSGordon Ross 	 * use the current user name (built-in default)
266613a2f6bSGordon Ross 	 */
267613a2f6bSGordon Ross 	if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
26802d09e03SGordon Ross 		error = smb_ctx_setuser(ctx, pw.pw_name, 0);
26902d09e03SGordon Ross 		if (error)
27002d09e03SGordon Ross 			return (error);
271613a2f6bSGordon Ross 		ctx->ct_home = strdup(pw.pw_name);
27202d09e03SGordon Ross 		if (ctx->ct_home == NULL)
27302d09e03SGordon Ross 			return (ENOMEM);
274613a2f6bSGordon Ross 	}
275613a2f6bSGordon Ross 
276613a2f6bSGordon Ross 	/*
277613a2f6bSGordon Ross 	 * Set a built-in default domain (workgroup).
278613a2f6bSGordon Ross 	 * Using the Windows/NT default for now.
279613a2f6bSGordon Ross 	 */
28002d09e03SGordon Ross 	error = smb_ctx_setdomain(ctx, "WORKGROUP", 0);
28102d09e03SGordon Ross 	if (error)
28202d09e03SGordon Ross 		return (error);
283613a2f6bSGordon Ross 
284613a2f6bSGordon Ross 	return (error);
285613a2f6bSGordon Ross }
286613a2f6bSGordon Ross 
287613a2f6bSGordon Ross /*
288613a2f6bSGordon Ross  * "Scan" the command line args to find the server name,
289613a2f6bSGordon Ross  * user name, and share name, as needed.  We need these
290613a2f6bSGordon Ross  * before reading the RC files and/or sharectl values.
2914bff34e3Sthurlow  *
2924bff34e3Sthurlow  * The sequence for getting all the members filled in
2934bff34e3Sthurlow  * has some tricky aspects.  Here's how it works:
2944bff34e3Sthurlow  *
2954bff34e3Sthurlow  * The search order for options is as follows:
2964bff34e3Sthurlow  *   command line options
2974bff34e3Sthurlow  *   values parsed from UNC path (cmd)
2984bff34e3Sthurlow  *   values from RC file (per-user)
2994bff34e3Sthurlow  *   values from SMF (system-wide)
3004bff34e3Sthurlow  *   built-in defaults
3014bff34e3Sthurlow  *
3024bff34e3Sthurlow  * Normally, one would simply get all the values starting with
3034bff34e3Sthurlow  * the bottom of the above list and working to the top, and
3044bff34e3Sthurlow  * overwriting values as you go.  But we need an exception.
3054bff34e3Sthurlow  *
3064bff34e3Sthurlow  * In this function, we parse the UNC path and command line options,
3074bff34e3Sthurlow  * because we need (at least) the server name when we're getting the
3084bff34e3Sthurlow  * SMF and RC file values.  However, values we get from the command
3094bff34e3Sthurlow  * should not be overwritten by SMF or RC file parsing, so we mark
3104bff34e3Sthurlow  * values from the command as "from CMD" and the RC file parser
3114bff34e3Sthurlow  * leaves in place any values so marked.  See: SMBCF_CMD_*
3124bff34e3Sthurlow  *
3134bff34e3Sthurlow  * The semantics of these flags are: "This value came from the
3144bff34e3Sthurlow  * current command instance, not from sources that may apply to
3154bff34e3Sthurlow  * multiple commands."  (Different from the old "FROMUSR" flag.)
3164bff34e3Sthurlow  *
3174bff34e3Sthurlow  * Note that smb_ctx_opt() is called later to handle the
3184bff34e3Sthurlow  * remaining options, which should be ignored here.
3194bff34e3Sthurlow  * The (magic) leading ":" in cf_getopt() makes it
3204bff34e3Sthurlow  * ignore options not in the options string.
3214bff34e3Sthurlow  */
3224bff34e3Sthurlow int
323613a2f6bSGordon Ross smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
3244bff34e3Sthurlow 	int minlevel, int maxlevel, int sharetype)
3254bff34e3Sthurlow {
326613a2f6bSGordon Ross 	int  ind, opt, error = 0;
3274bff34e3Sthurlow 	int aflg = 0, uflg = 0;
328613a2f6bSGordon Ross 	const char *arg;
3294bff34e3Sthurlow 
3304bff34e3Sthurlow 	/*
3314bff34e3Sthurlow 	 * Parse options, if any.  Values from here too
3324bff34e3Sthurlow 	 * are marked as "from CMD".
3334bff34e3Sthurlow 	 */
334613a2f6bSGordon Ross 	if (argv == NULL)
335613a2f6bSGordon Ross 		return (0);
336613a2f6bSGordon Ross 
337613a2f6bSGordon Ross 	ctx->ct_minlevel = minlevel;
338613a2f6bSGordon Ross 	ctx->ct_maxlevel = maxlevel;
339613a2f6bSGordon Ross 	ctx->ct_shtype_req = sharetype;
340613a2f6bSGordon Ross 
341613a2f6bSGordon Ross 	cf_opt_lock();
342613a2f6bSGordon Ross 	/* Careful: no return/goto before cf_opt_unlock! */
343613a2f6bSGordon Ross 	while (error == 0) {
344613a2f6bSGordon Ross 		opt = cf_getopt(argc, argv, STDPARAM_OPT);
345613a2f6bSGordon Ross 		if (opt == -1)
346613a2f6bSGordon Ross 			break;
3474bff34e3Sthurlow 		arg = cf_optarg;
348613a2f6bSGordon Ross 		/* NB: handle most in smb_ctx_opt */
3494bff34e3Sthurlow 		switch (opt) {
3504bff34e3Sthurlow 		case 'A':
3514bff34e3Sthurlow 			aflg = 1;
3524bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, "", TRUE);
3534bff34e3Sthurlow 			ctx->ct_flags |= SMBCF_NOPWD;
3544bff34e3Sthurlow 			break;
3554bff34e3Sthurlow 		case 'U':
3564bff34e3Sthurlow 			uflg = 1;
3574bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, arg, TRUE);
3584bff34e3Sthurlow 			break;
359613a2f6bSGordon Ross 		default:
360613a2f6bSGordon Ross 			DPRINT("skip opt=%c", opt);
361613a2f6bSGordon Ross 			break;
3624bff34e3Sthurlow 		}
3634bff34e3Sthurlow 	}
364613a2f6bSGordon Ross 	ind = cf_optind;
365613a2f6bSGordon Ross 	arg = argv[ind];
366613a2f6bSGordon Ross 	cf_optind = cf_optreset = 1;
367613a2f6bSGordon Ross 	cf_opt_unlock();
368613a2f6bSGordon Ross 
369613a2f6bSGordon Ross 	if (error)
370613a2f6bSGordon Ross 		return (error);
371613a2f6bSGordon Ross 
3724bff34e3Sthurlow 	if (aflg && uflg)  {
3734bff34e3Sthurlow 		printf(gettext("-A and -U flags are exclusive.\n"));
374613a2f6bSGordon Ross 		return (EINVAL);
3754bff34e3Sthurlow 	}
3764bff34e3Sthurlow 
377613a2f6bSGordon Ross 	/*
378613a2f6bSGordon Ross 	 * Parse the UNC path.  Values from here are
379613a2f6bSGordon Ross 	 * marked as "from CMD".
380613a2f6bSGordon Ross 	 */
381613a2f6bSGordon Ross 	for (; ind < argc; ind++) {
382613a2f6bSGordon Ross 		arg = argv[ind];
383613a2f6bSGordon Ross 		if (strncmp(arg, "//", 2) != 0)
384613a2f6bSGordon Ross 			continue;
385613a2f6bSGordon Ross 		error = smb_ctx_parseunc(ctx, arg,
386613a2f6bSGordon Ross 		    minlevel, maxlevel, sharetype, &arg);
387613a2f6bSGordon Ross 		if (error)
388613a2f6bSGordon Ross 			return (error);
389613a2f6bSGordon Ross 		break;
390613a2f6bSGordon Ross 	}
3914bff34e3Sthurlow 
3924bff34e3Sthurlow 	return (error);
3934bff34e3Sthurlow }
3944bff34e3Sthurlow 
3954bff34e3Sthurlow void
396613a2f6bSGordon Ross smb_ctx_free(smb_ctx_t *ctx)
397613a2f6bSGordon Ross {
398613a2f6bSGordon Ross 	smb_ctx_done(ctx);
399613a2f6bSGordon Ross 	free(ctx);
400613a2f6bSGordon Ross }
401613a2f6bSGordon Ross 
402613a2f6bSGordon Ross void
4034bff34e3Sthurlow smb_ctx_done(struct smb_ctx *ctx)
4044bff34e3Sthurlow {
4054bff34e3Sthurlow 
4064bff34e3Sthurlow 	rpc_cleanup_smbctx(ctx);
4074bff34e3Sthurlow 
408613a2f6bSGordon Ross 	if (ctx->ct_dev_fd != -1) {
409613a2f6bSGordon Ross 		close(ctx->ct_dev_fd);
410613a2f6bSGordon Ross 		ctx->ct_dev_fd = -1;
4114bff34e3Sthurlow 	}
4126b2bcd8eSGordon Ross 	if (ctx->ct_door_fd != -1) {
4136b2bcd8eSGordon Ross 		close(ctx->ct_door_fd);
4146b2bcd8eSGordon Ross 		ctx->ct_door_fd = -1;
4156b2bcd8eSGordon Ross 	}
416613a2f6bSGordon Ross 	if (ctx->ct_tran_fd != -1) {
417613a2f6bSGordon Ross 		close(ctx->ct_tran_fd);
418613a2f6bSGordon Ross 		ctx->ct_tran_fd = -1;
419613a2f6bSGordon Ross 	}
420613a2f6bSGordon Ross 	if (ctx->ct_srvaddr_s) {
421613a2f6bSGordon Ross 		free(ctx->ct_srvaddr_s);
422613a2f6bSGordon Ross 		ctx->ct_srvaddr_s = NULL;
423613a2f6bSGordon Ross 	}
424613a2f6bSGordon Ross 	if (ctx->ct_nb) {
4254bff34e3Sthurlow 		nb_ctx_done(ctx->ct_nb);
426613a2f6bSGordon Ross 		ctx->ct_nb = NULL;
427613a2f6bSGordon Ross 	}
428613a2f6bSGordon Ross 	if (ctx->ct_locname) {
429613a2f6bSGordon Ross 		free(ctx->ct_locname);
430613a2f6bSGordon Ross 		ctx->ct_locname = NULL;
431613a2f6bSGordon Ross 	}
432613a2f6bSGordon Ross 	if (ctx->ct_origshare) {
4334bff34e3Sthurlow 		free(ctx->ct_origshare);
434613a2f6bSGordon Ross 		ctx->ct_origshare = NULL;
435613a2f6bSGordon Ross 	}
436613a2f6bSGordon Ross 	if (ctx->ct_fullserver) {
4374bff34e3Sthurlow 		free(ctx->ct_fullserver);
438613a2f6bSGordon Ross 		ctx->ct_fullserver = NULL;
439613a2f6bSGordon Ross 	}
440613a2f6bSGordon Ross 	if (ctx->ct_addrinfo) {
441613a2f6bSGordon Ross 		freeaddrinfo(ctx->ct_addrinfo);
442613a2f6bSGordon Ross 		ctx->ct_addrinfo = NULL;
443613a2f6bSGordon Ross 	}
444613a2f6bSGordon Ross 	if (ctx->ct_home)
445613a2f6bSGordon Ross 		free(ctx->ct_home);
446613a2f6bSGordon Ross 	if (ctx->ct_srv_OS) {
447613a2f6bSGordon Ross 		free(ctx->ct_srv_OS);
448613a2f6bSGordon Ross 		ctx->ct_srv_OS = NULL;
449613a2f6bSGordon Ross 	}
450613a2f6bSGordon Ross 	if (ctx->ct_srv_LM) {
451613a2f6bSGordon Ross 		free(ctx->ct_srv_LM);
452613a2f6bSGordon Ross 		ctx->ct_srv_LM = NULL;
453613a2f6bSGordon Ross 	}
454613a2f6bSGordon Ross 	if (ctx->ct_mackey) {
455613a2f6bSGordon Ross 		free(ctx->ct_mackey);
456613a2f6bSGordon Ross 		ctx->ct_mackey = NULL;
457613a2f6bSGordon Ross 	}
4584bff34e3Sthurlow }
4594bff34e3Sthurlow 
4604bff34e3Sthurlow static int
4614bff34e3Sthurlow getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
4624bff34e3Sthurlow     const char **next)
4634bff34e3Sthurlow {
4644bff34e3Sthurlow 	int len;
4654bff34e3Sthurlow 
4664bff34e3Sthurlow 	maxlen--;
4674bff34e3Sthurlow 	for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
4684bff34e3Sthurlow 		if (*p == 0)
4694bff34e3Sthurlow 			return (EINVAL);
4704bff34e3Sthurlow 		*dest = *p;
4714bff34e3Sthurlow 	}
4724bff34e3Sthurlow 	*dest = 0;
4734bff34e3Sthurlow 	*next = *p ? p + 1 : p;
4744bff34e3Sthurlow 	return (0);
4754bff34e3Sthurlow }
4764bff34e3Sthurlow 
4774bff34e3Sthurlow /*
4784bff34e3Sthurlow  * Parse the UNC path.  Here we expect something like
4794bff34e3Sthurlow  *   "//[workgroup;][user[:password]@]host[/share[/path]]"
4804bff34e3Sthurlow  * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
4814bff34e3Sthurlow  * Values found here are marked as "from CMD".
4824bff34e3Sthurlow  */
4834bff34e3Sthurlow int
484613a2f6bSGordon Ross smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
485613a2f6bSGordon Ross 	int minlevel, int maxlevel, int sharetype,
4864bff34e3Sthurlow 	const char **next)
4874bff34e3Sthurlow {
4884bff34e3Sthurlow 	const char *p = unc;
489613a2f6bSGordon Ross 	char *p1, *colon;
4904bff34e3Sthurlow 	char tmp[1024];
4914bff34e3Sthurlow 	int error;
4924bff34e3Sthurlow 
493613a2f6bSGordon Ross 	/*
494613a2f6bSGordon Ross 	 * This may be called outside of _scan_argv,
495613a2f6bSGordon Ross 	 * so make sure these get initialized.
496613a2f6bSGordon Ross 	 */
497613a2f6bSGordon Ross 	ctx->ct_minlevel = minlevel;
498613a2f6bSGordon Ross 	ctx->ct_maxlevel = maxlevel;
499613a2f6bSGordon Ross 	ctx->ct_shtype_req = sharetype;
500613a2f6bSGordon Ross 
5014bff34e3Sthurlow 	ctx->ct_parsedlevel = SMBL_NONE;
5024bff34e3Sthurlow 	if (*p++ != '/' || *p++ != '/') {
5034bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
5044bff34e3Sthurlow 		    "UNC should start with '//'"), 0);
505613a2f6bSGordon Ross 		error = EINVAL;
506613a2f6bSGordon Ross 		goto out;
5074bff34e3Sthurlow 	}
5084bff34e3Sthurlow 	p1 = tmp;
5094bff34e3Sthurlow 	error = getsubstring(p, ';', p1, sizeof (tmp), &p);
5104bff34e3Sthurlow 	if (!error) {
5114bff34e3Sthurlow 		if (*p1 == 0) {
5124bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5134bff34e3Sthurlow 			    "empty workgroup name"), 0);
514613a2f6bSGordon Ross 			error = EINVAL;
515613a2f6bSGordon Ross 			goto out;
5164bff34e3Sthurlow 		}
517613a2f6bSGordon Ross 		error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE);
5184bff34e3Sthurlow 		if (error)
519613a2f6bSGordon Ross 			goto out;
5204bff34e3Sthurlow 	}
5214bff34e3Sthurlow 	colon = (char *)p;
5224bff34e3Sthurlow 	error = getsubstring(p, '@', p1, sizeof (tmp), &p);
5234bff34e3Sthurlow 	if (!error) {
5244bff34e3Sthurlow 		if (ctx->ct_maxlevel < SMBL_VC) {
5254bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5264bff34e3Sthurlow 			    "no user name required"), 0);
527613a2f6bSGordon Ross 			error = EINVAL;
528613a2f6bSGordon Ross 			goto out;
5294bff34e3Sthurlow 		}
5304bff34e3Sthurlow 		p1 = strchr(tmp, ':');
5314bff34e3Sthurlow 		if (p1) {
5324bff34e3Sthurlow 			colon += p1 - tmp;
5334bff34e3Sthurlow 			*p1++ = (char)0;
5344bff34e3Sthurlow 			error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
5354bff34e3Sthurlow 			if (error)
536613a2f6bSGordon Ross 				goto out;
5374bff34e3Sthurlow 			if (p - colon > 2)
5384bff34e3Sthurlow 				memset(colon+1, '*', p - colon - 2);
5394bff34e3Sthurlow 		}
5404bff34e3Sthurlow 		p1 = tmp;
5414bff34e3Sthurlow 		if (*p1 == 0) {
5424bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5434bff34e3Sthurlow 			    "empty user name"), 0);
544613a2f6bSGordon Ross 			error = EINVAL;
545613a2f6bSGordon Ross 			goto out;
5464bff34e3Sthurlow 		}
5474bff34e3Sthurlow 		error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
5484bff34e3Sthurlow 		if (error)
549613a2f6bSGordon Ross 			goto out;
5504bff34e3Sthurlow 		ctx->ct_parsedlevel = SMBL_VC;
5514bff34e3Sthurlow 	}
5524bff34e3Sthurlow 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
5534bff34e3Sthurlow 	if (error) {
5544bff34e3Sthurlow 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
5554bff34e3Sthurlow 		if (error) {
5564bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5574bff34e3Sthurlow 			    "no server name found"), 0);
558613a2f6bSGordon Ross 			goto out;
5594bff34e3Sthurlow 		}
5604bff34e3Sthurlow 	}
5614bff34e3Sthurlow 	if (*p1 == 0) {
5624bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
563613a2f6bSGordon Ross 		error = EINVAL;
564613a2f6bSGordon Ross 		goto out;
5654bff34e3Sthurlow 	}
5664bff34e3Sthurlow 
5674bff34e3Sthurlow 	/*
568613a2f6bSGordon Ross 	 * Save ct_fullserver without case conversion.
5694bff34e3Sthurlow 	 */
570613a2f6bSGordon Ross 	if (strchr(tmp, '%'))
571613a2f6bSGordon Ross 		(void) unpercent(tmp);
57202d09e03SGordon Ross 	error = smb_ctx_setfullserver(ctx, tmp);
5734bff34e3Sthurlow 	if (error)
574613a2f6bSGordon Ross 		goto out;
575613a2f6bSGordon Ross 
576613a2f6bSGordon Ross #ifdef	SMB_ST_NONE
5774bff34e3Sthurlow 	if (sharetype == SMB_ST_NONE) {
578613a2f6bSGordon Ross 		if (next)
5794bff34e3Sthurlow 			*next = p;
580613a2f6bSGordon Ross 		error = 0;
581613a2f6bSGordon Ross 		goto out;
5824bff34e3Sthurlow 	}
583613a2f6bSGordon Ross #endif
584613a2f6bSGordon Ross 
5854bff34e3Sthurlow 	if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
5864bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
587613a2f6bSGordon Ross 		error = EINVAL;
588613a2f6bSGordon Ross 		goto out;
5894bff34e3Sthurlow 	}
5904bff34e3Sthurlow 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
5914bff34e3Sthurlow 	if (error) {
5924bff34e3Sthurlow 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
5934bff34e3Sthurlow 		if (error) {
5944bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5954bff34e3Sthurlow 			    "unexpected end of line"), 0);
596613a2f6bSGordon Ross 			goto out;
5974bff34e3Sthurlow 		}
5984bff34e3Sthurlow 	}
5994bff34e3Sthurlow 	if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
6004bff34e3Sthurlow 	    !(ctx->ct_flags & SMBCF_BROWSEOK)) {
6014bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
602613a2f6bSGordon Ross 		error = EINVAL;
603613a2f6bSGordon Ross 		goto out;
6044bff34e3Sthurlow 	}
605613a2f6bSGordon Ross 	if (next)
6064bff34e3Sthurlow 		*next = p;
607613a2f6bSGordon Ross 	if (*p1 == 0) {
608613a2f6bSGordon Ross 		error = 0;
609613a2f6bSGordon Ross 		goto out;
610613a2f6bSGordon Ross 	}
6114bff34e3Sthurlow 	error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
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
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
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
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
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
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
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
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
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
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
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
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 
8624bff34e3Sthurlow static int
8634bff34e3Sthurlow smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
8644bff34e3Sthurlow {
8654bff34e3Sthurlow 	struct group gr;
8664bff34e3Sthurlow 	struct passwd pw;
8674bff34e3Sthurlow 	char buf[NSS_BUFLEN_PASSWD];
8684bff34e3Sthurlow 	char *cp;
8694bff34e3Sthurlow 
8704bff34e3Sthurlow 	cp = strchr(pair, ':');
8714bff34e3Sthurlow 	if (cp) {
8724bff34e3Sthurlow 		*cp++ = '\0';
873613a2f6bSGordon Ross 		if (*cp && gid) {
8744bff34e3Sthurlow 			if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
8754bff34e3Sthurlow 				*gid = gr.gr_gid;
8764bff34e3Sthurlow 			} else
8774bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
8784bff34e3Sthurlow 				    "Invalid group name %s, ignored"), 0, cp);
8794bff34e3Sthurlow 		}
8804bff34e3Sthurlow 	}
8814bff34e3Sthurlow 	if (*pair) {
8824bff34e3Sthurlow 		if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
8834bff34e3Sthurlow 			*uid = pw.pw_uid;
8844bff34e3Sthurlow 		} else
8854bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
8864bff34e3Sthurlow 			    "Invalid user name %s, ignored"), 0, pair);
8874bff34e3Sthurlow 	}
8884bff34e3Sthurlow 
8894bff34e3Sthurlow 	return (0);
8904bff34e3Sthurlow }
8914bff34e3Sthurlow 
8924bff34e3Sthurlow /*
89315359501SGordon Ross  * Suport a securty options arg, i.e. -S noext,lm,ntlm
89415359501SGordon Ross  * for testing various type of authenticators.
89515359501SGordon Ross  */
89615359501SGordon Ross static struct nv
89715359501SGordon Ross sectype_table[] = {
89815359501SGordon Ross 	/* noext - handled below */
89915359501SGordon Ross 	{ "anon",	SMB_AT_ANON },
90015359501SGordon Ross 	{ "lm",		SMB_AT_LM1 },
90115359501SGordon Ross 	{ "ntlm",	SMB_AT_NTLM1 },
90215359501SGordon Ross 	{ "ntlm2",	SMB_AT_NTLM2 },
90315359501SGordon Ross 	{ "krb5",	SMB_AT_KRB5 },
90415359501SGordon Ross 	{ NULL, 	0 },
90515359501SGordon Ross };
90615359501SGordon Ross int
90715359501SGordon Ross smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
90815359501SGordon Ross {
90915359501SGordon Ross 	const char *sep = ":;,";
91015359501SGordon Ross 	const char *p = arg;
91115359501SGordon Ross 	struct nv *nv;
91215359501SGordon Ross 	int nlen, tlen;
91315359501SGordon Ross 	int authflags = 0;
91415359501SGordon Ross 
91515359501SGordon Ross 	for (;;) {
91615359501SGordon Ross 		/* skip separators */
91715359501SGordon Ross 		tlen = strspn(p, sep);
91815359501SGordon Ross 		p += tlen;
91915359501SGordon Ross 
92015359501SGordon Ross 		nlen = strcspn(p, sep);
92115359501SGordon Ross 		if (nlen == 0)
92215359501SGordon Ross 			break;
92315359501SGordon Ross 
92415359501SGordon Ross 		if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
92515359501SGordon Ross 			/* Don't offer extended security. */
92615359501SGordon Ross 			ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
92715359501SGordon Ross 			p += nlen;
92815359501SGordon Ross 			continue;
92915359501SGordon Ross 		}
93015359501SGordon Ross 
93115359501SGordon Ross 		/* This is rarely called, so not optimized. */
93215359501SGordon Ross 		for (nv = sectype_table; nv->name; nv++) {
93315359501SGordon Ross 			tlen = strlen(nv->name);
93415359501SGordon Ross 			if (tlen == nlen && 0 == strncmp(p, nv->name, tlen))
93515359501SGordon Ross 				break;
93615359501SGordon Ross 		}
93715359501SGordon Ross 		if (nv->name == NULL) {
93815359501SGordon Ross 			smb_error(dgettext(TEXT_DOMAIN,
93915359501SGordon Ross 			    "%s: invalid security options"), 0, p);
94015359501SGordon Ross 			return (EINVAL);
94115359501SGordon Ross 		}
94215359501SGordon Ross 		authflags |= nv->value;
94315359501SGordon Ross 		p += nlen;
94415359501SGordon Ross 	}
94515359501SGordon Ross 
94615359501SGordon Ross 	if (authflags)
94715359501SGordon Ross 		ctx->ct_authflags = authflags;
94815359501SGordon Ross 
94915359501SGordon Ross 	return (0);
95015359501SGordon Ross }
95115359501SGordon Ross 
95215359501SGordon Ross /*
9534bff34e3Sthurlow  * Commands use this with getopt.  See:
9544bff34e3Sthurlow  *   STDPARAM_OPT, STDPARAM_ARGS
9554bff34e3Sthurlow  * Called after smb_ctx_readrc().
9564bff34e3Sthurlow  */
9574bff34e3Sthurlow int
9584bff34e3Sthurlow smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
9594bff34e3Sthurlow {
9604bff34e3Sthurlow 	int error = 0;
9614bff34e3Sthurlow 	char *p, *cp;
9624bff34e3Sthurlow 	char tmp[1024];
9634bff34e3Sthurlow 
9644bff34e3Sthurlow 	switch (opt) {
9654bff34e3Sthurlow 	case 'A':
9664bff34e3Sthurlow 	case 'U':
9674bff34e3Sthurlow 		/* Handled in smb_ctx_init() */
9684bff34e3Sthurlow 		break;
9694bff34e3Sthurlow 	case 'I':
9704bff34e3Sthurlow 		error = smb_ctx_setsrvaddr(ctx, arg);
9714bff34e3Sthurlow 		break;
9724bff34e3Sthurlow 	case 'M':
973613a2f6bSGordon Ross 		/* share connect rights - ignored */
9744bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_SRIGHTS;
9754bff34e3Sthurlow 		break;
9764bff34e3Sthurlow 	case 'N':
9774bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_NOPWD;
9784bff34e3Sthurlow 		break;
9794bff34e3Sthurlow 	case 'O':
9804bff34e3Sthurlow 		p = strdup(arg);
9814bff34e3Sthurlow 		cp = strchr(p, '/');
982613a2f6bSGordon Ross 		if (cp)
983613a2f6bSGordon Ross 			*cp = '\0';
984613a2f6bSGordon Ross 		error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
9854bff34e3Sthurlow 		free(p);
9864bff34e3Sthurlow 		break;
9874bff34e3Sthurlow 	case 'P':
988613a2f6bSGordon Ross /*		ctx->ct_vopt |= SMBCOPT_PERMANENT; */
9894bff34e3Sthurlow 		break;
9904bff34e3Sthurlow 	case 'R':
991613a2f6bSGordon Ross 		/* retry count - ignored */
9924bff34e3Sthurlow 		break;
99315359501SGordon Ross 	case 'S':
99415359501SGordon Ross 		/* Security options (undocumented, just for tests) */
99515359501SGordon Ross 		error = smb_parse_secopts(ctx, arg);
99615359501SGordon Ross 		break;
9974bff34e3Sthurlow 	case 'T':
998613a2f6bSGordon Ross 		/* timeout - ignored */
9994bff34e3Sthurlow 		break;
1000613a2f6bSGordon Ross 	case 'D':	/* domain */
1001613a2f6bSGordon Ross 	case 'W':	/* workgroup (legacy alias) */
1002613a2f6bSGordon Ross 		error = smb_ctx_setdomain(ctx, tmp, TRUE);
10034bff34e3Sthurlow 		break;
10044bff34e3Sthurlow 	}
10054bff34e3Sthurlow 	return (error);
10064bff34e3Sthurlow }
10074bff34e3Sthurlow 
10084bff34e3Sthurlow 
1009613a2f6bSGordon Ross /*
1010613a2f6bSGordon Ross  * Original code injected iconv tables into the kernel.
1011613a2f6bSGordon Ross  * Not sure if we'll need this or not...  REVISIT
1012613a2f6bSGordon Ross  */
1013613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
10144bff34e3Sthurlow static int
10154bff34e3Sthurlow smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
10164bff34e3Sthurlow {
1017613a2f6bSGordon Ross 	int error = 0;
10184bff34e3Sthurlow 
10194bff34e3Sthurlow 	error = kiconv_add_xlat_table(to, from, tbl);
10204bff34e3Sthurlow 	if (error && error != EEXIST) {
10214bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10224bff34e3Sthurlow 		    "can not setup kernel iconv table (%s:%s)"),
10234bff34e3Sthurlow 		    error, from, to);
10244bff34e3Sthurlow 		return (error);
10254bff34e3Sthurlow 	}
1026613a2f6bSGordon Ross 	return (error);
10274bff34e3Sthurlow }
1028613a2f6bSGordon Ross #endif	/* KICONV_SUPPORT */
10294bff34e3Sthurlow 
10304bff34e3Sthurlow /*
1031613a2f6bSGordon Ross  * Verify context info. before connect operation(s),
10324bff34e3Sthurlow  * lookup specified server and try to fill all forgotten fields.
1033613a2f6bSGordon Ross  * Legacy name used by commands.
10344bff34e3Sthurlow  */
10354bff34e3Sthurlow int
10364bff34e3Sthurlow smb_ctx_resolve(struct smb_ctx *ctx)
10374bff34e3Sthurlow {
10384bff34e3Sthurlow 	struct smbioc_ossn *ssn = &ctx->ct_ssn;
1039613a2f6bSGordon Ross 	int error = 0;
1040613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
10414bff34e3Sthurlow 	uchar_t cstbl[256];
10424bff34e3Sthurlow 	uint_t i;
1043613a2f6bSGordon Ross #endif
10444bff34e3Sthurlow 
104515359501SGordon Ross 	if (smb_debug)
104615359501SGordon Ross 		dump_ctx("before smb_ctx_resolve", ctx);
104715359501SGordon Ross 
10484bff34e3Sthurlow 	ctx->ct_flags &= ~SMBCF_RESOLVED;
1049613a2f6bSGordon Ross 
1050613a2f6bSGordon Ross 	if (ctx->ct_fullserver == NULL) {
10514bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10524bff34e3Sthurlow 		    "no server name specified"), 0);
10534bff34e3Sthurlow 		return (EINVAL);
10544bff34e3Sthurlow 	}
1055613a2f6bSGordon Ross 
1056613a2f6bSGordon Ross 	if (ctx->ct_minlevel >= SMBL_SHARE &&
1057613a2f6bSGordon Ross 	    ctx->ct_origshare == NULL) {
10584bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10594bff34e3Sthurlow 		    "no share name specified for %s@%s"),
1060613a2f6bSGordon Ross 		    0, ssn->ssn_user, ctx->ct_fullserver);
10614bff34e3Sthurlow 		return (EINVAL);
10624bff34e3Sthurlow 	}
10634bff34e3Sthurlow 	error = nb_ctx_resolve(ctx->ct_nb);
10644bff34e3Sthurlow 	if (error)
10654bff34e3Sthurlow 		return (error);
1066613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
10674bff34e3Sthurlow 	if (ssn->ioc_localcs[0] == 0)
10684bff34e3Sthurlow 		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
10694bff34e3Sthurlow 	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
10704bff34e3Sthurlow 	if (error)
10714bff34e3Sthurlow 		return (error);
10724bff34e3Sthurlow 	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
10734bff34e3Sthurlow 	if (error)
10744bff34e3Sthurlow 		return (error);
10754bff34e3Sthurlow 	if (ssn->ioc_servercs[0] != 0) {
10764bff34e3Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
10774bff34e3Sthurlow 			cstbl[i] = i;
10784bff34e3Sthurlow 		nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
10794bff34e3Sthurlow 		error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
10804bff34e3Sthurlow 		    cstbl);
10814bff34e3Sthurlow 		if (error)
10824bff34e3Sthurlow 			return (error);
10834bff34e3Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
10844bff34e3Sthurlow 			cstbl[i] = i;
10854bff34e3Sthurlow 		nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
10864bff34e3Sthurlow 		error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
10874bff34e3Sthurlow 		    cstbl);
10884bff34e3Sthurlow 		if (error)
10894bff34e3Sthurlow 			return (error);
10904bff34e3Sthurlow 	}
1091613a2f6bSGordon Ross #endif	/* KICONV_SUPPORT */
10924bff34e3Sthurlow 
10934bff34e3Sthurlow 	/*
10946b2bcd8eSGordon Ross 	 * Lookup the IP address and fill in ct_addrinfo.
10956b2bcd8eSGordon Ross 	 *
10966b2bcd8eSGordon Ross 	 * Note: smb_ctx_getaddr() returns a EAI_xxx
10976b2bcd8eSGordon Ross 	 * error value like getaddrinfo(3), but this
10986b2bcd8eSGordon Ross 	 * function needs to return an errno value.
10994bff34e3Sthurlow 	 */
1100613a2f6bSGordon Ross 	error = smb_ctx_getaddr(ctx);
11014bff34e3Sthurlow 	if (error) {
11026b2bcd8eSGordon Ross 		const char *ais = gai_strerror(error);
11034bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1104*ae3d7f90SGordon Ross 		    "can't resolve name\"%s\", %s"),
1105*ae3d7f90SGordon Ross 		    0, ctx->ct_fullserver, ais);
11066b2bcd8eSGordon Ross 		return (ENODATA);
11074bff34e3Sthurlow 	}
1108613a2f6bSGordon Ross 	assert(ctx->ct_addrinfo != NULL);
11094bff34e3Sthurlow 
11104bff34e3Sthurlow 	/*
1111613a2f6bSGordon Ross 	 * If we have a user name but no password,
1112613a2f6bSGordon Ross 	 * check for a keychain entry.
1113613a2f6bSGordon Ross 	 * XXX: Only for auth NTLM?
11144bff34e3Sthurlow 	 */
1115613a2f6bSGordon Ross 	if (ctx->ct_user[0] == '\0') {
11164bff34e3Sthurlow 		/*
1117613a2f6bSGordon Ross 		 * No user name (anonymous session).
1118613a2f6bSGordon Ross 		 * The minauth checks do not apply.
11194bff34e3Sthurlow 		 */
1120613a2f6bSGordon Ross 		ctx->ct_authflags = SMB_AT_ANON;
1121613a2f6bSGordon Ross 	} else {
11224bff34e3Sthurlow 		/*
1123613a2f6bSGordon Ross 		 * Have a user name.
1124613a2f6bSGordon Ross 		 * If we don't have a p/w yet,
1125613a2f6bSGordon Ross 		 * try the keychain.
11264bff34e3Sthurlow 		 */
1127613a2f6bSGordon Ross 		if (ctx->ct_password[0] == '\0')
1128613a2f6bSGordon Ross 			(void) smb_get_keychain(ctx);
1129613a2f6bSGordon Ross 		/*
1130613a2f6bSGordon Ross 		 * Mask out disallowed auth types.
1131613a2f6bSGordon Ross 		 */
1132613a2f6bSGordon Ross 		ctx->ct_authflags &= ctx->ct_minauth;
11334bff34e3Sthurlow 	}
1134613a2f6bSGordon Ross 	if (ctx->ct_authflags == 0) {
11354bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1136613a2f6bSGordon Ross 		    "no valid auth. types"), 0);
1137613a2f6bSGordon Ross 		return (ENOTSUP);
11384bff34e3Sthurlow 	}
1139613a2f6bSGordon Ross 
11404bff34e3Sthurlow 	ctx->ct_flags |= SMBCF_RESOLVED;
11414bff34e3Sthurlow 	if (smb_debug)
11424bff34e3Sthurlow 		dump_ctx("after smb_ctx_resolve", ctx);
11434bff34e3Sthurlow 
11444bff34e3Sthurlow 	return (0);
11454bff34e3Sthurlow }
11464bff34e3Sthurlow 
11474bff34e3Sthurlow int
11484bff34e3Sthurlow smb_open_driver()
11494bff34e3Sthurlow {
1150613a2f6bSGordon Ross 	int err, fd;
11514bff34e3Sthurlow 	uint32_t version;
11524bff34e3Sthurlow 
11534bff34e3Sthurlow 	fd = open("/dev/"NSMB_NAME, O_RDWR);
1154613a2f6bSGordon Ross 	if (fd < 0) {
1155613a2f6bSGordon Ross 		err = errno;
11564bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1157613a2f6bSGordon Ross 		    "failed to open driver"), err);
11584bff34e3Sthurlow 		return (-1);
1159613a2f6bSGordon Ross 	}
11604bff34e3Sthurlow 
11614bff34e3Sthurlow 	/*
11624bff34e3Sthurlow 	 * Check the driver version (paranoia)
11634bff34e3Sthurlow 	 * Do this BEFORE any other ioctl calls.
11644bff34e3Sthurlow 	 */
1165613a2f6bSGordon Ross 	if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1166613a2f6bSGordon Ross 		version = 0;
11674bff34e3Sthurlow 	if (version != NSMB_VERSION) {
11684bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
11694bff34e3Sthurlow 		    "incorrect driver version"), 0);
11704bff34e3Sthurlow 		close(fd);
11714bff34e3Sthurlow 		return (-1);
11724bff34e3Sthurlow 	}
11734bff34e3Sthurlow 
1174613a2f6bSGordon Ross 	/* This handle controls per-process resources. */
1175613a2f6bSGordon Ross 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1176613a2f6bSGordon Ross 
11774bff34e3Sthurlow 	return (fd);
11784bff34e3Sthurlow }
11794bff34e3Sthurlow 
1180613a2f6bSGordon Ross int
11814bff34e3Sthurlow smb_ctx_gethandle(struct smb_ctx *ctx)
11824bff34e3Sthurlow {
1183613a2f6bSGordon Ross 	int fd;
11844bff34e3Sthurlow 
1185613a2f6bSGordon Ross 	if (ctx->ct_dev_fd != -1) {
11864bff34e3Sthurlow 		rpc_cleanup_smbctx(ctx);
1187613a2f6bSGordon Ross 		close(ctx->ct_dev_fd);
1188613a2f6bSGordon Ross 		ctx->ct_dev_fd = -1;
11894bff34e3Sthurlow 		ctx->ct_flags &= ~SMBCF_SSNACTIVE;
11904bff34e3Sthurlow 	}
11914bff34e3Sthurlow 
11924bff34e3Sthurlow 	fd = smb_open_driver();
11934bff34e3Sthurlow 	if (fd < 0)
11944bff34e3Sthurlow 		return (ENODEV);
11954bff34e3Sthurlow 
1196613a2f6bSGordon Ross 	ctx->ct_dev_fd = fd;
11974bff34e3Sthurlow 	return (0);
11984bff34e3Sthurlow }
11994bff34e3Sthurlow 
1200613a2f6bSGordon Ross 
1201613a2f6bSGordon Ross /*
1202613a2f6bSGordon Ross  * Find or create a connection + logon session
1203613a2f6bSGordon Ross  */
12044bff34e3Sthurlow int
1205613a2f6bSGordon Ross smb_ctx_get_ssn(struct smb_ctx *ctx)
12064bff34e3Sthurlow {
1207613a2f6bSGordon Ross 	int err = 0;
12084bff34e3Sthurlow 
1209613a2f6bSGordon Ross 	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
12104bff34e3Sthurlow 		return (EINVAL);
12114bff34e3Sthurlow 
1212613a2f6bSGordon Ross 	if (ctx->ct_dev_fd < 0) {
1213613a2f6bSGordon Ross 		if ((err = smb_ctx_gethandle(ctx)))
1214613a2f6bSGordon Ross 			return (err);
12154bff34e3Sthurlow 	}
12164bff34e3Sthurlow 
12174bff34e3Sthurlow 	/*
1218613a2f6bSGordon Ross 	 * Check whether the driver already has a VC
1219613a2f6bSGordon Ross 	 * we can use.  If so, we're done!
12204bff34e3Sthurlow 	 */
1221613a2f6bSGordon Ross 	err = smb_ctx_findvc(ctx);
1222613a2f6bSGordon Ross 	if (err == 0) {
1223613a2f6bSGordon Ross 		DPRINT("found an existing VC");
12244bff34e3Sthurlow 	} else {
1225613a2f6bSGordon Ross 		/*
1226613a2f6bSGordon Ross 		 * This calls the IOD to create a new session.
1227613a2f6bSGordon Ross 		 */
1228613a2f6bSGordon Ross 		DPRINT("setup a new VC");
1229613a2f6bSGordon Ross 		err = smb_ctx_newvc(ctx);
1230613a2f6bSGordon Ross 		if (err != 0)
1231613a2f6bSGordon Ross 			return (err);
1232613a2f6bSGordon Ross 
1233613a2f6bSGordon Ross 		/*
1234613a2f6bSGordon Ross 		 * Call findvc again.  The new VC sould be
1235613a2f6bSGordon Ross 		 * found in the driver this time.
1236613a2f6bSGordon Ross 		 */
1237613a2f6bSGordon Ross 		err = smb_ctx_findvc(ctx);
12384bff34e3Sthurlow 	}
1239613a2f6bSGordon Ross 
1240613a2f6bSGordon Ross 	return (err);
12414bff34e3Sthurlow }
12424bff34e3Sthurlow 
12434bff34e3Sthurlow /*
1244613a2f6bSGordon Ross  * Get the string representation of a share "use" type,
1245613a2f6bSGordon Ross  * as needed for the "service" in tree connect.
12464bff34e3Sthurlow  */
1247613a2f6bSGordon Ross static const char *
1248613a2f6bSGordon Ross smb_use_type_str(smb_use_shtype_t stype)
1249613a2f6bSGordon Ross {
1250613a2f6bSGordon Ross 	const char *pp;
1251613a2f6bSGordon Ross 
1252613a2f6bSGordon Ross 	switch (stype) {
1253613a2f6bSGordon Ross 	default:
1254613a2f6bSGordon Ross 	case USE_WILDCARD:
1255613a2f6bSGordon Ross 		pp = "?????";
1256613a2f6bSGordon Ross 		break;
1257613a2f6bSGordon Ross 	case USE_DISKDEV:
1258613a2f6bSGordon Ross 		pp = "A:";
1259613a2f6bSGordon Ross 		break;
1260613a2f6bSGordon Ross 	case USE_SPOOLDEV:
1261613a2f6bSGordon Ross 		pp = "LPT1:";
1262613a2f6bSGordon Ross 		break;
1263613a2f6bSGordon Ross 	case USE_CHARDEV:
1264613a2f6bSGordon Ross 		pp = "COMM";
1265613a2f6bSGordon Ross 		break;
1266613a2f6bSGordon Ross 	case USE_IPC:
1267613a2f6bSGordon Ross 		pp = "IPC";
1268613a2f6bSGordon Ross 		break;
1269613a2f6bSGordon Ross 	}
1270613a2f6bSGordon Ross 	return (pp);
1271613a2f6bSGordon Ross }
1272613a2f6bSGordon Ross 
12734bff34e3Sthurlow /*
1274613a2f6bSGordon Ross  * Find or create a tree connection
12754bff34e3Sthurlow  */
1276613a2f6bSGordon Ross int
1277613a2f6bSGordon Ross smb_ctx_get_tree(struct smb_ctx *ctx)
1278613a2f6bSGordon Ross {
1279613a2f6bSGordon Ross 	smbioc_tcon_t *tcon = NULL;
1280613a2f6bSGordon Ross 	const char *stype;
1281613a2f6bSGordon Ross 	int cmd, err = 0;
1282613a2f6bSGordon Ross 
1283613a2f6bSGordon Ross 	if (ctx->ct_dev_fd < 0 ||
1284613a2f6bSGordon Ross 	    ctx->ct_origshare == NULL) {
1285613a2f6bSGordon Ross 		return (EINVAL);
1286613a2f6bSGordon Ross 	}
1287613a2f6bSGordon Ross 
1288613a2f6bSGordon Ross 	cmd = SMBIOC_TREE_CONNECT;
1289613a2f6bSGordon Ross 	tcon = malloc(sizeof (*tcon));
1290613a2f6bSGordon Ross 	if (tcon == NULL)
1291613a2f6bSGordon Ross 		return (ENOMEM);
1292613a2f6bSGordon Ross 	bzero(tcon, sizeof (*tcon));
1293613a2f6bSGordon Ross 	tcon->tc_flags = SMBLK_CREATE;
1294613a2f6bSGordon Ross 	tcon->tc_opt = 0;
1295613a2f6bSGordon Ross 
1296613a2f6bSGordon Ross 	/* The share name */
1297613a2f6bSGordon Ross 	strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
1298613a2f6bSGordon Ross 	    sizeof (tcon->tc_sh.sh_name));
1299613a2f6bSGordon Ross 
130042d15982SGordon Ross 	/*
130142d15982SGordon Ross 	 * Share password (unused - no share-level security)
130242d15982SGordon Ross 	 * MS-SMB 2.2.6 says this should be null terminated,
130342d15982SGordon Ross 	 * and the length includes the null.  Did bzero above,
130442d15982SGordon Ross 	 * so just set length for the null.
130542d15982SGordon Ross 	 */
130642d15982SGordon Ross 	tcon->tc_sh.sh_pwlen = 1;
130742d15982SGordon Ross 
1308613a2f6bSGordon Ross 	/* The share "use" type. */
1309613a2f6bSGordon Ross 	stype = smb_use_type_str(ctx->ct_shtype_req);
1310613a2f6bSGordon Ross 	strlcpy(tcon->tc_sh.sh_type_req, stype,
1311613a2f6bSGordon Ross 	    sizeof (tcon->tc_sh.sh_type_req));
1312613a2f6bSGordon Ross 
1313613a2f6bSGordon Ross 	/*
1314613a2f6bSGordon Ross 	 * Todo: share passwords for share-level security.
1315613a2f6bSGordon Ross 	 *
1316613a2f6bSGordon Ross 	 * The driver does the actual TCON call.
1317613a2f6bSGordon Ross 	 */
1318613a2f6bSGordon Ross 	if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1319613a2f6bSGordon Ross 		err = errno;
13204bff34e3Sthurlow 		goto out;
13214bff34e3Sthurlow 	}
1322613a2f6bSGordon Ross 
1323613a2f6bSGordon Ross 	/*
1324613a2f6bSGordon Ross 	 * Check the returned share type
1325613a2f6bSGordon Ross 	 */
1326613a2f6bSGordon Ross 	DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret);
1327613a2f6bSGordon Ross 	if (ctx->ct_shtype_req != USE_WILDCARD &&
1328613a2f6bSGordon Ross 	    0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) {
1329613a2f6bSGordon Ross 		smb_error(dgettext(TEXT_DOMAIN,
1330613a2f6bSGordon Ross 		    "%s: incompatible share type"),
1331613a2f6bSGordon Ross 		    0, ctx->ct_origshare);
1332613a2f6bSGordon Ross 		err = EINVAL;
13334bff34e3Sthurlow 	}
13344bff34e3Sthurlow 
13354bff34e3Sthurlow out:
1336613a2f6bSGordon Ross 	if (tcon != NULL)
1337613a2f6bSGordon Ross 		free(tcon);
1338613a2f6bSGordon Ross 
1339613a2f6bSGordon Ross 	return (err);
13404bff34e3Sthurlow }
13414bff34e3Sthurlow 
13424bff34e3Sthurlow /*
13434bff34e3Sthurlow  * Return the hflags2 word for an smb_ctx.
13444bff34e3Sthurlow  */
13454bff34e3Sthurlow int
13464bff34e3Sthurlow smb_ctx_flags2(struct smb_ctx *ctx)
13474bff34e3Sthurlow {
13484bff34e3Sthurlow 	uint16_t flags2;
13494bff34e3Sthurlow 
1350613a2f6bSGordon Ross 	if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
13514bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
13524bff34e3Sthurlow 		    "can't get flags2 for a session"), errno);
13534bff34e3Sthurlow 		return (-1);
13544bff34e3Sthurlow 	}
13554bff34e3Sthurlow 	return (flags2);
13564bff34e3Sthurlow }
13574bff34e3Sthurlow 
13584bff34e3Sthurlow /*
1359613a2f6bSGordon Ross  * Get the transport level session key.
1360613a2f6bSGordon Ross  * Must already have an active SMB session.
1361613a2f6bSGordon Ross  */
1362613a2f6bSGordon Ross int
1363613a2f6bSGordon Ross smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len)
1364613a2f6bSGordon Ross {
1365613a2f6bSGordon Ross 	if (len < SMBIOC_HASH_SZ)
1366613a2f6bSGordon Ross 		return (EINVAL);
1367613a2f6bSGordon Ross 
1368613a2f6bSGordon Ross 	if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1369613a2f6bSGordon Ross 		return (errno);
1370613a2f6bSGordon Ross 
1371613a2f6bSGordon Ross 	return (0);
1372613a2f6bSGordon Ross }
1373613a2f6bSGordon Ross 
1374613a2f6bSGordon Ross /*
1375613a2f6bSGordon Ross  * RC file parsing stuff
1376613a2f6bSGordon Ross  */
1377613a2f6bSGordon Ross 
137815359501SGordon Ross static struct nv
137915359501SGordon Ross minauth_table[] = {
1380613a2f6bSGordon Ross 	/* Allowed auth. types */
1381613a2f6bSGordon Ross 	{ "kerberos",	SMB_AT_KRB5 },
1382613a2f6bSGordon Ross 	{ "ntlmv2",	SMB_AT_KRB5|SMB_AT_NTLM2 },
1383613a2f6bSGordon Ross 	{ "ntlm",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
1384613a2f6bSGordon Ross 	{ "lm",		SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
1385613a2f6bSGordon Ross 	{ "none",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
1386613a2f6bSGordon Ross 			SMB_AT_ANON },
1387613a2f6bSGordon Ross 	{ NULL }
1388613a2f6bSGordon Ross };
1389613a2f6bSGordon Ross 
1390613a2f6bSGordon Ross 
1391613a2f6bSGordon Ross /*
13924bff34e3Sthurlow  * level values:
13934bff34e3Sthurlow  * 0 - default
13944bff34e3Sthurlow  * 1 - server
13954bff34e3Sthurlow  * 2 - server:user
13964bff34e3Sthurlow  * 3 - server:user:share
13974bff34e3Sthurlow  */
13984bff34e3Sthurlow static int
13994bff34e3Sthurlow smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
14004bff34e3Sthurlow {
14014bff34e3Sthurlow 	char *p;
14024bff34e3Sthurlow 	int error;
14034bff34e3Sthurlow 
1404613a2f6bSGordon Ross #ifdef	KICONV_SUPPORT
14054bff34e3Sthurlow 	if (level > 0) {
14064bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "charsets", &p);
14074bff34e3Sthurlow 		if (p) {
14084bff34e3Sthurlow 			error = smb_ctx_setcharset(ctx, p);
14094bff34e3Sthurlow 			if (error)
14104bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14114bff34e3Sthurlow 	"charset specification in the section '%s' ignored"),
14124bff34e3Sthurlow 				    error, sname);
14134bff34e3Sthurlow 		}
14144bff34e3Sthurlow 	}
14154bff34e3Sthurlow #endif
14164bff34e3Sthurlow 
14174bff34e3Sthurlow 	if (level <= 1) {
14184bff34e3Sthurlow 		/* Section is: [default] or [server] */
14194bff34e3Sthurlow 
14204bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "minauth", &p);
14214bff34e3Sthurlow 		if (p) {
14224bff34e3Sthurlow 			/*
14234bff34e3Sthurlow 			 * "minauth" was set in this section; override
14244bff34e3Sthurlow 			 * the current minimum authentication setting.
14254bff34e3Sthurlow 			 */
1426613a2f6bSGordon Ross 			struct nv *nvp;
1427613a2f6bSGordon Ross 			for (nvp = minauth_table; nvp->name; nvp++)
1428613a2f6bSGordon Ross 				if (strcmp(p, nvp->name) == 0)
1429613a2f6bSGordon Ross 					break;
1430613a2f6bSGordon Ross 			if (nvp->name)
1431613a2f6bSGordon Ross 				ctx->ct_minauth = nvp->value;
1432613a2f6bSGordon Ross 			else {
14334bff34e3Sthurlow 				/*
14344bff34e3Sthurlow 				 * Unknown minimum authentication level.
14354bff34e3Sthurlow 				 */
14364bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14374bff34e3Sthurlow "invalid minimum authentication level \"%s\" specified in the section %s"),
14384bff34e3Sthurlow 				    0, p, sname);
14394bff34e3Sthurlow 				return (EINVAL);
14404bff34e3Sthurlow 			}
14414bff34e3Sthurlow 		}
14424bff34e3Sthurlow 
14439c9af259SGordon Ross 		rc_getstringptr(smb_rc, sname, "signing", &p);
14449c9af259SGordon Ross 		if (p) {
14459c9af259SGordon Ross 			/*
14469c9af259SGordon Ross 			 * "signing" was set in this section; override
144702d09e03SGordon Ross 			 * the current signing settings.  Note:
144802d09e03SGordon Ross 			 * setsigning flags are: enable, require
14499c9af259SGordon Ross 			 */
14509c9af259SGordon Ross 			if (strcmp(p, "disabled") == 0) {
145102d09e03SGordon Ross 				(void) smb_ctx_setsigning(ctx, FALSE, FALSE);
14529c9af259SGordon Ross 			} else if (strcmp(p, "enabled") == 0) {
145302d09e03SGordon Ross 				(void) smb_ctx_setsigning(ctx, TRUE, FALSE);
14549c9af259SGordon Ross 			} else if (strcmp(p, "required") == 0) {
145502d09e03SGordon Ross 				(void) smb_ctx_setsigning(ctx, TRUE, TRUE);
14569c9af259SGordon Ross 			} else {
14579c9af259SGordon Ross 				/*
14589c9af259SGordon Ross 				 * Unknown "signing" value.
14599c9af259SGordon Ross 				 */
14609c9af259SGordon Ross 				smb_error(dgettext(TEXT_DOMAIN,
14619c9af259SGordon Ross "invalid signing policy \"%s\" specified in the section %s"),
14629c9af259SGordon Ross 				    0, p, sname);
14639c9af259SGordon Ross 				return (EINVAL);
14649c9af259SGordon Ross 			}
14659c9af259SGordon Ross 		}
14669c9af259SGordon Ross 
14674bff34e3Sthurlow 		/*
14684bff34e3Sthurlow 		 * Domain name.  Allow both keywords:
14694bff34e3Sthurlow 		 * "workgroup", "domain"
14704bff34e3Sthurlow 		 *
14714bff34e3Sthurlow 		 * Note: these are NOT marked "from CMD".
14724bff34e3Sthurlow 		 * See long comment at smb_ctx_init()
14734bff34e3Sthurlow 		 */
14744bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "workgroup", &p);
14754bff34e3Sthurlow 		if (p) {
1476613a2f6bSGordon Ross 			error = smb_ctx_setdomain(ctx, p, 0);
14774bff34e3Sthurlow 			if (error)
14784bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14794bff34e3Sthurlow 				    "workgroup specification in the "
14804bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
14814bff34e3Sthurlow 		}
14824bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "domain", &p);
14834bff34e3Sthurlow 		if (p) {
1484613a2f6bSGordon Ross 			error = smb_ctx_setdomain(ctx, p, 0);
14854bff34e3Sthurlow 			if (error)
14864bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14874bff34e3Sthurlow 				    "domain specification in the "
14884bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
14894bff34e3Sthurlow 		}
14904bff34e3Sthurlow 
14914bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "user", &p);
14924bff34e3Sthurlow 		if (p) {
14934bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, p, 0);
14944bff34e3Sthurlow 			if (error)
14954bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14964bff34e3Sthurlow 				    "user specification in the "
14974bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
14984bff34e3Sthurlow 		}
14994bff34e3Sthurlow 	}
15004bff34e3Sthurlow 
15014bff34e3Sthurlow 	if (level == 1) {
15024bff34e3Sthurlow 		/* Section is: [server] */
15034bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "addr", &p);
15044bff34e3Sthurlow 		if (p) {
15054bff34e3Sthurlow 			error = smb_ctx_setsrvaddr(ctx, p);
15064bff34e3Sthurlow 			if (error) {
15074bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
15084bff34e3Sthurlow 				    "invalid address specified in section %s"),
15094bff34e3Sthurlow 				    0, sname);
15104bff34e3Sthurlow 				return (error);
15114bff34e3Sthurlow 			}
15124bff34e3Sthurlow 		}
15134bff34e3Sthurlow 	}
15144bff34e3Sthurlow 
15154bff34e3Sthurlow 	rc_getstringptr(smb_rc, sname, "password", &p);
15164bff34e3Sthurlow 	if (p) {
15174bff34e3Sthurlow 		error = smb_ctx_setpassword(ctx, p, 0);
15184bff34e3Sthurlow 		if (error)
15194bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
15204bff34e3Sthurlow 	    "password specification in the section '%s' ignored"),
15214bff34e3Sthurlow 			    error, sname);
15224bff34e3Sthurlow 	}
15234bff34e3Sthurlow 
15244bff34e3Sthurlow 	return (0);
15254bff34e3Sthurlow }
15264bff34e3Sthurlow 
15274bff34e3Sthurlow /*
15284bff34e3Sthurlow  * read rc file as follows:
15294bff34e3Sthurlow  * 0: read [default] section
15304bff34e3Sthurlow  * 1: override with [server] section
15314bff34e3Sthurlow  * 2: override with [server:user] section
15324bff34e3Sthurlow  * 3: override with [server:user:share] section
15334bff34e3Sthurlow  * Since absence of rcfile is not fatal, silently ignore this fact.
15344bff34e3Sthurlow  * smb_rc file should be closed by caller.
15354bff34e3Sthurlow  */
15364bff34e3Sthurlow int
15374bff34e3Sthurlow smb_ctx_readrc(struct smb_ctx *ctx)
15384bff34e3Sthurlow {
1539613a2f6bSGordon Ross 	char *home;
1540613a2f6bSGordon Ross 	char *sname = NULL;
1541613a2f6bSGordon Ross 	int sname_max;
1542613a2f6bSGordon Ross 	int err = 0;
15434bff34e3Sthurlow 
1544613a2f6bSGordon Ross 	if ((home = getenv("HOME")) == NULL)
1545613a2f6bSGordon Ross 		home = ctx->ct_home;
1546613a2f6bSGordon Ross 	if ((err = smb_open_rcfile(home)) != 0) {
1547613a2f6bSGordon Ross 		DPRINT("smb_open_rcfile, err=%d", err);
1548613a2f6bSGordon Ross 		/* ignore any error here */
1549613a2f6bSGordon Ross 		return (0);
1550613a2f6bSGordon Ross 	}
1551613a2f6bSGordon Ross 
1552613a2f6bSGordon Ross 	sname_max = 3 * SMBIOC_MAX_NAME + 4;
1553613a2f6bSGordon Ross 	sname = malloc(sname_max);
1554613a2f6bSGordon Ross 	if (sname == NULL) {
1555613a2f6bSGordon Ross 		err = ENOMEM;
15564bff34e3Sthurlow 		goto done;
1557613a2f6bSGordon Ross 	}
15584bff34e3Sthurlow 
15594bff34e3Sthurlow 	/*
15604bff34e3Sthurlow 	 * default parameters (level=0)
15614bff34e3Sthurlow 	 */
15624bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, "default", 0);
15634bff34e3Sthurlow 	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
15644bff34e3Sthurlow 
15654bff34e3Sthurlow 	/*
15664bff34e3Sthurlow 	 * If we don't have a server name, we can't read any of the
15674bff34e3Sthurlow 	 * [server...] sections.
15684bff34e3Sthurlow 	 */
1569613a2f6bSGordon Ross 	if (ctx->ct_fullserver == NULL)
15704bff34e3Sthurlow 		goto done;
15714bff34e3Sthurlow 	/*
15724bff34e3Sthurlow 	 * SERVER parameters.
15734bff34e3Sthurlow 	 */
1574613a2f6bSGordon Ross 	smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
15754bff34e3Sthurlow 
15764bff34e3Sthurlow 	/*
15774bff34e3Sthurlow 	 * If we don't have a user name, we can't read any of the
15784bff34e3Sthurlow 	 * [server:user...] sections.
15794bff34e3Sthurlow 	 */
1580613a2f6bSGordon Ross 	if (ctx->ct_user[0] == 0)
15814bff34e3Sthurlow 		goto done;
15824bff34e3Sthurlow 	/*
15834bff34e3Sthurlow 	 * SERVER:USER parameters
15844bff34e3Sthurlow 	 */
1585613a2f6bSGordon Ross 	snprintf(sname, sname_max, "%s:%s",
1586613a2f6bSGordon Ross 	    ctx->ct_fullserver,
1587613a2f6bSGordon Ross 	    ctx->ct_user);
15884bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, sname, 2);
15894bff34e3Sthurlow 
1590613a2f6bSGordon Ross 
15914bff34e3Sthurlow 	/*
15924bff34e3Sthurlow 	 * If we don't have a share name, we can't read any of the
15934bff34e3Sthurlow 	 * [server:user:share] sections.
15944bff34e3Sthurlow 	 */
1595613a2f6bSGordon Ross 	if (ctx->ct_origshare == NULL)
1596613a2f6bSGordon Ross 		goto done;
15974bff34e3Sthurlow 	/*
15984bff34e3Sthurlow 	 * SERVER:USER:SHARE parameters
15994bff34e3Sthurlow 	 */
1600613a2f6bSGordon Ross 	snprintf(sname, sname_max, "%s:%s:%s",
1601613a2f6bSGordon Ross 	    ctx->ct_fullserver,
1602613a2f6bSGordon Ross 	    ctx->ct_user,
1603613a2f6bSGordon Ross 	    ctx->ct_origshare);
16044bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, sname, 3);
16054bff34e3Sthurlow 
16064bff34e3Sthurlow done:
1607613a2f6bSGordon Ross 	if (sname)
1608613a2f6bSGordon Ross 		free(sname);
1609613a2f6bSGordon Ross 	smb_close_rcfile();
16104bff34e3Sthurlow 	if (smb_debug)
16114bff34e3Sthurlow 		dump_ctx("after smb_ctx_readrc", ctx);
1612613a2f6bSGordon Ross 	if (err)
1613613a2f6bSGordon Ross 		DPRINT("err=%d\n", err);
16144bff34e3Sthurlow 
1615613a2f6bSGordon Ross 	return (err);
16164bff34e3Sthurlow }
1617