1145184Sglebius/* 2145184Sglebius * Copyright (c) 2000-2002, Boris Popov 3145184Sglebius * All rights reserved. 4145184Sglebius * 5145184Sglebius * Redistribution and use in source and binary forms, with or without 6145184Sglebius * modification, are permitted provided that the following conditions 7145184Sglebius * are met: 8145184Sglebius * 1. Redistributions of source code must retain the above copyright 9145184Sglebius * notice, this list of conditions and the following disclaimer. 10155768Sceri * 2. Redistributions in binary form must reproduce the above copyright 11145184Sglebius * notice, this list of conditions and the following disclaimer in the 12155458Sglebius * documentation and/or other materials provided with the distribution. 13145184Sglebius * 3. All advertising materials mentioning features or use of this software 14145184Sglebius * must display the following acknowledgement: 15216300Ssyrinx * This product includes software developed by Boris Popov. 16216300Ssyrinx * 4. Neither the name of the author nor the names of any co-contributors 17216300Ssyrinx * may be used to endorse or promote products derived from this software 18216300Ssyrinx * without specific prior written permission. 19216300Ssyrinx * 20216300Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21216300Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22216300Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23216300Ssyrinx * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24145184Sglebius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25145184Sglebius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26165685Smaxim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27165685Smaxim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28145184Sglebius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29145184Sglebius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30145184Sglebius * SUCH DAMAGE. 31216595Ssyrinx * 32216300Ssyrinx * $Id: ctx.c,v 1.24 2002/04/13 14:35:28 bp Exp $ 33216595Ssyrinx * $FreeBSD$ 34216595Ssyrinx */ 35216300Ssyrinx#include <sys/param.h> 36216300Ssyrinx#include <sys/sysctl.h> 37216300Ssyrinx#include <sys/ioctl.h> 38216300Ssyrinx#include <sys/time.h> 39216300Ssyrinx#include <sys/mount.h> 40216300Ssyrinx#include <fcntl.h> 41216300Ssyrinx#include <ctype.h> 42145184Sglebius#include <errno.h> 43216595Ssyrinx#include <stdio.h> 44216595Ssyrinx#include <string.h> 45216595Ssyrinx#include <stdlib.h> 46216595Ssyrinx#include <pwd.h> 47216595Ssyrinx#include <grp.h> 48216595Ssyrinx#include <unistd.h> 49216595Ssyrinx#include <sys/iconv.h> 50216595Ssyrinx 51216595Ssyrinx#define NB_NEEDRESOLVER 52216595Ssyrinx 53216595Ssyrinx#include <netsmb/smb_lib.h> 54216595Ssyrinx#include <netsmb/netbios.h> 55216595Ssyrinx#include <netsmb/nb_lib.h> 56216595Ssyrinx#include <netsmb/smb_conn.h> 57216595Ssyrinx#include <cflib.h> 58216595Ssyrinx 59216595Ssyrinx/* 60216595Ssyrinx * Prescan command line for [-U user] argument 61216595Ssyrinx * and fill context with defaults 62216595Ssyrinx */ 63216300Ssyrinxint 64216300Ssyrinxsmb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[], 65216300Ssyrinx int minlevel, int maxlevel, int sharetype) 66216300Ssyrinx{ 67216300Ssyrinx int opt, error = 0; 68216300Ssyrinx uid_t euid; 69216595Ssyrinx const char *arg, *cp; 70216300Ssyrinx struct passwd *pwd; 71216595Ssyrinx 72216595Ssyrinx bzero(ctx,sizeof(*ctx)); 73216300Ssyrinx error = nb_ctx_create(&ctx->ct_nb); 74216300Ssyrinx if (error) 75145184Sglebius return error; 76145184Sglebius ctx->ct_fd = -1; 77145184Sglebius ctx->ct_parsedlevel = SMBL_NONE; 78145184Sglebius ctx->ct_minlevel = minlevel; 79145184Sglebius ctx->ct_maxlevel = maxlevel; 80145184Sglebius ctx->ct_smbtcpport = SMB_TCP_PORT; 81154186Sharti 82154186Sharti ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE; 83154186Sharti ctx->ct_ssn.ioc_timeout = 15; 84154186Sharti ctx->ct_ssn.ioc_retrycount = 4; 85154186Sharti ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER; 86154186Sharti ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP; 87154186Sharti ctx->ct_ssn.ioc_mode = SMBM_EXEC; 88154186Sharti ctx->ct_ssn.ioc_rights = SMBM_DEFAULT; 89154186Sharti 90154186Sharti ctx->ct_sh.ioc_opt = SMBVOPT_CREATE; 91154186Sharti ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 92154186Sharti ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 93145184Sglebius ctx->ct_sh.ioc_mode = SMBM_EXEC; 94154186Sharti ctx->ct_sh.ioc_rights = SMBM_DEFAULT; 95145184Sglebius ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 96145184Sglebius ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 97145184Sglebius 98163823Sharti nb_ctx_setscope(ctx->ct_nb, ""); 99145184Sglebius euid = geteuid(); 100145184Sglebius if ((pwd = getpwuid(euid)) != NULL) { 101145184Sglebius smb_ctx_setuser(ctx, pwd->pw_name); 102145184Sglebius endpwent(); 103145184Sglebius } else if (euid == 0) 104145184Sglebius smb_ctx_setuser(ctx, "root"); 105145184Sglebius else 106145184Sglebius return 0; 107145184Sglebius if (argv == NULL) 108145184Sglebius return 0; 109145184Sglebius for (opt = 1; opt < argc; opt++) { 110145184Sglebius cp = argv[opt]; 111145184Sglebius if (strncmp(cp, "//", 2) != 0) 112145184Sglebius continue; 113145184Sglebius error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp); 114145184Sglebius if (error) 115145184Sglebius return error; 116216300Ssyrinx ctx->ct_uncnext = cp; 117216300Ssyrinx break; 118216300Ssyrinx } 119216300Ssyrinx while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) { 120216300Ssyrinx arg = cf_optarg; 121216300Ssyrinx switch (opt) { 122216300Ssyrinx case 'E': 123216300Ssyrinx error = smb_ctx_setcharset(ctx, arg); 124216300Ssyrinx if (error) 125216300Ssyrinx return error; 126216300Ssyrinx break; 127216300Ssyrinx case 'L': 128216300Ssyrinx error = nls_setlocale(arg); 129216300Ssyrinx if (error) 130216300Ssyrinx break; 131216300Ssyrinx break; 132216300Ssyrinx case 'U': 133216300Ssyrinx error = smb_ctx_setuser(ctx, arg); 134216300Ssyrinx break; 135216300Ssyrinx } 136216300Ssyrinx } 137216300Ssyrinx cf_optind = cf_optreset = 1; 138216300Ssyrinx return error; 139216300Ssyrinx} 140216300Ssyrinx 141216301Ssyrinxvoid 142216300Ssyrinxsmb_ctx_done(struct smb_ctx *ctx) 143216300Ssyrinx{ 144216300Ssyrinx if (ctx->ct_ssn.ioc_server) 145216300Ssyrinx nb_snbfree(ctx->ct_ssn.ioc_server); 146216300Ssyrinx if (ctx->ct_ssn.ioc_local) 147216300Ssyrinx nb_snbfree(ctx->ct_ssn.ioc_local); 148216300Ssyrinx if (ctx->ct_srvaddr) 149216300Ssyrinx free(ctx->ct_srvaddr); 150216300Ssyrinx if (ctx->ct_nb) 151216300Ssyrinx nb_ctx_done(ctx->ct_nb); 152216300Ssyrinx} 153216300Ssyrinx 154216300Ssyrinxstatic int 155216300Ssyrinxgetsubstring(const char *p, u_char sep, char *dest, int maxlen, const char **next) 156216300Ssyrinx{ 157216300Ssyrinx int len; 158216300Ssyrinx 159216300Ssyrinx maxlen--; 160216595Ssyrinx for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 161216595Ssyrinx if (*p == 0) 162216300Ssyrinx return EINVAL; 163216300Ssyrinx *dest = *p; 164216595Ssyrinx } 165216595Ssyrinx *dest = 0; 166216300Ssyrinx *next = *p ? p + 1 : p; 167216300Ssyrinx return 0; 168216595Ssyrinx} 169216595Ssyrinx 170216595Ssyrinx/* 171216595Ssyrinx * Here we expect something like "[proto:]//[user@]host[:psmb[:pnb]][/share][/path]" 172216300Ssyrinx */ 173216300Ssyrinxint 174216300Ssyrinxsmb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, 175216300Ssyrinx const char **next) 176216300Ssyrinx{ 177216300Ssyrinx const char *p = unc; 178216300Ssyrinx char *p1, *psmb, *pnb; 179216300Ssyrinx char tmp[1024]; 180216300Ssyrinx int error ; 181216300Ssyrinx 182216300Ssyrinx ctx->ct_parsedlevel = SMBL_NONE; 183216300Ssyrinx if (*p++ != '/' || *p++ != '/') { 184216300Ssyrinx smb_error("UNC should start with '//'", 0); 185216300Ssyrinx return EINVAL; 186216300Ssyrinx } 187216300Ssyrinx p1 = tmp; 188216300Ssyrinx error = getsubstring(p, '@', p1, sizeof(tmp), &p); 189216300Ssyrinx if (!error) { 190216300Ssyrinx if (ctx->ct_maxlevel < SMBL_VC) { 191216300Ssyrinx smb_error("no user name required", 0); 192216595Ssyrinx return EINVAL; 193216595Ssyrinx } 194216300Ssyrinx if (*p1 == 0) { 195216300Ssyrinx smb_error("empty user name", 0); 196216300Ssyrinx return EINVAL; 197216300Ssyrinx } 198216595Ssyrinx error = smb_ctx_setuser(ctx, tmp); 199216595Ssyrinx if (error) 200216595Ssyrinx return error; 201216300Ssyrinx ctx->ct_parsedlevel = SMBL_VC; 202216300Ssyrinx } 203216300Ssyrinx error = getsubstring(p, '/', p1, sizeof(tmp), &p); 204216300Ssyrinx if (error) { 205216300Ssyrinx error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 206216595Ssyrinx if (error) { 207216595Ssyrinx smb_error("no server name found", 0); 208216595Ssyrinx return error; 209216300Ssyrinx } 210216300Ssyrinx } 211216300Ssyrinx if (*p1 == 0) { 212216300Ssyrinx smb_error("empty server name", 0); 213216300Ssyrinx return EINVAL; 214216300Ssyrinx } 215216300Ssyrinx /* 216216300Ssyrinx * Check for port number specification. 217216300Ssyrinx */ 218216595Ssyrinx psmb = strchr(tmp, ':'); 219216595Ssyrinx if (psmb) { 220216595Ssyrinx *psmb++ = '\0'; 221216595Ssyrinx pnb = strchr(psmb, ':'); 222216595Ssyrinx if (pnb) { 223216595Ssyrinx *pnb++ = '\0'; 224216595Ssyrinx error = smb_ctx_setnbport(ctx, atoi(pnb)); 225216595Ssyrinx if (error) { 226216595Ssyrinx smb_error("Invalid NetBIOS port number", 0); 227216595Ssyrinx return error; 228216595Ssyrinx } 229216595Ssyrinx } 230216595Ssyrinx error = smb_ctx_setsmbport(ctx, atoi(psmb)); 231216595Ssyrinx if (error) { 232216595Ssyrinx smb_error("Invalid SMB port number", 0); 233216595Ssyrinx return error; 234216595Ssyrinx } 235216595Ssyrinx } 236216595Ssyrinx error = smb_ctx_setserver(ctx, tmp); 237216595Ssyrinx if (error) 238216595Ssyrinx return error; 239216595Ssyrinx if (sharetype == SMB_ST_NONE) { 240216595Ssyrinx *next = p; 241216595Ssyrinx return 0; 242216595Ssyrinx } 243216595Ssyrinx if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 244216595Ssyrinx smb_error("no share name required", 0); 245216595Ssyrinx return EINVAL; 246216595Ssyrinx } 247216595Ssyrinx error = getsubstring(p, '/', p1, sizeof(tmp), &p); 248216595Ssyrinx if (error) { 249216595Ssyrinx error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 250216595Ssyrinx if (error) { 251216595Ssyrinx smb_error("unexpected end of line", 0); 252216595Ssyrinx return error; 253216595Ssyrinx } 254216595Ssyrinx } 255216595Ssyrinx if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) { 256216595Ssyrinx smb_error("empty share name", 0); 257216595Ssyrinx return EINVAL; 258216595Ssyrinx } 259216595Ssyrinx *next = p; 260216595Ssyrinx if (*p1 == 0) 261216595Ssyrinx return 0; 262216595Ssyrinx error = smb_ctx_setshare(ctx, p1, sharetype); 263216595Ssyrinx return error; 264216595Ssyrinx} 265216595Ssyrinx 266216595Ssyrinxint 267216595Ssyrinxsmb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 268216595Ssyrinx{ 269216595Ssyrinx char *cp, *servercs, *localcs; 270216595Ssyrinx int cslen = sizeof(ctx->ct_ssn.ioc_localcs); 271216595Ssyrinx int scslen, lcslen, error; 272216595Ssyrinx 273216595Ssyrinx cp = strchr(arg, ':'); 274145184Sglebius lcslen = cp ? (cp - arg) : 0; 275145184Sglebius if (lcslen == 0 || lcslen >= cslen) { 276145184Sglebius smb_error("invalid local charset specification (%s)", 0, arg); 277145184Sglebius return EINVAL; 278145184Sglebius } 279145184Sglebius scslen = (size_t)strlen(++cp); 280145184Sglebius if (scslen == 0 || scslen >= cslen) { 281145184Sglebius smb_error("invalid server charset specification (%s)", 0, arg); 282145184Sglebius return EINVAL; 283145184Sglebius } 284145184Sglebius localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 285154177Sharti localcs[lcslen] = 0; 286154177Sharti servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 287154177Sharti error = nls_setrecode(localcs, servercs); 288154177Sharti if (error == 0) 289154177Sharti return 0; 290154177Sharti smb_error("can't initialize iconv support (%s:%s)", 291165419Ssyrinx error, localcs, servercs); 292165419Ssyrinx localcs[0] = 0; 293165419Ssyrinx servercs[0] = 0; 294165419Ssyrinx return error; 295165419Ssyrinx} 296165419Ssyrinx 297210503Ssyrinxint 298210503Ssyrinxsmb_ctx_setserver(struct smb_ctx *ctx, const char *name) 299210503Ssyrinx{ 300210503Ssyrinx if (strlen(name) > SMB_MAXSRVNAMELEN) { 301210503Ssyrinx smb_error("server name '%s' too long", 0, name); 302210503Ssyrinx return ENAMETOOLONG; 303 } 304 nls_str_upper(ctx->ct_ssn.ioc_srvname, name); 305 return 0; 306} 307 308int 309smb_ctx_setnbport(struct smb_ctx *ctx, int port) 310{ 311 if (port < 1 || port > 0xffff) 312 return EINVAL; 313 ctx->ct_nb->nb_nmbtcpport = port; 314 return 0; 315} 316 317int 318smb_ctx_setsmbport(struct smb_ctx *ctx, int port) 319{ 320 if (port < 1 || port > 0xffff) 321 return EINVAL; 322 ctx->ct_smbtcpport = port; 323 ctx->ct_nb->nb_smbtcpport = port; 324 return 0; 325} 326 327int 328smb_ctx_setuser(struct smb_ctx *ctx, const char *name) 329{ 330 if (strlen(name) > SMB_MAXUSERNAMELEN) { 331 smb_error("user name '%s' too long", 0, name); 332 return ENAMETOOLONG; 333 } 334 nls_str_upper(ctx->ct_ssn.ioc_user, name); 335 return 0; 336} 337 338int 339smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name) 340{ 341 if (strlen(name) > SMB_MAXUSERNAMELEN) { 342 smb_error("workgroup name '%s' too long", 0, name); 343 return ENAMETOOLONG; 344 } 345 nls_str_upper(ctx->ct_ssn.ioc_workgroup, name); 346 return 0; 347} 348 349int 350smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd) 351{ 352 if (passwd == NULL) 353 return EINVAL; 354 if (strlen(passwd) > SMB_MAXPASSWORDLEN) { 355 smb_error("password too long", 0); 356 return ENAMETOOLONG; 357 } 358 if (strncmp(passwd, "$$1", 3) == 0) 359 smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); 360 else 361 strcpy(ctx->ct_ssn.ioc_password, passwd); 362 strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); 363 return 0; 364} 365 366int 367smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 368{ 369 if (strlen(share) > SMB_MAXSHARENAMELEN) { 370 smb_error("share name '%s' too long", 0, share); 371 return ENAMETOOLONG; 372 } 373 nls_str_upper(ctx->ct_sh.ioc_share, share); 374 if (share[0] != 0) 375 ctx->ct_parsedlevel = SMBL_SHARE; 376 ctx->ct_sh.ioc_stype = stype; 377 return 0; 378} 379 380int 381smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 382{ 383 if (addr == NULL || addr[0] == 0) 384 return EINVAL; 385 if (ctx->ct_srvaddr) 386 free(ctx->ct_srvaddr); 387 if ((ctx->ct_srvaddr = strdup(addr)) == NULL) 388 return ENOMEM; 389 return 0; 390} 391 392static int 393smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 394{ 395 struct group *gr; 396 struct passwd *pw; 397 char *cp; 398 399 cp = strchr(pair, ':'); 400 if (cp) { 401 *cp++ = '\0'; 402 if (*cp) { 403 gr = getgrnam(cp); 404 if (gr) { 405 *gid = gr->gr_gid; 406 } else 407 smb_error("Invalid group name %s, ignored", 408 0, cp); 409 } 410 } 411 if (*pair) { 412 pw = getpwnam(pair); 413 if (pw) { 414 *uid = pw->pw_uid; 415 } else 416 smb_error("Invalid user name %s, ignored", 0, pair); 417 } 418 endpwent(); 419 return 0; 420} 421 422int 423smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 424{ 425 int error = 0; 426 char *p, *cp; 427 428 switch(opt) { 429 case 'U': 430 break; 431 case 'I': 432 error = smb_ctx_setsrvaddr(ctx, arg); 433 break; 434 case 'M': 435 ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8); 436 if (*cp == '/') { 437 ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8); 438 ctx->ct_flags |= SMBCF_SRIGHTS; 439 } 440 break; 441 case 'N': 442 ctx->ct_flags |= SMBCF_NOPWD; 443 break; 444 case 'O': 445 p = strdup(arg); 446 cp = strchr(p, '/'); 447 if (cp) { 448 *cp++ = '\0'; 449 error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner, 450 &ctx->ct_sh.ioc_group); 451 } 452 if (*p && error == 0) { 453 error = smb_parse_owner(p, &ctx->ct_ssn.ioc_owner, 454 &ctx->ct_ssn.ioc_group); 455 } 456 free(p); 457 break; 458 case 'P': 459/* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT;*/ 460 break; 461 case 'R': 462 ctx->ct_ssn.ioc_retrycount = atoi(arg); 463 break; 464 case 'T': 465 ctx->ct_ssn.ioc_timeout = atoi(arg); 466 break; 467 case 'W': 468 error = smb_ctx_setworkgroup(ctx, arg); 469 break; 470 } 471 return error; 472} 473 474#if 0 475static void 476smb_hexdump(const u_char *buf, int len) { 477 int ofs = 0; 478 479 while (len--) { 480 if (ofs % 16 == 0) 481 printf("\n%02X: ", ofs); 482 printf("%02x ", *buf++); 483 ofs++; 484 } 485 printf("\n"); 486} 487#endif 488 489 490static int 491smb_addiconvtbl(const char *to, const char *from, const u_char *tbl) 492{ 493 int error; 494 495 error = kiconv_add_xlat_table(to, from, tbl); 496 if (error && error != EEXIST) { 497 smb_error("can not setup kernel iconv table (%s:%s)", error, 498 from, to); 499 return error; 500 } 501 return 0; 502} 503 504/* 505 * Verify context before connect operation(s), 506 * lookup specified server and try to fill all forgotten fields. 507 */ 508int 509smb_ctx_resolve(struct smb_ctx *ctx) 510{ 511 struct smbioc_ossn *ssn = &ctx->ct_ssn; 512 struct smbioc_oshare *sh = &ctx->ct_sh; 513 struct nb_name nn; 514 struct sockaddr *sap; 515 struct sockaddr_nb *salocal, *saserver; 516 char *cp; 517 int error = 0; 518 519 ctx->ct_flags &= ~SMBCF_RESOLVED; 520 if (ssn->ioc_srvname[0] == 0) { 521 smb_error("no server name specified", 0); 522 return EINVAL; 523 } 524 if (ssn->ioc_user[0] == 0) { 525 smb_error("no user name specified for server %s", 526 0, ssn->ioc_srvname); 527 return EINVAL; 528 } 529 if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) { 530 smb_error("no share name specified for %s@%s", 531 0, ssn->ioc_user, ssn->ioc_srvname); 532 return EINVAL; 533 } 534 error = nb_ctx_resolve(ctx->ct_nb); 535 if (error) 536 return error; 537 if (ssn->ioc_localcs[0] == 0) 538 strcpy(ssn->ioc_localcs, "ISO8859-1"); 539 error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 540 if (error) 541 return error; 542 error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 543 if (error) 544 return error; 545 if (ssn->ioc_servercs[0] != 0) { 546 error = kiconv_add_xlat16_cspairs 547 (ssn->ioc_servercs, ssn->ioc_localcs); 548 if (error) return error; 549 } 550 if (ctx->ct_srvaddr) { 551 error = nb_resolvehost_in(ctx->ct_srvaddr, &sap, ctx->ct_smbtcpport); 552 } else { 553 error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap); 554 } 555 if (error) { 556 smb_error("can't get server address", error); 557 return error; 558 } 559 nn.nn_scope = ctx->ct_nb->nb_scope; 560 nn.nn_type = NBT_SERVER; 561 strcpy(nn.nn_name, ssn->ioc_srvname); 562 error = nb_sockaddr(sap, &nn, &saserver); 563 nb_snbfree(sap); 564 if (error) { 565 smb_error("can't allocate server address", error); 566 return error; 567 } 568 ssn->ioc_server = (struct sockaddr*)saserver; 569 if (ctx->ct_locname[0] == 0) { 570 error = nb_getlocalname(ctx->ct_locname); 571 if (error) { 572 smb_error("can't get local name", error); 573 return error; 574 } 575 nls_str_upper(ctx->ct_locname, ctx->ct_locname); 576 } 577 strcpy(nn.nn_name, ctx->ct_locname); 578 nn.nn_type = NBT_WKSTA; 579 nn.nn_scope = ctx->ct_nb->nb_scope; 580 error = nb_sockaddr(NULL, &nn, &salocal); 581 if (error) { 582 nb_snbfree((struct sockaddr*)saserver); 583 smb_error("can't allocate local address", error); 584 return error; 585 } 586 ssn->ioc_local = (struct sockaddr*)salocal; 587 ssn->ioc_lolen = salocal->snb_len; 588 ssn->ioc_svlen = saserver->snb_len; 589 if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) { 590 cp = getpass("Password:"); 591 error = smb_ctx_setpassword(ctx, cp); 592 if (error) 593 return error; 594 } 595 ctx->ct_flags |= SMBCF_RESOLVED; 596 return 0; 597} 598 599static int 600smb_ctx_gethandle(struct smb_ctx *ctx) 601{ 602 int fd, i; 603 char buf[20]; 604 605 /* 606 * First, try to open as cloned device 607 */ 608 fd = open("/dev/"NSMB_NAME, O_RDWR); 609 if (fd >= 0) { 610 ctx->ct_fd = fd; 611 return 0; 612 } 613 /* 614 * well, no clone capabilities available - we have to scan 615 * all devices in order to get free one 616 */ 617 for (i = 0; i < 1024; i++) { 618 snprintf(buf, sizeof(buf), "/dev/%s%d", NSMB_NAME, i); 619 fd = open(buf, O_RDWR); 620 if (fd >= 0) { 621 ctx->ct_fd = fd; 622 return 0; 623 } 624 } 625 /* 626 * This is a compatibility with old /dev/net/nsmb device 627 */ 628 for (i = 0; i < 1024; i++) { 629 snprintf(buf, sizeof(buf), "/dev/net/%s%d", NSMB_NAME, i); 630 fd = open(buf, O_RDWR); 631 if (fd >= 0) { 632 ctx->ct_fd = fd; 633 return 0; 634 } 635 if (errno == ENOENT) 636 return ENOENT; 637 } 638 return ENOENT; 639} 640 641int 642smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) 643{ 644 struct smbioc_lookup rq; 645 int error; 646 647 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 648 smb_error("smb_ctx_lookup() data is not resolved", 0); 649 return EINVAL; 650 } 651 if (ctx->ct_fd != -1) { 652 close(ctx->ct_fd); 653 ctx->ct_fd = -1; 654 } 655 error = smb_ctx_gethandle(ctx); 656 if (error) { 657 smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0); 658 return EINVAL; 659 } 660 bzero(&rq, sizeof(rq)); 661 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn)); 662 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare)); 663 rq.ioc_flags = flags; 664 rq.ioc_level = level; 665 if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) { 666 error = errno; 667 if (flags & SMBLK_CREATE) 668 smb_error("unable to open connection", error); 669 return error; 670 } 671 return 0; 672} 673 674int 675smb_ctx_login(struct smb_ctx *ctx) 676{ 677 struct smbioc_ossn *ssn = &ctx->ct_ssn; 678 struct smbioc_oshare *sh = &ctx->ct_sh; 679 int error; 680 681 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 682 smb_error("smb_ctx_resolve() should be called first", 0); 683 return EINVAL; 684 } 685 if (ctx->ct_fd != -1) { 686 close(ctx->ct_fd); 687 ctx->ct_fd = -1; 688 } 689 error = smb_ctx_gethandle(ctx); 690 if (error) { 691 smb_error("can't get handle to requester", 0); 692 return EINVAL; 693 } 694 if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) { 695 error = errno; 696 smb_error("can't open session to server %s", error, ssn->ioc_srvname); 697 return error; 698 } 699 if (sh->ioc_share[0] == 0) 700 return 0; 701 if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) { 702 error = errno; 703 smb_error("can't connect to share //%s/%s", error, 704 ssn->ioc_srvname, sh->ioc_share); 705 return error; 706 } 707 return 0; 708} 709 710int 711smb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags) 712{ 713 struct smbioc_flags fl; 714 715 if (ctx->ct_fd == -1) 716 return EINVAL; 717 fl.ioc_level = level; 718 fl.ioc_mask = mask; 719 fl.ioc_flags = flags; 720 if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1) 721 return errno; 722 return 0; 723} 724 725/* 726 * level values: 727 * 0 - default 728 * 1 - server 729 * 2 - server:user 730 * 3 - server:user:share 731 */ 732static int 733smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 734{ 735 char *p; 736 int error; 737 738 if (level >= 0) { 739 rc_getstringptr(smb_rc, sname, "charsets", &p); 740 if (p) { 741 error = smb_ctx_setcharset(ctx, p); 742 if (error) 743 smb_error("charset specification in the section '%s' ignored", error, sname); 744 } 745 } 746 if (level <= 1) { 747 rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout); 748 rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount); 749 } 750 if (level == 1) { 751 rc_getstringptr(smb_rc, sname, "addr", &p); 752 if (p) { 753 error = smb_ctx_setsrvaddr(ctx, p); 754 if (error) { 755 smb_error("invalid address specified in the section %s", 0, sname); 756 return error; 757 } 758 } 759 } 760 if (level >= 2) { 761 rc_getstringptr(smb_rc, sname, "password", &p); 762 if (p) 763 smb_ctx_setpassword(ctx, p); 764 } 765 rc_getstringptr(smb_rc, sname, "workgroup", &p); 766 if (p) 767 smb_ctx_setworkgroup(ctx, p); 768 return 0; 769} 770 771/* 772 * read rc file as follows: 773 * 1. read [default] section 774 * 2. override with [server] section 775 * 3. override with [server:user:share] section 776 * Since abcence of rcfile is not fatal, silently ignore this fact. 777 * smb_rc file should be closed by caller. 778 */ 779int 780smb_ctx_readrc(struct smb_ctx *ctx) 781{ 782 char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + SMB_MAXSHARENAMELEN + 4]; 783/* char *p;*/ 784 785 if (smb_open_rcfile() != 0) 786 return 0; 787 788 if (ctx->ct_ssn.ioc_user[0] == 0 || ctx->ct_ssn.ioc_srvname[0] == 0) 789 return 0; 790 791 smb_ctx_readrcsection(ctx, "default", 0); 792 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 793 smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1); 794 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, ctx->ct_ssn.ioc_srvname, 1); 795 /* 796 * SERVER:USER parameters 797 */ 798 snprintf(sname, sizeof(sname), "%s:%s", ctx->ct_ssn.ioc_srvname, 799 ctx->ct_ssn.ioc_user); 800 smb_ctx_readrcsection(ctx, sname, 2); 801 802 if (ctx->ct_sh.ioc_share[0] != 0) { 803 /* 804 * SERVER:USER:SHARE parameters 805 */ 806 snprintf(sname, sizeof(sname), "%s:%s:%s", ctx->ct_ssn.ioc_srvname, 807 ctx->ct_ssn.ioc_user, ctx->ct_sh.ioc_share); 808 smb_ctx_readrcsection(ctx, sname, 3); 809 } 810 return 0; 811} 812 813