ctx.c revision 118079
1219131Srwatson/* 2219131Srwatson * Copyright (c) 2000-2002, Boris Popov 3219131Srwatson * All rights reserved. 4219131Srwatson * 5219131Srwatson * Redistribution and use in source and binary forms, with or without 6219131Srwatson * modification, are permitted provided that the following conditions 7219131Srwatson * are met: 8219131Srwatson * 1. Redistributions of source code must retain the above copyright 9219131Srwatson * notice, this list of conditions and the following disclaimer. 10219131Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11219131Srwatson * notice, this list of conditions and the following disclaimer in the 12219131Srwatson * documentation and/or other materials provided with the distribution. 13219131Srwatson * 3. All advertising materials mentioning features or use of this software 14219131Srwatson * must display the following acknowledgement: 15219131Srwatson * This product includes software developed by Boris Popov. 16219131Srwatson * 4. Neither the name of the author nor the names of any co-contributors 17219131Srwatson * may be used to endorse or promote products derived from this software 18219131Srwatson * without specific prior written permission. 19219131Srwatson * 20219131Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21219131Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22219131Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23219131Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24219131Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25219131Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26219131Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27219131Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28219131Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29219131Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30219131Srwatson * SUCH DAMAGE. 31219131Srwatson * 32219131Srwatson * $Id: ctx.c,v 1.24 2002/04/13 14:35:28 bp Exp $ 33219131Srwatson * $FreeBSD: head/contrib/smbfs/lib/smb/ctx.c 118079 2003-07-27 11:41:38Z tjr $ 34219131Srwatson */ 35219131Srwatson#include <sys/param.h> 36219131Srwatson#include <sys/sysctl.h> 37219131Srwatson#include <sys/ioctl.h> 38219131Srwatson#include <sys/time.h> 39219131Srwatson#include <sys/mount.h> 40219131Srwatson#include <fcntl.h> 41219131Srwatson#include <ctype.h> 42219131Srwatson#include <errno.h> 43219131Srwatson#include <stdio.h> 44219131Srwatson#include <string.h> 45219131Srwatson#include <stdlib.h> 46219131Srwatson#include <pwd.h> 47219131Srwatson#include <grp.h> 48219131Srwatson#include <unistd.h> 49219131Srwatson#include <sys/iconv.h> 50219131Srwatson 51219131Srwatson#define NB_NEEDRESOLVER 52219131Srwatson 53219131Srwatson#include <netsmb/smb_lib.h> 54219131Srwatson#include <netsmb/netbios.h> 55219131Srwatson#include <netsmb/nb_lib.h> 56219131Srwatson#include <netsmb/smb_conn.h> 57219131Srwatson#include <cflib.h> 58219131Srwatson 59219131Srwatson/* 60219131Srwatson * Prescan command line for [-U user] argument 61219131Srwatson * and fill context with defaults 62219131Srwatson */ 63219131Srwatsonint 64219131Srwatsonsmb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[], 65219131Srwatson int minlevel, int maxlevel, int sharetype) 66219131Srwatson{ 67219131Srwatson int opt, error = 0; 68219131Srwatson uid_t euid; 69219131Srwatson const char *arg, *cp; 70219131Srwatson struct passwd *pwd; 71219131Srwatson 72219131Srwatson bzero(ctx,sizeof(*ctx)); 73219131Srwatson error = nb_ctx_create(&ctx->ct_nb); 74219131Srwatson if (error) 75219131Srwatson return error; 76219131Srwatson ctx->ct_fd = -1; 77219131Srwatson ctx->ct_parsedlevel = SMBL_NONE; 78219131Srwatson ctx->ct_minlevel = minlevel; 79250154Sjilles ctx->ct_maxlevel = maxlevel; 80219131Srwatson 81219131Srwatson ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE; 82219131Srwatson ctx->ct_ssn.ioc_timeout = 15; 83219131Srwatson ctx->ct_ssn.ioc_retrycount = 4; 84219131Srwatson ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER; 85219131Srwatson ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP; 86219131Srwatson ctx->ct_ssn.ioc_mode = SMBM_EXEC; 87219131Srwatson ctx->ct_ssn.ioc_rights = SMBM_DEFAULT; 88219131Srwatson 89219131Srwatson ctx->ct_sh.ioc_opt = SMBVOPT_CREATE; 90219131Srwatson ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 91219131Srwatson ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 92219131Srwatson ctx->ct_sh.ioc_mode = SMBM_EXEC; 93219131Srwatson ctx->ct_sh.ioc_rights = SMBM_DEFAULT; 94219131Srwatson ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 95219131Srwatson ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 96219131Srwatson 97219131Srwatson nb_ctx_setscope(ctx->ct_nb, ""); 98219131Srwatson euid = geteuid(); 99219131Srwatson if ((pwd = getpwuid(euid)) != NULL) { 100219131Srwatson smb_ctx_setuser(ctx, pwd->pw_name); 101219131Srwatson endpwent(); 102247667Spjd } else if (euid == 0) 103219131Srwatson smb_ctx_setuser(ctx, "root"); 104247667Spjd else 105219131Srwatson return 0; 106219131Srwatson if (argv == NULL) 107219131Srwatson return 0; 108219131Srwatson for (opt = 1; opt < argc; opt++) { 109219131Srwatson cp = argv[opt]; 110247602Spjd if (strncmp(cp, "//", 2) != 0) 111247602Spjd continue; 112219131Srwatson error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp); 113247602Spjd if (error) 114247602Spjd return error; 115255219Spjd ctx->ct_uncnext = cp; 116247602Spjd break; 117219131Srwatson } 118219131Srwatson while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) { 119219131Srwatson arg = cf_optarg; 120219131Srwatson switch (opt) { 121255374Spjd case 'E': 122219131Srwatson error = smb_ctx_setcharset(ctx, arg); 123219131Srwatson if (error) 124219131Srwatson return error; 125219131Srwatson break; 126219131Srwatson case 'L': 127219131Srwatson error = nls_setlocale(optarg); 128219131Srwatson if (error) 129219131Srwatson break; 130219131Srwatson break; 131247667Spjd case 'U': 132219131Srwatson error = smb_ctx_setuser(ctx, arg); 133247667Spjd break; 134219131Srwatson } 135219131Srwatson } 136319819Sallanjude cf_optind = cf_optreset = 1; 137219131Srwatson return error; 138219131Srwatson} 139319819Sallanjude 140219131Srwatsonvoid 141319819Sallanjudesmb_ctx_done(struct smb_ctx *ctx) 142219131Srwatson{ 143219131Srwatson if (ctx->ct_ssn.ioc_server) 144219131Srwatson nb_snbfree(ctx->ct_ssn.ioc_server); 145219131Srwatson if (ctx->ct_ssn.ioc_local) 146219131Srwatson nb_snbfree(ctx->ct_ssn.ioc_local); 147219131Srwatson if (ctx->ct_srvaddr) 148219131Srwatson free(ctx->ct_srvaddr); 149219131Srwatson if (ctx->ct_nb) 150219131Srwatson nb_ctx_done(ctx->ct_nb); 151219131Srwatson} 152219131Srwatson 153219131Srwatsonstatic int 154219131Srwatsongetsubstring(const char *p, u_char sep, char *dest, int maxlen, const char **next) 155219131Srwatson{ 156219131Srwatson int len; 157219131Srwatson 158219131Srwatson maxlen--; 159219131Srwatson for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 160219131Srwatson if (*p == 0) 161219131Srwatson return EINVAL; 162219131Srwatson *dest = *p; 163219131Srwatson } 164219131Srwatson *dest = 0; 165219131Srwatson *next = *p ? p + 1 : p; 166219131Srwatson return 0; 167219131Srwatson} 168219131Srwatson 169219131Srwatson/* 170219131Srwatson * Here we expect something like "[proto:]//[user@]host[/share][/path]" 171219131Srwatson */ 172219131Srwatsonint 173219131Srwatsonsmb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, 174219131Srwatson const char **next) 175219131Srwatson{ 176219131Srwatson const char *p = unc; 177219131Srwatson char *p1; 178219131Srwatson char tmp[1024]; 179219131Srwatson int error ; 180219131Srwatson 181219131Srwatson ctx->ct_parsedlevel = SMBL_NONE; 182219131Srwatson if (*p++ != '/' || *p++ != '/') { 183219131Srwatson smb_error("UNC should start with '//'", 0); 184219131Srwatson return EINVAL; 185219131Srwatson } 186219131Srwatson p1 = tmp; 187219131Srwatson error = getsubstring(p, '@', p1, sizeof(tmp), &p); 188219131Srwatson if (!error) { 189219131Srwatson if (ctx->ct_maxlevel < SMBL_VC) { 190219131Srwatson smb_error("no user name required", 0); 191219131Srwatson return EINVAL; 192219131Srwatson } 193219131Srwatson if (*p1 == 0) { 194219131Srwatson smb_error("empty user name", 0); 195219131Srwatson return EINVAL; 196219131Srwatson } 197224852Srwatson error = smb_ctx_setuser(ctx, tmp); 198219131Srwatson if (error) 199219131Srwatson return error; 200219131Srwatson ctx->ct_parsedlevel = SMBL_VC; 201219131Srwatson } 202219131Srwatson error = getsubstring(p, '/', p1, sizeof(tmp), &p); 203219131Srwatson if (error) { 204219131Srwatson error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 205219131Srwatson if (error) { 206219131Srwatson smb_error("no server name found", 0); 207219131Srwatson return error; 208219131Srwatson } 209219131Srwatson } 210219131Srwatson if (*p1 == 0) { 211219131Srwatson smb_error("empty server name", 0); 212219131Srwatson return EINVAL; 213219131Srwatson } 214219131Srwatson error = smb_ctx_setserver(ctx, tmp); 215219131Srwatson if (error) 216219131Srwatson return error; 217219131Srwatson if (sharetype == SMB_ST_NONE) { 218219131Srwatson *next = p; 219219131Srwatson return 0; 220277610Sjilles } 221219131Srwatson if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 222277610Sjilles smb_error("no share name required", 0); 223219131Srwatson return EINVAL; 224219131Srwatson } 225219131Srwatson error = getsubstring(p, '/', p1, sizeof(tmp), &p); 226219131Srwatson if (error) { 227219131Srwatson error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 228219131Srwatson if (error) { 229219131Srwatson smb_error("unexpected end of line", 0); 230219131Srwatson return error; 231219131Srwatson } 232219131Srwatson } 233219131Srwatson if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) { 234219131Srwatson smb_error("empty share name", 0); 235219131Srwatson return EINVAL; 236219131Srwatson } 237219131Srwatson *next = p; 238219131Srwatson if (*p1 == 0) 239219131Srwatson return 0; 240219131Srwatson error = smb_ctx_setshare(ctx, p1, sharetype); 241247602Spjd return error; 242219131Srwatson} 243219131Srwatson 244219131Srwatsonint 245219131Srwatsonsmb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 246219131Srwatson{ 247219131Srwatson char *cp, *servercs, *localcs; 248219131Srwatson int cslen = sizeof(ctx->ct_ssn.ioc_localcs); 249219131Srwatson int scslen, lcslen, error; 250305514Semaste 251219131Srwatson cp = strchr(arg, ':'); 252219131Srwatson lcslen = cp ? (cp - arg) : 0; 253219131Srwatson if (lcslen == 0 || lcslen >= cslen) { 254219131Srwatson smb_error("invalid local charset specification (%s)", 0, arg); 255219131Srwatson return EINVAL; 256219131Srwatson } 257219131Srwatson scslen = (size_t)strlen(++cp); 258219131Srwatson if (scslen == 0 || scslen >= cslen) { 259219131Srwatson smb_error("invalid server charset specification (%s)", 0, arg); 260219131Srwatson return EINVAL; 261219131Srwatson } 262219131Srwatson localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 263219131Srwatson localcs[lcslen] = 0; 264219131Srwatson servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 265219131Srwatson error = nls_setrecode(localcs, servercs); 266219131Srwatson if (error == 0) 267219131Srwatson return 0; 268219131Srwatson smb_error("can't initialize iconv support (%s:%s)", 269219131Srwatson error, localcs, servercs); 270219131Srwatson localcs[0] = 0; 271219131Srwatson servercs[0] = 0; 272219131Srwatson return error; 273219131Srwatson} 274219131Srwatson 275219131Srwatsonint 276219131Srwatsonsmb_ctx_setserver(struct smb_ctx *ctx, const char *name) 277219131Srwatson{ 278219131Srwatson if (strlen(name) > SMB_MAXSRVNAMELEN) { 279219131Srwatson smb_error("server name '%s' too long", 0, name); 280219131Srwatson return ENAMETOOLONG; 281219131Srwatson } 282219131Srwatson nls_str_upper(ctx->ct_ssn.ioc_srvname, name); 283219131Srwatson return 0; 284219131Srwatson} 285219131Srwatson 286219131Srwatsonint 287219131Srwatsonsmb_ctx_setuser(struct smb_ctx *ctx, const char *name) 288219131Srwatson{ 289219131Srwatson if (strlen(name) > SMB_MAXUSERNAMELEN) { 290219131Srwatson smb_error("user name '%s' too long", 0, name); 291219131Srwatson return ENAMETOOLONG; 292219131Srwatson } 293219131Srwatson nls_str_upper(ctx->ct_ssn.ioc_user, name); 294219131Srwatson return 0; 295219131Srwatson} 296219131Srwatson 297219131Srwatsonint 298219131Srwatsonsmb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name) 299219131Srwatson{ 300219131Srwatson if (strlen(name) > SMB_MAXUSERNAMELEN) { 301219131Srwatson smb_error("workgroup name '%s' too long", 0, name); 302219131Srwatson return ENAMETOOLONG; 303219131Srwatson } 304219131Srwatson nls_str_upper(ctx->ct_ssn.ioc_workgroup, name); 305219131Srwatson return 0; 306219131Srwatson} 307219131Srwatson 308219131Srwatsonint 309219131Srwatsonsmb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd) 310219131Srwatson{ 311219131Srwatson if (passwd == NULL) 312219131Srwatson return EINVAL; 313219131Srwatson if (strlen(passwd) > SMB_MAXPASSWORDLEN) { 314219131Srwatson smb_error("password too long", 0); 315219131Srwatson return ENAMETOOLONG; 316219131Srwatson } 317219131Srwatson if (strncmp(passwd, "$$1", 3) == 0) 318219131Srwatson smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); 319219131Srwatson else 320247602Spjd strcpy(ctx->ct_ssn.ioc_password, passwd); 321247602Spjd strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); 322219131Srwatson return 0; 323247602Spjd} 324219131Srwatson 325219131Srwatsonint 326219131Srwatsonsmb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 327219131Srwatson{ 328219131Srwatson if (strlen(share) > SMB_MAXSHARENAMELEN) { 329219131Srwatson smb_error("share name '%s' too long", 0, share); 330219131Srwatson return ENAMETOOLONG; 331219131Srwatson } 332219131Srwatson nls_str_upper(ctx->ct_sh.ioc_share, share); 333219131Srwatson if (share[0] != 0) 334219131Srwatson ctx->ct_parsedlevel = SMBL_SHARE; 335219131Srwatson ctx->ct_sh.ioc_stype = stype; 336219131Srwatson return 0; 337243610Spjd} 338243610Spjd 339243610Spjdint 340243610Spjdsmb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 341243610Spjd{ 342219131Srwatson if (addr == NULL || addr[0] == 0) 343219131Srwatson return EINVAL; 344321322Skib if (ctx->ct_srvaddr) 345321322Skib free(ctx->ct_srvaddr); 346219131Srwatson if ((ctx->ct_srvaddr = strdup(addr)) == NULL) 347219131Srwatson return ENOMEM; 348219131Srwatson return 0; 349219131Srwatson} 350219131Srwatson 351219131Srwatsonstatic int 352219131Srwatsonsmb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 353219131Srwatson{ 354219131Srwatson struct group *gr; 355219131Srwatson struct passwd *pw; 356219131Srwatson char *cp; 357219131Srwatson 358219131Srwatson cp = strchr(pair, ':'); 359219131Srwatson if (cp) { 360219131Srwatson *cp++ = '\0'; 361219131Srwatson if (*cp) { 362219131Srwatson gr = getgrnam(cp); 363219131Srwatson if (gr) { 364219131Srwatson *gid = gr->gr_gid; 365219131Srwatson } else 366219131Srwatson smb_error("Invalid group name %s, ignored", 367219131Srwatson 0, cp); 368219131Srwatson } 369219131Srwatson } 370219131Srwatson if (*pair) { 371219131Srwatson pw = getpwnam(pair); 372219131Srwatson if (pw) { 373219131Srwatson *uid = pw->pw_uid; 374219131Srwatson } else 375219131Srwatson smb_error("Invalid user name %s, ignored", 0, pair); 376219131Srwatson } 377219131Srwatson endpwent(); 378219131Srwatson return 0; 379219131Srwatson} 380219131Srwatson 381219131Srwatsonint 382219131Srwatsonsmb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 383219131Srwatson{ 384219131Srwatson int error = 0; 385219131Srwatson char *p, *cp; 386219131Srwatson 387219131Srwatson switch(opt) { 388219131Srwatson case 'U': 389219131Srwatson break; 390219131Srwatson case 'I': 391219131Srwatson error = smb_ctx_setsrvaddr(ctx, arg); 392219131Srwatson break; 393219131Srwatson case 'M': 394219131Srwatson ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8); 395219131Srwatson if (*cp == '/') { 396219131Srwatson ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8); 397219131Srwatson ctx->ct_flags |= SMBCF_SRIGHTS; 398219131Srwatson } 399219131Srwatson break; 400219131Srwatson case 'N': 401219131Srwatson ctx->ct_flags |= SMBCF_NOPWD; 402219131Srwatson break; 403219131Srwatson case 'O': 404219131Srwatson p = strdup(arg); 405219131Srwatson cp = strchr(p, '/'); 406219131Srwatson if (cp) { 407219131Srwatson *cp++ = '\0'; 408219131Srwatson error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner, 409219131Srwatson &ctx->ct_sh.ioc_group); 410219131Srwatson } 411219131Srwatson if (*p && error == 0) { 412219131Srwatson error = smb_parse_owner(p, &ctx->ct_ssn.ioc_owner, 413219131Srwatson &ctx->ct_ssn.ioc_group); 414219131Srwatson } 415219131Srwatson free(p); 416219131Srwatson break; 417219131Srwatson case 'P': 418219131Srwatson/* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT;*/ 419219131Srwatson break; 420219131Srwatson case 'R': 421219131Srwatson ctx->ct_ssn.ioc_retrycount = atoi(arg); 422219131Srwatson break; 423219131Srwatson case 'T': 424219131Srwatson ctx->ct_ssn.ioc_timeout = atoi(arg); 425219131Srwatson break; 426219131Srwatson case 'W': 427219131Srwatson error = smb_ctx_setworkgroup(ctx, arg); 428219131Srwatson break; 429219131Srwatson } 430219131Srwatson return error; 431219131Srwatson} 432219131Srwatson 433219131Srwatson#if 0 434219131Srwatsonstatic void 435219131Srwatsonsmb_hexdump(const u_char *buf, int len) { 436219131Srwatson int ofs = 0; 437219131Srwatson 438219131Srwatson while (len--) { 439219131Srwatson if (ofs % 16 == 0) 440224812Sjonathan printf("\n%02X: ", ofs); 441219131Srwatson printf("%02x ", *buf++); 442248599Spjd ofs++; 443224812Sjonathan } 444224812Sjonathan printf("\n"); 445236361Spjd} 446248359Spjd#endif 447224812Sjonathan 448236361Spjd 449224812Sjonathanstatic int 450224812Sjonathansmb_addiconvtbl(const char *to, const char *from, const u_char *tbl) 451224812Sjonathan{ 452224812Sjonathan int error; 453236361Spjd 454224812Sjonathan error = kiconv_add_xlat_table(to, from, tbl); 455236361Spjd if (error && error != EEXIST) { 456236361Spjd smb_error("can not setup kernel iconv table (%s:%s)", error, 457277610Sjilles from, to); 458219131Srwatson return error; 459219131Srwatson } 460224812Sjonathan return 0; 461224812Sjonathan} 462224812Sjonathan 463224812Sjonathan/* 464219131Srwatson * Verify context before connect operation(s), 465224812Sjonathan * lookup specified server and try to fill all forgotten fields. 466219131Srwatson */ 467219131Srwatsonint 468219131Srwatsonsmb_ctx_resolve(struct smb_ctx *ctx) 469219131Srwatson{ 470219131Srwatson struct smbioc_ossn *ssn = &ctx->ct_ssn; 471219131Srwatson struct smbioc_oshare *sh = &ctx->ct_sh; 472219131Srwatson struct nb_name nn; 473219131Srwatson struct sockaddr *sap; 474219131Srwatson struct sockaddr_nb *salocal, *saserver; 475219131Srwatson char *cp; 476219131Srwatson u_char cstbl[256]; 477219131Srwatson u_int i; 478219131Srwatson int error = 0; 479219131Srwatson 480219131Srwatson ctx->ct_flags &= ~SMBCF_RESOLVED; 481224987Sjonathan if (ssn->ioc_srvname[0] == 0) { 482219131Srwatson smb_error("no server name specified", 0); 483219131Srwatson return EINVAL; 484219131Srwatson } 485219131Srwatson if (ssn->ioc_user[0] == 0) { 486219131Srwatson smb_error("no user name specified for server %s", 487250159Sjilles 0, ssn->ioc_srvname); 488219131Srwatson return EINVAL; 489219131Srwatson } 490219131Srwatson if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) { 491219131Srwatson smb_error("no share name specified for %s@%s", 492219131Srwatson 0, ssn->ioc_user, ssn->ioc_srvname); 493219131Srwatson return EINVAL; 494219131Srwatson } 495219131Srwatson error = nb_ctx_resolve(ctx->ct_nb); 496219131Srwatson if (error) 497219131Srwatson return error; 498331679Semaste if (ssn->ioc_localcs[0] == 0) 499219131Srwatson strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ 500219131Srwatson error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 501219131Srwatson if (error) 502219131Srwatson return error; 503219131Srwatson error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 504219131Srwatson if (error) 505219131Srwatson return error; 506219131Srwatson if (ssn->ioc_servercs[0] != 0) { 507219131Srwatson for(i = 0; i < sizeof(cstbl); i++) 508219131Srwatson cstbl[i] = i; 509219131Srwatson nls_mem_toext(cstbl, cstbl, sizeof(cstbl)); 510219131Srwatson error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, cstbl); 511219131Srwatson if (error) 512219131Srwatson return error; 513219131Srwatson for(i = 0; i < sizeof(cstbl); i++) 514219131Srwatson cstbl[i] = i; 515219131Srwatson nls_mem_toloc(cstbl, cstbl, sizeof(cstbl)); 516219131Srwatson error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, cstbl); 517219131Srwatson if (error) 518219131Srwatson return error; 519219131Srwatson } 520219131Srwatson if (ctx->ct_srvaddr) { 521219131Srwatson error = nb_resolvehost_in(ctx->ct_srvaddr, &sap); 522219131Srwatson } else { 523219131Srwatson error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap); 524219131Srwatson } 525219131Srwatson if (error) { 526219131Srwatson smb_error("can't get server address", error); 527219131Srwatson return error; 528219131Srwatson } 529219131Srwatson nn.nn_scope = ctx->ct_nb->nb_scope; 530219131Srwatson nn.nn_type = NBT_SERVER; 531219131Srwatson strcpy(nn.nn_name, ssn->ioc_srvname); 532219131Srwatson error = nb_sockaddr(sap, &nn, &saserver); 533219131Srwatson nb_snbfree(sap); 534219131Srwatson if (error) { 535219131Srwatson smb_error("can't allocate server address", error); 536219131Srwatson return error; 537219131Srwatson } 538219131Srwatson ssn->ioc_server = (struct sockaddr*)saserver; 539219131Srwatson if (ctx->ct_locname[0] == 0) { 540219131Srwatson error = nb_getlocalname(ctx->ct_locname); 541219131Srwatson if (error) { 542219131Srwatson smb_error("can't get local name", error); 543219131Srwatson return error; 544219131Srwatson } 545219131Srwatson nls_str_upper(ctx->ct_locname, ctx->ct_locname); 546219131Srwatson } 547219131Srwatson strcpy(nn.nn_name, ctx->ct_locname); 548219131Srwatson nn.nn_type = NBT_WKSTA; 549219131Srwatson nn.nn_scope = ctx->ct_nb->nb_scope; 550219131Srwatson error = nb_sockaddr(NULL, &nn, &salocal); 551257736Spjd if (error) { 552219131Srwatson nb_snbfree((struct sockaddr*)saserver); 553219131Srwatson smb_error("can't allocate local address", error); 554219131Srwatson return error; 555219131Srwatson } 556219131Srwatson ssn->ioc_local = (struct sockaddr*)salocal; 557219131Srwatson ssn->ioc_lolen = salocal->snb_len; 558321322Skib ssn->ioc_svlen = saserver->snb_len; 559321322Skib if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) { 560219131Srwatson cp = getpass("Password:"); 561219131Srwatson error = smb_ctx_setpassword(ctx, cp); 562219131Srwatson if (error) 563219131Srwatson return error; 564219131Srwatson } 565219131Srwatson ctx->ct_flags |= SMBCF_RESOLVED; 566219131Srwatson return 0; 567259436Spjd} 568219131Srwatson 569219131Srwatsonstatic int 570219131Srwatsonsmb_ctx_gethandle(struct smb_ctx *ctx) 571259436Spjd{ 572219131Srwatson int fd, i; 573219131Srwatson char buf[20]; 574219131Srwatson 575219131Srwatson /* 576219131Srwatson * First, try to open as cloned device 577219131Srwatson */ 578219131Srwatson fd = open("/dev/"NSMB_NAME, O_RDWR); 579219131Srwatson if (fd >= 0) { 580219131Srwatson ctx->ct_fd = fd; 581219131Srwatson return 0; 582219131Srwatson } 583219131Srwatson /* 584219131Srwatson * well, no clone capabilities available - we have to scan 585219131Srwatson * all devices in order to get free one 586219131Srwatson */ 587219131Srwatson for (i = 0; i < 1024; i++) { 588219131Srwatson snprintf(buf, sizeof(buf), "/dev/%s%d", NSMB_NAME, i); 589219131Srwatson fd = open(buf, O_RDWR); 590219131Srwatson if (fd >= 0) { 591219131Srwatson ctx->ct_fd = fd; 592219131Srwatson return 0; 593219131Srwatson } 594219131Srwatson } 595219131Srwatson /* 596219131Srwatson * This is a compatibility with old /dev/net/nsmb device 597219131Srwatson */ 598219131Srwatson for (i = 0; i < 1024; i++) { 599219131Srwatson snprintf(buf, sizeof(buf), "/dev/net/%s%d", NSMB_NAME, i); 600219131Srwatson fd = open(buf, O_RDWR); 601219131Srwatson if (fd >= 0) { 602219131Srwatson ctx->ct_fd = fd; 603219131Srwatson return 0; 604219131Srwatson } 605219131Srwatson if (errno == ENOENT) 606219131Srwatson return ENOENT; 607219131Srwatson } 608219131Srwatson return ENOENT; 609219131Srwatson} 610219131Srwatson 611219131Srwatsonint 612219131Srwatsonsmb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) 613219131Srwatson{ 614219131Srwatson struct smbioc_lookup rq; 615219131Srwatson int error; 616219131Srwatson 617219131Srwatson if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 618219131Srwatson smb_error("smb_ctx_lookup() data is not resolved", 0); 619219131Srwatson return EINVAL; 620219131Srwatson } 621219131Srwatson if (ctx->ct_fd != -1) { 622219131Srwatson close(ctx->ct_fd); 623219131Srwatson ctx->ct_fd = -1; 624219131Srwatson } 625219131Srwatson error = smb_ctx_gethandle(ctx); 626219131Srwatson if (error) { 627219131Srwatson smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0); 628219131Srwatson return EINVAL; 629219131Srwatson } 630219131Srwatson bzero(&rq, sizeof(rq)); 631219131Srwatson bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn)); 632219131Srwatson bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare)); 633219131Srwatson rq.ioc_flags = flags; 634219131Srwatson rq.ioc_level = level; 635219131Srwatson if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) { 636219131Srwatson error = errno; 637219131Srwatson if (flags & SMBLK_CREATE) 638219131Srwatson smb_error("unable to open connection", error); 639219131Srwatson return error; 640219131Srwatson } 641219131Srwatson return 0; 642219131Srwatson} 643219131Srwatson 644219131Srwatsonint 645219131Srwatsonsmb_ctx_login(struct smb_ctx *ctx) 646219131Srwatson{ 647219131Srwatson struct smbioc_ossn *ssn = &ctx->ct_ssn; 648219131Srwatson struct smbioc_oshare *sh = &ctx->ct_sh; 649219131Srwatson int error; 650224812Sjonathan 651219131Srwatson if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 652224812Sjonathan smb_error("smb_ctx_resolve() should be called first", 0); 653219131Srwatson return EINVAL; 654219131Srwatson } 655219131Srwatson if (ctx->ct_fd != -1) { 656219131Srwatson close(ctx->ct_fd); 657219131Srwatson ctx->ct_fd = -1; 658219131Srwatson } 659219131Srwatson error = smb_ctx_gethandle(ctx); 660219131Srwatson if (error) { 661219131Srwatson smb_error("can't get handle to requester", 0); 662219131Srwatson return EINVAL; 663219131Srwatson } 664219131Srwatson if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) { 665219131Srwatson error = errno; 666219131Srwatson smb_error("can't open session to server %s", error, ssn->ioc_srvname); 667219131Srwatson return error; 668219131Srwatson } 669219131Srwatson if (sh->ioc_share[0] == 0) 670219131Srwatson return 0; 671219131Srwatson if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) { 672219131Srwatson error = errno; 673219131Srwatson smb_error("can't connect to share //%s/%s", error, 674219131Srwatson ssn->ioc_srvname, sh->ioc_share); 675261220Scsjp return error; 676219131Srwatson } 677219131Srwatson return 0; 678219131Srwatson} 679219131Srwatson 680219131Srwatsonint 681219131Srwatsonsmb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags) 682219131Srwatson{ 683219131Srwatson struct smbioc_flags fl; 684219131Srwatson 685219131Srwatson if (ctx->ct_fd == -1) 686219131Srwatson return EINVAL; 687219131Srwatson fl.ioc_level = level; 688219131Srwatson fl.ioc_mask = mask; 689219131Srwatson fl.ioc_flags = flags; 690219131Srwatson if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1) 691219131Srwatson return errno; 692219131Srwatson return 0; 693219131Srwatson} 694219131Srwatson 695219131Srwatson/* 696219131Srwatson * level values: 697219131Srwatson * 0 - default 698219131Srwatson * 1 - server 699219131Srwatson * 2 - server:user 700219131Srwatson * 3 - server:user:share 701219131Srwatson */ 702219131Srwatsonstatic int 703219131Srwatsonsmb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 704219131Srwatson{ 705219131Srwatson char *p; 706219131Srwatson int error; 707219131Srwatson 708219131Srwatson if (level >= 0) { 709219131Srwatson rc_getstringptr(smb_rc, sname, "charsets", &p); 710219131Srwatson if (p) { 711219131Srwatson error = smb_ctx_setcharset(ctx, p); 712219131Srwatson if (error) 713219131Srwatson smb_error("charset specification in the section '%s' ignored", error, sname); 714219131Srwatson } 715219131Srwatson } 716219131Srwatson if (level <= 1) { 717219131Srwatson rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout); 718219131Srwatson rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount); 719219131Srwatson } 720219131Srwatson if (level == 1) { 721219131Srwatson rc_getstringptr(smb_rc, sname, "addr", &p); 722219131Srwatson if (p) { 723219131Srwatson error = smb_ctx_setsrvaddr(ctx, p); 724219131Srwatson if (error) { 725219131Srwatson smb_error("invalid address specified in the section %s", 0, sname); 726219131Srwatson return error; 727219131Srwatson } 728219131Srwatson } 729219131Srwatson } 730219131Srwatson if (level >= 2) { 731219131Srwatson rc_getstringptr(smb_rc, sname, "password", &p); 732219131Srwatson if (p) 733219131Srwatson smb_ctx_setpassword(ctx, p); 734219131Srwatson } 735219131Srwatson rc_getstringptr(smb_rc, sname, "workgroup", &p); 736219131Srwatson if (p) 737219131Srwatson smb_ctx_setworkgroup(ctx, p); 738219131Srwatson return 0; 739219131Srwatson} 740219131Srwatson 741219131Srwatson/* 742219131Srwatson * read rc file as follows: 743219131Srwatson * 1. read [default] section 744219131Srwatson * 2. override with [server] section 745219131Srwatson * 3. override with [server:user:share] section 746219131Srwatson * Since abcence of rcfile is not fatal, silently ignore this fact. 747219131Srwatson * smb_rc file should be closed by caller. 748219131Srwatson */ 749219131Srwatsonint 750219131Srwatsonsmb_ctx_readrc(struct smb_ctx *ctx) 751219131Srwatson{ 752219131Srwatson char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + SMB_MAXSHARENAMELEN + 4]; 753219131Srwatson/* char *p;*/ 754219131Srwatson 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