xref: /illumos-gate/usr/src/lib/libsmbfs/smb/ctx.c (revision 5328fc53d11d7151861fa272e4fb0248b8f0e145)
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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
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 "private.h"
69 #include "ntlm.h"
70 
71 #ifndef FALSE
72 #define	FALSE	0
73 #endif
74 #ifndef TRUE
75 #define	TRUE	1
76 #endif
77 
78 #define	SMB_AT_DEFAULT	(SMB_AT_KRB5 | SMB_AT_NTLM2)
79 #define	SMB_AT_MINAUTH	(SMB_AT_KRB5 | SMB_AT_NTLM2 | SMB_AT_NTLM1)
80 
81 struct nv {
82 	char *name;
83 	int value;
84 };
85 
86 /* These two may be set by commands. */
87 int smb_debug, smb_verbose;
88 
89 /*
90  * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
91  */
92 const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
93 
94 /*
95  * Defaults for new contexts (connections to servers).
96  * These are set by smbfs_set_default_...
97  */
98 static char default_domain[SMBIOC_MAX_NAME];
99 static char default_user[SMBIOC_MAX_NAME];
100 
101 
102 /*
103  * Give the RPC library a callback hook that will be
104  * called whenever we destroy or reinit an smb_ctx_t.
105  * The name rpc_cleanup_smbctx() is legacy, and was
106  * originally a direct call into the RPC code.
107  */
108 static smb_ctx_close_hook_t close_hook;
109 static void
110 rpc_cleanup_smbctx(struct smb_ctx *ctx)
111 {
112 	if (close_hook)
113 		(*close_hook)(ctx);
114 }
115 void
116 smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
117 {
118 	close_hook = hook;
119 }
120 
121 void
122 dump_ctx_flags(int flags)
123 {
124 	printf(" Flags: ");
125 	if (flags == 0)
126 		printf("0");
127 	if (flags & SMBCF_NOPWD)
128 		printf("NOPWD ");
129 	if (flags & SMBCF_SRIGHTS)
130 		printf("SRIGHTS ");
131 	if (flags & SMBCF_LOCALE)
132 		printf("LOCALE ");
133 	if (flags & SMBCF_CMD_DOM)
134 		printf("CMD_DOM ");
135 	if (flags & SMBCF_CMD_USR)
136 		printf("CMD_USR ");
137 	if (flags & SMBCF_CMD_PW)
138 		printf("CMD_PW ");
139 	if (flags & SMBCF_RESOLVED)
140 		printf("RESOLVED ");
141 	if (flags & SMBCF_KCBAD)
142 		printf("KCBAD ");
143 	if (flags & SMBCF_KCFOUND)
144 		printf("KCFOUND ");
145 	if (flags & SMBCF_BROWSEOK)
146 		printf("BROWSEOK ");
147 	if (flags & SMBCF_AUTHREQ)
148 		printf("AUTHREQ ");
149 	if (flags & SMBCF_KCSAVE)
150 		printf("KCSAVE  ");
151 	if (flags & SMBCF_KCDOMAIN)
152 		printf("KCDOMAIN ");
153 	printf("\n");
154 }
155 
156 void
157 dump_iod_ssn(smb_iod_ssn_t *is)
158 {
159 	static const char zeros[NTLM_HASH_SZ] = {0};
160 	struct smbioc_ossn *ssn = &is->iod_ossn;
161 
162 	printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
163 	dump_sockaddr(&ssn->ssn_srvaddr.sa);
164 	printf(" dom=\"%s\", user=\"%s\"\n",
165 	    ssn->ssn_domain, ssn->ssn_user);
166 	printf(" ct_vopt=0x%x, ct_owner=%d\n",
167 	    ssn->ssn_vopt, ssn->ssn_owner);
168 	printf(" ct_minver=0x%x, ct_maxver=0x%x\n",
169 	    ssn->ssn_minver, ssn->ssn_maxver);
170 	printf(" ct_authflags=0x%x\n", is->iod_authflags);
171 
172 	printf(" ct_nthash:");
173 	if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
174 		smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
175 	else
176 		printf(" {0}\n");
177 
178 	printf(" ct_lmhash:");
179 	if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
180 		smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
181 	else
182 		printf(" {0}\n");
183 }
184 
185 void
186 dump_ctx(char *where, struct smb_ctx *ctx)
187 {
188 	printf("context %s:\n", where);
189 	dump_ctx_flags(ctx->ct_flags);
190 
191 	if (ctx->ct_locname)
192 		printf(" localname=\"%s\"", ctx->ct_locname);
193 	else
194 		printf(" localname=NULL");
195 
196 	if (ctx->ct_fullserver)
197 		printf(" fullserver=\"%s\"", ctx->ct_fullserver);
198 	else
199 		printf(" fullserver=NULL");
200 
201 	if (ctx->ct_srvaddr_s)
202 		printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
203 	else
204 		printf(" srvaddr_s=NULL\n");
205 
206 	if (ctx->ct_addrinfo)
207 		dump_addrinfo(ctx->ct_addrinfo);
208 	else
209 		printf(" ct_addrinfo = NULL\n");
210 
211 	dump_iod_ssn(&ctx->ct_iod_ssn);
212 
213 	printf(" share_name=\"%s\", share_type=%d\n",
214 	    ctx->ct_origshare ? ctx->ct_origshare : "",
215 	    ctx->ct_shtype_req);
216 
217 	printf(" ct_home=\"%s\"\n", ctx->ct_home);
218 	printf(" ct_rpath=\"%s\"\n", ctx->ct_rpath);
219 }
220 
221 int
222 smb_ctx_alloc(struct smb_ctx **ctx_pp)
223 {
224 	smb_ctx_t *ctx;
225 	int err;
226 
227 	ctx = malloc(sizeof (*ctx));
228 	if (ctx == NULL)
229 		return (ENOMEM);
230 	err = smb_ctx_init(ctx);
231 	if (err != 0) {
232 		free(ctx);
233 		return (err);
234 	}
235 	*ctx_pp = ctx;
236 	return (0);
237 }
238 
239 /*
240  * Initialize an smb_ctx struct (defaults)
241  */
242 int
243 smb_ctx_init(struct smb_ctx *ctx)
244 {
245 	int error;
246 
247 	bzero(ctx, sizeof (*ctx));
248 
249 	error = nb_ctx_create(&ctx->ct_nb);
250 	if (error)
251 		return (error);
252 
253 	ctx->ct_dev_fd = -1;
254 	ctx->ct_door_fd = -1;
255 	ctx->ct_parsedlevel = SMBL_NONE;
256 	ctx->ct_minlevel = SMBL_NONE;
257 	ctx->ct_maxlevel = SMBL_PATH;
258 
259 	/* Fill in defaults */
260 	ctx->ct_vopt = SMBVOPT_SIGNING_ENABLED;
261 	ctx->ct_owner = SMBM_ANY_OWNER;
262 	ctx->ct_authflags = SMB_AT_DEFAULT;
263 	ctx->ct_minauth = SMB_AT_MINAUTH;
264 	ctx->ct_maxver = SMB2_DIALECT_MAX;
265 
266 	/*
267 	 * Default domain, user, ...
268 	 */
269 	strlcpy(ctx->ct_domain, default_domain,
270 	    sizeof (ctx->ct_domain));
271 	strlcpy(ctx->ct_user, default_user,
272 	    sizeof (ctx->ct_user));
273 
274 	return (0);
275 }
276 
277 /*
278  * "Scan" the command line args to find the server name,
279  * user name, and share name, as needed.  We need these
280  * before reading the RC files and/or sharectl values.
281  *
282  * The sequence for getting all the members filled in
283  * has some tricky aspects.  Here's how it works:
284  *
285  * The search order for options is as follows:
286  *   command line options
287  *   values parsed from UNC path (cmd)
288  *   values from RC file (per-user)
289  *   values from SMF (system-wide)
290  *   built-in defaults
291  *
292  * Normally, one would simply get all the values starting with
293  * the bottom of the above list and working to the top, and
294  * overwriting values as you go.  But we need an exception.
295  *
296  * In this function, we parse the UNC path and command line options,
297  * because we need (at least) the server name when we're getting the
298  * SMF and RC file values.  However, values we get from the command
299  * should not be overwritten by SMF or RC file parsing, so we mark
300  * values from the command as "from CMD" and the RC file parser
301  * leaves in place any values so marked.  See: SMBCF_CMD_*
302  *
303  * The semantics of these flags are: "This value came from the
304  * current command instance, not from sources that may apply to
305  * multiple commands."  (Different from the old "FROMUSR" flag.)
306  *
307  * Note that smb_ctx_opt() is called later to handle the
308  * remaining options, which should be ignored here.
309  * The (magic) leading ":" in cf_getopt() makes it
310  * ignore options not in the options string.
311  */
312 int
313 smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
314 	int minlevel, int maxlevel, int sharetype)
315 {
316 	int  ind, opt, error = 0;
317 	int aflg = 0, uflg = 0;
318 	const char *arg;
319 
320 	/*
321 	 * Parse options, if any.  Values from here too
322 	 * are marked as "from CMD".
323 	 */
324 	if (argv == NULL)
325 		return (0);
326 
327 	ctx->ct_minlevel = minlevel;
328 	ctx->ct_maxlevel = maxlevel;
329 	ctx->ct_shtype_req = sharetype;
330 
331 	cf_opt_lock();
332 	/* Careful: no return/goto before cf_opt_unlock! */
333 	while (error == 0) {
334 		/*
335 		 * Leading ':' tells this to skip unknown opts.
336 		 * Just get -A and -U here so we know the user
337 		 * for config file parsing.
338 		 */
339 		opt = cf_getopt(argc, argv, ":AU:");
340 		if (opt == -1)
341 			break;
342 		arg = cf_optarg;
343 		/* NB: handle most in smb_ctx_opt */
344 		switch (opt) {
345 		case 'A':
346 			aflg = 1;
347 			error = smb_ctx_setuser(ctx, "", TRUE);
348 			ctx->ct_flags |= SMBCF_NOPWD;
349 			break;
350 		case 'U':
351 			uflg = 1;
352 			error = smb_ctx_setuser(ctx, arg, TRUE);
353 			break;
354 		default:
355 			DPRINT("skip opt=%c", opt);
356 			break;
357 		}
358 	}
359 	ind = cf_optind;
360 	arg = argv[ind];
361 	cf_optind = cf_optreset = 1;
362 	cf_opt_unlock();
363 
364 	if (error)
365 		return (error);
366 
367 	if (aflg && uflg)  {
368 		printf(gettext("-A and -U flags are exclusive.\n"));
369 		return (EINVAL);
370 	}
371 
372 	/*
373 	 * Parse the UNC path.  Values from here are
374 	 * marked as "from CMD".
375 	 */
376 	for (; ind < argc; ind++) {
377 		arg = argv[ind];
378 		if (strncmp(arg, "//", 2) != 0)
379 			continue;
380 		error = smb_ctx_parseunc(ctx, arg,
381 		    minlevel, maxlevel, sharetype, &arg);
382 		if (error)
383 			return (error);
384 		break;
385 	}
386 
387 	return (error);
388 }
389 
390 void
391 smb_ctx_free(smb_ctx_t *ctx)
392 {
393 	smb_ctx_done(ctx);
394 	free(ctx);
395 }
396 
397 void
398 smb_ctx_done(struct smb_ctx *ctx)
399 {
400 
401 	rpc_cleanup_smbctx(ctx);
402 
403 	if (ctx->ct_dev_fd != -1) {
404 		nsmb_close(ctx->ct_dev_fd);
405 		ctx->ct_dev_fd = -1;
406 	}
407 	if (ctx->ct_door_fd != -1) {
408 		close(ctx->ct_door_fd);
409 		ctx->ct_door_fd = -1;
410 	}
411 	if (ctx->ct_srvaddr_s) {
412 		free(ctx->ct_srvaddr_s);
413 		ctx->ct_srvaddr_s = NULL;
414 	}
415 	if (ctx->ct_nb) {
416 		nb_ctx_done(ctx->ct_nb);
417 		ctx->ct_nb = NULL;
418 	}
419 	if (ctx->ct_locname) {
420 		free(ctx->ct_locname);
421 		ctx->ct_locname = NULL;
422 	}
423 	if (ctx->ct_origshare) {
424 		free(ctx->ct_origshare);
425 		ctx->ct_origshare = NULL;
426 	}
427 	if (ctx->ct_fullserver) {
428 		free(ctx->ct_fullserver);
429 		ctx->ct_fullserver = NULL;
430 	}
431 	if (ctx->ct_addrinfo) {
432 		freeaddrinfo(ctx->ct_addrinfo);
433 		ctx->ct_addrinfo = NULL;
434 	}
435 	if (ctx->ct_home) {
436 		free(ctx->ct_home);
437 		ctx->ct_home = NULL;
438 	}
439 	if (ctx->ct_rpath) {
440 		free(ctx->ct_rpath);
441 		ctx->ct_rpath = NULL;
442 	}
443 	if (ctx->ct_ssnkey_buf) {
444 		free(ctx->ct_ssnkey_buf);
445 		ctx->ct_ssnkey_buf = NULL;
446 	}
447 }
448 
449 /*
450  * Parse the UNC path.  Here we expect something like
451  *   "//[[domain;]user[:password]@]host[/share[/path]]"
452  * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
453  * Values found here are marked as "from CMD".
454  */
455 int
456 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
457 	int minlevel, int maxlevel, int sharetype,
458 	const char **next)
459 {
460 	char tmp[1024];
461 	char *host, *share, *path;
462 	char *dom, *usr, *pw, *p;
463 	int error;
464 
465 	/*
466 	 * This may be called outside of _scan_argv,
467 	 * so make sure these get initialized.
468 	 */
469 	ctx->ct_minlevel = minlevel;
470 	ctx->ct_maxlevel = maxlevel;
471 	ctx->ct_shtype_req = sharetype;
472 	ctx->ct_parsedlevel = SMBL_NONE;
473 
474 	dom = usr = pw = host = NULL;
475 
476 	/* Work on a temporary copy, fix back slashes. */
477 	strlcpy(tmp, unc, sizeof (tmp));
478 	for (p = tmp; *p; p++)
479 		if (*p == '\\')
480 			*p = '/';
481 
482 	if (tmp[0] != '/' || tmp[1] != '/') {
483 		smb_error(dgettext(TEXT_DOMAIN,
484 		    "UNC should start with '//'"), 0);
485 		error = EINVAL;
486 		goto out;
487 	}
488 	p = tmp + 2;	/* user@host... */
489 
490 	/* Find the share part, if any. */
491 	share = strchr(p, '/');
492 	if (share)
493 		*share = '\0';
494 	(void) unpercent(p);	/* host component */
495 
496 	/*
497 	 * Parse the "host" stuff right to left:
498 	 * 1: trailing "@hostname" (or whole field)
499 	 * 2: trailing ":password"
500 	 * 3: trailing "domain;user" (or just user)
501 	 */
502 	host = strrchr(p, '@');
503 	if (host == NULL) {
504 		host = p;	/* no user@ prefix */
505 	} else {
506 		*host++ = '\0';
507 
508 		/* may have [[domain;]user[:passwd]] */
509 		pw = strchr(p, ':');
510 		if (pw)
511 			*pw++ = '\0';
512 		usr = strchr(p, ';');
513 		if (usr) {
514 			*usr++ = '\0';
515 			dom = p;
516 		} else
517 			usr = p;
518 	}
519 
520 	if (*host == '\0') {
521 		smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
522 		error = EINVAL;
523 		goto out;
524 	}
525 	error = smb_ctx_setfullserver(ctx, host);
526 	if (error)
527 		goto out;
528 	ctx->ct_parsedlevel = SMBL_VC;
529 
530 	if (dom != NULL) {
531 		error = smb_ctx_setdomain(ctx, dom, TRUE);
532 		if (error)
533 			goto out;
534 	}
535 	if (usr != NULL) {
536 		if (*usr == '\0') {
537 			smb_error(dgettext(TEXT_DOMAIN,
538 			    "empty user name"), 0);
539 			error = EINVAL;
540 			goto out;
541 		}
542 		if (ctx->ct_maxlevel < SMBL_VC) {
543 			smb_error(dgettext(TEXT_DOMAIN,
544 			    "no user name required"), 0);
545 			error = EINVAL;
546 			goto out;
547 		}
548 		error = smb_ctx_setuser(ctx, usr, TRUE);
549 		if (error)
550 			goto out;
551 	}
552 	if (pw != NULL) {
553 		error = smb_ctx_setpassword(ctx, pw, TRUE);
554 		if (error)
555 			goto out;
556 	}
557 
558 	if (share != NULL) {
559 		/* restore the slash */
560 		*share = '/';
561 		p = share + 1;
562 
563 		/* Find the path part, if any. */
564 		path = strchr(p, '/');
565 		if (path)
566 			*path = '\0';
567 		(void) unpercent(p);	/* share component */
568 
569 		if (*p == '\0') {
570 			smb_error(dgettext(TEXT_DOMAIN,
571 			    "empty share name"), 0);
572 			error = EINVAL;
573 			goto out;
574 		}
575 		if (ctx->ct_maxlevel < SMBL_SHARE) {
576 			smb_error(dgettext(TEXT_DOMAIN,
577 			    "no share name required"), 0);
578 			error = EINVAL;
579 			goto out;
580 		}
581 
582 		/*
583 		 * Special case UNC names like:
584 		 *	//host/PIPE/endpoint
585 		 * to have share: IPC$
586 		 */
587 		if (strcasecmp(p, "PIPE") == 0) {
588 			sharetype = USE_IPC;
589 			p = "IPC$";
590 		}
591 		error = smb_ctx_setshare(ctx, p, sharetype);
592 		if (error)
593 			goto out;
594 		ctx->ct_parsedlevel = SMBL_SHARE;
595 
596 		if (path) {
597 			/* restore the slash */
598 			*path = '/';
599 			p = path + 1;
600 			(void) unpercent(p);	/* remainder */
601 			free(ctx->ct_rpath);
602 			ctx->ct_rpath = strdup(path);
603 		}
604 	} else if (ctx->ct_minlevel >= SMBL_SHARE) {
605 		smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
606 		error = EINVAL;
607 		goto out;
608 	}
609 
610 	if (next)
611 		*next = NULL;
612 
613 out:
614 	if (error == 0 && smb_debug > 0)
615 		dump_ctx("after smb_ctx_parseunc", ctx);
616 
617 	return (error);
618 }
619 
620 #ifdef KICONV_SUPPORT
621 int
622 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
623 {
624 	char *cp, *servercs, *localcs;
625 	int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
626 	int scslen, lcslen, error;
627 
628 	cp = strchr(arg, ':');
629 	lcslen = cp ? (cp - arg) : 0;
630 	if (lcslen == 0 || lcslen >= cslen) {
631 		smb_error(dgettext(TEXT_DOMAIN,
632 		    "invalid local charset specification (%s)"), 0, arg);
633 		return (EINVAL);
634 	}
635 	scslen = (size_t)strlen(++cp);
636 	if (scslen == 0 || scslen >= cslen) {
637 		smb_error(dgettext(TEXT_DOMAIN,
638 		    "invalid server charset specification (%s)"), 0, arg);
639 		return (EINVAL);
640 	}
641 	localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
642 	localcs[lcslen] = 0;
643 	servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
644 	error = nls_setrecode(localcs, servercs);
645 	if (error == 0)
646 		return (0);
647 	smb_error(dgettext(TEXT_DOMAIN,
648 	    "can't initialize iconv support (%s:%s)"),
649 	    error, localcs, servercs);
650 	localcs[0] = 0;
651 	servercs[0] = 0;
652 	return (error);
653 }
654 #endif /* KICONV_SUPPORT */
655 
656 int
657 smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
658 {
659 	ctx->ct_authflags = flags;
660 	return (0);
661 }
662 
663 int
664 smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
665 {
666 	char *p = strdup(name);
667 
668 	if (p == NULL)
669 		return (ENOMEM);
670 	if (ctx->ct_fullserver)
671 		free(ctx->ct_fullserver);
672 	ctx->ct_fullserver = p;
673 	return (0);
674 }
675 
676 int
677 smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
678 {
679 	strlcpy(ctx->ct_srvname, name,
680 	    sizeof (ctx->ct_srvname));
681 	return (0);
682 }
683 
684 int
685 smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
686 {
687 
688 	if (strlen(name) >= sizeof (ctx->ct_user)) {
689 		smb_error(dgettext(TEXT_DOMAIN,
690 		    "user name '%s' too long"), 0, name);
691 		return (ENAMETOOLONG);
692 	}
693 
694 	/*
695 	 * Don't overwrite a value from the command line
696 	 * with one from anywhere else.
697 	 */
698 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
699 		return (0);
700 
701 	strlcpy(ctx->ct_user, name,
702 	    sizeof (ctx->ct_user));
703 
704 	/* Mark this as "from the command line". */
705 	if (from_cmd)
706 		ctx->ct_flags |= SMBCF_CMD_USR;
707 
708 	return (0);
709 }
710 
711 /*
712  * Don't overwrite a domain name from the
713  * command line with one from anywhere else.
714  * See smb_ctx_init() for notes about this.
715  */
716 int
717 smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd)
718 {
719 
720 	if (strlen(name) >= sizeof (ctx->ct_domain)) {
721 		smb_error(dgettext(TEXT_DOMAIN,
722 		    "workgroup name '%s' too long"), 0, name);
723 		return (ENAMETOOLONG);
724 	}
725 
726 	/*
727 	 * Don't overwrite a value from the command line
728 	 * with one from anywhere else.
729 	 */
730 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
731 		return (0);
732 
733 	strlcpy(ctx->ct_domain, name,
734 	    sizeof (ctx->ct_domain));
735 
736 	/* Mark this as "from the command line". */
737 	if (from_cmd)
738 		ctx->ct_flags |= SMBCF_CMD_DOM;
739 
740 	return (0);
741 }
742 
743 int
744 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
745 {
746 	int err;
747 
748 	if (passwd == NULL)
749 		return (EINVAL);
750 	if (strlen(passwd) >= sizeof (ctx->ct_password)) {
751 		smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
752 		return (ENAMETOOLONG);
753 	}
754 
755 	/*
756 	 * If called again after comand line parsing,
757 	 * don't overwrite a value from the command line
758 	 * with one from any stored config.
759 	 */
760 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
761 		return (0);
762 
763 	memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
764 	if (strncmp(passwd, "$$1", 3) == 0)
765 		(void) smb_simpledecrypt(ctx->ct_password, passwd);
766 	else
767 		strlcpy(ctx->ct_password, passwd,
768 		    sizeof (ctx->ct_password));
769 
770 	/*
771 	 * Compute LM hash, NT hash.
772 	 */
773 	if (ctx->ct_password[0]) {
774 		err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
775 		if (err != 0)
776 			return (err);
777 		err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
778 		if (err != 0)
779 			return (err);
780 	}
781 
782 	/* Mark this as "from the command line". */
783 	if (from_cmd)
784 		ctx->ct_flags |= SMBCF_CMD_PW;
785 
786 	return (0);
787 }
788 
789 /*
790  * Use this to set NTLM auth. info (hashes)
791  * when we don't have the password.
792  */
793 int
794 smb_ctx_setpwhash(smb_ctx_t *ctx,
795     const uchar_t *nthash, const uchar_t *lmhash)
796 {
797 
798 	/* Need ct_password to be non-null. */
799 	if (ctx->ct_password[0] == '\0')
800 		strlcpy(ctx->ct_password, "$HASH",
801 		    sizeof (ctx->ct_password));
802 
803 	/*
804 	 * Compute LM hash, NT hash.
805 	 */
806 	memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
807 
808 	/* The LM hash is optional */
809 	if (lmhash) {
810 		memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
811 	}
812 
813 	return (0);
814 }
815 
816 int
817 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
818 {
819 	if (strlen(share) >= SMBIOC_MAX_NAME) {
820 		smb_error(dgettext(TEXT_DOMAIN,
821 		    "share name '%s' too long"), 0, share);
822 		return (ENAMETOOLONG);
823 	}
824 	if (ctx->ct_origshare)
825 		free(ctx->ct_origshare);
826 	if ((ctx->ct_origshare = strdup(share)) == NULL)
827 		return (ENOMEM);
828 
829 	ctx->ct_shtype_req = stype;
830 
831 	return (0);
832 }
833 
834 int
835 smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
836 {
837 	if (addr == NULL || addr[0] == 0)
838 		return (EINVAL);
839 	if (ctx->ct_srvaddr_s)
840 		free(ctx->ct_srvaddr_s);
841 	if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL)
842 		return (ENOMEM);
843 	return (0);
844 }
845 
846 /*
847  * API for library caller to set signing enabled, required
848  * Note: if not enable, ignore require
849  */
850 int
851 smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
852 {
853 	ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
854 	if (enable) {
855 		ctx->ct_vopt |=	SMBVOPT_SIGNING_ENABLED;
856 		if (require)
857 			ctx->ct_vopt |=	SMBVOPT_SIGNING_REQUIRED;
858 	}
859 	return (0);
860 }
861 
862 /*
863  * Handle .nsmbrc "minver" option.
864  * Must be <= maxver
865  */
866 int
867 smb_ctx_setminver(struct smb_ctx *ctx, int ver)
868 {
869 	if (ver < 0 || ver > ctx->ct_maxver)
870 		return (EINVAL);
871 	ctx->ct_minver = (uint16_t)ver;
872 	return (0);
873 }
874 
875 /*
876  * Handle .nsmbrc "maxver" option.
877  * Must be >= minver
878  *
879  * Any "too high" value is just clamped, so the caller
880  * doesn't need to know what's the highest we support.
881  */
882 int
883 smb_ctx_setmaxver(struct smb_ctx *ctx, int ver)
884 {
885 	if (ver < 1 || ver < ctx->ct_minver)
886 		return (EINVAL);
887 	if (ver > SMB2_DIALECT_MAX)
888 		ver = SMB2_DIALECT_MAX;
889 	ctx->ct_maxver = (uint16_t)ver;
890 	return (0);
891 }
892 
893 static int
894 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
895 {
896 	struct group gr;
897 	struct passwd pw;
898 	char buf[NSS_BUFLEN_PASSWD];
899 	char *cp;
900 
901 	cp = strchr(pair, ':');
902 	if (cp) {
903 		*cp++ = '\0';
904 		if (*cp && gid) {
905 			if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
906 				*gid = gr.gr_gid;
907 			} else
908 				smb_error(dgettext(TEXT_DOMAIN,
909 				    "Invalid group name %s, ignored"), 0, cp);
910 		}
911 	}
912 	if (*pair) {
913 		if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
914 			*uid = pw.pw_uid;
915 		} else
916 			smb_error(dgettext(TEXT_DOMAIN,
917 			    "Invalid user name %s, ignored"), 0, pair);
918 	}
919 
920 	return (0);
921 }
922 
923 /*
924  * Suport a securty options arg, i.e. -S lm,ntlm
925  * for testing various type of authenticators.
926  */
927 static struct nv
928 sectype_table[] = {
929 	{ "anon",	SMB_AT_ANON },
930 	{ "lm",		SMB_AT_LM1 },
931 	{ "ntlm",	SMB_AT_NTLM1 },
932 	{ "ntlm2",	SMB_AT_NTLM2 },
933 	{ "krb5",	SMB_AT_KRB5 },
934 	{ NULL,		0 },
935 };
936 int
937 smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
938 {
939 	const char *sep = ":;,";
940 	const char *p = arg;
941 	struct nv *nv;
942 	int nlen, tlen;
943 	int authflags = 0;
944 
945 	for (;;) {
946 		/* skip separators */
947 		tlen = strspn(p, sep);
948 		p += tlen;
949 
950 		nlen = strcspn(p, sep);
951 		if (nlen == 0)
952 			break;
953 
954 		/* This is rarely called, so not optimized. */
955 		for (nv = sectype_table; nv->name; nv++) {
956 			tlen = strlen(nv->name);
957 			if (tlen == nlen && 0 == strncmp(p, nv->name, tlen))
958 				break;
959 		}
960 		if (nv->name == NULL) {
961 			smb_error(dgettext(TEXT_DOMAIN,
962 			    "%s: invalid security options"), 0, p);
963 			return (EINVAL);
964 		}
965 		authflags |= nv->value;
966 		p += nlen;
967 	}
968 
969 	if (authflags)
970 		ctx->ct_authflags = authflags;
971 
972 	return (0);
973 }
974 
975 /*
976  * Commands use this with getopt.  See:
977  *   STDPARAM_OPT, STDPARAM_ARGS
978  * Called after smb_ctx_readrc().
979  */
980 int
981 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
982 {
983 	int error = 0;
984 	char *p, *cp;
985 	char tmp[1024];
986 
987 	switch (opt) {
988 	case 'A':
989 	case 'U':
990 		/* Handled in smb_ctx_init() */
991 		break;
992 	case 'I':
993 		error = smb_ctx_setsrvaddr(ctx, arg);
994 		break;
995 	case 'M':
996 		/* share connect rights - ignored */
997 		ctx->ct_flags |= SMBCF_SRIGHTS;
998 		break;
999 	case 'N':
1000 		ctx->ct_flags |= SMBCF_NOPWD;
1001 		break;
1002 	case 'O':
1003 		p = strdup(arg);
1004 		cp = strchr(p, '/');
1005 		if (cp)
1006 			*cp = '\0';
1007 		error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
1008 		free(p);
1009 		break;
1010 	case 'P':
1011 /*		ctx->ct_vopt |= SMBCOPT_PERMANENT; */
1012 		break;
1013 	case 'R':
1014 		/* retry count - ignored */
1015 		break;
1016 	case 'S':
1017 		/* Security options (undocumented, just for tests) */
1018 		error = smb_parse_secopts(ctx, arg);
1019 		break;
1020 	case 'T':
1021 		/* timeout - ignored */
1022 		break;
1023 	case 'D':	/* domain */
1024 	case 'W':	/* workgroup (legacy alias) */
1025 		error = smb_ctx_setdomain(ctx, tmp, TRUE);
1026 		break;
1027 	}
1028 	return (error);
1029 }
1030 
1031 
1032 /*
1033  * Original code injected iconv tables into the kernel.
1034  * Not sure if we'll need this or not...  REVISIT
1035  */
1036 #ifdef KICONV_SUPPORT
1037 static int
1038 smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
1039 {
1040 	int error = 0;
1041 
1042 	error = kiconv_add_xlat_table(to, from, tbl);
1043 	if (error && error != EEXIST) {
1044 		smb_error(dgettext(TEXT_DOMAIN,
1045 		    "can not setup kernel iconv table (%s:%s)"),
1046 		    error, from, to);
1047 		return (error);
1048 	}
1049 	return (error);
1050 }
1051 #endif	/* KICONV_SUPPORT */
1052 
1053 /*
1054  * Verify context info. before connect operation(s),
1055  * lookup specified server and try to fill all forgotten fields.
1056  * Legacy name used by commands.
1057  */
1058 int
1059 smb_ctx_resolve(struct smb_ctx *ctx)
1060 {
1061 	struct smbioc_ossn *ssn = &ctx->ct_ssn;
1062 	int error = 0;
1063 #ifdef KICONV_SUPPORT
1064 	uchar_t cstbl[256];
1065 	uint_t i;
1066 #endif
1067 
1068 	if (smb_debug)
1069 		dump_ctx("before smb_ctx_resolve", ctx);
1070 
1071 	ctx->ct_flags &= ~SMBCF_RESOLVED;
1072 
1073 	if (ctx->ct_fullserver == NULL) {
1074 		smb_error(dgettext(TEXT_DOMAIN,
1075 		    "no server name specified"), 0);
1076 		return (EINVAL);
1077 	}
1078 
1079 	if (ctx->ct_minlevel >= SMBL_SHARE &&
1080 	    ctx->ct_origshare == NULL) {
1081 		smb_error(dgettext(TEXT_DOMAIN,
1082 		    "no share name specified for %s@%s"),
1083 		    0, ssn->ssn_user, ctx->ct_fullserver);
1084 		return (EINVAL);
1085 	}
1086 	error = nb_ctx_resolve(ctx->ct_nb);
1087 	if (error)
1088 		return (error);
1089 #ifdef KICONV_SUPPORT
1090 	if (ssn->ioc_localcs[0] == 0)
1091 		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
1092 	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
1093 	if (error)
1094 		return (error);
1095 	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
1096 	if (error)
1097 		return (error);
1098 	if (ssn->ioc_servercs[0] != 0) {
1099 		for (i = 0; i < sizeof (cstbl); i++)
1100 			cstbl[i] = i;
1101 		nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
1102 		error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
1103 		    cstbl);
1104 		if (error)
1105 			return (error);
1106 		for (i = 0; i < sizeof (cstbl); i++)
1107 			cstbl[i] = i;
1108 		nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
1109 		error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
1110 		    cstbl);
1111 		if (error)
1112 			return (error);
1113 	}
1114 #endif	/* KICONV_SUPPORT */
1115 
1116 	/*
1117 	 * Lookup the IP address and fill in ct_addrinfo.
1118 	 *
1119 	 * Note: smb_ctx_getaddr() returns a EAI_xxx
1120 	 * error value like getaddrinfo(3), but this
1121 	 * function needs to return an errno value.
1122 	 */
1123 	error = smb_ctx_getaddr(ctx);
1124 	if (error) {
1125 		const char *ais = gai_strerror(error);
1126 		smb_error(dgettext(TEXT_DOMAIN,
1127 		    "can't resolve name\"%s\", %s"),
1128 		    0, ctx->ct_fullserver, ais);
1129 		return (ENODATA);
1130 	}
1131 	assert(ctx->ct_addrinfo != NULL);
1132 
1133 	/*
1134 	 * Empty user name means an explicit request for
1135 	 * NULL session setup, which is a special case.
1136 	 * (No SMB signing, per [MS-SMB] 3.3.5.3)
1137 	 */
1138 	if (ctx->ct_user[0] == '\0') {
1139 		/* Null user should have null domain too. */
1140 		ctx->ct_domain[0] = '\0';
1141 		ctx->ct_authflags = SMB_AT_ANON;
1142 		ctx->ct_vopt |= SMBVOPT_ANONYMOUS;
1143 		ctx->ct_vopt &= ~SMBVOPT_SIGNING_REQUIRED;
1144 	}
1145 
1146 	/*
1147 	 * If we have a user name but no password,
1148 	 * check for a keychain entry.
1149 	 * XXX: Only for auth NTLM?
1150 	 */
1151 	if (ctx->ct_user[0] != '\0') {
1152 		/*
1153 		 * Have a user name.
1154 		 * If we don't have a p/w yet,
1155 		 * try the keychain.
1156 		 */
1157 		if (ctx->ct_password[0] == '\0' &&
1158 		    smb_get_keychain(ctx) == 0) {
1159 			strlcpy(ctx->ct_password, "$HASH",
1160 			    sizeof (ctx->ct_password));
1161 		}
1162 
1163 		/*
1164 		 * Mask out disallowed auth types.
1165 		 */
1166 		ctx->ct_authflags &= ctx->ct_minauth;
1167 	}
1168 
1169 	if (ctx->ct_authflags == 0) {
1170 		smb_error(dgettext(TEXT_DOMAIN,
1171 		    "no valid auth. types"), 0);
1172 		return (ENOTSUP);
1173 	}
1174 
1175 	ctx->ct_flags |= SMBCF_RESOLVED;
1176 	if (smb_debug)
1177 		dump_ctx("after smb_ctx_resolve", ctx);
1178 
1179 	return (0);
1180 }
1181 
1182 /*
1183  * Note: The next three have NODIRECT binding so the
1184  * "fksmbcl" development tool can provide its own.
1185  */
1186 int
1187 smb_open_driver()
1188 {
1189 	int fd;
1190 
1191 	fd = open("/dev/"NSMB_NAME, O_RDWR);
1192 	if (fd < 0) {
1193 		return (-1);
1194 	}
1195 
1196 	/* This handle controls per-process resources. */
1197 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1198 
1199 	return (fd);
1200 }
1201 
1202 int
1203 nsmb_close(int fd)
1204 {
1205 	return (close(fd));
1206 }
1207 
1208 int
1209 nsmb_ioctl(int fd, int cmd, void *arg)
1210 {
1211 	return (ioctl(fd, cmd, arg));
1212 }
1213 
1214 
1215 int
1216 smb_ctx_gethandle(struct smb_ctx *ctx)
1217 {
1218 	int fd, err;
1219 	uint32_t version;
1220 
1221 	if (ctx->ct_dev_fd != -1) {
1222 		rpc_cleanup_smbctx(ctx);
1223 		nsmb_close(ctx->ct_dev_fd);
1224 		ctx->ct_dev_fd = -1;
1225 	}
1226 
1227 	fd = smb_open_driver();
1228 	if (fd < 0) {
1229 		err = errno;
1230 		smb_error(dgettext(TEXT_DOMAIN,
1231 		    "failed to open driver"), err);
1232 		return (err);
1233 	}
1234 
1235 	/*
1236 	 * Check the driver version (paranoia)
1237 	 */
1238 	if (nsmb_ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1239 		version = 0;
1240 	if (version != NSMB_VERSION) {
1241 		smb_error(dgettext(TEXT_DOMAIN,
1242 		    "incorrect driver version"), 0);
1243 		nsmb_close(fd);
1244 		return (ENODEV);
1245 	}
1246 
1247 	ctx->ct_dev_fd = fd;
1248 	return (0);
1249 }
1250 
1251 
1252 /*
1253  * Find or create a connection + logon session
1254  */
1255 int
1256 smb_ctx_get_ssn(struct smb_ctx *ctx)
1257 {
1258 	int err = 0;
1259 
1260 	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
1261 		return (EINVAL);
1262 
1263 	/*
1264 	 * Check whether the driver already has a VC
1265 	 * we can use.  If so, we're done!
1266 	 */
1267 	err = smb_ctx_findvc(ctx);
1268 	if (err == 0) {
1269 		DPRINT("found an existing VC");
1270 	} else {
1271 		/*
1272 		 * If we're authenticating (real user, not NULL session)
1273 		 * and we don't yet have a password, return EAUTH and
1274 		 * the caller will prompt for it and call again.
1275 		 */
1276 		if (ctx->ct_user[0] != '\0' &&
1277 		    ctx->ct_password[0] == '\0')
1278 			return (EAUTH);
1279 
1280 		/*
1281 		 * This calls the IOD to create a new session.
1282 		 */
1283 		DPRINT("setup a new VC");
1284 		err = smb_ctx_newvc(ctx);
1285 		if (err != 0)
1286 			return (err);
1287 
1288 		/*
1289 		 * Call findvc again.  The new VC sould be
1290 		 * found in the driver this time.
1291 		 */
1292 		err = smb_ctx_findvc(ctx);
1293 	}
1294 
1295 	return (err);
1296 }
1297 
1298 /*
1299  * Find or create a tree connection
1300  */
1301 int
1302 smb_ctx_get_tree(struct smb_ctx *ctx)
1303 {
1304 	smbioc_tcon_t *tcon = NULL;
1305 	int cmd, err = 0;
1306 
1307 	if (ctx->ct_dev_fd < 0 ||
1308 	    ctx->ct_origshare == NULL) {
1309 		return (EINVAL);
1310 	}
1311 
1312 	cmd = SMBIOC_TREE_CONNECT;
1313 	tcon = malloc(sizeof (*tcon));
1314 	if (tcon == NULL)
1315 		return (ENOMEM);
1316 	bzero(tcon, sizeof (*tcon));
1317 	tcon->tc_flags = SMBLK_CREATE;
1318 	tcon->tc_opt = 0;
1319 
1320 	/* The share name */
1321 	strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
1322 	    sizeof (tcon->tc_sh.sh_name));
1323 
1324 	/* The share "use" type. */
1325 	tcon->tc_sh.sh_use = ctx->ct_shtype_req;
1326 
1327 	/*
1328 	 * Todo: share passwords for share-level security.
1329 	 *
1330 	 * The driver does the actual TCON call.
1331 	 */
1332 	if (nsmb_ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1333 		err = errno;
1334 		goto out;
1335 	}
1336 
1337 	/*
1338 	 * Check the returned share type
1339 	 */
1340 	DPRINT("ret. sh_type: \"%d\"", tcon->tc_sh.sh_type);
1341 	if (ctx->ct_shtype_req != USE_WILDCARD &&
1342 	    ctx->ct_shtype_req != tcon->tc_sh.sh_type) {
1343 		smb_error(dgettext(TEXT_DOMAIN,
1344 		    "%s: incompatible share type"),
1345 		    0, ctx->ct_origshare);
1346 	}
1347 
1348 out:
1349 	if (tcon != NULL)
1350 		free(tcon);
1351 
1352 	return (err);
1353 }
1354 
1355 /*
1356  * Return the hflags2 word for an smb_ctx.
1357  */
1358 int
1359 smb_ctx_flags2(struct smb_ctx *ctx)
1360 {
1361 	uint16_t flags2;
1362 
1363 	if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
1364 		smb_error(dgettext(TEXT_DOMAIN,
1365 		    "can't get flags2 for a session"), errno);
1366 		return (-1);
1367 	}
1368 	return (flags2);
1369 }
1370 
1371 /*
1372  * Get the transport level session key.
1373  * Must already have an active SMB session.
1374  */
1375 int
1376 smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len)
1377 {
1378 	if (len < SMBIOC_HASH_SZ)
1379 		return (EINVAL);
1380 
1381 	if (nsmb_ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1382 		return (errno);
1383 
1384 	return (0);
1385 }
1386 
1387 /*
1388  * RC file parsing stuff
1389  */
1390 
1391 static struct nv
1392 minauth_table[] = {
1393 	/* Allowed auth. types */
1394 	{ "kerberos",	SMB_AT_KRB5 },
1395 	{ "ntlmv2",	SMB_AT_KRB5|SMB_AT_NTLM2 },
1396 	{ "ntlm",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
1397 	{ "lm",		SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
1398 	{ "none",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
1399 			SMB_AT_ANON },
1400 	{ NULL }
1401 };
1402 
1403 int
1404 smb_cf_minauth_from_str(char *str)
1405 {
1406 	struct nv *nvp;
1407 
1408 	for (nvp = minauth_table; nvp->name; nvp++)
1409 		if (strcmp(nvp->name, str) == 0)
1410 			return (nvp->value);
1411 	return (-1);
1412 }
1413 
1414 
1415 static struct nv
1416 smbver_table[] = {
1417 	{ "2.1",	SMB2_DIALECT_0210 },
1418 	{ "1",		1 },
1419 	{ NULL,		0 }
1420 };
1421 
1422 int
1423 smb_cf_version_from_str(char *str)
1424 {
1425 	struct nv *nvp;
1426 
1427 	for (nvp = smbver_table; nvp->name; nvp++)
1428 		if (strcmp(nvp->name, str) == 0)
1429 			return (nvp->value);
1430 	return (-1);
1431 }
1432 
1433 /*
1434  * level values:
1435  * 0 - default
1436  * 1 - server
1437  * 2 - server:user
1438  * 3 - server:user:share
1439  */
1440 static int
1441 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
1442 {
1443 	char *p;
1444 	int ival;
1445 	int error;
1446 	int minver, maxver;
1447 
1448 #ifdef	KICONV_SUPPORT
1449 	if (level > 0) {
1450 		rc_getstringptr(smb_rc, sname, "charsets", &p);
1451 		if (p) {
1452 			error = smb_ctx_setcharset(ctx, p);
1453 			if (error)
1454 				smb_error(dgettext(TEXT_DOMAIN,
1455 	"charset specification in the section '%s' ignored"),
1456 				    error, sname);
1457 		}
1458 	}
1459 #endif
1460 
1461 	if (level <= 1) {
1462 		/* Section is: [default] or [server] */
1463 
1464 		/*
1465 		 * Handle min_protocol, max_protocol
1466 		 * (SMB protocol versions)
1467 		 */
1468 		minver = -1;
1469 		rc_getstringptr(smb_rc, sname, "min_protocol", &p);
1470 		if (p != NULL) {
1471 			minver = smb_cf_version_from_str(p);
1472 			if (minver == -1) {
1473 				smb_error(dgettext(TEXT_DOMAIN,
1474 "invalid min_protocol value \"%s\" specified in the section %s"),
1475 				    0, p, sname);
1476 			}
1477 		}
1478 		maxver = -1;
1479 		rc_getstringptr(smb_rc, sname, "max_protocol", &p);
1480 		if (p != NULL) {
1481 			maxver = smb_cf_version_from_str(p);
1482 			if (maxver == -1) {
1483 				smb_error(dgettext(TEXT_DOMAIN,
1484 "invalid max_protocol value \"%s\" specified in the section %s"),
1485 				    0, p, sname);
1486 			}
1487 		}
1488 
1489 		/*
1490 		 * If setting both min/max protocol,
1491 		 * validate against each other
1492 		 */
1493 		if (minver != -1 && maxver != -1) {
1494 			if (minver > maxver) {
1495 				smb_error(dgettext(TEXT_DOMAIN,
1496 "invalid min/max protocol combination in the section %s"),
1497 				    0, sname);
1498 			} else {
1499 				ctx->ct_minver = minver;
1500 				ctx->ct_maxver = maxver;
1501 			}
1502 		}
1503 
1504 		/*
1505 		 * Setting just min or max, validate against
1506 		 * current settings
1507 		 */
1508 		if (minver != -1) {
1509 			if (minver > ctx->ct_maxver) {
1510 				smb_error(dgettext(TEXT_DOMAIN,
1511 "invalid min/max protocol combination in the section %s"),
1512 				    0, sname);
1513 			} else {
1514 				ctx->ct_minver = minver;
1515 			}
1516 		}
1517 		if (maxver != -1) {
1518 			if (maxver < ctx->ct_minver) {
1519 				smb_error(dgettext(TEXT_DOMAIN,
1520 "invalid min/max protocol combination in the section %s"),
1521 				    0, sname);
1522 			} else {
1523 				ctx->ct_maxver = maxver;
1524 			}
1525 		}
1526 
1527 		rc_getstringptr(smb_rc, sname, "minauth", &p);
1528 		if (p) {
1529 			/*
1530 			 * "minauth" was set in this section; override
1531 			 * the current minimum authentication setting.
1532 			 */
1533 			ival = smb_cf_minauth_from_str(p);
1534 			if (ival != -1) {
1535 				ctx->ct_minauth = ival;
1536 			} else {
1537 				/*
1538 				 * Unknown minimum authentication level.
1539 				 */
1540 				smb_error(dgettext(TEXT_DOMAIN,
1541 "invalid minimum authentication level \"%s\" specified in the section %s"),
1542 				    0, p, sname);
1543 				return (EINVAL);
1544 			}
1545 		}
1546 
1547 		rc_getstringptr(smb_rc, sname, "signing", &p);
1548 		if (p) {
1549 			/*
1550 			 * "signing" was set in this section; override
1551 			 * the current signing settings.  Note:
1552 			 * setsigning flags are: enable, require
1553 			 */
1554 			if (strcmp(p, "disabled") == 0) {
1555 				(void) smb_ctx_setsigning(ctx, FALSE, FALSE);
1556 			} else if (strcmp(p, "enabled") == 0) {
1557 				(void) smb_ctx_setsigning(ctx, TRUE, FALSE);
1558 			} else if (strcmp(p, "required") == 0) {
1559 				(void) smb_ctx_setsigning(ctx, TRUE, TRUE);
1560 			} else {
1561 				/*
1562 				 * Unknown "signing" value.
1563 				 */
1564 				smb_error(dgettext(TEXT_DOMAIN,
1565 "invalid signing policy \"%s\" specified in the section %s"),
1566 				    0, p, sname);
1567 				return (EINVAL);
1568 			}
1569 		}
1570 
1571 		/*
1572 		 * Domain name.  Allow both keywords:
1573 		 * "workgroup", "domain"
1574 		 *
1575 		 * Note: these are NOT marked "from CMD".
1576 		 * See long comment at smb_ctx_init()
1577 		 */
1578 		rc_getstringptr(smb_rc, sname, "workgroup", &p);
1579 		if (p) {
1580 			error = smb_ctx_setdomain(ctx, p, 0);
1581 			if (error)
1582 				smb_error(dgettext(TEXT_DOMAIN,
1583 				    "workgroup specification in the "
1584 				    "section '%s' ignored"), error, sname);
1585 		}
1586 		rc_getstringptr(smb_rc, sname, "domain", &p);
1587 		if (p) {
1588 			error = smb_ctx_setdomain(ctx, p, 0);
1589 			if (error)
1590 				smb_error(dgettext(TEXT_DOMAIN,
1591 				    "domain specification in the "
1592 				    "section '%s' ignored"), error, sname);
1593 		}
1594 
1595 		rc_getstringptr(smb_rc, sname, "user", &p);
1596 		if (p) {
1597 			error = smb_ctx_setuser(ctx, p, 0);
1598 			if (error)
1599 				smb_error(dgettext(TEXT_DOMAIN,
1600 				    "user specification in the "
1601 				    "section '%s' ignored"), error, sname);
1602 		}
1603 	}
1604 
1605 	if (level == 1) {
1606 		/* Section is: [server] */
1607 		rc_getstringptr(smb_rc, sname, "addr", &p);
1608 		if (p) {
1609 			error = smb_ctx_setsrvaddr(ctx, p);
1610 			if (error) {
1611 				smb_error(dgettext(TEXT_DOMAIN,
1612 				    "invalid address specified in section %s"),
1613 				    0, sname);
1614 				return (error);
1615 			}
1616 		}
1617 	}
1618 
1619 	rc_getstringptr(smb_rc, sname, "password", &p);
1620 	if (p) {
1621 		error = smb_ctx_setpassword(ctx, p, 0);
1622 		if (error)
1623 			smb_error(dgettext(TEXT_DOMAIN,
1624 	    "password specification in the section '%s' ignored"),
1625 			    error, sname);
1626 	}
1627 
1628 	return (0);
1629 }
1630 
1631 /*
1632  * read rc file as follows:
1633  * 0: read [default] section
1634  * 1: override with [server] section
1635  * 2: override with [server:user] section
1636  * 3: override with [server:user:share] section
1637  * Since absence of rcfile is not fatal, silently ignore this fact.
1638  * smb_rc file should be closed by caller.
1639  */
1640 int
1641 smb_ctx_readrc(struct smb_ctx *ctx)
1642 {
1643 	char pwbuf[NSS_BUFLEN_PASSWD];
1644 	struct passwd pw;
1645 	char *sname = NULL;
1646 	int sname_max;
1647 	int err = 0;
1648 
1649 	/*
1650 	 * If the user name is not specified some other way,
1651 	 * use the current user name.  Also save the homedir.
1652 	 * NB: ct_home=NULL is allowed, and we don't want to
1653 	 * bail out with an error for a missing ct_home.
1654 	 */
1655 	if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
1656 		if (ctx->ct_user[0] == 0)
1657 			(void) smb_ctx_setuser(ctx, pw.pw_name, B_FALSE);
1658 		if (ctx->ct_home == NULL)
1659 			ctx->ct_home = strdup(pw.pw_dir);
1660 	}
1661 
1662 	if ((err = smb_open_rcfile(ctx->ct_home)) != 0) {
1663 		DPRINT("smb_open_rcfile, err=%d", err);
1664 		/* ignore any error here */
1665 		return (0);
1666 	}
1667 
1668 	sname_max = 3 * SMBIOC_MAX_NAME + 4;
1669 	sname = malloc(sname_max);
1670 	if (sname == NULL) {
1671 		err = ENOMEM;
1672 		goto done;
1673 	}
1674 
1675 	/*
1676 	 * default parameters (level=0)
1677 	 */
1678 	smb_ctx_readrcsection(ctx, "default", 0);
1679 	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
1680 
1681 	/*
1682 	 * If we don't have a server name, we can't read any of the
1683 	 * [server...] sections.
1684 	 */
1685 	if (ctx->ct_fullserver == NULL)
1686 		goto done;
1687 	/*
1688 	 * SERVER parameters.
1689 	 */
1690 	smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
1691 
1692 	/*
1693 	 * If we don't have a user name, we can't read any of the
1694 	 * [server:user...] sections.
1695 	 */
1696 	if (ctx->ct_user[0] == 0)
1697 		goto done;
1698 	/*
1699 	 * SERVER:USER parameters
1700 	 */
1701 	snprintf(sname, sname_max, "%s:%s",
1702 	    ctx->ct_fullserver,
1703 	    ctx->ct_user);
1704 	smb_ctx_readrcsection(ctx, sname, 2);
1705 
1706 
1707 	/*
1708 	 * If we don't have a share name, we can't read any of the
1709 	 * [server:user:share] sections.
1710 	 */
1711 	if (ctx->ct_origshare == NULL)
1712 		goto done;
1713 	/*
1714 	 * SERVER:USER:SHARE parameters
1715 	 */
1716 	snprintf(sname, sname_max, "%s:%s:%s",
1717 	    ctx->ct_fullserver,
1718 	    ctx->ct_user,
1719 	    ctx->ct_origshare);
1720 	smb_ctx_readrcsection(ctx, sname, 3);
1721 
1722 done:
1723 	if (sname)
1724 		free(sname);
1725 	smb_close_rcfile();
1726 	if (smb_debug)
1727 		dump_ctx("after smb_ctx_readrc", ctx);
1728 	if (err)
1729 		DPRINT("err=%d\n", err);
1730 
1731 	return (err);
1732 }
1733 
1734 void
1735 smbfs_set_default_domain(const char *domain)
1736 {
1737 	strlcpy(default_domain, domain, sizeof (default_domain));
1738 }
1739 
1740 void
1741 smbfs_set_default_user(const char *user)
1742 {
1743 	strlcpy(default_user, user, sizeof (default_user));
1744 }
1745