187866Ssheldonh/* 295267Ssheldonh * Copyright (c) 2000-2002, Boris Popov 387866Ssheldonh * All rights reserved. 487866Ssheldonh * 587866Ssheldonh * Redistribution and use in source and binary forms, with or without 687866Ssheldonh * modification, are permitted provided that the following conditions 787866Ssheldonh * are met: 887866Ssheldonh * 1. Redistributions of source code must retain the above copyright 987866Ssheldonh * notice, this list of conditions and the following disclaimer. 1087866Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright 1187866Ssheldonh * notice, this list of conditions and the following disclaimer in the 1287866Ssheldonh * documentation and/or other materials provided with the distribution. 1387866Ssheldonh * 3. All advertising materials mentioning features or use of this software 1487866Ssheldonh * must display the following acknowledgement: 1587866Ssheldonh * This product includes software developed by Boris Popov. 1687866Ssheldonh * 4. Neither the name of the author nor the names of any co-contributors 1787866Ssheldonh * may be used to endorse or promote products derived from this software 1887866Ssheldonh * without specific prior written permission. 1987866Ssheldonh * 2087866Ssheldonh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2187866Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2287866Ssheldonh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2387866Ssheldonh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2487866Ssheldonh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2587866Ssheldonh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2687866Ssheldonh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2787866Ssheldonh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2887866Ssheldonh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2987866Ssheldonh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3087866Ssheldonh * SUCH DAMAGE. 3187866Ssheldonh * 3295267Ssheldonh * $Id: ctx.c,v 1.24 2002/04/13 14:35:28 bp Exp $ 33113396Stjr * $FreeBSD: stable/11/contrib/smbfs/lib/smb/ctx.c 335774 2018-06-28 20:33:12Z brooks $ 3487866Ssheldonh */ 3587866Ssheldonh#include <sys/param.h> 3687866Ssheldonh#include <sys/sysctl.h> 3787866Ssheldonh#include <sys/ioctl.h> 3887866Ssheldonh#include <sys/time.h> 3987866Ssheldonh#include <sys/mount.h> 4087866Ssheldonh#include <fcntl.h> 4187866Ssheldonh#include <ctype.h> 4287866Ssheldonh#include <errno.h> 4387866Ssheldonh#include <stdio.h> 4487866Ssheldonh#include <string.h> 4587866Ssheldonh#include <stdlib.h> 4687866Ssheldonh#include <pwd.h> 4787866Ssheldonh#include <grp.h> 4887866Ssheldonh#include <unistd.h> 4987866Ssheldonh#include <sys/iconv.h> 5087866Ssheldonh 5187866Ssheldonh#define NB_NEEDRESOLVER 5287866Ssheldonh 5387866Ssheldonh#include <netsmb/smb_lib.h> 5487866Ssheldonh#include <netsmb/netbios.h> 5587866Ssheldonh#include <netsmb/nb_lib.h> 5687866Ssheldonh#include <netsmb/smb_conn.h> 5787866Ssheldonh#include <cflib.h> 5887866Ssheldonh 5987866Ssheldonh/* 6087866Ssheldonh * Prescan command line for [-U user] argument 6187866Ssheldonh * and fill context with defaults 6287866Ssheldonh */ 6387866Ssheldonhint 6487866Ssheldonhsmb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[], 6587866Ssheldonh int minlevel, int maxlevel, int sharetype) 6687866Ssheldonh{ 6787866Ssheldonh int opt, error = 0; 6895267Ssheldonh uid_t euid; 6987866Ssheldonh const char *arg, *cp; 7095267Ssheldonh struct passwd *pwd; 7187866Ssheldonh 7287866Ssheldonh bzero(ctx,sizeof(*ctx)); 7387866Ssheldonh error = nb_ctx_create(&ctx->ct_nb); 7487866Ssheldonh if (error) 7587866Ssheldonh return error; 7687866Ssheldonh ctx->ct_fd = -1; 7787866Ssheldonh ctx->ct_parsedlevel = SMBL_NONE; 7887866Ssheldonh ctx->ct_minlevel = minlevel; 7987866Ssheldonh ctx->ct_maxlevel = maxlevel; 80150802Sbp ctx->ct_smbtcpport = SMB_TCP_PORT; 8187866Ssheldonh 8287866Ssheldonh ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE; 8387866Ssheldonh ctx->ct_ssn.ioc_timeout = 15; 8487866Ssheldonh ctx->ct_ssn.ioc_retrycount = 4; 8587866Ssheldonh ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER; 8687866Ssheldonh ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP; 8787866Ssheldonh ctx->ct_ssn.ioc_mode = SMBM_EXEC; 8887866Ssheldonh ctx->ct_ssn.ioc_rights = SMBM_DEFAULT; 8987866Ssheldonh 9087866Ssheldonh ctx->ct_sh.ioc_opt = SMBVOPT_CREATE; 9187866Ssheldonh ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 9287866Ssheldonh ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 9387866Ssheldonh ctx->ct_sh.ioc_mode = SMBM_EXEC; 9487866Ssheldonh ctx->ct_sh.ioc_rights = SMBM_DEFAULT; 9587866Ssheldonh ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 9687866Ssheldonh ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 9787866Ssheldonh 9887866Ssheldonh nb_ctx_setscope(ctx->ct_nb, ""); 9995267Ssheldonh euid = geteuid(); 10095267Ssheldonh if ((pwd = getpwuid(euid)) != NULL) { 10195267Ssheldonh smb_ctx_setuser(ctx, pwd->pw_name); 10295267Ssheldonh endpwent(); 10395267Ssheldonh } else if (euid == 0) 10495267Ssheldonh smb_ctx_setuser(ctx, "root"); 10595267Ssheldonh else 10695267Ssheldonh return 0; 10787866Ssheldonh if (argv == NULL) 10887866Ssheldonh return 0; 10987866Ssheldonh for (opt = 1; opt < argc; opt++) { 11087866Ssheldonh cp = argv[opt]; 11187866Ssheldonh if (strncmp(cp, "//", 2) != 0) 11287866Ssheldonh continue; 11387866Ssheldonh error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp); 11487866Ssheldonh if (error) 11587866Ssheldonh return error; 11687866Ssheldonh ctx->ct_uncnext = cp; 11787866Ssheldonh break; 11887866Ssheldonh } 11987866Ssheldonh while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) { 12087866Ssheldonh arg = cf_optarg; 12187866Ssheldonh switch (opt) { 12287866Ssheldonh case 'E': 12387866Ssheldonh error = smb_ctx_setcharset(ctx, arg); 12487866Ssheldonh if (error) 12587866Ssheldonh return error; 12687866Ssheldonh break; 12787866Ssheldonh case 'L': 128148815Simura error = nls_setlocale(arg); 12987866Ssheldonh if (error) 13087866Ssheldonh break; 13187866Ssheldonh break; 13287866Ssheldonh case 'U': 13387866Ssheldonh error = smb_ctx_setuser(ctx, arg); 13487866Ssheldonh break; 13587866Ssheldonh } 13687866Ssheldonh } 13787866Ssheldonh cf_optind = cf_optreset = 1; 13887866Ssheldonh return error; 13987866Ssheldonh} 14087866Ssheldonh 14187866Ssheldonhvoid 14287866Ssheldonhsmb_ctx_done(struct smb_ctx *ctx) 14387866Ssheldonh{ 14487866Ssheldonh if (ctx->ct_ssn.ioc_server) 14587866Ssheldonh nb_snbfree(ctx->ct_ssn.ioc_server); 14687866Ssheldonh if (ctx->ct_ssn.ioc_local) 14787866Ssheldonh nb_snbfree(ctx->ct_ssn.ioc_local); 14887866Ssheldonh if (ctx->ct_srvaddr) 14987866Ssheldonh free(ctx->ct_srvaddr); 15087866Ssheldonh if (ctx->ct_nb) 15187866Ssheldonh nb_ctx_done(ctx->ct_nb); 15287866Ssheldonh} 15387866Ssheldonh 15487866Ssheldonhstatic int 15587866Ssheldonhgetsubstring(const char *p, u_char sep, char *dest, int maxlen, const char **next) 15687866Ssheldonh{ 15787866Ssheldonh int len; 15887866Ssheldonh 15987866Ssheldonh maxlen--; 16087866Ssheldonh for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 16187866Ssheldonh if (*p == 0) 16287866Ssheldonh return EINVAL; 16387866Ssheldonh *dest = *p; 16487866Ssheldonh } 16587866Ssheldonh *dest = 0; 16687866Ssheldonh *next = *p ? p + 1 : p; 16787866Ssheldonh return 0; 16887866Ssheldonh} 16987866Ssheldonh 17087866Ssheldonh/* 171150802Sbp * Here we expect something like "[proto:]//[user@]host[:psmb[:pnb]][/share][/path]" 17287866Ssheldonh */ 17387866Ssheldonhint 17487866Ssheldonhsmb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, 17587866Ssheldonh const char **next) 17687866Ssheldonh{ 17787866Ssheldonh const char *p = unc; 178150802Sbp char *p1, *psmb, *pnb; 17987866Ssheldonh char tmp[1024]; 18087866Ssheldonh int error ; 18187866Ssheldonh 18287866Ssheldonh ctx->ct_parsedlevel = SMBL_NONE; 18387866Ssheldonh if (*p++ != '/' || *p++ != '/') { 18487866Ssheldonh smb_error("UNC should start with '//'", 0); 18587866Ssheldonh return EINVAL; 18687866Ssheldonh } 18787866Ssheldonh p1 = tmp; 18887866Ssheldonh error = getsubstring(p, '@', p1, sizeof(tmp), &p); 18987866Ssheldonh if (!error) { 19087866Ssheldonh if (ctx->ct_maxlevel < SMBL_VC) { 19187866Ssheldonh smb_error("no user name required", 0); 19287866Ssheldonh return EINVAL; 19387866Ssheldonh } 19487866Ssheldonh error = smb_ctx_setuser(ctx, tmp); 19587866Ssheldonh if (error) 19687866Ssheldonh return error; 19787866Ssheldonh ctx->ct_parsedlevel = SMBL_VC; 19887866Ssheldonh } 19987866Ssheldonh error = getsubstring(p, '/', p1, sizeof(tmp), &p); 20087866Ssheldonh if (error) { 20187866Ssheldonh error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 20287866Ssheldonh if (error) { 20387866Ssheldonh smb_error("no server name found", 0); 20487866Ssheldonh return error; 20587866Ssheldonh } 20687866Ssheldonh } 20787866Ssheldonh if (*p1 == 0) { 20887866Ssheldonh smb_error("empty server name", 0); 20987866Ssheldonh return EINVAL; 21087866Ssheldonh } 211150802Sbp /* 212150802Sbp * Check for port number specification. 213150802Sbp */ 214150802Sbp psmb = strchr(tmp, ':'); 215150802Sbp if (psmb) { 216150802Sbp *psmb++ = '\0'; 217150802Sbp pnb = strchr(psmb, ':'); 218150802Sbp if (pnb) { 219150802Sbp *pnb++ = '\0'; 220150802Sbp error = smb_ctx_setnbport(ctx, atoi(pnb)); 221150802Sbp if (error) { 222150802Sbp smb_error("Invalid NetBIOS port number", 0); 223150802Sbp return error; 224150802Sbp } 225150802Sbp } 226150802Sbp error = smb_ctx_setsmbport(ctx, atoi(psmb)); 227150802Sbp if (error) { 228150802Sbp smb_error("Invalid SMB port number", 0); 229150802Sbp return error; 230150802Sbp } 231150802Sbp } 23287866Ssheldonh error = smb_ctx_setserver(ctx, tmp); 23387866Ssheldonh if (error) 23487866Ssheldonh return error; 23587866Ssheldonh if (sharetype == SMB_ST_NONE) { 23687866Ssheldonh *next = p; 23787866Ssheldonh return 0; 23887866Ssheldonh } 23987866Ssheldonh if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 24087866Ssheldonh smb_error("no share name required", 0); 24187866Ssheldonh return EINVAL; 24287866Ssheldonh } 24387866Ssheldonh error = getsubstring(p, '/', p1, sizeof(tmp), &p); 24487866Ssheldonh if (error) { 24587866Ssheldonh error = getsubstring(p, '\0', p1, sizeof(tmp), &p); 24687866Ssheldonh if (error) { 24787866Ssheldonh smb_error("unexpected end of line", 0); 24887866Ssheldonh return error; 24987866Ssheldonh } 25087866Ssheldonh } 25187866Ssheldonh if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) { 25287866Ssheldonh smb_error("empty share name", 0); 25387866Ssheldonh return EINVAL; 25487866Ssheldonh } 25587866Ssheldonh *next = p; 25687866Ssheldonh if (*p1 == 0) 25787866Ssheldonh return 0; 25887866Ssheldonh error = smb_ctx_setshare(ctx, p1, sharetype); 25987866Ssheldonh return error; 26087866Ssheldonh} 26187866Ssheldonh 26287866Ssheldonhint 26387866Ssheldonhsmb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 26487866Ssheldonh{ 26587866Ssheldonh char *cp, *servercs, *localcs; 26687866Ssheldonh int cslen = sizeof(ctx->ct_ssn.ioc_localcs); 26787866Ssheldonh int scslen, lcslen, error; 26887866Ssheldonh 26987866Ssheldonh cp = strchr(arg, ':'); 27087866Ssheldonh lcslen = cp ? (cp - arg) : 0; 27187866Ssheldonh if (lcslen == 0 || lcslen >= cslen) { 27287866Ssheldonh smb_error("invalid local charset specification (%s)", 0, arg); 27387866Ssheldonh return EINVAL; 27487866Ssheldonh } 27587866Ssheldonh scslen = (size_t)strlen(++cp); 27687866Ssheldonh if (scslen == 0 || scslen >= cslen) { 27787866Ssheldonh smb_error("invalid server charset specification (%s)", 0, arg); 27887866Ssheldonh return EINVAL; 27987866Ssheldonh } 28087866Ssheldonh localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 28187866Ssheldonh localcs[lcslen] = 0; 28287866Ssheldonh servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 28387866Ssheldonh error = nls_setrecode(localcs, servercs); 28487866Ssheldonh if (error == 0) 28587866Ssheldonh return 0; 28687866Ssheldonh smb_error("can't initialize iconv support (%s:%s)", 28787866Ssheldonh error, localcs, servercs); 28887866Ssheldonh localcs[0] = 0; 28987866Ssheldonh servercs[0] = 0; 29087866Ssheldonh return error; 29187866Ssheldonh} 29287866Ssheldonh 29387866Ssheldonhint 29487866Ssheldonhsmb_ctx_setserver(struct smb_ctx *ctx, const char *name) 29587866Ssheldonh{ 296118079Stjr if (strlen(name) > SMB_MAXSRVNAMELEN) { 29787866Ssheldonh smb_error("server name '%s' too long", 0, name); 29887866Ssheldonh return ENAMETOOLONG; 29987866Ssheldonh } 30087866Ssheldonh nls_str_upper(ctx->ct_ssn.ioc_srvname, name); 30187866Ssheldonh return 0; 30287866Ssheldonh} 30387866Ssheldonh 30487866Ssheldonhint 305150802Sbpsmb_ctx_setnbport(struct smb_ctx *ctx, int port) 306150802Sbp{ 307150802Sbp if (port < 1 || port > 0xffff) 308150802Sbp return EINVAL; 309150802Sbp ctx->ct_nb->nb_nmbtcpport = port; 310150802Sbp return 0; 311150802Sbp} 312150802Sbp 313150802Sbpint 314150802Sbpsmb_ctx_setsmbport(struct smb_ctx *ctx, int port) 315150802Sbp{ 316150802Sbp if (port < 1 || port > 0xffff) 317150802Sbp return EINVAL; 318150802Sbp ctx->ct_smbtcpport = port; 319150802Sbp ctx->ct_nb->nb_smbtcpport = port; 320150802Sbp return 0; 321150802Sbp} 322150802Sbp 323150802Sbpint 32487866Ssheldonhsmb_ctx_setuser(struct smb_ctx *ctx, const char *name) 32587866Ssheldonh{ 326118079Stjr if (strlen(name) > SMB_MAXUSERNAMELEN) { 32787866Ssheldonh smb_error("user name '%s' too long", 0, name); 32887866Ssheldonh return ENAMETOOLONG; 32987866Ssheldonh } 33087866Ssheldonh nls_str_upper(ctx->ct_ssn.ioc_user, name); 33187866Ssheldonh return 0; 33287866Ssheldonh} 33387866Ssheldonh 33487866Ssheldonhint 33587866Ssheldonhsmb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name) 33687866Ssheldonh{ 337118079Stjr if (strlen(name) > SMB_MAXUSERNAMELEN) { 33887866Ssheldonh smb_error("workgroup name '%s' too long", 0, name); 33987866Ssheldonh return ENAMETOOLONG; 34087866Ssheldonh } 34187866Ssheldonh nls_str_upper(ctx->ct_ssn.ioc_workgroup, name); 34287866Ssheldonh return 0; 34387866Ssheldonh} 34487866Ssheldonh 34587866Ssheldonhint 34687866Ssheldonhsmb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd) 34787866Ssheldonh{ 34887866Ssheldonh if (passwd == NULL) 34987866Ssheldonh return EINVAL; 350118079Stjr if (strlen(passwd) > SMB_MAXPASSWORDLEN) { 35187866Ssheldonh smb_error("password too long", 0); 35287866Ssheldonh return ENAMETOOLONG; 35387866Ssheldonh } 35487866Ssheldonh if (strncmp(passwd, "$$1", 3) == 0) 35587866Ssheldonh smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); 35687866Ssheldonh else 35787866Ssheldonh strcpy(ctx->ct_ssn.ioc_password, passwd); 35887866Ssheldonh strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); 35987866Ssheldonh return 0; 36087866Ssheldonh} 36187866Ssheldonh 36287866Ssheldonhint 36387866Ssheldonhsmb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 36487866Ssheldonh{ 365118079Stjr if (strlen(share) > SMB_MAXSHARENAMELEN) { 36687866Ssheldonh smb_error("share name '%s' too long", 0, share); 36787866Ssheldonh return ENAMETOOLONG; 36887866Ssheldonh } 36987866Ssheldonh nls_str_upper(ctx->ct_sh.ioc_share, share); 37087866Ssheldonh if (share[0] != 0) 37187866Ssheldonh ctx->ct_parsedlevel = SMBL_SHARE; 37287866Ssheldonh ctx->ct_sh.ioc_stype = stype; 37387866Ssheldonh return 0; 37487866Ssheldonh} 37587866Ssheldonh 37687866Ssheldonhint 37787866Ssheldonhsmb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 37887866Ssheldonh{ 37987866Ssheldonh if (addr == NULL || addr[0] == 0) 38087866Ssheldonh return EINVAL; 38187866Ssheldonh if (ctx->ct_srvaddr) 38287866Ssheldonh free(ctx->ct_srvaddr); 38387866Ssheldonh if ((ctx->ct_srvaddr = strdup(addr)) == NULL) 38487866Ssheldonh return ENOMEM; 38587866Ssheldonh return 0; 38687866Ssheldonh} 38787866Ssheldonh 38887866Ssheldonhstatic int 38987866Ssheldonhsmb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 39087866Ssheldonh{ 39187866Ssheldonh struct group *gr; 39287866Ssheldonh struct passwd *pw; 39387866Ssheldonh char *cp; 39487866Ssheldonh 39587866Ssheldonh cp = strchr(pair, ':'); 39687866Ssheldonh if (cp) { 39787866Ssheldonh *cp++ = '\0'; 39887866Ssheldonh if (*cp) { 39987866Ssheldonh gr = getgrnam(cp); 40087866Ssheldonh if (gr) { 40187866Ssheldonh *gid = gr->gr_gid; 40287866Ssheldonh } else 40387866Ssheldonh smb_error("Invalid group name %s, ignored", 40487866Ssheldonh 0, cp); 40587866Ssheldonh } 40687866Ssheldonh } 40787866Ssheldonh if (*pair) { 40887866Ssheldonh pw = getpwnam(pair); 40987866Ssheldonh if (pw) { 41087866Ssheldonh *uid = pw->pw_uid; 41187866Ssheldonh } else 41287866Ssheldonh smb_error("Invalid user name %s, ignored", 0, pair); 41387866Ssheldonh } 41487866Ssheldonh endpwent(); 41587866Ssheldonh return 0; 41687866Ssheldonh} 41787866Ssheldonh 41887866Ssheldonhint 41987866Ssheldonhsmb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 42087866Ssheldonh{ 42187866Ssheldonh int error = 0; 42287866Ssheldonh char *p, *cp; 42387866Ssheldonh 42487866Ssheldonh switch(opt) { 42587866Ssheldonh case 'U': 42687866Ssheldonh break; 42787866Ssheldonh case 'I': 42887866Ssheldonh error = smb_ctx_setsrvaddr(ctx, arg); 42987866Ssheldonh break; 43087866Ssheldonh case 'M': 43187866Ssheldonh ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8); 43287866Ssheldonh if (*cp == '/') { 43387866Ssheldonh ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8); 43487866Ssheldonh ctx->ct_flags |= SMBCF_SRIGHTS; 43587866Ssheldonh } 43687866Ssheldonh break; 43787866Ssheldonh case 'N': 43887866Ssheldonh ctx->ct_flags |= SMBCF_NOPWD; 43987866Ssheldonh break; 44087866Ssheldonh case 'O': 44187866Ssheldonh p = strdup(arg); 44287866Ssheldonh cp = strchr(p, '/'); 44387866Ssheldonh if (cp) { 44487866Ssheldonh *cp++ = '\0'; 44587866Ssheldonh error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner, 44687866Ssheldonh &ctx->ct_sh.ioc_group); 44787866Ssheldonh } 44887866Ssheldonh if (*p && error == 0) { 449113396Stjr error = smb_parse_owner(p, &ctx->ct_ssn.ioc_owner, 45087866Ssheldonh &ctx->ct_ssn.ioc_group); 45187866Ssheldonh } 45287866Ssheldonh free(p); 45387866Ssheldonh break; 45487866Ssheldonh case 'P': 45587866Ssheldonh/* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT;*/ 45687866Ssheldonh break; 45787866Ssheldonh case 'R': 45887866Ssheldonh ctx->ct_ssn.ioc_retrycount = atoi(arg); 45987866Ssheldonh break; 46087866Ssheldonh case 'T': 46187866Ssheldonh ctx->ct_ssn.ioc_timeout = atoi(arg); 46287866Ssheldonh break; 46387866Ssheldonh case 'W': 46487866Ssheldonh error = smb_ctx_setworkgroup(ctx, arg); 46587866Ssheldonh break; 46687866Ssheldonh } 46787866Ssheldonh return error; 46887866Ssheldonh} 46987866Ssheldonh 47087866Ssheldonh#if 0 47187866Ssheldonhstatic void 47287866Ssheldonhsmb_hexdump(const u_char *buf, int len) { 47387866Ssheldonh int ofs = 0; 47487866Ssheldonh 47587866Ssheldonh while (len--) { 47687866Ssheldonh if (ofs % 16 == 0) 47787866Ssheldonh printf("\n%02X: ", ofs); 47887866Ssheldonh printf("%02x ", *buf++); 47987866Ssheldonh ofs++; 48087866Ssheldonh } 48187866Ssheldonh printf("\n"); 48287866Ssheldonh} 48387866Ssheldonh#endif 48487866Ssheldonh 48587866Ssheldonh 48687866Ssheldonhstatic int 48787866Ssheldonhsmb_addiconvtbl(const char *to, const char *from, const u_char *tbl) 48887866Ssheldonh{ 48987866Ssheldonh int error; 49087866Ssheldonh 49187866Ssheldonh error = kiconv_add_xlat_table(to, from, tbl); 49287866Ssheldonh if (error && error != EEXIST) { 49387866Ssheldonh smb_error("can not setup kernel iconv table (%s:%s)", error, 49487866Ssheldonh from, to); 49587866Ssheldonh return error; 49687866Ssheldonh } 49787866Ssheldonh return 0; 49887866Ssheldonh} 49987866Ssheldonh 50087866Ssheldonh/* 50187866Ssheldonh * Verify context before connect operation(s), 50287866Ssheldonh * lookup specified server and try to fill all forgotten fields. 50387866Ssheldonh */ 50487866Ssheldonhint 50587866Ssheldonhsmb_ctx_resolve(struct smb_ctx *ctx) 50687866Ssheldonh{ 50787866Ssheldonh struct smbioc_ossn *ssn = &ctx->ct_ssn; 50887866Ssheldonh struct smbioc_oshare *sh = &ctx->ct_sh; 50987866Ssheldonh struct nb_name nn; 51087866Ssheldonh struct sockaddr *sap; 51187866Ssheldonh struct sockaddr_nb *salocal, *saserver; 51287866Ssheldonh char *cp; 51387866Ssheldonh int error = 0; 51487866Ssheldonh 51587866Ssheldonh ctx->ct_flags &= ~SMBCF_RESOLVED; 51687866Ssheldonh if (ssn->ioc_srvname[0] == 0) { 51787866Ssheldonh smb_error("no server name specified", 0); 51887866Ssheldonh return EINVAL; 51987866Ssheldonh } 52087866Ssheldonh if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) { 52187866Ssheldonh smb_error("no share name specified for %s@%s", 52287866Ssheldonh 0, ssn->ioc_user, ssn->ioc_srvname); 52387866Ssheldonh return EINVAL; 52487866Ssheldonh } 52587866Ssheldonh error = nb_ctx_resolve(ctx->ct_nb); 52687866Ssheldonh if (error) 52787866Ssheldonh return error; 52887866Ssheldonh if (ssn->ioc_localcs[0] == 0) 529145872Stakawata strcpy(ssn->ioc_localcs, "ISO8859-1"); 53087866Ssheldonh error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 53187866Ssheldonh if (error) 53287866Ssheldonh return error; 53387866Ssheldonh error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 53487866Ssheldonh if (error) 53587866Ssheldonh return error; 53687866Ssheldonh if (ssn->ioc_servercs[0] != 0) { 537145872Stakawata error = kiconv_add_xlat16_cspairs 538148519Simura (ssn->ioc_servercs, ssn->ioc_localcs); 539145872Stakawata if (error) return error; 54087866Ssheldonh } 54187866Ssheldonh if (ctx->ct_srvaddr) { 542150802Sbp error = nb_resolvehost_in(ctx->ct_srvaddr, &sap, ctx->ct_smbtcpport); 54387866Ssheldonh } else { 54487866Ssheldonh error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap); 54587866Ssheldonh } 54687866Ssheldonh if (error) { 54787866Ssheldonh smb_error("can't get server address", error); 54887866Ssheldonh return error; 54987866Ssheldonh } 55087866Ssheldonh nn.nn_scope = ctx->ct_nb->nb_scope; 55187866Ssheldonh nn.nn_type = NBT_SERVER; 552335774Sbrooks if (strlen(ssn->ioc_srvname) > NB_NAMELEN) 553335774Sbrooks return NBERROR(NBERR_NAMETOOLONG); 554335774Sbrooks strlcpy(nn.nn_name, ssn->ioc_srvname, sizeof(nn.nn_name)); 55587866Ssheldonh error = nb_sockaddr(sap, &nn, &saserver); 55687866Ssheldonh nb_snbfree(sap); 55787866Ssheldonh if (error) { 55887866Ssheldonh smb_error("can't allocate server address", error); 55987866Ssheldonh return error; 56087866Ssheldonh } 56187866Ssheldonh ssn->ioc_server = (struct sockaddr*)saserver; 56287866Ssheldonh if (ctx->ct_locname[0] == 0) { 56387866Ssheldonh error = nb_getlocalname(ctx->ct_locname); 56487866Ssheldonh if (error) { 56587866Ssheldonh smb_error("can't get local name", error); 56687866Ssheldonh return error; 56787866Ssheldonh } 56887866Ssheldonh nls_str_upper(ctx->ct_locname, ctx->ct_locname); 56987866Ssheldonh } 570335774Sbrooks /* 571335774Sbrooks * Truncate the local host name to NB_NAMELEN-1 which gives a 572335774Sbrooks * suffix of 0 which is "workstation name". 573335774Sbrooks */ 574335774Sbrooks strlcpy(nn.nn_name, ctx->ct_locname, NB_NAMELEN); 57587866Ssheldonh nn.nn_type = NBT_WKSTA; 57687866Ssheldonh nn.nn_scope = ctx->ct_nb->nb_scope; 57787866Ssheldonh error = nb_sockaddr(NULL, &nn, &salocal); 57887866Ssheldonh if (error) { 57987866Ssheldonh nb_snbfree((struct sockaddr*)saserver); 58087866Ssheldonh smb_error("can't allocate local address", error); 58187866Ssheldonh return error; 58287866Ssheldonh } 58387866Ssheldonh ssn->ioc_local = (struct sockaddr*)salocal; 58487866Ssheldonh ssn->ioc_lolen = salocal->snb_len; 58587866Ssheldonh ssn->ioc_svlen = saserver->snb_len; 58687866Ssheldonh if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) { 58787866Ssheldonh cp = getpass("Password:"); 58887866Ssheldonh error = smb_ctx_setpassword(ctx, cp); 58987866Ssheldonh if (error) 59087866Ssheldonh return error; 59187866Ssheldonh } 59287866Ssheldonh ctx->ct_flags |= SMBCF_RESOLVED; 59387866Ssheldonh return 0; 59487866Ssheldonh} 59587866Ssheldonh 59687866Ssheldonhstatic int 59787866Ssheldonhsmb_ctx_gethandle(struct smb_ctx *ctx) 59887866Ssheldonh{ 59987866Ssheldonh int fd, i; 60087866Ssheldonh char buf[20]; 60187866Ssheldonh 60287866Ssheldonh fd = open("/dev/"NSMB_NAME, O_RDWR); 60387866Ssheldonh if (fd >= 0) { 60487866Ssheldonh ctx->ct_fd = fd; 60587866Ssheldonh return 0; 60687866Ssheldonh } 607250236Sdavide return ENOENT; 60887866Ssheldonh} 60987866Ssheldonh 61087866Ssheldonhint 61187866Ssheldonhsmb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) 61287866Ssheldonh{ 61387866Ssheldonh struct smbioc_lookup rq; 61487866Ssheldonh int error; 61587866Ssheldonh 61687866Ssheldonh if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 61787866Ssheldonh smb_error("smb_ctx_lookup() data is not resolved", 0); 61887866Ssheldonh return EINVAL; 61987866Ssheldonh } 62087866Ssheldonh if (ctx->ct_fd != -1) { 62187866Ssheldonh close(ctx->ct_fd); 62287866Ssheldonh ctx->ct_fd = -1; 62387866Ssheldonh } 62487866Ssheldonh error = smb_ctx_gethandle(ctx); 62587866Ssheldonh if (error) { 62688492Ssheldonh smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0); 62787866Ssheldonh return EINVAL; 62887866Ssheldonh } 62987866Ssheldonh bzero(&rq, sizeof(rq)); 63087866Ssheldonh bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn)); 63187866Ssheldonh bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare)); 63287866Ssheldonh rq.ioc_flags = flags; 63387866Ssheldonh rq.ioc_level = level; 63487866Ssheldonh if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) { 63587866Ssheldonh error = errno; 63687866Ssheldonh if (flags & SMBLK_CREATE) 63787866Ssheldonh smb_error("unable to open connection", error); 63887866Ssheldonh return error; 63987866Ssheldonh } 64087866Ssheldonh return 0; 64187866Ssheldonh} 64287866Ssheldonh 64387866Ssheldonhint 64487866Ssheldonhsmb_ctx_login(struct smb_ctx *ctx) 64587866Ssheldonh{ 64687866Ssheldonh struct smbioc_ossn *ssn = &ctx->ct_ssn; 64787866Ssheldonh struct smbioc_oshare *sh = &ctx->ct_sh; 64887866Ssheldonh int error; 64987866Ssheldonh 65087866Ssheldonh if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 65187866Ssheldonh smb_error("smb_ctx_resolve() should be called first", 0); 65287866Ssheldonh return EINVAL; 65387866Ssheldonh } 65487866Ssheldonh if (ctx->ct_fd != -1) { 65587866Ssheldonh close(ctx->ct_fd); 65687866Ssheldonh ctx->ct_fd = -1; 65787866Ssheldonh } 65887866Ssheldonh error = smb_ctx_gethandle(ctx); 65987866Ssheldonh if (error) { 66087866Ssheldonh smb_error("can't get handle to requester", 0); 66187866Ssheldonh return EINVAL; 66287866Ssheldonh } 66387866Ssheldonh if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) { 66487866Ssheldonh error = errno; 66587866Ssheldonh smb_error("can't open session to server %s", error, ssn->ioc_srvname); 66687866Ssheldonh return error; 66787866Ssheldonh } 66887866Ssheldonh if (sh->ioc_share[0] == 0) 66987866Ssheldonh return 0; 67087866Ssheldonh if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) { 67187866Ssheldonh error = errno; 67287866Ssheldonh smb_error("can't connect to share //%s/%s", error, 67387866Ssheldonh ssn->ioc_srvname, sh->ioc_share); 67487866Ssheldonh return error; 67587866Ssheldonh } 67687866Ssheldonh return 0; 67787866Ssheldonh} 67887866Ssheldonh 67987866Ssheldonhint 68087866Ssheldonhsmb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags) 68187866Ssheldonh{ 68287866Ssheldonh struct smbioc_flags fl; 68387866Ssheldonh 68487866Ssheldonh if (ctx->ct_fd == -1) 68587866Ssheldonh return EINVAL; 68687866Ssheldonh fl.ioc_level = level; 68787866Ssheldonh fl.ioc_mask = mask; 68887866Ssheldonh fl.ioc_flags = flags; 68987866Ssheldonh if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1) 69087866Ssheldonh return errno; 69187866Ssheldonh return 0; 69287866Ssheldonh} 69387866Ssheldonh 69487866Ssheldonh/* 69587866Ssheldonh * level values: 69687866Ssheldonh * 0 - default 69787866Ssheldonh * 1 - server 69887866Ssheldonh * 2 - server:user 69987866Ssheldonh * 3 - server:user:share 70087866Ssheldonh */ 70187866Ssheldonhstatic int 70287866Ssheldonhsmb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 70387866Ssheldonh{ 70487866Ssheldonh char *p; 70587866Ssheldonh int error; 70687866Ssheldonh 70788492Ssheldonh if (level >= 0) { 70887866Ssheldonh rc_getstringptr(smb_rc, sname, "charsets", &p); 70987866Ssheldonh if (p) { 71087866Ssheldonh error = smb_ctx_setcharset(ctx, p); 71187866Ssheldonh if (error) 71287866Ssheldonh smb_error("charset specification in the section '%s' ignored", error, sname); 71387866Ssheldonh } 71487866Ssheldonh } 71587866Ssheldonh if (level <= 1) { 71687866Ssheldonh rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout); 71787866Ssheldonh rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount); 71887866Ssheldonh } 71987866Ssheldonh if (level == 1) { 72087866Ssheldonh rc_getstringptr(smb_rc, sname, "addr", &p); 72187866Ssheldonh if (p) { 72287866Ssheldonh error = smb_ctx_setsrvaddr(ctx, p); 72387866Ssheldonh if (error) { 72487866Ssheldonh smb_error("invalid address specified in the section %s", 0, sname); 72587866Ssheldonh return error; 72687866Ssheldonh } 72787866Ssheldonh } 72887866Ssheldonh } 72987866Ssheldonh if (level >= 2) { 73087866Ssheldonh rc_getstringptr(smb_rc, sname, "password", &p); 73187866Ssheldonh if (p) 73287866Ssheldonh smb_ctx_setpassword(ctx, p); 73387866Ssheldonh } 73487866Ssheldonh rc_getstringptr(smb_rc, sname, "workgroup", &p); 73587866Ssheldonh if (p) 73687866Ssheldonh smb_ctx_setworkgroup(ctx, p); 73787866Ssheldonh return 0; 73887866Ssheldonh} 73987866Ssheldonh 74087866Ssheldonh/* 74187866Ssheldonh * read rc file as follows: 74287866Ssheldonh * 1. read [default] section 74387866Ssheldonh * 2. override with [server] section 74487866Ssheldonh * 3. override with [server:user:share] section 74587866Ssheldonh * Since abcence of rcfile is not fatal, silently ignore this fact. 74687866Ssheldonh * smb_rc file should be closed by caller. 74787866Ssheldonh */ 74887866Ssheldonhint 74987866Ssheldonhsmb_ctx_readrc(struct smb_ctx *ctx) 75087866Ssheldonh{ 75187866Ssheldonh char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + SMB_MAXSHARENAMELEN + 4]; 75287866Ssheldonh/* char *p;*/ 75387866Ssheldonh 75487866Ssheldonh if (smb_open_rcfile() != 0) 75587866Ssheldonh return 0; 75687866Ssheldonh 75787866Ssheldonh if (ctx->ct_ssn.ioc_user[0] == 0 || ctx->ct_ssn.ioc_srvname[0] == 0) 75887866Ssheldonh return 0; 75987866Ssheldonh 76087866Ssheldonh smb_ctx_readrcsection(ctx, "default", 0); 76187866Ssheldonh nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 76287866Ssheldonh smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1); 76387866Ssheldonh nb_ctx_readrcsection(smb_rc, ctx->ct_nb, ctx->ct_ssn.ioc_srvname, 1); 76487866Ssheldonh /* 76587866Ssheldonh * SERVER:USER parameters 76687866Ssheldonh */ 76787866Ssheldonh snprintf(sname, sizeof(sname), "%s:%s", ctx->ct_ssn.ioc_srvname, 76887866Ssheldonh ctx->ct_ssn.ioc_user); 76987866Ssheldonh smb_ctx_readrcsection(ctx, sname, 2); 77087866Ssheldonh 77187866Ssheldonh if (ctx->ct_sh.ioc_share[0] != 0) { 77287866Ssheldonh /* 77387866Ssheldonh * SERVER:USER:SHARE parameters 77487866Ssheldonh */ 77587866Ssheldonh snprintf(sname, sizeof(sname), "%s:%s:%s", ctx->ct_ssn.ioc_srvname, 77687866Ssheldonh ctx->ct_ssn.ioc_user, ctx->ct_sh.ioc_share); 77787866Ssheldonh smb_ctx_readrcsection(ctx, sname, 3); 77887866Ssheldonh } 77987866Ssheldonh return 0; 78087866Ssheldonh} 78187866Ssheldonh 782