xref: /titanic_50/usr/src/lib/libsmbfs/smb/ctx.c (revision 613a2f6ba31e891e3d947a356daf5e563d43c1ce)
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 /*
36*613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
379c9af259SGordon Ross  * Use is subject to license terms.
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 
61*613a2f6bSGordon 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 
67*613a2f6bSGordon Ross #include "charsets.h"
68*613a2f6bSGordon Ross #include "spnego.h"
694bff34e3Sthurlow #include "derparse.h"
709c9af259SGordon Ross #include "private.h"
71*613a2f6bSGordon Ross #include "ntlm.h"
724bff34e3Sthurlow 
73*613a2f6bSGordon Ross #ifndef FALSE
74*613a2f6bSGordon Ross #define	FALSE	0
75*613a2f6bSGordon Ross #endif
76*613a2f6bSGordon Ross #ifndef TRUE
77*613a2f6bSGordon Ross #define	TRUE	1
78*613a2f6bSGordon Ross #endif
794bff34e3Sthurlow 
804bff34e3Sthurlow 
814bff34e3Sthurlow /* These two may be set by commands. */
824bff34e3Sthurlow int smb_debug, smb_verbose;
834bff34e3Sthurlow 
844bff34e3Sthurlow /*
85*613a2f6bSGordon Ross  * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
86*613a2f6bSGordon Ross  */
87*613a2f6bSGordon Ross const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
88*613a2f6bSGordon Ross 
89*613a2f6bSGordon Ross /*
909c9af259SGordon Ross  * Give the RPC library a callback hook that will be
919c9af259SGordon Ross  * called whenever we destroy or reinit an smb_ctx_t.
929c9af259SGordon Ross  * The name rpc_cleanup_smbctx() is legacy, and was
939c9af259SGordon Ross  * originally a direct call into the RPC code.
944bff34e3Sthurlow  */
959c9af259SGordon Ross static smb_ctx_close_hook_t close_hook;
964bff34e3Sthurlow static void
974bff34e3Sthurlow rpc_cleanup_smbctx(struct smb_ctx *ctx)
984bff34e3Sthurlow {
999c9af259SGordon Ross 	if (close_hook)
1009c9af259SGordon Ross 		(*close_hook)(ctx);
1014bff34e3Sthurlow }
1029c9af259SGordon Ross void
1039c9af259SGordon Ross smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
1049c9af259SGordon Ross {
1059c9af259SGordon Ross 	close_hook = hook;
1069c9af259SGordon Ross }
1074bff34e3Sthurlow 
1084bff34e3Sthurlow void
1094bff34e3Sthurlow dump_ctx_flags(int flags)
1104bff34e3Sthurlow {
1114bff34e3Sthurlow 	printf(" Flags: ");
1124bff34e3Sthurlow 	if (flags == 0)
1134bff34e3Sthurlow 		printf("0");
1144bff34e3Sthurlow 	if (flags & SMBCF_NOPWD)
1154bff34e3Sthurlow 		printf("NOPWD ");
1164bff34e3Sthurlow 	if (flags & SMBCF_SRIGHTS)
1174bff34e3Sthurlow 		printf("SRIGHTS ");
1184bff34e3Sthurlow 	if (flags & SMBCF_LOCALE)
1194bff34e3Sthurlow 		printf("LOCALE ");
1204bff34e3Sthurlow 	if (flags & SMBCF_CMD_DOM)
1214bff34e3Sthurlow 		printf("CMD_DOM ");
1224bff34e3Sthurlow 	if (flags & SMBCF_CMD_USR)
1234bff34e3Sthurlow 		printf("CMD_USR ");
1244bff34e3Sthurlow 	if (flags & SMBCF_CMD_PW)
1254bff34e3Sthurlow 		printf("CMD_PW ");
1264bff34e3Sthurlow 	if (flags & SMBCF_RESOLVED)
1274bff34e3Sthurlow 		printf("RESOLVED ");
1284bff34e3Sthurlow 	if (flags & SMBCF_KCBAD)
1294bff34e3Sthurlow 		printf("KCBAD ");
1304bff34e3Sthurlow 	if (flags & SMBCF_KCFOUND)
1314bff34e3Sthurlow 		printf("KCFOUND ");
1324bff34e3Sthurlow 	if (flags & SMBCF_BROWSEOK)
1334bff34e3Sthurlow 		printf("BROWSEOK ");
1344bff34e3Sthurlow 	if (flags & SMBCF_AUTHREQ)
1354bff34e3Sthurlow 		printf("AUTHREQ ");
1364bff34e3Sthurlow 	if (flags & SMBCF_KCSAVE)
1374bff34e3Sthurlow 		printf("KCSAVE  ");
1384bff34e3Sthurlow 	if (flags & SMBCF_XXX)
1394bff34e3Sthurlow 		printf("XXX ");
1404bff34e3Sthurlow 	if (flags & SMBCF_SSNACTIVE)
1414bff34e3Sthurlow 		printf("SSNACTIVE ");
1424bff34e3Sthurlow 	if (flags & SMBCF_KCDOMAIN)
1434bff34e3Sthurlow 		printf("KCDOMAIN ");
1444bff34e3Sthurlow 	printf("\n");
1454bff34e3Sthurlow }
1464bff34e3Sthurlow 
1474bff34e3Sthurlow void
148*613a2f6bSGordon Ross dump_iod_ssn(smb_iod_ssn_t *is)
1494bff34e3Sthurlow {
150*613a2f6bSGordon Ross 	static const char zeros[NTLM_HASH_SZ] = {0};
151*613a2f6bSGordon Ross 	struct smbioc_ossn *ssn = &is->iod_ossn;
1524bff34e3Sthurlow 
153*613a2f6bSGordon Ross 	printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
154*613a2f6bSGordon Ross 	dump_sockaddr(&ssn->ssn_srvaddr.sa);
155*613a2f6bSGordon Ross 	printf(" dom=\"%s\", user=\"%s\"\n",
156*613a2f6bSGordon Ross 	    ssn->ssn_domain, ssn->ssn_user);
157*613a2f6bSGordon Ross 	printf(" ct_vopt=0x%x, ct_owner=%d\n",
158*613a2f6bSGordon Ross 	    ssn->ssn_vopt, ssn->ssn_owner);
159*613a2f6bSGordon Ross 	printf(" ct_authflags=0x%x\n", is->iod_authflags);
160*613a2f6bSGordon Ross 
161*613a2f6bSGordon Ross 	printf(" ct_nthash:");
162*613a2f6bSGordon Ross 	if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
163*613a2f6bSGordon Ross 		smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
164*613a2f6bSGordon Ross 	else
165*613a2f6bSGordon Ross 		printf(" {0}\n");
166*613a2f6bSGordon Ross 
167*613a2f6bSGordon Ross 	printf(" ct_lmhash:");
168*613a2f6bSGordon Ross 	if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
169*613a2f6bSGordon Ross 		smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
170*613a2f6bSGordon Ross 	else
171*613a2f6bSGordon Ross 		printf(" {0}\n");
1724bff34e3Sthurlow }
1734bff34e3Sthurlow 
1744bff34e3Sthurlow void
1754bff34e3Sthurlow dump_ctx(char *where, struct smb_ctx *ctx)
1764bff34e3Sthurlow {
1774bff34e3Sthurlow 	printf("context %s:\n", where);
1784bff34e3Sthurlow 	dump_ctx_flags(ctx->ct_flags);
1794bff34e3Sthurlow 
180*613a2f6bSGordon Ross 	if (ctx->ct_locname)
1814bff34e3Sthurlow 		printf(" localname=\"%s\"", ctx->ct_locname);
182*613a2f6bSGordon Ross 	else
183*613a2f6bSGordon Ross 		printf(" localname=NULL");
1844bff34e3Sthurlow 
1854bff34e3Sthurlow 	if (ctx->ct_fullserver)
1864bff34e3Sthurlow 		printf(" fullserver=\"%s\"", ctx->ct_fullserver);
1874bff34e3Sthurlow 	else
1884bff34e3Sthurlow 		printf(" fullserver=NULL");
1894bff34e3Sthurlow 
190*613a2f6bSGordon Ross 	if (ctx->ct_srvaddr_s)
191*613a2f6bSGordon Ross 		printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
1924bff34e3Sthurlow 	else
193*613a2f6bSGordon Ross 		printf(" srvaddr_s=NULL\n");
1944bff34e3Sthurlow 
195*613a2f6bSGordon Ross 	if (ctx->ct_addrinfo)
196*613a2f6bSGordon Ross 		dump_addrinfo(ctx->ct_addrinfo);
197*613a2f6bSGordon Ross 	else
198*613a2f6bSGordon Ross 		printf(" ct_addrinfo = NULL\n");
199*613a2f6bSGordon Ross 
200*613a2f6bSGordon Ross 	dump_iod_ssn(&ctx->ct_iod_ssn);
201*613a2f6bSGordon Ross 
202*613a2f6bSGordon Ross 	printf(" share_name=\"%s\", share_type=%d\n",
203*613a2f6bSGordon Ross 	    ctx->ct_origshare ? ctx->ct_origshare : "",
204*613a2f6bSGordon Ross 	    ctx->ct_shtype_req);
205*613a2f6bSGordon Ross 
206*613a2f6bSGordon Ross 	/* dump_iod_work()? */
207*613a2f6bSGordon Ross }
208*613a2f6bSGordon Ross 
209*613a2f6bSGordon Ross int
210*613a2f6bSGordon Ross smb_ctx_alloc(struct smb_ctx **ctx_pp)
211*613a2f6bSGordon Ross {
212*613a2f6bSGordon Ross 	smb_ctx_t *ctx;
213*613a2f6bSGordon Ross 	int err;
214*613a2f6bSGordon Ross 
215*613a2f6bSGordon Ross 	ctx = malloc(sizeof (*ctx));
216*613a2f6bSGordon Ross 	if (ctx == NULL)
217*613a2f6bSGordon Ross 		return (ENOMEM);
218*613a2f6bSGordon Ross 	err = smb_ctx_init(ctx);
219*613a2f6bSGordon Ross 	if (err != 0) {
220*613a2f6bSGordon Ross 		free(ctx);
221*613a2f6bSGordon Ross 		return (err);
222*613a2f6bSGordon Ross 	}
223*613a2f6bSGordon Ross 	*ctx_pp = ctx;
224*613a2f6bSGordon Ross 	return (0);
2254bff34e3Sthurlow }
2264bff34e3Sthurlow 
2274bff34e3Sthurlow /*
228*613a2f6bSGordon Ross  * Initialize an smb_ctx struct (defaults)
229*613a2f6bSGordon Ross  */
230*613a2f6bSGordon Ross int
231*613a2f6bSGordon Ross smb_ctx_init(struct smb_ctx *ctx)
232*613a2f6bSGordon Ross {
233*613a2f6bSGordon Ross 	char pwbuf[NSS_BUFLEN_PASSWD];
234*613a2f6bSGordon Ross 	struct passwd pw;
235*613a2f6bSGordon Ross 	int error = 0;
236*613a2f6bSGordon Ross 
237*613a2f6bSGordon Ross 	bzero(ctx, sizeof (*ctx));
238*613a2f6bSGordon Ross 
239*613a2f6bSGordon Ross 	error = nb_ctx_create(&ctx->ct_nb);
240*613a2f6bSGordon Ross 	if (error)
241*613a2f6bSGordon Ross 		return (error);
242*613a2f6bSGordon Ross 
243*613a2f6bSGordon Ross 	ctx->ct_dev_fd = -1;
244*613a2f6bSGordon Ross 	ctx->ct_tran_fd = -1;
245*613a2f6bSGordon Ross 	ctx->ct_parsedlevel = SMBL_NONE;
246*613a2f6bSGordon Ross 	ctx->ct_minlevel = SMBL_NONE;
247*613a2f6bSGordon Ross 	ctx->ct_maxlevel = SMBL_PATH;
248*613a2f6bSGordon Ross 
249*613a2f6bSGordon Ross 	/* Fill in defaults */
250*613a2f6bSGordon Ross 	ctx->ct_vopt = SMBVOPT_EXT_SEC;
251*613a2f6bSGordon Ross 	ctx->ct_owner = SMBM_ANY_OWNER;
252*613a2f6bSGordon Ross 	ctx->ct_authflags = SMB_AT_DEFAULT;
253*613a2f6bSGordon Ross 	ctx->ct_minauth = SMB_AT_DEFAULT;
254*613a2f6bSGordon Ross 
255*613a2f6bSGordon Ross 	nb_ctx_setscope(ctx->ct_nb, "");
256*613a2f6bSGordon Ross 
257*613a2f6bSGordon Ross 	/*
258*613a2f6bSGordon Ross 	 * if the user name is not specified some other way,
259*613a2f6bSGordon Ross 	 * use the current user name (built-in default)
260*613a2f6bSGordon Ross 	 */
261*613a2f6bSGordon Ross 	if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
262*613a2f6bSGordon Ross 		smb_ctx_setuser(ctx, pw.pw_name, 0);
263*613a2f6bSGordon Ross 		ctx->ct_home = strdup(pw.pw_name);
264*613a2f6bSGordon Ross 	}
265*613a2f6bSGordon Ross 
266*613a2f6bSGordon Ross 	/*
267*613a2f6bSGordon Ross 	 * Set a built-in default domain (workgroup).
268*613a2f6bSGordon Ross 	 * Using the Windows/NT default for now.
269*613a2f6bSGordon Ross 	 */
270*613a2f6bSGordon Ross 	smb_ctx_setdomain(ctx, "WORKGROUP", 0);
271*613a2f6bSGordon Ross 
272*613a2f6bSGordon Ross 	return (error);
273*613a2f6bSGordon Ross }
274*613a2f6bSGordon Ross 
275*613a2f6bSGordon Ross /*
276*613a2f6bSGordon Ross  * "Scan" the command line args to find the server name,
277*613a2f6bSGordon Ross  * user name, and share name, as needed.  We need these
278*613a2f6bSGordon Ross  * before reading the RC files and/or sharectl values.
2794bff34e3Sthurlow  *
2804bff34e3Sthurlow  * The sequence for getting all the members filled in
2814bff34e3Sthurlow  * has some tricky aspects.  Here's how it works:
2824bff34e3Sthurlow  *
2834bff34e3Sthurlow  * The search order for options is as follows:
2844bff34e3Sthurlow  *   command line options
2854bff34e3Sthurlow  *   values parsed from UNC path (cmd)
2864bff34e3Sthurlow  *   values from RC file (per-user)
2874bff34e3Sthurlow  *   values from SMF (system-wide)
2884bff34e3Sthurlow  *   built-in defaults
2894bff34e3Sthurlow  *
2904bff34e3Sthurlow  * Normally, one would simply get all the values starting with
2914bff34e3Sthurlow  * the bottom of the above list and working to the top, and
2924bff34e3Sthurlow  * overwriting values as you go.  But we need an exception.
2934bff34e3Sthurlow  *
2944bff34e3Sthurlow  * In this function, we parse the UNC path and command line options,
2954bff34e3Sthurlow  * because we need (at least) the server name when we're getting the
2964bff34e3Sthurlow  * SMF and RC file values.  However, values we get from the command
2974bff34e3Sthurlow  * should not be overwritten by SMF or RC file parsing, so we mark
2984bff34e3Sthurlow  * values from the command as "from CMD" and the RC file parser
2994bff34e3Sthurlow  * leaves in place any values so marked.  See: SMBCF_CMD_*
3004bff34e3Sthurlow  *
3014bff34e3Sthurlow  * The semantics of these flags are: "This value came from the
3024bff34e3Sthurlow  * current command instance, not from sources that may apply to
3034bff34e3Sthurlow  * multiple commands."  (Different from the old "FROMUSR" flag.)
3044bff34e3Sthurlow  *
3054bff34e3Sthurlow  * Note that smb_ctx_opt() is called later to handle the
3064bff34e3Sthurlow  * remaining options, which should be ignored here.
3074bff34e3Sthurlow  * The (magic) leading ":" in cf_getopt() makes it
3084bff34e3Sthurlow  * ignore options not in the options string.
3094bff34e3Sthurlow  */
3104bff34e3Sthurlow int
311*613a2f6bSGordon Ross smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
3124bff34e3Sthurlow 	int minlevel, int maxlevel, int sharetype)
3134bff34e3Sthurlow {
314*613a2f6bSGordon Ross 	int  ind, opt, error = 0;
3154bff34e3Sthurlow 	int aflg = 0, uflg = 0;
316*613a2f6bSGordon Ross 	const char *arg;
3174bff34e3Sthurlow 
3184bff34e3Sthurlow 	/*
3194bff34e3Sthurlow 	 * Parse options, if any.  Values from here too
3204bff34e3Sthurlow 	 * are marked as "from CMD".
3214bff34e3Sthurlow 	 */
322*613a2f6bSGordon Ross 	if (argv == NULL)
323*613a2f6bSGordon Ross 		return (0);
324*613a2f6bSGordon Ross 
325*613a2f6bSGordon Ross 	ctx->ct_minlevel = minlevel;
326*613a2f6bSGordon Ross 	ctx->ct_maxlevel = maxlevel;
327*613a2f6bSGordon Ross 	ctx->ct_shtype_req = sharetype;
328*613a2f6bSGordon Ross 
329*613a2f6bSGordon Ross 	cf_opt_lock();
330*613a2f6bSGordon Ross 	/* Careful: no return/goto before cf_opt_unlock! */
331*613a2f6bSGordon Ross 	while (error == 0) {
332*613a2f6bSGordon Ross 		opt = cf_getopt(argc, argv, STDPARAM_OPT);
333*613a2f6bSGordon Ross 		if (opt == -1)
334*613a2f6bSGordon Ross 			break;
3354bff34e3Sthurlow 		arg = cf_optarg;
336*613a2f6bSGordon Ross 		/* NB: handle most in smb_ctx_opt */
3374bff34e3Sthurlow 		switch (opt) {
3384bff34e3Sthurlow 		case 'A':
3394bff34e3Sthurlow 			aflg = 1;
3404bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, "", TRUE);
3414bff34e3Sthurlow 			ctx->ct_flags |= SMBCF_NOPWD;
3424bff34e3Sthurlow 			break;
3434bff34e3Sthurlow 		case 'U':
3444bff34e3Sthurlow 			uflg = 1;
3454bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, arg, TRUE);
3464bff34e3Sthurlow 			break;
347*613a2f6bSGordon Ross 		default:
348*613a2f6bSGordon Ross 			DPRINT("skip opt=%c", opt);
349*613a2f6bSGordon Ross 			break;
3504bff34e3Sthurlow 		}
3514bff34e3Sthurlow 	}
352*613a2f6bSGordon Ross 	ind = cf_optind;
353*613a2f6bSGordon Ross 	arg = argv[ind];
354*613a2f6bSGordon Ross 	cf_optind = cf_optreset = 1;
355*613a2f6bSGordon Ross 	cf_opt_unlock();
356*613a2f6bSGordon Ross 
357*613a2f6bSGordon Ross 	if (error)
358*613a2f6bSGordon Ross 		return (error);
359*613a2f6bSGordon Ross 
3604bff34e3Sthurlow 	if (aflg && uflg)  {
3614bff34e3Sthurlow 		printf(gettext("-A and -U flags are exclusive.\n"));
362*613a2f6bSGordon Ross 		return (EINVAL);
3634bff34e3Sthurlow 	}
3644bff34e3Sthurlow 
365*613a2f6bSGordon Ross 	/*
366*613a2f6bSGordon Ross 	 * Parse the UNC path.  Values from here are
367*613a2f6bSGordon Ross 	 * marked as "from CMD".
368*613a2f6bSGordon Ross 	 */
369*613a2f6bSGordon Ross 	for (; ind < argc; ind++) {
370*613a2f6bSGordon Ross 		arg = argv[ind];
371*613a2f6bSGordon Ross 		if (strncmp(arg, "//", 2) != 0)
372*613a2f6bSGordon Ross 			continue;
373*613a2f6bSGordon Ross 		error = smb_ctx_parseunc(ctx, arg,
374*613a2f6bSGordon Ross 		    minlevel, maxlevel, sharetype, &arg);
375*613a2f6bSGordon Ross 		if (error)
376*613a2f6bSGordon Ross 			return (error);
377*613a2f6bSGordon Ross 		break;
378*613a2f6bSGordon Ross 	}
3794bff34e3Sthurlow 
3804bff34e3Sthurlow 	return (error);
3814bff34e3Sthurlow }
3824bff34e3Sthurlow 
3834bff34e3Sthurlow void
384*613a2f6bSGordon Ross smb_ctx_free(smb_ctx_t *ctx)
385*613a2f6bSGordon Ross {
386*613a2f6bSGordon Ross 	smb_ctx_done(ctx);
387*613a2f6bSGordon Ross 	free(ctx);
388*613a2f6bSGordon Ross }
389*613a2f6bSGordon Ross 
390*613a2f6bSGordon Ross void
3914bff34e3Sthurlow smb_ctx_done(struct smb_ctx *ctx)
3924bff34e3Sthurlow {
3934bff34e3Sthurlow 
3944bff34e3Sthurlow 	rpc_cleanup_smbctx(ctx);
3954bff34e3Sthurlow 
396*613a2f6bSGordon Ross 	if (ctx->ct_dev_fd != -1) {
397*613a2f6bSGordon Ross 		close(ctx->ct_dev_fd);
398*613a2f6bSGordon Ross 		ctx->ct_dev_fd = -1;
3994bff34e3Sthurlow 	}
400*613a2f6bSGordon Ross 	if (ctx->ct_tran_fd != -1) {
401*613a2f6bSGordon Ross 		close(ctx->ct_tran_fd);
402*613a2f6bSGordon Ross 		ctx->ct_tran_fd = -1;
403*613a2f6bSGordon Ross 	}
404*613a2f6bSGordon Ross 	if (ctx->ct_srvaddr_s) {
405*613a2f6bSGordon Ross 		free(ctx->ct_srvaddr_s);
406*613a2f6bSGordon Ross 		ctx->ct_srvaddr_s = NULL;
407*613a2f6bSGordon Ross 	}
408*613a2f6bSGordon Ross 	if (ctx->ct_nb) {
4094bff34e3Sthurlow 		nb_ctx_done(ctx->ct_nb);
410*613a2f6bSGordon Ross 		ctx->ct_nb = NULL;
411*613a2f6bSGordon Ross 	}
412*613a2f6bSGordon Ross 	if (ctx->ct_locname) {
413*613a2f6bSGordon Ross 		free(ctx->ct_locname);
414*613a2f6bSGordon Ross 		ctx->ct_locname = NULL;
415*613a2f6bSGordon Ross 	}
416*613a2f6bSGordon Ross 	if (ctx->ct_origshare) {
4174bff34e3Sthurlow 		free(ctx->ct_origshare);
418*613a2f6bSGordon Ross 		ctx->ct_origshare = NULL;
419*613a2f6bSGordon Ross 	}
420*613a2f6bSGordon Ross 	if (ctx->ct_fullserver) {
4214bff34e3Sthurlow 		free(ctx->ct_fullserver);
422*613a2f6bSGordon Ross 		ctx->ct_fullserver = NULL;
423*613a2f6bSGordon Ross 	}
424*613a2f6bSGordon Ross 	if (ctx->ct_addrinfo) {
425*613a2f6bSGordon Ross 		freeaddrinfo(ctx->ct_addrinfo);
426*613a2f6bSGordon Ross 		ctx->ct_addrinfo = NULL;
427*613a2f6bSGordon Ross 	}
428*613a2f6bSGordon Ross 	if (ctx->ct_home)
429*613a2f6bSGordon Ross 		free(ctx->ct_home);
430*613a2f6bSGordon Ross 	if (ctx->ct_srv_OS) {
431*613a2f6bSGordon Ross 		free(ctx->ct_srv_OS);
432*613a2f6bSGordon Ross 		ctx->ct_srv_OS = NULL;
433*613a2f6bSGordon Ross 	}
434*613a2f6bSGordon Ross 	if (ctx->ct_srv_LM) {
435*613a2f6bSGordon Ross 		free(ctx->ct_srv_LM);
436*613a2f6bSGordon Ross 		ctx->ct_srv_LM = NULL;
437*613a2f6bSGordon Ross 	}
438*613a2f6bSGordon Ross 	if (ctx->ct_mackey) {
439*613a2f6bSGordon Ross 		free(ctx->ct_mackey);
440*613a2f6bSGordon Ross 		ctx->ct_mackey = NULL;
441*613a2f6bSGordon Ross 	}
4424bff34e3Sthurlow }
4434bff34e3Sthurlow 
4444bff34e3Sthurlow static int
4454bff34e3Sthurlow getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
4464bff34e3Sthurlow     const char **next)
4474bff34e3Sthurlow {
4484bff34e3Sthurlow 	int len;
4494bff34e3Sthurlow 
4504bff34e3Sthurlow 	maxlen--;
4514bff34e3Sthurlow 	for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
4524bff34e3Sthurlow 		if (*p == 0)
4534bff34e3Sthurlow 			return (EINVAL);
4544bff34e3Sthurlow 		*dest = *p;
4554bff34e3Sthurlow 	}
4564bff34e3Sthurlow 	*dest = 0;
4574bff34e3Sthurlow 	*next = *p ? p + 1 : p;
4584bff34e3Sthurlow 	return (0);
4594bff34e3Sthurlow }
4604bff34e3Sthurlow 
4614bff34e3Sthurlow /*
4624bff34e3Sthurlow  * Parse the UNC path.  Here we expect something like
4634bff34e3Sthurlow  *   "//[workgroup;][user[:password]@]host[/share[/path]]"
4644bff34e3Sthurlow  * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
4654bff34e3Sthurlow  * Values found here are marked as "from CMD".
4664bff34e3Sthurlow  */
4674bff34e3Sthurlow int
468*613a2f6bSGordon Ross smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
469*613a2f6bSGordon Ross 	int minlevel, int maxlevel, int sharetype,
4704bff34e3Sthurlow 	const char **next)
4714bff34e3Sthurlow {
4724bff34e3Sthurlow 	const char *p = unc;
473*613a2f6bSGordon Ross 	char *p1, *colon;
4744bff34e3Sthurlow 	char tmp[1024];
4754bff34e3Sthurlow 	char tmp2[1024];
4764bff34e3Sthurlow 	int error;
4774bff34e3Sthurlow 
478*613a2f6bSGordon Ross 	/*
479*613a2f6bSGordon Ross 	 * This may be called outside of _scan_argv,
480*613a2f6bSGordon Ross 	 * so make sure these get initialized.
481*613a2f6bSGordon Ross 	 */
482*613a2f6bSGordon Ross 	ctx->ct_minlevel = minlevel;
483*613a2f6bSGordon Ross 	ctx->ct_maxlevel = maxlevel;
484*613a2f6bSGordon Ross 	ctx->ct_shtype_req = sharetype;
485*613a2f6bSGordon Ross 
4864bff34e3Sthurlow 	ctx->ct_parsedlevel = SMBL_NONE;
4874bff34e3Sthurlow 	if (*p++ != '/' || *p++ != '/') {
4884bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
4894bff34e3Sthurlow 		    "UNC should start with '//'"), 0);
490*613a2f6bSGordon Ross 		error = EINVAL;
491*613a2f6bSGordon Ross 		goto out;
4924bff34e3Sthurlow 	}
4934bff34e3Sthurlow 	p1 = tmp;
4944bff34e3Sthurlow 	error = getsubstring(p, ';', p1, sizeof (tmp), &p);
4954bff34e3Sthurlow 	if (!error) {
4964bff34e3Sthurlow 		if (*p1 == 0) {
4974bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
4984bff34e3Sthurlow 			    "empty workgroup name"), 0);
499*613a2f6bSGordon Ross 			error = EINVAL;
500*613a2f6bSGordon Ross 			goto out;
5014bff34e3Sthurlow 		}
5024bff34e3Sthurlow 		nls_str_upper(tmp, tmp);
503*613a2f6bSGordon Ross 		error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE);
5044bff34e3Sthurlow 		if (error)
505*613a2f6bSGordon Ross 			goto out;
5064bff34e3Sthurlow 	}
5074bff34e3Sthurlow 	colon = (char *)p;
5084bff34e3Sthurlow 	error = getsubstring(p, '@', p1, sizeof (tmp), &p);
5094bff34e3Sthurlow 	if (!error) {
5104bff34e3Sthurlow 		if (ctx->ct_maxlevel < SMBL_VC) {
5114bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5124bff34e3Sthurlow 			    "no user name required"), 0);
513*613a2f6bSGordon Ross 			error = EINVAL;
514*613a2f6bSGordon Ross 			goto out;
5154bff34e3Sthurlow 		}
5164bff34e3Sthurlow 		p1 = strchr(tmp, ':');
5174bff34e3Sthurlow 		if (p1) {
5184bff34e3Sthurlow 			colon += p1 - tmp;
5194bff34e3Sthurlow 			*p1++ = (char)0;
5204bff34e3Sthurlow 			error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
5214bff34e3Sthurlow 			if (error)
522*613a2f6bSGordon Ross 				goto out;
5234bff34e3Sthurlow 			if (p - colon > 2)
5244bff34e3Sthurlow 				memset(colon+1, '*', p - colon - 2);
5254bff34e3Sthurlow 		}
5264bff34e3Sthurlow 		p1 = tmp;
5274bff34e3Sthurlow 		if (*p1 == 0) {
5284bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5294bff34e3Sthurlow 			    "empty user name"), 0);
530*613a2f6bSGordon Ross 			error = EINVAL;
531*613a2f6bSGordon Ross 			goto out;
5324bff34e3Sthurlow 		}
5334bff34e3Sthurlow 		error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
5344bff34e3Sthurlow 		if (error)
535*613a2f6bSGordon Ross 			goto out;
5364bff34e3Sthurlow 		ctx->ct_parsedlevel = SMBL_VC;
5374bff34e3Sthurlow 	}
5384bff34e3Sthurlow 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
5394bff34e3Sthurlow 	if (error) {
5404bff34e3Sthurlow 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
5414bff34e3Sthurlow 		if (error) {
5424bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5434bff34e3Sthurlow 			    "no server name found"), 0);
544*613a2f6bSGordon Ross 			goto out;
5454bff34e3Sthurlow 		}
5464bff34e3Sthurlow 	}
5474bff34e3Sthurlow 	if (*p1 == 0) {
5484bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
549*613a2f6bSGordon Ross 		error = EINVAL;
550*613a2f6bSGordon Ross 		goto out;
5514bff34e3Sthurlow 	}
5524bff34e3Sthurlow 
5534bff34e3Sthurlow 	/*
5544bff34e3Sthurlow 	 * It's safe to uppercase this string, which
5554bff34e3Sthurlow 	 * consists of ascii characters that should
5564bff34e3Sthurlow 	 * be uppercased, %s, and ascii characters representing
5574bff34e3Sthurlow 	 * hex digits 0-9 and A-F (already uppercased, and
5584bff34e3Sthurlow 	 * if not uppercased they need to be). However,
5594bff34e3Sthurlow 	 * it is NOT safe to uppercase after it has been
560*613a2f6bSGordon Ross 	 * "unpercent" converted, below!
5614bff34e3Sthurlow 	 */
5624bff34e3Sthurlow 	nls_str_upper(tmp2, tmp);
5634bff34e3Sthurlow 
5644bff34e3Sthurlow 	/*
565*613a2f6bSGordon Ross 	 * Save ct_fullserver without case conversion.
5664bff34e3Sthurlow 	 */
567*613a2f6bSGordon Ross 	if (strchr(tmp, '%'))
568*613a2f6bSGordon Ross 		(void) unpercent(tmp);
569*613a2f6bSGordon Ross 	smb_ctx_setfullserver(ctx, tmp);
5704bff34e3Sthurlow 	if (error)
571*613a2f6bSGordon Ross 		goto out;
572*613a2f6bSGordon Ross 
573*613a2f6bSGordon Ross #ifdef	SMB_ST_NONE
5744bff34e3Sthurlow 	if (sharetype == SMB_ST_NONE) {
575*613a2f6bSGordon Ross 		if (next)
5764bff34e3Sthurlow 			*next = p;
577*613a2f6bSGordon Ross 		error = 0;
578*613a2f6bSGordon Ross 		goto out;
5794bff34e3Sthurlow 	}
580*613a2f6bSGordon Ross #endif
581*613a2f6bSGordon Ross 
5824bff34e3Sthurlow 	if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
5834bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
584*613a2f6bSGordon Ross 		error = EINVAL;
585*613a2f6bSGordon Ross 		goto out;
5864bff34e3Sthurlow 	}
5874bff34e3Sthurlow 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
5884bff34e3Sthurlow 	if (error) {
5894bff34e3Sthurlow 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
5904bff34e3Sthurlow 		if (error) {
5914bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5924bff34e3Sthurlow 			    "unexpected end of line"), 0);
593*613a2f6bSGordon Ross 			goto out;
5944bff34e3Sthurlow 		}
5954bff34e3Sthurlow 	}
5964bff34e3Sthurlow 	if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
5974bff34e3Sthurlow 	    !(ctx->ct_flags & SMBCF_BROWSEOK)) {
5984bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
599*613a2f6bSGordon Ross 		error = EINVAL;
600*613a2f6bSGordon Ross 		goto out;
6014bff34e3Sthurlow 	}
602*613a2f6bSGordon Ross 	if (next)
6034bff34e3Sthurlow 		*next = p;
604*613a2f6bSGordon Ross 	if (*p1 == 0) {
605*613a2f6bSGordon Ross 		error = 0;
606*613a2f6bSGordon Ross 		goto out;
607*613a2f6bSGordon Ross 	}
6084bff34e3Sthurlow 	error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
609*613a2f6bSGordon Ross 
610*613a2f6bSGordon Ross out:
611*613a2f6bSGordon Ross 	if (error == 0 && smb_debug > 0)
612*613a2f6bSGordon Ross 		dump_ctx("after smb_ctx_parseunc", ctx);
613*613a2f6bSGordon Ross 
6144bff34e3Sthurlow 	return (error);
6154bff34e3Sthurlow }
6164bff34e3Sthurlow 
617*613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
6184bff34e3Sthurlow int
6194bff34e3Sthurlow smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
6204bff34e3Sthurlow {
6214bff34e3Sthurlow 	char *cp, *servercs, *localcs;
6224bff34e3Sthurlow 	int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
6234bff34e3Sthurlow 	int scslen, lcslen, error;
6244bff34e3Sthurlow 
6254bff34e3Sthurlow 	cp = strchr(arg, ':');
6264bff34e3Sthurlow 	lcslen = cp ? (cp - arg) : 0;
6274bff34e3Sthurlow 	if (lcslen == 0 || lcslen >= cslen) {
6284bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
6294bff34e3Sthurlow 		    "invalid local charset specification (%s)"), 0, arg);
6304bff34e3Sthurlow 		return (EINVAL);
6314bff34e3Sthurlow 	}
6324bff34e3Sthurlow 	scslen = (size_t)strlen(++cp);
6334bff34e3Sthurlow 	if (scslen == 0 || scslen >= cslen) {
6344bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
6354bff34e3Sthurlow 		    "invalid server charset specification (%s)"), 0, arg);
6364bff34e3Sthurlow 		return (EINVAL);
6374bff34e3Sthurlow 	}
6384bff34e3Sthurlow 	localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
6394bff34e3Sthurlow 	localcs[lcslen] = 0;
6404bff34e3Sthurlow 	servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
6414bff34e3Sthurlow 	error = nls_setrecode(localcs, servercs);
6424bff34e3Sthurlow 	if (error == 0)
6434bff34e3Sthurlow 		return (0);
6444bff34e3Sthurlow 	smb_error(dgettext(TEXT_DOMAIN,
6454bff34e3Sthurlow 	    "can't initialize iconv support (%s:%s)"),
6464bff34e3Sthurlow 	    error, localcs, servercs);
6474bff34e3Sthurlow 	localcs[0] = 0;
6484bff34e3Sthurlow 	servercs[0] = 0;
6494bff34e3Sthurlow 	return (error);
6504bff34e3Sthurlow }
651*613a2f6bSGordon Ross #endif /* KICONV_SUPPORT */
652*613a2f6bSGordon Ross 
653*613a2f6bSGordon Ross int
654*613a2f6bSGordon Ross smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
655*613a2f6bSGordon Ross {
656*613a2f6bSGordon Ross 	ctx->ct_authflags = flags;
657*613a2f6bSGordon Ross 	return (0);
658*613a2f6bSGordon Ross }
6594bff34e3Sthurlow 
6604bff34e3Sthurlow int
6614bff34e3Sthurlow smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
6624bff34e3Sthurlow {
663*613a2f6bSGordon Ross 	char *p = strdup(name);
664*613a2f6bSGordon Ross 
665*613a2f6bSGordon Ross 	if (p == NULL)
6664bff34e3Sthurlow 		return (ENOMEM);
667*613a2f6bSGordon Ross 	if (ctx->ct_fullserver)
668*613a2f6bSGordon Ross 		free(ctx->ct_fullserver);
669*613a2f6bSGordon Ross 	ctx->ct_fullserver = p;
6704bff34e3Sthurlow 	return (0);
6714bff34e3Sthurlow }
6724bff34e3Sthurlow 
6734bff34e3Sthurlow /* this routine does not uppercase the server name */
674*613a2f6bSGordon Ross int
6754bff34e3Sthurlow smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
6764bff34e3Sthurlow {
6774bff34e3Sthurlow 	/* don't uppercase the server name */
678*613a2f6bSGordon Ross 	strlcpy(ctx->ct_srvname, name,
679*613a2f6bSGordon Ross 	    sizeof (ctx->ct_srvname));
680*613a2f6bSGordon Ross 	return (0);
6814bff34e3Sthurlow }
6824bff34e3Sthurlow 
6834bff34e3Sthurlow int
6844bff34e3Sthurlow smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
6854bff34e3Sthurlow {
6864bff34e3Sthurlow 
687*613a2f6bSGordon Ross 	if (strlen(name) >= sizeof (ctx->ct_user)) {
6884bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
6894bff34e3Sthurlow 		    "user name '%s' too long"), 0, name);
6904bff34e3Sthurlow 		return (ENAMETOOLONG);
6914bff34e3Sthurlow 	}
6924bff34e3Sthurlow 
6934bff34e3Sthurlow 	/*
6944bff34e3Sthurlow 	 * Don't overwrite a value from the command line
6954bff34e3Sthurlow 	 * with one from anywhere else.
6964bff34e3Sthurlow 	 */
6974bff34e3Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
6984bff34e3Sthurlow 		return (0);
6994bff34e3Sthurlow 
7004bff34e3Sthurlow 	/* don't uppercase the username, just copy it. */
701*613a2f6bSGordon Ross 	strlcpy(ctx->ct_user, name,
702*613a2f6bSGordon 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  * Never uppercase the workgroup
7134bff34e3Sthurlow  * name here, because it might come
7144bff34e3Sthurlow  * from a Windows codepage encoding.
7154bff34e3Sthurlow  *
7164bff34e3Sthurlow  * Don't overwrite a domain name from the
7174bff34e3Sthurlow  * command line with one from anywhere else.
7184bff34e3Sthurlow  * See smb_ctx_init() for notes about this.
7194bff34e3Sthurlow  */
7204bff34e3Sthurlow int
721*613a2f6bSGordon Ross smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd)
7224bff34e3Sthurlow {
7234bff34e3Sthurlow 
724*613a2f6bSGordon Ross 	if (strlen(name) >= sizeof (ctx->ct_domain)) {
7254bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
7264bff34e3Sthurlow 		    "workgroup name '%s' too long"), 0, name);
7274bff34e3Sthurlow 		return (ENAMETOOLONG);
7284bff34e3Sthurlow 	}
7294bff34e3Sthurlow 
7304bff34e3Sthurlow 	/*
7314bff34e3Sthurlow 	 * Don't overwrite a value from the command line
7324bff34e3Sthurlow 	 * with one from anywhere else.
7334bff34e3Sthurlow 	 */
7344bff34e3Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
7354bff34e3Sthurlow 		return (0);
7364bff34e3Sthurlow 
737*613a2f6bSGordon Ross 	strlcpy(ctx->ct_domain, name,
738*613a2f6bSGordon Ross 	    sizeof (ctx->ct_domain));
7394bff34e3Sthurlow 
7404bff34e3Sthurlow 	/* Mark this as "from the command line". */
7414bff34e3Sthurlow 	if (from_cmd)
7424bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_CMD_DOM;
7434bff34e3Sthurlow 
7444bff34e3Sthurlow 	return (0);
7454bff34e3Sthurlow }
7464bff34e3Sthurlow 
7474bff34e3Sthurlow int
7484bff34e3Sthurlow smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
7494bff34e3Sthurlow {
750*613a2f6bSGordon Ross 	int err;
7514bff34e3Sthurlow 
752*613a2f6bSGordon Ross 	if (passwd == NULL)
7534bff34e3Sthurlow 		return (EINVAL);
754*613a2f6bSGordon Ross 	if (strlen(passwd) >= sizeof (ctx->ct_password)) {
7554bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
7564bff34e3Sthurlow 		return (ENAMETOOLONG);
7574bff34e3Sthurlow 	}
7584bff34e3Sthurlow 
7594bff34e3Sthurlow 	/*
760*613a2f6bSGordon Ross 	 * If called again after comand line parsing,
761*613a2f6bSGordon Ross 	 * don't overwrite a value from the command line
762*613a2f6bSGordon Ross 	 * with one from any stored config.
7634bff34e3Sthurlow 	 */
7644bff34e3Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
7654bff34e3Sthurlow 		return (0);
7664bff34e3Sthurlow 
767*613a2f6bSGordon Ross 	memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
7684bff34e3Sthurlow 	if (strncmp(passwd, "$$1", 3) == 0)
769*613a2f6bSGordon Ross 		smb_simpledecrypt(ctx->ct_password, passwd);
7704bff34e3Sthurlow 	else
771*613a2f6bSGordon Ross 		strlcpy(ctx->ct_password, passwd,
772*613a2f6bSGordon Ross 		    sizeof (ctx->ct_password));
773*613a2f6bSGordon Ross 
774*613a2f6bSGordon Ross 	/*
775*613a2f6bSGordon Ross 	 * Compute LM hash, NT hash.
776*613a2f6bSGordon Ross 	 */
777*613a2f6bSGordon Ross 	if (ctx->ct_password[0]) {
778*613a2f6bSGordon Ross 		err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
779*613a2f6bSGordon Ross 		if (err != 0)
780*613a2f6bSGordon Ross 			return (err);
781*613a2f6bSGordon Ross 		err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
782*613a2f6bSGordon Ross 		if (err != 0)
783*613a2f6bSGordon Ross 			return (err);
784*613a2f6bSGordon Ross 	}
7854bff34e3Sthurlow 
7864bff34e3Sthurlow 	/* Mark this as "from the command line". */
7874bff34e3Sthurlow 	if (from_cmd)
7884bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_CMD_PW;
7894bff34e3Sthurlow 
7904bff34e3Sthurlow 	return (0);
7914bff34e3Sthurlow }
7924bff34e3Sthurlow 
793*613a2f6bSGordon Ross /*
794*613a2f6bSGordon Ross  * Use this to set NTLM auth. info (hashes)
795*613a2f6bSGordon Ross  * when we don't have the password.
796*613a2f6bSGordon Ross  */
797*613a2f6bSGordon Ross int
798*613a2f6bSGordon Ross smb_ctx_setpwhash(smb_ctx_t *ctx,
799*613a2f6bSGordon Ross     const uchar_t *nthash, const uchar_t *lmhash)
800*613a2f6bSGordon Ross {
801*613a2f6bSGordon Ross 
802*613a2f6bSGordon Ross 	/* Need ct_password to be non-null. */
803*613a2f6bSGordon Ross 	if (ctx->ct_password[0] == '\0')
804*613a2f6bSGordon Ross 		strlcpy(ctx->ct_password, "$HASH",
805*613a2f6bSGordon Ross 		    sizeof (ctx->ct_password));
806*613a2f6bSGordon Ross 
807*613a2f6bSGordon Ross 	/*
808*613a2f6bSGordon Ross 	 * Compute LM hash, NT hash.
809*613a2f6bSGordon Ross 	 */
810*613a2f6bSGordon Ross 	memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
811*613a2f6bSGordon Ross 
812*613a2f6bSGordon Ross 	/* The LM hash is optional */
813*613a2f6bSGordon Ross 	if (lmhash) {
814*613a2f6bSGordon Ross 		memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
815*613a2f6bSGordon Ross 	}
816*613a2f6bSGordon Ross 
817*613a2f6bSGordon Ross 	return (0);
818*613a2f6bSGordon Ross }
819*613a2f6bSGordon Ross 
8204bff34e3Sthurlow int
8214bff34e3Sthurlow smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
8224bff34e3Sthurlow {
823*613a2f6bSGordon Ross 	if (strlen(share) >= SMBIOC_MAX_NAME) {
8244bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
8254bff34e3Sthurlow 		    "share name '%s' too long"), 0, share);
8264bff34e3Sthurlow 		return (ENAMETOOLONG);
8274bff34e3Sthurlow 	}
8284bff34e3Sthurlow 	if (ctx->ct_origshare)
8294bff34e3Sthurlow 		free(ctx->ct_origshare);
8304bff34e3Sthurlow 	if ((ctx->ct_origshare = strdup(share)) == NULL)
8314bff34e3Sthurlow 		return (ENOMEM);
832*613a2f6bSGordon Ross 
833*613a2f6bSGordon Ross 	ctx->ct_shtype_req = stype;
834*613a2f6bSGordon Ross 
8354bff34e3Sthurlow 	return (0);
8364bff34e3Sthurlow }
8374bff34e3Sthurlow 
8384bff34e3Sthurlow int
8394bff34e3Sthurlow smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
8404bff34e3Sthurlow {
8414bff34e3Sthurlow 	if (addr == NULL || addr[0] == 0)
8424bff34e3Sthurlow 		return (EINVAL);
843*613a2f6bSGordon Ross 	if (ctx->ct_srvaddr_s)
844*613a2f6bSGordon Ross 		free(ctx->ct_srvaddr_s);
845*613a2f6bSGordon Ross 	if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL)
8464bff34e3Sthurlow 		return (ENOMEM);
8474bff34e3Sthurlow 	return (0);
8484bff34e3Sthurlow }
8494bff34e3Sthurlow 
8504bff34e3Sthurlow static int
8514bff34e3Sthurlow smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
8524bff34e3Sthurlow {
8534bff34e3Sthurlow 	struct group gr;
8544bff34e3Sthurlow 	struct passwd pw;
8554bff34e3Sthurlow 	char buf[NSS_BUFLEN_PASSWD];
8564bff34e3Sthurlow 	char *cp;
8574bff34e3Sthurlow 
8584bff34e3Sthurlow 	cp = strchr(pair, ':');
8594bff34e3Sthurlow 	if (cp) {
8604bff34e3Sthurlow 		*cp++ = '\0';
861*613a2f6bSGordon Ross 		if (*cp && gid) {
8624bff34e3Sthurlow 			if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
8634bff34e3Sthurlow 				*gid = gr.gr_gid;
8644bff34e3Sthurlow 			} else
8654bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
8664bff34e3Sthurlow 				    "Invalid group name %s, ignored"), 0, cp);
8674bff34e3Sthurlow 		}
8684bff34e3Sthurlow 	}
8694bff34e3Sthurlow 	if (*pair) {
8704bff34e3Sthurlow 		if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
8714bff34e3Sthurlow 			*uid = pw.pw_uid;
8724bff34e3Sthurlow 		} else
8734bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
8744bff34e3Sthurlow 			    "Invalid user name %s, ignored"), 0, pair);
8754bff34e3Sthurlow 	}
8764bff34e3Sthurlow 
8774bff34e3Sthurlow 	return (0);
8784bff34e3Sthurlow }
8794bff34e3Sthurlow 
8804bff34e3Sthurlow /*
8814bff34e3Sthurlow  * Commands use this with getopt.  See:
8824bff34e3Sthurlow  *   STDPARAM_OPT, STDPARAM_ARGS
8834bff34e3Sthurlow  * Called after smb_ctx_readrc().
8844bff34e3Sthurlow  */
8854bff34e3Sthurlow int
8864bff34e3Sthurlow smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
8874bff34e3Sthurlow {
8884bff34e3Sthurlow 	int error = 0;
8894bff34e3Sthurlow 	char *p, *cp;
8904bff34e3Sthurlow 	char tmp[1024];
8914bff34e3Sthurlow 
8924bff34e3Sthurlow 	switch (opt) {
8934bff34e3Sthurlow 	case 'A':
8944bff34e3Sthurlow 	case 'U':
8954bff34e3Sthurlow 		/* Handled in smb_ctx_init() */
8964bff34e3Sthurlow 		break;
8974bff34e3Sthurlow 	case 'I':
8984bff34e3Sthurlow 		error = smb_ctx_setsrvaddr(ctx, arg);
8994bff34e3Sthurlow 		break;
9004bff34e3Sthurlow 	case 'M':
901*613a2f6bSGordon Ross 		/* share connect rights - ignored */
9024bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_SRIGHTS;
9034bff34e3Sthurlow 		break;
9044bff34e3Sthurlow 	case 'N':
9054bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_NOPWD;
9064bff34e3Sthurlow 		break;
9074bff34e3Sthurlow 	case 'O':
9084bff34e3Sthurlow 		p = strdup(arg);
9094bff34e3Sthurlow 		cp = strchr(p, '/');
910*613a2f6bSGordon Ross 		if (cp)
911*613a2f6bSGordon Ross 			*cp = '\0';
912*613a2f6bSGordon Ross 		error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
9134bff34e3Sthurlow 		free(p);
9144bff34e3Sthurlow 		break;
9154bff34e3Sthurlow 	case 'P':
916*613a2f6bSGordon Ross /*		ctx->ct_vopt |= SMBCOPT_PERMANENT; */
9174bff34e3Sthurlow 		break;
9184bff34e3Sthurlow 	case 'R':
919*613a2f6bSGordon Ross 		/* retry count - ignored */
9204bff34e3Sthurlow 		break;
9214bff34e3Sthurlow 	case 'T':
922*613a2f6bSGordon Ross 		/* timeout - ignored */
9234bff34e3Sthurlow 		break;
924*613a2f6bSGordon Ross 	case 'D':	/* domain */
925*613a2f6bSGordon Ross 	case 'W':	/* workgroup (legacy alias) */
9264bff34e3Sthurlow 		nls_str_upper(tmp, arg);
927*613a2f6bSGordon Ross 		error = smb_ctx_setdomain(ctx, tmp, TRUE);
9284bff34e3Sthurlow 		break;
9294bff34e3Sthurlow 	}
9304bff34e3Sthurlow 	return (error);
9314bff34e3Sthurlow }
9324bff34e3Sthurlow 
9334bff34e3Sthurlow 
934*613a2f6bSGordon Ross /*
935*613a2f6bSGordon Ross  * Original code injected iconv tables into the kernel.
936*613a2f6bSGordon Ross  * Not sure if we'll need this or not...  REVISIT
937*613a2f6bSGordon Ross  */
938*613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
9394bff34e3Sthurlow static int
9404bff34e3Sthurlow smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
9414bff34e3Sthurlow {
942*613a2f6bSGordon Ross 	int error = 0;
9434bff34e3Sthurlow 
9444bff34e3Sthurlow 	error = kiconv_add_xlat_table(to, from, tbl);
9454bff34e3Sthurlow 	if (error && error != EEXIST) {
9464bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
9474bff34e3Sthurlow 		    "can not setup kernel iconv table (%s:%s)"),
9484bff34e3Sthurlow 		    error, from, to);
9494bff34e3Sthurlow 		return (error);
9504bff34e3Sthurlow 	}
951*613a2f6bSGordon Ross 	return (error);
9524bff34e3Sthurlow }
953*613a2f6bSGordon Ross #endif	/* KICONV_SUPPORT */
9544bff34e3Sthurlow 
9554bff34e3Sthurlow /*
956*613a2f6bSGordon Ross  * Verify context info. before connect operation(s),
9574bff34e3Sthurlow  * lookup specified server and try to fill all forgotten fields.
958*613a2f6bSGordon Ross  * Legacy name used by commands.
9594bff34e3Sthurlow  */
9604bff34e3Sthurlow int
9614bff34e3Sthurlow smb_ctx_resolve(struct smb_ctx *ctx)
9624bff34e3Sthurlow {
9634bff34e3Sthurlow 	struct smbioc_ossn *ssn = &ctx->ct_ssn;
964*613a2f6bSGordon Ross 	int error = 0;
965*613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
9664bff34e3Sthurlow 	uchar_t cstbl[256];
9674bff34e3Sthurlow 	uint_t i;
968*613a2f6bSGordon Ross #endif
9694bff34e3Sthurlow 
9704bff34e3Sthurlow 	ctx->ct_flags &= ~SMBCF_RESOLVED;
971*613a2f6bSGordon Ross 
972*613a2f6bSGordon Ross 	if (ctx->ct_fullserver == NULL) {
9734bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
9744bff34e3Sthurlow 		    "no server name specified"), 0);
9754bff34e3Sthurlow 		return (EINVAL);
9764bff34e3Sthurlow 	}
977*613a2f6bSGordon Ross 
978*613a2f6bSGordon Ross 	if (ctx->ct_minlevel >= SMBL_SHARE &&
979*613a2f6bSGordon Ross 	    ctx->ct_origshare == NULL) {
9804bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
9814bff34e3Sthurlow 		    "no share name specified for %s@%s"),
982*613a2f6bSGordon Ross 		    0, ssn->ssn_user, ctx->ct_fullserver);
9834bff34e3Sthurlow 		return (EINVAL);
9844bff34e3Sthurlow 	}
9854bff34e3Sthurlow 	error = nb_ctx_resolve(ctx->ct_nb);
9864bff34e3Sthurlow 	if (error)
9874bff34e3Sthurlow 		return (error);
988*613a2f6bSGordon Ross #ifdef KICONV_SUPPORT
9894bff34e3Sthurlow 	if (ssn->ioc_localcs[0] == 0)
9904bff34e3Sthurlow 		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
9914bff34e3Sthurlow 	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
9924bff34e3Sthurlow 	if (error)
9934bff34e3Sthurlow 		return (error);
9944bff34e3Sthurlow 	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
9954bff34e3Sthurlow 	if (error)
9964bff34e3Sthurlow 		return (error);
9974bff34e3Sthurlow 	if (ssn->ioc_servercs[0] != 0) {
9984bff34e3Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
9994bff34e3Sthurlow 			cstbl[i] = i;
10004bff34e3Sthurlow 		nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
10014bff34e3Sthurlow 		error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
10024bff34e3Sthurlow 		    cstbl);
10034bff34e3Sthurlow 		if (error)
10044bff34e3Sthurlow 			return (error);
10054bff34e3Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
10064bff34e3Sthurlow 			cstbl[i] = i;
10074bff34e3Sthurlow 		nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
10084bff34e3Sthurlow 		error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
10094bff34e3Sthurlow 		    cstbl);
10104bff34e3Sthurlow 		if (error)
10114bff34e3Sthurlow 			return (error);
10124bff34e3Sthurlow 	}
1013*613a2f6bSGordon Ross #endif	/* KICONV_SUPPORT */
10144bff34e3Sthurlow 
10154bff34e3Sthurlow 	/*
1016*613a2f6bSGordon Ross 	 * Lookup the IP address.
1017*613a2f6bSGordon Ross 	 * Puts a list in ct_addrinfo
10184bff34e3Sthurlow 	 */
1019*613a2f6bSGordon Ross 	error = smb_ctx_getaddr(ctx);
10204bff34e3Sthurlow 	if (error) {
10214bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10224bff34e3Sthurlow 		    "can't get server address"), error);
10234bff34e3Sthurlow 		return (error);
10244bff34e3Sthurlow 	}
1025*613a2f6bSGordon Ross 	assert(ctx->ct_addrinfo != NULL);
10264bff34e3Sthurlow 
10274bff34e3Sthurlow 	/*
1028*613a2f6bSGordon Ross 	 * If we have a user name but no password,
1029*613a2f6bSGordon Ross 	 * check for a keychain entry.
1030*613a2f6bSGordon Ross 	 * XXX: Only for auth NTLM?
10314bff34e3Sthurlow 	 */
1032*613a2f6bSGordon Ross 	if (ctx->ct_user[0] == '\0') {
10334bff34e3Sthurlow 		/*
1034*613a2f6bSGordon Ross 		 * No user name (anonymous session).
1035*613a2f6bSGordon Ross 		 * The minauth checks do not apply.
10364bff34e3Sthurlow 		 */
1037*613a2f6bSGordon Ross 		ctx->ct_authflags = SMB_AT_ANON;
1038*613a2f6bSGordon Ross 	} else {
10394bff34e3Sthurlow 		/*
1040*613a2f6bSGordon Ross 		 * Have a user name.
1041*613a2f6bSGordon Ross 		 * If we don't have a p/w yet,
1042*613a2f6bSGordon Ross 		 * try the keychain.
10434bff34e3Sthurlow 		 */
1044*613a2f6bSGordon Ross 		if (ctx->ct_password[0] == '\0')
1045*613a2f6bSGordon Ross 			(void) smb_get_keychain(ctx);
1046*613a2f6bSGordon Ross 		/*
1047*613a2f6bSGordon Ross 		 * If we're doing p/w based auth,
1048*613a2f6bSGordon Ross 		 * that means not using Kerberos.
1049*613a2f6bSGordon Ross 		 */
1050*613a2f6bSGordon Ross 		if (ctx->ct_password[0] != '\0')
1051*613a2f6bSGordon Ross 			ctx->ct_authflags &= ~SMB_AT_KRB5;
1052*613a2f6bSGordon Ross 		/*
1053*613a2f6bSGordon Ross 		 * Mask out disallowed auth types.
1054*613a2f6bSGordon Ross 		 */
1055*613a2f6bSGordon Ross 		ctx->ct_authflags &= ctx->ct_minauth;
10564bff34e3Sthurlow 	}
1057*613a2f6bSGordon Ross 	if (ctx->ct_authflags == 0) {
10584bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1059*613a2f6bSGordon Ross 		    "no valid auth. types"), 0);
1060*613a2f6bSGordon Ross 		return (ENOTSUP);
10614bff34e3Sthurlow 	}
1062*613a2f6bSGordon Ross 
10634bff34e3Sthurlow 	ctx->ct_flags |= SMBCF_RESOLVED;
10644bff34e3Sthurlow 	if (smb_debug)
10654bff34e3Sthurlow 		dump_ctx("after smb_ctx_resolve", ctx);
10664bff34e3Sthurlow 
10674bff34e3Sthurlow 	return (0);
10684bff34e3Sthurlow }
10694bff34e3Sthurlow 
10704bff34e3Sthurlow int
10714bff34e3Sthurlow smb_open_driver()
10724bff34e3Sthurlow {
1073*613a2f6bSGordon Ross 	int err, fd;
10744bff34e3Sthurlow 	uint32_t version;
10754bff34e3Sthurlow 
10764bff34e3Sthurlow 	fd = open("/dev/"NSMB_NAME, O_RDWR);
1077*613a2f6bSGordon Ross 	if (fd < 0) {
1078*613a2f6bSGordon Ross 		err = errno;
10794bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1080*613a2f6bSGordon Ross 		    "failed to open driver"), err);
10814bff34e3Sthurlow 		return (-1);
1082*613a2f6bSGordon Ross 	}
10834bff34e3Sthurlow 
10844bff34e3Sthurlow 	/*
10854bff34e3Sthurlow 	 * Check the driver version (paranoia)
10864bff34e3Sthurlow 	 * Do this BEFORE any other ioctl calls.
10874bff34e3Sthurlow 	 */
1088*613a2f6bSGordon Ross 	if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1089*613a2f6bSGordon Ross 		version = 0;
10904bff34e3Sthurlow 	if (version != NSMB_VERSION) {
10914bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
10924bff34e3Sthurlow 		    "incorrect driver version"), 0);
10934bff34e3Sthurlow 		close(fd);
10944bff34e3Sthurlow 		return (-1);
10954bff34e3Sthurlow 	}
10964bff34e3Sthurlow 
1097*613a2f6bSGordon Ross 	/* This handle controls per-process resources. */
1098*613a2f6bSGordon Ross 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1099*613a2f6bSGordon Ross 
11004bff34e3Sthurlow 	return (fd);
11014bff34e3Sthurlow }
11024bff34e3Sthurlow 
1103*613a2f6bSGordon Ross int
11044bff34e3Sthurlow smb_ctx_gethandle(struct smb_ctx *ctx)
11054bff34e3Sthurlow {
1106*613a2f6bSGordon Ross 	int fd;
11074bff34e3Sthurlow 
1108*613a2f6bSGordon Ross 	if (ctx->ct_dev_fd != -1) {
11094bff34e3Sthurlow 		rpc_cleanup_smbctx(ctx);
1110*613a2f6bSGordon Ross 		close(ctx->ct_dev_fd);
1111*613a2f6bSGordon Ross 		ctx->ct_dev_fd = -1;
11124bff34e3Sthurlow 		ctx->ct_flags &= ~SMBCF_SSNACTIVE;
11134bff34e3Sthurlow 	}
11144bff34e3Sthurlow 
11154bff34e3Sthurlow 	fd = smb_open_driver();
11164bff34e3Sthurlow 	if (fd < 0)
11174bff34e3Sthurlow 		return (ENODEV);
11184bff34e3Sthurlow 
1119*613a2f6bSGordon Ross 	ctx->ct_dev_fd = fd;
11204bff34e3Sthurlow 	return (0);
11214bff34e3Sthurlow }
11224bff34e3Sthurlow 
1123*613a2f6bSGordon Ross 
1124*613a2f6bSGordon Ross /*
1125*613a2f6bSGordon Ross  * Find or create a connection + logon session
1126*613a2f6bSGordon Ross  */
11274bff34e3Sthurlow int
1128*613a2f6bSGordon Ross smb_ctx_get_ssn(struct smb_ctx *ctx)
11294bff34e3Sthurlow {
1130*613a2f6bSGordon Ross 	int err = 0;
11314bff34e3Sthurlow 
1132*613a2f6bSGordon Ross 	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
11334bff34e3Sthurlow 		return (EINVAL);
11344bff34e3Sthurlow 
1135*613a2f6bSGordon Ross 	if (ctx->ct_dev_fd < 0) {
1136*613a2f6bSGordon Ross 		if ((err = smb_ctx_gethandle(ctx)))
1137*613a2f6bSGordon Ross 			return (err);
11384bff34e3Sthurlow 	}
11394bff34e3Sthurlow 
11404bff34e3Sthurlow 	/*
1141*613a2f6bSGordon Ross 	 * Check whether the driver already has a VC
1142*613a2f6bSGordon Ross 	 * we can use.  If so, we're done!
11434bff34e3Sthurlow 	 */
1144*613a2f6bSGordon Ross 	err = smb_ctx_findvc(ctx);
1145*613a2f6bSGordon Ross 	if (err == 0) {
1146*613a2f6bSGordon Ross 		DPRINT("found an existing VC");
11474bff34e3Sthurlow 	} else {
1148*613a2f6bSGordon Ross 		/*
1149*613a2f6bSGordon Ross 		 * This calls the IOD to create a new session.
1150*613a2f6bSGordon Ross 		 */
1151*613a2f6bSGordon Ross 		DPRINT("setup a new VC");
1152*613a2f6bSGordon Ross 		err = smb_ctx_newvc(ctx);
1153*613a2f6bSGordon Ross 		if (err != 0)
1154*613a2f6bSGordon Ross 			return (err);
1155*613a2f6bSGordon Ross 
1156*613a2f6bSGordon Ross 		/*
1157*613a2f6bSGordon Ross 		 * Call findvc again.  The new VC sould be
1158*613a2f6bSGordon Ross 		 * found in the driver this time.
1159*613a2f6bSGordon Ross 		 */
1160*613a2f6bSGordon Ross 		err = smb_ctx_findvc(ctx);
11614bff34e3Sthurlow 	}
1162*613a2f6bSGordon Ross 
1163*613a2f6bSGordon Ross 	return (err);
11644bff34e3Sthurlow }
11654bff34e3Sthurlow 
11664bff34e3Sthurlow /*
1167*613a2f6bSGordon Ross  * Get the string representation of a share "use" type,
1168*613a2f6bSGordon Ross  * as needed for the "service" in tree connect.
11694bff34e3Sthurlow  */
1170*613a2f6bSGordon Ross static const char *
1171*613a2f6bSGordon Ross smb_use_type_str(smb_use_shtype_t stype)
1172*613a2f6bSGordon Ross {
1173*613a2f6bSGordon Ross 	const char *pp;
1174*613a2f6bSGordon Ross 
1175*613a2f6bSGordon Ross 	switch (stype) {
1176*613a2f6bSGordon Ross 	default:
1177*613a2f6bSGordon Ross 	case USE_WILDCARD:
1178*613a2f6bSGordon Ross 		pp = "?????";
1179*613a2f6bSGordon Ross 		break;
1180*613a2f6bSGordon Ross 	case USE_DISKDEV:
1181*613a2f6bSGordon Ross 		pp = "A:";
1182*613a2f6bSGordon Ross 		break;
1183*613a2f6bSGordon Ross 	case USE_SPOOLDEV:
1184*613a2f6bSGordon Ross 		pp = "LPT1:";
1185*613a2f6bSGordon Ross 		break;
1186*613a2f6bSGordon Ross 	case USE_CHARDEV:
1187*613a2f6bSGordon Ross 		pp = "COMM";
1188*613a2f6bSGordon Ross 		break;
1189*613a2f6bSGordon Ross 	case USE_IPC:
1190*613a2f6bSGordon Ross 		pp = "IPC";
1191*613a2f6bSGordon Ross 		break;
1192*613a2f6bSGordon Ross 	}
1193*613a2f6bSGordon Ross 	return (pp);
1194*613a2f6bSGordon Ross }
1195*613a2f6bSGordon Ross 
11964bff34e3Sthurlow /*
1197*613a2f6bSGordon Ross  * Find or create a tree connection
11984bff34e3Sthurlow  */
1199*613a2f6bSGordon Ross int
1200*613a2f6bSGordon Ross smb_ctx_get_tree(struct smb_ctx *ctx)
1201*613a2f6bSGordon Ross {
1202*613a2f6bSGordon Ross 	smbioc_tcon_t *tcon = NULL;
1203*613a2f6bSGordon Ross 	const char *stype;
1204*613a2f6bSGordon Ross 	int cmd, err = 0;
1205*613a2f6bSGordon Ross 
1206*613a2f6bSGordon Ross 	if (ctx->ct_dev_fd < 0 ||
1207*613a2f6bSGordon Ross 	    ctx->ct_origshare == NULL) {
1208*613a2f6bSGordon Ross 		return (EINVAL);
1209*613a2f6bSGordon Ross 	}
1210*613a2f6bSGordon Ross 
1211*613a2f6bSGordon Ross 	cmd = SMBIOC_TREE_CONNECT;
1212*613a2f6bSGordon Ross 	tcon = malloc(sizeof (*tcon));
1213*613a2f6bSGordon Ross 	if (tcon == NULL)
1214*613a2f6bSGordon Ross 		return (ENOMEM);
1215*613a2f6bSGordon Ross 	bzero(tcon, sizeof (*tcon));
1216*613a2f6bSGordon Ross 	tcon->tc_flags = SMBLK_CREATE;
1217*613a2f6bSGordon Ross 	tcon->tc_opt = 0;
1218*613a2f6bSGordon Ross 
1219*613a2f6bSGordon Ross 	/* The share name */
1220*613a2f6bSGordon Ross 	strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
1221*613a2f6bSGordon Ross 	    sizeof (tcon->tc_sh.sh_name));
1222*613a2f6bSGordon Ross 
1223*613a2f6bSGordon Ross 	/* The share "use" type. */
1224*613a2f6bSGordon Ross 	stype = smb_use_type_str(ctx->ct_shtype_req);
1225*613a2f6bSGordon Ross 	strlcpy(tcon->tc_sh.sh_type_req, stype,
1226*613a2f6bSGordon Ross 	    sizeof (tcon->tc_sh.sh_type_req));
1227*613a2f6bSGordon Ross 
1228*613a2f6bSGordon Ross 	/*
1229*613a2f6bSGordon Ross 	 * Todo: share passwords for share-level security.
1230*613a2f6bSGordon Ross 	 *
1231*613a2f6bSGordon Ross 	 * The driver does the actual TCON call.
1232*613a2f6bSGordon Ross 	 */
1233*613a2f6bSGordon Ross 	if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1234*613a2f6bSGordon Ross 		err = errno;
12354bff34e3Sthurlow 		goto out;
12364bff34e3Sthurlow 	}
1237*613a2f6bSGordon Ross 
1238*613a2f6bSGordon Ross 	/*
1239*613a2f6bSGordon Ross 	 * Check the returned share type
1240*613a2f6bSGordon Ross 	 */
1241*613a2f6bSGordon Ross 	DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret);
1242*613a2f6bSGordon Ross 	if (ctx->ct_shtype_req != USE_WILDCARD &&
1243*613a2f6bSGordon Ross 	    0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) {
1244*613a2f6bSGordon Ross 		smb_error(dgettext(TEXT_DOMAIN,
1245*613a2f6bSGordon Ross 		    "%s: incompatible share type"),
1246*613a2f6bSGordon Ross 		    0, ctx->ct_origshare);
1247*613a2f6bSGordon Ross 		err = EINVAL;
12484bff34e3Sthurlow 	}
12494bff34e3Sthurlow 
12504bff34e3Sthurlow out:
1251*613a2f6bSGordon Ross 	if (tcon != NULL)
1252*613a2f6bSGordon Ross 		free(tcon);
1253*613a2f6bSGordon Ross 
1254*613a2f6bSGordon Ross 	return (err);
12554bff34e3Sthurlow }
12564bff34e3Sthurlow 
12574bff34e3Sthurlow /*
12584bff34e3Sthurlow  * Return the hflags2 word for an smb_ctx.
12594bff34e3Sthurlow  */
12604bff34e3Sthurlow int
12614bff34e3Sthurlow smb_ctx_flags2(struct smb_ctx *ctx)
12624bff34e3Sthurlow {
12634bff34e3Sthurlow 	uint16_t flags2;
12644bff34e3Sthurlow 
1265*613a2f6bSGordon Ross 	if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
12664bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
12674bff34e3Sthurlow 		    "can't get flags2 for a session"), errno);
12684bff34e3Sthurlow 		return (-1);
12694bff34e3Sthurlow 	}
12704bff34e3Sthurlow 	return (flags2);
12714bff34e3Sthurlow }
12724bff34e3Sthurlow 
12734bff34e3Sthurlow /*
1274*613a2f6bSGordon Ross  * Get the transport level session key.
1275*613a2f6bSGordon Ross  * Must already have an active SMB session.
1276*613a2f6bSGordon Ross  */
1277*613a2f6bSGordon Ross int
1278*613a2f6bSGordon Ross smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len)
1279*613a2f6bSGordon Ross {
1280*613a2f6bSGordon Ross 	if (len < SMBIOC_HASH_SZ)
1281*613a2f6bSGordon Ross 		return (EINVAL);
1282*613a2f6bSGordon Ross 
1283*613a2f6bSGordon Ross 	if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1284*613a2f6bSGordon Ross 		return (errno);
1285*613a2f6bSGordon Ross 
1286*613a2f6bSGordon Ross 	return (0);
1287*613a2f6bSGordon Ross }
1288*613a2f6bSGordon Ross 
1289*613a2f6bSGordon Ross 
1290*613a2f6bSGordon Ross /*
1291*613a2f6bSGordon Ross  * RC file parsing stuff
1292*613a2f6bSGordon Ross  */
1293*613a2f6bSGordon Ross 
1294*613a2f6bSGordon Ross struct nv {
1295*613a2f6bSGordon Ross 	char *name;
1296*613a2f6bSGordon Ross 	int value;
1297*613a2f6bSGordon Ross } minauth_table[] = {
1298*613a2f6bSGordon Ross 	/* Allowed auth. types */
1299*613a2f6bSGordon Ross 	{ "kerberos",	SMB_AT_KRB5 },
1300*613a2f6bSGordon Ross 	{ "ntlmv2",	SMB_AT_KRB5|SMB_AT_NTLM2 },
1301*613a2f6bSGordon Ross 	{ "ntlm",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
1302*613a2f6bSGordon Ross 	{ "lm",		SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
1303*613a2f6bSGordon Ross 	{ "none",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
1304*613a2f6bSGordon Ross 			SMB_AT_ANON },
1305*613a2f6bSGordon Ross 	{ NULL }
1306*613a2f6bSGordon Ross };
1307*613a2f6bSGordon Ross 
1308*613a2f6bSGordon Ross 
1309*613a2f6bSGordon Ross /*
13104bff34e3Sthurlow  * level values:
13114bff34e3Sthurlow  * 0 - default
13124bff34e3Sthurlow  * 1 - server
13134bff34e3Sthurlow  * 2 - server:user
13144bff34e3Sthurlow  * 3 - server:user:share
13154bff34e3Sthurlow  */
13164bff34e3Sthurlow static int
13174bff34e3Sthurlow smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
13184bff34e3Sthurlow {
13194bff34e3Sthurlow 	char *p;
13204bff34e3Sthurlow 	int error;
13214bff34e3Sthurlow 
1322*613a2f6bSGordon Ross #ifdef	KICONV_SUPPORT
13234bff34e3Sthurlow 	if (level > 0) {
13244bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "charsets", &p);
13254bff34e3Sthurlow 		if (p) {
13264bff34e3Sthurlow 			error = smb_ctx_setcharset(ctx, p);
13274bff34e3Sthurlow 			if (error)
13284bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
13294bff34e3Sthurlow 	"charset specification in the section '%s' ignored"),
13304bff34e3Sthurlow 				    error, sname);
13314bff34e3Sthurlow 		}
13324bff34e3Sthurlow 	}
13334bff34e3Sthurlow #endif
13344bff34e3Sthurlow 
13354bff34e3Sthurlow 	if (level <= 1) {
13364bff34e3Sthurlow 		/* Section is: [default] or [server] */
13374bff34e3Sthurlow 
13384bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "minauth", &p);
13394bff34e3Sthurlow 		if (p) {
13404bff34e3Sthurlow 			/*
13414bff34e3Sthurlow 			 * "minauth" was set in this section; override
13424bff34e3Sthurlow 			 * the current minimum authentication setting.
13434bff34e3Sthurlow 			 */
1344*613a2f6bSGordon Ross 			struct nv *nvp;
1345*613a2f6bSGordon Ross 			for (nvp = minauth_table; nvp->name; nvp++)
1346*613a2f6bSGordon Ross 				if (strcmp(p, nvp->name) == 0)
1347*613a2f6bSGordon Ross 					break;
1348*613a2f6bSGordon Ross 			if (nvp->name)
1349*613a2f6bSGordon Ross 				ctx->ct_minauth = nvp->value;
1350*613a2f6bSGordon Ross 			else {
13514bff34e3Sthurlow 				/*
13524bff34e3Sthurlow 				 * Unknown minimum authentication level.
13534bff34e3Sthurlow 				 */
13544bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
13554bff34e3Sthurlow "invalid minimum authentication level \"%s\" specified in the section %s"),
13564bff34e3Sthurlow 				    0, p, sname);
13574bff34e3Sthurlow 				return (EINVAL);
13584bff34e3Sthurlow 			}
13594bff34e3Sthurlow 		}
13604bff34e3Sthurlow 
13619c9af259SGordon Ross 		rc_getstringptr(smb_rc, sname, "signing", &p);
13629c9af259SGordon Ross 		if (p) {
13639c9af259SGordon Ross 			/*
13649c9af259SGordon Ross 			 * "signing" was set in this section; override
13659c9af259SGordon Ross 			 * the current signing settings.
13669c9af259SGordon Ross 			 */
1367*613a2f6bSGordon Ross 			ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
13689c9af259SGordon Ross 			if (strcmp(p, "disabled") == 0) {
13699c9af259SGordon Ross 				/* leave flags zero (expr for lint) */
1370*613a2f6bSGordon Ross 				(void) ctx->ct_vopt;
13719c9af259SGordon Ross 			} else if (strcmp(p, "enabled") == 0) {
1372*613a2f6bSGordon Ross 				ctx->ct_vopt |=
13739c9af259SGordon Ross 				    SMBVOPT_SIGNING_ENABLED;
13749c9af259SGordon Ross 			} else if (strcmp(p, "required") == 0) {
1375*613a2f6bSGordon Ross 				ctx->ct_vopt |=
13769c9af259SGordon Ross 				    SMBVOPT_SIGNING_ENABLED |
13779c9af259SGordon Ross 				    SMBVOPT_SIGNING_REQUIRED;
13789c9af259SGordon Ross 			} else {
13799c9af259SGordon Ross 				/*
13809c9af259SGordon Ross 				 * Unknown "signing" value.
13819c9af259SGordon Ross 				 */
13829c9af259SGordon Ross 				smb_error(dgettext(TEXT_DOMAIN,
13839c9af259SGordon Ross "invalid signing policy \"%s\" specified in the section %s"),
13849c9af259SGordon Ross 				    0, p, sname);
13859c9af259SGordon Ross 				return (EINVAL);
13869c9af259SGordon Ross 			}
13879c9af259SGordon Ross 		}
13889c9af259SGordon Ross 
13894bff34e3Sthurlow 		/*
13904bff34e3Sthurlow 		 * Domain name.  Allow both keywords:
13914bff34e3Sthurlow 		 * "workgroup", "domain"
13924bff34e3Sthurlow 		 *
13934bff34e3Sthurlow 		 * Note: these are NOT marked "from CMD".
13944bff34e3Sthurlow 		 * See long comment at smb_ctx_init()
13954bff34e3Sthurlow 		 */
13964bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "workgroup", &p);
13974bff34e3Sthurlow 		if (p) {
13984bff34e3Sthurlow 			nls_str_upper(p, p);
1399*613a2f6bSGordon Ross 			error = smb_ctx_setdomain(ctx, p, 0);
14004bff34e3Sthurlow 			if (error)
14014bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14024bff34e3Sthurlow 				    "workgroup specification in the "
14034bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
14044bff34e3Sthurlow 		}
14054bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "domain", &p);
14064bff34e3Sthurlow 		if (p) {
14074bff34e3Sthurlow 			nls_str_upper(p, p);
1408*613a2f6bSGordon Ross 			error = smb_ctx_setdomain(ctx, p, 0);
14094bff34e3Sthurlow 			if (error)
14104bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14114bff34e3Sthurlow 				    "domain specification in the "
14124bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
14134bff34e3Sthurlow 		}
14144bff34e3Sthurlow 
14154bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "user", &p);
14164bff34e3Sthurlow 		if (p) {
14174bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, p, 0);
14184bff34e3Sthurlow 			if (error)
14194bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14204bff34e3Sthurlow 				    "user specification in the "
14214bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
14224bff34e3Sthurlow 		}
14234bff34e3Sthurlow 	}
14244bff34e3Sthurlow 
14254bff34e3Sthurlow 	if (level == 1) {
14264bff34e3Sthurlow 		/* Section is: [server] */
14274bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "addr", &p);
14284bff34e3Sthurlow 		if (p) {
14294bff34e3Sthurlow 			error = smb_ctx_setsrvaddr(ctx, p);
14304bff34e3Sthurlow 			if (error) {
14314bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
14324bff34e3Sthurlow 				    "invalid address specified in section %s"),
14334bff34e3Sthurlow 				    0, sname);
14344bff34e3Sthurlow 				return (error);
14354bff34e3Sthurlow 			}
14364bff34e3Sthurlow 		}
14374bff34e3Sthurlow 	}
14384bff34e3Sthurlow 
14394bff34e3Sthurlow 	rc_getstringptr(smb_rc, sname, "password", &p);
14404bff34e3Sthurlow 	if (p) {
14414bff34e3Sthurlow 		error = smb_ctx_setpassword(ctx, p, 0);
14424bff34e3Sthurlow 		if (error)
14434bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
14444bff34e3Sthurlow 	    "password specification in the section '%s' ignored"),
14454bff34e3Sthurlow 			    error, sname);
14464bff34e3Sthurlow 	}
14474bff34e3Sthurlow 
14484bff34e3Sthurlow 	return (0);
14494bff34e3Sthurlow }
14504bff34e3Sthurlow 
14514bff34e3Sthurlow /*
14524bff34e3Sthurlow  * read rc file as follows:
14534bff34e3Sthurlow  * 0: read [default] section
14544bff34e3Sthurlow  * 1: override with [server] section
14554bff34e3Sthurlow  * 2: override with [server:user] section
14564bff34e3Sthurlow  * 3: override with [server:user:share] section
14574bff34e3Sthurlow  * Since absence of rcfile is not fatal, silently ignore this fact.
14584bff34e3Sthurlow  * smb_rc file should be closed by caller.
14594bff34e3Sthurlow  */
14604bff34e3Sthurlow int
14614bff34e3Sthurlow smb_ctx_readrc(struct smb_ctx *ctx)
14624bff34e3Sthurlow {
1463*613a2f6bSGordon Ross 	char *home;
1464*613a2f6bSGordon Ross 	char *sname = NULL;
1465*613a2f6bSGordon Ross 	int sname_max;
1466*613a2f6bSGordon Ross 	int err = 0;
14674bff34e3Sthurlow 
1468*613a2f6bSGordon Ross 	if ((home = getenv("HOME")) == NULL)
1469*613a2f6bSGordon Ross 		home = ctx->ct_home;
1470*613a2f6bSGordon Ross 	if ((err = smb_open_rcfile(home)) != 0) {
1471*613a2f6bSGordon Ross 		DPRINT("smb_open_rcfile, err=%d", err);
1472*613a2f6bSGordon Ross 		/* ignore any error here */
1473*613a2f6bSGordon Ross 		return (0);
1474*613a2f6bSGordon Ross 	}
1475*613a2f6bSGordon Ross 
1476*613a2f6bSGordon Ross 	sname_max = 3 * SMBIOC_MAX_NAME + 4;
1477*613a2f6bSGordon Ross 	sname = malloc(sname_max);
1478*613a2f6bSGordon Ross 	if (sname == NULL) {
1479*613a2f6bSGordon Ross 		err = ENOMEM;
14804bff34e3Sthurlow 		goto done;
1481*613a2f6bSGordon Ross 	}
14824bff34e3Sthurlow 
14834bff34e3Sthurlow 	/*
14844bff34e3Sthurlow 	 * default parameters (level=0)
14854bff34e3Sthurlow 	 */
14864bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, "default", 0);
14874bff34e3Sthurlow 	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
14884bff34e3Sthurlow 
14894bff34e3Sthurlow 	/*
14904bff34e3Sthurlow 	 * If we don't have a server name, we can't read any of the
14914bff34e3Sthurlow 	 * [server...] sections.
14924bff34e3Sthurlow 	 */
1493*613a2f6bSGordon Ross 	if (ctx->ct_fullserver == NULL)
14944bff34e3Sthurlow 		goto done;
14954bff34e3Sthurlow 	/*
14964bff34e3Sthurlow 	 * SERVER parameters.
14974bff34e3Sthurlow 	 */
1498*613a2f6bSGordon Ross 	smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
14994bff34e3Sthurlow 
15004bff34e3Sthurlow 	/*
15014bff34e3Sthurlow 	 * If we don't have a user name, we can't read any of the
15024bff34e3Sthurlow 	 * [server:user...] sections.
15034bff34e3Sthurlow 	 */
1504*613a2f6bSGordon Ross 	if (ctx->ct_user[0] == 0)
15054bff34e3Sthurlow 		goto done;
15064bff34e3Sthurlow 	/*
15074bff34e3Sthurlow 	 * SERVER:USER parameters
15084bff34e3Sthurlow 	 */
1509*613a2f6bSGordon Ross 	snprintf(sname, sname_max, "%s:%s",
1510*613a2f6bSGordon Ross 	    ctx->ct_fullserver,
1511*613a2f6bSGordon Ross 	    ctx->ct_user);
15124bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, sname, 2);
15134bff34e3Sthurlow 
1514*613a2f6bSGordon Ross 
15154bff34e3Sthurlow 	/*
15164bff34e3Sthurlow 	 * If we don't have a share name, we can't read any of the
15174bff34e3Sthurlow 	 * [server:user:share] sections.
15184bff34e3Sthurlow 	 */
1519*613a2f6bSGordon Ross 	if (ctx->ct_origshare == NULL)
1520*613a2f6bSGordon Ross 		goto done;
15214bff34e3Sthurlow 	/*
15224bff34e3Sthurlow 	 * SERVER:USER:SHARE parameters
15234bff34e3Sthurlow 	 */
1524*613a2f6bSGordon Ross 	snprintf(sname, sname_max, "%s:%s:%s",
1525*613a2f6bSGordon Ross 	    ctx->ct_fullserver,
1526*613a2f6bSGordon Ross 	    ctx->ct_user,
1527*613a2f6bSGordon Ross 	    ctx->ct_origshare);
15284bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, sname, 3);
15294bff34e3Sthurlow 
15304bff34e3Sthurlow done:
1531*613a2f6bSGordon Ross 	if (sname)
1532*613a2f6bSGordon Ross 		free(sname);
1533*613a2f6bSGordon Ross 	smb_close_rcfile();
15344bff34e3Sthurlow 	if (smb_debug)
15354bff34e3Sthurlow 		dump_ctx("after smb_ctx_readrc", ctx);
1536*613a2f6bSGordon Ross 	if (err)
1537*613a2f6bSGordon Ross 		DPRINT("err=%d\n", err);
15384bff34e3Sthurlow 
1539*613a2f6bSGordon Ross 	return (err);
15404bff34e3Sthurlow }
1541