ctx.c revision 335781
159191Skris/* 259191Skris * Copyright (c) 2000-2002, Boris Popov 359191Skris * All rights reserved. 459191Skris * 559191Skris * Redistribution and use in source and binary forms, with or without 659191Skris * modification, are permitted provided that the following conditions 759191Skris * are met: 8280304Sjkim * 1. Redistributions of source code must retain the above copyright 959191Skris * notice, this list of conditions and the following disclaimer. 1059191Skris * 2. Redistributions in binary form must reproduce the above copyright 1159191Skris * notice, this list of conditions and the following disclaimer in the 1259191Skris * documentation and/or other materials provided with the distribution. 1359191Skris * 3. All advertising materials mentioning features or use of this software 1459191Skris * must display the following acknowledgement: 15280304Sjkim * This product includes software developed by Boris Popov. 1659191Skris * 4. Neither the name of the author nor the names of any co-contributors 1759191Skris * may be used to endorse or promote products derived from this software 1859191Skris * without specific prior written permission. 1959191Skris * 2059191Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2159191Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22280304Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359191Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2459191Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559191Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659191Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859191Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959191Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059191Skris * SUCH DAMAGE. 3159191Skris * 3259191Skris * $Id: ctx.c,v 1.24 2002/04/13 14:35:28 bp Exp $ 3359191Skris * $FreeBSD: stable/10/contrib/smbfs/lib/smb/ctx.c 335781 2018-06-28 21:23:05Z brooks $ 3459191Skris */ 3559191Skris#include <sys/param.h> 3659191Skris#include <sys/sysctl.h> 37280304Sjkim#include <sys/ioctl.h> 3859191Skris#include <sys/time.h> 3959191Skris#include <sys/mount.h> 40280304Sjkim#include <fcntl.h> 4159191Skris#include <ctype.h> 4259191Skris#include <errno.h> 4359191Skris#include <stdio.h> 4459191Skris#include <string.h> 4559191Skris#include <stdlib.h> 4659191Skris#include <pwd.h> 4759191Skris#include <grp.h> 4859191Skris#include <unistd.h> 4959191Skris#include <sys/iconv.h> 5059191Skris 5159191Skris#define NB_NEEDRESOLVER 52280304Sjkim 5359191Skris#include <netsmb/smb_lib.h> 5459191Skris#include <netsmb/netbios.h> 5559191Skris#include <netsmb/nb_lib.h> 5659191Skris#include <netsmb/smb_conn.h> 5759191Skris#include <cflib.h> 5859191Skris 5959191Skris/* 6059191Skris * Prescan command line for [-U user] argument 6159191Skris * and fill context with defaults 6259191Skris */ 6359191Skrisint 64238405Sjkimsmb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[], 6559191Skris int minlevel, int maxlevel, int sharetype) 6659191Skris{ 6759191Skris int opt, error = 0; 6859191Skris uid_t euid; 6959191Skris const char *arg, *cp; 70280304Sjkim struct passwd *pwd; 71280304Sjkim 72280304Sjkim bzero(ctx,sizeof(*ctx)); 73280304Sjkim error = nb_ctx_create(&ctx->ct_nb); 7459191Skris if (error) 7559191Skris return error; 7659191Skris ctx->ct_fd = -1; 7759191Skris ctx->ct_parsedlevel = SMBL_NONE; 78280304Sjkim ctx->ct_minlevel = minlevel; 79280304Sjkim ctx->ct_maxlevel = maxlevel; 80280304Sjkim ctx->ct_smbtcpport = SMB_TCP_PORT; 81280304Sjkim 82280304Sjkim ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE; 83280304Sjkim ctx->ct_ssn.ioc_timeout = 15; 84280304Sjkim ctx->ct_ssn.ioc_retrycount = 4; 85280304Sjkim ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER; 86280304Sjkim ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP; 87280304Sjkim ctx->ct_ssn.ioc_mode = SMBM_EXEC; 88280304Sjkim ctx->ct_ssn.ioc_rights = SMBM_DEFAULT; 89280304Sjkim 9059191Skris ctx->ct_sh.ioc_opt = SMBVOPT_CREATE; 9159191Skris ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 92280304Sjkim ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 93280304Sjkim ctx->ct_sh.ioc_mode = SMBM_EXEC; 94160814Ssimon ctx->ct_sh.ioc_rights = SMBM_DEFAULT; 95160814Ssimon ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 96280304Sjkim ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 97160814Ssimon 98160814Ssimon nb_ctx_setscope(ctx->ct_nb, ""); 99160814Ssimon euid = geteuid(); 100160814Ssimon if ((pwd = getpwuid(euid)) != NULL) { 101160814Ssimon smb_ctx_setuser(ctx, pwd->pw_name); 102160814Ssimon endpwent(); 103160814Ssimon } else if (euid == 0) 104160814Ssimon smb_ctx_setuser(ctx, "root"); 105160814Ssimon else 106160814Ssimon return 0; 107280304Sjkim if (argv == NULL) 108280304Sjkim return 0; 109284285Sjkim for (opt = 1; opt < argc; opt++) { 110280304Sjkim cp = argv[opt]; 111280304Sjkim if (strncmp(cp, "//", 2) != 0) 112280304Sjkim continue; 113280304Sjkim error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp); 114280304Sjkim if (error) 115284285Sjkim return error; 116280304Sjkim ctx->ct_uncnext = cp; 117160814Ssimon break; 118280304Sjkim } 119280304Sjkim while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) { 120284285Sjkim arg = cf_optarg; 121280304Sjkim switch (opt) { 122280304Sjkim case 'E': 123280304Sjkim error = smb_ctx_setcharset(ctx, arg); 124280304Sjkim if (error) 125284285Sjkim return error; 126280304Sjkim break; 127160814Ssimon case 'L': 128109998Smarkm error = nls_setlocale(arg); 12959191Skris if (error) 130280304Sjkim break; 13159191Skris break; 13259191Skris case 'U': 13359191Skris error = smb_ctx_setuser(ctx, arg); 134280304Sjkim break; 135280304Sjkim } 136280304Sjkim } 137280304Sjkim cf_optind = cf_optreset = 1; 138280304Sjkim return error; 139280304Sjkim} 140280304Sjkim 141280304Sjkimvoid 14259191Skrissmb_ctx_done(struct smb_ctx *ctx) 143280304Sjkim{ 144280304Sjkim if (ctx->ct_ssn.ioc_server) 145111147Snectar nb_snbfree(ctx->ct_ssn.ioc_server); 146280304Sjkim if (ctx->ct_ssn.ioc_local) 147280304Sjkim nb_snbfree(ctx->ct_ssn.ioc_local); 148280304Sjkim if (ctx->ct_srvaddr) 149280304Sjkim free(ctx->ct_srvaddr); 150111147Snectar if (ctx->ct_nb) 151280304Sjkim nb_ctx_done(ctx->ct_nb); 152280304Sjkim} 153280304Sjkim 154280304Sjkimstatic int 155280304Sjkimgetsubstring(const char *p, u_char sep, char *dest, int maxlen, const char **next) 156280304Sjkim{ 157280304Sjkim int len; 158280304Sjkim 159280304Sjkim maxlen--; 160280304Sjkim for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 161280304Sjkim if (*p == 0) 162280304Sjkim return EINVAL; 163280304Sjkim *dest = *p; 164280304Sjkim } 165280304Sjkim *dest = 0; 166280304Sjkim *next = *p ? p + 1 : p; 167280304Sjkim return 0; 16859191Skris} 169280304Sjkim 170280304Sjkim/* 171280304Sjkim * Here we expect something like "[proto:]//[user@]host[:psmb[:pnb]][/share][/path]" 172280304Sjkim */ 173280304Sjkimint 174280304Sjkimsmb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, 175280304Sjkim const char **next) 176280304Sjkim{ 177280304Sjkim const char *p = unc; 17859191Skris char *p1, *psmb, *pnb; 179280304Sjkim char tmp[1024]; 180280304Sjkim int error ; 181280304Sjkim 182280304Sjkim ctx->ct_parsedlevel = SMBL_NONE; 183280304Sjkim if (*p++ != '/' || *p++ != '/') { 184280304Sjkim smb_error("UNC should start with '//'", 0); 185280304Sjkim return EINVAL; 186280304Sjkim } 187280304Sjkim p1 = tmp; 188280304Sjkim error = getsubstring(p, '@', p1, sizeof(tmp), &p); 18959191Skris if (!error) { 190280304Sjkim if (ctx->ct_maxlevel < SMBL_VC) { 191280304Sjkim smb_error("no user name required", 0); 192280304Sjkim return EINVAL; 193280304Sjkim } 194280304Sjkim error = smb_ctx_setuser(ctx, tmp); 195280304Sjkim if (error) 196280304Sjkim return error; 197280304Sjkim ctx->ct_parsedlevel = SMBL_VC; 198280304Sjkim } 199280304Sjkim error = getsubstring(p, '/', p1, sizeof(tmp), &p); 200280304Sjkim if (error) { 201295016Sjkim error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 202295016Sjkim if (error) { 203295016Sjkim smb_error("no server name found", 0); 204280304Sjkim return error; 205280304Sjkim } 20659191Skris } 207280304Sjkim if (*p1 == 0) { 208295016Sjkim smb_error("empty server name", 0); 209280304Sjkim return EINVAL; 210280304Sjkim } 211280304Sjkim /* 212280304Sjkim * Check for port number specification. 213280304Sjkim */ 214280304Sjkim psmb = strchr(tmp, ':'); 215280304Sjkim if (psmb) { 216280304Sjkim *psmb++ = '\0'; 217280304Sjkim pnb = strchr(psmb, ':'); 218280304Sjkim if (pnb) { 219280304Sjkim *pnb++ = '\0'; 220280304Sjkim error = smb_ctx_setnbport(ctx, atoi(pnb)); 22159191Skris if (error) { 222280304Sjkim smb_error("Invalid NetBIOS port number", 0); 223280304Sjkim return error; 224280304Sjkim } 225280304Sjkim } 226280304Sjkim error = smb_ctx_setsmbport(ctx, atoi(psmb)); 227280304Sjkim if (error) { 228111147Snectar smb_error("Invalid SMB port number", 0); 229280304Sjkim return error; 230280304Sjkim } 231280304Sjkim } 232280304Sjkim error = smb_ctx_setserver(ctx, tmp); 233111147Snectar if (error) 234280304Sjkim return error; 235280304Sjkim if (sharetype == SMB_ST_NONE) { 23659191Skris *next = p; 237280304Sjkim return 0; 238280304Sjkim } 239280304Sjkim if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 240280304Sjkim smb_error("no share name required", 0); 241280304Sjkim return EINVAL; 24259191Skris } 243280304Sjkim error = getsubstring(p, '/', p1, sizeof(tmp), &p); 244280304Sjkim if (error) { 24559191Skris error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 246280304Sjkim if (error) { 247280304Sjkim smb_error("unexpected end of line", 0); 248280304Sjkim return error; 249280304Sjkim } 250306196Sjkim } 251306196Sjkim if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) { 252280304Sjkim smb_error("empty share name", 0); 253280304Sjkim return EINVAL; 254280304Sjkim } 25559191Skris *next = p; 256306196Sjkim if (*p1 == 0) 257280304Sjkim return 0; 258280304Sjkim error = smb_ctx_setshare(ctx, p1, sharetype); 259280304Sjkim return error; 260280304Sjkim} 261280304Sjkim 262160814Ssimonint 263280304Sjkimsmb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 264160814Ssimon{ 265280304Sjkim char *cp, *servercs, *localcs; 266280304Sjkim int cslen = sizeof(ctx->ct_ssn.ioc_localcs); 267280304Sjkim int scslen, lcslen, error; 268160814Ssimon 269306196Sjkim cp = strchr(arg, ':'); 270306196Sjkim lcslen = cp ? (cp - arg) : 0; 271280304Sjkim if (lcslen == 0 || lcslen >= cslen) { 272280304Sjkim smb_error("invalid local charset specification (%s)", 0, arg); 273280304Sjkim return EINVAL; 274280304Sjkim } 275280304Sjkim scslen = (size_t)strlen(++cp); 276280304Sjkim if (scslen == 0 || scslen >= cslen) { 277160814Ssimon smb_error("invalid server charset specification (%s)", 0, arg); 278280304Sjkim return EINVAL; 279280304Sjkim } 280280304Sjkim localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 281280304Sjkim localcs[lcslen] = 0; 282280304Sjkim servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 283280304Sjkim error = nls_setrecode(localcs, servercs); 28459191Skris if (error == 0) 285280304Sjkim return 0; 286280304Sjkim smb_error("can't initialize iconv support (%s:%s)", 287280304Sjkim error, localcs, servercs); 288280304Sjkim localcs[0] = 0; 289306196Sjkim servercs[0] = 0; 290280304Sjkim return error; 291280304Sjkim} 292280304Sjkim 293280304Sjkimint 29459191Skrissmb_ctx_setserver(struct smb_ctx *ctx, const char *name) 295280304Sjkim{ 296280304Sjkim if (strlen(name) > SMB_MAXSRVNAMELEN) { 297280304Sjkim smb_error("server name '%s' too long", 0, name); 29859191Skris return ENAMETOOLONG; 299280304Sjkim } 300280304Sjkim nls_str_upper(ctx->ct_ssn.ioc_srvname, name); 301280304Sjkim return 0; 302280304Sjkim} 303280304Sjkim 304280304Sjkimint 305280304Sjkimsmb_ctx_setnbport(struct smb_ctx *ctx, int port) 306280304Sjkim{ 307280304Sjkim if (port < 1 || port > 0xffff) 308280304Sjkim return EINVAL; 309280304Sjkim ctx->ct_nb->nb_nmbtcpport = port; 310280304Sjkim return 0; 311280304Sjkim} 312280304Sjkim 313280304Sjkimint 314280304Sjkimsmb_ctx_setsmbport(struct smb_ctx *ctx, int port) 315280304Sjkim{ 316280304Sjkim if (port < 1 || port > 0xffff) 317280304Sjkim return EINVAL; 318280304Sjkim ctx->ct_smbtcpport = port; 31959191Skris ctx->ct_nb->nb_smbtcpport = port; 320280304Sjkim return 0; 321280304Sjkim} 322280304Sjkim 323280304Sjkimint 324280304Sjkimsmb_ctx_setuser(struct smb_ctx *ctx, const char *name) 325280304Sjkim{ 326280304Sjkim if (strlen(name) > SMB_MAXUSERNAMELEN) { 327280304Sjkim smb_error("user name '%s' too long", 0, name); 328280304Sjkim return ENAMETOOLONG; 329280304Sjkim } 330280304Sjkim nls_str_upper(ctx->ct_ssn.ioc_user, name); 331162911Ssimon return 0; 332280304Sjkim} 333280304Sjkim 334280304Sjkimint 335280304Sjkimsmb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name) 336280304Sjkim{ 337280304Sjkim if (strlen(name) > SMB_MAXUSERNAMELEN) { 33859191Skris smb_error("workgroup name '%s' too long", 0, name); 339280304Sjkim return ENAMETOOLONG; 340280304Sjkim } 341280304Sjkim nls_str_upper(ctx->ct_ssn.ioc_workgroup, name); 342280304Sjkim return 0; 343280304Sjkim} 344280304Sjkim 345280304Sjkimint 346111147Snectarsmb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd) 347280304Sjkim{ 348280304Sjkim if (passwd == NULL) 34979998Skris return EINVAL; 350280304Sjkim if (strlen(passwd) > SMB_MAXPASSWORDLEN) { 351280304Sjkim smb_error("password too long", 0); 352280304Sjkim return ENAMETOOLONG; 353280304Sjkim } 354280304Sjkim if (strncmp(passwd, "$$1", 3) == 0) 355280304Sjkim smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); 356280304Sjkim else 357280304Sjkim strcpy(ctx->ct_ssn.ioc_password, passwd); 358280304Sjkim strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); 359280304Sjkim return 0; 36059191Skris} 361280304Sjkim 362280304Sjkimint 363280304Sjkimsmb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 364280304Sjkim{ 365280304Sjkim if (strlen(share) > SMB_MAXSHARENAMELEN) { 36659191Skris smb_error("share name '%s' too long", 0, share); 367280304Sjkim return ENAMETOOLONG; 368280304Sjkim } 369280304Sjkim nls_str_upper(ctx->ct_sh.ioc_share, share); 370280304Sjkim if (share[0] != 0) 371280304Sjkim ctx->ct_parsedlevel = SMBL_SHARE; 372280304Sjkim ctx->ct_sh.ioc_stype = stype; 373280304Sjkim return 0; 374280304Sjkim} 375280304Sjkim 376280304Sjkimint 37759191Skrissmb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 378280304Sjkim{ 379280304Sjkim if (addr == NULL || addr[0] == 0) 380280304Sjkim return EINVAL; 38159191Skris if (ctx->ct_srvaddr) 382280304Sjkim free(ctx->ct_srvaddr); 383280304Sjkim if ((ctx->ct_srvaddr = strdup(addr)) == NULL) 384280304Sjkim return ENOMEM; 385160814Ssimon return 0; 386280304Sjkim} 387280304Sjkim 388280304Sjkimstatic int 389280304Sjkimsmb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 390280304Sjkim{ 391280304Sjkim struct group *gr; 39259191Skris struct passwd *pw; 393280304Sjkim char *cp; 394280304Sjkim 395280304Sjkim cp = strchr(pair, ':'); 396280304Sjkim if (cp) { 397280304Sjkim *cp++ = '\0'; 398280304Sjkim if (*cp) { 39959191Skris gr = getgrnam(cp); 400280304Sjkim if (gr) { 401280304Sjkim *gid = gr->gr_gid; 402280304Sjkim } else 403280304Sjkim smb_error("Invalid group name %s, ignored", 404160814Ssimon 0, cp); 405280304Sjkim } 406280304Sjkim } 407280304Sjkim if (*pair) { 408280304Sjkim pw = getpwnam(pair); 409280304Sjkim if (pw) { 410280304Sjkim *uid = pw->pw_uid; 411280304Sjkim } else 412280304Sjkim smb_error("Invalid user name %s, ignored", 0, pair); 413280304Sjkim } 414280304Sjkim endpwent(); 415280304Sjkim return 0; 416280304Sjkim} 417280304Sjkim 418280304Sjkimint 41959191Skrissmb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 42059191Skris{ 42159191Skris int error = 0; 422280304Sjkim char *p, *cp; 423280304Sjkim 42459191Skris switch(opt) { 42559191Skris case 'U': 42659191Skris break; 42759191Skris case 'I': 428280304Sjkim error = smb_ctx_setsrvaddr(ctx, arg); 429280304Sjkim break; 430280304Sjkim case 'M': 43159191Skris 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 471static void 472smb_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 486static int 487smb_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 */ 504int 505smb_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 if (strlen(ssn->ioc_srvname) > NB_NAMELEN) 553 return NBERROR(NBERR_NAMETOOLONG); 554 strlcpy(nn.nn_name, ssn->ioc_srvname, sizeof(nn.nn_name)); 555 error = nb_sockaddr(sap, &nn, &saserver); 556 nb_snbfree(sap); 557 if (error) { 558 smb_error("can't allocate server address", error); 559 return error; 560 } 561 ssn->ioc_server = (struct sockaddr*)saserver; 562 if (ctx->ct_locname[0] == 0) { 563 error = nb_getlocalname(ctx->ct_locname); 564 if (error) { 565 smb_error("can't get local name", error); 566 return error; 567 } 568 nls_str_upper(ctx->ct_locname, ctx->ct_locname); 569 } 570 /* 571 * Truncate the local host name to NB_NAMELEN-1 which gives a 572 * suffix of 0 which is "workstation name". 573 */ 574 strlcpy(nn.nn_name, ctx->ct_locname, NB_NAMELEN); 575 nn.nn_type = NBT_WKSTA; 576 nn.nn_scope = ctx->ct_nb->nb_scope; 577 error = nb_sockaddr(NULL, &nn, &salocal); 578 if (error) { 579 nb_snbfree((struct sockaddr*)saserver); 580 smb_error("can't allocate local address", error); 581 return error; 582 } 583 ssn->ioc_local = (struct sockaddr*)salocal; 584 ssn->ioc_lolen = salocal->snb_len; 585 ssn->ioc_svlen = saserver->snb_len; 586 if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) { 587 cp = getpass("Password:"); 588 error = smb_ctx_setpassword(ctx, cp); 589 if (error) 590 return error; 591 } 592 ctx->ct_flags |= SMBCF_RESOLVED; 593 return 0; 594} 595 596static int 597smb_ctx_gethandle(struct smb_ctx *ctx) 598{ 599 int fd, i; 600 char buf[20]; 601 602 fd = open("/dev/"NSMB_NAME, O_RDWR); 603 if (fd >= 0) { 604 ctx->ct_fd = fd; 605 return 0; 606 } 607 return ENOENT; 608} 609 610int 611smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) 612{ 613 struct smbioc_lookup rq; 614 int error; 615 616 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 617 smb_error("smb_ctx_lookup() data is not resolved", 0); 618 return EINVAL; 619 } 620 if (ctx->ct_fd != -1) { 621 close(ctx->ct_fd); 622 ctx->ct_fd = -1; 623 } 624 error = smb_ctx_gethandle(ctx); 625 if (error) { 626 smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0); 627 return EINVAL; 628 } 629 bzero(&rq, sizeof(rq)); 630 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn)); 631 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare)); 632 rq.ioc_flags = flags; 633 rq.ioc_level = level; 634 if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) { 635 error = errno; 636 if (flags & SMBLK_CREATE) 637 smb_error("unable to open connection", error); 638 return error; 639 } 640 return 0; 641} 642 643int 644smb_ctx_login(struct smb_ctx *ctx) 645{ 646 struct smbioc_ossn *ssn = &ctx->ct_ssn; 647 struct smbioc_oshare *sh = &ctx->ct_sh; 648 int error; 649 650 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 651 smb_error("smb_ctx_resolve() should be called first", 0); 652 return EINVAL; 653 } 654 if (ctx->ct_fd != -1) { 655 close(ctx->ct_fd); 656 ctx->ct_fd = -1; 657 } 658 error = smb_ctx_gethandle(ctx); 659 if (error) { 660 smb_error("can't get handle to requester", 0); 661 return EINVAL; 662 } 663 if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) { 664 error = errno; 665 smb_error("can't open session to server %s", error, ssn->ioc_srvname); 666 return error; 667 } 668 if (sh->ioc_share[0] == 0) 669 return 0; 670 if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) { 671 error = errno; 672 smb_error("can't connect to share //%s/%s", error, 673 ssn->ioc_srvname, sh->ioc_share); 674 return error; 675 } 676 return 0; 677} 678 679int 680smb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags) 681{ 682 struct smbioc_flags fl; 683 684 if (ctx->ct_fd == -1) 685 return EINVAL; 686 fl.ioc_level = level; 687 fl.ioc_mask = mask; 688 fl.ioc_flags = flags; 689 if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1) 690 return errno; 691 return 0; 692} 693 694/* 695 * level values: 696 * 0 - default 697 * 1 - server 698 * 2 - server:user 699 * 3 - server:user:share 700 */ 701static int 702smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 703{ 704 char *p; 705 int error; 706 707 if (level >= 0) { 708 rc_getstringptr(smb_rc, sname, "charsets", &p); 709 if (p) { 710 error = smb_ctx_setcharset(ctx, p); 711 if (error) 712 smb_error("charset specification in the section '%s' ignored", error, sname); 713 } 714 } 715 if (level <= 1) { 716 rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout); 717 rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount); 718 } 719 if (level == 1) { 720 rc_getstringptr(smb_rc, sname, "addr", &p); 721 if (p) { 722 error = smb_ctx_setsrvaddr(ctx, p); 723 if (error) { 724 smb_error("invalid address specified in the section %s", 0, sname); 725 return error; 726 } 727 } 728 } 729 if (level >= 2) { 730 rc_getstringptr(smb_rc, sname, "password", &p); 731 if (p) 732 smb_ctx_setpassword(ctx, p); 733 } 734 rc_getstringptr(smb_rc, sname, "workgroup", &p); 735 if (p) 736 smb_ctx_setworkgroup(ctx, p); 737 return 0; 738} 739 740/* 741 * read rc file as follows: 742 * 1. read [default] section 743 * 2. override with [server] section 744 * 3. override with [server:user:share] section 745 * Since abcence of rcfile is not fatal, silently ignore this fact. 746 * smb_rc file should be closed by caller. 747 */ 748int 749smb_ctx_readrc(struct smb_ctx *ctx) 750{ 751 char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + SMB_MAXSHARENAMELEN + 4]; 752/* char *p;*/ 753 754 if (smb_open_rcfile() != 0) 755 return 0; 756 757 if (ctx->ct_ssn.ioc_user[0] == 0 || ctx->ct_ssn.ioc_srvname[0] == 0) 758 return 0; 759 760 smb_ctx_readrcsection(ctx, "default", 0); 761 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 762 smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1); 763 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, ctx->ct_ssn.ioc_srvname, 1); 764 /* 765 * SERVER:USER parameters 766 */ 767 snprintf(sname, sizeof(sname), "%s:%s", ctx->ct_ssn.ioc_srvname, 768 ctx->ct_ssn.ioc_user); 769 smb_ctx_readrcsection(ctx, sname, 2); 770 771 if (ctx->ct_sh.ioc_share[0] != 0) { 772 /* 773 * SERVER:USER:SHARE parameters 774 */ 775 snprintf(sname, sizeof(sname), "%s:%s:%s", ctx->ct_ssn.ioc_srvname, 776 ctx->ct_ssn.ioc_user, ctx->ct_sh.ioc_share); 777 smb_ctx_readrcsection(ctx, sname, 3); 778 } 779 return 0; 780} 781 782