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