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 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include <sys/param.h> 38 #include <sys/ioctl.h> 39 #include <sys/time.h> 40 #include <sys/mount.h> 41 #include <sys/types.h> 42 #include <sys/byteorder.h> 43 44 #include <fcntl.h> 45 #include <ctype.h> 46 #include <errno.h> 47 #include <stdio.h> 48 #include <string.h> 49 #include <strings.h> 50 #include <stdlib.h> 51 #include <pwd.h> 52 #include <grp.h> 53 #include <unistd.h> 54 #include <libintl.h> 55 #include <assert.h> 56 #include <nss_dbdefs.h> 57 58 #include <kerberosv5/krb5.h> 59 #include <kerberosv5/com_err.h> 60 61 extern uid_t real_uid, eff_uid; 62 63 #define NB_NEEDRESOLVER 64 65 #include <netsmb/smb_lib.h> 66 #include <netsmb/netbios.h> 67 #include <netsmb/nb_lib.h> 68 #include <netsmb/smb_dev.h> 69 #include <cflib.h> 70 #include <charsets.h> 71 72 #include <spnego.h> 73 #include "derparse.h" 74 75 extern MECH_OID g_stcMechOIDList []; 76 77 #define POWEROF2(x) (((x) & ((x)-1)) == 0) 78 79 /* These two may be set by commands. */ 80 int smb_debug, smb_verbose; 81 82 /* 83 * This used to call the DCE/RPC code. 84 * We want more strict layering than this. 85 * The redirector should simply export a 86 * remote pipe API, comsumed by dce rpc. 87 * Make it a no-op for now. 88 */ 89 #if 0 90 #include <rpc_cleanup.h> 91 #else 92 static void 93 rpc_cleanup_smbctx(struct smb_ctx *ctx) 94 { 95 } 96 #endif 97 98 void 99 dump_ctx_flags(int flags) 100 { 101 printf(" Flags: "); 102 if (flags == 0) 103 printf("0"); 104 if (flags & SMBCF_NOPWD) 105 printf("NOPWD "); 106 if (flags & SMBCF_SRIGHTS) 107 printf("SRIGHTS "); 108 if (flags & SMBCF_LOCALE) 109 printf("LOCALE "); 110 if (flags & SMBCF_CMD_DOM) 111 printf("CMD_DOM "); 112 if (flags & SMBCF_CMD_USR) 113 printf("CMD_USR "); 114 if (flags & SMBCF_CMD_PW) 115 printf("CMD_PW "); 116 if (flags & SMBCF_RESOLVED) 117 printf("RESOLVED "); 118 if (flags & SMBCF_KCBAD) 119 printf("KCBAD "); 120 if (flags & SMBCF_KCFOUND) 121 printf("KCFOUND "); 122 if (flags & SMBCF_BROWSEOK) 123 printf("BROWSEOK "); 124 if (flags & SMBCF_AUTHREQ) 125 printf("AUTHREQ "); 126 if (flags & SMBCF_KCSAVE) 127 printf("KCSAVE "); 128 if (flags & SMBCF_XXX) 129 printf("XXX "); 130 if (flags & SMBCF_SSNACTIVE) 131 printf("SSNACTIVE "); 132 if (flags & SMBCF_KCDOMAIN) 133 printf("KCDOMAIN "); 134 printf("\n"); 135 } 136 137 void 138 dump_ctx_ssn(struct smbioc_ossn *ssn) 139 { 140 printf(" srvname=\"%s\", dom=\"%s\", user=\"%s\", password=%s\n", 141 ssn->ioc_srvname, ssn->ioc_workgroup, ssn->ioc_user, 142 ssn->ioc_password[0] ? "(non-null)" : "NULL"); 143 printf(" timeout=%d, retry=%d, owner=%d, group=%d\n", 144 ssn->ioc_timeout, ssn->ioc_retrycount, 145 ssn->ioc_owner, ssn->ioc_group); 146 } 147 148 void 149 dump_ctx_sh(struct smbioc_oshare *sh) 150 { 151 printf(" share_name=\"%s\", share_pw=\"%s\"\n", 152 sh->ioc_share, sh->ioc_password); 153 } 154 155 void 156 dump_ctx(char *where, struct smb_ctx *ctx) 157 { 158 printf("context %s:\n", where); 159 dump_ctx_flags(ctx->ct_flags); 160 161 printf(" localname=\"%s\"", ctx->ct_locname); 162 163 if (ctx->ct_fullserver) 164 printf(" fullserver=\"%s\"", ctx->ct_fullserver); 165 else 166 printf(" fullserver=NULL"); 167 168 if (ctx->ct_srvaddr) 169 printf(" srvaddr=\"%s\"\n", ctx->ct_srvaddr); 170 else 171 printf(" srvaddr=NULL\n"); 172 173 dump_ctx_ssn(&ctx->ct_ssn); 174 dump_ctx_sh(&ctx->ct_sh); 175 } 176 177 /* 178 * Initialize an smb_ctx struct. 179 * 180 * The sequence for getting all the members filled in 181 * has some tricky aspects. Here's how it works: 182 * 183 * The search order for options is as follows: 184 * command line options 185 * values parsed from UNC path (cmd) 186 * values from RC file (per-user) 187 * values from SMF (system-wide) 188 * built-in defaults 189 * 190 * Normally, one would simply get all the values starting with 191 * the bottom of the above list and working to the top, and 192 * overwriting values as you go. But we need an exception. 193 * 194 * In this function, we parse the UNC path and command line options, 195 * because we need (at least) the server name when we're getting the 196 * SMF and RC file values. However, values we get from the command 197 * should not be overwritten by SMF or RC file parsing, so we mark 198 * values from the command as "from CMD" and the RC file parser 199 * leaves in place any values so marked. See: SMBCF_CMD_* 200 * 201 * The semantics of these flags are: "This value came from the 202 * current command instance, not from sources that may apply to 203 * multiple commands." (Different from the old "FROMUSR" flag.) 204 * 205 * Note that smb_ctx_opt() is called later to handle the 206 * remaining options, which should be ignored here. 207 * The (magic) leading ":" in cf_getopt() makes it 208 * ignore options not in the options string. 209 */ 210 int 211 smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[], 212 int minlevel, int maxlevel, int sharetype) 213 { 214 int opt, error = 0; 215 const char *arg, *cp; 216 struct passwd pw; 217 char pwbuf[NSS_BUFLEN_PASSWD]; 218 int aflg = 0, uflg = 0; 219 220 bzero(ctx, sizeof (*ctx)); 221 if (sharetype == SMB_ST_DISK) 222 ctx->ct_flags |= SMBCF_BROWSEOK; 223 error = nb_ctx_create(&ctx->ct_nb); 224 if (error) 225 return (error); 226 227 ctx->ct_fd = -1; 228 ctx->ct_parsedlevel = SMBL_NONE; 229 ctx->ct_minlevel = minlevel; 230 ctx->ct_maxlevel = maxlevel; 231 232 ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE | SMBVOPT_MINAUTH_NTLM; 233 ctx->ct_ssn.ioc_timeout = 15; 234 ctx->ct_ssn.ioc_retrycount = 4; 235 ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER; 236 ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP; 237 ctx->ct_ssn.ioc_mode = SMBM_EXEC; 238 ctx->ct_ssn.ioc_rights = SMBM_DEFAULT; 239 240 ctx->ct_sh.ioc_opt = SMBVOPT_CREATE; 241 ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 242 ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 243 ctx->ct_sh.ioc_mode = SMBM_EXEC; 244 ctx->ct_sh.ioc_rights = SMBM_DEFAULT; 245 ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 246 ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 247 248 nb_ctx_setscope(ctx->ct_nb, ""); 249 250 /* 251 * if the user name is not specified some other way, 252 * use the current user name (built-in default) 253 */ 254 if (getpwuid_r(geteuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) 255 smb_ctx_setuser(ctx, pw.pw_name, 0); 256 257 /* 258 * Set a built-in default domain (workgroup). 259 * XXX: What's the best default? Use "?" instead? 260 * Using the Windows/NT default for now. 261 */ 262 smb_ctx_setworkgroup(ctx, "WORKGROUP", 0); 263 264 /* 265 * Parse the UNC path. Values from here are 266 * marked as "from CMD". 267 */ 268 if (argv == NULL) 269 goto done; 270 for (opt = 1; opt < argc; opt++) { 271 cp = argv[opt]; 272 if (strncmp(cp, "//", 2) != 0) 273 continue; 274 error = smb_ctx_parseunc(ctx, cp, sharetype, &cp); 275 if (error) 276 return (error); 277 break; 278 } 279 280 /* 281 * Parse options, if any. Values from here too 282 * are marked as "from CMD". 283 */ 284 while (error == 0 && (opt = cf_getopt(argc, argv, ":AU:E:L:")) != -1) { 285 arg = cf_optarg; 286 switch (opt) { 287 case 'A': 288 aflg = 1; 289 error = smb_ctx_setuser(ctx, "", TRUE); 290 error = smb_ctx_setpassword(ctx, "", TRUE); 291 ctx->ct_flags |= SMBCF_NOPWD; 292 break; 293 case 'E': 294 #if 0 /* We don't support any "charset" stuff. (ignore -E) */ 295 error = smb_ctx_setcharset(ctx, arg); 296 if (error) 297 return (error); 298 #endif 299 break; 300 case 'L': 301 #if 0 /* Use the standard environment variables (ignore -L) */ 302 error = nls_setlocale(optarg); 303 if (error) 304 break; 305 #endif 306 break; 307 case 'U': 308 uflg = 1; 309 error = smb_ctx_setuser(ctx, arg, TRUE); 310 break; 311 } 312 } 313 if (aflg && uflg) { 314 printf(gettext("-A and -U flags are exclusive.\n")); 315 return (1); 316 } 317 cf_optind = cf_optreset = 1; 318 319 done: 320 if (smb_debug) 321 dump_ctx("after smb_ctx_init", ctx); 322 323 return (error); 324 } 325 326 void 327 smb_ctx_done(struct smb_ctx *ctx) 328 { 329 330 rpc_cleanup_smbctx(ctx); 331 332 /* Kerberos stuff. See smb_ctx_krb5init() */ 333 if (ctx->ct_krb5ctx) { 334 if (ctx->ct_krb5cp) 335 krb5_free_principal(ctx->ct_krb5ctx, ctx->ct_krb5cp); 336 krb5_free_context(ctx->ct_krb5ctx); 337 } 338 339 if (ctx->ct_fd != -1) 340 close(ctx->ct_fd); 341 #if 0 /* XXX: not pointers anymore */ 342 if (&ctx->ct_ssn.ioc_server) 343 nb_snbfree(&ctx->ct_ssn.ioc_server); 344 if (&ctx->ct_ssn.ioc_local) 345 nb_snbfree(&ctx->ct_ssn.ioc_local); 346 #endif 347 if (ctx->ct_srvaddr) 348 free(ctx->ct_srvaddr); 349 if (ctx->ct_nb) 350 nb_ctx_done(ctx->ct_nb); 351 if (ctx->ct_secblob) 352 free(ctx->ct_secblob); 353 if (ctx->ct_origshare) 354 free(ctx->ct_origshare); 355 if (ctx->ct_fullserver) 356 free(ctx->ct_fullserver); 357 } 358 359 static int 360 getsubstring(const char *p, uchar_t sep, char *dest, int maxlen, 361 const char **next) 362 { 363 int len; 364 365 maxlen--; 366 for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 367 if (*p == 0) 368 return (EINVAL); 369 *dest = *p; 370 } 371 *dest = 0; 372 *next = *p ? p + 1 : p; 373 return (0); 374 } 375 376 /* 377 * Parse the UNC path. Here we expect something like 378 * "//[workgroup;][user[:password]@]host[/share[/path]]" 379 * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 380 * Values found here are marked as "from CMD". 381 */ 382 int 383 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, 384 const char **next) 385 { 386 const char *p = unc; 387 char *p1, *colon, *servername; 388 char tmp[1024]; 389 char tmp2[1024]; 390 int error; 391 392 ctx->ct_parsedlevel = SMBL_NONE; 393 if (*p++ != '/' || *p++ != '/') { 394 smb_error(dgettext(TEXT_DOMAIN, 395 "UNC should start with '//'"), 0); 396 return (EINVAL); 397 } 398 p1 = tmp; 399 error = getsubstring(p, ';', p1, sizeof (tmp), &p); 400 if (!error) { 401 if (*p1 == 0) { 402 smb_error(dgettext(TEXT_DOMAIN, 403 "empty workgroup name"), 0); 404 return (EINVAL); 405 } 406 nls_str_upper(tmp, tmp); 407 error = smb_ctx_setworkgroup(ctx, unpercent(tmp), TRUE); 408 if (error) 409 return (error); 410 } 411 colon = (char *)p; 412 error = getsubstring(p, '@', p1, sizeof (tmp), &p); 413 if (!error) { 414 if (ctx->ct_maxlevel < SMBL_VC) { 415 smb_error(dgettext(TEXT_DOMAIN, 416 "no user name required"), 0); 417 return (EINVAL); 418 } 419 p1 = strchr(tmp, ':'); 420 if (p1) { 421 colon += p1 - tmp; 422 *p1++ = (char)0; 423 error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE); 424 if (error) 425 return (error); 426 if (p - colon > 2) 427 memset(colon+1, '*', p - colon - 2); 428 } 429 p1 = tmp; 430 if (*p1 == 0) { 431 smb_error(dgettext(TEXT_DOMAIN, 432 "empty user name"), 0); 433 return (EINVAL); 434 } 435 error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE); 436 if (error) 437 return (error); 438 ctx->ct_parsedlevel = SMBL_VC; 439 } 440 error = getsubstring(p, '/', p1, sizeof (tmp), &p); 441 if (error) { 442 error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 443 if (error) { 444 smb_error(dgettext(TEXT_DOMAIN, 445 "no server name found"), 0); 446 return (error); 447 } 448 } 449 if (*p1 == 0) { 450 smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0); 451 return (EINVAL); 452 } 453 454 455 /* 456 * It's safe to uppercase this string, which 457 * consists of ascii characters that should 458 * be uppercased, %s, and ascii characters representing 459 * hex digits 0-9 and A-F (already uppercased, and 460 * if not uppercased they need to be). However, 461 * it is NOT safe to uppercase after it has been 462 * converted, below! 463 */ 464 465 nls_str_upper(tmp2, tmp); 466 467 /* 468 * scan for % in the string. 469 * If we find one, convert 470 * to the assumed codepage. 471 */ 472 473 if (strchr(tmp2, '%')) { 474 /* use the 1st buffer, we don't need the old string */ 475 servername = tmp; 476 if (!(servername = convert_utf8_to_wincs(unpercent(tmp2)))) { 477 smb_error(dgettext(TEXT_DOMAIN, "bad server name"), 0); 478 return (EINVAL); 479 } 480 /* 481 * Converts utf8 to win equivalent of 482 * what is configured on this machine. 483 * Note that we are assuming this is the 484 * encoding used on the server, and that 485 * assumption might be incorrect. This is 486 * the best we can do now, and we should 487 * move to use port 445 to avoid having 488 * to worry about server codepages. 489 */ 490 } else /* no conversion needed */ 491 servername = tmp2; 492 493 smb_ctx_setserver(ctx, servername); 494 error = smb_ctx_setfullserver(ctx, servername); 495 496 if (error) 497 return (error); 498 if (sharetype == SMB_ST_NONE) { 499 *next = p; 500 return (0); 501 } 502 if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 503 smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0); 504 return (EINVAL); 505 } 506 error = getsubstring(p, '/', p1, sizeof (tmp), &p); 507 if (error) { 508 error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 509 if (error) { 510 smb_error(dgettext(TEXT_DOMAIN, 511 "unexpected end of line"), 0); 512 return (error); 513 } 514 } 515 if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE && 516 !(ctx->ct_flags & SMBCF_BROWSEOK)) { 517 smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0); 518 return (EINVAL); 519 } 520 *next = p; 521 if (*p1 == 0) 522 return (0); 523 error = smb_ctx_setshare(ctx, unpercent(p1), sharetype); 524 return (error); 525 } 526 527 int 528 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 529 { 530 char *cp, *servercs, *localcs; 531 int cslen = sizeof (ctx->ct_ssn.ioc_localcs); 532 int scslen, lcslen, error; 533 534 cp = strchr(arg, ':'); 535 lcslen = cp ? (cp - arg) : 0; 536 if (lcslen == 0 || lcslen >= cslen) { 537 smb_error(dgettext(TEXT_DOMAIN, 538 "invalid local charset specification (%s)"), 0, arg); 539 return (EINVAL); 540 } 541 scslen = (size_t)strlen(++cp); 542 if (scslen == 0 || scslen >= cslen) { 543 smb_error(dgettext(TEXT_DOMAIN, 544 "invalid server charset specification (%s)"), 0, arg); 545 return (EINVAL); 546 } 547 localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 548 localcs[lcslen] = 0; 549 servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 550 error = nls_setrecode(localcs, servercs); 551 if (error == 0) 552 return (0); 553 smb_error(dgettext(TEXT_DOMAIN, 554 "can't initialize iconv support (%s:%s)"), 555 error, localcs, servercs); 556 localcs[0] = 0; 557 servercs[0] = 0; 558 return (error); 559 } 560 561 int 562 smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name) 563 { 564 ctx->ct_fullserver = strdup(name); 565 if (ctx->ct_fullserver == NULL) 566 return (ENOMEM); 567 return (0); 568 } 569 570 /* 571 * XXX TODO FIXME etc etc 572 * If the call to nbns_getnodestatus(...) fails we can try one of two other 573 * methods; use a name of "*SMBSERVER", which is supported by Samba (at least) 574 * or, as a last resort, try the "truncate-at-dot" heuristic. 575 * And the heuristic really should attempt truncation at 576 * each dot in turn, left to right. 577 * 578 * These fallback heuristics should be triggered when the attempt to open the 579 * session fails instead of in the code below. 580 * 581 * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 582 */ 583 int 584 smb_ctx_getnbname(struct smb_ctx *ctx, struct sockaddr *sap) 585 { 586 char server[SMB_MAXSRVNAMELEN + 1]; 587 char workgroup[SMB_MAXUSERNAMELEN + 1]; 588 int error; 589 #if 0 590 char *dot; 591 #endif 592 593 server[0] = workgroup[0] = '\0'; 594 error = nbns_getnodestatus(sap, ctx->ct_nb, server, workgroup); 595 if (error == 0) { 596 /* 597 * Used to set our domain name to be the same as 598 * the server's domain name. Unnecessary at best, 599 * and wrong for accounts in a trusted domain. 600 */ 601 #ifdef APPLE 602 if (workgroup[0] && !ctx->ct_ssn.ioc_workgroup[0]) 603 smb_ctx_setworkgroup(ctx, workgroup, 0); 604 #endif 605 if (server[0]) 606 smb_ctx_setserver(ctx, server); 607 } else { 608 if (smb_verbose) 609 smb_error(dgettext(TEXT_DOMAIN, 610 "Failed to get NetBIOS node status."), 0); 611 if (ctx->ct_ssn.ioc_srvname[0] == (char)0) 612 smb_ctx_setserver(ctx, "*SMBSERVER"); 613 } 614 #if 0 615 if (server[0] == (char)0) { 616 dot = strchr(ctx->ct_fullserver, '.'); 617 if (dot) 618 *dot = '\0'; 619 if (strlen(ctx->ct_fullserver) <= SMB_MAXSRVNAMELEN) { 620 /* 621 * don't uppercase the server name. it comes from 622 * NBNS and uppercasing can clobber the characters 623 */ 624 strcpy(ctx->ct_ssn.ioc_srvname, ctx->ct_fullserver); 625 error = 0; 626 } else { 627 error = -1; 628 } 629 if (dot) 630 *dot = '.'; 631 } 632 #endif 633 return (error); 634 } 635 636 /* this routine does not uppercase the server name */ 637 void 638 smb_ctx_setserver(struct smb_ctx *ctx, const char *name) 639 { 640 /* don't uppercase the server name */ 641 if (strlen(name) > SMB_MAXSRVNAMELEN) { /* NB limit is 15 */ 642 ctx->ct_ssn.ioc_srvname[0] = '\0'; 643 } else 644 strcpy(ctx->ct_ssn.ioc_srvname, name); 645 } 646 647 int 648 smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) 649 { 650 651 if (strlen(name) >= SMB_MAXUSERNAMELEN) { 652 smb_error(dgettext(TEXT_DOMAIN, 653 "user name '%s' too long"), 0, name); 654 return (ENAMETOOLONG); 655 } 656 657 /* 658 * Don't overwrite a value from the command line 659 * with one from anywhere else. 660 */ 661 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR)) 662 return (0); 663 664 /* don't uppercase the username, just copy it. */ 665 strcpy(ctx->ct_ssn.ioc_user, name); 666 667 /* Mark this as "from the command line". */ 668 if (from_cmd) 669 ctx->ct_flags |= SMBCF_CMD_USR; 670 671 return (0); 672 } 673 674 /* 675 * Never uppercase the workgroup 676 * name here, because it might come 677 * from a Windows codepage encoding. 678 * 679 * Don't overwrite a domain name from the 680 * command line with one from anywhere else. 681 * See smb_ctx_init() for notes about this. 682 */ 683 int 684 smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd) 685 { 686 687 if (strlen(name) >= SMB_MAXUSERNAMELEN) { 688 smb_error(dgettext(TEXT_DOMAIN, 689 "workgroup name '%s' too long"), 0, name); 690 return (ENAMETOOLONG); 691 } 692 693 /* 694 * Don't overwrite a value from the command line 695 * with one from anywhere else. 696 */ 697 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM)) 698 return (0); 699 700 strcpy(ctx->ct_ssn.ioc_workgroup, name); 701 702 /* Mark this as "from the command line". */ 703 if (from_cmd) 704 ctx->ct_flags |= SMBCF_CMD_DOM; 705 706 return (0); 707 } 708 709 int 710 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd) 711 { 712 713 if (passwd == NULL) /* XXX Huh? */ 714 return (EINVAL); 715 if (strlen(passwd) >= SMB_MAXPASSWORDLEN) { 716 smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0); 717 return (ENAMETOOLONG); 718 } 719 720 /* 721 * Don't overwrite a value from the command line 722 * with one from anywhere else. 723 */ 724 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW)) 725 return (0); 726 727 if (strncmp(passwd, "$$1", 3) == 0) 728 smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); 729 else 730 strcpy(ctx->ct_ssn.ioc_password, passwd); 731 strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); 732 733 /* Mark this as "from the command line". */ 734 if (from_cmd) 735 ctx->ct_flags |= SMBCF_CMD_PW; 736 737 return (0); 738 } 739 740 int 741 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 742 { 743 if (strlen(share) >= SMB_MAXSHARENAMELEN) { 744 smb_error(dgettext(TEXT_DOMAIN, 745 "share name '%s' too long"), 0, share); 746 return (ENAMETOOLONG); 747 } 748 if (ctx->ct_origshare) 749 free(ctx->ct_origshare); 750 if ((ctx->ct_origshare = strdup(share)) == NULL) 751 return (ENOMEM); 752 nls_str_upper(ctx->ct_sh.ioc_share, share); 753 if (share[0] != 0) 754 ctx->ct_parsedlevel = SMBL_SHARE; 755 ctx->ct_sh.ioc_stype = stype; 756 return (0); 757 } 758 759 int 760 smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 761 { 762 if (addr == NULL || addr[0] == 0) 763 return (EINVAL); 764 if (ctx->ct_srvaddr) 765 free(ctx->ct_srvaddr); 766 if ((ctx->ct_srvaddr = strdup(addr)) == NULL) 767 return (ENOMEM); 768 return (0); 769 } 770 771 static int 772 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 773 { 774 struct group gr; 775 struct passwd pw; 776 char buf[NSS_BUFLEN_PASSWD]; 777 char *cp; 778 779 cp = strchr(pair, ':'); 780 if (cp) { 781 *cp++ = '\0'; 782 if (*cp) { 783 if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) { 784 *gid = gr.gr_gid; 785 } else 786 smb_error(dgettext(TEXT_DOMAIN, 787 "Invalid group name %s, ignored"), 0, cp); 788 } 789 } 790 if (*pair) { 791 if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) { 792 *uid = pw.pw_uid; 793 } else 794 smb_error(dgettext(TEXT_DOMAIN, 795 "Invalid user name %s, ignored"), 0, pair); 796 } 797 798 return (0); 799 } 800 801 /* 802 * Commands use this with getopt. See: 803 * STDPARAM_OPT, STDPARAM_ARGS 804 * Called after smb_ctx_readrc(). 805 */ 806 int 807 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 808 { 809 int error = 0; 810 char *p, *cp; 811 char tmp[1024]; 812 813 switch (opt) { 814 case 'A': 815 case 'U': 816 /* Handled in smb_ctx_init() */ 817 break; 818 case 'I': 819 error = smb_ctx_setsrvaddr(ctx, arg); 820 break; 821 case 'M': 822 ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8); 823 if (*cp == '/') { 824 ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8); 825 ctx->ct_flags |= SMBCF_SRIGHTS; 826 } 827 break; 828 case 'N': 829 ctx->ct_flags |= SMBCF_NOPWD; 830 break; 831 case 'O': 832 p = strdup(arg); 833 cp = strchr(p, '/'); 834 if (cp) { 835 *cp++ = '\0'; 836 error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner, 837 &ctx->ct_sh.ioc_group); 838 } 839 if (*p && error == 0) { 840 error = smb_parse_owner(cp, &ctx->ct_ssn.ioc_owner, 841 &ctx->ct_ssn.ioc_group); 842 } 843 free(p); 844 break; 845 case 'P': 846 /* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT; */ 847 break; 848 case 'R': 849 ctx->ct_ssn.ioc_retrycount = atoi(arg); 850 break; 851 case 'T': 852 ctx->ct_ssn.ioc_timeout = atoi(arg); 853 break; 854 case 'W': 855 nls_str_upper(tmp, arg); 856 error = smb_ctx_setworkgroup(ctx, tmp, TRUE); 857 break; 858 } 859 return (error); 860 } 861 862 #if 0 863 static void 864 smb_hexdump(const uchar_t *buf, int len) { 865 int ofs = 0; 866 867 while (len--) { 868 if (ofs % 16 == 0) 869 printf("\n%02X: ", ofs); 870 printf("%02x ", *buf++); 871 ofs++; 872 } 873 printf("\n"); 874 } 875 #endif 876 877 878 static int 879 smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl) 880 { 881 int error; 882 883 /* 884 * Not able to find out what is the work of this routine till 885 * now. Still investigating. 886 * REVISIT 887 */ 888 #ifdef KICONV_SUPPORT 889 error = kiconv_add_xlat_table(to, from, tbl); 890 if (error && error != EEXIST) { 891 smb_error(dgettext(TEXT_DOMAIN, 892 "can not setup kernel iconv table (%s:%s)"), 893 error, from, to); 894 return (error); 895 } 896 #endif 897 return (0); 898 } 899 900 /* 901 * Verify context before connect operation(s), 902 * lookup specified server and try to fill all forgotten fields. 903 */ 904 int 905 smb_ctx_resolve(struct smb_ctx *ctx) 906 { 907 struct smbioc_ossn *ssn = &ctx->ct_ssn; 908 struct smbioc_oshare *sh = &ctx->ct_sh; 909 struct nb_name nn; 910 struct sockaddr *sap; 911 struct sockaddr_nb *salocal, *saserver; 912 char *cp; 913 uchar_t cstbl[256]; 914 uint_t i; 915 int error = 0; 916 int browseok = ctx->ct_flags & SMBCF_BROWSEOK; 917 int renego = 0; 918 919 ctx->ct_flags &= ~SMBCF_RESOLVED; 920 if (isatty(STDIN_FILENO)) 921 browseok = 0; 922 if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == 0) { 923 smb_error(dgettext(TEXT_DOMAIN, 924 "no server name specified"), 0); 925 return (EINVAL); 926 } 927 if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0 && 928 !browseok) { 929 smb_error(dgettext(TEXT_DOMAIN, 930 "no share name specified for %s@%s"), 931 0, ssn->ioc_user, ssn->ioc_srvname); 932 return (EINVAL); 933 } 934 error = nb_ctx_resolve(ctx->ct_nb); 935 if (error) 936 return (error); 937 if (ssn->ioc_localcs[0] == 0) 938 strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ 939 error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 940 if (error) 941 return (error); 942 error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 943 if (error) 944 return (error); 945 if (ssn->ioc_servercs[0] != 0) { 946 for (i = 0; i < sizeof (cstbl); i++) 947 cstbl[i] = i; 948 nls_mem_toext(cstbl, cstbl, sizeof (cstbl)); 949 error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, 950 cstbl); 951 if (error) 952 return (error); 953 for (i = 0; i < sizeof (cstbl); i++) 954 cstbl[i] = i; 955 nls_mem_toloc(cstbl, cstbl, sizeof (cstbl)); 956 error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, 957 cstbl); 958 if (error) 959 return (error); 960 } 961 /* 962 * If we have an explicit address set for the server in 963 * an "addr=X" setting in .nsmbrc or SMF, just try using a 964 * gethostbyname() lookup for it. 965 */ 966 if (ctx->ct_srvaddr) { 967 error = nb_resolvehost_in(ctx->ct_srvaddr, &sap); 968 if (error == 0) 969 (void) smb_ctx_getnbname(ctx, sap); 970 } else 971 error = -1; 972 973 /* 974 * Next try a gethostbyname() lookup on the original user- 975 * specified server name. This is similar to Windows 976 * NBT option "Use DNS for name resolution." 977 */ 978 if (error && ctx->ct_fullserver) { 979 error = nb_resolvehost_in(ctx->ct_fullserver, &sap); 980 if (error == 0) 981 (void) smb_ctx_getnbname(ctx, sap); 982 } 983 984 /* 985 * Finally, try the shorter, upper-cased ssn->ioc_srvname 986 * with a NBNS/WINS lookup if the "nbns_enable" property is 987 * true (the default). nbns_resolvename() may unicast to the 988 * "nbns" server or broadcast on the subnet. 989 */ 990 if (error && ssn->ioc_srvname[0] && 991 ctx->ct_nb->nb_flags & NBCF_NS_ENABLE) { 992 error = nbns_resolvename(ssn->ioc_srvname, 993 ctx->ct_nb, &sap); 994 /* 995 * Used to get the NetBIOS node status here. 996 * Not necessary (we have the NetBIOS name). 997 */ 998 } 999 if (error) { 1000 smb_error(dgettext(TEXT_DOMAIN, 1001 "can't get server address"), error); 1002 return (error); 1003 } 1004 1005 /* XXX: no nls_str_upper(ssn->ioc_srvname) here? */ 1006 1007 assert(sizeof (nn.nn_name) == sizeof (ssn->ioc_srvname)); 1008 memcpy(nn.nn_name, ssn->ioc_srvname, NB_NAMELEN); 1009 nn.nn_type = NBT_SERVER; 1010 nn.nn_scope = ctx->ct_nb->nb_scope; 1011 1012 error = nb_sockaddr(sap, &nn, &saserver); 1013 memcpy(&ctx->ct_srvinaddr, sap, sizeof (struct sockaddr_in)); 1014 nb_snbfree(sap); 1015 if (error) { 1016 smb_error(dgettext(TEXT_DOMAIN, 1017 "can't allocate server address"), error); 1018 return (error); 1019 } 1020 /* We know it's a NetBIOS address here. */ 1021 bcopy(saserver, &ssn->ioc_server.nb, 1022 sizeof (struct sockaddr_nb)); 1023 if (ctx->ct_locname[0] == 0) { 1024 error = nb_getlocalname(ctx->ct_locname, 1025 SMB_MAXUSERNAMELEN + 1); 1026 if (error) { 1027 smb_error(dgettext(TEXT_DOMAIN, 1028 "can't get local name"), error); 1029 return (error); 1030 } 1031 nls_str_upper(ctx->ct_locname, ctx->ct_locname); 1032 } 1033 1034 /* XXX: no nls_str_upper(ctx->ct_locname); here? */ 1035 1036 memcpy(nn.nn_name, ctx->ct_locname, NB_NAMELEN); 1037 nn.nn_type = NBT_WKSTA; 1038 nn.nn_scope = ctx->ct_nb->nb_scope; 1039 1040 error = nb_sockaddr(NULL, &nn, &salocal); 1041 if (error) { 1042 nb_snbfree((struct sockaddr *)saserver); 1043 smb_error(dgettext(TEXT_DOMAIN, 1044 "can't allocate local address"), error); 1045 return (error); 1046 } 1047 1048 /* We know it's a NetBIOS address here. */ 1049 bcopy(salocal, &ssn->ioc_local.nb, 1050 sizeof (struct sockaddr_nb)); 1051 1052 error = smb_ctx_findvc(ctx, SMBL_VC, 0); 1053 if (error == 0) { 1054 /* re-use and existing VC */ 1055 ctx->ct_flags |= SMBCF_RESOLVED | SMBCF_SSNACTIVE; 1056 return (0); 1057 } 1058 1059 /* Make a new connection via smb_ctx_negotiate()... */ 1060 error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, 1061 ssn->ioc_workgroup); 1062 if (error) 1063 return (error); 1064 ctx->ct_flags &= ~SMBCF_AUTHREQ; 1065 if (!ctx->ct_secblob && browseok && !sh->ioc_share[0] && 1066 !(ctx->ct_flags & SMBCF_XXX)) { 1067 /* assert: anon share list is subset of overall server shares */ 1068 error = smb_browse(ctx, 1); 1069 if (error) /* user cancel or other error? */ 1070 return (error); 1071 /* 1072 * A share was selected, authenticate button was pressed, 1073 * or anon-authentication failed getting browse list. 1074 */ 1075 } 1076 if ((ctx->ct_secblob == NULL) && (ctx->ct_flags & SMBCF_AUTHREQ || 1077 (ssn->ioc_password[0] == '\0' && 1078 !(ctx->ct_flags & SMBCF_NOPWD)))) { 1079 reauth: 1080 /* 1081 * This function is implemented in both 1082 * ui-apple.c and ui-sun.c so let's try to 1083 * keep the same interface. Not sure why 1084 * they didn't just pass ssn here. 1085 */ 1086 error = smb_get_authentication( 1087 ssn->ioc_workgroup, sizeof (ssn->ioc_workgroup) - 1, 1088 ssn->ioc_user, sizeof (ssn->ioc_user) - 1, 1089 ssn->ioc_password, sizeof (ssn->ioc_password) - 1, 1090 ssn->ioc_srvname, ctx); 1091 if (error) 1092 return (error); 1093 } 1094 /* 1095 * if we have a session it is either anonymous 1096 * or from a stale authentication. re-negotiating 1097 * gets us ready for a fresh session 1098 */ 1099 if (ctx->ct_flags & SMBCF_SSNACTIVE || renego) { 1100 renego = 0; 1101 /* don't clobber workgroup name, pass null arg */ 1102 error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, NULL); 1103 if (error) 1104 return (error); 1105 } 1106 if (browseok && !sh->ioc_share[0]) { 1107 ctx->ct_flags &= ~SMBCF_AUTHREQ; 1108 error = smb_browse(ctx, 0); 1109 if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) { 1110 smb_error(dgettext(TEXT_DOMAIN, 1111 "smb_ctx_resolve: bad keychain entry"), 0); 1112 ctx->ct_flags |= SMBCF_KCBAD; 1113 renego = 1; 1114 goto reauth; 1115 } 1116 if (error) /* auth, user cancel, or other error */ 1117 return (error); 1118 /* 1119 * Re-authenticate button was pressed? 1120 */ 1121 if (ctx->ct_flags & SMBCF_AUTHREQ) 1122 goto reauth; 1123 if (!sh->ioc_share[0] && !(ctx->ct_flags & SMBCF_XXX)) { 1124 smb_error(dgettext(TEXT_DOMAIN, 1125 "no share specified for %s@%s"), 1126 0, ssn->ioc_user, ssn->ioc_srvname); 1127 return (EINVAL); 1128 } 1129 } 1130 ctx->ct_flags |= SMBCF_RESOLVED; 1131 1132 if (smb_debug) 1133 dump_ctx("after smb_ctx_resolve", ctx); 1134 1135 return (0); 1136 } 1137 1138 int 1139 smb_open_driver() 1140 { 1141 char buf[20]; 1142 int err, fd, i; 1143 uint32_t version; 1144 1145 /* 1146 * First try to open as clone 1147 */ 1148 fd = open("/dev/"NSMB_NAME, O_RDWR); 1149 if (fd >= 0) 1150 goto opened; 1151 1152 err = errno; /* from open */ 1153 #ifdef APPLE 1154 /* 1155 * well, no clone capabilities available - we have to scan 1156 * all devices in order to get free one 1157 */ 1158 for (i = 0; i < 1024; i++) { 1159 snprintf(buf, sizeof (buf), "/dev/%s%d", NSMB_NAME, i); 1160 fd = open(buf, O_RDWR); 1161 if (fd >= 0) 1162 goto opened; 1163 if (i && POWEROF2(i+1)) 1164 smb_error(dgettext(TEXT_DOMAIN, 1165 "%d failures to open smb device"), errno, i+1); 1166 } 1167 err = ENOENT; 1168 #endif 1169 smb_error(dgettext(TEXT_DOMAIN, 1170 "failed to open %s"), err, "/dev/" NSMB_NAME); 1171 return (-1); 1172 1173 opened: 1174 /* 1175 * Check the driver version (paranoia) 1176 * Do this BEFORE any other ioctl calls. 1177 */ 1178 if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) { 1179 err = errno; 1180 smb_error(dgettext(TEXT_DOMAIN, 1181 "failed to get driver version"), err); 1182 close(fd); 1183 return (-1); 1184 } 1185 if (version != NSMB_VERSION) { 1186 smb_error(dgettext(TEXT_DOMAIN, 1187 "incorrect driver version"), 0); 1188 close(fd); 1189 return (-1); 1190 } 1191 1192 return (fd); 1193 } 1194 1195 static int 1196 smb_ctx_gethandle(struct smb_ctx *ctx) 1197 { 1198 int err, fd; 1199 1200 if (ctx->ct_fd != -1) { 1201 rpc_cleanup_smbctx(ctx); 1202 close(ctx->ct_fd); 1203 ctx->ct_fd = -1; 1204 ctx->ct_flags &= ~SMBCF_SSNACTIVE; 1205 } 1206 1207 fd = smb_open_driver(); 1208 if (fd < 0) 1209 return (ENODEV); 1210 1211 ctx->ct_fd = fd; 1212 return (0); 1213 } 1214 1215 int 1216 smb_ctx_ioctl(struct smb_ctx *ctx, int inum, struct smbioc_lookup *rqp) 1217 { 1218 size_t siz = DEF_SEC_TOKEN_LEN; 1219 int rc = 0; 1220 struct sockaddr sap1, sap2; 1221 int i; 1222 1223 if (rqp->ioc_ssn.ioc_outtok) 1224 free(rqp->ioc_ssn.ioc_outtok); 1225 rqp->ioc_ssn.ioc_outtoklen = siz; 1226 rqp->ioc_ssn.ioc_outtok = malloc(siz+1); 1227 if (rqp->ioc_ssn.ioc_outtok == NULL) 1228 return (ENOMEM); 1229 bzero(rqp->ioc_ssn.ioc_outtok, siz+1); 1230 /* Note: No longer put length in outtok[0] */ 1231 /* *((int *)rqp->ioc_ssn.ioc_outtok) = (int)siz; */ 1232 1233 seteuid(eff_uid); /* restore setuid root briefly */ 1234 if (ioctl(ctx->ct_fd, inum, rqp) == -1) { 1235 rc = errno; 1236 goto out; 1237 } 1238 if (rqp->ioc_ssn.ioc_outtoklen <= siz) 1239 goto out; 1240 1241 /* 1242 * Operation completed, but our output token wasn't large enough. 1243 * The re-call below only pulls the token from the kernel. 1244 */ 1245 siz = rqp->ioc_ssn.ioc_outtoklen; 1246 free(rqp->ioc_ssn.ioc_outtok); 1247 rqp->ioc_ssn.ioc_outtok = malloc(siz + 1); 1248 if (rqp->ioc_ssn.ioc_outtok == NULL) { 1249 rc = ENOMEM; 1250 goto out; 1251 } 1252 bzero(rqp->ioc_ssn.ioc_outtok, siz+1); 1253 /* Note: No longer put length in outtok[0] */ 1254 /* *((int *)rqp->ioc_ssn.ioc_outtok) = siz; */ 1255 if (ioctl(ctx->ct_fd, inum, rqp) == -1) 1256 rc = errno; 1257 out: 1258 seteuid(real_uid); /* and back to real user */ 1259 return (rc); 1260 } 1261 1262 int 1263 smb_ctx_findvc(struct smb_ctx *ctx, int level, int flags) 1264 { 1265 struct smbioc_lookup rq; 1266 int error = 0; 1267 1268 if ((error = smb_ctx_gethandle(ctx))) 1269 return (error); 1270 1271 bzero(&rq, sizeof (rq)); 1272 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 1273 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 1274 1275 rq.ioc_flags = flags; 1276 rq.ioc_level = level; 1277 1278 return (smb_ctx_ioctl(ctx, SMBIOC_FINDVC, &rq)); 1279 } 1280 1281 /* 1282 * adds a GSSAPI wrapper 1283 */ 1284 char * 1285 smb_ctx_tkt2gtok(uchar_t *tkt, ulong_t tktlen, 1286 uchar_t **gtokp, ulong_t *gtoklenp) 1287 { 1288 ulong_t bloblen = tktlen; 1289 ulong_t len; 1290 uchar_t krbapreq[2] = "\x01\x00"; /* see RFC 1964 */ 1291 char *failure; 1292 uchar_t *blob = NULL; /* result */ 1293 uchar_t *b; 1294 1295 bloblen += sizeof (krbapreq); 1296 bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen; 1297 len = bloblen; 1298 bloblen = ASNDerCalcTokenLength(bloblen, bloblen); 1299 failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok malloc"); 1300 if (!(blob = malloc(bloblen))) 1301 goto out; 1302 b = blob; 1303 b += ASNDerWriteToken(b, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, len); 1304 b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5); 1305 memcpy(b, krbapreq, sizeof (krbapreq)); 1306 b += sizeof (krbapreq); 1307 failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok insanity check"); 1308 if (b + tktlen != blob + bloblen) 1309 goto out; 1310 memcpy(b, tkt, tktlen); 1311 *gtoklenp = bloblen; 1312 *gtokp = blob; 1313 failure = NULL; 1314 out:; 1315 if (blob && failure) 1316 free(blob); 1317 return (failure); 1318 } 1319 1320 1321 /* 1322 * Initialization for Kerberos, pulled out of smb_ctx_principal2tkt. 1323 * This just gets our cached credentials, if we have any. 1324 * Based on the "klist" command. 1325 */ 1326 char * 1327 smb_ctx_krb5init(struct smb_ctx *ctx) 1328 { 1329 char *failure; 1330 krb5_error_code kerr; 1331 krb5_context kctx = NULL; 1332 krb5_ccache kcc = NULL; 1333 krb5_principal kprin = NULL; 1334 1335 kerr = krb5_init_context(&kctx); 1336 if (kerr) { 1337 failure = "krb5_init_context"; 1338 goto out; 1339 } 1340 ctx->ct_krb5ctx = kctx; 1341 1342 /* non-default would instead use krb5_cc_resolve */ 1343 kerr = krb5_cc_default(kctx, &kcc); 1344 if (kerr) { 1345 failure = "krb5_cc_default"; 1346 goto out; 1347 } 1348 ctx->ct_krb5cc = kcc; 1349 1350 /* 1351 * Get the client principal (ticket), 1352 * or find out if we don't have one. 1353 */ 1354 kerr = krb5_cc_get_principal(kctx, kcc, &kprin); 1355 if (kerr) { 1356 failure = "krb5_cc_get_principal"; 1357 goto out; 1358 } 1359 ctx->ct_krb5cp = kprin; 1360 1361 if (smb_verbose) { 1362 fprintf(stderr, gettext("Ticket cache: %s:%s\n"), 1363 krb5_cc_get_type(kctx, kcc), 1364 krb5_cc_get_name(kctx, kcc)); 1365 } 1366 failure = NULL; 1367 1368 out: 1369 return (failure); 1370 } 1371 1372 1373 /* 1374 * See "Windows 2000 Kerberos Interoperability" paper by 1375 * Christopher Nebergall. RC4 HMAC is the W2K default but 1376 * Samba support lagged (not due to Samba itself, but due to OS' 1377 * Kerberos implementations.) 1378 * 1379 * Only session enc type should matter, not ticket enc type, 1380 * per Sam Hartman on krbdev. 1381 * 1382 * Preauthentication failure topics in krb-protocol may help here... 1383 * try "John Brezak" and/or "Clifford Neuman" too. 1384 */ 1385 static krb5_enctype kenctypes[] = { 1386 ENCTYPE_ARCFOUR_HMAC, /* defined in Tiger krb5.h */ 1387 ENCTYPE_DES_CBC_MD5, 1388 ENCTYPE_DES_CBC_CRC, 1389 ENCTYPE_NULL 1390 }; 1391 1392 /* 1393 * Obtain a kerberos ticket... 1394 * (if TLD != "gov" then pray first) 1395 */ 1396 char * 1397 smb_ctx_principal2tkt( 1398 struct smb_ctx *ctx, char *prin, 1399 uchar_t **tktp, ulong_t *tktlenp) 1400 { 1401 char *failure; 1402 krb5_context kctx = NULL; 1403 krb5_error_code kerr; 1404 krb5_ccache kcc = NULL; 1405 krb5_principal kprin = NULL, cprn = NULL; 1406 krb5_creds kcreds, *kcredsp = NULL; 1407 krb5_auth_context kauth = NULL; 1408 krb5_data kdata, kdata0; 1409 uchar_t *tkt; 1410 1411 memset((char *)&kcreds, 0, sizeof (kcreds)); 1412 kdata0.length = 0; 1413 1414 /* These shoud have been done in smb_ctx_krb5init() */ 1415 if (ctx->ct_krb5ctx == NULL || 1416 ctx->ct_krb5cc == NULL || 1417 ctx->ct_krb5cp == NULL) { 1418 failure = "smb_ctx_krb5init"; 1419 goto out; 1420 } 1421 kctx = ctx->ct_krb5ctx; 1422 kcc = ctx->ct_krb5cc; 1423 cprn = ctx->ct_krb5cp; 1424 1425 failure = "krb5_set_default_tgs_enctypes"; 1426 if ((kerr = krb5_set_default_tgs_enctypes(kctx, kenctypes))) 1427 goto out; 1428 /* 1429 * The following is an unrolling of krb5_mk_req. Something like: 1430 * krb5_mk_req(kctx, &kauth, 0, service(prin), hostname(prin), 1431 * &kdata0, kcc, &kdata);) 1432 * ...except we needed krb5_parse_name not krb5_sname_to_principal. 1433 */ 1434 failure = "krb5_parse_name"; 1435 if ((kerr = krb5_parse_name(kctx, prin, &kprin))) 1436 goto out; 1437 failure = "krb5_copy_principal(server)"; 1438 if ((kerr = krb5_copy_principal(kctx, kprin, &kcreds.server))) 1439 goto out; 1440 failure = "krb5_copy_principal(client)"; 1441 if ((kerr = krb5_copy_principal(kctx, cprn, &kcreds.client))) 1442 goto out; 1443 failure = "krb5_get_credentials"; 1444 if ((kerr = krb5_get_credentials(kctx, 0, kcc, &kcreds, &kcredsp))) 1445 goto out; 1446 failure = "krb5_mk_req_extended"; 1447 if ((kerr = krb5_mk_req_extended(kctx, &kauth, 0, &kdata0, kcredsp, 1448 &kdata))) 1449 goto out; 1450 failure = "malloc"; 1451 if (!(tkt = malloc(kdata.length))) { 1452 krb5_free_data_contents(kctx, &kdata); 1453 goto out; 1454 } 1455 *tktlenp = kdata.length; 1456 memcpy(tkt, kdata.data, kdata.length); 1457 krb5_free_data_contents(kctx, &kdata); 1458 *tktp = tkt; 1459 failure = NULL; 1460 out:; 1461 if (kerr) { 1462 if (!failure) 1463 failure = "smb_ctx_principal2tkt"; 1464 /* 1465 * Avoid logging the typical "No credentials cache found" 1466 */ 1467 if (kerr != KRB5_FCC_NOFILE || 1468 strcmp(failure, "krb5_cc_get_principal")) 1469 com_err(__progname, kerr, failure); 1470 } 1471 if (kauth) 1472 krb5_auth_con_free(kctx, kauth); 1473 if (kcredsp) 1474 krb5_free_creds(kctx, kcredsp); 1475 if (kcreds.server || kcreds.client) 1476 krb5_free_cred_contents(kctx, &kcreds); 1477 if (kprin) 1478 krb5_free_principal(kctx, kprin); 1479 1480 /* Free kctx in smb_ctx_done */ 1481 1482 return (failure); 1483 } 1484 1485 char * 1486 smb_ctx_principal2blob( 1487 struct smb_ctx *ctx, 1488 smbioc_ossn_t *ssn, 1489 char *prin) 1490 { 1491 int rc = 0; 1492 char *failure; 1493 uchar_t *tkt = NULL; 1494 ulong_t tktlen; 1495 uchar_t *gtok = NULL; /* gssapi token */ 1496 ulong_t gtoklen; /* gssapi token length */ 1497 SPNEGO_TOKEN_HANDLE stok = NULL; /* spnego token */ 1498 void *blob = NULL; /* result */ 1499 ulong_t bloblen; /* result length */ 1500 1501 if ((failure = smb_ctx_principal2tkt(ctx, prin, &tkt, &tktlen))) 1502 goto out; 1503 if ((failure = smb_ctx_tkt2gtok(tkt, tktlen, >ok, >oklen))) 1504 goto out; 1505 /* 1506 * RFC says to send NegTokenTarg now. So does MS docs. But 1507 * win2k gives ERRbaduid if we do... we must send 1508 * another NegTokenInit now! 1509 */ 1510 failure = "spnegoCreateNegTokenInit"; 1511 if ((rc = spnegoCreateNegTokenInit(spnego_mech_oid_Kerberos_V5_Legacy, 1512 0, gtok, gtoklen, NULL, 0, &stok))) 1513 goto out; 1514 failure = "spnegoTokenGetBinary(NULL)"; 1515 rc = spnegoTokenGetBinary(stok, NULL, &bloblen); 1516 if (rc != SPNEGO_E_BUFFER_TOO_SMALL) 1517 goto out; 1518 failure = "malloc"; 1519 if (!(blob = malloc((size_t)bloblen))) 1520 goto out; 1521 /* No longer store length at start of blob. */ 1522 /* *blob = bloblen; */ 1523 failure = "spnegoTokenGetBinary"; 1524 if ((rc = spnegoTokenGetBinary(stok, blob, &bloblen))) 1525 goto out; 1526 ssn->ioc_intoklen = bloblen; 1527 ssn->ioc_intok = blob; 1528 failure = NULL; 1529 out:; 1530 if (rc) { 1531 /* XXX better is to embed rc in failure */ 1532 smb_error(dgettext(TEXT_DOMAIN, 1533 "spnego principal2blob error %d"), 0, -rc); 1534 if (!failure) 1535 failure = "spnego"; 1536 } 1537 if (blob && failure) 1538 free(blob); 1539 if (stok) 1540 spnegoFreeData(stok); 1541 if (gtok) 1542 free(gtok); 1543 if (tkt) 1544 free(tkt); 1545 return (failure); 1546 } 1547 1548 1549 #if 0 1550 void 1551 prblob(uchar_t *b, size_t len) 1552 { 1553 while (len--) 1554 fprintf(stderr, "%02x", *b++); 1555 fprintf(stderr, "\n"); 1556 } 1557 #endif 1558 1559 1560 /* 1561 * We navigate the SPNEGO & ASN1 encoding to find a kerberos principal 1562 * Note: driver no longer puts length at start of blob. 1563 */ 1564 char * 1565 smb_ctx_blob2principal( 1566 struct smb_ctx *ctx, 1567 smbioc_ossn_t *ssn, 1568 char **prinp) 1569 { 1570 uchar_t *blob = ssn->ioc_outtok; 1571 size_t len = ssn->ioc_outtoklen; 1572 int rc = 0; 1573 SPNEGO_TOKEN_HANDLE stok = NULL; 1574 int indx = 0; 1575 char *failure; 1576 uchar_t flags = 0; 1577 unsigned long plen = 0; 1578 uchar_t *prin; 1579 1580 #if 0 1581 fprintf(stderr, "blob from negotiate:\n"); 1582 prblob(blob, len); 1583 #endif 1584 1585 /* Skip the GUID */ 1586 assert(len >= SMB_GUIDLEN); 1587 blob += SMB_GUIDLEN; 1588 len -= SMB_GUIDLEN; 1589 1590 failure = "spnegoInitFromBinary"; 1591 if ((rc = spnegoInitFromBinary(blob, len, &stok))) 1592 goto out; 1593 /* 1594 * Needn't use new Kerberos OID - the Legacy one is fine. 1595 */ 1596 failure = "spnegoIsMechTypeAvailable"; 1597 if (spnegoIsMechTypeAvailable(stok, spnego_mech_oid_Kerberos_V5_Legacy, 1598 &indx)) 1599 goto out; 1600 /* 1601 * Ignoring optional context flags for now. May want to pass 1602 * them to krb5 layer. XXX 1603 */ 1604 if (!spnegoGetContextFlags(stok, &flags)) 1605 fprintf(stderr, dgettext(TEXT_DOMAIN, 1606 "spnego context flags 0x%x\n"), flags); 1607 failure = "spnegoGetMechListMIC(NULL)"; 1608 rc = spnegoGetMechListMIC(stok, NULL, &plen); 1609 if (rc != SPNEGO_E_BUFFER_TOO_SMALL) 1610 goto out; 1611 failure = "malloc"; 1612 if (!(prin = malloc(plen + 1))) 1613 goto out; 1614 failure = "spnegoGetMechListMIC"; 1615 if ((rc = spnegoGetMechListMIC(stok, prin, &plen))) { 1616 free(prin); 1617 goto out; 1618 } 1619 prin[plen] = '\0'; 1620 *prinp = (char *)prin; 1621 failure = NULL; 1622 out:; 1623 if (stok) 1624 spnegoFreeData(stok); 1625 if (rc) { 1626 /* XXX better is to embed rc in failure */ 1627 smb_error(dgettext(TEXT_DOMAIN, 1628 "spnego blob2principal error %d"), 0, -rc); 1629 if (!failure) 1630 failure = "spnego"; 1631 } 1632 return (failure); 1633 } 1634 1635 1636 int 1637 smb_ctx_negotiate(struct smb_ctx *ctx, int level, int flags, char *workgroup) 1638 { 1639 struct smbioc_lookup rq; 1640 int error = 0; 1641 char *failure = NULL; 1642 char *principal = NULL; 1643 char c; 1644 int i; 1645 ssize_t *outtoklen; 1646 uchar_t *blob; 1647 1648 /* 1649 * We leave ct_secblob set iff extended security 1650 * negotiation succeeds. 1651 */ 1652 if (ctx->ct_secblob) { 1653 free(ctx->ct_secblob); 1654 ctx->ct_secblob = NULL; 1655 } 1656 #ifdef XXX 1657 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 1658 smb_error(dgettext(TEXT_DOMAIN, 1659 "smb_ctx_lookup() data is not resolved"), 0); 1660 return (EINVAL); 1661 } 1662 #endif 1663 if ((error = smb_ctx_gethandle(ctx))) 1664 return (error); 1665 1666 bzero(&rq, sizeof (rq)); 1667 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 1668 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 1669 1670 /* 1671 * Find out if we have a Kerberos ticket, 1672 * and only offer SPNEGO if we have one. 1673 */ 1674 failure = smb_ctx_krb5init(ctx); 1675 if (failure) { 1676 if (smb_verbose) 1677 smb_error(failure, 0); 1678 goto out; 1679 } 1680 1681 rq.ioc_flags = flags; 1682 rq.ioc_level = level; 1683 rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC; 1684 error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq); 1685 if (error) { 1686 failure = dgettext(TEXT_DOMAIN, "negotiate failed"); 1687 smb_error(failure, error); 1688 if (error == ETIMEDOUT) 1689 return (error); 1690 goto out; 1691 } 1692 /* 1693 * If the server capabilities did not include 1694 * SMB_CAP_EXT_SECURITY then the driver clears 1695 * the flag SMBVOPT_EXT_SEC for us. 1696 * XXX: should add the capabilities to ioc_ssn 1697 * XXX: see comment in driver - smb_usr.c 1698 */ 1699 failure = dgettext(TEXT_DOMAIN, "SPNEGO unsupported"); 1700 if ((rq.ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC) == 0) { 1701 if (smb_verbose) 1702 smb_error(failure, 0); 1703 /* 1704 * Do regular (old style) NTLM or NTLMv2 1705 * Nothing more to do here in negotiate. 1706 */ 1707 return (0); 1708 } 1709 1710 /* 1711 * Capabilities DO include SMB_CAP_EXT_SECURITY, 1712 * so this should be an SPNEGO security blob. 1713 * Parse the ASN.1/DER, prepare response(s). 1714 * XXX: Handle STATUS_MORE_PROCESSING_REQUIRED? 1715 * XXX: Requires additional session setup calls. 1716 */ 1717 if (rq.ioc_ssn.ioc_outtoklen <= SMB_GUIDLEN) 1718 goto out; 1719 /* some servers send padding junk */ 1720 blob = rq.ioc_ssn.ioc_outtok; 1721 if (blob[0] == 0) 1722 goto out; 1723 1724 failure = smb_ctx_blob2principal( 1725 ctx, &rq.ioc_ssn, &principal); 1726 if (failure) 1727 goto out; 1728 failure = smb_ctx_principal2blob( 1729 ctx, &rq.ioc_ssn, principal); 1730 if (failure) 1731 goto out; 1732 1733 /* Success! Save the blob to send next. */ 1734 ctx->ct_secblob = rq.ioc_ssn.ioc_intok; 1735 ctx->ct_secbloblen = rq.ioc_ssn.ioc_intoklen; 1736 rq.ioc_ssn.ioc_intok = NULL; 1737 1738 out: 1739 if (principal) 1740 free(principal); 1741 if (rq.ioc_ssn.ioc_intok) 1742 free(rq.ioc_ssn.ioc_intok); 1743 if (rq.ioc_ssn.ioc_outtok) 1744 free(rq.ioc_ssn.ioc_outtok); 1745 if (!failure) 1746 return (0); /* Success! */ 1747 1748 /* 1749 * Negotiate failed with "extended security". 1750 * 1751 * XXX: If we are doing SPNEGO correctly, 1752 * we should never get here unless the user 1753 * supplied invalid authentication data, 1754 * or we saw some kind of protocol error. 1755 * 1756 * XXX: The error message below should be 1757 * XXX: unconditional (remove "if verbose") 1758 * XXX: but not until we have "NTLMSSP" 1759 * Avoid spew for anticipated failure modes 1760 * but enable this with the verbose flag 1761 */ 1762 if (smb_verbose) { 1763 smb_error(dgettext(TEXT_DOMAIN, 1764 "%s (extended security negotiate)"), error, failure); 1765 } 1766 1767 /* 1768 * XXX: Try again using NTLM (or NTLMv2) 1769 * XXX: Normal clients don't do this. 1770 * XXX: Should just return an error, but 1771 * keep the fall-back to NTLM for now. 1772 * 1773 * Start over with a new connection. 1774 */ 1775 if ((error = smb_ctx_gethandle(ctx))) 1776 return (error); 1777 bzero(&rq, sizeof (rq)); 1778 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 1779 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 1780 rq.ioc_flags = flags; 1781 rq.ioc_level = level; 1782 /* Note: NO SMBVOPT_EXT_SEC */ 1783 error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq); 1784 if (error) { 1785 failure = dgettext(TEXT_DOMAIN, "negotiate failed"); 1786 smb_error(failure, error); 1787 rpc_cleanup_smbctx(ctx); 1788 close(ctx->ct_fd); 1789 ctx->ct_fd = -1; 1790 return (error); 1791 } 1792 1793 /* 1794 * Used to copy the workgroup out of the SMB_NEGOTIATE response 1795 * here, to default our domain name to be the same as the server. 1796 * Not a good idea: Unnecessary at best, and sometimes wrong, i.e. 1797 * when our account is in a trusted domain. 1798 */ 1799 1800 return (error); 1801 } 1802 1803 1804 int 1805 smb_ctx_tdis(struct smb_ctx *ctx) 1806 { 1807 struct smbioc_lookup rq; /* XXX may be used, someday */ 1808 int error = 0; 1809 1810 if (ctx->ct_fd < 0) { 1811 smb_error(dgettext(TEXT_DOMAIN, 1812 "tree disconnect without handle?!"), 0); 1813 return (EINVAL); 1814 } 1815 if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) { 1816 smb_error(dgettext(TEXT_DOMAIN, 1817 "tree disconnect without session?!"), 0); 1818 return (EINVAL); 1819 } 1820 bzero(&rq, sizeof (rq)); 1821 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 1822 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 1823 if (ioctl(ctx->ct_fd, SMBIOC_TDIS, &rq) == -1) { 1824 error = errno; 1825 smb_error(dgettext(TEXT_DOMAIN, 1826 "tree disconnect failed"), error); 1827 } 1828 return (error); 1829 } 1830 1831 1832 int 1833 smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) 1834 { 1835 struct smbioc_lookup rq; 1836 int error = 0; 1837 char *failure = NULL; 1838 1839 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 1840 smb_error(dgettext(TEXT_DOMAIN, 1841 "smb_ctx_lookup() data is not resolved"), 0); 1842 return (EINVAL); 1843 } 1844 if (ctx->ct_fd < 0) { 1845 smb_error(dgettext(TEXT_DOMAIN, 1846 "handle from smb_ctx_nego() gone?!"), 0); 1847 return (EINVAL); 1848 } 1849 if (!(flags & SMBLK_CREATE)) 1850 return (0); 1851 bzero(&rq, sizeof (rq)); 1852 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 1853 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 1854 rq.ioc_flags = flags; 1855 rq.ioc_level = level; 1856 1857 /* 1858 * Iff we have a security blob, we're using 1859 * extended security... 1860 */ 1861 if (ctx->ct_secblob) { 1862 rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC; 1863 if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) { 1864 rq.ioc_ssn.ioc_intok = ctx->ct_secblob; 1865 rq.ioc_ssn.ioc_intoklen = ctx->ct_secbloblen; 1866 error = smb_ctx_ioctl(ctx, SMBIOC_SSNSETUP, &rq); 1867 } 1868 rq.ioc_ssn.ioc_intok = NULL; 1869 if (error) { 1870 failure = dgettext(TEXT_DOMAIN, 1871 "session setup failed"); 1872 } else { 1873 ctx->ct_flags |= SMBCF_SSNACTIVE; 1874 if ((error = smb_ctx_ioctl(ctx, SMBIOC_TCON, &rq))) 1875 failure = dgettext(TEXT_DOMAIN, 1876 "tree connect failed"); 1877 } 1878 if (rq.ioc_ssn.ioc_intok) 1879 free(rq.ioc_ssn.ioc_intok); 1880 if (rq.ioc_ssn.ioc_outtok) 1881 free(rq.ioc_ssn.ioc_outtok); 1882 if (!failure) 1883 return (0); 1884 smb_error(dgettext(TEXT_DOMAIN, 1885 "%s (extended security lookup2)"), error, failure); 1886 /* unwise to failback to NTLM now */ 1887 return (error); 1888 } 1889 1890 /* 1891 * Otherwise we're doing plain old NTLM 1892 */ 1893 seteuid(eff_uid); /* restore setuid root briefly */ 1894 if ((ctx->ct_flags & SMBCF_SSNACTIVE) == 0) { 1895 /* 1896 * This is the magic that tells the driver to 1897 * copy the password from the keychain, and 1898 * whether to use the system name or the 1899 * account domain to lookup the keychain. 1900 */ 1901 if (ctx->ct_flags & SMBCF_KCFOUND) 1902 rq.ioc_ssn.ioc_opt |= SMBVOPT_USE_KEYCHAIN; 1903 if (ctx->ct_flags & SMBCF_KCDOMAIN) 1904 rq.ioc_ssn.ioc_opt |= SMBVOPT_KC_DOMAIN; 1905 if (ioctl(ctx->ct_fd, SMBIOC_SSNSETUP, &rq) < 0) { 1906 error = errno; 1907 failure = dgettext(TEXT_DOMAIN, "session setup"); 1908 goto out; 1909 } 1910 ctx->ct_flags |= SMBCF_SSNACTIVE; 1911 } 1912 if (ioctl(ctx->ct_fd, SMBIOC_TCON, &rq) == -1) { 1913 error = errno; 1914 failure = dgettext(TEXT_DOMAIN, "tree connect"); 1915 } 1916 1917 out: 1918 seteuid(real_uid); /* and back to real user */ 1919 if (failure) { 1920 error = errno; 1921 smb_error(dgettext(TEXT_DOMAIN, 1922 "%s phase failed"), error, failure); 1923 } 1924 return (error); 1925 } 1926 1927 /* 1928 * Return the hflags2 word for an smb_ctx. 1929 */ 1930 int 1931 smb_ctx_flags2(struct smb_ctx *ctx) 1932 { 1933 uint16_t flags2; 1934 1935 if (ioctl(ctx->ct_fd, SMBIOC_FLAGS2, &flags2) == -1) { 1936 smb_error(dgettext(TEXT_DOMAIN, 1937 "can't get flags2 for a session"), errno); 1938 return (-1); 1939 } 1940 printf(dgettext(TEXT_DOMAIN, "Flags2 value is %d\n"), flags2); 1941 return (flags2); 1942 } 1943 1944 /* 1945 * level values: 1946 * 0 - default 1947 * 1 - server 1948 * 2 - server:user 1949 * 3 - server:user:share 1950 */ 1951 static int 1952 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 1953 { 1954 char *p; 1955 int error; 1956 1957 #ifdef NOT_DEFINED 1958 if (level > 0) { 1959 rc_getstringptr(smb_rc, sname, "charsets", &p); 1960 if (p) { 1961 error = smb_ctx_setcharset(ctx, p); 1962 if (error) 1963 smb_error(dgettext(TEXT_DOMAIN, 1964 "charset specification in the section '%s' ignored"), 1965 error, sname); 1966 } 1967 } 1968 #endif 1969 1970 if (level <= 1) { 1971 /* Section is: [default] or [server] */ 1972 1973 rc_getint(smb_rc, sname, "timeout", 1974 &ctx->ct_ssn.ioc_timeout); 1975 1976 #ifdef NOT_DEFINED 1977 rc_getint(smb_rc, sname, "retry_count", 1978 &ctx->ct_ssn.ioc_retrycount); 1979 rc_getstringptr(smb_rc, sname, "use_negprot_domain", &p); 1980 if (p && strcmp(p, "NO") == 0) 1981 ctx->ct_flags |= SMBCF_NONEGDOM; 1982 #endif 1983 1984 rc_getstringptr(smb_rc, sname, "minauth", &p); 1985 if (p) { 1986 /* 1987 * "minauth" was set in this section; override 1988 * the current minimum authentication setting. 1989 */ 1990 ctx->ct_ssn.ioc_opt &= ~SMBVOPT_MINAUTH; 1991 if (strcmp(p, "kerberos") == 0) { 1992 /* 1993 * Don't fall back to NTLMv2, NTLMv1, or 1994 * a clear text password. 1995 */ 1996 ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_KERBEROS; 1997 } else if (strcmp(p, "ntlmv2") == 0) { 1998 /* 1999 * Don't fall back to NTLMv1 or a clear 2000 * text password. 2001 */ 2002 ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLMV2; 2003 } else if (strcmp(p, "ntlm") == 0) { 2004 /* 2005 * Don't send the LM response over the wire. 2006 */ 2007 ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLM; 2008 } else if (strcmp(p, "lm") == 0) { 2009 /* 2010 * Fail if the server doesn't do encrypted 2011 * passwords. 2012 */ 2013 ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_LM; 2014 } else if (strcmp(p, "none") == 0) { 2015 /* 2016 * Anything goes. 2017 * (The following statement should be 2018 * optimized away.) 2019 */ 2020 /* LINTED */ 2021 ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NONE; 2022 } else { 2023 /* 2024 * Unknown minimum authentication level. 2025 */ 2026 smb_error(dgettext(TEXT_DOMAIN, 2027 "invalid minimum authentication level \"%s\" specified in the section %s"), 2028 0, p, sname); 2029 return (EINVAL); 2030 } 2031 } 2032 2033 /* 2034 * Domain name. Allow both keywords: 2035 * "workgroup", "domain" 2036 * 2037 * Note: these are NOT marked "from CMD". 2038 * See long comment at smb_ctx_init() 2039 */ 2040 rc_getstringptr(smb_rc, sname, "workgroup", &p); 2041 if (p) { 2042 nls_str_upper(p, p); 2043 error = smb_ctx_setworkgroup(ctx, p, 0); 2044 if (error) 2045 smb_error(dgettext(TEXT_DOMAIN, 2046 "workgroup specification in the " 2047 "section '%s' ignored"), error, sname); 2048 } 2049 rc_getstringptr(smb_rc, sname, "domain", &p); 2050 if (p) { 2051 nls_str_upper(p, p); 2052 error = smb_ctx_setworkgroup(ctx, p, 0); 2053 if (error) 2054 smb_error(dgettext(TEXT_DOMAIN, 2055 "domain specification in the " 2056 "section '%s' ignored"), error, sname); 2057 } 2058 2059 rc_getstringptr(smb_rc, sname, "user", &p); 2060 if (p) { 2061 error = smb_ctx_setuser(ctx, p, 0); 2062 if (error) 2063 smb_error(dgettext(TEXT_DOMAIN, 2064 "user specification in the " 2065 "section '%s' ignored"), error, sname); 2066 } 2067 } 2068 2069 if (level == 1) { 2070 /* Section is: [server] */ 2071 rc_getstringptr(smb_rc, sname, "addr", &p); 2072 if (p) { 2073 error = smb_ctx_setsrvaddr(ctx, p); 2074 if (error) { 2075 smb_error(dgettext(TEXT_DOMAIN, 2076 "invalid address specified in section %s"), 2077 0, sname); 2078 return (error); 2079 } 2080 } 2081 } 2082 2083 rc_getstringptr(smb_rc, sname, "password", &p); 2084 if (p) { 2085 error = smb_ctx_setpassword(ctx, p, 0); 2086 if (error) 2087 smb_error(dgettext(TEXT_DOMAIN, 2088 "password specification in the section '%s' ignored"), 2089 error, sname); 2090 } 2091 2092 return (0); 2093 } 2094 2095 /* 2096 * read rc file as follows: 2097 * 0: read [default] section 2098 * 1: override with [server] section 2099 * 2: override with [server:user] section 2100 * 3: override with [server:user:share] section 2101 * Since absence of rcfile is not fatal, silently ignore this fact. 2102 * smb_rc file should be closed by caller. 2103 */ 2104 int 2105 smb_ctx_readrc(struct smb_ctx *ctx) 2106 { 2107 char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + 2108 SMB_MAXSHARENAMELEN + 4]; 2109 2110 if (smb_open_rcfile(ctx) != 0) 2111 goto done; 2112 2113 /* 2114 * default parameters (level=0) 2115 */ 2116 smb_ctx_readrcsection(ctx, "default", 0); 2117 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 2118 2119 /* 2120 * If we don't have a server name, we can't read any of the 2121 * [server...] sections. 2122 */ 2123 if (ctx->ct_ssn.ioc_srvname[0] == 0) 2124 goto done; 2125 2126 /* 2127 * SERVER parameters. 2128 */ 2129 smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1); 2130 2131 /* 2132 * If we don't have a user name, we can't read any of the 2133 * [server:user...] sections. 2134 */ 2135 if (ctx->ct_ssn.ioc_user[0] == 0) 2136 goto done; 2137 2138 /* 2139 * SERVER:USER parameters 2140 */ 2141 snprintf(sname, sizeof (sname), "%s:%s", 2142 ctx->ct_ssn.ioc_srvname, 2143 ctx->ct_ssn.ioc_user); 2144 smb_ctx_readrcsection(ctx, sname, 2); 2145 2146 /* 2147 * If we don't have a share name, we can't read any of the 2148 * [server:user:share] sections. 2149 */ 2150 if (ctx->ct_sh.ioc_share[0] != 0) { 2151 /* 2152 * SERVER:USER:SHARE parameters 2153 */ 2154 snprintf(sname, sizeof (sname), "%s:%s:%s", 2155 ctx->ct_ssn.ioc_srvname, 2156 ctx->ct_ssn.ioc_user, 2157 ctx->ct_sh.ioc_share); 2158 smb_ctx_readrcsection(ctx, sname, 3); 2159 } 2160 2161 done: 2162 if (smb_debug) 2163 dump_ctx("after smb_ctx_readrc", ctx); 2164 2165 return (0); 2166 } 2167