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