1 /* 2 * Copyright (c) 2000-2002, 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.24 2002/04/13 14:35:28 bp Exp $ 33 * $FreeBSD$ 34 */ 35 #include <sys/param.h> 36 #include <sys/sysctl.h> 37 #include <sys/ioctl.h> 38 #include <sys/time.h> 39 #include <sys/mount.h> 40 #include <fcntl.h> 41 #include <ctype.h> 42 #include <errno.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <stdlib.h> 46 #include <pwd.h> 47 #include <grp.h> 48 #include <unistd.h> 49 #include <sys/iconv.h> 50 51 #define NB_NEEDRESOLVER 52 53 #include <netsmb/smb_lib.h> 54 #include <netsmb/netbios.h> 55 #include <netsmb/nb_lib.h> 56 #include <netsmb/smb_conn.h> 57 #include <cflib.h> 58 59 /* 60 * Prescan command line for [-U user] argument 61 * and fill context with defaults 62 */ 63 int 64 smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[], 65 int minlevel, int maxlevel, int sharetype) 66 { 67 int opt, error = 0; 68 uid_t euid; 69 const char *arg, *cp; 70 struct passwd *pwd; 71 72 bzero(ctx,sizeof(*ctx)); 73 error = nb_ctx_create(&ctx->ct_nb); 74 if (error) 75 return error; 76 ctx->ct_fd = -1; 77 ctx->ct_parsedlevel = SMBL_NONE; 78 ctx->ct_minlevel = minlevel; 79 ctx->ct_maxlevel = maxlevel; 80 ctx->ct_smbtcpport = SMB_TCP_PORT; 81 82 ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE; 83 ctx->ct_ssn.ioc_timeout = 15; 84 ctx->ct_ssn.ioc_retrycount = 4; 85 ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER; 86 ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP; 87 ctx->ct_ssn.ioc_mode = SMBM_EXEC; 88 ctx->ct_ssn.ioc_rights = SMBM_DEFAULT; 89 90 ctx->ct_sh.ioc_opt = SMBVOPT_CREATE; 91 ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 92 ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 93 ctx->ct_sh.ioc_mode = SMBM_EXEC; 94 ctx->ct_sh.ioc_rights = SMBM_DEFAULT; 95 ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 96 ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 97 98 nb_ctx_setscope(ctx->ct_nb, ""); 99 euid = geteuid(); 100 if ((pwd = getpwuid(euid)) != NULL) { 101 smb_ctx_setuser(ctx, pwd->pw_name); 102 endpwent(); 103 } else if (euid == 0) 104 smb_ctx_setuser(ctx, "root"); 105 else 106 return 0; 107 if (argv == NULL) 108 return 0; 109 for (opt = 1; opt < argc; opt++) { 110 cp = argv[opt]; 111 if (strncmp(cp, "//", 2) != 0) 112 continue; 113 error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp); 114 if (error) 115 return error; 116 ctx->ct_uncnext = cp; 117 break; 118 } 119 while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) { 120 arg = cf_optarg; 121 switch (opt) { 122 case 'E': 123 error = smb_ctx_setcharset(ctx, arg); 124 if (error) 125 return error; 126 break; 127 case 'L': 128 error = nls_setlocale(arg); 129 if (error) 130 break; 131 break; 132 case 'U': 133 error = smb_ctx_setuser(ctx, arg); 134 break; 135 } 136 } 137 cf_optind = cf_optreset = 1; 138 return error; 139 } 140 141 void 142 smb_ctx_done(struct smb_ctx *ctx) 143 { 144 if (ctx->ct_ssn.ioc_server) 145 nb_snbfree(ctx->ct_ssn.ioc_server); 146 if (ctx->ct_ssn.ioc_local) 147 nb_snbfree(ctx->ct_ssn.ioc_local); 148 if (ctx->ct_srvaddr) 149 free(ctx->ct_srvaddr); 150 if (ctx->ct_nb) 151 nb_ctx_done(ctx->ct_nb); 152 } 153 154 static int 155 getsubstring(const char *p, u_char sep, char *dest, int maxlen, const char **next) 156 { 157 int len; 158 159 maxlen--; 160 for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 161 if (*p == 0) 162 return EINVAL; 163 *dest = *p; 164 } 165 *dest = 0; 166 *next = *p ? p + 1 : p; 167 return 0; 168 } 169 170 /* 171 * Here we expect something like "[proto:]//[user@]host[:psmb[:pnb]][/share][/path]" 172 */ 173 int 174 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, 175 const char **next) 176 { 177 const char *p = unc; 178 char *p1, *psmb, *pnb; 179 char tmp[1024]; 180 int error ; 181 182 ctx->ct_parsedlevel = SMBL_NONE; 183 if (*p++ != '/' || *p++ != '/') { 184 smb_error("UNC should start with '//'", 0); 185 return EINVAL; 186 } 187 p1 = tmp; 188 error = getsubstring(p, '@', p1, sizeof(tmp), &p); 189 if (!error) { 190 if (ctx->ct_maxlevel < SMBL_VC) { 191 smb_error("no user name required", 0); 192 return EINVAL; 193 } 194 error = smb_ctx_setuser(ctx, tmp); 195 if (error) 196 return error; 197 ctx->ct_parsedlevel = SMBL_VC; 198 } 199 error = getsubstring(p, '/', p1, sizeof(tmp), &p); 200 if (error) { 201 error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 202 if (error) { 203 smb_error("no server name found", 0); 204 return error; 205 } 206 } 207 if (*p1 == 0) { 208 smb_error("empty server name", 0); 209 return EINVAL; 210 } 211 /* 212 * Check for port number specification. 213 */ 214 psmb = strchr(tmp, ':'); 215 if (psmb) { 216 *psmb++ = '\0'; 217 pnb = strchr(psmb, ':'); 218 if (pnb) { 219 *pnb++ = '\0'; 220 error = smb_ctx_setnbport(ctx, atoi(pnb)); 221 if (error) { 222 smb_error("Invalid NetBIOS port number", 0); 223 return error; 224 } 225 } 226 error = smb_ctx_setsmbport(ctx, atoi(psmb)); 227 if (error) { 228 smb_error("Invalid SMB port number", 0); 229 return error; 230 } 231 } 232 error = smb_ctx_setserver(ctx, tmp); 233 if (error) 234 return error; 235 if (sharetype == SMB_ST_NONE) { 236 *next = p; 237 return 0; 238 } 239 if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 240 smb_error("no share name required", 0); 241 return EINVAL; 242 } 243 error = getsubstring(p, '/', p1, sizeof(tmp), &p); 244 if (error) { 245 error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 246 if (error) { 247 smb_error("unexpected end of line", 0); 248 return error; 249 } 250 } 251 if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) { 252 smb_error("empty share name", 0); 253 return EINVAL; 254 } 255 *next = p; 256 if (*p1 == 0) 257 return 0; 258 error = smb_ctx_setshare(ctx, p1, sharetype); 259 return error; 260 } 261 262 int 263 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 264 { 265 char *cp, *servercs, *localcs; 266 int cslen = sizeof(ctx->ct_ssn.ioc_localcs); 267 int scslen, lcslen, error; 268 269 cp = strchr(arg, ':'); 270 lcslen = cp ? (cp - arg) : 0; 271 if (lcslen == 0 || lcslen >= cslen) { 272 smb_error("invalid local charset specification (%s)", 0, arg); 273 return EINVAL; 274 } 275 scslen = (size_t)strlen(++cp); 276 if (scslen == 0 || scslen >= cslen) { 277 smb_error("invalid server charset specification (%s)", 0, arg); 278 return EINVAL; 279 } 280 localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 281 localcs[lcslen] = 0; 282 servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 283 error = nls_setrecode(localcs, servercs); 284 if (error == 0) 285 return 0; 286 smb_error("can't initialize iconv support (%s:%s)", 287 error, localcs, servercs); 288 localcs[0] = 0; 289 servercs[0] = 0; 290 return error; 291 } 292 293 int 294 smb_ctx_setserver(struct smb_ctx *ctx, const char *name) 295 { 296 if (strlen(name) > SMB_MAXSRVNAMELEN) { 297 smb_error("server name '%s' too long", 0, name); 298 return ENAMETOOLONG; 299 } 300 nls_str_upper(ctx->ct_ssn.ioc_srvname, name); 301 return 0; 302 } 303 304 int 305 smb_ctx_setnbport(struct smb_ctx *ctx, int port) 306 { 307 if (port < 1 || port > 0xffff) 308 return EINVAL; 309 ctx->ct_nb->nb_nmbtcpport = port; 310 return 0; 311 } 312 313 int 314 smb_ctx_setsmbport(struct smb_ctx *ctx, int port) 315 { 316 if (port < 1 || port > 0xffff) 317 return EINVAL; 318 ctx->ct_smbtcpport = port; 319 ctx->ct_nb->nb_smbtcpport = port; 320 return 0; 321 } 322 323 int 324 smb_ctx_setuser(struct smb_ctx *ctx, const char *name) 325 { 326 if (strlen(name) > SMB_MAXUSERNAMELEN) { 327 smb_error("user name '%s' too long", 0, name); 328 return ENAMETOOLONG; 329 } 330 nls_str_upper(ctx->ct_ssn.ioc_user, name); 331 return 0; 332 } 333 334 int 335 smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name) 336 { 337 if (strlen(name) > SMB_MAXUSERNAMELEN) { 338 smb_error("workgroup name '%s' too long", 0, name); 339 return ENAMETOOLONG; 340 } 341 nls_str_upper(ctx->ct_ssn.ioc_workgroup, name); 342 return 0; 343 } 344 345 int 346 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd) 347 { 348 if (passwd == NULL) 349 return EINVAL; 350 if (strlen(passwd) > SMB_MAXPASSWORDLEN) { 351 smb_error("password too long", 0); 352 return ENAMETOOLONG; 353 } 354 if (strncmp(passwd, "$$1", 3) == 0) 355 smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); 356 else 357 strcpy(ctx->ct_ssn.ioc_password, passwd); 358 strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); 359 return 0; 360 } 361 362 int 363 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 364 { 365 if (strlen(share) > SMB_MAXSHARENAMELEN) { 366 smb_error("share name '%s' too long", 0, share); 367 return ENAMETOOLONG; 368 } 369 nls_str_upper(ctx->ct_sh.ioc_share, share); 370 if (share[0] != 0) 371 ctx->ct_parsedlevel = SMBL_SHARE; 372 ctx->ct_sh.ioc_stype = stype; 373 return 0; 374 } 375 376 int 377 smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 378 { 379 if (addr == NULL || addr[0] == 0) 380 return EINVAL; 381 if (ctx->ct_srvaddr) 382 free(ctx->ct_srvaddr); 383 if ((ctx->ct_srvaddr = strdup(addr)) == NULL) 384 return ENOMEM; 385 return 0; 386 } 387 388 static int 389 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 390 { 391 struct group *gr; 392 struct passwd *pw; 393 char *cp; 394 395 cp = strchr(pair, ':'); 396 if (cp) { 397 *cp++ = '\0'; 398 if (*cp) { 399 gr = getgrnam(cp); 400 if (gr) { 401 *gid = gr->gr_gid; 402 } else 403 smb_error("Invalid group name %s, ignored", 404 0, cp); 405 } 406 } 407 if (*pair) { 408 pw = getpwnam(pair); 409 if (pw) { 410 *uid = pw->pw_uid; 411 } else 412 smb_error("Invalid user name %s, ignored", 0, pair); 413 } 414 endpwent(); 415 return 0; 416 } 417 418 int 419 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 420 { 421 int error = 0; 422 char *p, *cp; 423 424 switch(opt) { 425 case 'U': 426 break; 427 case 'I': 428 error = smb_ctx_setsrvaddr(ctx, arg); 429 break; 430 case 'M': 431 ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8); 432 if (*cp == '/') { 433 ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8); 434 ctx->ct_flags |= SMBCF_SRIGHTS; 435 } 436 break; 437 case 'N': 438 ctx->ct_flags |= SMBCF_NOPWD; 439 break; 440 case 'O': 441 p = strdup(arg); 442 cp = strchr(p, '/'); 443 if (cp) { 444 *cp++ = '\0'; 445 error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner, 446 &ctx->ct_sh.ioc_group); 447 } 448 if (*p && error == 0) { 449 error = smb_parse_owner(p, &ctx->ct_ssn.ioc_owner, 450 &ctx->ct_ssn.ioc_group); 451 } 452 free(p); 453 break; 454 case 'P': 455 /* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT;*/ 456 break; 457 case 'R': 458 ctx->ct_ssn.ioc_retrycount = atoi(arg); 459 break; 460 case 'T': 461 ctx->ct_ssn.ioc_timeout = atoi(arg); 462 break; 463 case 'W': 464 error = smb_ctx_setworkgroup(ctx, arg); 465 break; 466 } 467 return error; 468 } 469 470 #if 0 471 static void 472 smb_hexdump(const u_char *buf, int len) { 473 int ofs = 0; 474 475 while (len--) { 476 if (ofs % 16 == 0) 477 printf("\n%02X: ", ofs); 478 printf("%02x ", *buf++); 479 ofs++; 480 } 481 printf("\n"); 482 } 483 #endif 484 485 486 static int 487 smb_addiconvtbl(const char *to, const char *from, const u_char *tbl) 488 { 489 int error; 490 491 error = kiconv_add_xlat_table(to, from, tbl); 492 if (error && error != EEXIST) { 493 smb_error("can not setup kernel iconv table (%s:%s)", error, 494 from, to); 495 return error; 496 } 497 return 0; 498 } 499 500 /* 501 * Verify context before connect operation(s), 502 * lookup specified server and try to fill all forgotten fields. 503 */ 504 int 505 smb_ctx_resolve(struct smb_ctx *ctx) 506 { 507 struct smbioc_ossn *ssn = &ctx->ct_ssn; 508 struct smbioc_oshare *sh = &ctx->ct_sh; 509 struct nb_name nn; 510 struct sockaddr *sap; 511 struct sockaddr_nb *salocal, *saserver; 512 char *cp; 513 int error = 0; 514 515 ctx->ct_flags &= ~SMBCF_RESOLVED; 516 if (ssn->ioc_srvname[0] == 0) { 517 smb_error("no server name specified", 0); 518 return EINVAL; 519 } 520 if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) { 521 smb_error("no share name specified for %s@%s", 522 0, ssn->ioc_user, ssn->ioc_srvname); 523 return EINVAL; 524 } 525 error = nb_ctx_resolve(ctx->ct_nb); 526 if (error) 527 return error; 528 if (ssn->ioc_localcs[0] == 0) 529 strcpy(ssn->ioc_localcs, "ISO8859-1"); 530 error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 531 if (error) 532 return error; 533 error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 534 if (error) 535 return error; 536 if (ssn->ioc_servercs[0] != 0) { 537 error = kiconv_add_xlat16_cspairs 538 (ssn->ioc_servercs, ssn->ioc_localcs); 539 if (error) return error; 540 } 541 if (ctx->ct_srvaddr) { 542 error = nb_resolvehost_in(ctx->ct_srvaddr, &sap, ctx->ct_smbtcpport); 543 } else { 544 error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap); 545 } 546 if (error) { 547 smb_error("can't get server address", error); 548 return error; 549 } 550 nn.nn_scope = ctx->ct_nb->nb_scope; 551 nn.nn_type = NBT_SERVER; 552 strcpy(nn.nn_name, ssn->ioc_srvname); 553 error = nb_sockaddr(sap, &nn, &saserver); 554 nb_snbfree(sap); 555 if (error) { 556 smb_error("can't allocate server address", error); 557 return error; 558 } 559 ssn->ioc_server = (struct sockaddr*)saserver; 560 if (ctx->ct_locname[0] == 0) { 561 error = nb_getlocalname(ctx->ct_locname); 562 if (error) { 563 smb_error("can't get local name", error); 564 return error; 565 } 566 nls_str_upper(ctx->ct_locname, ctx->ct_locname); 567 } 568 strcpy(nn.nn_name, ctx->ct_locname); 569 nn.nn_type = NBT_WKSTA; 570 nn.nn_scope = ctx->ct_nb->nb_scope; 571 error = nb_sockaddr(NULL, &nn, &salocal); 572 if (error) { 573 nb_snbfree((struct sockaddr*)saserver); 574 smb_error("can't allocate local address", error); 575 return error; 576 } 577 ssn->ioc_local = (struct sockaddr*)salocal; 578 ssn->ioc_lolen = salocal->snb_len; 579 ssn->ioc_svlen = saserver->snb_len; 580 if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) { 581 cp = getpass("Password:"); 582 error = smb_ctx_setpassword(ctx, cp); 583 if (error) 584 return error; 585 } 586 ctx->ct_flags |= SMBCF_RESOLVED; 587 return 0; 588 } 589 590 static int 591 smb_ctx_gethandle(struct smb_ctx *ctx) 592 { 593 int fd, i; 594 char buf[20]; 595 596 fd = open("/dev/"NSMB_NAME, O_RDWR); 597 if (fd >= 0) { 598 ctx->ct_fd = fd; 599 return 0; 600 } 601 return ENOENT; 602 } 603 604 int 605 smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) 606 { 607 struct smbioc_lookup rq; 608 int error; 609 610 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 611 smb_error("smb_ctx_lookup() data is not resolved", 0); 612 return EINVAL; 613 } 614 if (ctx->ct_fd != -1) { 615 close(ctx->ct_fd); 616 ctx->ct_fd = -1; 617 } 618 error = smb_ctx_gethandle(ctx); 619 if (error) { 620 smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0); 621 return EINVAL; 622 } 623 bzero(&rq, sizeof(rq)); 624 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn)); 625 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare)); 626 rq.ioc_flags = flags; 627 rq.ioc_level = level; 628 if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) { 629 error = errno; 630 if (flags & SMBLK_CREATE) 631 smb_error("unable to open connection", error); 632 return error; 633 } 634 return 0; 635 } 636 637 int 638 smb_ctx_login(struct smb_ctx *ctx) 639 { 640 struct smbioc_ossn *ssn = &ctx->ct_ssn; 641 struct smbioc_oshare *sh = &ctx->ct_sh; 642 int error; 643 644 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 645 smb_error("smb_ctx_resolve() should be called first", 0); 646 return EINVAL; 647 } 648 if (ctx->ct_fd != -1) { 649 close(ctx->ct_fd); 650 ctx->ct_fd = -1; 651 } 652 error = smb_ctx_gethandle(ctx); 653 if (error) { 654 smb_error("can't get handle to requester", 0); 655 return EINVAL; 656 } 657 if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) { 658 error = errno; 659 smb_error("can't open session to server %s", error, ssn->ioc_srvname); 660 return error; 661 } 662 if (sh->ioc_share[0] == 0) 663 return 0; 664 if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) { 665 error = errno; 666 smb_error("can't connect to share //%s/%s", error, 667 ssn->ioc_srvname, sh->ioc_share); 668 return error; 669 } 670 return 0; 671 } 672 673 int 674 smb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags) 675 { 676 struct smbioc_flags fl; 677 678 if (ctx->ct_fd == -1) 679 return EINVAL; 680 fl.ioc_level = level; 681 fl.ioc_mask = mask; 682 fl.ioc_flags = flags; 683 if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1) 684 return errno; 685 return 0; 686 } 687 688 /* 689 * level values: 690 * 0 - default 691 * 1 - server 692 * 2 - server:user 693 * 3 - server:user:share 694 */ 695 static int 696 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 697 { 698 char *p; 699 int error; 700 701 if (level >= 0) { 702 rc_getstringptr(smb_rc, sname, "charsets", &p); 703 if (p) { 704 error = smb_ctx_setcharset(ctx, p); 705 if (error) 706 smb_error("charset specification in the section '%s' ignored", error, sname); 707 } 708 } 709 if (level <= 1) { 710 rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout); 711 rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount); 712 } 713 if (level == 1) { 714 rc_getstringptr(smb_rc, sname, "addr", &p); 715 if (p) { 716 error = smb_ctx_setsrvaddr(ctx, p); 717 if (error) { 718 smb_error("invalid address specified in the section %s", 0, sname); 719 return error; 720 } 721 } 722 } 723 if (level >= 2) { 724 rc_getstringptr(smb_rc, sname, "password", &p); 725 if (p) 726 smb_ctx_setpassword(ctx, p); 727 } 728 rc_getstringptr(smb_rc, sname, "workgroup", &p); 729 if (p) 730 smb_ctx_setworkgroup(ctx, p); 731 return 0; 732 } 733 734 /* 735 * read rc file as follows: 736 * 1. read [default] section 737 * 2. override with [server] section 738 * 3. override with [server:user:share] section 739 * Since abcence of rcfile is not fatal, silently ignore this fact. 740 * smb_rc file should be closed by caller. 741 */ 742 int 743 smb_ctx_readrc(struct smb_ctx *ctx) 744 { 745 char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + SMB_MAXSHARENAMELEN + 4]; 746 /* char *p;*/ 747 748 if (smb_open_rcfile() != 0) 749 return 0; 750 751 if (ctx->ct_ssn.ioc_user[0] == 0 || ctx->ct_ssn.ioc_srvname[0] == 0) 752 return 0; 753 754 smb_ctx_readrcsection(ctx, "default", 0); 755 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 756 smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1); 757 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, ctx->ct_ssn.ioc_srvname, 1); 758 /* 759 * SERVER:USER parameters 760 */ 761 snprintf(sname, sizeof(sname), "%s:%s", ctx->ct_ssn.ioc_srvname, 762 ctx->ct_ssn.ioc_user); 763 smb_ctx_readrcsection(ctx, sname, 2); 764 765 if (ctx->ct_sh.ioc_share[0] != 0) { 766 /* 767 * SERVER:USER:SHARE parameters 768 */ 769 snprintf(sname, sizeof(sname), "%s:%s:%s", ctx->ct_ssn.ioc_srvname, 770 ctx->ct_ssn.ioc_user, ctx->ct_sh.ioc_share); 771 smb_ctx_readrcsection(ctx, sname, 3); 772 } 773 return 0; 774 } 775 776