xref: /titanic_54/usr/src/lib/libsmbfs/smb/ctx.c (revision 4bff34e37def8a90f9194d81bc345c52ba20086a)
1*4bff34e3Sthurlow /*
2*4bff34e3Sthurlow  * Copyright (c) 2000, Boris Popov
3*4bff34e3Sthurlow  * All rights reserved.
4*4bff34e3Sthurlow  *
5*4bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
6*4bff34e3Sthurlow  * modification, are permitted provided that the following conditions
7*4bff34e3Sthurlow  * are met:
8*4bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
9*4bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
10*4bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
11*4bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
12*4bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
13*4bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
14*4bff34e3Sthurlow  *    must display the following acknowledgement:
15*4bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
16*4bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
17*4bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
18*4bff34e3Sthurlow  *    without specific prior written permission.
19*4bff34e3Sthurlow  *
20*4bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21*4bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*4bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*4bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24*4bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*4bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*4bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*4bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*4bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*4bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*4bff34e3Sthurlow  * SUCH DAMAGE.
31*4bff34e3Sthurlow  *
32*4bff34e3Sthurlow  * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $
33*4bff34e3Sthurlow  */
34*4bff34e3Sthurlow 
35*4bff34e3Sthurlow #pragma ident	"%Z%%M%	%I%	%E% SMI"
36*4bff34e3Sthurlow 
37*4bff34e3Sthurlow #include <sys/param.h>
38*4bff34e3Sthurlow #include <sys/ioctl.h>
39*4bff34e3Sthurlow #include <sys/time.h>
40*4bff34e3Sthurlow #include <sys/mount.h>
41*4bff34e3Sthurlow #include <sys/types.h>
42*4bff34e3Sthurlow #include <sys/byteorder.h>
43*4bff34e3Sthurlow 
44*4bff34e3Sthurlow #include <fcntl.h>
45*4bff34e3Sthurlow #include <ctype.h>
46*4bff34e3Sthurlow #include <errno.h>
47*4bff34e3Sthurlow #include <stdio.h>
48*4bff34e3Sthurlow #include <string.h>
49*4bff34e3Sthurlow #include <strings.h>
50*4bff34e3Sthurlow #include <stdlib.h>
51*4bff34e3Sthurlow #include <pwd.h>
52*4bff34e3Sthurlow #include <grp.h>
53*4bff34e3Sthurlow #include <unistd.h>
54*4bff34e3Sthurlow #include <libintl.h>
55*4bff34e3Sthurlow #include <assert.h>
56*4bff34e3Sthurlow #include <nss_dbdefs.h>
57*4bff34e3Sthurlow 
58*4bff34e3Sthurlow #include <kerberosv5/krb5.h>
59*4bff34e3Sthurlow #include <kerberosv5/com_err.h>
60*4bff34e3Sthurlow 
61*4bff34e3Sthurlow extern uid_t real_uid, eff_uid;
62*4bff34e3Sthurlow 
63*4bff34e3Sthurlow #define	NB_NEEDRESOLVER
64*4bff34e3Sthurlow 
65*4bff34e3Sthurlow #include <netsmb/smb_lib.h>
66*4bff34e3Sthurlow #include <netsmb/netbios.h>
67*4bff34e3Sthurlow #include <netsmb/nb_lib.h>
68*4bff34e3Sthurlow #include <netsmb/smb_dev.h>
69*4bff34e3Sthurlow #include <cflib.h>
70*4bff34e3Sthurlow #include <charsets.h>
71*4bff34e3Sthurlow 
72*4bff34e3Sthurlow #include <spnego.h>
73*4bff34e3Sthurlow #include "derparse.h"
74*4bff34e3Sthurlow 
75*4bff34e3Sthurlow extern MECH_OID g_stcMechOIDList [];
76*4bff34e3Sthurlow 
77*4bff34e3Sthurlow #define	POWEROF2(x) (((x) & ((x)-1)) == 0)
78*4bff34e3Sthurlow 
79*4bff34e3Sthurlow /* These two may be set by commands. */
80*4bff34e3Sthurlow int smb_debug, smb_verbose;
81*4bff34e3Sthurlow 
82*4bff34e3Sthurlow /*
83*4bff34e3Sthurlow  * This used to call the DCE/RPC code.
84*4bff34e3Sthurlow  * We want more strict layering than this.
85*4bff34e3Sthurlow  * The redirector should simply export a
86*4bff34e3Sthurlow  * remote pipe API, comsumed by dce rpc.
87*4bff34e3Sthurlow  * Make it a no-op for now.
88*4bff34e3Sthurlow  */
89*4bff34e3Sthurlow #if 0
90*4bff34e3Sthurlow #include <rpc_cleanup.h>
91*4bff34e3Sthurlow #else
92*4bff34e3Sthurlow static void
93*4bff34e3Sthurlow rpc_cleanup_smbctx(struct smb_ctx *ctx)
94*4bff34e3Sthurlow {
95*4bff34e3Sthurlow }
96*4bff34e3Sthurlow #endif
97*4bff34e3Sthurlow 
98*4bff34e3Sthurlow void
99*4bff34e3Sthurlow dump_ctx_flags(int flags)
100*4bff34e3Sthurlow {
101*4bff34e3Sthurlow 	printf(" Flags: ");
102*4bff34e3Sthurlow 	if (flags == 0)
103*4bff34e3Sthurlow 		printf("0");
104*4bff34e3Sthurlow 	if (flags & SMBCF_NOPWD)
105*4bff34e3Sthurlow 		printf("NOPWD ");
106*4bff34e3Sthurlow 	if (flags & SMBCF_SRIGHTS)
107*4bff34e3Sthurlow 		printf("SRIGHTS ");
108*4bff34e3Sthurlow 	if (flags & SMBCF_LOCALE)
109*4bff34e3Sthurlow 		printf("LOCALE ");
110*4bff34e3Sthurlow 	if (flags & SMBCF_CMD_DOM)
111*4bff34e3Sthurlow 		printf("CMD_DOM ");
112*4bff34e3Sthurlow 	if (flags & SMBCF_CMD_USR)
113*4bff34e3Sthurlow 		printf("CMD_USR ");
114*4bff34e3Sthurlow 	if (flags & SMBCF_CMD_PW)
115*4bff34e3Sthurlow 		printf("CMD_PW ");
116*4bff34e3Sthurlow 	if (flags & SMBCF_RESOLVED)
117*4bff34e3Sthurlow 		printf("RESOLVED ");
118*4bff34e3Sthurlow 	if (flags & SMBCF_KCBAD)
119*4bff34e3Sthurlow 		printf("KCBAD ");
120*4bff34e3Sthurlow 	if (flags & SMBCF_KCFOUND)
121*4bff34e3Sthurlow 		printf("KCFOUND ");
122*4bff34e3Sthurlow 	if (flags & SMBCF_BROWSEOK)
123*4bff34e3Sthurlow 		printf("BROWSEOK ");
124*4bff34e3Sthurlow 	if (flags & SMBCF_AUTHREQ)
125*4bff34e3Sthurlow 		printf("AUTHREQ ");
126*4bff34e3Sthurlow 	if (flags & SMBCF_KCSAVE)
127*4bff34e3Sthurlow 		printf("KCSAVE  ");
128*4bff34e3Sthurlow 	if (flags & SMBCF_XXX)
129*4bff34e3Sthurlow 		printf("XXX ");
130*4bff34e3Sthurlow 	if (flags & SMBCF_SSNACTIVE)
131*4bff34e3Sthurlow 		printf("SSNACTIVE ");
132*4bff34e3Sthurlow 	if (flags & SMBCF_KCDOMAIN)
133*4bff34e3Sthurlow 		printf("KCDOMAIN ");
134*4bff34e3Sthurlow 	printf("\n");
135*4bff34e3Sthurlow }
136*4bff34e3Sthurlow 
137*4bff34e3Sthurlow void
138*4bff34e3Sthurlow dump_ctx_ssn(struct smbioc_ossn *ssn)
139*4bff34e3Sthurlow {
140*4bff34e3Sthurlow 	printf(" srvname=\"%s\", dom=\"%s\", user=\"%s\", password=%s\n",
141*4bff34e3Sthurlow 	    ssn->ioc_srvname, ssn->ioc_workgroup, ssn->ioc_user,
142*4bff34e3Sthurlow 	    ssn->ioc_password[0] ? "(non-null)" : "NULL");
143*4bff34e3Sthurlow 	printf(" timeout=%d, retry=%d, owner=%d, group=%d\n",
144*4bff34e3Sthurlow 	    ssn->ioc_timeout, ssn->ioc_retrycount,
145*4bff34e3Sthurlow 	    ssn->ioc_owner, ssn->ioc_group);
146*4bff34e3Sthurlow }
147*4bff34e3Sthurlow 
148*4bff34e3Sthurlow void
149*4bff34e3Sthurlow dump_ctx_sh(struct smbioc_oshare *sh)
150*4bff34e3Sthurlow {
151*4bff34e3Sthurlow 	printf(" share_name=\"%s\", share_pw=\"%s\"\n",
152*4bff34e3Sthurlow 	    sh->ioc_share, sh->ioc_password);
153*4bff34e3Sthurlow }
154*4bff34e3Sthurlow 
155*4bff34e3Sthurlow void
156*4bff34e3Sthurlow dump_ctx(char *where, struct smb_ctx *ctx)
157*4bff34e3Sthurlow {
158*4bff34e3Sthurlow 	printf("context %s:\n", where);
159*4bff34e3Sthurlow 	dump_ctx_flags(ctx->ct_flags);
160*4bff34e3Sthurlow 
161*4bff34e3Sthurlow 	printf(" localname=\"%s\"", ctx->ct_locname);
162*4bff34e3Sthurlow 
163*4bff34e3Sthurlow 	if (ctx->ct_fullserver)
164*4bff34e3Sthurlow 		printf(" fullserver=\"%s\"", ctx->ct_fullserver);
165*4bff34e3Sthurlow 	else
166*4bff34e3Sthurlow 		printf(" fullserver=NULL");
167*4bff34e3Sthurlow 
168*4bff34e3Sthurlow 	if (ctx->ct_srvaddr)
169*4bff34e3Sthurlow 		printf(" srvaddr=\"%s\"\n", ctx->ct_srvaddr);
170*4bff34e3Sthurlow 	else
171*4bff34e3Sthurlow 		printf(" srvaddr=NULL\n");
172*4bff34e3Sthurlow 
173*4bff34e3Sthurlow 	dump_ctx_ssn(&ctx->ct_ssn);
174*4bff34e3Sthurlow 	dump_ctx_sh(&ctx->ct_sh);
175*4bff34e3Sthurlow }
176*4bff34e3Sthurlow 
177*4bff34e3Sthurlow /*
178*4bff34e3Sthurlow  * Initialize an smb_ctx struct.
179*4bff34e3Sthurlow  *
180*4bff34e3Sthurlow  * The sequence for getting all the members filled in
181*4bff34e3Sthurlow  * has some tricky aspects.  Here's how it works:
182*4bff34e3Sthurlow  *
183*4bff34e3Sthurlow  * The search order for options is as follows:
184*4bff34e3Sthurlow  *   command line options
185*4bff34e3Sthurlow  *   values parsed from UNC path (cmd)
186*4bff34e3Sthurlow  *   values from RC file (per-user)
187*4bff34e3Sthurlow  *   values from SMF (system-wide)
188*4bff34e3Sthurlow  *   built-in defaults
189*4bff34e3Sthurlow  *
190*4bff34e3Sthurlow  * Normally, one would simply get all the values starting with
191*4bff34e3Sthurlow  * the bottom of the above list and working to the top, and
192*4bff34e3Sthurlow  * overwriting values as you go.  But we need an exception.
193*4bff34e3Sthurlow  *
194*4bff34e3Sthurlow  * In this function, we parse the UNC path and command line options,
195*4bff34e3Sthurlow  * because we need (at least) the server name when we're getting the
196*4bff34e3Sthurlow  * SMF and RC file values.  However, values we get from the command
197*4bff34e3Sthurlow  * should not be overwritten by SMF or RC file parsing, so we mark
198*4bff34e3Sthurlow  * values from the command as "from CMD" and the RC file parser
199*4bff34e3Sthurlow  * leaves in place any values so marked.  See: SMBCF_CMD_*
200*4bff34e3Sthurlow  *
201*4bff34e3Sthurlow  * The semantics of these flags are: "This value came from the
202*4bff34e3Sthurlow  * current command instance, not from sources that may apply to
203*4bff34e3Sthurlow  * multiple commands."  (Different from the old "FROMUSR" flag.)
204*4bff34e3Sthurlow  *
205*4bff34e3Sthurlow  * Note that smb_ctx_opt() is called later to handle the
206*4bff34e3Sthurlow  * remaining options, which should be ignored here.
207*4bff34e3Sthurlow  * The (magic) leading ":" in cf_getopt() makes it
208*4bff34e3Sthurlow  * ignore options not in the options string.
209*4bff34e3Sthurlow  */
210*4bff34e3Sthurlow int
211*4bff34e3Sthurlow smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[],
212*4bff34e3Sthurlow 	int minlevel, int maxlevel, int sharetype)
213*4bff34e3Sthurlow {
214*4bff34e3Sthurlow 	int  opt, error = 0;
215*4bff34e3Sthurlow 	const char *arg, *cp;
216*4bff34e3Sthurlow 	struct passwd pw;
217*4bff34e3Sthurlow 	char pwbuf[NSS_BUFLEN_PASSWD];
218*4bff34e3Sthurlow 	int aflg = 0, uflg = 0;
219*4bff34e3Sthurlow 
220*4bff34e3Sthurlow 	bzero(ctx, sizeof (*ctx));
221*4bff34e3Sthurlow 	if (sharetype == SMB_ST_DISK)
222*4bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_BROWSEOK;
223*4bff34e3Sthurlow 	error = nb_ctx_create(&ctx->ct_nb);
224*4bff34e3Sthurlow 	if (error)
225*4bff34e3Sthurlow 		return (error);
226*4bff34e3Sthurlow 
227*4bff34e3Sthurlow 	ctx->ct_fd = -1;
228*4bff34e3Sthurlow 	ctx->ct_parsedlevel = SMBL_NONE;
229*4bff34e3Sthurlow 	ctx->ct_minlevel = minlevel;
230*4bff34e3Sthurlow 	ctx->ct_maxlevel = maxlevel;
231*4bff34e3Sthurlow 
232*4bff34e3Sthurlow 	ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE | SMBVOPT_MINAUTH_NTLM;
233*4bff34e3Sthurlow 	ctx->ct_ssn.ioc_timeout = 15;
234*4bff34e3Sthurlow 	ctx->ct_ssn.ioc_retrycount = 4;
235*4bff34e3Sthurlow 	ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER;
236*4bff34e3Sthurlow 	ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP;
237*4bff34e3Sthurlow 	ctx->ct_ssn.ioc_mode = SMBM_EXEC;
238*4bff34e3Sthurlow 	ctx->ct_ssn.ioc_rights = SMBM_DEFAULT;
239*4bff34e3Sthurlow 
240*4bff34e3Sthurlow 	ctx->ct_sh.ioc_opt = SMBVOPT_CREATE;
241*4bff34e3Sthurlow 	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
242*4bff34e3Sthurlow 	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
243*4bff34e3Sthurlow 	ctx->ct_sh.ioc_mode = SMBM_EXEC;
244*4bff34e3Sthurlow 	ctx->ct_sh.ioc_rights = SMBM_DEFAULT;
245*4bff34e3Sthurlow 	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
246*4bff34e3Sthurlow 	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
247*4bff34e3Sthurlow 
248*4bff34e3Sthurlow 	nb_ctx_setscope(ctx->ct_nb, "");
249*4bff34e3Sthurlow 
250*4bff34e3Sthurlow 	/*
251*4bff34e3Sthurlow 	 * if the user name is not specified some other way,
252*4bff34e3Sthurlow 	 * use the current user name (built-in default)
253*4bff34e3Sthurlow 	 */
254*4bff34e3Sthurlow 	if (getpwuid_r(geteuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL)
255*4bff34e3Sthurlow 		smb_ctx_setuser(ctx, pw.pw_name, 0);
256*4bff34e3Sthurlow 
257*4bff34e3Sthurlow 	/*
258*4bff34e3Sthurlow 	 * Set a built-in default domain (workgroup).
259*4bff34e3Sthurlow 	 * XXX: What's the best default? Use "?" instead?
260*4bff34e3Sthurlow 	 * Using the Windows/NT default for now.
261*4bff34e3Sthurlow 	 */
262*4bff34e3Sthurlow 	smb_ctx_setworkgroup(ctx, "WORKGROUP", 0);
263*4bff34e3Sthurlow 
264*4bff34e3Sthurlow 	/*
265*4bff34e3Sthurlow 	 * Parse the UNC path.  Values from here are
266*4bff34e3Sthurlow 	 * marked as "from CMD".
267*4bff34e3Sthurlow 	 */
268*4bff34e3Sthurlow 	if (argv == NULL)
269*4bff34e3Sthurlow 		goto done;
270*4bff34e3Sthurlow 	for (opt = 1; opt < argc; opt++) {
271*4bff34e3Sthurlow 		cp = argv[opt];
272*4bff34e3Sthurlow 		if (strncmp(cp, "//", 2) != 0)
273*4bff34e3Sthurlow 			continue;
274*4bff34e3Sthurlow 		error = smb_ctx_parseunc(ctx, cp, sharetype, &cp);
275*4bff34e3Sthurlow 		if (error)
276*4bff34e3Sthurlow 			return (error);
277*4bff34e3Sthurlow 		break;
278*4bff34e3Sthurlow 	}
279*4bff34e3Sthurlow 
280*4bff34e3Sthurlow 	/*
281*4bff34e3Sthurlow 	 * Parse options, if any.  Values from here too
282*4bff34e3Sthurlow 	 * are marked as "from CMD".
283*4bff34e3Sthurlow 	 */
284*4bff34e3Sthurlow 	while (error == 0 && (opt = cf_getopt(argc, argv, ":AU:E:L:")) != -1) {
285*4bff34e3Sthurlow 		arg = cf_optarg;
286*4bff34e3Sthurlow 		switch (opt) {
287*4bff34e3Sthurlow 		case 'A':
288*4bff34e3Sthurlow 			aflg = 1;
289*4bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, "", TRUE);
290*4bff34e3Sthurlow 			error = smb_ctx_setpassword(ctx, "", TRUE);
291*4bff34e3Sthurlow 			ctx->ct_flags |= SMBCF_NOPWD;
292*4bff34e3Sthurlow 			break;
293*4bff34e3Sthurlow 		case 'E':
294*4bff34e3Sthurlow #if 0 /* We don't support any "charset" stuff. (ignore -E) */
295*4bff34e3Sthurlow 			error = smb_ctx_setcharset(ctx, arg);
296*4bff34e3Sthurlow 			if (error)
297*4bff34e3Sthurlow 				return (error);
298*4bff34e3Sthurlow #endif
299*4bff34e3Sthurlow 			break;
300*4bff34e3Sthurlow 		case 'L':
301*4bff34e3Sthurlow #if 0 /* Use the standard environment variables (ignore -L) */
302*4bff34e3Sthurlow 			error = nls_setlocale(optarg);
303*4bff34e3Sthurlow 			if (error)
304*4bff34e3Sthurlow 				break;
305*4bff34e3Sthurlow #endif
306*4bff34e3Sthurlow 			break;
307*4bff34e3Sthurlow 		case 'U':
308*4bff34e3Sthurlow 			uflg = 1;
309*4bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, arg, TRUE);
310*4bff34e3Sthurlow 			break;
311*4bff34e3Sthurlow 		}
312*4bff34e3Sthurlow 	}
313*4bff34e3Sthurlow 	if (aflg && uflg)  {
314*4bff34e3Sthurlow 		printf(gettext("-A and -U flags are exclusive.\n"));
315*4bff34e3Sthurlow 		return (1);
316*4bff34e3Sthurlow 	}
317*4bff34e3Sthurlow 	cf_optind = cf_optreset = 1;
318*4bff34e3Sthurlow 
319*4bff34e3Sthurlow done:
320*4bff34e3Sthurlow 	if (smb_debug)
321*4bff34e3Sthurlow 		dump_ctx("after smb_ctx_init", ctx);
322*4bff34e3Sthurlow 
323*4bff34e3Sthurlow 	return (error);
324*4bff34e3Sthurlow }
325*4bff34e3Sthurlow 
326*4bff34e3Sthurlow void
327*4bff34e3Sthurlow smb_ctx_done(struct smb_ctx *ctx)
328*4bff34e3Sthurlow {
329*4bff34e3Sthurlow 
330*4bff34e3Sthurlow 	rpc_cleanup_smbctx(ctx);
331*4bff34e3Sthurlow 
332*4bff34e3Sthurlow 	/* Kerberos stuff.  See smb_ctx_krb5init() */
333*4bff34e3Sthurlow 	if (ctx->ct_krb5ctx) {
334*4bff34e3Sthurlow 		if (ctx->ct_krb5cp)
335*4bff34e3Sthurlow 			krb5_free_principal(ctx->ct_krb5ctx, ctx->ct_krb5cp);
336*4bff34e3Sthurlow 		krb5_free_context(ctx->ct_krb5ctx);
337*4bff34e3Sthurlow 	}
338*4bff34e3Sthurlow 
339*4bff34e3Sthurlow 	if (ctx->ct_fd != -1)
340*4bff34e3Sthurlow 		close(ctx->ct_fd);
341*4bff34e3Sthurlow #if 0 /* XXX: not pointers anymore */
342*4bff34e3Sthurlow 	if (&ctx->ct_ssn.ioc_server)
343*4bff34e3Sthurlow 		nb_snbfree(&ctx->ct_ssn.ioc_server);
344*4bff34e3Sthurlow 	if (&ctx->ct_ssn.ioc_local)
345*4bff34e3Sthurlow 		nb_snbfree(&ctx->ct_ssn.ioc_local);
346*4bff34e3Sthurlow #endif
347*4bff34e3Sthurlow 	if (ctx->ct_srvaddr)
348*4bff34e3Sthurlow 		free(ctx->ct_srvaddr);
349*4bff34e3Sthurlow 	if (ctx->ct_nb)
350*4bff34e3Sthurlow 		nb_ctx_done(ctx->ct_nb);
351*4bff34e3Sthurlow 	if (ctx->ct_secblob)
352*4bff34e3Sthurlow 		free(ctx->ct_secblob);
353*4bff34e3Sthurlow 	if (ctx->ct_origshare)
354*4bff34e3Sthurlow 		free(ctx->ct_origshare);
355*4bff34e3Sthurlow 	if (ctx->ct_fullserver)
356*4bff34e3Sthurlow 		free(ctx->ct_fullserver);
357*4bff34e3Sthurlow }
358*4bff34e3Sthurlow 
359*4bff34e3Sthurlow static int
360*4bff34e3Sthurlow getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
361*4bff34e3Sthurlow     const char **next)
362*4bff34e3Sthurlow {
363*4bff34e3Sthurlow 	int len;
364*4bff34e3Sthurlow 
365*4bff34e3Sthurlow 	maxlen--;
366*4bff34e3Sthurlow 	for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
367*4bff34e3Sthurlow 		if (*p == 0)
368*4bff34e3Sthurlow 			return (EINVAL);
369*4bff34e3Sthurlow 		*dest = *p;
370*4bff34e3Sthurlow 	}
371*4bff34e3Sthurlow 	*dest = 0;
372*4bff34e3Sthurlow 	*next = *p ? p + 1 : p;
373*4bff34e3Sthurlow 	return (0);
374*4bff34e3Sthurlow }
375*4bff34e3Sthurlow 
376*4bff34e3Sthurlow /*
377*4bff34e3Sthurlow  * Parse the UNC path.  Here we expect something like
378*4bff34e3Sthurlow  *   "//[workgroup;][user[:password]@]host[/share[/path]]"
379*4bff34e3Sthurlow  * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
380*4bff34e3Sthurlow  * Values found here are marked as "from CMD".
381*4bff34e3Sthurlow  */
382*4bff34e3Sthurlow int
383*4bff34e3Sthurlow smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
384*4bff34e3Sthurlow 	const char **next)
385*4bff34e3Sthurlow {
386*4bff34e3Sthurlow 	const char *p = unc;
387*4bff34e3Sthurlow 	char *p1, *colon, *servername;
388*4bff34e3Sthurlow 	char tmp[1024];
389*4bff34e3Sthurlow 	char tmp2[1024];
390*4bff34e3Sthurlow 	int error;
391*4bff34e3Sthurlow 
392*4bff34e3Sthurlow 	ctx->ct_parsedlevel = SMBL_NONE;
393*4bff34e3Sthurlow 	if (*p++ != '/' || *p++ != '/') {
394*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
395*4bff34e3Sthurlow 		    "UNC should start with '//'"), 0);
396*4bff34e3Sthurlow 		return (EINVAL);
397*4bff34e3Sthurlow 	}
398*4bff34e3Sthurlow 	p1 = tmp;
399*4bff34e3Sthurlow 	error = getsubstring(p, ';', p1, sizeof (tmp), &p);
400*4bff34e3Sthurlow 	if (!error) {
401*4bff34e3Sthurlow 		if (*p1 == 0) {
402*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
403*4bff34e3Sthurlow 			    "empty workgroup name"), 0);
404*4bff34e3Sthurlow 			return (EINVAL);
405*4bff34e3Sthurlow 		}
406*4bff34e3Sthurlow 		nls_str_upper(tmp, tmp);
407*4bff34e3Sthurlow 		error = smb_ctx_setworkgroup(ctx, unpercent(tmp), TRUE);
408*4bff34e3Sthurlow 		if (error)
409*4bff34e3Sthurlow 			return (error);
410*4bff34e3Sthurlow 	}
411*4bff34e3Sthurlow 	colon = (char *)p;
412*4bff34e3Sthurlow 	error = getsubstring(p, '@', p1, sizeof (tmp), &p);
413*4bff34e3Sthurlow 	if (!error) {
414*4bff34e3Sthurlow 		if (ctx->ct_maxlevel < SMBL_VC) {
415*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
416*4bff34e3Sthurlow 			    "no user name required"), 0);
417*4bff34e3Sthurlow 			return (EINVAL);
418*4bff34e3Sthurlow 		}
419*4bff34e3Sthurlow 		p1 = strchr(tmp, ':');
420*4bff34e3Sthurlow 		if (p1) {
421*4bff34e3Sthurlow 			colon += p1 - tmp;
422*4bff34e3Sthurlow 			*p1++ = (char)0;
423*4bff34e3Sthurlow 			error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
424*4bff34e3Sthurlow 			if (error)
425*4bff34e3Sthurlow 				return (error);
426*4bff34e3Sthurlow 			if (p - colon > 2)
427*4bff34e3Sthurlow 				memset(colon+1, '*', p - colon - 2);
428*4bff34e3Sthurlow 		}
429*4bff34e3Sthurlow 		p1 = tmp;
430*4bff34e3Sthurlow 		if (*p1 == 0) {
431*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
432*4bff34e3Sthurlow 			    "empty user name"), 0);
433*4bff34e3Sthurlow 			return (EINVAL);
434*4bff34e3Sthurlow 		}
435*4bff34e3Sthurlow 		error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
436*4bff34e3Sthurlow 		if (error)
437*4bff34e3Sthurlow 			return (error);
438*4bff34e3Sthurlow 		ctx->ct_parsedlevel = SMBL_VC;
439*4bff34e3Sthurlow 	}
440*4bff34e3Sthurlow 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
441*4bff34e3Sthurlow 	if (error) {
442*4bff34e3Sthurlow 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
443*4bff34e3Sthurlow 		if (error) {
444*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
445*4bff34e3Sthurlow 			    "no server name found"), 0);
446*4bff34e3Sthurlow 			return (error);
447*4bff34e3Sthurlow 		}
448*4bff34e3Sthurlow 	}
449*4bff34e3Sthurlow 	if (*p1 == 0) {
450*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
451*4bff34e3Sthurlow 		return (EINVAL);
452*4bff34e3Sthurlow 	}
453*4bff34e3Sthurlow 
454*4bff34e3Sthurlow 
455*4bff34e3Sthurlow 	/*
456*4bff34e3Sthurlow 	 * It's safe to uppercase this string, which
457*4bff34e3Sthurlow 	 * consists of ascii characters that should
458*4bff34e3Sthurlow 	 * be uppercased, %s, and ascii characters representing
459*4bff34e3Sthurlow 	 * hex digits 0-9 and A-F (already uppercased, and
460*4bff34e3Sthurlow 	 * if not uppercased they need to be). However,
461*4bff34e3Sthurlow 	 * it is NOT safe to uppercase after it has been
462*4bff34e3Sthurlow 	 * converted, below!
463*4bff34e3Sthurlow 	 */
464*4bff34e3Sthurlow 
465*4bff34e3Sthurlow 	nls_str_upper(tmp2, tmp);
466*4bff34e3Sthurlow 
467*4bff34e3Sthurlow 	/*
468*4bff34e3Sthurlow 	 * scan for % in the string.
469*4bff34e3Sthurlow 	 * If we find one, convert
470*4bff34e3Sthurlow 	 * to the assumed codepage.
471*4bff34e3Sthurlow 	 */
472*4bff34e3Sthurlow 
473*4bff34e3Sthurlow 	if (strchr(tmp2, '%')) {
474*4bff34e3Sthurlow 		/* use the 1st buffer, we don't need the old string */
475*4bff34e3Sthurlow 		servername = tmp;
476*4bff34e3Sthurlow 		if (!(servername = convert_utf8_to_wincs(unpercent(tmp2)))) {
477*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN, "bad server name"), 0);
478*4bff34e3Sthurlow 			return (EINVAL);
479*4bff34e3Sthurlow 		}
480*4bff34e3Sthurlow 		/*
481*4bff34e3Sthurlow 		 * Converts utf8 to win equivalent of
482*4bff34e3Sthurlow 		 * what is configured on this machine.
483*4bff34e3Sthurlow 		 * Note that we are assuming this is the
484*4bff34e3Sthurlow 		 * encoding used on the server, and that
485*4bff34e3Sthurlow 		 * assumption might be incorrect. This is
486*4bff34e3Sthurlow 		 * the best we can do now, and we should
487*4bff34e3Sthurlow 		 * move to use port 445 to avoid having
488*4bff34e3Sthurlow 		 * to worry about server codepages.
489*4bff34e3Sthurlow 		 */
490*4bff34e3Sthurlow 	} else /* no conversion needed */
491*4bff34e3Sthurlow 		servername = tmp2;
492*4bff34e3Sthurlow 
493*4bff34e3Sthurlow 	smb_ctx_setserver(ctx, servername);
494*4bff34e3Sthurlow 	error = smb_ctx_setfullserver(ctx, servername);
495*4bff34e3Sthurlow 
496*4bff34e3Sthurlow 	if (error)
497*4bff34e3Sthurlow 		return (error);
498*4bff34e3Sthurlow 	if (sharetype == SMB_ST_NONE) {
499*4bff34e3Sthurlow 		*next = p;
500*4bff34e3Sthurlow 		return (0);
501*4bff34e3Sthurlow 	}
502*4bff34e3Sthurlow 	if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
503*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
504*4bff34e3Sthurlow 		return (EINVAL);
505*4bff34e3Sthurlow 	}
506*4bff34e3Sthurlow 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
507*4bff34e3Sthurlow 	if (error) {
508*4bff34e3Sthurlow 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
509*4bff34e3Sthurlow 		if (error) {
510*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
511*4bff34e3Sthurlow 			    "unexpected end of line"), 0);
512*4bff34e3Sthurlow 			return (error);
513*4bff34e3Sthurlow 		}
514*4bff34e3Sthurlow 	}
515*4bff34e3Sthurlow 	if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
516*4bff34e3Sthurlow 	    !(ctx->ct_flags & SMBCF_BROWSEOK)) {
517*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
518*4bff34e3Sthurlow 		return (EINVAL);
519*4bff34e3Sthurlow 	}
520*4bff34e3Sthurlow 	*next = p;
521*4bff34e3Sthurlow 	if (*p1 == 0)
522*4bff34e3Sthurlow 		return (0);
523*4bff34e3Sthurlow 	error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
524*4bff34e3Sthurlow 	return (error);
525*4bff34e3Sthurlow }
526*4bff34e3Sthurlow 
527*4bff34e3Sthurlow int
528*4bff34e3Sthurlow smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
529*4bff34e3Sthurlow {
530*4bff34e3Sthurlow 	char *cp, *servercs, *localcs;
531*4bff34e3Sthurlow 	int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
532*4bff34e3Sthurlow 	int scslen, lcslen, error;
533*4bff34e3Sthurlow 
534*4bff34e3Sthurlow 	cp = strchr(arg, ':');
535*4bff34e3Sthurlow 	lcslen = cp ? (cp - arg) : 0;
536*4bff34e3Sthurlow 	if (lcslen == 0 || lcslen >= cslen) {
537*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
538*4bff34e3Sthurlow 		    "invalid local charset specification (%s)"), 0, arg);
539*4bff34e3Sthurlow 		return (EINVAL);
540*4bff34e3Sthurlow 	}
541*4bff34e3Sthurlow 	scslen = (size_t)strlen(++cp);
542*4bff34e3Sthurlow 	if (scslen == 0 || scslen >= cslen) {
543*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
544*4bff34e3Sthurlow 		    "invalid server charset specification (%s)"), 0, arg);
545*4bff34e3Sthurlow 		return (EINVAL);
546*4bff34e3Sthurlow 	}
547*4bff34e3Sthurlow 	localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
548*4bff34e3Sthurlow 	localcs[lcslen] = 0;
549*4bff34e3Sthurlow 	servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
550*4bff34e3Sthurlow 	error = nls_setrecode(localcs, servercs);
551*4bff34e3Sthurlow 	if (error == 0)
552*4bff34e3Sthurlow 		return (0);
553*4bff34e3Sthurlow 	smb_error(dgettext(TEXT_DOMAIN,
554*4bff34e3Sthurlow 	    "can't initialize iconv support (%s:%s)"),
555*4bff34e3Sthurlow 	    error, localcs, servercs);
556*4bff34e3Sthurlow 	localcs[0] = 0;
557*4bff34e3Sthurlow 	servercs[0] = 0;
558*4bff34e3Sthurlow 	return (error);
559*4bff34e3Sthurlow }
560*4bff34e3Sthurlow 
561*4bff34e3Sthurlow int
562*4bff34e3Sthurlow smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
563*4bff34e3Sthurlow {
564*4bff34e3Sthurlow 	ctx->ct_fullserver = strdup(name);
565*4bff34e3Sthurlow 	if (ctx->ct_fullserver == NULL)
566*4bff34e3Sthurlow 		return (ENOMEM);
567*4bff34e3Sthurlow 	return (0);
568*4bff34e3Sthurlow }
569*4bff34e3Sthurlow 
570*4bff34e3Sthurlow /*
571*4bff34e3Sthurlow  * XXX TODO FIXME etc etc
572*4bff34e3Sthurlow  * If the call to nbns_getnodestatus(...) fails we can try one of two other
573*4bff34e3Sthurlow  * methods; use a name of "*SMBSERVER", which is supported by Samba (at least)
574*4bff34e3Sthurlow  * or, as a last resort, try the "truncate-at-dot" heuristic.
575*4bff34e3Sthurlow  * And the heuristic really should attempt truncation at
576*4bff34e3Sthurlow  * each dot in turn, left to right.
577*4bff34e3Sthurlow  *
578*4bff34e3Sthurlow  * These fallback heuristics should be triggered when the attempt to open the
579*4bff34e3Sthurlow  * session fails instead of in the code below.
580*4bff34e3Sthurlow  *
581*4bff34e3Sthurlow  * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
582*4bff34e3Sthurlow  */
583*4bff34e3Sthurlow int
584*4bff34e3Sthurlow smb_ctx_getnbname(struct smb_ctx *ctx, struct sockaddr *sap)
585*4bff34e3Sthurlow {
586*4bff34e3Sthurlow 	char server[SMB_MAXSRVNAMELEN + 1];
587*4bff34e3Sthurlow 	char workgroup[SMB_MAXUSERNAMELEN + 1];
588*4bff34e3Sthurlow 	int error;
589*4bff34e3Sthurlow #if 0
590*4bff34e3Sthurlow 	char *dot;
591*4bff34e3Sthurlow #endif
592*4bff34e3Sthurlow 
593*4bff34e3Sthurlow 	server[0] = workgroup[0] = '\0';
594*4bff34e3Sthurlow 	error = nbns_getnodestatus(sap, ctx->ct_nb, server, workgroup);
595*4bff34e3Sthurlow 	if (error == 0) {
596*4bff34e3Sthurlow 		/*
597*4bff34e3Sthurlow 		 * Used to set our domain name to be the same as
598*4bff34e3Sthurlow 		 * the server's domain name.   Unnecessary at best,
599*4bff34e3Sthurlow 		 * and wrong for accounts in a trusted domain.
600*4bff34e3Sthurlow 		 */
601*4bff34e3Sthurlow #ifdef APPLE
602*4bff34e3Sthurlow 		if (workgroup[0] && !ctx->ct_ssn.ioc_workgroup[0])
603*4bff34e3Sthurlow 			smb_ctx_setworkgroup(ctx, workgroup, 0);
604*4bff34e3Sthurlow #endif
605*4bff34e3Sthurlow 		if (server[0])
606*4bff34e3Sthurlow 			smb_ctx_setserver(ctx, server);
607*4bff34e3Sthurlow 	} else {
608*4bff34e3Sthurlow 		if (smb_verbose)
609*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
610*4bff34e3Sthurlow 			    "Failed to get NetBIOS node status."), 0);
611*4bff34e3Sthurlow 		if (ctx->ct_ssn.ioc_srvname[0] == (char)0)
612*4bff34e3Sthurlow 			smb_ctx_setserver(ctx, "*SMBSERVER");
613*4bff34e3Sthurlow 	}
614*4bff34e3Sthurlow #if 0
615*4bff34e3Sthurlow 	if (server[0] == (char)0) {
616*4bff34e3Sthurlow 		dot = strchr(ctx->ct_fullserver, '.');
617*4bff34e3Sthurlow 		if (dot)
618*4bff34e3Sthurlow 			*dot = '\0';
619*4bff34e3Sthurlow 		if (strlen(ctx->ct_fullserver) <= SMB_MAXSRVNAMELEN) {
620*4bff34e3Sthurlow 			/*
621*4bff34e3Sthurlow 			 * don't uppercase the server name. it comes from
622*4bff34e3Sthurlow 			 * NBNS and uppercasing can clobber the characters
623*4bff34e3Sthurlow 			 */
624*4bff34e3Sthurlow 			strcpy(ctx->ct_ssn.ioc_srvname, ctx->ct_fullserver);
625*4bff34e3Sthurlow 			error = 0;
626*4bff34e3Sthurlow 		} else {
627*4bff34e3Sthurlow 			error = -1;
628*4bff34e3Sthurlow 		}
629*4bff34e3Sthurlow 		if (dot)
630*4bff34e3Sthurlow 			*dot = '.';
631*4bff34e3Sthurlow 	}
632*4bff34e3Sthurlow #endif
633*4bff34e3Sthurlow 	return (error);
634*4bff34e3Sthurlow }
635*4bff34e3Sthurlow 
636*4bff34e3Sthurlow /* this routine does not uppercase the server name */
637*4bff34e3Sthurlow void
638*4bff34e3Sthurlow smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
639*4bff34e3Sthurlow {
640*4bff34e3Sthurlow 	/* don't uppercase the server name */
641*4bff34e3Sthurlow 	if (strlen(name) > SMB_MAXSRVNAMELEN) { /* NB limit is 15 */
642*4bff34e3Sthurlow 		ctx->ct_ssn.ioc_srvname[0] = '\0';
643*4bff34e3Sthurlow 	} else
644*4bff34e3Sthurlow 		strcpy(ctx->ct_ssn.ioc_srvname, name);
645*4bff34e3Sthurlow }
646*4bff34e3Sthurlow 
647*4bff34e3Sthurlow int
648*4bff34e3Sthurlow smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
649*4bff34e3Sthurlow {
650*4bff34e3Sthurlow 
651*4bff34e3Sthurlow 	if (strlen(name) >= SMB_MAXUSERNAMELEN) {
652*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
653*4bff34e3Sthurlow 		    "user name '%s' too long"), 0, name);
654*4bff34e3Sthurlow 		return (ENAMETOOLONG);
655*4bff34e3Sthurlow 	}
656*4bff34e3Sthurlow 
657*4bff34e3Sthurlow 	/*
658*4bff34e3Sthurlow 	 * Don't overwrite a value from the command line
659*4bff34e3Sthurlow 	 * with one from anywhere else.
660*4bff34e3Sthurlow 	 */
661*4bff34e3Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
662*4bff34e3Sthurlow 		return (0);
663*4bff34e3Sthurlow 
664*4bff34e3Sthurlow 	/* don't uppercase the username, just copy it. */
665*4bff34e3Sthurlow 	strcpy(ctx->ct_ssn.ioc_user, name);
666*4bff34e3Sthurlow 
667*4bff34e3Sthurlow 	/* Mark this as "from the command line". */
668*4bff34e3Sthurlow 	if (from_cmd)
669*4bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_CMD_USR;
670*4bff34e3Sthurlow 
671*4bff34e3Sthurlow 	return (0);
672*4bff34e3Sthurlow }
673*4bff34e3Sthurlow 
674*4bff34e3Sthurlow /*
675*4bff34e3Sthurlow  * Never uppercase the workgroup
676*4bff34e3Sthurlow  * name here, because it might come
677*4bff34e3Sthurlow  * from a Windows codepage encoding.
678*4bff34e3Sthurlow  *
679*4bff34e3Sthurlow  * Don't overwrite a domain name from the
680*4bff34e3Sthurlow  * command line with one from anywhere else.
681*4bff34e3Sthurlow  * See smb_ctx_init() for notes about this.
682*4bff34e3Sthurlow  */
683*4bff34e3Sthurlow int
684*4bff34e3Sthurlow smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd)
685*4bff34e3Sthurlow {
686*4bff34e3Sthurlow 
687*4bff34e3Sthurlow 	if (strlen(name) >= SMB_MAXUSERNAMELEN) {
688*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
689*4bff34e3Sthurlow 		    "workgroup name '%s' too long"), 0, name);
690*4bff34e3Sthurlow 		return (ENAMETOOLONG);
691*4bff34e3Sthurlow 	}
692*4bff34e3Sthurlow 
693*4bff34e3Sthurlow 	/*
694*4bff34e3Sthurlow 	 * Don't overwrite a value from the command line
695*4bff34e3Sthurlow 	 * with one from anywhere else.
696*4bff34e3Sthurlow 	 */
697*4bff34e3Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
698*4bff34e3Sthurlow 		return (0);
699*4bff34e3Sthurlow 
700*4bff34e3Sthurlow 	strcpy(ctx->ct_ssn.ioc_workgroup, name);
701*4bff34e3Sthurlow 
702*4bff34e3Sthurlow 	/* Mark this as "from the command line". */
703*4bff34e3Sthurlow 	if (from_cmd)
704*4bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_CMD_DOM;
705*4bff34e3Sthurlow 
706*4bff34e3Sthurlow 	return (0);
707*4bff34e3Sthurlow }
708*4bff34e3Sthurlow 
709*4bff34e3Sthurlow int
710*4bff34e3Sthurlow smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
711*4bff34e3Sthurlow {
712*4bff34e3Sthurlow 
713*4bff34e3Sthurlow 	if (passwd == NULL) /* XXX Huh? */
714*4bff34e3Sthurlow 		return (EINVAL);
715*4bff34e3Sthurlow 	if (strlen(passwd) >= SMB_MAXPASSWORDLEN) {
716*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
717*4bff34e3Sthurlow 		return (ENAMETOOLONG);
718*4bff34e3Sthurlow 	}
719*4bff34e3Sthurlow 
720*4bff34e3Sthurlow 	/*
721*4bff34e3Sthurlow 	 * Don't overwrite a value from the command line
722*4bff34e3Sthurlow 	 * with one from anywhere else.
723*4bff34e3Sthurlow 	 */
724*4bff34e3Sthurlow 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
725*4bff34e3Sthurlow 		return (0);
726*4bff34e3Sthurlow 
727*4bff34e3Sthurlow 	if (strncmp(passwd, "$$1", 3) == 0)
728*4bff34e3Sthurlow 		smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd);
729*4bff34e3Sthurlow 	else
730*4bff34e3Sthurlow 		strcpy(ctx->ct_ssn.ioc_password, passwd);
731*4bff34e3Sthurlow 	strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password);
732*4bff34e3Sthurlow 
733*4bff34e3Sthurlow 	/* Mark this as "from the command line". */
734*4bff34e3Sthurlow 	if (from_cmd)
735*4bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_CMD_PW;
736*4bff34e3Sthurlow 
737*4bff34e3Sthurlow 	return (0);
738*4bff34e3Sthurlow }
739*4bff34e3Sthurlow 
740*4bff34e3Sthurlow int
741*4bff34e3Sthurlow smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
742*4bff34e3Sthurlow {
743*4bff34e3Sthurlow 	if (strlen(share) >= SMB_MAXSHARENAMELEN) {
744*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
745*4bff34e3Sthurlow 		    "share name '%s' too long"), 0, share);
746*4bff34e3Sthurlow 		return (ENAMETOOLONG);
747*4bff34e3Sthurlow 	}
748*4bff34e3Sthurlow 	if (ctx->ct_origshare)
749*4bff34e3Sthurlow 		free(ctx->ct_origshare);
750*4bff34e3Sthurlow 	if ((ctx->ct_origshare = strdup(share)) == NULL)
751*4bff34e3Sthurlow 		return (ENOMEM);
752*4bff34e3Sthurlow 	nls_str_upper(ctx->ct_sh.ioc_share, share);
753*4bff34e3Sthurlow 	if (share[0] != 0)
754*4bff34e3Sthurlow 		ctx->ct_parsedlevel = SMBL_SHARE;
755*4bff34e3Sthurlow 	ctx->ct_sh.ioc_stype = stype;
756*4bff34e3Sthurlow 	return (0);
757*4bff34e3Sthurlow }
758*4bff34e3Sthurlow 
759*4bff34e3Sthurlow int
760*4bff34e3Sthurlow smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
761*4bff34e3Sthurlow {
762*4bff34e3Sthurlow 	if (addr == NULL || addr[0] == 0)
763*4bff34e3Sthurlow 		return (EINVAL);
764*4bff34e3Sthurlow 	if (ctx->ct_srvaddr)
765*4bff34e3Sthurlow 		free(ctx->ct_srvaddr);
766*4bff34e3Sthurlow 	if ((ctx->ct_srvaddr = strdup(addr)) == NULL)
767*4bff34e3Sthurlow 		return (ENOMEM);
768*4bff34e3Sthurlow 	return (0);
769*4bff34e3Sthurlow }
770*4bff34e3Sthurlow 
771*4bff34e3Sthurlow static int
772*4bff34e3Sthurlow smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
773*4bff34e3Sthurlow {
774*4bff34e3Sthurlow 	struct group gr;
775*4bff34e3Sthurlow 	struct passwd pw;
776*4bff34e3Sthurlow 	char buf[NSS_BUFLEN_PASSWD];
777*4bff34e3Sthurlow 	char *cp;
778*4bff34e3Sthurlow 
779*4bff34e3Sthurlow 	cp = strchr(pair, ':');
780*4bff34e3Sthurlow 	if (cp) {
781*4bff34e3Sthurlow 		*cp++ = '\0';
782*4bff34e3Sthurlow 		if (*cp) {
783*4bff34e3Sthurlow 			if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
784*4bff34e3Sthurlow 				*gid = gr.gr_gid;
785*4bff34e3Sthurlow 			} else
786*4bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
787*4bff34e3Sthurlow 				    "Invalid group name %s, ignored"), 0, cp);
788*4bff34e3Sthurlow 		}
789*4bff34e3Sthurlow 	}
790*4bff34e3Sthurlow 	if (*pair) {
791*4bff34e3Sthurlow 		if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
792*4bff34e3Sthurlow 			*uid = pw.pw_uid;
793*4bff34e3Sthurlow 		} else
794*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
795*4bff34e3Sthurlow 			    "Invalid user name %s, ignored"), 0, pair);
796*4bff34e3Sthurlow 	}
797*4bff34e3Sthurlow 
798*4bff34e3Sthurlow 	return (0);
799*4bff34e3Sthurlow }
800*4bff34e3Sthurlow 
801*4bff34e3Sthurlow /*
802*4bff34e3Sthurlow  * Commands use this with getopt.  See:
803*4bff34e3Sthurlow  *   STDPARAM_OPT, STDPARAM_ARGS
804*4bff34e3Sthurlow  * Called after smb_ctx_readrc().
805*4bff34e3Sthurlow  */
806*4bff34e3Sthurlow int
807*4bff34e3Sthurlow smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
808*4bff34e3Sthurlow {
809*4bff34e3Sthurlow 	int error = 0;
810*4bff34e3Sthurlow 	char *p, *cp;
811*4bff34e3Sthurlow 	char tmp[1024];
812*4bff34e3Sthurlow 
813*4bff34e3Sthurlow 	switch (opt) {
814*4bff34e3Sthurlow 	case 'A':
815*4bff34e3Sthurlow 	case 'U':
816*4bff34e3Sthurlow 		/* Handled in smb_ctx_init() */
817*4bff34e3Sthurlow 		break;
818*4bff34e3Sthurlow 	case 'I':
819*4bff34e3Sthurlow 		error = smb_ctx_setsrvaddr(ctx, arg);
820*4bff34e3Sthurlow 		break;
821*4bff34e3Sthurlow 	case 'M':
822*4bff34e3Sthurlow 		ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8);
823*4bff34e3Sthurlow 		if (*cp == '/') {
824*4bff34e3Sthurlow 			ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8);
825*4bff34e3Sthurlow 			ctx->ct_flags |= SMBCF_SRIGHTS;
826*4bff34e3Sthurlow 		}
827*4bff34e3Sthurlow 		break;
828*4bff34e3Sthurlow 	case 'N':
829*4bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_NOPWD;
830*4bff34e3Sthurlow 		break;
831*4bff34e3Sthurlow 	case 'O':
832*4bff34e3Sthurlow 		p = strdup(arg);
833*4bff34e3Sthurlow 		cp = strchr(p, '/');
834*4bff34e3Sthurlow 		if (cp) {
835*4bff34e3Sthurlow 			*cp++ = '\0';
836*4bff34e3Sthurlow 			error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner,
837*4bff34e3Sthurlow 			    &ctx->ct_sh.ioc_group);
838*4bff34e3Sthurlow 		}
839*4bff34e3Sthurlow 		if (*p && error == 0) {
840*4bff34e3Sthurlow 			error = smb_parse_owner(cp, &ctx->ct_ssn.ioc_owner,
841*4bff34e3Sthurlow 			    &ctx->ct_ssn.ioc_group);
842*4bff34e3Sthurlow 		}
843*4bff34e3Sthurlow 		free(p);
844*4bff34e3Sthurlow 		break;
845*4bff34e3Sthurlow 	case 'P':
846*4bff34e3Sthurlow /*		ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT; */
847*4bff34e3Sthurlow 		break;
848*4bff34e3Sthurlow 	case 'R':
849*4bff34e3Sthurlow 		ctx->ct_ssn.ioc_retrycount = atoi(arg);
850*4bff34e3Sthurlow 		break;
851*4bff34e3Sthurlow 	case 'T':
852*4bff34e3Sthurlow 		ctx->ct_ssn.ioc_timeout = atoi(arg);
853*4bff34e3Sthurlow 		break;
854*4bff34e3Sthurlow 	case 'W':
855*4bff34e3Sthurlow 		nls_str_upper(tmp, arg);
856*4bff34e3Sthurlow 		error = smb_ctx_setworkgroup(ctx, tmp, TRUE);
857*4bff34e3Sthurlow 		break;
858*4bff34e3Sthurlow 	}
859*4bff34e3Sthurlow 	return (error);
860*4bff34e3Sthurlow }
861*4bff34e3Sthurlow 
862*4bff34e3Sthurlow #if 0
863*4bff34e3Sthurlow static void
864*4bff34e3Sthurlow smb_hexdump(const uchar_t *buf, int len) {
865*4bff34e3Sthurlow 	int ofs = 0;
866*4bff34e3Sthurlow 
867*4bff34e3Sthurlow 	while (len--) {
868*4bff34e3Sthurlow 		if (ofs % 16 == 0)
869*4bff34e3Sthurlow 			printf("\n%02X: ", ofs);
870*4bff34e3Sthurlow 		printf("%02x ", *buf++);
871*4bff34e3Sthurlow 		ofs++;
872*4bff34e3Sthurlow 	}
873*4bff34e3Sthurlow 	printf("\n");
874*4bff34e3Sthurlow }
875*4bff34e3Sthurlow #endif
876*4bff34e3Sthurlow 
877*4bff34e3Sthurlow 
878*4bff34e3Sthurlow static int
879*4bff34e3Sthurlow smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
880*4bff34e3Sthurlow {
881*4bff34e3Sthurlow 	int error;
882*4bff34e3Sthurlow 
883*4bff34e3Sthurlow 	/*
884*4bff34e3Sthurlow 	 * Not able to find out what is the work of this routine till
885*4bff34e3Sthurlow 	 * now. Still investigating.
886*4bff34e3Sthurlow 	 * REVISIT
887*4bff34e3Sthurlow 	 */
888*4bff34e3Sthurlow #ifdef KICONV_SUPPORT
889*4bff34e3Sthurlow 	error = kiconv_add_xlat_table(to, from, tbl);
890*4bff34e3Sthurlow 	if (error && error != EEXIST) {
891*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
892*4bff34e3Sthurlow 		    "can not setup kernel iconv table (%s:%s)"),
893*4bff34e3Sthurlow 		    error, from, to);
894*4bff34e3Sthurlow 		return (error);
895*4bff34e3Sthurlow 	}
896*4bff34e3Sthurlow #endif
897*4bff34e3Sthurlow 	return (0);
898*4bff34e3Sthurlow }
899*4bff34e3Sthurlow 
900*4bff34e3Sthurlow /*
901*4bff34e3Sthurlow  * Verify context before connect operation(s),
902*4bff34e3Sthurlow  * lookup specified server and try to fill all forgotten fields.
903*4bff34e3Sthurlow  */
904*4bff34e3Sthurlow int
905*4bff34e3Sthurlow smb_ctx_resolve(struct smb_ctx *ctx)
906*4bff34e3Sthurlow {
907*4bff34e3Sthurlow 	struct smbioc_ossn *ssn = &ctx->ct_ssn;
908*4bff34e3Sthurlow 	struct smbioc_oshare *sh = &ctx->ct_sh;
909*4bff34e3Sthurlow 	struct nb_name nn;
910*4bff34e3Sthurlow 	struct sockaddr *sap;
911*4bff34e3Sthurlow 	struct sockaddr_nb *salocal, *saserver;
912*4bff34e3Sthurlow 	char *cp;
913*4bff34e3Sthurlow 	uchar_t cstbl[256];
914*4bff34e3Sthurlow 	uint_t i;
915*4bff34e3Sthurlow 	int error = 0;
916*4bff34e3Sthurlow 	int browseok = ctx->ct_flags & SMBCF_BROWSEOK;
917*4bff34e3Sthurlow 	int renego = 0;
918*4bff34e3Sthurlow 
919*4bff34e3Sthurlow 	ctx->ct_flags &= ~SMBCF_RESOLVED;
920*4bff34e3Sthurlow 	if (isatty(STDIN_FILENO))
921*4bff34e3Sthurlow 		browseok = 0;
922*4bff34e3Sthurlow 	if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == 0) {
923*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
924*4bff34e3Sthurlow 		    "no server name specified"), 0);
925*4bff34e3Sthurlow 		return (EINVAL);
926*4bff34e3Sthurlow 	}
927*4bff34e3Sthurlow 	if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0 &&
928*4bff34e3Sthurlow 	    !browseok) {
929*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
930*4bff34e3Sthurlow 		    "no share name specified for %s@%s"),
931*4bff34e3Sthurlow 		    0, ssn->ioc_user, ssn->ioc_srvname);
932*4bff34e3Sthurlow 		return (EINVAL);
933*4bff34e3Sthurlow 	}
934*4bff34e3Sthurlow 	error = nb_ctx_resolve(ctx->ct_nb);
935*4bff34e3Sthurlow 	if (error)
936*4bff34e3Sthurlow 		return (error);
937*4bff34e3Sthurlow 	if (ssn->ioc_localcs[0] == 0)
938*4bff34e3Sthurlow 		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
939*4bff34e3Sthurlow 	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
940*4bff34e3Sthurlow 	if (error)
941*4bff34e3Sthurlow 		return (error);
942*4bff34e3Sthurlow 	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
943*4bff34e3Sthurlow 	if (error)
944*4bff34e3Sthurlow 		return (error);
945*4bff34e3Sthurlow 	if (ssn->ioc_servercs[0] != 0) {
946*4bff34e3Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
947*4bff34e3Sthurlow 			cstbl[i] = i;
948*4bff34e3Sthurlow 		nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
949*4bff34e3Sthurlow 		error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
950*4bff34e3Sthurlow 		    cstbl);
951*4bff34e3Sthurlow 		if (error)
952*4bff34e3Sthurlow 			return (error);
953*4bff34e3Sthurlow 		for (i = 0; i < sizeof (cstbl); i++)
954*4bff34e3Sthurlow 			cstbl[i] = i;
955*4bff34e3Sthurlow 		nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
956*4bff34e3Sthurlow 		error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
957*4bff34e3Sthurlow 		    cstbl);
958*4bff34e3Sthurlow 		if (error)
959*4bff34e3Sthurlow 			return (error);
960*4bff34e3Sthurlow 	}
961*4bff34e3Sthurlow 	/*
962*4bff34e3Sthurlow 	 * If we have an explicit address set for the server in
963*4bff34e3Sthurlow 	 * an "addr=X" setting in .nsmbrc or SMF, just try using a
964*4bff34e3Sthurlow 	 * gethostbyname() lookup for it.
965*4bff34e3Sthurlow 	 */
966*4bff34e3Sthurlow 	if (ctx->ct_srvaddr) {
967*4bff34e3Sthurlow 		error = nb_resolvehost_in(ctx->ct_srvaddr, &sap);
968*4bff34e3Sthurlow 		if (error == 0)
969*4bff34e3Sthurlow 			(void) smb_ctx_getnbname(ctx, sap);
970*4bff34e3Sthurlow 	} else
971*4bff34e3Sthurlow 		error = -1;
972*4bff34e3Sthurlow 
973*4bff34e3Sthurlow 	/*
974*4bff34e3Sthurlow 	 * Next try a gethostbyname() lookup on the original user-
975*4bff34e3Sthurlow 	 * specified server name. This is similar to Windows
976*4bff34e3Sthurlow 	 * NBT option "Use DNS for name resolution."
977*4bff34e3Sthurlow 	 */
978*4bff34e3Sthurlow 	if (error && ctx->ct_fullserver) {
979*4bff34e3Sthurlow 		error = nb_resolvehost_in(ctx->ct_fullserver, &sap);
980*4bff34e3Sthurlow 		if (error == 0)
981*4bff34e3Sthurlow 			(void) smb_ctx_getnbname(ctx, sap);
982*4bff34e3Sthurlow 	}
983*4bff34e3Sthurlow 
984*4bff34e3Sthurlow 	/*
985*4bff34e3Sthurlow 	 * Finally, try the shorter, upper-cased ssn->ioc_srvname
986*4bff34e3Sthurlow 	 * with a NBNS/WINS lookup if the "nbns_enable" property is
987*4bff34e3Sthurlow 	 * true (the default).  nbns_resolvename() may unicast to the
988*4bff34e3Sthurlow 	 * "nbns" server or broadcast on the subnet.
989*4bff34e3Sthurlow 	 */
990*4bff34e3Sthurlow 	if (error && ssn->ioc_srvname[0] &&
991*4bff34e3Sthurlow 	    ctx->ct_nb->nb_flags & NBCF_NS_ENABLE) {
992*4bff34e3Sthurlow 		error = nbns_resolvename(ssn->ioc_srvname,
993*4bff34e3Sthurlow 		    ctx->ct_nb, &sap);
994*4bff34e3Sthurlow 		/*
995*4bff34e3Sthurlow 		 * Used to get the NetBIOS node status here.
996*4bff34e3Sthurlow 		 * Not necessary (we have the NetBIOS name).
997*4bff34e3Sthurlow 		 */
998*4bff34e3Sthurlow 	}
999*4bff34e3Sthurlow 	if (error) {
1000*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1001*4bff34e3Sthurlow 		    "can't get server address"), error);
1002*4bff34e3Sthurlow 		return (error);
1003*4bff34e3Sthurlow 	}
1004*4bff34e3Sthurlow 
1005*4bff34e3Sthurlow 	/* XXX: no nls_str_upper(ssn->ioc_srvname) here? */
1006*4bff34e3Sthurlow 
1007*4bff34e3Sthurlow 	assert(sizeof (nn.nn_name) == sizeof (ssn->ioc_srvname));
1008*4bff34e3Sthurlow 	memcpy(nn.nn_name, ssn->ioc_srvname, NB_NAMELEN);
1009*4bff34e3Sthurlow 	nn.nn_type = NBT_SERVER;
1010*4bff34e3Sthurlow 	nn.nn_scope = ctx->ct_nb->nb_scope;
1011*4bff34e3Sthurlow 
1012*4bff34e3Sthurlow 	error = nb_sockaddr(sap, &nn, &saserver);
1013*4bff34e3Sthurlow 	memcpy(&ctx->ct_srvinaddr, sap, sizeof (struct sockaddr_in));
1014*4bff34e3Sthurlow 	nb_snbfree(sap);
1015*4bff34e3Sthurlow 	if (error) {
1016*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1017*4bff34e3Sthurlow 		    "can't allocate server address"), error);
1018*4bff34e3Sthurlow 		return (error);
1019*4bff34e3Sthurlow 	}
1020*4bff34e3Sthurlow 	/* We know it's a NetBIOS address here. */
1021*4bff34e3Sthurlow 	bcopy(saserver, &ssn->ioc_server.nb,
1022*4bff34e3Sthurlow 	    sizeof (struct sockaddr_nb));
1023*4bff34e3Sthurlow 	if (ctx->ct_locname[0] == 0) {
1024*4bff34e3Sthurlow 		error = nb_getlocalname(ctx->ct_locname,
1025*4bff34e3Sthurlow 		    SMB_MAXUSERNAMELEN + 1);
1026*4bff34e3Sthurlow 		if (error) {
1027*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
1028*4bff34e3Sthurlow 			    "can't get local name"), error);
1029*4bff34e3Sthurlow 			return (error);
1030*4bff34e3Sthurlow 		}
1031*4bff34e3Sthurlow 		nls_str_upper(ctx->ct_locname, ctx->ct_locname);
1032*4bff34e3Sthurlow 	}
1033*4bff34e3Sthurlow 
1034*4bff34e3Sthurlow 	/* XXX: no nls_str_upper(ctx->ct_locname); here? */
1035*4bff34e3Sthurlow 
1036*4bff34e3Sthurlow 	memcpy(nn.nn_name, ctx->ct_locname, NB_NAMELEN);
1037*4bff34e3Sthurlow 	nn.nn_type = NBT_WKSTA;
1038*4bff34e3Sthurlow 	nn.nn_scope = ctx->ct_nb->nb_scope;
1039*4bff34e3Sthurlow 
1040*4bff34e3Sthurlow 	error = nb_sockaddr(NULL, &nn, &salocal);
1041*4bff34e3Sthurlow 	if (error) {
1042*4bff34e3Sthurlow 		nb_snbfree((struct sockaddr *)saserver);
1043*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1044*4bff34e3Sthurlow 		    "can't allocate local address"), error);
1045*4bff34e3Sthurlow 		return (error);
1046*4bff34e3Sthurlow 	}
1047*4bff34e3Sthurlow 
1048*4bff34e3Sthurlow 	/* We know it's a NetBIOS address here. */
1049*4bff34e3Sthurlow 	bcopy(salocal, &ssn->ioc_local.nb,
1050*4bff34e3Sthurlow 	    sizeof (struct sockaddr_nb));
1051*4bff34e3Sthurlow 
1052*4bff34e3Sthurlow 	error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE,
1053*4bff34e3Sthurlow 	    ssn->ioc_workgroup);
1054*4bff34e3Sthurlow 	if (error)
1055*4bff34e3Sthurlow 		return (error);
1056*4bff34e3Sthurlow 	ctx->ct_flags &= ~SMBCF_AUTHREQ;
1057*4bff34e3Sthurlow 	if (!ctx->ct_secblob && browseok && !sh->ioc_share[0] &&
1058*4bff34e3Sthurlow 	    !(ctx->ct_flags & SMBCF_XXX)) {
1059*4bff34e3Sthurlow 		/* assert: anon share list is subset of overall server shares */
1060*4bff34e3Sthurlow 		error = smb_browse(ctx, 1);
1061*4bff34e3Sthurlow 		if (error) /* user cancel or other error? */
1062*4bff34e3Sthurlow 			return (error);
1063*4bff34e3Sthurlow 		/*
1064*4bff34e3Sthurlow 		 * A share was selected, authenticate button was pressed,
1065*4bff34e3Sthurlow 		 * or anon-authentication failed getting browse list.
1066*4bff34e3Sthurlow 		 */
1067*4bff34e3Sthurlow 	}
1068*4bff34e3Sthurlow 	if ((ctx->ct_secblob == NULL) && (ctx->ct_flags & SMBCF_AUTHREQ ||
1069*4bff34e3Sthurlow 	    (ssn->ioc_password[0] == '\0' &&
1070*4bff34e3Sthurlow 	    !(ctx->ct_flags & SMBCF_NOPWD)))) {
1071*4bff34e3Sthurlow reauth:
1072*4bff34e3Sthurlow 		/*
1073*4bff34e3Sthurlow 		 * This function is implemented in both
1074*4bff34e3Sthurlow 		 * ui-apple.c and ui-sun.c so let's try to
1075*4bff34e3Sthurlow 		 * keep the same interface.  Not sure why
1076*4bff34e3Sthurlow 		 * they didn't just pass ssn here.
1077*4bff34e3Sthurlow 		 */
1078*4bff34e3Sthurlow 		error = smb_get_authentication(
1079*4bff34e3Sthurlow 		    ssn->ioc_workgroup, sizeof (ssn->ioc_workgroup) - 1,
1080*4bff34e3Sthurlow 		    ssn->ioc_user, sizeof (ssn->ioc_user) - 1,
1081*4bff34e3Sthurlow 		    ssn->ioc_password, sizeof (ssn->ioc_password) - 1,
1082*4bff34e3Sthurlow 		    ssn->ioc_srvname, ctx);
1083*4bff34e3Sthurlow 		if (error)
1084*4bff34e3Sthurlow 			return (error);
1085*4bff34e3Sthurlow 	}
1086*4bff34e3Sthurlow 	/*
1087*4bff34e3Sthurlow 	 * if we have a session it is either anonymous
1088*4bff34e3Sthurlow 	 * or from a stale authentication.  re-negotiating
1089*4bff34e3Sthurlow 	 * gets us ready for a fresh session
1090*4bff34e3Sthurlow 	 */
1091*4bff34e3Sthurlow 	if (ctx->ct_flags & SMBCF_SSNACTIVE || renego) {
1092*4bff34e3Sthurlow 		renego = 0;
1093*4bff34e3Sthurlow 		/* don't clobber workgroup name, pass null arg */
1094*4bff34e3Sthurlow 		error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, NULL);
1095*4bff34e3Sthurlow 		if (error)
1096*4bff34e3Sthurlow 			return (error);
1097*4bff34e3Sthurlow 	}
1098*4bff34e3Sthurlow 	if (browseok && !sh->ioc_share[0]) {
1099*4bff34e3Sthurlow 		ctx->ct_flags &= ~SMBCF_AUTHREQ;
1100*4bff34e3Sthurlow 		error = smb_browse(ctx, 0);
1101*4bff34e3Sthurlow 		if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) {
1102*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
1103*4bff34e3Sthurlow 			    "smb_ctx_resolve: bad keychain entry"), 0);
1104*4bff34e3Sthurlow 			ctx->ct_flags |= SMBCF_KCBAD;
1105*4bff34e3Sthurlow 			renego = 1;
1106*4bff34e3Sthurlow 			goto reauth;
1107*4bff34e3Sthurlow 		}
1108*4bff34e3Sthurlow 		if (error) /* auth, user cancel, or other error */
1109*4bff34e3Sthurlow 			return (error);
1110*4bff34e3Sthurlow 		/*
1111*4bff34e3Sthurlow 		 * Re-authenticate button was pressed?
1112*4bff34e3Sthurlow 		 */
1113*4bff34e3Sthurlow 		if (ctx->ct_flags & SMBCF_AUTHREQ)
1114*4bff34e3Sthurlow 			goto reauth;
1115*4bff34e3Sthurlow 		if (!sh->ioc_share[0] && !(ctx->ct_flags & SMBCF_XXX)) {
1116*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
1117*4bff34e3Sthurlow 			    "no share specified for %s@%s"),
1118*4bff34e3Sthurlow 			    0, ssn->ioc_user, ssn->ioc_srvname);
1119*4bff34e3Sthurlow 			return (EINVAL);
1120*4bff34e3Sthurlow 		}
1121*4bff34e3Sthurlow 	}
1122*4bff34e3Sthurlow 	ctx->ct_flags |= SMBCF_RESOLVED;
1123*4bff34e3Sthurlow 
1124*4bff34e3Sthurlow 	if (smb_debug)
1125*4bff34e3Sthurlow 		dump_ctx("after smb_ctx_resolve", ctx);
1126*4bff34e3Sthurlow 
1127*4bff34e3Sthurlow 	return (0);
1128*4bff34e3Sthurlow }
1129*4bff34e3Sthurlow 
1130*4bff34e3Sthurlow int
1131*4bff34e3Sthurlow smb_open_driver()
1132*4bff34e3Sthurlow {
1133*4bff34e3Sthurlow 	char buf[20];
1134*4bff34e3Sthurlow 	int err, fd, i;
1135*4bff34e3Sthurlow 	uint32_t version;
1136*4bff34e3Sthurlow 
1137*4bff34e3Sthurlow 	/*
1138*4bff34e3Sthurlow 	 * First try to open as clone
1139*4bff34e3Sthurlow 	 */
1140*4bff34e3Sthurlow 	fd = open("/dev/"NSMB_NAME, O_RDWR);
1141*4bff34e3Sthurlow 	if (fd >= 0)
1142*4bff34e3Sthurlow 		goto opened;
1143*4bff34e3Sthurlow 
1144*4bff34e3Sthurlow 	err = errno; /* from open */
1145*4bff34e3Sthurlow #ifdef APPLE
1146*4bff34e3Sthurlow 	/*
1147*4bff34e3Sthurlow 	 * well, no clone capabilities available - we have to scan
1148*4bff34e3Sthurlow 	 * all devices in order to get free one
1149*4bff34e3Sthurlow 	 */
1150*4bff34e3Sthurlow 	for (i = 0; i < 1024; i++) {
1151*4bff34e3Sthurlow 		snprintf(buf, sizeof (buf), "/dev/%s%d", NSMB_NAME, i);
1152*4bff34e3Sthurlow 		fd = open(buf, O_RDWR);
1153*4bff34e3Sthurlow 		if (fd >= 0)
1154*4bff34e3Sthurlow 			goto opened;
1155*4bff34e3Sthurlow 		if (i && POWEROF2(i+1))
1156*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
1157*4bff34e3Sthurlow 			    "%d failures to open smb device"), errno, i+1);
1158*4bff34e3Sthurlow 	}
1159*4bff34e3Sthurlow 	err = ENOENT;
1160*4bff34e3Sthurlow #endif
1161*4bff34e3Sthurlow 	smb_error(dgettext(TEXT_DOMAIN,
1162*4bff34e3Sthurlow 	    "failed to open %s"), err, "/dev/" NSMB_NAME);
1163*4bff34e3Sthurlow 	return (-1);
1164*4bff34e3Sthurlow 
1165*4bff34e3Sthurlow opened:
1166*4bff34e3Sthurlow 	/*
1167*4bff34e3Sthurlow 	 * Check the driver version (paranoia)
1168*4bff34e3Sthurlow 	 * Do this BEFORE any other ioctl calls.
1169*4bff34e3Sthurlow 	 */
1170*4bff34e3Sthurlow 	if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) {
1171*4bff34e3Sthurlow 		err = errno;
1172*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1173*4bff34e3Sthurlow 		    "failed to get driver version"), err);
1174*4bff34e3Sthurlow 		close(fd);
1175*4bff34e3Sthurlow 		return (-1);
1176*4bff34e3Sthurlow 	}
1177*4bff34e3Sthurlow 	if (version != NSMB_VERSION) {
1178*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1179*4bff34e3Sthurlow 		    "incorrect driver version"), 0);
1180*4bff34e3Sthurlow 		close(fd);
1181*4bff34e3Sthurlow 		return (-1);
1182*4bff34e3Sthurlow 	}
1183*4bff34e3Sthurlow 
1184*4bff34e3Sthurlow 	return (fd);
1185*4bff34e3Sthurlow }
1186*4bff34e3Sthurlow 
1187*4bff34e3Sthurlow static int
1188*4bff34e3Sthurlow smb_ctx_gethandle(struct smb_ctx *ctx)
1189*4bff34e3Sthurlow {
1190*4bff34e3Sthurlow 	int err, fd;
1191*4bff34e3Sthurlow 
1192*4bff34e3Sthurlow 	if (ctx->ct_fd != -1) {
1193*4bff34e3Sthurlow 		rpc_cleanup_smbctx(ctx);
1194*4bff34e3Sthurlow 		close(ctx->ct_fd);
1195*4bff34e3Sthurlow 		ctx->ct_fd = -1;
1196*4bff34e3Sthurlow 		ctx->ct_flags &= ~SMBCF_SSNACTIVE;
1197*4bff34e3Sthurlow 	}
1198*4bff34e3Sthurlow 
1199*4bff34e3Sthurlow 	fd = smb_open_driver();
1200*4bff34e3Sthurlow 	if (fd < 0)
1201*4bff34e3Sthurlow 		return (ENODEV);
1202*4bff34e3Sthurlow 
1203*4bff34e3Sthurlow 	ctx->ct_fd = fd;
1204*4bff34e3Sthurlow 	return (0);
1205*4bff34e3Sthurlow }
1206*4bff34e3Sthurlow 
1207*4bff34e3Sthurlow int
1208*4bff34e3Sthurlow smb_ctx_ioctl(struct smb_ctx *ctx, int inum, struct smbioc_lookup *rqp)
1209*4bff34e3Sthurlow {
1210*4bff34e3Sthurlow 	size_t	siz = DEF_SEC_TOKEN_LEN;
1211*4bff34e3Sthurlow 	int	rc = 0;
1212*4bff34e3Sthurlow 	struct sockaddr sap1, sap2;
1213*4bff34e3Sthurlow 	int i;
1214*4bff34e3Sthurlow 
1215*4bff34e3Sthurlow 	if (rqp->ioc_ssn.ioc_outtok)
1216*4bff34e3Sthurlow 		free(rqp->ioc_ssn.ioc_outtok);
1217*4bff34e3Sthurlow 	rqp->ioc_ssn.ioc_outtoklen = siz;
1218*4bff34e3Sthurlow 	rqp->ioc_ssn.ioc_outtok = malloc(siz+1);
1219*4bff34e3Sthurlow 	if (rqp->ioc_ssn.ioc_outtok == NULL)
1220*4bff34e3Sthurlow 		return (ENOMEM);
1221*4bff34e3Sthurlow 	bzero(rqp->ioc_ssn.ioc_outtok, siz+1);
1222*4bff34e3Sthurlow 	/* Note: No longer put length in outtok[0] */
1223*4bff34e3Sthurlow 	/* *((int *)rqp->ioc_ssn.ioc_outtok) = (int)siz; */
1224*4bff34e3Sthurlow 
1225*4bff34e3Sthurlow 	seteuid(eff_uid); /* restore setuid root briefly */
1226*4bff34e3Sthurlow 	if (ioctl(ctx->ct_fd, inum, rqp) == -1) {
1227*4bff34e3Sthurlow 		rc = errno;
1228*4bff34e3Sthurlow 		goto out;
1229*4bff34e3Sthurlow 	}
1230*4bff34e3Sthurlow 	if (rqp->ioc_ssn.ioc_outtoklen <= siz)
1231*4bff34e3Sthurlow 		goto out;
1232*4bff34e3Sthurlow 
1233*4bff34e3Sthurlow 	/*
1234*4bff34e3Sthurlow 	 * Operation completed, but our output token wasn't large enough.
1235*4bff34e3Sthurlow 	 * The re-call below only pulls the token from the kernel.
1236*4bff34e3Sthurlow 	 */
1237*4bff34e3Sthurlow 	siz = rqp->ioc_ssn.ioc_outtoklen;
1238*4bff34e3Sthurlow 	free(rqp->ioc_ssn.ioc_outtok);
1239*4bff34e3Sthurlow 	rqp->ioc_ssn.ioc_outtok = malloc(siz + 1);
1240*4bff34e3Sthurlow 	if (rqp->ioc_ssn.ioc_outtok == NULL) {
1241*4bff34e3Sthurlow 		rc = ENOMEM;
1242*4bff34e3Sthurlow 		goto out;
1243*4bff34e3Sthurlow 	}
1244*4bff34e3Sthurlow 	bzero(rqp->ioc_ssn.ioc_outtok, siz+1);
1245*4bff34e3Sthurlow 	/* Note: No longer put length in outtok[0] */
1246*4bff34e3Sthurlow 	/* *((int *)rqp->ioc_ssn.ioc_outtok) = siz; */
1247*4bff34e3Sthurlow 	if (ioctl(ctx->ct_fd, inum, rqp) == -1)
1248*4bff34e3Sthurlow 		rc = errno;
1249*4bff34e3Sthurlow out:
1250*4bff34e3Sthurlow 	seteuid(real_uid); /* and back to real user */
1251*4bff34e3Sthurlow 	return (rc);
1252*4bff34e3Sthurlow }
1253*4bff34e3Sthurlow 
1254*4bff34e3Sthurlow 
1255*4bff34e3Sthurlow /*
1256*4bff34e3Sthurlow  * adds a GSSAPI wrapper
1257*4bff34e3Sthurlow  */
1258*4bff34e3Sthurlow char *
1259*4bff34e3Sthurlow smb_ctx_tkt2gtok(uchar_t *tkt, ulong_t tktlen,
1260*4bff34e3Sthurlow     uchar_t **gtokp, ulong_t *gtoklenp)
1261*4bff34e3Sthurlow {
1262*4bff34e3Sthurlow 	ulong_t		bloblen = tktlen;
1263*4bff34e3Sthurlow 	ulong_t		len;
1264*4bff34e3Sthurlow 	uchar_t		krbapreq[2] = "\x01\x00"; /* see RFC 1964 */
1265*4bff34e3Sthurlow 	char 		*failure;
1266*4bff34e3Sthurlow 	uchar_t 	*blob = NULL;		/* result */
1267*4bff34e3Sthurlow 	uchar_t 	*b;
1268*4bff34e3Sthurlow 
1269*4bff34e3Sthurlow 	bloblen += sizeof (krbapreq);
1270*4bff34e3Sthurlow 	bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen;
1271*4bff34e3Sthurlow 	len = bloblen;
1272*4bff34e3Sthurlow 	bloblen = ASNDerCalcTokenLength(bloblen, bloblen);
1273*4bff34e3Sthurlow 	failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok malloc");
1274*4bff34e3Sthurlow 	if (!(blob = malloc(bloblen)))
1275*4bff34e3Sthurlow 		goto out;
1276*4bff34e3Sthurlow 	b = blob;
1277*4bff34e3Sthurlow 	b += ASNDerWriteToken(b, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, len);
1278*4bff34e3Sthurlow 	b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5);
1279*4bff34e3Sthurlow 	memcpy(b, krbapreq, sizeof (krbapreq));
1280*4bff34e3Sthurlow 	b += sizeof (krbapreq);
1281*4bff34e3Sthurlow 	failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok insanity check");
1282*4bff34e3Sthurlow 	if (b + tktlen != blob + bloblen)
1283*4bff34e3Sthurlow 		goto out;
1284*4bff34e3Sthurlow 	memcpy(b, tkt, tktlen);
1285*4bff34e3Sthurlow 	*gtoklenp = bloblen;
1286*4bff34e3Sthurlow 	*gtokp = blob;
1287*4bff34e3Sthurlow 	failure = NULL;
1288*4bff34e3Sthurlow out:;
1289*4bff34e3Sthurlow 	if (blob && failure)
1290*4bff34e3Sthurlow 		free(blob);
1291*4bff34e3Sthurlow 	return (failure);
1292*4bff34e3Sthurlow }
1293*4bff34e3Sthurlow 
1294*4bff34e3Sthurlow 
1295*4bff34e3Sthurlow /*
1296*4bff34e3Sthurlow  * Initialization for Kerberos, pulled out of smb_ctx_principal2tkt.
1297*4bff34e3Sthurlow  * This just gets our cached credentials, if we have any.
1298*4bff34e3Sthurlow  * Based on the "klist" command.
1299*4bff34e3Sthurlow  */
1300*4bff34e3Sthurlow char *
1301*4bff34e3Sthurlow smb_ctx_krb5init(struct smb_ctx *ctx)
1302*4bff34e3Sthurlow {
1303*4bff34e3Sthurlow 	char *failure;
1304*4bff34e3Sthurlow 	krb5_error_code	kerr;
1305*4bff34e3Sthurlow 	krb5_context	kctx = NULL;
1306*4bff34e3Sthurlow 	krb5_ccache 	kcc = NULL;
1307*4bff34e3Sthurlow 	krb5_principal	kprin = NULL;
1308*4bff34e3Sthurlow 
1309*4bff34e3Sthurlow 	kerr = krb5_init_context(&kctx);
1310*4bff34e3Sthurlow 	if (kerr) {
1311*4bff34e3Sthurlow 		failure = "krb5_init_context";
1312*4bff34e3Sthurlow 		goto out;
1313*4bff34e3Sthurlow 	}
1314*4bff34e3Sthurlow 	ctx->ct_krb5ctx = kctx;
1315*4bff34e3Sthurlow 
1316*4bff34e3Sthurlow 	/* non-default would instead use krb5_cc_resolve */
1317*4bff34e3Sthurlow 	kerr = krb5_cc_default(kctx, &kcc);
1318*4bff34e3Sthurlow 	if (kerr) {
1319*4bff34e3Sthurlow 		failure = "krb5_cc_default";
1320*4bff34e3Sthurlow 		goto out;
1321*4bff34e3Sthurlow 	}
1322*4bff34e3Sthurlow 	ctx->ct_krb5cc = kcc;
1323*4bff34e3Sthurlow 
1324*4bff34e3Sthurlow 	/*
1325*4bff34e3Sthurlow 	 * Get the client principal (ticket),
1326*4bff34e3Sthurlow 	 * or find out if we don't have one.
1327*4bff34e3Sthurlow 	 */
1328*4bff34e3Sthurlow 	kerr = krb5_cc_get_principal(kctx, kcc, &kprin);
1329*4bff34e3Sthurlow 	if (kerr) {
1330*4bff34e3Sthurlow 		failure = "krb5_cc_get_principal";
1331*4bff34e3Sthurlow 		goto out;
1332*4bff34e3Sthurlow 	}
1333*4bff34e3Sthurlow 	ctx->ct_krb5cp = kprin;
1334*4bff34e3Sthurlow 
1335*4bff34e3Sthurlow 	if (smb_verbose) {
1336*4bff34e3Sthurlow 		fprintf(stderr, gettext("Ticket cache: %s:%s\n"),
1337*4bff34e3Sthurlow 		    krb5_cc_get_type(kctx, kcc),
1338*4bff34e3Sthurlow 		    krb5_cc_get_name(kctx, kcc));
1339*4bff34e3Sthurlow 	}
1340*4bff34e3Sthurlow 	failure = NULL;
1341*4bff34e3Sthurlow 
1342*4bff34e3Sthurlow out:
1343*4bff34e3Sthurlow 	return (failure);
1344*4bff34e3Sthurlow }
1345*4bff34e3Sthurlow 
1346*4bff34e3Sthurlow 
1347*4bff34e3Sthurlow /*
1348*4bff34e3Sthurlow  * See "Windows 2000 Kerberos Interoperability" paper by
1349*4bff34e3Sthurlow  * Christopher Nebergall.  RC4 HMAC is the W2K default but
1350*4bff34e3Sthurlow  * Samba support lagged (not due to Samba itself, but due to OS'
1351*4bff34e3Sthurlow  * Kerberos implementations.)
1352*4bff34e3Sthurlow  *
1353*4bff34e3Sthurlow  * Only session enc type should matter, not ticket enc type,
1354*4bff34e3Sthurlow  * per Sam Hartman on krbdev.
1355*4bff34e3Sthurlow  *
1356*4bff34e3Sthurlow  * Preauthentication failure topics in krb-protocol may help here...
1357*4bff34e3Sthurlow  * try "John Brezak" and/or "Clifford Neuman" too.
1358*4bff34e3Sthurlow  */
1359*4bff34e3Sthurlow static krb5_enctype kenctypes[] = {
1360*4bff34e3Sthurlow 	ENCTYPE_ARCFOUR_HMAC,	/* defined in Tiger krb5.h */
1361*4bff34e3Sthurlow 	ENCTYPE_DES_CBC_MD5,
1362*4bff34e3Sthurlow 	ENCTYPE_DES_CBC_CRC,
1363*4bff34e3Sthurlow 	ENCTYPE_NULL
1364*4bff34e3Sthurlow };
1365*4bff34e3Sthurlow 
1366*4bff34e3Sthurlow /*
1367*4bff34e3Sthurlow  * Obtain a kerberos ticket...
1368*4bff34e3Sthurlow  * (if TLD != "gov" then pray first)
1369*4bff34e3Sthurlow  */
1370*4bff34e3Sthurlow char *
1371*4bff34e3Sthurlow smb_ctx_principal2tkt(
1372*4bff34e3Sthurlow 	struct smb_ctx *ctx, char *prin,
1373*4bff34e3Sthurlow 	uchar_t **tktp, ulong_t *tktlenp)
1374*4bff34e3Sthurlow {
1375*4bff34e3Sthurlow 	char 		*failure;
1376*4bff34e3Sthurlow 	krb5_context	kctx = NULL;
1377*4bff34e3Sthurlow 	krb5_error_code	kerr;
1378*4bff34e3Sthurlow 	krb5_ccache	kcc = NULL;
1379*4bff34e3Sthurlow 	krb5_principal	kprin = NULL, cprn = NULL;
1380*4bff34e3Sthurlow 	krb5_creds	kcreds, *kcredsp = NULL;
1381*4bff34e3Sthurlow 	krb5_auth_context	kauth = NULL;
1382*4bff34e3Sthurlow 	krb5_data	kdata, kdata0;
1383*4bff34e3Sthurlow 	uchar_t 		*tkt;
1384*4bff34e3Sthurlow 
1385*4bff34e3Sthurlow 	memset((char *)&kcreds, 0, sizeof (kcreds));
1386*4bff34e3Sthurlow 	kdata0.length = 0;
1387*4bff34e3Sthurlow 
1388*4bff34e3Sthurlow 	/* These shoud have been done in smb_ctx_krb5init() */
1389*4bff34e3Sthurlow 	if (ctx->ct_krb5ctx == NULL ||
1390*4bff34e3Sthurlow 	    ctx->ct_krb5cc == NULL ||
1391*4bff34e3Sthurlow 	    ctx->ct_krb5cp == NULL) {
1392*4bff34e3Sthurlow 		failure = "smb_ctx_krb5init";
1393*4bff34e3Sthurlow 		goto out;
1394*4bff34e3Sthurlow 	}
1395*4bff34e3Sthurlow 	kctx = ctx->ct_krb5ctx;
1396*4bff34e3Sthurlow 	kcc  = ctx->ct_krb5cc;
1397*4bff34e3Sthurlow 	cprn = ctx->ct_krb5cp;
1398*4bff34e3Sthurlow 
1399*4bff34e3Sthurlow 	failure = "krb5_set_default_tgs_enctypes";
1400*4bff34e3Sthurlow 	if ((kerr = krb5_set_default_tgs_enctypes(kctx, kenctypes)))
1401*4bff34e3Sthurlow 		goto out;
1402*4bff34e3Sthurlow 	/*
1403*4bff34e3Sthurlow 	 * The following is an unrolling of krb5_mk_req.  Something like:
1404*4bff34e3Sthurlow 	 * krb5_mk_req(kctx, &kauth, 0, service(prin), hostname(prin),
1405*4bff34e3Sthurlow 	 *		&kdata0, kcc, &kdata);)
1406*4bff34e3Sthurlow 	 * ...except we needed krb5_parse_name not krb5_sname_to_principal.
1407*4bff34e3Sthurlow 	 */
1408*4bff34e3Sthurlow 	failure = "krb5_parse_name";
1409*4bff34e3Sthurlow 	if ((kerr = krb5_parse_name(kctx, prin, &kprin)))
1410*4bff34e3Sthurlow 		goto out;
1411*4bff34e3Sthurlow 	failure = "krb5_copy_principal(server)";
1412*4bff34e3Sthurlow 	if ((kerr = krb5_copy_principal(kctx, kprin, &kcreds.server)))
1413*4bff34e3Sthurlow 		goto out;
1414*4bff34e3Sthurlow 	failure = "krb5_copy_principal(client)";
1415*4bff34e3Sthurlow 	if ((kerr = krb5_copy_principal(kctx, cprn, &kcreds.client)))
1416*4bff34e3Sthurlow 		goto out;
1417*4bff34e3Sthurlow 	failure = "krb5_get_credentials";
1418*4bff34e3Sthurlow 	if ((kerr = krb5_get_credentials(kctx, 0, kcc, &kcreds, &kcredsp)))
1419*4bff34e3Sthurlow 		goto out;
1420*4bff34e3Sthurlow 	failure = "krb5_mk_req_extended";
1421*4bff34e3Sthurlow 	if ((kerr = krb5_mk_req_extended(kctx, &kauth, 0, &kdata0, kcredsp,
1422*4bff34e3Sthurlow 	    &kdata)))
1423*4bff34e3Sthurlow 		goto out;
1424*4bff34e3Sthurlow 	failure = "malloc";
1425*4bff34e3Sthurlow 	if (!(tkt = malloc(kdata.length))) {
1426*4bff34e3Sthurlow 		krb5_free_data_contents(kctx, &kdata);
1427*4bff34e3Sthurlow 		goto out;
1428*4bff34e3Sthurlow 	}
1429*4bff34e3Sthurlow 	*tktlenp = kdata.length;
1430*4bff34e3Sthurlow 	memcpy(tkt, kdata.data, kdata.length);
1431*4bff34e3Sthurlow 	krb5_free_data_contents(kctx, &kdata);
1432*4bff34e3Sthurlow 	*tktp = tkt;
1433*4bff34e3Sthurlow 	failure = NULL;
1434*4bff34e3Sthurlow out:;
1435*4bff34e3Sthurlow 	if (kerr) {
1436*4bff34e3Sthurlow 		if (!failure)
1437*4bff34e3Sthurlow 			failure = "smb_ctx_principal2tkt";
1438*4bff34e3Sthurlow 		/*
1439*4bff34e3Sthurlow 		 * Avoid logging the typical "No credentials cache found"
1440*4bff34e3Sthurlow 		 */
1441*4bff34e3Sthurlow 		if (kerr != KRB5_FCC_NOFILE ||
1442*4bff34e3Sthurlow 		    strcmp(failure, "krb5_cc_get_principal"))
1443*4bff34e3Sthurlow 			com_err(__progname, kerr, failure);
1444*4bff34e3Sthurlow 	}
1445*4bff34e3Sthurlow 	if (kauth)
1446*4bff34e3Sthurlow 		krb5_auth_con_free(kctx, kauth);
1447*4bff34e3Sthurlow 	if (kcredsp)
1448*4bff34e3Sthurlow 		krb5_free_creds(kctx, kcredsp);
1449*4bff34e3Sthurlow 	if (kcreds.server || kcreds.client)
1450*4bff34e3Sthurlow 		krb5_free_cred_contents(kctx, &kcreds);
1451*4bff34e3Sthurlow 	if (kprin)
1452*4bff34e3Sthurlow 		krb5_free_principal(kctx, kprin);
1453*4bff34e3Sthurlow 
1454*4bff34e3Sthurlow 	/* Free kctx in smb_ctx_done */
1455*4bff34e3Sthurlow 
1456*4bff34e3Sthurlow 	return (failure);
1457*4bff34e3Sthurlow }
1458*4bff34e3Sthurlow 
1459*4bff34e3Sthurlow char *
1460*4bff34e3Sthurlow smb_ctx_principal2blob(
1461*4bff34e3Sthurlow 	struct smb_ctx *ctx,
1462*4bff34e3Sthurlow 	smbioc_ossn_t *ssn,
1463*4bff34e3Sthurlow 	char *prin)
1464*4bff34e3Sthurlow {
1465*4bff34e3Sthurlow 	int		rc = 0;
1466*4bff34e3Sthurlow 	char 		*failure;
1467*4bff34e3Sthurlow 	uchar_t 	*tkt = NULL;
1468*4bff34e3Sthurlow 	ulong_t		tktlen;
1469*4bff34e3Sthurlow 	uchar_t 	*gtok = NULL;		/* gssapi token */
1470*4bff34e3Sthurlow 	ulong_t		gtoklen;		/* gssapi token length */
1471*4bff34e3Sthurlow 	SPNEGO_TOKEN_HANDLE  stok = NULL;	/* spnego token */
1472*4bff34e3Sthurlow 	void 	*blob = NULL;		/* result */
1473*4bff34e3Sthurlow 	ulong_t		bloblen;		/* result length */
1474*4bff34e3Sthurlow 
1475*4bff34e3Sthurlow 	if ((failure = smb_ctx_principal2tkt(ctx, prin, &tkt, &tktlen)))
1476*4bff34e3Sthurlow 		goto out;
1477*4bff34e3Sthurlow 	if ((failure = smb_ctx_tkt2gtok(tkt, tktlen, &gtok, &gtoklen)))
1478*4bff34e3Sthurlow 		goto out;
1479*4bff34e3Sthurlow 	/*
1480*4bff34e3Sthurlow 	 * RFC says to send NegTokenTarg now.  So does MS docs.  But
1481*4bff34e3Sthurlow 	 * win2k gives ERRbaduid if we do...  we must send
1482*4bff34e3Sthurlow 	 * another NegTokenInit now!
1483*4bff34e3Sthurlow 	 */
1484*4bff34e3Sthurlow 	failure = "spnegoCreateNegTokenInit";
1485*4bff34e3Sthurlow 	if ((rc = spnegoCreateNegTokenInit(spnego_mech_oid_Kerberos_V5_Legacy,
1486*4bff34e3Sthurlow 	    0, gtok, gtoklen, NULL, 0, &stok)))
1487*4bff34e3Sthurlow 		goto out;
1488*4bff34e3Sthurlow 	failure = "spnegoTokenGetBinary(NULL)";
1489*4bff34e3Sthurlow 	rc = spnegoTokenGetBinary(stok, NULL, &bloblen);
1490*4bff34e3Sthurlow 	if (rc != SPNEGO_E_BUFFER_TOO_SMALL)
1491*4bff34e3Sthurlow 		goto out;
1492*4bff34e3Sthurlow 	failure = "malloc";
1493*4bff34e3Sthurlow 	if (!(blob = malloc((size_t)bloblen)))
1494*4bff34e3Sthurlow 		goto out;
1495*4bff34e3Sthurlow 	/* No longer store length at start of blob. */
1496*4bff34e3Sthurlow 	/* *blob = bloblen; */
1497*4bff34e3Sthurlow 	failure = "spnegoTokenGetBinary";
1498*4bff34e3Sthurlow 	if ((rc = spnegoTokenGetBinary(stok, blob, &bloblen)))
1499*4bff34e3Sthurlow 		goto out;
1500*4bff34e3Sthurlow 	ssn->ioc_intoklen = bloblen;
1501*4bff34e3Sthurlow 	ssn->ioc_intok = blob;
1502*4bff34e3Sthurlow 	failure = NULL;
1503*4bff34e3Sthurlow out:;
1504*4bff34e3Sthurlow 	if (rc) {
1505*4bff34e3Sthurlow 		/* XXX better is to embed rc in failure */
1506*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1507*4bff34e3Sthurlow 		    "spnego principal2blob error %d"), 0, -rc);
1508*4bff34e3Sthurlow 		if (!failure)
1509*4bff34e3Sthurlow 			failure = "spnego";
1510*4bff34e3Sthurlow 	}
1511*4bff34e3Sthurlow 	if (blob && failure)
1512*4bff34e3Sthurlow 		free(blob);
1513*4bff34e3Sthurlow 	if (stok)
1514*4bff34e3Sthurlow 		spnegoFreeData(stok);
1515*4bff34e3Sthurlow 	if (gtok)
1516*4bff34e3Sthurlow 		free(gtok);
1517*4bff34e3Sthurlow 	if (tkt)
1518*4bff34e3Sthurlow 		free(tkt);
1519*4bff34e3Sthurlow 	return (failure);
1520*4bff34e3Sthurlow }
1521*4bff34e3Sthurlow 
1522*4bff34e3Sthurlow 
1523*4bff34e3Sthurlow #if 0
1524*4bff34e3Sthurlow void
1525*4bff34e3Sthurlow prblob(uchar_t *b, size_t len)
1526*4bff34e3Sthurlow {
1527*4bff34e3Sthurlow 	while (len--)
1528*4bff34e3Sthurlow 		fprintf(stderr, "%02x", *b++);
1529*4bff34e3Sthurlow 	fprintf(stderr, "\n");
1530*4bff34e3Sthurlow }
1531*4bff34e3Sthurlow #endif
1532*4bff34e3Sthurlow 
1533*4bff34e3Sthurlow 
1534*4bff34e3Sthurlow /*
1535*4bff34e3Sthurlow  * We navigate the SPNEGO & ASN1 encoding to find a kerberos principal
1536*4bff34e3Sthurlow  * Note: driver no longer puts length at start of blob.
1537*4bff34e3Sthurlow  */
1538*4bff34e3Sthurlow char *
1539*4bff34e3Sthurlow smb_ctx_blob2principal(
1540*4bff34e3Sthurlow 	struct smb_ctx *ctx,
1541*4bff34e3Sthurlow 	smbioc_ossn_t *ssn,
1542*4bff34e3Sthurlow 	char **prinp)
1543*4bff34e3Sthurlow {
1544*4bff34e3Sthurlow 	uchar_t		*blob = ssn->ioc_outtok;
1545*4bff34e3Sthurlow 	size_t		len = ssn->ioc_outtoklen;
1546*4bff34e3Sthurlow 	int		rc = 0;
1547*4bff34e3Sthurlow 	SPNEGO_TOKEN_HANDLE	stok = NULL;
1548*4bff34e3Sthurlow 	int		indx = 0;
1549*4bff34e3Sthurlow 	char 		*failure;
1550*4bff34e3Sthurlow 	uchar_t		flags = 0;
1551*4bff34e3Sthurlow 	unsigned long	plen = 0;
1552*4bff34e3Sthurlow 	uchar_t 	*prin;
1553*4bff34e3Sthurlow 
1554*4bff34e3Sthurlow #if 0
1555*4bff34e3Sthurlow 	fprintf(stderr, "blob from negotiate:\n");
1556*4bff34e3Sthurlow 	prblob(blob, len);
1557*4bff34e3Sthurlow #endif
1558*4bff34e3Sthurlow 
1559*4bff34e3Sthurlow 	/* Skip the GUID */
1560*4bff34e3Sthurlow 	assert(len >= SMB_GUIDLEN);
1561*4bff34e3Sthurlow 	blob += SMB_GUIDLEN;
1562*4bff34e3Sthurlow 	len  -= SMB_GUIDLEN;
1563*4bff34e3Sthurlow 
1564*4bff34e3Sthurlow 	failure = "spnegoInitFromBinary";
1565*4bff34e3Sthurlow 	if ((rc = spnegoInitFromBinary(blob, len, &stok)))
1566*4bff34e3Sthurlow 		goto out;
1567*4bff34e3Sthurlow 	/*
1568*4bff34e3Sthurlow 	 * Needn't use new Kerberos OID - the Legacy one is fine.
1569*4bff34e3Sthurlow 	 */
1570*4bff34e3Sthurlow 	failure = "spnegoIsMechTypeAvailable";
1571*4bff34e3Sthurlow 	if (spnegoIsMechTypeAvailable(stok, spnego_mech_oid_Kerberos_V5_Legacy,
1572*4bff34e3Sthurlow 	    &indx))
1573*4bff34e3Sthurlow 		goto out;
1574*4bff34e3Sthurlow 	/*
1575*4bff34e3Sthurlow 	 * Ignoring optional context flags for now.  May want to pass
1576*4bff34e3Sthurlow 	 * them to krb5 layer.  XXX
1577*4bff34e3Sthurlow 	 */
1578*4bff34e3Sthurlow 	if (!spnegoGetContextFlags(stok, &flags))
1579*4bff34e3Sthurlow 		fprintf(stderr, dgettext(TEXT_DOMAIN,
1580*4bff34e3Sthurlow 		    "spnego context flags 0x%x\n"), flags);
1581*4bff34e3Sthurlow 	failure = "spnegoGetMechListMIC(NULL)";
1582*4bff34e3Sthurlow 	rc = spnegoGetMechListMIC(stok, NULL, &plen);
1583*4bff34e3Sthurlow 	if (rc != SPNEGO_E_BUFFER_TOO_SMALL)
1584*4bff34e3Sthurlow 		goto out;
1585*4bff34e3Sthurlow 	failure = "malloc";
1586*4bff34e3Sthurlow 	if (!(prin = malloc(plen + 1)))
1587*4bff34e3Sthurlow 		goto out;
1588*4bff34e3Sthurlow 	failure = "spnegoGetMechListMIC";
1589*4bff34e3Sthurlow 	if ((rc = spnegoGetMechListMIC(stok, prin, &plen))) {
1590*4bff34e3Sthurlow 		free(prin);
1591*4bff34e3Sthurlow 		goto out;
1592*4bff34e3Sthurlow 	}
1593*4bff34e3Sthurlow 	prin[plen] = '\0';
1594*4bff34e3Sthurlow 	*prinp = (char *)prin;
1595*4bff34e3Sthurlow 	failure = NULL;
1596*4bff34e3Sthurlow out:;
1597*4bff34e3Sthurlow 	if (stok)
1598*4bff34e3Sthurlow 		spnegoFreeData(stok);
1599*4bff34e3Sthurlow 	if (rc) {
1600*4bff34e3Sthurlow 		/* XXX better is to embed rc in failure */
1601*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1602*4bff34e3Sthurlow 		    "spnego blob2principal error %d"), 0, -rc);
1603*4bff34e3Sthurlow 		if (!failure)
1604*4bff34e3Sthurlow 			failure = "spnego";
1605*4bff34e3Sthurlow 	}
1606*4bff34e3Sthurlow 	return (failure);
1607*4bff34e3Sthurlow }
1608*4bff34e3Sthurlow 
1609*4bff34e3Sthurlow 
1610*4bff34e3Sthurlow int
1611*4bff34e3Sthurlow smb_ctx_negotiate(struct smb_ctx *ctx, int level, int flags, char *workgroup)
1612*4bff34e3Sthurlow {
1613*4bff34e3Sthurlow 	struct smbioc_lookup	rq;
1614*4bff34e3Sthurlow 	int	error = 0;
1615*4bff34e3Sthurlow 	char 	*failure = NULL;
1616*4bff34e3Sthurlow 	char	*principal = NULL;
1617*4bff34e3Sthurlow 	char c;
1618*4bff34e3Sthurlow 	int i;
1619*4bff34e3Sthurlow 	ssize_t *outtoklen;
1620*4bff34e3Sthurlow 	uchar_t *blob;
1621*4bff34e3Sthurlow 
1622*4bff34e3Sthurlow 	/*
1623*4bff34e3Sthurlow 	 * We leave ct_secblob set iff extended security
1624*4bff34e3Sthurlow 	 * negotiation succeeds.
1625*4bff34e3Sthurlow 	 */
1626*4bff34e3Sthurlow 	if (ctx->ct_secblob) {
1627*4bff34e3Sthurlow 		free(ctx->ct_secblob);
1628*4bff34e3Sthurlow 		ctx->ct_secblob = NULL;
1629*4bff34e3Sthurlow 	}
1630*4bff34e3Sthurlow #ifdef XXX
1631*4bff34e3Sthurlow 	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
1632*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1633*4bff34e3Sthurlow 		    "smb_ctx_lookup() data is not resolved"), 0);
1634*4bff34e3Sthurlow 		return (EINVAL);
1635*4bff34e3Sthurlow 	}
1636*4bff34e3Sthurlow #endif
1637*4bff34e3Sthurlow 	if ((error = smb_ctx_gethandle(ctx)))
1638*4bff34e3Sthurlow 		return (error);
1639*4bff34e3Sthurlow 
1640*4bff34e3Sthurlow 	bzero(&rq, sizeof (rq));
1641*4bff34e3Sthurlow 	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
1642*4bff34e3Sthurlow 	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
1643*4bff34e3Sthurlow 
1644*4bff34e3Sthurlow 	/*
1645*4bff34e3Sthurlow 	 * Find out if we have a Kerberos ticket,
1646*4bff34e3Sthurlow 	 * and only offer SPNEGO if we have one.
1647*4bff34e3Sthurlow 	 */
1648*4bff34e3Sthurlow 	failure = smb_ctx_krb5init(ctx);
1649*4bff34e3Sthurlow 	if (failure) {
1650*4bff34e3Sthurlow 		if (smb_verbose)
1651*4bff34e3Sthurlow 			smb_error(failure, 0);
1652*4bff34e3Sthurlow 		goto out;
1653*4bff34e3Sthurlow 	}
1654*4bff34e3Sthurlow 
1655*4bff34e3Sthurlow 	rq.ioc_flags = flags;
1656*4bff34e3Sthurlow 	rq.ioc_level = level;
1657*4bff34e3Sthurlow 	rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC;
1658*4bff34e3Sthurlow 	error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq);
1659*4bff34e3Sthurlow 	if (error) {
1660*4bff34e3Sthurlow 		failure = dgettext(TEXT_DOMAIN, "negotiate failed");
1661*4bff34e3Sthurlow 		smb_error(failure, error);
1662*4bff34e3Sthurlow 		if (error == ETIMEDOUT)
1663*4bff34e3Sthurlow 			return (error);
1664*4bff34e3Sthurlow 		goto out;
1665*4bff34e3Sthurlow 	}
1666*4bff34e3Sthurlow 	/*
1667*4bff34e3Sthurlow 	 * If the server capabilities did not include
1668*4bff34e3Sthurlow 	 * SMB_CAP_EXT_SECURITY then the driver clears
1669*4bff34e3Sthurlow 	 * the flag SMBVOPT_EXT_SEC for us.
1670*4bff34e3Sthurlow 	 * XXX: should add the capabilities to ioc_ssn
1671*4bff34e3Sthurlow 	 * XXX: see comment in driver - smb_usr.c
1672*4bff34e3Sthurlow 	 */
1673*4bff34e3Sthurlow 	failure = dgettext(TEXT_DOMAIN, "SPNEGO unsupported");
1674*4bff34e3Sthurlow 	if ((rq.ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC) == 0) {
1675*4bff34e3Sthurlow 		if (smb_verbose)
1676*4bff34e3Sthurlow 			smb_error(failure, 0);
1677*4bff34e3Sthurlow 		/*
1678*4bff34e3Sthurlow 		 * Do regular (old style) NTLM or NTLMv2
1679*4bff34e3Sthurlow 		 * Nothing more to do here in negotiate.
1680*4bff34e3Sthurlow 		 */
1681*4bff34e3Sthurlow 		return (0);
1682*4bff34e3Sthurlow 	}
1683*4bff34e3Sthurlow 
1684*4bff34e3Sthurlow 	/*
1685*4bff34e3Sthurlow 	 * Capabilities DO include SMB_CAP_EXT_SECURITY,
1686*4bff34e3Sthurlow 	 * so this should be an SPNEGO security blob.
1687*4bff34e3Sthurlow 	 * Parse the ASN.1/DER, prepare response(s).
1688*4bff34e3Sthurlow 	 * XXX: Handle STATUS_MORE_PROCESSING_REQUIRED?
1689*4bff34e3Sthurlow 	 * XXX: Requires additional session setup calls.
1690*4bff34e3Sthurlow 	 */
1691*4bff34e3Sthurlow 	if (rq.ioc_ssn.ioc_outtoklen <= SMB_GUIDLEN)
1692*4bff34e3Sthurlow 		goto out;
1693*4bff34e3Sthurlow 	/* some servers send padding junk */
1694*4bff34e3Sthurlow 	blob = rq.ioc_ssn.ioc_outtok;
1695*4bff34e3Sthurlow 	if (blob[0] == 0)
1696*4bff34e3Sthurlow 		goto out;
1697*4bff34e3Sthurlow 
1698*4bff34e3Sthurlow 	failure = smb_ctx_blob2principal(
1699*4bff34e3Sthurlow 	    ctx, &rq.ioc_ssn, &principal);
1700*4bff34e3Sthurlow 	if (failure)
1701*4bff34e3Sthurlow 		goto out;
1702*4bff34e3Sthurlow 	failure = smb_ctx_principal2blob(
1703*4bff34e3Sthurlow 	    ctx, &rq.ioc_ssn, principal);
1704*4bff34e3Sthurlow 	if (failure)
1705*4bff34e3Sthurlow 		goto out;
1706*4bff34e3Sthurlow 
1707*4bff34e3Sthurlow 	/* Success! Save the blob to send next. */
1708*4bff34e3Sthurlow 	ctx->ct_secblob = rq.ioc_ssn.ioc_intok;
1709*4bff34e3Sthurlow 	ctx->ct_secbloblen = rq.ioc_ssn.ioc_intoklen;
1710*4bff34e3Sthurlow 	rq.ioc_ssn.ioc_intok = NULL;
1711*4bff34e3Sthurlow 
1712*4bff34e3Sthurlow out:
1713*4bff34e3Sthurlow 	if (principal)
1714*4bff34e3Sthurlow 		free(principal);
1715*4bff34e3Sthurlow 	if (rq.ioc_ssn.ioc_intok)
1716*4bff34e3Sthurlow 		free(rq.ioc_ssn.ioc_intok);
1717*4bff34e3Sthurlow 	if (rq.ioc_ssn.ioc_outtok)
1718*4bff34e3Sthurlow 		free(rq.ioc_ssn.ioc_outtok);
1719*4bff34e3Sthurlow 	if (!failure)
1720*4bff34e3Sthurlow 		return (0);		/* Success! */
1721*4bff34e3Sthurlow 
1722*4bff34e3Sthurlow 	/*
1723*4bff34e3Sthurlow 	 * Negotiate failed with "extended security".
1724*4bff34e3Sthurlow 	 *
1725*4bff34e3Sthurlow 	 * XXX: If we are doing SPNEGO correctly,
1726*4bff34e3Sthurlow 	 * we should never get here unless the user
1727*4bff34e3Sthurlow 	 * supplied invalid authentication data,
1728*4bff34e3Sthurlow 	 * or we saw some kind of protocol error.
1729*4bff34e3Sthurlow 	 *
1730*4bff34e3Sthurlow 	 * XXX: The error message below should be
1731*4bff34e3Sthurlow 	 * XXX: unconditional (remove "if verbose")
1732*4bff34e3Sthurlow 	 * XXX: but not until we have "NTLMSSP"
1733*4bff34e3Sthurlow 	 * Avoid spew for anticipated failure modes
1734*4bff34e3Sthurlow 	 * but enable this with the verbose flag
1735*4bff34e3Sthurlow 	 */
1736*4bff34e3Sthurlow 	if (smb_verbose) {
1737*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1738*4bff34e3Sthurlow 		    "%s (extended security negotiate)"), error, failure);
1739*4bff34e3Sthurlow 	}
1740*4bff34e3Sthurlow 
1741*4bff34e3Sthurlow 	/*
1742*4bff34e3Sthurlow 	 * XXX: Try again using NTLM (or NTLMv2)
1743*4bff34e3Sthurlow 	 * XXX: Normal clients don't do this.
1744*4bff34e3Sthurlow 	 * XXX: Should just return an error, but
1745*4bff34e3Sthurlow 	 * keep the fall-back to NTLM for now.
1746*4bff34e3Sthurlow 	 *
1747*4bff34e3Sthurlow 	 * Start over with a new connection.
1748*4bff34e3Sthurlow 	 */
1749*4bff34e3Sthurlow 	if ((error = smb_ctx_gethandle(ctx)))
1750*4bff34e3Sthurlow 		return (error);
1751*4bff34e3Sthurlow 	bzero(&rq, sizeof (rq));
1752*4bff34e3Sthurlow 	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
1753*4bff34e3Sthurlow 	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
1754*4bff34e3Sthurlow 	rq.ioc_flags = flags;
1755*4bff34e3Sthurlow 	rq.ioc_level = level;
1756*4bff34e3Sthurlow 	/* Note: NO SMBVOPT_EXT_SEC */
1757*4bff34e3Sthurlow 	error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq);
1758*4bff34e3Sthurlow 	if (error) {
1759*4bff34e3Sthurlow 		failure = dgettext(TEXT_DOMAIN, "negotiate failed");
1760*4bff34e3Sthurlow 		smb_error(failure, error);
1761*4bff34e3Sthurlow 		rpc_cleanup_smbctx(ctx);
1762*4bff34e3Sthurlow 		close(ctx->ct_fd);
1763*4bff34e3Sthurlow 		ctx->ct_fd = -1;
1764*4bff34e3Sthurlow 		return (error);
1765*4bff34e3Sthurlow 	}
1766*4bff34e3Sthurlow 
1767*4bff34e3Sthurlow 	/*
1768*4bff34e3Sthurlow 	 * Used to copy the workgroup out of the SMB_NEGOTIATE response
1769*4bff34e3Sthurlow 	 * here, to default our domain name to be the same as the server.
1770*4bff34e3Sthurlow 	 * Not a good idea: Unnecessary at best, and sometimes wrong, i.e.
1771*4bff34e3Sthurlow 	 * when our account is in a trusted domain.
1772*4bff34e3Sthurlow 	 */
1773*4bff34e3Sthurlow 
1774*4bff34e3Sthurlow 	return (error);
1775*4bff34e3Sthurlow }
1776*4bff34e3Sthurlow 
1777*4bff34e3Sthurlow 
1778*4bff34e3Sthurlow int
1779*4bff34e3Sthurlow smb_ctx_tdis(struct smb_ctx *ctx)
1780*4bff34e3Sthurlow {
1781*4bff34e3Sthurlow 	struct smbioc_lookup rq; /* XXX may be used, someday */
1782*4bff34e3Sthurlow 	int error = 0;
1783*4bff34e3Sthurlow 
1784*4bff34e3Sthurlow 	if (ctx->ct_fd < 0) {
1785*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1786*4bff34e3Sthurlow 		    "tree disconnect without handle?!"), 0);
1787*4bff34e3Sthurlow 		return (EINVAL);
1788*4bff34e3Sthurlow 	}
1789*4bff34e3Sthurlow 	if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) {
1790*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1791*4bff34e3Sthurlow 		    "tree disconnect without session?!"), 0);
1792*4bff34e3Sthurlow 		return (EINVAL);
1793*4bff34e3Sthurlow 	}
1794*4bff34e3Sthurlow 	bzero(&rq, sizeof (rq));
1795*4bff34e3Sthurlow 	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
1796*4bff34e3Sthurlow 	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
1797*4bff34e3Sthurlow 	if (ioctl(ctx->ct_fd, SMBIOC_TDIS, &rq) == -1) {
1798*4bff34e3Sthurlow 		error = errno;
1799*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1800*4bff34e3Sthurlow 		    "tree disconnect failed"), error);
1801*4bff34e3Sthurlow 	}
1802*4bff34e3Sthurlow 	return (error);
1803*4bff34e3Sthurlow }
1804*4bff34e3Sthurlow 
1805*4bff34e3Sthurlow 
1806*4bff34e3Sthurlow int
1807*4bff34e3Sthurlow smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags)
1808*4bff34e3Sthurlow {
1809*4bff34e3Sthurlow 	struct smbioc_lookup rq;
1810*4bff34e3Sthurlow 	int error = 0;
1811*4bff34e3Sthurlow 	char 	*failure = NULL;
1812*4bff34e3Sthurlow 
1813*4bff34e3Sthurlow 	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
1814*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1815*4bff34e3Sthurlow 		    "smb_ctx_lookup() data is not resolved"), 0);
1816*4bff34e3Sthurlow 		return (EINVAL);
1817*4bff34e3Sthurlow 	}
1818*4bff34e3Sthurlow 	if (ctx->ct_fd < 0) {
1819*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1820*4bff34e3Sthurlow 		    "handle from smb_ctx_nego() gone?!"), 0);
1821*4bff34e3Sthurlow 		return (EINVAL);
1822*4bff34e3Sthurlow 	}
1823*4bff34e3Sthurlow 	if (!(flags & SMBLK_CREATE))
1824*4bff34e3Sthurlow 		return (0);
1825*4bff34e3Sthurlow 	bzero(&rq, sizeof (rq));
1826*4bff34e3Sthurlow 	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
1827*4bff34e3Sthurlow 	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
1828*4bff34e3Sthurlow 	rq.ioc_flags = flags;
1829*4bff34e3Sthurlow 	rq.ioc_level = level;
1830*4bff34e3Sthurlow 
1831*4bff34e3Sthurlow 	/*
1832*4bff34e3Sthurlow 	 * Iff we have a security blob, we're using
1833*4bff34e3Sthurlow 	 * extended security...
1834*4bff34e3Sthurlow 	 */
1835*4bff34e3Sthurlow 	if (ctx->ct_secblob) {
1836*4bff34e3Sthurlow 		rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC;
1837*4bff34e3Sthurlow 		if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) {
1838*4bff34e3Sthurlow 			rq.ioc_ssn.ioc_intok = ctx->ct_secblob;
1839*4bff34e3Sthurlow 			rq.ioc_ssn.ioc_intoklen = ctx->ct_secbloblen;
1840*4bff34e3Sthurlow 			error = smb_ctx_ioctl(ctx, SMBIOC_SSNSETUP, &rq);
1841*4bff34e3Sthurlow 		}
1842*4bff34e3Sthurlow 		rq.ioc_ssn.ioc_intok = NULL;
1843*4bff34e3Sthurlow 		if (error) {
1844*4bff34e3Sthurlow 			failure = dgettext(TEXT_DOMAIN,
1845*4bff34e3Sthurlow 			    "session setup failed");
1846*4bff34e3Sthurlow 		} else {
1847*4bff34e3Sthurlow 			ctx->ct_flags |= SMBCF_SSNACTIVE;
1848*4bff34e3Sthurlow 			if ((error = smb_ctx_ioctl(ctx, SMBIOC_TCON, &rq)))
1849*4bff34e3Sthurlow 				failure = dgettext(TEXT_DOMAIN,
1850*4bff34e3Sthurlow 				    "tree connect failed");
1851*4bff34e3Sthurlow 		}
1852*4bff34e3Sthurlow 		if (rq.ioc_ssn.ioc_intok)
1853*4bff34e3Sthurlow 			free(rq.ioc_ssn.ioc_intok);
1854*4bff34e3Sthurlow 		if (rq.ioc_ssn.ioc_outtok)
1855*4bff34e3Sthurlow 			free(rq.ioc_ssn.ioc_outtok);
1856*4bff34e3Sthurlow 		if (!failure)
1857*4bff34e3Sthurlow 			return (0);
1858*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1859*4bff34e3Sthurlow 		    "%s (extended security lookup2)"), error, failure);
1860*4bff34e3Sthurlow 		/* unwise to failback to NTLM now */
1861*4bff34e3Sthurlow 		return (error);
1862*4bff34e3Sthurlow 	}
1863*4bff34e3Sthurlow 
1864*4bff34e3Sthurlow 	/*
1865*4bff34e3Sthurlow 	 * Otherwise we're doing plain old NTLM
1866*4bff34e3Sthurlow 	 */
1867*4bff34e3Sthurlow 	seteuid(eff_uid); /* restore setuid root briefly */
1868*4bff34e3Sthurlow 	if ((ctx->ct_flags & SMBCF_SSNACTIVE) == 0) {
1869*4bff34e3Sthurlow 		/*
1870*4bff34e3Sthurlow 		 * This is the magic that tells the driver to
1871*4bff34e3Sthurlow 		 * copy the password from the keychain, and
1872*4bff34e3Sthurlow 		 * whether to use the system name or the
1873*4bff34e3Sthurlow 		 * account domain to lookup the keychain.
1874*4bff34e3Sthurlow 		 */
1875*4bff34e3Sthurlow 		if (ctx->ct_flags & SMBCF_KCFOUND)
1876*4bff34e3Sthurlow 			rq.ioc_ssn.ioc_opt |= SMBVOPT_USE_KEYCHAIN;
1877*4bff34e3Sthurlow 		if (ctx->ct_flags & SMBCF_KCDOMAIN)
1878*4bff34e3Sthurlow 			rq.ioc_ssn.ioc_opt |= SMBVOPT_KC_DOMAIN;
1879*4bff34e3Sthurlow 		if (ioctl(ctx->ct_fd, SMBIOC_SSNSETUP, &rq) < 0) {
1880*4bff34e3Sthurlow 			error = errno;
1881*4bff34e3Sthurlow 			failure = dgettext(TEXT_DOMAIN, "session setup");
1882*4bff34e3Sthurlow 			goto out;
1883*4bff34e3Sthurlow 		}
1884*4bff34e3Sthurlow 		ctx->ct_flags |= SMBCF_SSNACTIVE;
1885*4bff34e3Sthurlow 	}
1886*4bff34e3Sthurlow 	if (ioctl(ctx->ct_fd, SMBIOC_TCON, &rq) == -1) {
1887*4bff34e3Sthurlow 		error = errno;
1888*4bff34e3Sthurlow 		failure = dgettext(TEXT_DOMAIN, "tree connect");
1889*4bff34e3Sthurlow 	}
1890*4bff34e3Sthurlow 
1891*4bff34e3Sthurlow out:
1892*4bff34e3Sthurlow 	seteuid(real_uid); /* and back to real user */
1893*4bff34e3Sthurlow 	if (failure) {
1894*4bff34e3Sthurlow 		error = errno;
1895*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1896*4bff34e3Sthurlow 		    "%s phase failed"), error, failure);
1897*4bff34e3Sthurlow 	}
1898*4bff34e3Sthurlow 	return (error);
1899*4bff34e3Sthurlow }
1900*4bff34e3Sthurlow 
1901*4bff34e3Sthurlow /*
1902*4bff34e3Sthurlow  * Return the hflags2 word for an smb_ctx.
1903*4bff34e3Sthurlow  */
1904*4bff34e3Sthurlow int
1905*4bff34e3Sthurlow smb_ctx_flags2(struct smb_ctx *ctx)
1906*4bff34e3Sthurlow {
1907*4bff34e3Sthurlow 	uint16_t flags2;
1908*4bff34e3Sthurlow 
1909*4bff34e3Sthurlow 	if (ioctl(ctx->ct_fd, SMBIOC_FLAGS2, &flags2) == -1) {
1910*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
1911*4bff34e3Sthurlow 		    "can't get flags2 for a session"), errno);
1912*4bff34e3Sthurlow 		return (-1);
1913*4bff34e3Sthurlow 	}
1914*4bff34e3Sthurlow 	printf(dgettext(TEXT_DOMAIN, "Flags2 value is %d\n"), flags2);
1915*4bff34e3Sthurlow 	return (flags2);
1916*4bff34e3Sthurlow }
1917*4bff34e3Sthurlow 
1918*4bff34e3Sthurlow /*
1919*4bff34e3Sthurlow  * level values:
1920*4bff34e3Sthurlow  * 0 - default
1921*4bff34e3Sthurlow  * 1 - server
1922*4bff34e3Sthurlow  * 2 - server:user
1923*4bff34e3Sthurlow  * 3 - server:user:share
1924*4bff34e3Sthurlow  */
1925*4bff34e3Sthurlow static int
1926*4bff34e3Sthurlow smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
1927*4bff34e3Sthurlow {
1928*4bff34e3Sthurlow 	char *p;
1929*4bff34e3Sthurlow 	int error;
1930*4bff34e3Sthurlow 
1931*4bff34e3Sthurlow #ifdef NOT_DEFINED
1932*4bff34e3Sthurlow 	if (level > 0) {
1933*4bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "charsets", &p);
1934*4bff34e3Sthurlow 		if (p) {
1935*4bff34e3Sthurlow 			error = smb_ctx_setcharset(ctx, p);
1936*4bff34e3Sthurlow 			if (error)
1937*4bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
1938*4bff34e3Sthurlow 	"charset specification in the section '%s' ignored"),
1939*4bff34e3Sthurlow 				    error, sname);
1940*4bff34e3Sthurlow 		}
1941*4bff34e3Sthurlow 	}
1942*4bff34e3Sthurlow #endif
1943*4bff34e3Sthurlow 
1944*4bff34e3Sthurlow 	if (level <= 1) {
1945*4bff34e3Sthurlow 		/* Section is: [default] or [server] */
1946*4bff34e3Sthurlow 
1947*4bff34e3Sthurlow 		rc_getint(smb_rc, sname, "timeout",
1948*4bff34e3Sthurlow 		    &ctx->ct_ssn.ioc_timeout);
1949*4bff34e3Sthurlow 
1950*4bff34e3Sthurlow #ifdef NOT_DEFINED
1951*4bff34e3Sthurlow 		rc_getint(smb_rc, sname, "retry_count",
1952*4bff34e3Sthurlow 		    &ctx->ct_ssn.ioc_retrycount);
1953*4bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "use_negprot_domain", &p);
1954*4bff34e3Sthurlow 		if (p && strcmp(p, "NO") == 0)
1955*4bff34e3Sthurlow 			ctx->ct_flags |= SMBCF_NONEGDOM;
1956*4bff34e3Sthurlow #endif
1957*4bff34e3Sthurlow 
1958*4bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "minauth", &p);
1959*4bff34e3Sthurlow 		if (p) {
1960*4bff34e3Sthurlow 			/*
1961*4bff34e3Sthurlow 			 * "minauth" was set in this section; override
1962*4bff34e3Sthurlow 			 * the current minimum authentication setting.
1963*4bff34e3Sthurlow 			 */
1964*4bff34e3Sthurlow 			ctx->ct_ssn.ioc_opt &= ~SMBVOPT_MINAUTH;
1965*4bff34e3Sthurlow 			if (strcmp(p, "kerberos") == 0) {
1966*4bff34e3Sthurlow 				/*
1967*4bff34e3Sthurlow 				 * Don't fall back to NTLMv2, NTLMv1, or
1968*4bff34e3Sthurlow 				 * a clear text password.
1969*4bff34e3Sthurlow 				 */
1970*4bff34e3Sthurlow 				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_KERBEROS;
1971*4bff34e3Sthurlow 			} else if (strcmp(p, "ntlmv2") == 0) {
1972*4bff34e3Sthurlow 				/*
1973*4bff34e3Sthurlow 				 * Don't fall back to NTLMv1 or a clear
1974*4bff34e3Sthurlow 				 * text password.
1975*4bff34e3Sthurlow 				 */
1976*4bff34e3Sthurlow 				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLMV2;
1977*4bff34e3Sthurlow 			} else if (strcmp(p, "ntlm") == 0) {
1978*4bff34e3Sthurlow 				/*
1979*4bff34e3Sthurlow 				 * Don't send the LM response over the wire.
1980*4bff34e3Sthurlow 				 */
1981*4bff34e3Sthurlow 				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLM;
1982*4bff34e3Sthurlow 			} else if (strcmp(p, "lm") == 0) {
1983*4bff34e3Sthurlow 				/*
1984*4bff34e3Sthurlow 				 * Fail if the server doesn't do encrypted
1985*4bff34e3Sthurlow 				 * passwords.
1986*4bff34e3Sthurlow 				 */
1987*4bff34e3Sthurlow 				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_LM;
1988*4bff34e3Sthurlow 			} else if (strcmp(p, "none") == 0) {
1989*4bff34e3Sthurlow 				/*
1990*4bff34e3Sthurlow 				 * Anything goes.
1991*4bff34e3Sthurlow 				 * (The following statement should be
1992*4bff34e3Sthurlow 				 * optimized away.)
1993*4bff34e3Sthurlow 				 */
1994*4bff34e3Sthurlow 				/* LINTED */
1995*4bff34e3Sthurlow 				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NONE;
1996*4bff34e3Sthurlow 			} else {
1997*4bff34e3Sthurlow 				/*
1998*4bff34e3Sthurlow 				 * Unknown minimum authentication level.
1999*4bff34e3Sthurlow 				 */
2000*4bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
2001*4bff34e3Sthurlow "invalid minimum authentication level \"%s\" specified in the section %s"),
2002*4bff34e3Sthurlow 				    0, p, sname);
2003*4bff34e3Sthurlow 				return (EINVAL);
2004*4bff34e3Sthurlow 			}
2005*4bff34e3Sthurlow 		}
2006*4bff34e3Sthurlow 
2007*4bff34e3Sthurlow 		/*
2008*4bff34e3Sthurlow 		 * Domain name.  Allow both keywords:
2009*4bff34e3Sthurlow 		 * "workgroup", "domain"
2010*4bff34e3Sthurlow 		 *
2011*4bff34e3Sthurlow 		 * Note: these are NOT marked "from CMD".
2012*4bff34e3Sthurlow 		 * See long comment at smb_ctx_init()
2013*4bff34e3Sthurlow 		 */
2014*4bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "workgroup", &p);
2015*4bff34e3Sthurlow 		if (p) {
2016*4bff34e3Sthurlow 			nls_str_upper(p, p);
2017*4bff34e3Sthurlow 			error = smb_ctx_setworkgroup(ctx, p, 0);
2018*4bff34e3Sthurlow 			if (error)
2019*4bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
2020*4bff34e3Sthurlow 				    "workgroup specification in the "
2021*4bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
2022*4bff34e3Sthurlow 		}
2023*4bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "domain", &p);
2024*4bff34e3Sthurlow 		if (p) {
2025*4bff34e3Sthurlow 			nls_str_upper(p, p);
2026*4bff34e3Sthurlow 			error = smb_ctx_setworkgroup(ctx, p, 0);
2027*4bff34e3Sthurlow 			if (error)
2028*4bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
2029*4bff34e3Sthurlow 				    "domain specification in the "
2030*4bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
2031*4bff34e3Sthurlow 		}
2032*4bff34e3Sthurlow 
2033*4bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "user", &p);
2034*4bff34e3Sthurlow 		if (p) {
2035*4bff34e3Sthurlow 			error = smb_ctx_setuser(ctx, p, 0);
2036*4bff34e3Sthurlow 			if (error)
2037*4bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
2038*4bff34e3Sthurlow 				    "user specification in the "
2039*4bff34e3Sthurlow 				    "section '%s' ignored"), error, sname);
2040*4bff34e3Sthurlow 		}
2041*4bff34e3Sthurlow 	}
2042*4bff34e3Sthurlow 
2043*4bff34e3Sthurlow 	if (level == 1) {
2044*4bff34e3Sthurlow 		/* Section is: [server] */
2045*4bff34e3Sthurlow 		rc_getstringptr(smb_rc, sname, "addr", &p);
2046*4bff34e3Sthurlow 		if (p) {
2047*4bff34e3Sthurlow 			error = smb_ctx_setsrvaddr(ctx, p);
2048*4bff34e3Sthurlow 			if (error) {
2049*4bff34e3Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
2050*4bff34e3Sthurlow 				    "invalid address specified in section %s"),
2051*4bff34e3Sthurlow 				    0, sname);
2052*4bff34e3Sthurlow 				return (error);
2053*4bff34e3Sthurlow 			}
2054*4bff34e3Sthurlow 		}
2055*4bff34e3Sthurlow 	}
2056*4bff34e3Sthurlow 
2057*4bff34e3Sthurlow 	rc_getstringptr(smb_rc, sname, "password", &p);
2058*4bff34e3Sthurlow 	if (p) {
2059*4bff34e3Sthurlow 		error = smb_ctx_setpassword(ctx, p, 0);
2060*4bff34e3Sthurlow 		if (error)
2061*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
2062*4bff34e3Sthurlow 	    "password specification in the section '%s' ignored"),
2063*4bff34e3Sthurlow 			    error, sname);
2064*4bff34e3Sthurlow 	}
2065*4bff34e3Sthurlow 
2066*4bff34e3Sthurlow 	return (0);
2067*4bff34e3Sthurlow }
2068*4bff34e3Sthurlow 
2069*4bff34e3Sthurlow /*
2070*4bff34e3Sthurlow  * read rc file as follows:
2071*4bff34e3Sthurlow  * 0: read [default] section
2072*4bff34e3Sthurlow  * 1: override with [server] section
2073*4bff34e3Sthurlow  * 2: override with [server:user] section
2074*4bff34e3Sthurlow  * 3: override with [server:user:share] section
2075*4bff34e3Sthurlow  * Since absence of rcfile is not fatal, silently ignore this fact.
2076*4bff34e3Sthurlow  * smb_rc file should be closed by caller.
2077*4bff34e3Sthurlow  */
2078*4bff34e3Sthurlow int
2079*4bff34e3Sthurlow smb_ctx_readrc(struct smb_ctx *ctx)
2080*4bff34e3Sthurlow {
2081*4bff34e3Sthurlow 	char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN +
2082*4bff34e3Sthurlow 	    SMB_MAXSHARENAMELEN + 4];
2083*4bff34e3Sthurlow 
2084*4bff34e3Sthurlow 	if (smb_open_rcfile(ctx) != 0)
2085*4bff34e3Sthurlow 		goto done;
2086*4bff34e3Sthurlow 
2087*4bff34e3Sthurlow 	/*
2088*4bff34e3Sthurlow 	 * default parameters (level=0)
2089*4bff34e3Sthurlow 	 */
2090*4bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, "default", 0);
2091*4bff34e3Sthurlow 	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
2092*4bff34e3Sthurlow 
2093*4bff34e3Sthurlow 	/*
2094*4bff34e3Sthurlow 	 * If we don't have a server name, we can't read any of the
2095*4bff34e3Sthurlow 	 * [server...] sections.
2096*4bff34e3Sthurlow 	 */
2097*4bff34e3Sthurlow 	if (ctx->ct_ssn.ioc_srvname[0] == 0)
2098*4bff34e3Sthurlow 		goto done;
2099*4bff34e3Sthurlow 
2100*4bff34e3Sthurlow 	/*
2101*4bff34e3Sthurlow 	 * SERVER parameters.
2102*4bff34e3Sthurlow 	 */
2103*4bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1);
2104*4bff34e3Sthurlow 
2105*4bff34e3Sthurlow 	/*
2106*4bff34e3Sthurlow 	 * If we don't have a user name, we can't read any of the
2107*4bff34e3Sthurlow 	 * [server:user...] sections.
2108*4bff34e3Sthurlow 	 */
2109*4bff34e3Sthurlow 	if (ctx->ct_ssn.ioc_user[0] == 0)
2110*4bff34e3Sthurlow 		goto done;
2111*4bff34e3Sthurlow 
2112*4bff34e3Sthurlow 	/*
2113*4bff34e3Sthurlow 	 * SERVER:USER parameters
2114*4bff34e3Sthurlow 	 */
2115*4bff34e3Sthurlow 	snprintf(sname, sizeof (sname), "%s:%s",
2116*4bff34e3Sthurlow 	    ctx->ct_ssn.ioc_srvname,
2117*4bff34e3Sthurlow 	    ctx->ct_ssn.ioc_user);
2118*4bff34e3Sthurlow 	smb_ctx_readrcsection(ctx, sname, 2);
2119*4bff34e3Sthurlow 
2120*4bff34e3Sthurlow 	/*
2121*4bff34e3Sthurlow 	 * If we don't have a share name, we can't read any of the
2122*4bff34e3Sthurlow 	 * [server:user:share] sections.
2123*4bff34e3Sthurlow 	 */
2124*4bff34e3Sthurlow 	if (ctx->ct_sh.ioc_share[0] != 0) {
2125*4bff34e3Sthurlow 		/*
2126*4bff34e3Sthurlow 		 * SERVER:USER:SHARE parameters
2127*4bff34e3Sthurlow 		 */
2128*4bff34e3Sthurlow 		snprintf(sname, sizeof (sname), "%s:%s:%s",
2129*4bff34e3Sthurlow 		    ctx->ct_ssn.ioc_srvname,
2130*4bff34e3Sthurlow 		    ctx->ct_ssn.ioc_user,
2131*4bff34e3Sthurlow 		    ctx->ct_sh.ioc_share);
2132*4bff34e3Sthurlow 		smb_ctx_readrcsection(ctx, sname, 3);
2133*4bff34e3Sthurlow 	}
2134*4bff34e3Sthurlow 
2135*4bff34e3Sthurlow done:
2136*4bff34e3Sthurlow 	if (smb_debug)
2137*4bff34e3Sthurlow 		dump_ctx("after smb_ctx_readrc", ctx);
2138*4bff34e3Sthurlow 
2139*4bff34e3Sthurlow 	return (0);
2140*4bff34e3Sthurlow }
2141