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