xref: /illumos-gate/usr/src/lib/libsmbfs/smb/ctx.c (revision aedf2b3bb56b025fcaf87b49ec6c8aeea07f16d7)
1 /*
2  * Copyright (c) 2000, Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $
33  */
34 
35 /*
36  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37  * Use is subject to license terms.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/ioctl.h>
42 #include <sys/time.h>
43 #include <sys/mount.h>
44 #include <sys/types.h>
45 #include <sys/byteorder.h>
46 
47 #include <fcntl.h>
48 #include <ctype.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <strings.h>
53 #include <stdlib.h>
54 #include <pwd.h>
55 #include <grp.h>
56 #include <unistd.h>
57 #include <libintl.h>
58 #include <assert.h>
59 #include <nss_dbdefs.h>
60 
61 #include <cflib.h>
62 #include <netsmb/smb_lib.h>
63 #include <netsmb/netbios.h>
64 #include <netsmb/nb_lib.h>
65 #include <netsmb/smb_dev.h>
66 
67 #include "charsets.h"
68 #include "spnego.h"
69 #include "derparse.h"
70 #include "private.h"
71 #include "ntlm.h"
72 
73 #ifndef FALSE
74 #define	FALSE	0
75 #endif
76 #ifndef TRUE
77 #define	TRUE	1
78 #endif
79 
80 
81 /* These two may be set by commands. */
82 int smb_debug, smb_verbose;
83 
84 /*
85  * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
86  */
87 const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
88 
89 /*
90  * Give the RPC library a callback hook that will be
91  * called whenever we destroy or reinit an smb_ctx_t.
92  * The name rpc_cleanup_smbctx() is legacy, and was
93  * originally a direct call into the RPC code.
94  */
95 static smb_ctx_close_hook_t close_hook;
96 static void
97 rpc_cleanup_smbctx(struct smb_ctx *ctx)
98 {
99 	if (close_hook)
100 		(*close_hook)(ctx);
101 }
102 void
103 smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
104 {
105 	close_hook = hook;
106 }
107 
108 void
109 dump_ctx_flags(int flags)
110 {
111 	printf(" Flags: ");
112 	if (flags == 0)
113 		printf("0");
114 	if (flags & SMBCF_NOPWD)
115 		printf("NOPWD ");
116 	if (flags & SMBCF_SRIGHTS)
117 		printf("SRIGHTS ");
118 	if (flags & SMBCF_LOCALE)
119 		printf("LOCALE ");
120 	if (flags & SMBCF_CMD_DOM)
121 		printf("CMD_DOM ");
122 	if (flags & SMBCF_CMD_USR)
123 		printf("CMD_USR ");
124 	if (flags & SMBCF_CMD_PW)
125 		printf("CMD_PW ");
126 	if (flags & SMBCF_RESOLVED)
127 		printf("RESOLVED ");
128 	if (flags & SMBCF_KCBAD)
129 		printf("KCBAD ");
130 	if (flags & SMBCF_KCFOUND)
131 		printf("KCFOUND ");
132 	if (flags & SMBCF_BROWSEOK)
133 		printf("BROWSEOK ");
134 	if (flags & SMBCF_AUTHREQ)
135 		printf("AUTHREQ ");
136 	if (flags & SMBCF_KCSAVE)
137 		printf("KCSAVE  ");
138 	if (flags & SMBCF_XXX)
139 		printf("XXX ");
140 	if (flags & SMBCF_SSNACTIVE)
141 		printf("SSNACTIVE ");
142 	if (flags & SMBCF_KCDOMAIN)
143 		printf("KCDOMAIN ");
144 	printf("\n");
145 }
146 
147 void
148 dump_iod_ssn(smb_iod_ssn_t *is)
149 {
150 	static const char zeros[NTLM_HASH_SZ] = {0};
151 	struct smbioc_ossn *ssn = &is->iod_ossn;
152 
153 	printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
154 	dump_sockaddr(&ssn->ssn_srvaddr.sa);
155 	printf(" dom=\"%s\", user=\"%s\"\n",
156 	    ssn->ssn_domain, ssn->ssn_user);
157 	printf(" ct_vopt=0x%x, ct_owner=%d\n",
158 	    ssn->ssn_vopt, ssn->ssn_owner);
159 	printf(" ct_authflags=0x%x\n", is->iod_authflags);
160 
161 	printf(" ct_nthash:");
162 	if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
163 		smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
164 	else
165 		printf(" {0}\n");
166 
167 	printf(" ct_lmhash:");
168 	if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
169 		smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
170 	else
171 		printf(" {0}\n");
172 }
173 
174 void
175 dump_ctx(char *where, struct smb_ctx *ctx)
176 {
177 	printf("context %s:\n", where);
178 	dump_ctx_flags(ctx->ct_flags);
179 
180 	if (ctx->ct_locname)
181 		printf(" localname=\"%s\"", ctx->ct_locname);
182 	else
183 		printf(" localname=NULL");
184 
185 	if (ctx->ct_fullserver)
186 		printf(" fullserver=\"%s\"", ctx->ct_fullserver);
187 	else
188 		printf(" fullserver=NULL");
189 
190 	if (ctx->ct_srvaddr_s)
191 		printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
192 	else
193 		printf(" srvaddr_s=NULL\n");
194 
195 	if (ctx->ct_addrinfo)
196 		dump_addrinfo(ctx->ct_addrinfo);
197 	else
198 		printf(" ct_addrinfo = NULL\n");
199 
200 	dump_iod_ssn(&ctx->ct_iod_ssn);
201 
202 	printf(" share_name=\"%s\", share_type=%d\n",
203 	    ctx->ct_origshare ? ctx->ct_origshare : "",
204 	    ctx->ct_shtype_req);
205 
206 	/* dump_iod_work()? */
207 }
208 
209 int
210 smb_ctx_alloc(struct smb_ctx **ctx_pp)
211 {
212 	smb_ctx_t *ctx;
213 	int err;
214 
215 	ctx = malloc(sizeof (*ctx));
216 	if (ctx == NULL)
217 		return (ENOMEM);
218 	err = smb_ctx_init(ctx);
219 	if (err != 0) {
220 		free(ctx);
221 		return (err);
222 	}
223 	*ctx_pp = ctx;
224 	return (0);
225 }
226 
227 /*
228  * Initialize an smb_ctx struct (defaults)
229  */
230 int
231 smb_ctx_init(struct smb_ctx *ctx)
232 {
233 	char pwbuf[NSS_BUFLEN_PASSWD];
234 	struct passwd pw;
235 	int error = 0;
236 
237 	bzero(ctx, sizeof (*ctx));
238 
239 	error = nb_ctx_create(&ctx->ct_nb);
240 	if (error)
241 		return (error);
242 
243 	ctx->ct_dev_fd = -1;
244 	ctx->ct_door_fd = -1;
245 	ctx->ct_tran_fd = -1;
246 	ctx->ct_parsedlevel = SMBL_NONE;
247 	ctx->ct_minlevel = SMBL_NONE;
248 	ctx->ct_maxlevel = SMBL_PATH;
249 
250 	/* Fill in defaults */
251 	ctx->ct_vopt = SMBVOPT_EXT_SEC;
252 	ctx->ct_owner = SMBM_ANY_OWNER;
253 	ctx->ct_authflags = SMB_AT_DEFAULT;
254 	ctx->ct_minauth = SMB_AT_DEFAULT;
255 
256 	nb_ctx_setscope(ctx->ct_nb, "");
257 
258 	/*
259 	 * if the user name is not specified some other way,
260 	 * use the current user name (built-in default)
261 	 */
262 	if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
263 		smb_ctx_setuser(ctx, pw.pw_name, 0);
264 		ctx->ct_home = strdup(pw.pw_name);
265 	}
266 
267 	/*
268 	 * Set a built-in default domain (workgroup).
269 	 * Using the Windows/NT default for now.
270 	 */
271 	smb_ctx_setdomain(ctx, "WORKGROUP", 0);
272 
273 	return (error);
274 }
275 
276 /*
277  * "Scan" the command line args to find the server name,
278  * user name, and share name, as needed.  We need these
279  * before reading the RC files and/or sharectl values.
280  *
281  * The sequence for getting all the members filled in
282  * has some tricky aspects.  Here's how it works:
283  *
284  * The search order for options is as follows:
285  *   command line options
286  *   values parsed from UNC path (cmd)
287  *   values from RC file (per-user)
288  *   values from SMF (system-wide)
289  *   built-in defaults
290  *
291  * Normally, one would simply get all the values starting with
292  * the bottom of the above list and working to the top, and
293  * overwriting values as you go.  But we need an exception.
294  *
295  * In this function, we parse the UNC path and command line options,
296  * because we need (at least) the server name when we're getting the
297  * SMF and RC file values.  However, values we get from the command
298  * should not be overwritten by SMF or RC file parsing, so we mark
299  * values from the command as "from CMD" and the RC file parser
300  * leaves in place any values so marked.  See: SMBCF_CMD_*
301  *
302  * The semantics of these flags are: "This value came from the
303  * current command instance, not from sources that may apply to
304  * multiple commands."  (Different from the old "FROMUSR" flag.)
305  *
306  * Note that smb_ctx_opt() is called later to handle the
307  * remaining options, which should be ignored here.
308  * The (magic) leading ":" in cf_getopt() makes it
309  * ignore options not in the options string.
310  */
311 int
312 smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
313 	int minlevel, int maxlevel, int sharetype)
314 {
315 	int  ind, opt, error = 0;
316 	int aflg = 0, uflg = 0;
317 	const char *arg;
318 
319 	/*
320 	 * Parse options, if any.  Values from here too
321 	 * are marked as "from CMD".
322 	 */
323 	if (argv == NULL)
324 		return (0);
325 
326 	ctx->ct_minlevel = minlevel;
327 	ctx->ct_maxlevel = maxlevel;
328 	ctx->ct_shtype_req = sharetype;
329 
330 	cf_opt_lock();
331 	/* Careful: no return/goto before cf_opt_unlock! */
332 	while (error == 0) {
333 		opt = cf_getopt(argc, argv, STDPARAM_OPT);
334 		if (opt == -1)
335 			break;
336 		arg = cf_optarg;
337 		/* NB: handle most in smb_ctx_opt */
338 		switch (opt) {
339 		case 'A':
340 			aflg = 1;
341 			error = smb_ctx_setuser(ctx, "", TRUE);
342 			ctx->ct_flags |= SMBCF_NOPWD;
343 			break;
344 		case 'U':
345 			uflg = 1;
346 			error = smb_ctx_setuser(ctx, arg, TRUE);
347 			break;
348 		default:
349 			DPRINT("skip opt=%c", opt);
350 			break;
351 		}
352 	}
353 	ind = cf_optind;
354 	arg = argv[ind];
355 	cf_optind = cf_optreset = 1;
356 	cf_opt_unlock();
357 
358 	if (error)
359 		return (error);
360 
361 	if (aflg && uflg)  {
362 		printf(gettext("-A and -U flags are exclusive.\n"));
363 		return (EINVAL);
364 	}
365 
366 	/*
367 	 * Parse the UNC path.  Values from here are
368 	 * marked as "from CMD".
369 	 */
370 	for (; ind < argc; ind++) {
371 		arg = argv[ind];
372 		if (strncmp(arg, "//", 2) != 0)
373 			continue;
374 		error = smb_ctx_parseunc(ctx, arg,
375 		    minlevel, maxlevel, sharetype, &arg);
376 		if (error)
377 			return (error);
378 		break;
379 	}
380 
381 	return (error);
382 }
383 
384 void
385 smb_ctx_free(smb_ctx_t *ctx)
386 {
387 	smb_ctx_done(ctx);
388 	free(ctx);
389 }
390 
391 void
392 smb_ctx_done(struct smb_ctx *ctx)
393 {
394 
395 	rpc_cleanup_smbctx(ctx);
396 
397 	if (ctx->ct_dev_fd != -1) {
398 		close(ctx->ct_dev_fd);
399 		ctx->ct_dev_fd = -1;
400 	}
401 	if (ctx->ct_door_fd != -1) {
402 		close(ctx->ct_door_fd);
403 		ctx->ct_door_fd = -1;
404 	}
405 	if (ctx->ct_tran_fd != -1) {
406 		close(ctx->ct_tran_fd);
407 		ctx->ct_tran_fd = -1;
408 	}
409 	if (ctx->ct_srvaddr_s) {
410 		free(ctx->ct_srvaddr_s);
411 		ctx->ct_srvaddr_s = NULL;
412 	}
413 	if (ctx->ct_nb) {
414 		nb_ctx_done(ctx->ct_nb);
415 		ctx->ct_nb = NULL;
416 	}
417 	if (ctx->ct_locname) {
418 		free(ctx->ct_locname);
419 		ctx->ct_locname = NULL;
420 	}
421 	if (ctx->ct_origshare) {
422 		free(ctx->ct_origshare);
423 		ctx->ct_origshare = NULL;
424 	}
425 	if (ctx->ct_fullserver) {
426 		free(ctx->ct_fullserver);
427 		ctx->ct_fullserver = NULL;
428 	}
429 	if (ctx->ct_addrinfo) {
430 		freeaddrinfo(ctx->ct_addrinfo);
431 		ctx->ct_addrinfo = NULL;
432 	}
433 	if (ctx->ct_home)
434 		free(ctx->ct_home);
435 	if (ctx->ct_srv_OS) {
436 		free(ctx->ct_srv_OS);
437 		ctx->ct_srv_OS = NULL;
438 	}
439 	if (ctx->ct_srv_LM) {
440 		free(ctx->ct_srv_LM);
441 		ctx->ct_srv_LM = NULL;
442 	}
443 	if (ctx->ct_mackey) {
444 		free(ctx->ct_mackey);
445 		ctx->ct_mackey = NULL;
446 	}
447 }
448 
449 static int
450 getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
451     const char **next)
452 {
453 	int len;
454 
455 	maxlen--;
456 	for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
457 		if (*p == 0)
458 			return (EINVAL);
459 		*dest = *p;
460 	}
461 	*dest = 0;
462 	*next = *p ? p + 1 : p;
463 	return (0);
464 }
465 
466 /*
467  * Parse the UNC path.  Here we expect something like
468  *   "//[workgroup;][user[:password]@]host[/share[/path]]"
469  * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
470  * Values found here are marked as "from CMD".
471  */
472 int
473 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
474 	int minlevel, int maxlevel, int sharetype,
475 	const char **next)
476 {
477 	const char *p = unc;
478 	char *p1, *colon;
479 	char tmp[1024];
480 	char tmp2[1024];
481 	int error;
482 
483 	/*
484 	 * This may be called outside of _scan_argv,
485 	 * so make sure these get initialized.
486 	 */
487 	ctx->ct_minlevel = minlevel;
488 	ctx->ct_maxlevel = maxlevel;
489 	ctx->ct_shtype_req = sharetype;
490 
491 	ctx->ct_parsedlevel = SMBL_NONE;
492 	if (*p++ != '/' || *p++ != '/') {
493 		smb_error(dgettext(TEXT_DOMAIN,
494 		    "UNC should start with '//'"), 0);
495 		error = EINVAL;
496 		goto out;
497 	}
498 	p1 = tmp;
499 	error = getsubstring(p, ';', p1, sizeof (tmp), &p);
500 	if (!error) {
501 		if (*p1 == 0) {
502 			smb_error(dgettext(TEXT_DOMAIN,
503 			    "empty workgroup name"), 0);
504 			error = EINVAL;
505 			goto out;
506 		}
507 		nls_str_upper(tmp, tmp);
508 		error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE);
509 		if (error)
510 			goto out;
511 	}
512 	colon = (char *)p;
513 	error = getsubstring(p, '@', p1, sizeof (tmp), &p);
514 	if (!error) {
515 		if (ctx->ct_maxlevel < SMBL_VC) {
516 			smb_error(dgettext(TEXT_DOMAIN,
517 			    "no user name required"), 0);
518 			error = EINVAL;
519 			goto out;
520 		}
521 		p1 = strchr(tmp, ':');
522 		if (p1) {
523 			colon += p1 - tmp;
524 			*p1++ = (char)0;
525 			error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
526 			if (error)
527 				goto out;
528 			if (p - colon > 2)
529 				memset(colon+1, '*', p - colon - 2);
530 		}
531 		p1 = tmp;
532 		if (*p1 == 0) {
533 			smb_error(dgettext(TEXT_DOMAIN,
534 			    "empty user name"), 0);
535 			error = EINVAL;
536 			goto out;
537 		}
538 		error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
539 		if (error)
540 			goto out;
541 		ctx->ct_parsedlevel = SMBL_VC;
542 	}
543 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
544 	if (error) {
545 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
546 		if (error) {
547 			smb_error(dgettext(TEXT_DOMAIN,
548 			    "no server name found"), 0);
549 			goto out;
550 		}
551 	}
552 	if (*p1 == 0) {
553 		smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
554 		error = EINVAL;
555 		goto out;
556 	}
557 
558 	/*
559 	 * It's safe to uppercase this string, which
560 	 * consists of ascii characters that should
561 	 * be uppercased, %s, and ascii characters representing
562 	 * hex digits 0-9 and A-F (already uppercased, and
563 	 * if not uppercased they need to be). However,
564 	 * it is NOT safe to uppercase after it has been
565 	 * "unpercent" converted, below!
566 	 */
567 	nls_str_upper(tmp2, tmp);
568 
569 	/*
570 	 * Save ct_fullserver without case conversion.
571 	 */
572 	if (strchr(tmp, '%'))
573 		(void) unpercent(tmp);
574 	smb_ctx_setfullserver(ctx, tmp);
575 	if (error)
576 		goto out;
577 
578 #ifdef	SMB_ST_NONE
579 	if (sharetype == SMB_ST_NONE) {
580 		if (next)
581 			*next = p;
582 		error = 0;
583 		goto out;
584 	}
585 #endif
586 
587 	if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
588 		smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
589 		error = EINVAL;
590 		goto out;
591 	}
592 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
593 	if (error) {
594 		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
595 		if (error) {
596 			smb_error(dgettext(TEXT_DOMAIN,
597 			    "unexpected end of line"), 0);
598 			goto out;
599 		}
600 	}
601 	if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
602 	    !(ctx->ct_flags & SMBCF_BROWSEOK)) {
603 		smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
604 		error = EINVAL;
605 		goto out;
606 	}
607 	if (next)
608 		*next = p;
609 	if (*p1 == 0) {
610 		error = 0;
611 		goto out;
612 	}
613 	error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
614 
615 out:
616 	if (error == 0 && smb_debug > 0)
617 		dump_ctx("after smb_ctx_parseunc", ctx);
618 
619 	return (error);
620 }
621 
622 #ifdef KICONV_SUPPORT
623 int
624 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
625 {
626 	char *cp, *servercs, *localcs;
627 	int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
628 	int scslen, lcslen, error;
629 
630 	cp = strchr(arg, ':');
631 	lcslen = cp ? (cp - arg) : 0;
632 	if (lcslen == 0 || lcslen >= cslen) {
633 		smb_error(dgettext(TEXT_DOMAIN,
634 		    "invalid local charset specification (%s)"), 0, arg);
635 		return (EINVAL);
636 	}
637 	scslen = (size_t)strlen(++cp);
638 	if (scslen == 0 || scslen >= cslen) {
639 		smb_error(dgettext(TEXT_DOMAIN,
640 		    "invalid server charset specification (%s)"), 0, arg);
641 		return (EINVAL);
642 	}
643 	localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
644 	localcs[lcslen] = 0;
645 	servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
646 	error = nls_setrecode(localcs, servercs);
647 	if (error == 0)
648 		return (0);
649 	smb_error(dgettext(TEXT_DOMAIN,
650 	    "can't initialize iconv support (%s:%s)"),
651 	    error, localcs, servercs);
652 	localcs[0] = 0;
653 	servercs[0] = 0;
654 	return (error);
655 }
656 #endif /* KICONV_SUPPORT */
657 
658 int
659 smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
660 {
661 	ctx->ct_authflags = flags;
662 	return (0);
663 }
664 
665 int
666 smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
667 {
668 	char *p = strdup(name);
669 
670 	if (p == NULL)
671 		return (ENOMEM);
672 	if (ctx->ct_fullserver)
673 		free(ctx->ct_fullserver);
674 	ctx->ct_fullserver = p;
675 	return (0);
676 }
677 
678 /* this routine does not uppercase the server name */
679 int
680 smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
681 {
682 	/* don't uppercase the server name */
683 	strlcpy(ctx->ct_srvname, name,
684 	    sizeof (ctx->ct_srvname));
685 	return (0);
686 }
687 
688 int
689 smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
690 {
691 
692 	if (strlen(name) >= sizeof (ctx->ct_user)) {
693 		smb_error(dgettext(TEXT_DOMAIN,
694 		    "user name '%s' too long"), 0, name);
695 		return (ENAMETOOLONG);
696 	}
697 
698 	/*
699 	 * Don't overwrite a value from the command line
700 	 * with one from anywhere else.
701 	 */
702 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
703 		return (0);
704 
705 	/* don't uppercase the username, just copy it. */
706 	strlcpy(ctx->ct_user, name,
707 	    sizeof (ctx->ct_user));
708 
709 	/* Mark this as "from the command line". */
710 	if (from_cmd)
711 		ctx->ct_flags |= SMBCF_CMD_USR;
712 
713 	return (0);
714 }
715 
716 /*
717  * Never uppercase the workgroup
718  * name here, because it might come
719  * from a Windows codepage encoding.
720  *
721  * Don't overwrite a domain name from the
722  * command line with one from anywhere else.
723  * See smb_ctx_init() for notes about this.
724  */
725 int
726 smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd)
727 {
728 
729 	if (strlen(name) >= sizeof (ctx->ct_domain)) {
730 		smb_error(dgettext(TEXT_DOMAIN,
731 		    "workgroup name '%s' too long"), 0, name);
732 		return (ENAMETOOLONG);
733 	}
734 
735 	/*
736 	 * Don't overwrite a value from the command line
737 	 * with one from anywhere else.
738 	 */
739 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
740 		return (0);
741 
742 	strlcpy(ctx->ct_domain, name,
743 	    sizeof (ctx->ct_domain));
744 
745 	/* Mark this as "from the command line". */
746 	if (from_cmd)
747 		ctx->ct_flags |= SMBCF_CMD_DOM;
748 
749 	return (0);
750 }
751 
752 int
753 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
754 {
755 	int err;
756 
757 	if (passwd == NULL)
758 		return (EINVAL);
759 	if (strlen(passwd) >= sizeof (ctx->ct_password)) {
760 		smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
761 		return (ENAMETOOLONG);
762 	}
763 
764 	/*
765 	 * If called again after comand line parsing,
766 	 * don't overwrite a value from the command line
767 	 * with one from any stored config.
768 	 */
769 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
770 		return (0);
771 
772 	memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
773 	if (strncmp(passwd, "$$1", 3) == 0)
774 		smb_simpledecrypt(ctx->ct_password, passwd);
775 	else
776 		strlcpy(ctx->ct_password, passwd,
777 		    sizeof (ctx->ct_password));
778 
779 	/*
780 	 * Compute LM hash, NT hash.
781 	 */
782 	if (ctx->ct_password[0]) {
783 		err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
784 		if (err != 0)
785 			return (err);
786 		err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
787 		if (err != 0)
788 			return (err);
789 	}
790 
791 	/* Mark this as "from the command line". */
792 	if (from_cmd)
793 		ctx->ct_flags |= SMBCF_CMD_PW;
794 
795 	return (0);
796 }
797 
798 /*
799  * Use this to set NTLM auth. info (hashes)
800  * when we don't have the password.
801  */
802 int
803 smb_ctx_setpwhash(smb_ctx_t *ctx,
804     const uchar_t *nthash, const uchar_t *lmhash)
805 {
806 
807 	/* Need ct_password to be non-null. */
808 	if (ctx->ct_password[0] == '\0')
809 		strlcpy(ctx->ct_password, "$HASH",
810 		    sizeof (ctx->ct_password));
811 
812 	/*
813 	 * Compute LM hash, NT hash.
814 	 */
815 	memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
816 
817 	/* The LM hash is optional */
818 	if (lmhash) {
819 		memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
820 	}
821 
822 	return (0);
823 }
824 
825 int
826 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
827 {
828 	if (strlen(share) >= SMBIOC_MAX_NAME) {
829 		smb_error(dgettext(TEXT_DOMAIN,
830 		    "share name '%s' too long"), 0, share);
831 		return (ENAMETOOLONG);
832 	}
833 	if (ctx->ct_origshare)
834 		free(ctx->ct_origshare);
835 	if ((ctx->ct_origshare = strdup(share)) == NULL)
836 		return (ENOMEM);
837 
838 	ctx->ct_shtype_req = stype;
839 
840 	return (0);
841 }
842 
843 int
844 smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
845 {
846 	if (addr == NULL || addr[0] == 0)
847 		return (EINVAL);
848 	if (ctx->ct_srvaddr_s)
849 		free(ctx->ct_srvaddr_s);
850 	if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL)
851 		return (ENOMEM);
852 	return (0);
853 }
854 
855 /*
856  * API for library caller to set signing enabled, required
857  * Note: if not enable, ignore require
858  */
859 int
860 smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
861 {
862 	ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
863 	if (enable) {
864 		ctx->ct_vopt |=	SMBVOPT_SIGNING_ENABLED;
865 		if (require)
866 			ctx->ct_vopt |=	SMBVOPT_SIGNING_REQUIRED;
867 	}
868 	return (0);
869 }
870 
871 static int
872 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
873 {
874 	struct group gr;
875 	struct passwd pw;
876 	char buf[NSS_BUFLEN_PASSWD];
877 	char *cp;
878 
879 	cp = strchr(pair, ':');
880 	if (cp) {
881 		*cp++ = '\0';
882 		if (*cp && gid) {
883 			if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
884 				*gid = gr.gr_gid;
885 			} else
886 				smb_error(dgettext(TEXT_DOMAIN,
887 				    "Invalid group name %s, ignored"), 0, cp);
888 		}
889 	}
890 	if (*pair) {
891 		if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
892 			*uid = pw.pw_uid;
893 		} else
894 			smb_error(dgettext(TEXT_DOMAIN,
895 			    "Invalid user name %s, ignored"), 0, pair);
896 	}
897 
898 	return (0);
899 }
900 
901 /*
902  * Commands use this with getopt.  See:
903  *   STDPARAM_OPT, STDPARAM_ARGS
904  * Called after smb_ctx_readrc().
905  */
906 int
907 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
908 {
909 	int error = 0;
910 	char *p, *cp;
911 	char tmp[1024];
912 
913 	switch (opt) {
914 	case 'A':
915 	case 'U':
916 		/* Handled in smb_ctx_init() */
917 		break;
918 	case 'I':
919 		error = smb_ctx_setsrvaddr(ctx, arg);
920 		break;
921 	case 'M':
922 		/* share connect rights - ignored */
923 		ctx->ct_flags |= SMBCF_SRIGHTS;
924 		break;
925 	case 'N':
926 		ctx->ct_flags |= SMBCF_NOPWD;
927 		break;
928 	case 'O':
929 		p = strdup(arg);
930 		cp = strchr(p, '/');
931 		if (cp)
932 			*cp = '\0';
933 		error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
934 		free(p);
935 		break;
936 	case 'P':
937 /*		ctx->ct_vopt |= SMBCOPT_PERMANENT; */
938 		break;
939 	case 'R':
940 		/* retry count - ignored */
941 		break;
942 	case 'T':
943 		/* timeout - ignored */
944 		break;
945 	case 'D':	/* domain */
946 	case 'W':	/* workgroup (legacy alias) */
947 		nls_str_upper(tmp, arg);
948 		error = smb_ctx_setdomain(ctx, tmp, TRUE);
949 		break;
950 	}
951 	return (error);
952 }
953 
954 
955 /*
956  * Original code injected iconv tables into the kernel.
957  * Not sure if we'll need this or not...  REVISIT
958  */
959 #ifdef KICONV_SUPPORT
960 static int
961 smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
962 {
963 	int error = 0;
964 
965 	error = kiconv_add_xlat_table(to, from, tbl);
966 	if (error && error != EEXIST) {
967 		smb_error(dgettext(TEXT_DOMAIN,
968 		    "can not setup kernel iconv table (%s:%s)"),
969 		    error, from, to);
970 		return (error);
971 	}
972 	return (error);
973 }
974 #endif	/* KICONV_SUPPORT */
975 
976 /*
977  * Verify context info. before connect operation(s),
978  * lookup specified server and try to fill all forgotten fields.
979  * Legacy name used by commands.
980  */
981 int
982 smb_ctx_resolve(struct smb_ctx *ctx)
983 {
984 	struct smbioc_ossn *ssn = &ctx->ct_ssn;
985 	int error = 0;
986 #ifdef KICONV_SUPPORT
987 	uchar_t cstbl[256];
988 	uint_t i;
989 #endif
990 
991 	ctx->ct_flags &= ~SMBCF_RESOLVED;
992 
993 	if (ctx->ct_fullserver == NULL) {
994 		smb_error(dgettext(TEXT_DOMAIN,
995 		    "no server name specified"), 0);
996 		return (EINVAL);
997 	}
998 
999 	if (ctx->ct_minlevel >= SMBL_SHARE &&
1000 	    ctx->ct_origshare == NULL) {
1001 		smb_error(dgettext(TEXT_DOMAIN,
1002 		    "no share name specified for %s@%s"),
1003 		    0, ssn->ssn_user, ctx->ct_fullserver);
1004 		return (EINVAL);
1005 	}
1006 	error = nb_ctx_resolve(ctx->ct_nb);
1007 	if (error)
1008 		return (error);
1009 #ifdef KICONV_SUPPORT
1010 	if (ssn->ioc_localcs[0] == 0)
1011 		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
1012 	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
1013 	if (error)
1014 		return (error);
1015 	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
1016 	if (error)
1017 		return (error);
1018 	if (ssn->ioc_servercs[0] != 0) {
1019 		for (i = 0; i < sizeof (cstbl); i++)
1020 			cstbl[i] = i;
1021 		nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
1022 		error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
1023 		    cstbl);
1024 		if (error)
1025 			return (error);
1026 		for (i = 0; i < sizeof (cstbl); i++)
1027 			cstbl[i] = i;
1028 		nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
1029 		error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
1030 		    cstbl);
1031 		if (error)
1032 			return (error);
1033 	}
1034 #endif	/* KICONV_SUPPORT */
1035 
1036 	/*
1037 	 * Lookup the IP address and fill in ct_addrinfo.
1038 	 *
1039 	 * Note: smb_ctx_getaddr() returns a EAI_xxx
1040 	 * error value like getaddrinfo(3), but this
1041 	 * function needs to return an errno value.
1042 	 */
1043 	error = smb_ctx_getaddr(ctx);
1044 	if (error) {
1045 		const char *ais = gai_strerror(error);
1046 		smb_error(dgettext(TEXT_DOMAIN,
1047 		    "can't get server address, %s"), 0, ais);
1048 		return (ENODATA);
1049 	}
1050 	assert(ctx->ct_addrinfo != NULL);
1051 
1052 	/*
1053 	 * If we have a user name but no password,
1054 	 * check for a keychain entry.
1055 	 * XXX: Only for auth NTLM?
1056 	 */
1057 	if (ctx->ct_user[0] == '\0') {
1058 		/*
1059 		 * No user name (anonymous session).
1060 		 * The minauth checks do not apply.
1061 		 */
1062 		ctx->ct_authflags = SMB_AT_ANON;
1063 	} else {
1064 		/*
1065 		 * Have a user name.
1066 		 * If we don't have a p/w yet,
1067 		 * try the keychain.
1068 		 */
1069 		if (ctx->ct_password[0] == '\0')
1070 			(void) smb_get_keychain(ctx);
1071 		/*
1072 		 * If we're doing p/w based auth,
1073 		 * that means not using Kerberos.
1074 		 */
1075 		if (ctx->ct_password[0] != '\0')
1076 			ctx->ct_authflags &= ~SMB_AT_KRB5;
1077 		/*
1078 		 * Mask out disallowed auth types.
1079 		 */
1080 		ctx->ct_authflags &= ctx->ct_minauth;
1081 	}
1082 	if (ctx->ct_authflags == 0) {
1083 		smb_error(dgettext(TEXT_DOMAIN,
1084 		    "no valid auth. types"), 0);
1085 		return (ENOTSUP);
1086 	}
1087 
1088 	ctx->ct_flags |= SMBCF_RESOLVED;
1089 	if (smb_debug)
1090 		dump_ctx("after smb_ctx_resolve", ctx);
1091 
1092 	return (0);
1093 }
1094 
1095 int
1096 smb_open_driver()
1097 {
1098 	int err, fd;
1099 	uint32_t version;
1100 
1101 	fd = open("/dev/"NSMB_NAME, O_RDWR);
1102 	if (fd < 0) {
1103 		err = errno;
1104 		smb_error(dgettext(TEXT_DOMAIN,
1105 		    "failed to open driver"), err);
1106 		return (-1);
1107 	}
1108 
1109 	/*
1110 	 * Check the driver version (paranoia)
1111 	 * Do this BEFORE any other ioctl calls.
1112 	 */
1113 	if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1114 		version = 0;
1115 	if (version != NSMB_VERSION) {
1116 		smb_error(dgettext(TEXT_DOMAIN,
1117 		    "incorrect driver version"), 0);
1118 		close(fd);
1119 		return (-1);
1120 	}
1121 
1122 	/* This handle controls per-process resources. */
1123 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1124 
1125 	return (fd);
1126 }
1127 
1128 int
1129 smb_ctx_gethandle(struct smb_ctx *ctx)
1130 {
1131 	int fd;
1132 
1133 	if (ctx->ct_dev_fd != -1) {
1134 		rpc_cleanup_smbctx(ctx);
1135 		close(ctx->ct_dev_fd);
1136 		ctx->ct_dev_fd = -1;
1137 		ctx->ct_flags &= ~SMBCF_SSNACTIVE;
1138 	}
1139 
1140 	fd = smb_open_driver();
1141 	if (fd < 0)
1142 		return (ENODEV);
1143 
1144 	ctx->ct_dev_fd = fd;
1145 	return (0);
1146 }
1147 
1148 
1149 /*
1150  * Find or create a connection + logon session
1151  */
1152 int
1153 smb_ctx_get_ssn(struct smb_ctx *ctx)
1154 {
1155 	int err = 0;
1156 
1157 	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
1158 		return (EINVAL);
1159 
1160 	if (ctx->ct_dev_fd < 0) {
1161 		if ((err = smb_ctx_gethandle(ctx)))
1162 			return (err);
1163 	}
1164 
1165 	/*
1166 	 * Check whether the driver already has a VC
1167 	 * we can use.  If so, we're done!
1168 	 */
1169 	err = smb_ctx_findvc(ctx);
1170 	if (err == 0) {
1171 		DPRINT("found an existing VC");
1172 	} else {
1173 		/*
1174 		 * This calls the IOD to create a new session.
1175 		 */
1176 		DPRINT("setup a new VC");
1177 		err = smb_ctx_newvc(ctx);
1178 		if (err != 0)
1179 			return (err);
1180 
1181 		/*
1182 		 * Call findvc again.  The new VC sould be
1183 		 * found in the driver this time.
1184 		 */
1185 		err = smb_ctx_findvc(ctx);
1186 	}
1187 
1188 	return (err);
1189 }
1190 
1191 /*
1192  * Get the string representation of a share "use" type,
1193  * as needed for the "service" in tree connect.
1194  */
1195 static const char *
1196 smb_use_type_str(smb_use_shtype_t stype)
1197 {
1198 	const char *pp;
1199 
1200 	switch (stype) {
1201 	default:
1202 	case USE_WILDCARD:
1203 		pp = "?????";
1204 		break;
1205 	case USE_DISKDEV:
1206 		pp = "A:";
1207 		break;
1208 	case USE_SPOOLDEV:
1209 		pp = "LPT1:";
1210 		break;
1211 	case USE_CHARDEV:
1212 		pp = "COMM";
1213 		break;
1214 	case USE_IPC:
1215 		pp = "IPC";
1216 		break;
1217 	}
1218 	return (pp);
1219 }
1220 
1221 /*
1222  * Find or create a tree connection
1223  */
1224 int
1225 smb_ctx_get_tree(struct smb_ctx *ctx)
1226 {
1227 	smbioc_tcon_t *tcon = NULL;
1228 	const char *stype;
1229 	int cmd, err = 0;
1230 
1231 	if (ctx->ct_dev_fd < 0 ||
1232 	    ctx->ct_origshare == NULL) {
1233 		return (EINVAL);
1234 	}
1235 
1236 	cmd = SMBIOC_TREE_CONNECT;
1237 	tcon = malloc(sizeof (*tcon));
1238 	if (tcon == NULL)
1239 		return (ENOMEM);
1240 	bzero(tcon, sizeof (*tcon));
1241 	tcon->tc_flags = SMBLK_CREATE;
1242 	tcon->tc_opt = 0;
1243 
1244 	/* The share name */
1245 	strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
1246 	    sizeof (tcon->tc_sh.sh_name));
1247 
1248 	/* The share "use" type. */
1249 	stype = smb_use_type_str(ctx->ct_shtype_req);
1250 	strlcpy(tcon->tc_sh.sh_type_req, stype,
1251 	    sizeof (tcon->tc_sh.sh_type_req));
1252 
1253 	/*
1254 	 * Todo: share passwords for share-level security.
1255 	 *
1256 	 * The driver does the actual TCON call.
1257 	 */
1258 	if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1259 		err = errno;
1260 		goto out;
1261 	}
1262 
1263 	/*
1264 	 * Check the returned share type
1265 	 */
1266 	DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret);
1267 	if (ctx->ct_shtype_req != USE_WILDCARD &&
1268 	    0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) {
1269 		smb_error(dgettext(TEXT_DOMAIN,
1270 		    "%s: incompatible share type"),
1271 		    0, ctx->ct_origshare);
1272 		err = EINVAL;
1273 	}
1274 
1275 out:
1276 	if (tcon != NULL)
1277 		free(tcon);
1278 
1279 	return (err);
1280 }
1281 
1282 /*
1283  * Return the hflags2 word for an smb_ctx.
1284  */
1285 int
1286 smb_ctx_flags2(struct smb_ctx *ctx)
1287 {
1288 	uint16_t flags2;
1289 
1290 	if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
1291 		smb_error(dgettext(TEXT_DOMAIN,
1292 		    "can't get flags2 for a session"), errno);
1293 		return (-1);
1294 	}
1295 	return (flags2);
1296 }
1297 
1298 /*
1299  * Get the transport level session key.
1300  * Must already have an active SMB session.
1301  */
1302 int
1303 smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len)
1304 {
1305 	if (len < SMBIOC_HASH_SZ)
1306 		return (EINVAL);
1307 
1308 	if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1309 		return (errno);
1310 
1311 	return (0);
1312 }
1313 
1314 
1315 /*
1316  * RC file parsing stuff
1317  */
1318 
1319 struct nv {
1320 	char *name;
1321 	int value;
1322 } minauth_table[] = {
1323 	/* Allowed auth. types */
1324 	{ "kerberos",	SMB_AT_KRB5 },
1325 	{ "ntlmv2",	SMB_AT_KRB5|SMB_AT_NTLM2 },
1326 	{ "ntlm",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
1327 	{ "lm",		SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
1328 	{ "none",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
1329 			SMB_AT_ANON },
1330 	{ NULL }
1331 };
1332 
1333 
1334 /*
1335  * level values:
1336  * 0 - default
1337  * 1 - server
1338  * 2 - server:user
1339  * 3 - server:user:share
1340  */
1341 static int
1342 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
1343 {
1344 	char *p;
1345 	int error;
1346 
1347 #ifdef	KICONV_SUPPORT
1348 	if (level > 0) {
1349 		rc_getstringptr(smb_rc, sname, "charsets", &p);
1350 		if (p) {
1351 			error = smb_ctx_setcharset(ctx, p);
1352 			if (error)
1353 				smb_error(dgettext(TEXT_DOMAIN,
1354 	"charset specification in the section '%s' ignored"),
1355 				    error, sname);
1356 		}
1357 	}
1358 #endif
1359 
1360 	if (level <= 1) {
1361 		/* Section is: [default] or [server] */
1362 
1363 		rc_getstringptr(smb_rc, sname, "minauth", &p);
1364 		if (p) {
1365 			/*
1366 			 * "minauth" was set in this section; override
1367 			 * the current minimum authentication setting.
1368 			 */
1369 			struct nv *nvp;
1370 			for (nvp = minauth_table; nvp->name; nvp++)
1371 				if (strcmp(p, nvp->name) == 0)
1372 					break;
1373 			if (nvp->name)
1374 				ctx->ct_minauth = nvp->value;
1375 			else {
1376 				/*
1377 				 * Unknown minimum authentication level.
1378 				 */
1379 				smb_error(dgettext(TEXT_DOMAIN,
1380 "invalid minimum authentication level \"%s\" specified in the section %s"),
1381 				    0, p, sname);
1382 				return (EINVAL);
1383 			}
1384 		}
1385 
1386 		rc_getstringptr(smb_rc, sname, "signing", &p);
1387 		if (p) {
1388 			/*
1389 			 * "signing" was set in this section; override
1390 			 * the current signing settings.
1391 			 */
1392 			if (strcmp(p, "disabled") == 0) {
1393 				smb_ctx_setsigning(ctx, FALSE, FALSE);
1394 			} else if (strcmp(p, "enabled") == 0) {
1395 				smb_ctx_setsigning(ctx, TRUE, FALSE);
1396 			} else if (strcmp(p, "required") == 0) {
1397 				smb_ctx_setsigning(ctx, TRUE, TRUE);
1398 			} else {
1399 				/*
1400 				 * Unknown "signing" value.
1401 				 */
1402 				smb_error(dgettext(TEXT_DOMAIN,
1403 "invalid signing policy \"%s\" specified in the section %s"),
1404 				    0, p, sname);
1405 				return (EINVAL);
1406 			}
1407 		}
1408 
1409 		/*
1410 		 * Domain name.  Allow both keywords:
1411 		 * "workgroup", "domain"
1412 		 *
1413 		 * Note: these are NOT marked "from CMD".
1414 		 * See long comment at smb_ctx_init()
1415 		 */
1416 		rc_getstringptr(smb_rc, sname, "workgroup", &p);
1417 		if (p) {
1418 			nls_str_upper(p, p);
1419 			error = smb_ctx_setdomain(ctx, p, 0);
1420 			if (error)
1421 				smb_error(dgettext(TEXT_DOMAIN,
1422 				    "workgroup specification in the "
1423 				    "section '%s' ignored"), error, sname);
1424 		}
1425 		rc_getstringptr(smb_rc, sname, "domain", &p);
1426 		if (p) {
1427 			nls_str_upper(p, p);
1428 			error = smb_ctx_setdomain(ctx, p, 0);
1429 			if (error)
1430 				smb_error(dgettext(TEXT_DOMAIN,
1431 				    "domain specification in the "
1432 				    "section '%s' ignored"), error, sname);
1433 		}
1434 
1435 		rc_getstringptr(smb_rc, sname, "user", &p);
1436 		if (p) {
1437 			error = smb_ctx_setuser(ctx, p, 0);
1438 			if (error)
1439 				smb_error(dgettext(TEXT_DOMAIN,
1440 				    "user specification in the "
1441 				    "section '%s' ignored"), error, sname);
1442 		}
1443 	}
1444 
1445 	if (level == 1) {
1446 		/* Section is: [server] */
1447 		rc_getstringptr(smb_rc, sname, "addr", &p);
1448 		if (p) {
1449 			error = smb_ctx_setsrvaddr(ctx, p);
1450 			if (error) {
1451 				smb_error(dgettext(TEXT_DOMAIN,
1452 				    "invalid address specified in section %s"),
1453 				    0, sname);
1454 				return (error);
1455 			}
1456 		}
1457 	}
1458 
1459 	rc_getstringptr(smb_rc, sname, "password", &p);
1460 	if (p) {
1461 		error = smb_ctx_setpassword(ctx, p, 0);
1462 		if (error)
1463 			smb_error(dgettext(TEXT_DOMAIN,
1464 	    "password specification in the section '%s' ignored"),
1465 			    error, sname);
1466 	}
1467 
1468 	return (0);
1469 }
1470 
1471 /*
1472  * read rc file as follows:
1473  * 0: read [default] section
1474  * 1: override with [server] section
1475  * 2: override with [server:user] section
1476  * 3: override with [server:user:share] section
1477  * Since absence of rcfile is not fatal, silently ignore this fact.
1478  * smb_rc file should be closed by caller.
1479  */
1480 int
1481 smb_ctx_readrc(struct smb_ctx *ctx)
1482 {
1483 	char *home;
1484 	char *sname = NULL;
1485 	int sname_max;
1486 	int err = 0;
1487 
1488 	if ((home = getenv("HOME")) == NULL)
1489 		home = ctx->ct_home;
1490 	if ((err = smb_open_rcfile(home)) != 0) {
1491 		DPRINT("smb_open_rcfile, err=%d", err);
1492 		/* ignore any error here */
1493 		return (0);
1494 	}
1495 
1496 	sname_max = 3 * SMBIOC_MAX_NAME + 4;
1497 	sname = malloc(sname_max);
1498 	if (sname == NULL) {
1499 		err = ENOMEM;
1500 		goto done;
1501 	}
1502 
1503 	/*
1504 	 * default parameters (level=0)
1505 	 */
1506 	smb_ctx_readrcsection(ctx, "default", 0);
1507 	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
1508 
1509 	/*
1510 	 * If we don't have a server name, we can't read any of the
1511 	 * [server...] sections.
1512 	 */
1513 	if (ctx->ct_fullserver == NULL)
1514 		goto done;
1515 	/*
1516 	 * SERVER parameters.
1517 	 */
1518 	smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
1519 
1520 	/*
1521 	 * If we don't have a user name, we can't read any of the
1522 	 * [server:user...] sections.
1523 	 */
1524 	if (ctx->ct_user[0] == 0)
1525 		goto done;
1526 	/*
1527 	 * SERVER:USER parameters
1528 	 */
1529 	snprintf(sname, sname_max, "%s:%s",
1530 	    ctx->ct_fullserver,
1531 	    ctx->ct_user);
1532 	smb_ctx_readrcsection(ctx, sname, 2);
1533 
1534 
1535 	/*
1536 	 * If we don't have a share name, we can't read any of the
1537 	 * [server:user:share] sections.
1538 	 */
1539 	if (ctx->ct_origshare == NULL)
1540 		goto done;
1541 	/*
1542 	 * SERVER:USER:SHARE parameters
1543 	 */
1544 	snprintf(sname, sname_max, "%s:%s:%s",
1545 	    ctx->ct_fullserver,
1546 	    ctx->ct_user,
1547 	    ctx->ct_origshare);
1548 	smb_ctx_readrcsection(ctx, sname, 3);
1549 
1550 done:
1551 	if (sname)
1552 		free(sname);
1553 	smb_close_rcfile();
1554 	if (smb_debug)
1555 		dump_ctx("after smb_ctx_readrc", ctx);
1556 	if (err)
1557 		DPRINT("err=%d\n", err);
1558 
1559 	return (err);
1560 }
1561