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 */
38
39 #include <sys/param.h>
40 #include <sys/ioctl.h>
41 #include <sys/time.h>
42 #include <sys/mount.h>
43 #include <sys/types.h>
44 #include <sys/byteorder.h>
45
46 #include <fcntl.h>
47 #include <ctype.h>
48 #include <errno.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <strings.h>
52 #include <stdlib.h>
53 #include <pwd.h>
54 #include <grp.h>
55 #include <unistd.h>
56 #include <libintl.h>
57 #include <assert.h>
58 #include <nss_dbdefs.h>
59
60 #include <cflib.h>
61 #include <netsmb/smb_lib.h>
62 #include <netsmb/netbios.h>
63 #include <netsmb/nb_lib.h>
64 #include <netsmb/smb_dev.h>
65
66 #include "charsets.h"
67 #include "spnego.h"
68 #include "derparse.h"
69 #include "private.h"
70 #include "ntlm.h"
71
72 #ifndef FALSE
73 #define FALSE 0
74 #endif
75 #ifndef TRUE
76 #define TRUE 1
77 #endif
78
79 struct nv {
80 char *name;
81 int value;
82 };
83
84 /* These two may be set by commands. */
85 int smb_debug, smb_verbose;
86
87 /*
88 * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
89 */
90 const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
91
92 /*
93 * Give the RPC library a callback hook that will be
94 * called whenever we destroy or reinit an smb_ctx_t.
95 * The name rpc_cleanup_smbctx() is legacy, and was
96 * originally a direct call into the RPC code.
97 */
98 static smb_ctx_close_hook_t close_hook;
99 static void
rpc_cleanup_smbctx(struct smb_ctx * ctx)100 rpc_cleanup_smbctx(struct smb_ctx *ctx)
101 {
102 if (close_hook)
103 (*close_hook)(ctx);
104 }
105 void
smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)106 smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
107 {
108 close_hook = hook;
109 }
110
111 void
dump_ctx_flags(int flags)112 dump_ctx_flags(int flags)
113 {
114 printf(" Flags: ");
115 if (flags == 0)
116 printf("0");
117 if (flags & SMBCF_NOPWD)
118 printf("NOPWD ");
119 if (flags & SMBCF_SRIGHTS)
120 printf("SRIGHTS ");
121 if (flags & SMBCF_LOCALE)
122 printf("LOCALE ");
123 if (flags & SMBCF_CMD_DOM)
124 printf("CMD_DOM ");
125 if (flags & SMBCF_CMD_USR)
126 printf("CMD_USR ");
127 if (flags & SMBCF_CMD_PW)
128 printf("CMD_PW ");
129 if (flags & SMBCF_RESOLVED)
130 printf("RESOLVED ");
131 if (flags & SMBCF_KCBAD)
132 printf("KCBAD ");
133 if (flags & SMBCF_KCFOUND)
134 printf("KCFOUND ");
135 if (flags & SMBCF_BROWSEOK)
136 printf("BROWSEOK ");
137 if (flags & SMBCF_AUTHREQ)
138 printf("AUTHREQ ");
139 if (flags & SMBCF_KCSAVE)
140 printf("KCSAVE ");
141 if (flags & SMBCF_XXX)
142 printf("XXX ");
143 if (flags & SMBCF_SSNACTIVE)
144 printf("SSNACTIVE ");
145 if (flags & SMBCF_KCDOMAIN)
146 printf("KCDOMAIN ");
147 printf("\n");
148 }
149
150 void
dump_iod_ssn(smb_iod_ssn_t * is)151 dump_iod_ssn(smb_iod_ssn_t *is)
152 {
153 static const char zeros[NTLM_HASH_SZ] = {0};
154 struct smbioc_ossn *ssn = &is->iod_ossn;
155
156 printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
157 dump_sockaddr(&ssn->ssn_srvaddr.sa);
158 printf(" dom=\"%s\", user=\"%s\"\n",
159 ssn->ssn_domain, ssn->ssn_user);
160 printf(" ct_vopt=0x%x, ct_owner=%d\n",
161 ssn->ssn_vopt, ssn->ssn_owner);
162 printf(" ct_authflags=0x%x\n", is->iod_authflags);
163
164 printf(" ct_nthash:");
165 if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
166 smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
167 else
168 printf(" {0}\n");
169
170 printf(" ct_lmhash:");
171 if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
172 smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
173 else
174 printf(" {0}\n");
175 }
176
177 void
dump_ctx(char * where,struct smb_ctx * ctx)178 dump_ctx(char *where, struct smb_ctx *ctx)
179 {
180 printf("context %s:\n", where);
181 dump_ctx_flags(ctx->ct_flags);
182
183 if (ctx->ct_locname)
184 printf(" localname=\"%s\"", ctx->ct_locname);
185 else
186 printf(" localname=NULL");
187
188 if (ctx->ct_fullserver)
189 printf(" fullserver=\"%s\"", ctx->ct_fullserver);
190 else
191 printf(" fullserver=NULL");
192
193 if (ctx->ct_srvaddr_s)
194 printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
195 else
196 printf(" srvaddr_s=NULL\n");
197
198 if (ctx->ct_addrinfo)
199 dump_addrinfo(ctx->ct_addrinfo);
200 else
201 printf(" ct_addrinfo = NULL\n");
202
203 dump_iod_ssn(&ctx->ct_iod_ssn);
204
205 printf(" share_name=\"%s\", share_type=%d\n",
206 ctx->ct_origshare ? ctx->ct_origshare : "",
207 ctx->ct_shtype_req);
208
209 /* dump_iod_work()? */
210 }
211
212 int
smb_ctx_alloc(struct smb_ctx ** ctx_pp)213 smb_ctx_alloc(struct smb_ctx **ctx_pp)
214 {
215 smb_ctx_t *ctx;
216 int err;
217
218 ctx = malloc(sizeof (*ctx));
219 if (ctx == NULL)
220 return (ENOMEM);
221 err = smb_ctx_init(ctx);
222 if (err != 0) {
223 free(ctx);
224 return (err);
225 }
226 *ctx_pp = ctx;
227 return (0);
228 }
229
230 /*
231 * Initialize an smb_ctx struct (defaults)
232 */
233 int
smb_ctx_init(struct smb_ctx * ctx)234 smb_ctx_init(struct smb_ctx *ctx)
235 {
236 char pwbuf[NSS_BUFLEN_PASSWD];
237 struct passwd pw;
238 int error = 0;
239
240 bzero(ctx, sizeof (*ctx));
241
242 error = nb_ctx_create(&ctx->ct_nb);
243 if (error)
244 return (error);
245
246 ctx->ct_dev_fd = -1;
247 ctx->ct_door_fd = -1;
248 ctx->ct_tran_fd = -1;
249 ctx->ct_parsedlevel = SMBL_NONE;
250 ctx->ct_minlevel = SMBL_NONE;
251 ctx->ct_maxlevel = SMBL_PATH;
252
253 /* Fill in defaults */
254 ctx->ct_vopt = SMBVOPT_EXT_SEC;
255 ctx->ct_owner = SMBM_ANY_OWNER;
256 ctx->ct_authflags = SMB_AT_DEFAULT;
257 ctx->ct_minauth = SMB_AT_DEFAULT;
258
259 error = nb_ctx_setscope(ctx->ct_nb, "");
260 if (error)
261 return (error);
262
263 /*
264 * if the user name is not specified some other way,
265 * use the current user name (built-in default)
266 */
267 if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
268 error = smb_ctx_setuser(ctx, pw.pw_name, 0);
269 if (error)
270 return (error);
271 ctx->ct_home = strdup(pw.pw_name);
272 if (ctx->ct_home == NULL)
273 return (ENOMEM);
274 }
275
276 /*
277 * Set a built-in default domain (workgroup).
278 * Using the Windows/NT default for now.
279 */
280 error = smb_ctx_setdomain(ctx, "WORKGROUP", 0);
281 if (error)
282 return (error);
283
284 return (error);
285 }
286
287 /*
288 * "Scan" the command line args to find the server name,
289 * user name, and share name, as needed. We need these
290 * before reading the RC files and/or sharectl values.
291 *
292 * The sequence for getting all the members filled in
293 * has some tricky aspects. Here's how it works:
294 *
295 * The search order for options is as follows:
296 * command line options
297 * values parsed from UNC path (cmd)
298 * values from RC file (per-user)
299 * values from SMF (system-wide)
300 * built-in defaults
301 *
302 * Normally, one would simply get all the values starting with
303 * the bottom of the above list and working to the top, and
304 * overwriting values as you go. But we need an exception.
305 *
306 * In this function, we parse the UNC path and command line options,
307 * because we need (at least) the server name when we're getting the
308 * SMF and RC file values. However, values we get from the command
309 * should not be overwritten by SMF or RC file parsing, so we mark
310 * values from the command as "from CMD" and the RC file parser
311 * leaves in place any values so marked. See: SMBCF_CMD_*
312 *
313 * The semantics of these flags are: "This value came from the
314 * current command instance, not from sources that may apply to
315 * multiple commands." (Different from the old "FROMUSR" flag.)
316 *
317 * Note that smb_ctx_opt() is called later to handle the
318 * remaining options, which should be ignored here.
319 * The (magic) leading ":" in cf_getopt() makes it
320 * ignore options not in the options string.
321 */
322 int
smb_ctx_scan_argv(struct smb_ctx * ctx,int argc,char ** argv,int minlevel,int maxlevel,int sharetype)323 smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
324 int minlevel, int maxlevel, int sharetype)
325 {
326 int ind, opt, error = 0;
327 int aflg = 0, uflg = 0;
328 const char *arg;
329
330 /*
331 * Parse options, if any. Values from here too
332 * are marked as "from CMD".
333 */
334 if (argv == NULL)
335 return (0);
336
337 ctx->ct_minlevel = minlevel;
338 ctx->ct_maxlevel = maxlevel;
339 ctx->ct_shtype_req = sharetype;
340
341 cf_opt_lock();
342 /* Careful: no return/goto before cf_opt_unlock! */
343 while (error == 0) {
344 opt = cf_getopt(argc, argv, STDPARAM_OPT);
345 if (opt == -1)
346 break;
347 arg = cf_optarg;
348 /* NB: handle most in smb_ctx_opt */
349 switch (opt) {
350 case 'A':
351 aflg = 1;
352 error = smb_ctx_setuser(ctx, "", TRUE);
353 ctx->ct_flags |= SMBCF_NOPWD;
354 break;
355 case 'U':
356 uflg = 1;
357 error = smb_ctx_setuser(ctx, arg, TRUE);
358 break;
359 default:
360 DPRINT("skip opt=%c", opt);
361 break;
362 }
363 }
364 ind = cf_optind;
365 arg = argv[ind];
366 cf_optind = cf_optreset = 1;
367 cf_opt_unlock();
368
369 if (error)
370 return (error);
371
372 if (aflg && uflg) {
373 printf(gettext("-A and -U flags are exclusive.\n"));
374 return (EINVAL);
375 }
376
377 /*
378 * Parse the UNC path. Values from here are
379 * marked as "from CMD".
380 */
381 for (; ind < argc; ind++) {
382 arg = argv[ind];
383 if (strncmp(arg, "//", 2) != 0)
384 continue;
385 error = smb_ctx_parseunc(ctx, arg,
386 minlevel, maxlevel, sharetype, &arg);
387 if (error)
388 return (error);
389 break;
390 }
391
392 return (error);
393 }
394
395 void
smb_ctx_free(smb_ctx_t * ctx)396 smb_ctx_free(smb_ctx_t *ctx)
397 {
398 smb_ctx_done(ctx);
399 free(ctx);
400 }
401
402 void
smb_ctx_done(struct smb_ctx * ctx)403 smb_ctx_done(struct smb_ctx *ctx)
404 {
405
406 rpc_cleanup_smbctx(ctx);
407
408 if (ctx->ct_dev_fd != -1) {
409 close(ctx->ct_dev_fd);
410 ctx->ct_dev_fd = -1;
411 }
412 if (ctx->ct_door_fd != -1) {
413 close(ctx->ct_door_fd);
414 ctx->ct_door_fd = -1;
415 }
416 if (ctx->ct_tran_fd != -1) {
417 close(ctx->ct_tran_fd);
418 ctx->ct_tran_fd = -1;
419 }
420 if (ctx->ct_srvaddr_s) {
421 free(ctx->ct_srvaddr_s);
422 ctx->ct_srvaddr_s = NULL;
423 }
424 if (ctx->ct_nb) {
425 nb_ctx_done(ctx->ct_nb);
426 ctx->ct_nb = NULL;
427 }
428 if (ctx->ct_locname) {
429 free(ctx->ct_locname);
430 ctx->ct_locname = NULL;
431 }
432 if (ctx->ct_origshare) {
433 free(ctx->ct_origshare);
434 ctx->ct_origshare = NULL;
435 }
436 if (ctx->ct_fullserver) {
437 free(ctx->ct_fullserver);
438 ctx->ct_fullserver = NULL;
439 }
440 if (ctx->ct_addrinfo) {
441 freeaddrinfo(ctx->ct_addrinfo);
442 ctx->ct_addrinfo = NULL;
443 }
444 if (ctx->ct_home)
445 free(ctx->ct_home);
446 if (ctx->ct_srv_OS) {
447 free(ctx->ct_srv_OS);
448 ctx->ct_srv_OS = NULL;
449 }
450 if (ctx->ct_srv_LM) {
451 free(ctx->ct_srv_LM);
452 ctx->ct_srv_LM = NULL;
453 }
454 if (ctx->ct_mackey) {
455 free(ctx->ct_mackey);
456 ctx->ct_mackey = NULL;
457 }
458 }
459
460 static int
getsubstring(const char * p,uchar_t sep,char * dest,int maxlen,const char ** next)461 getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
462 const char **next)
463 {
464 int len;
465
466 maxlen--;
467 for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
468 if (*p == 0)
469 return (EINVAL);
470 *dest = *p;
471 }
472 *dest = 0;
473 *next = *p ? p + 1 : p;
474 return (0);
475 }
476
477 /*
478 * Parse the UNC path. Here we expect something like
479 * "//[workgroup;][user[:password]@]host[/share[/path]]"
480 * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
481 * Values found here are marked as "from CMD".
482 */
483 int
smb_ctx_parseunc(struct smb_ctx * ctx,const char * unc,int minlevel,int maxlevel,int sharetype,const char ** next)484 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
485 int minlevel, int maxlevel, int sharetype,
486 const char **next)
487 {
488 const char *p = unc;
489 char *p1, *colon;
490 char tmp[1024];
491 int error;
492
493 /*
494 * This may be called outside of _scan_argv,
495 * so make sure these get initialized.
496 */
497 ctx->ct_minlevel = minlevel;
498 ctx->ct_maxlevel = maxlevel;
499 ctx->ct_shtype_req = sharetype;
500
501 ctx->ct_parsedlevel = SMBL_NONE;
502 if (*p++ != '/' || *p++ != '/') {
503 smb_error(dgettext(TEXT_DOMAIN,
504 "UNC should start with '//'"), 0);
505 error = EINVAL;
506 goto out;
507 }
508 p1 = tmp;
509 error = getsubstring(p, ';', p1, sizeof (tmp), &p);
510 if (!error) {
511 if (*p1 == 0) {
512 smb_error(dgettext(TEXT_DOMAIN,
513 "empty workgroup name"), 0);
514 error = EINVAL;
515 goto out;
516 }
517 error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE);
518 if (error)
519 goto out;
520 }
521 colon = (char *)p;
522 error = getsubstring(p, '@', p1, sizeof (tmp), &p);
523 if (!error) {
524 if (ctx->ct_maxlevel < SMBL_VC) {
525 smb_error(dgettext(TEXT_DOMAIN,
526 "no user name required"), 0);
527 error = EINVAL;
528 goto out;
529 }
530 p1 = strchr(tmp, ':');
531 if (p1) {
532 colon += p1 - tmp;
533 *p1++ = (char)0;
534 error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
535 if (error)
536 goto out;
537 if (p - colon > 2)
538 memset(colon+1, '*', p - colon - 2);
539 }
540 p1 = tmp;
541 if (*p1 == 0) {
542 smb_error(dgettext(TEXT_DOMAIN,
543 "empty user name"), 0);
544 error = EINVAL;
545 goto out;
546 }
547 error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
548 if (error)
549 goto out;
550 ctx->ct_parsedlevel = SMBL_VC;
551 }
552 error = getsubstring(p, '/', p1, sizeof (tmp), &p);
553 if (error) {
554 error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
555 if (error) {
556 smb_error(dgettext(TEXT_DOMAIN,
557 "no server name found"), 0);
558 goto out;
559 }
560 }
561 if (*p1 == 0) {
562 smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
563 error = EINVAL;
564 goto out;
565 }
566
567 /*
568 * Save ct_fullserver without case conversion.
569 */
570 if (strchr(tmp, '%'))
571 (void) unpercent(tmp);
572 error = smb_ctx_setfullserver(ctx, tmp);
573 if (error)
574 goto out;
575
576 #ifdef SMB_ST_NONE
577 if (sharetype == SMB_ST_NONE) {
578 if (next)
579 *next = p;
580 error = 0;
581 goto out;
582 }
583 #endif
584
585 if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
586 smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
587 error = EINVAL;
588 goto out;
589 }
590 error = getsubstring(p, '/', p1, sizeof (tmp), &p);
591 if (error) {
592 error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
593 if (error) {
594 smb_error(dgettext(TEXT_DOMAIN,
595 "unexpected end of line"), 0);
596 goto out;
597 }
598 }
599 if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
600 !(ctx->ct_flags & SMBCF_BROWSEOK)) {
601 smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
602 error = EINVAL;
603 goto out;
604 }
605 if (next)
606 *next = p;
607 if (*p1 == 0) {
608 error = 0;
609 goto out;
610 }
611 error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
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 static int
smb_parse_owner(char * pair,uid_t * uid,gid_t * gid)863 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
864 {
865 struct group gr;
866 struct passwd pw;
867 char buf[NSS_BUFLEN_PASSWD];
868 char *cp;
869
870 cp = strchr(pair, ':');
871 if (cp) {
872 *cp++ = '\0';
873 if (*cp && gid) {
874 if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
875 *gid = gr.gr_gid;
876 } else
877 smb_error(dgettext(TEXT_DOMAIN,
878 "Invalid group name %s, ignored"), 0, cp);
879 }
880 }
881 if (*pair) {
882 if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
883 *uid = pw.pw_uid;
884 } else
885 smb_error(dgettext(TEXT_DOMAIN,
886 "Invalid user name %s, ignored"), 0, pair);
887 }
888
889 return (0);
890 }
891
892 /*
893 * Suport a securty options arg, i.e. -S noext,lm,ntlm
894 * for testing various type of authenticators.
895 */
896 static struct nv
897 sectype_table[] = {
898 /* noext - handled below */
899 { "anon", SMB_AT_ANON },
900 { "lm", SMB_AT_LM1 },
901 { "ntlm", SMB_AT_NTLM1 },
902 { "ntlm2", SMB_AT_NTLM2 },
903 { "krb5", SMB_AT_KRB5 },
904 { NULL, 0 },
905 };
906 int
smb_parse_secopts(struct smb_ctx * ctx,const char * arg)907 smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
908 {
909 const char *sep = ":;,";
910 const char *p = arg;
911 struct nv *nv;
912 int nlen, tlen;
913 int authflags = 0;
914
915 for (;;) {
916 /* skip separators */
917 tlen = strspn(p, sep);
918 p += tlen;
919
920 nlen = strcspn(p, sep);
921 if (nlen == 0)
922 break;
923
924 if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
925 /* Don't offer extended security. */
926 ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
927 p += nlen;
928 continue;
929 }
930
931 /* This is rarely called, so not optimized. */
932 for (nv = sectype_table; nv->name; nv++) {
933 tlen = strlen(nv->name);
934 if (tlen == nlen && 0 == strncmp(p, nv->name, tlen))
935 break;
936 }
937 if (nv->name == NULL) {
938 smb_error(dgettext(TEXT_DOMAIN,
939 "%s: invalid security options"), 0, p);
940 return (EINVAL);
941 }
942 authflags |= nv->value;
943 p += nlen;
944 }
945
946 if (authflags)
947 ctx->ct_authflags = authflags;
948
949 return (0);
950 }
951
952 /*
953 * Commands use this with getopt. See:
954 * STDPARAM_OPT, STDPARAM_ARGS
955 * Called after smb_ctx_readrc().
956 */
957 int
smb_ctx_opt(struct smb_ctx * ctx,int opt,const char * arg)958 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
959 {
960 int error = 0;
961 char *p, *cp;
962 char tmp[1024];
963
964 switch (opt) {
965 case 'A':
966 case 'U':
967 /* Handled in smb_ctx_init() */
968 break;
969 case 'I':
970 error = smb_ctx_setsrvaddr(ctx, arg);
971 break;
972 case 'M':
973 /* share connect rights - ignored */
974 ctx->ct_flags |= SMBCF_SRIGHTS;
975 break;
976 case 'N':
977 ctx->ct_flags |= SMBCF_NOPWD;
978 break;
979 case 'O':
980 p = strdup(arg);
981 cp = strchr(p, '/');
982 if (cp)
983 *cp = '\0';
984 error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
985 free(p);
986 break;
987 case 'P':
988 /* ctx->ct_vopt |= SMBCOPT_PERMANENT; */
989 break;
990 case 'R':
991 /* retry count - ignored */
992 break;
993 case 'S':
994 /* Security options (undocumented, just for tests) */
995 error = smb_parse_secopts(ctx, arg);
996 break;
997 case 'T':
998 /* timeout - ignored */
999 break;
1000 case 'D': /* domain */
1001 case 'W': /* workgroup (legacy alias) */
1002 error = smb_ctx_setdomain(ctx, tmp, TRUE);
1003 break;
1004 }
1005 return (error);
1006 }
1007
1008
1009 /*
1010 * Original code injected iconv tables into the kernel.
1011 * Not sure if we'll need this or not... REVISIT
1012 */
1013 #ifdef KICONV_SUPPORT
1014 static int
smb_addiconvtbl(const char * to,const char * from,const uchar_t * tbl)1015 smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
1016 {
1017 int error = 0;
1018
1019 error = kiconv_add_xlat_table(to, from, tbl);
1020 if (error && error != EEXIST) {
1021 smb_error(dgettext(TEXT_DOMAIN,
1022 "can not setup kernel iconv table (%s:%s)"),
1023 error, from, to);
1024 return (error);
1025 }
1026 return (error);
1027 }
1028 #endif /* KICONV_SUPPORT */
1029
1030 /*
1031 * Verify context info. before connect operation(s),
1032 * lookup specified server and try to fill all forgotten fields.
1033 * Legacy name used by commands.
1034 */
1035 int
smb_ctx_resolve(struct smb_ctx * ctx)1036 smb_ctx_resolve(struct smb_ctx *ctx)
1037 {
1038 struct smbioc_ossn *ssn = &ctx->ct_ssn;
1039 int error = 0;
1040 #ifdef KICONV_SUPPORT
1041 uchar_t cstbl[256];
1042 uint_t i;
1043 #endif
1044
1045 if (smb_debug)
1046 dump_ctx("before smb_ctx_resolve", ctx);
1047
1048 ctx->ct_flags &= ~SMBCF_RESOLVED;
1049
1050 if (ctx->ct_fullserver == NULL) {
1051 smb_error(dgettext(TEXT_DOMAIN,
1052 "no server name specified"), 0);
1053 return (EINVAL);
1054 }
1055
1056 if (ctx->ct_minlevel >= SMBL_SHARE &&
1057 ctx->ct_origshare == NULL) {
1058 smb_error(dgettext(TEXT_DOMAIN,
1059 "no share name specified for %s@%s"),
1060 0, ssn->ssn_user, ctx->ct_fullserver);
1061 return (EINVAL);
1062 }
1063 error = nb_ctx_resolve(ctx->ct_nb);
1064 if (error)
1065 return (error);
1066 #ifdef KICONV_SUPPORT
1067 if (ssn->ioc_localcs[0] == 0)
1068 strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */
1069 error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
1070 if (error)
1071 return (error);
1072 error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
1073 if (error)
1074 return (error);
1075 if (ssn->ioc_servercs[0] != 0) {
1076 for (i = 0; i < sizeof (cstbl); i++)
1077 cstbl[i] = i;
1078 nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
1079 error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
1080 cstbl);
1081 if (error)
1082 return (error);
1083 for (i = 0; i < sizeof (cstbl); i++)
1084 cstbl[i] = i;
1085 nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
1086 error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
1087 cstbl);
1088 if (error)
1089 return (error);
1090 }
1091 #endif /* KICONV_SUPPORT */
1092
1093 /*
1094 * Lookup the IP address and fill in ct_addrinfo.
1095 *
1096 * Note: smb_ctx_getaddr() returns a EAI_xxx
1097 * error value like getaddrinfo(3), but this
1098 * function needs to return an errno value.
1099 */
1100 error = smb_ctx_getaddr(ctx);
1101 if (error) {
1102 const char *ais = gai_strerror(error);
1103 smb_error(dgettext(TEXT_DOMAIN,
1104 "can't resolve name\"%s\", %s"),
1105 0, ctx->ct_fullserver, ais);
1106 return (ENODATA);
1107 }
1108 assert(ctx->ct_addrinfo != NULL);
1109
1110 /*
1111 * If we have a user name but no password,
1112 * check for a keychain entry.
1113 * XXX: Only for auth NTLM?
1114 */
1115 if (ctx->ct_user[0] == '\0') {
1116 /*
1117 * No user name (anonymous session).
1118 * The minauth checks do not apply.
1119 */
1120 ctx->ct_authflags = SMB_AT_ANON;
1121 } else {
1122 /*
1123 * Have a user name.
1124 * If we don't have a p/w yet,
1125 * try the keychain.
1126 */
1127 if (ctx->ct_password[0] == '\0')
1128 (void) smb_get_keychain(ctx);
1129 /*
1130 * Mask out disallowed auth types.
1131 */
1132 ctx->ct_authflags &= ctx->ct_minauth;
1133 }
1134 if (ctx->ct_authflags == 0) {
1135 smb_error(dgettext(TEXT_DOMAIN,
1136 "no valid auth. types"), 0);
1137 return (ENOTSUP);
1138 }
1139
1140 ctx->ct_flags |= SMBCF_RESOLVED;
1141 if (smb_debug)
1142 dump_ctx("after smb_ctx_resolve", ctx);
1143
1144 return (0);
1145 }
1146
1147 int
smb_open_driver()1148 smb_open_driver()
1149 {
1150 int err, fd;
1151 uint32_t version;
1152
1153 fd = open("/dev/"NSMB_NAME, O_RDWR);
1154 if (fd < 0) {
1155 err = errno;
1156 smb_error(dgettext(TEXT_DOMAIN,
1157 "failed to open driver"), err);
1158 return (-1);
1159 }
1160
1161 /*
1162 * Check the driver version (paranoia)
1163 * Do this BEFORE any other ioctl calls.
1164 */
1165 if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1166 version = 0;
1167 if (version != NSMB_VERSION) {
1168 smb_error(dgettext(TEXT_DOMAIN,
1169 "incorrect driver version"), 0);
1170 close(fd);
1171 return (-1);
1172 }
1173
1174 /* This handle controls per-process resources. */
1175 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1176
1177 return (fd);
1178 }
1179
1180 int
smb_ctx_gethandle(struct smb_ctx * ctx)1181 smb_ctx_gethandle(struct smb_ctx *ctx)
1182 {
1183 int fd;
1184
1185 if (ctx->ct_dev_fd != -1) {
1186 rpc_cleanup_smbctx(ctx);
1187 close(ctx->ct_dev_fd);
1188 ctx->ct_dev_fd = -1;
1189 ctx->ct_flags &= ~SMBCF_SSNACTIVE;
1190 }
1191
1192 fd = smb_open_driver();
1193 if (fd < 0)
1194 return (ENODEV);
1195
1196 ctx->ct_dev_fd = fd;
1197 return (0);
1198 }
1199
1200
1201 /*
1202 * Find or create a connection + logon session
1203 */
1204 int
smb_ctx_get_ssn(struct smb_ctx * ctx)1205 smb_ctx_get_ssn(struct smb_ctx *ctx)
1206 {
1207 int err = 0;
1208
1209 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
1210 return (EINVAL);
1211
1212 if (ctx->ct_dev_fd < 0) {
1213 if ((err = smb_ctx_gethandle(ctx)))
1214 return (err);
1215 }
1216
1217 /*
1218 * Check whether the driver already has a VC
1219 * we can use. If so, we're done!
1220 */
1221 err = smb_ctx_findvc(ctx);
1222 if (err == 0) {
1223 DPRINT("found an existing VC");
1224 } else {
1225 /*
1226 * This calls the IOD to create a new session.
1227 */
1228 DPRINT("setup a new VC");
1229 err = smb_ctx_newvc(ctx);
1230 if (err != 0)
1231 return (err);
1232
1233 /*
1234 * Call findvc again. The new VC sould be
1235 * found in the driver this time.
1236 */
1237 err = smb_ctx_findvc(ctx);
1238 }
1239
1240 return (err);
1241 }
1242
1243 /*
1244 * Get the string representation of a share "use" type,
1245 * as needed for the "service" in tree connect.
1246 */
1247 static const char *
smb_use_type_str(smb_use_shtype_t stype)1248 smb_use_type_str(smb_use_shtype_t stype)
1249 {
1250 const char *pp;
1251
1252 switch (stype) {
1253 default:
1254 case USE_WILDCARD:
1255 pp = "?????";
1256 break;
1257 case USE_DISKDEV:
1258 pp = "A:";
1259 break;
1260 case USE_SPOOLDEV:
1261 pp = "LPT1:";
1262 break;
1263 case USE_CHARDEV:
1264 pp = "COMM";
1265 break;
1266 case USE_IPC:
1267 pp = "IPC";
1268 break;
1269 }
1270 return (pp);
1271 }
1272
1273 /*
1274 * Find or create a tree connection
1275 */
1276 int
smb_ctx_get_tree(struct smb_ctx * ctx)1277 smb_ctx_get_tree(struct smb_ctx *ctx)
1278 {
1279 smbioc_tcon_t *tcon = NULL;
1280 const char *stype;
1281 int cmd, err = 0;
1282
1283 if (ctx->ct_dev_fd < 0 ||
1284 ctx->ct_origshare == NULL) {
1285 return (EINVAL);
1286 }
1287
1288 cmd = SMBIOC_TREE_CONNECT;
1289 tcon = malloc(sizeof (*tcon));
1290 if (tcon == NULL)
1291 return (ENOMEM);
1292 bzero(tcon, sizeof (*tcon));
1293 tcon->tc_flags = SMBLK_CREATE;
1294 tcon->tc_opt = 0;
1295
1296 /* The share name */
1297 strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
1298 sizeof (tcon->tc_sh.sh_name));
1299
1300 /*
1301 * Share password (unused - no share-level security)
1302 * MS-SMB 2.2.6 says this should be null terminated,
1303 * and the length includes the null. Did bzero above,
1304 * so just set length for the null.
1305 */
1306 tcon->tc_sh.sh_pwlen = 1;
1307
1308 /* The share "use" type. */
1309 stype = smb_use_type_str(ctx->ct_shtype_req);
1310 strlcpy(tcon->tc_sh.sh_type_req, stype,
1311 sizeof (tcon->tc_sh.sh_type_req));
1312
1313 /*
1314 * Todo: share passwords for share-level security.
1315 *
1316 * The driver does the actual TCON call.
1317 */
1318 if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1319 err = errno;
1320 goto out;
1321 }
1322
1323 /*
1324 * Check the returned share type
1325 */
1326 DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret);
1327 if (ctx->ct_shtype_req != USE_WILDCARD &&
1328 0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) {
1329 smb_error(dgettext(TEXT_DOMAIN,
1330 "%s: incompatible share type"),
1331 0, ctx->ct_origshare);
1332 err = EINVAL;
1333 }
1334
1335 out:
1336 if (tcon != NULL)
1337 free(tcon);
1338
1339 return (err);
1340 }
1341
1342 /*
1343 * Return the hflags2 word for an smb_ctx.
1344 */
1345 int
smb_ctx_flags2(struct smb_ctx * ctx)1346 smb_ctx_flags2(struct smb_ctx *ctx)
1347 {
1348 uint16_t flags2;
1349
1350 if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
1351 smb_error(dgettext(TEXT_DOMAIN,
1352 "can't get flags2 for a session"), errno);
1353 return (-1);
1354 }
1355 return (flags2);
1356 }
1357
1358 /*
1359 * Get the transport level session key.
1360 * Must already have an active SMB session.
1361 */
1362 int
smb_ctx_get_ssnkey(struct smb_ctx * ctx,uchar_t * key,size_t len)1363 smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len)
1364 {
1365 if (len < SMBIOC_HASH_SZ)
1366 return (EINVAL);
1367
1368 if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1369 return (errno);
1370
1371 return (0);
1372 }
1373
1374 /*
1375 * RC file parsing stuff
1376 */
1377
1378 static struct nv
1379 minauth_table[] = {
1380 /* Allowed auth. types */
1381 { "kerberos", SMB_AT_KRB5 },
1382 { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 },
1383 { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
1384 { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
1385 { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
1386 SMB_AT_ANON },
1387 { NULL }
1388 };
1389
1390
1391 /*
1392 * level values:
1393 * 0 - default
1394 * 1 - server
1395 * 2 - server:user
1396 * 3 - server:user:share
1397 */
1398 static int
smb_ctx_readrcsection(struct smb_ctx * ctx,const char * sname,int level)1399 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
1400 {
1401 char *p;
1402 int error;
1403
1404 #ifdef KICONV_SUPPORT
1405 if (level > 0) {
1406 rc_getstringptr(smb_rc, sname, "charsets", &p);
1407 if (p) {
1408 error = smb_ctx_setcharset(ctx, p);
1409 if (error)
1410 smb_error(dgettext(TEXT_DOMAIN,
1411 "charset specification in the section '%s' ignored"),
1412 error, sname);
1413 }
1414 }
1415 #endif
1416
1417 if (level <= 1) {
1418 /* Section is: [default] or [server] */
1419
1420 rc_getstringptr(smb_rc, sname, "minauth", &p);
1421 if (p) {
1422 /*
1423 * "minauth" was set in this section; override
1424 * the current minimum authentication setting.
1425 */
1426 struct nv *nvp;
1427 for (nvp = minauth_table; nvp->name; nvp++)
1428 if (strcmp(p, nvp->name) == 0)
1429 break;
1430 if (nvp->name)
1431 ctx->ct_minauth = nvp->value;
1432 else {
1433 /*
1434 * Unknown minimum authentication level.
1435 */
1436 smb_error(dgettext(TEXT_DOMAIN,
1437 "invalid minimum authentication level \"%s\" specified in the section %s"),
1438 0, p, sname);
1439 return (EINVAL);
1440 }
1441 }
1442
1443 rc_getstringptr(smb_rc, sname, "signing", &p);
1444 if (p) {
1445 /*
1446 * "signing" was set in this section; override
1447 * the current signing settings. Note:
1448 * setsigning flags are: enable, require
1449 */
1450 if (strcmp(p, "disabled") == 0) {
1451 (void) smb_ctx_setsigning(ctx, FALSE, FALSE);
1452 } else if (strcmp(p, "enabled") == 0) {
1453 (void) smb_ctx_setsigning(ctx, TRUE, FALSE);
1454 } else if (strcmp(p, "required") == 0) {
1455 (void) smb_ctx_setsigning(ctx, TRUE, TRUE);
1456 } else {
1457 /*
1458 * Unknown "signing" value.
1459 */
1460 smb_error(dgettext(TEXT_DOMAIN,
1461 "invalid signing policy \"%s\" specified in the section %s"),
1462 0, p, sname);
1463 return (EINVAL);
1464 }
1465 }
1466
1467 /*
1468 * Domain name. Allow both keywords:
1469 * "workgroup", "domain"
1470 *
1471 * Note: these are NOT marked "from CMD".
1472 * See long comment at smb_ctx_init()
1473 */
1474 rc_getstringptr(smb_rc, sname, "workgroup", &p);
1475 if (p) {
1476 error = smb_ctx_setdomain(ctx, p, 0);
1477 if (error)
1478 smb_error(dgettext(TEXT_DOMAIN,
1479 "workgroup specification in the "
1480 "section '%s' ignored"), error, sname);
1481 }
1482 rc_getstringptr(smb_rc, sname, "domain", &p);
1483 if (p) {
1484 error = smb_ctx_setdomain(ctx, p, 0);
1485 if (error)
1486 smb_error(dgettext(TEXT_DOMAIN,
1487 "domain specification in the "
1488 "section '%s' ignored"), error, sname);
1489 }
1490
1491 rc_getstringptr(smb_rc, sname, "user", &p);
1492 if (p) {
1493 error = smb_ctx_setuser(ctx, p, 0);
1494 if (error)
1495 smb_error(dgettext(TEXT_DOMAIN,
1496 "user specification in the "
1497 "section '%s' ignored"), error, sname);
1498 }
1499 }
1500
1501 if (level == 1) {
1502 /* Section is: [server] */
1503 rc_getstringptr(smb_rc, sname, "addr", &p);
1504 if (p) {
1505 error = smb_ctx_setsrvaddr(ctx, p);
1506 if (error) {
1507 smb_error(dgettext(TEXT_DOMAIN,
1508 "invalid address specified in section %s"),
1509 0, sname);
1510 return (error);
1511 }
1512 }
1513 }
1514
1515 rc_getstringptr(smb_rc, sname, "password", &p);
1516 if (p) {
1517 error = smb_ctx_setpassword(ctx, p, 0);
1518 if (error)
1519 smb_error(dgettext(TEXT_DOMAIN,
1520 "password specification in the section '%s' ignored"),
1521 error, sname);
1522 }
1523
1524 return (0);
1525 }
1526
1527 /*
1528 * read rc file as follows:
1529 * 0: read [default] section
1530 * 1: override with [server] section
1531 * 2: override with [server:user] section
1532 * 3: override with [server:user:share] section
1533 * Since absence of rcfile is not fatal, silently ignore this fact.
1534 * smb_rc file should be closed by caller.
1535 */
1536 int
smb_ctx_readrc(struct smb_ctx * ctx)1537 smb_ctx_readrc(struct smb_ctx *ctx)
1538 {
1539 char *home;
1540 char *sname = NULL;
1541 int sname_max;
1542 int err = 0;
1543
1544 if ((home = getenv("HOME")) == NULL)
1545 home = ctx->ct_home;
1546 if ((err = smb_open_rcfile(home)) != 0) {
1547 DPRINT("smb_open_rcfile, err=%d", err);
1548 /* ignore any error here */
1549 return (0);
1550 }
1551
1552 sname_max = 3 * SMBIOC_MAX_NAME + 4;
1553 sname = malloc(sname_max);
1554 if (sname == NULL) {
1555 err = ENOMEM;
1556 goto done;
1557 }
1558
1559 /*
1560 * default parameters (level=0)
1561 */
1562 smb_ctx_readrcsection(ctx, "default", 0);
1563 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
1564
1565 /*
1566 * If we don't have a server name, we can't read any of the
1567 * [server...] sections.
1568 */
1569 if (ctx->ct_fullserver == NULL)
1570 goto done;
1571 /*
1572 * SERVER parameters.
1573 */
1574 smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
1575
1576 /*
1577 * If we don't have a user name, we can't read any of the
1578 * [server:user...] sections.
1579 */
1580 if (ctx->ct_user[0] == 0)
1581 goto done;
1582 /*
1583 * SERVER:USER parameters
1584 */
1585 snprintf(sname, sname_max, "%s:%s",
1586 ctx->ct_fullserver,
1587 ctx->ct_user);
1588 smb_ctx_readrcsection(ctx, sname, 2);
1589
1590
1591 /*
1592 * If we don't have a share name, we can't read any of the
1593 * [server:user:share] sections.
1594 */
1595 if (ctx->ct_origshare == NULL)
1596 goto done;
1597 /*
1598 * SERVER:USER:SHARE parameters
1599 */
1600 snprintf(sname, sname_max, "%s:%s:%s",
1601 ctx->ct_fullserver,
1602 ctx->ct_user,
1603 ctx->ct_origshare);
1604 smb_ctx_readrcsection(ctx, sname, 3);
1605
1606 done:
1607 if (sname)
1608 free(sname);
1609 smb_close_rcfile();
1610 if (smb_debug)
1611 dump_ctx("after smb_ctx_readrc", ctx);
1612 if (err)
1613 DPRINT("err=%d\n", err);
1614
1615 return (err);
1616 }
1617