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
rpc_cleanup_smbctx(struct smb_ctx * ctx)110 rpc_cleanup_smbctx(struct smb_ctx *ctx)
111 {
112 if (close_hook)
113 (*close_hook)(ctx);
114 }
115 void
smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)116 smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
117 {
118 close_hook = hook;
119 }
120
121 void
dump_ctx_flags(int flags)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
dump_iod_ssn(smb_iod_ssn_t * is)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
dump_ctx(char * where,struct smb_ctx * ctx)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
smb_ctx_alloc(struct smb_ctx ** ctx_pp)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
smb_ctx_init(struct smb_ctx * ctx)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
smb_ctx_scan_argv(struct smb_ctx * ctx,int argc,char ** argv,int minlevel,int maxlevel,int sharetype)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
smb_ctx_free(smb_ctx_t * ctx)391 smb_ctx_free(smb_ctx_t *ctx)
392 {
393 smb_ctx_done(ctx);
394 free(ctx);
395 }
396
397 void
smb_ctx_done(struct smb_ctx * ctx)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
smb_ctx_parseunc(struct smb_ctx * ctx,const char * unc,int minlevel,int maxlevel,int sharetype,const char ** next)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
smb_ctx_setcharset(struct smb_ctx * ctx,const char * arg)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
smb_ctx_setauthflags(struct smb_ctx * ctx,int flags)657 smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
658 {
659 ctx->ct_authflags = flags;
660 return (0);
661 }
662
663 int
smb_ctx_setfullserver(struct smb_ctx * ctx,const char * name)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
smb_ctx_setserver(struct smb_ctx * ctx,const char * name)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
smb_ctx_setuser(struct smb_ctx * ctx,const char * name,int from_cmd)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
smb_ctx_setdomain(struct smb_ctx * ctx,const char * name,int from_cmd)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
smb_ctx_setpassword(struct smb_ctx * ctx,const char * passwd,int from_cmd)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
smb_ctx_setpwhash(smb_ctx_t * ctx,const uchar_t * nthash,const uchar_t * lmhash)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
smb_ctx_setshare(struct smb_ctx * ctx,const char * share,int stype)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
smb_ctx_setsrvaddr(struct smb_ctx * ctx,const char * addr)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
smb_ctx_setsigning(struct smb_ctx * ctx,int enable,int require)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
smb_ctx_setminver(struct smb_ctx * ctx,int ver)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
smb_ctx_setmaxver(struct smb_ctx * ctx,int ver)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
smb_parse_owner(char * pair,uid_t * uid,gid_t * gid)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
smb_parse_secopts(struct smb_ctx * ctx,const char * arg)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
smb_ctx_opt(struct smb_ctx * ctx,int opt,const char * arg)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
smb_addiconvtbl(const char * to,const char * from,const uchar_t * tbl)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
smb_ctx_resolve(struct smb_ctx * ctx)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
smb_open_driver()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
nsmb_close(int fd)1203 nsmb_close(int fd)
1204 {
1205 return (close(fd));
1206 }
1207
1208 int
nsmb_ioctl(int fd,int cmd,void * arg)1209 nsmb_ioctl(int fd, int cmd, void *arg)
1210 {
1211 return (ioctl(fd, cmd, arg));
1212 }
1213
1214
1215 int
smb_ctx_gethandle(struct smb_ctx * ctx)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
smb_ctx_get_ssn(struct smb_ctx * ctx)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
smb_ctx_get_tree(struct smb_ctx * ctx)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
smb_ctx_flags2(struct smb_ctx * ctx)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
smb_fh_getssnkey(int dev_fd,uchar_t * key,size_t len)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
smb_cf_minauth_from_str(char * str)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 * SMB 2.1 is the oldest SMB2 dialect implemented (we skipped SMB 2.002)
1416 * so if we see a_protocol value of just "2" assume they meant 2.1
1417 */
1418 static struct nv
1419 smbver_table[] = {
1420 { "3.02", SMB2_DIALECT_0302 },
1421 { "3.0", SMB2_DIALECT_0300 },
1422 { "2.1", SMB2_DIALECT_0210 },
1423 { "2", SMB2_DIALECT_0210 },
1424 { "1", 1 },
1425 { NULL, 0 }
1426 };
1427
1428 int
smb_cf_version_from_str(char * str)1429 smb_cf_version_from_str(char *str)
1430 {
1431 struct nv *nvp;
1432
1433 for (nvp = smbver_table; nvp->name; nvp++)
1434 if (strcmp(nvp->name, str) == 0)
1435 return (nvp->value);
1436 return (-1);
1437 }
1438
1439 /*
1440 * level values:
1441 * 0 - default
1442 * 1 - server
1443 * 2 - server:user
1444 * 3 - server:user:share
1445 */
1446 static int
smb_ctx_readrcsection(struct smb_ctx * ctx,const char * sname,int level)1447 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
1448 {
1449 char *p;
1450 int ival;
1451 int error;
1452 int minver, maxver;
1453
1454 #ifdef KICONV_SUPPORT
1455 if (level > 0) {
1456 rc_getstringptr(smb_rc, sname, "charsets", &p);
1457 if (p) {
1458 error = smb_ctx_setcharset(ctx, p);
1459 if (error)
1460 smb_error(dgettext(TEXT_DOMAIN,
1461 "charset specification in the section '%s' ignored"),
1462 error, sname);
1463 }
1464 }
1465 #endif
1466
1467 if (level <= 1) {
1468 /* Section is: [default] or [server] */
1469
1470 /*
1471 * Handle min_protocol, max_protocol
1472 * (SMB protocol versions)
1473 */
1474 minver = -1;
1475 rc_getstringptr(smb_rc, sname, "min_protocol", &p);
1476 if (p != NULL) {
1477 minver = smb_cf_version_from_str(p);
1478 if (minver == -1) {
1479 smb_error(dgettext(TEXT_DOMAIN,
1480 "invalid min_protocol value \"%s\" specified in the section %s"),
1481 0, p, sname);
1482 }
1483 }
1484 maxver = -1;
1485 rc_getstringptr(smb_rc, sname, "max_protocol", &p);
1486 if (p != NULL) {
1487 maxver = smb_cf_version_from_str(p);
1488 if (maxver == -1) {
1489 smb_error(dgettext(TEXT_DOMAIN,
1490 "invalid max_protocol value \"%s\" specified in the section %s"),
1491 0, p, sname);
1492 }
1493 }
1494
1495 /*
1496 * If setting both min/max protocol,
1497 * validate against each other
1498 */
1499 if (minver != -1 && maxver != -1) {
1500 if (minver > maxver) {
1501 smb_error(dgettext(TEXT_DOMAIN,
1502 "invalid min/max protocol combination in the section %s"),
1503 0, sname);
1504 } else {
1505 ctx->ct_minver = minver;
1506 ctx->ct_maxver = maxver;
1507 }
1508 }
1509
1510 /*
1511 * Setting just min or max, validate against
1512 * current settings
1513 */
1514 if (minver != -1) {
1515 if (minver > ctx->ct_maxver) {
1516 smb_error(dgettext(TEXT_DOMAIN,
1517 "invalid min/max protocol combination in the section %s"),
1518 0, sname);
1519 } else {
1520 ctx->ct_minver = minver;
1521 }
1522 }
1523 if (maxver != -1) {
1524 if (maxver < ctx->ct_minver) {
1525 smb_error(dgettext(TEXT_DOMAIN,
1526 "invalid min/max protocol combination in the section %s"),
1527 0, sname);
1528 } else {
1529 ctx->ct_maxver = maxver;
1530 }
1531 }
1532
1533 rc_getstringptr(smb_rc, sname, "minauth", &p);
1534 if (p) {
1535 /*
1536 * "minauth" was set in this section; override
1537 * the current minimum authentication setting.
1538 */
1539 ival = smb_cf_minauth_from_str(p);
1540 if (ival != -1) {
1541 ctx->ct_minauth = ival;
1542 } else {
1543 /*
1544 * Unknown minimum authentication level.
1545 */
1546 smb_error(dgettext(TEXT_DOMAIN,
1547 "invalid minimum authentication level \"%s\" specified in the section %s"),
1548 0, p, sname);
1549 return (EINVAL);
1550 }
1551 }
1552
1553 rc_getstringptr(smb_rc, sname, "signing", &p);
1554 if (p) {
1555 /*
1556 * "signing" was set in this section; override
1557 * the current signing settings. Note:
1558 * setsigning flags are: enable, require
1559 */
1560 if (strcmp(p, "disabled") == 0) {
1561 (void) smb_ctx_setsigning(ctx, FALSE, FALSE);
1562 } else if (strcmp(p, "enabled") == 0) {
1563 (void) smb_ctx_setsigning(ctx, TRUE, FALSE);
1564 } else if (strcmp(p, "required") == 0) {
1565 (void) smb_ctx_setsigning(ctx, TRUE, TRUE);
1566 } else {
1567 /*
1568 * Unknown "signing" value.
1569 */
1570 smb_error(dgettext(TEXT_DOMAIN,
1571 "invalid signing policy \"%s\" specified in the section %s"),
1572 0, p, sname);
1573 return (EINVAL);
1574 }
1575 }
1576
1577 /*
1578 * Domain name. Allow both keywords:
1579 * "workgroup", "domain"
1580 *
1581 * Note: these are NOT marked "from CMD".
1582 * See long comment at smb_ctx_init()
1583 */
1584 rc_getstringptr(smb_rc, sname, "workgroup", &p);
1585 if (p) {
1586 error = smb_ctx_setdomain(ctx, p, 0);
1587 if (error)
1588 smb_error(dgettext(TEXT_DOMAIN,
1589 "workgroup specification in the "
1590 "section '%s' ignored"), error, sname);
1591 }
1592 rc_getstringptr(smb_rc, sname, "domain", &p);
1593 if (p) {
1594 error = smb_ctx_setdomain(ctx, p, 0);
1595 if (error)
1596 smb_error(dgettext(TEXT_DOMAIN,
1597 "domain specification in the "
1598 "section '%s' ignored"), error, sname);
1599 }
1600
1601 rc_getstringptr(smb_rc, sname, "user", &p);
1602 if (p) {
1603 error = smb_ctx_setuser(ctx, p, 0);
1604 if (error)
1605 smb_error(dgettext(TEXT_DOMAIN,
1606 "user specification in the "
1607 "section '%s' ignored"), error, sname);
1608 }
1609 }
1610
1611 if (level == 1) {
1612 /* Section is: [server] */
1613 rc_getstringptr(smb_rc, sname, "addr", &p);
1614 if (p) {
1615 error = smb_ctx_setsrvaddr(ctx, p);
1616 if (error) {
1617 smb_error(dgettext(TEXT_DOMAIN,
1618 "invalid address specified in section %s"),
1619 0, sname);
1620 return (error);
1621 }
1622 }
1623 }
1624
1625 rc_getstringptr(smb_rc, sname, "password", &p);
1626 if (p) {
1627 error = smb_ctx_setpassword(ctx, p, 0);
1628 if (error)
1629 smb_error(dgettext(TEXT_DOMAIN,
1630 "password specification in the section '%s' ignored"),
1631 error, sname);
1632 }
1633
1634 return (0);
1635 }
1636
1637 /*
1638 * read rc file as follows:
1639 * 0: read [default] section
1640 * 1: override with [server] section
1641 * 2: override with [server:user] section
1642 * 3: override with [server:user:share] section
1643 * Since absence of rcfile is not fatal, silently ignore this fact.
1644 * smb_rc file should be closed by caller.
1645 */
1646 int
smb_ctx_readrc(struct smb_ctx * ctx)1647 smb_ctx_readrc(struct smb_ctx *ctx)
1648 {
1649 char pwbuf[NSS_BUFLEN_PASSWD];
1650 struct passwd pw;
1651 char *sname = NULL;
1652 int sname_max;
1653 int err = 0;
1654
1655 /*
1656 * If the user name is not specified some other way,
1657 * use the current user name. Also save the homedir.
1658 * NB: ct_home=NULL is allowed, and we don't want to
1659 * bail out with an error for a missing ct_home.
1660 */
1661 if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
1662 if (ctx->ct_user[0] == 0)
1663 (void) smb_ctx_setuser(ctx, pw.pw_name, B_FALSE);
1664 if (ctx->ct_home == NULL)
1665 ctx->ct_home = strdup(pw.pw_dir);
1666 }
1667
1668 if ((err = smb_open_rcfile(ctx->ct_home)) != 0) {
1669 DPRINT("smb_open_rcfile, err=%d", err);
1670 /* ignore any error here */
1671 return (0);
1672 }
1673
1674 sname_max = 3 * SMBIOC_MAX_NAME + 4;
1675 sname = malloc(sname_max);
1676 if (sname == NULL) {
1677 err = ENOMEM;
1678 goto done;
1679 }
1680
1681 /*
1682 * default parameters (level=0)
1683 */
1684 smb_ctx_readrcsection(ctx, "default", 0);
1685 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
1686
1687 /*
1688 * If we don't have a server name, we can't read any of the
1689 * [server...] sections.
1690 */
1691 if (ctx->ct_fullserver == NULL)
1692 goto done;
1693 /*
1694 * SERVER parameters.
1695 */
1696 smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
1697
1698 /*
1699 * If we don't have a user name, we can't read any of the
1700 * [server:user...] sections.
1701 */
1702 if (ctx->ct_user[0] == 0)
1703 goto done;
1704 /*
1705 * SERVER:USER parameters
1706 */
1707 snprintf(sname, sname_max, "%s:%s",
1708 ctx->ct_fullserver,
1709 ctx->ct_user);
1710 smb_ctx_readrcsection(ctx, sname, 2);
1711
1712
1713 /*
1714 * If we don't have a share name, we can't read any of the
1715 * [server:user:share] sections.
1716 */
1717 if (ctx->ct_origshare == NULL)
1718 goto done;
1719 /*
1720 * SERVER:USER:SHARE parameters
1721 */
1722 snprintf(sname, sname_max, "%s:%s:%s",
1723 ctx->ct_fullserver,
1724 ctx->ct_user,
1725 ctx->ct_origshare);
1726 smb_ctx_readrcsection(ctx, sname, 3);
1727
1728 done:
1729 if (sname)
1730 free(sname);
1731 smb_close_rcfile();
1732 if (smb_debug)
1733 dump_ctx("after smb_ctx_readrc", ctx);
1734 if (err)
1735 DPRINT("err=%d\n", err);
1736
1737 return (err);
1738 }
1739
1740 void
smbfs_set_default_domain(const char * domain)1741 smbfs_set_default_domain(const char *domain)
1742 {
1743 strlcpy(default_domain, domain, sizeof (default_domain));
1744 }
1745
1746 void
smbfs_set_default_user(const char * user)1747 smbfs_set_default_user(const char *user)
1748 {
1749 strlcpy(default_user, user, sizeof (default_user));
1750 }
1751