14bff34e3Sthurlow /* 24bff34e3Sthurlow * Copyright (c) 2000, Boris Popov 34bff34e3Sthurlow * All rights reserved. 44bff34e3Sthurlow * 54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 64bff34e3Sthurlow * modification, are permitted provided that the following conditions 74bff34e3Sthurlow * are met: 84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 124bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 144bff34e3Sthurlow * must display the following acknowledgement: 154bff34e3Sthurlow * This product includes software developed by Boris Popov. 164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 174bff34e3Sthurlow * may be used to endorse or promote products derived from this software 184bff34e3Sthurlow * without specific prior written permission. 194bff34e3Sthurlow * 204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304bff34e3Sthurlow * SUCH DAMAGE. 314bff34e3Sthurlow * 324bff34e3Sthurlow * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $ 334bff34e3Sthurlow */ 344bff34e3Sthurlow 359c9af259SGordon Ross /* 36613a2f6bSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 379c9af259SGordon Ross * Use is subject to license terms. 389c9af259SGordon Ross */ 394bff34e3Sthurlow 404bff34e3Sthurlow #include <sys/param.h> 414bff34e3Sthurlow #include <sys/ioctl.h> 424bff34e3Sthurlow #include <sys/time.h> 434bff34e3Sthurlow #include <sys/mount.h> 444bff34e3Sthurlow #include <sys/types.h> 454bff34e3Sthurlow #include <sys/byteorder.h> 464bff34e3Sthurlow 474bff34e3Sthurlow #include <fcntl.h> 484bff34e3Sthurlow #include <ctype.h> 494bff34e3Sthurlow #include <errno.h> 504bff34e3Sthurlow #include <stdio.h> 514bff34e3Sthurlow #include <string.h> 524bff34e3Sthurlow #include <strings.h> 534bff34e3Sthurlow #include <stdlib.h> 544bff34e3Sthurlow #include <pwd.h> 554bff34e3Sthurlow #include <grp.h> 564bff34e3Sthurlow #include <unistd.h> 574bff34e3Sthurlow #include <libintl.h> 584bff34e3Sthurlow #include <assert.h> 594bff34e3Sthurlow #include <nss_dbdefs.h> 604bff34e3Sthurlow 61613a2f6bSGordon Ross #include <cflib.h> 624bff34e3Sthurlow #include <netsmb/smb_lib.h> 634bff34e3Sthurlow #include <netsmb/netbios.h> 644bff34e3Sthurlow #include <netsmb/nb_lib.h> 654bff34e3Sthurlow #include <netsmb/smb_dev.h> 664bff34e3Sthurlow 67613a2f6bSGordon Ross #include "charsets.h" 68613a2f6bSGordon Ross #include "spnego.h" 694bff34e3Sthurlow #include "derparse.h" 709c9af259SGordon Ross #include "private.h" 71613a2f6bSGordon Ross #include "ntlm.h" 724bff34e3Sthurlow 73613a2f6bSGordon Ross #ifndef FALSE 74613a2f6bSGordon Ross #define FALSE 0 75613a2f6bSGordon Ross #endif 76613a2f6bSGordon Ross #ifndef TRUE 77613a2f6bSGordon Ross #define TRUE 1 78613a2f6bSGordon Ross #endif 794bff34e3Sthurlow 804bff34e3Sthurlow 814bff34e3Sthurlow /* These two may be set by commands. */ 824bff34e3Sthurlow int smb_debug, smb_verbose; 834bff34e3Sthurlow 844bff34e3Sthurlow /* 85613a2f6bSGordon Ross * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt 86613a2f6bSGordon Ross */ 87613a2f6bSGordon Ross const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:"; 88613a2f6bSGordon Ross 89613a2f6bSGordon Ross /* 909c9af259SGordon Ross * Give the RPC library a callback hook that will be 919c9af259SGordon Ross * called whenever we destroy or reinit an smb_ctx_t. 929c9af259SGordon Ross * The name rpc_cleanup_smbctx() is legacy, and was 939c9af259SGordon Ross * originally a direct call into the RPC code. 944bff34e3Sthurlow */ 959c9af259SGordon Ross static smb_ctx_close_hook_t close_hook; 964bff34e3Sthurlow static void 974bff34e3Sthurlow rpc_cleanup_smbctx(struct smb_ctx *ctx) 984bff34e3Sthurlow { 999c9af259SGordon Ross if (close_hook) 1009c9af259SGordon Ross (*close_hook)(ctx); 1014bff34e3Sthurlow } 1029c9af259SGordon Ross void 1039c9af259SGordon Ross smb_ctx_set_close_hook(smb_ctx_close_hook_t hook) 1049c9af259SGordon Ross { 1059c9af259SGordon Ross close_hook = hook; 1069c9af259SGordon Ross } 1074bff34e3Sthurlow 1084bff34e3Sthurlow void 1094bff34e3Sthurlow dump_ctx_flags(int flags) 1104bff34e3Sthurlow { 1114bff34e3Sthurlow printf(" Flags: "); 1124bff34e3Sthurlow if (flags == 0) 1134bff34e3Sthurlow printf("0"); 1144bff34e3Sthurlow if (flags & SMBCF_NOPWD) 1154bff34e3Sthurlow printf("NOPWD "); 1164bff34e3Sthurlow if (flags & SMBCF_SRIGHTS) 1174bff34e3Sthurlow printf("SRIGHTS "); 1184bff34e3Sthurlow if (flags & SMBCF_LOCALE) 1194bff34e3Sthurlow printf("LOCALE "); 1204bff34e3Sthurlow if (flags & SMBCF_CMD_DOM) 1214bff34e3Sthurlow printf("CMD_DOM "); 1224bff34e3Sthurlow if (flags & SMBCF_CMD_USR) 1234bff34e3Sthurlow printf("CMD_USR "); 1244bff34e3Sthurlow if (flags & SMBCF_CMD_PW) 1254bff34e3Sthurlow printf("CMD_PW "); 1264bff34e3Sthurlow if (flags & SMBCF_RESOLVED) 1274bff34e3Sthurlow printf("RESOLVED "); 1284bff34e3Sthurlow if (flags & SMBCF_KCBAD) 1294bff34e3Sthurlow printf("KCBAD "); 1304bff34e3Sthurlow if (flags & SMBCF_KCFOUND) 1314bff34e3Sthurlow printf("KCFOUND "); 1324bff34e3Sthurlow if (flags & SMBCF_BROWSEOK) 1334bff34e3Sthurlow printf("BROWSEOK "); 1344bff34e3Sthurlow if (flags & SMBCF_AUTHREQ) 1354bff34e3Sthurlow printf("AUTHREQ "); 1364bff34e3Sthurlow if (flags & SMBCF_KCSAVE) 1374bff34e3Sthurlow printf("KCSAVE "); 1384bff34e3Sthurlow if (flags & SMBCF_XXX) 1394bff34e3Sthurlow printf("XXX "); 1404bff34e3Sthurlow if (flags & SMBCF_SSNACTIVE) 1414bff34e3Sthurlow printf("SSNACTIVE "); 1424bff34e3Sthurlow if (flags & SMBCF_KCDOMAIN) 1434bff34e3Sthurlow printf("KCDOMAIN "); 1444bff34e3Sthurlow printf("\n"); 1454bff34e3Sthurlow } 1464bff34e3Sthurlow 1474bff34e3Sthurlow void 148613a2f6bSGordon Ross dump_iod_ssn(smb_iod_ssn_t *is) 1494bff34e3Sthurlow { 150613a2f6bSGordon Ross static const char zeros[NTLM_HASH_SZ] = {0}; 151613a2f6bSGordon Ross struct smbioc_ossn *ssn = &is->iod_ossn; 1524bff34e3Sthurlow 153613a2f6bSGordon Ross printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname); 154613a2f6bSGordon Ross dump_sockaddr(&ssn->ssn_srvaddr.sa); 155613a2f6bSGordon Ross printf(" dom=\"%s\", user=\"%s\"\n", 156613a2f6bSGordon Ross ssn->ssn_domain, ssn->ssn_user); 157613a2f6bSGordon Ross printf(" ct_vopt=0x%x, ct_owner=%d\n", 158613a2f6bSGordon Ross ssn->ssn_vopt, ssn->ssn_owner); 159613a2f6bSGordon Ross printf(" ct_authflags=0x%x\n", is->iod_authflags); 160613a2f6bSGordon Ross 161613a2f6bSGordon Ross printf(" ct_nthash:"); 162613a2f6bSGordon Ross if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ)) 163613a2f6bSGordon Ross smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ); 164613a2f6bSGordon Ross else 165613a2f6bSGordon Ross printf(" {0}\n"); 166613a2f6bSGordon Ross 167613a2f6bSGordon Ross printf(" ct_lmhash:"); 168613a2f6bSGordon Ross if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ)) 169613a2f6bSGordon Ross smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ); 170613a2f6bSGordon Ross else 171613a2f6bSGordon Ross printf(" {0}\n"); 1724bff34e3Sthurlow } 1734bff34e3Sthurlow 1744bff34e3Sthurlow void 1754bff34e3Sthurlow dump_ctx(char *where, struct smb_ctx *ctx) 1764bff34e3Sthurlow { 1774bff34e3Sthurlow printf("context %s:\n", where); 1784bff34e3Sthurlow dump_ctx_flags(ctx->ct_flags); 1794bff34e3Sthurlow 180613a2f6bSGordon Ross if (ctx->ct_locname) 1814bff34e3Sthurlow printf(" localname=\"%s\"", ctx->ct_locname); 182613a2f6bSGordon Ross else 183613a2f6bSGordon Ross printf(" localname=NULL"); 1844bff34e3Sthurlow 1854bff34e3Sthurlow if (ctx->ct_fullserver) 1864bff34e3Sthurlow printf(" fullserver=\"%s\"", ctx->ct_fullserver); 1874bff34e3Sthurlow else 1884bff34e3Sthurlow printf(" fullserver=NULL"); 1894bff34e3Sthurlow 190613a2f6bSGordon Ross if (ctx->ct_srvaddr_s) 191613a2f6bSGordon Ross printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s); 1924bff34e3Sthurlow else 193613a2f6bSGordon Ross printf(" srvaddr_s=NULL\n"); 1944bff34e3Sthurlow 195613a2f6bSGordon Ross if (ctx->ct_addrinfo) 196613a2f6bSGordon Ross dump_addrinfo(ctx->ct_addrinfo); 197613a2f6bSGordon Ross else 198613a2f6bSGordon Ross printf(" ct_addrinfo = NULL\n"); 199613a2f6bSGordon Ross 200613a2f6bSGordon Ross dump_iod_ssn(&ctx->ct_iod_ssn); 201613a2f6bSGordon Ross 202613a2f6bSGordon Ross printf(" share_name=\"%s\", share_type=%d\n", 203613a2f6bSGordon Ross ctx->ct_origshare ? ctx->ct_origshare : "", 204613a2f6bSGordon Ross ctx->ct_shtype_req); 205613a2f6bSGordon Ross 206613a2f6bSGordon Ross /* dump_iod_work()? */ 207613a2f6bSGordon Ross } 208613a2f6bSGordon Ross 209613a2f6bSGordon Ross int 210613a2f6bSGordon Ross smb_ctx_alloc(struct smb_ctx **ctx_pp) 211613a2f6bSGordon Ross { 212613a2f6bSGordon Ross smb_ctx_t *ctx; 213613a2f6bSGordon Ross int err; 214613a2f6bSGordon Ross 215613a2f6bSGordon Ross ctx = malloc(sizeof (*ctx)); 216613a2f6bSGordon Ross if (ctx == NULL) 217613a2f6bSGordon Ross return (ENOMEM); 218613a2f6bSGordon Ross err = smb_ctx_init(ctx); 219613a2f6bSGordon Ross if (err != 0) { 220613a2f6bSGordon Ross free(ctx); 221613a2f6bSGordon Ross return (err); 222613a2f6bSGordon Ross } 223613a2f6bSGordon Ross *ctx_pp = ctx; 224613a2f6bSGordon Ross return (0); 2254bff34e3Sthurlow } 2264bff34e3Sthurlow 2274bff34e3Sthurlow /* 228613a2f6bSGordon Ross * Initialize an smb_ctx struct (defaults) 229613a2f6bSGordon Ross */ 230613a2f6bSGordon Ross int 231613a2f6bSGordon Ross smb_ctx_init(struct smb_ctx *ctx) 232613a2f6bSGordon Ross { 233613a2f6bSGordon Ross char pwbuf[NSS_BUFLEN_PASSWD]; 234613a2f6bSGordon Ross struct passwd pw; 235613a2f6bSGordon Ross int error = 0; 236613a2f6bSGordon Ross 237613a2f6bSGordon Ross bzero(ctx, sizeof (*ctx)); 238613a2f6bSGordon Ross 239613a2f6bSGordon Ross error = nb_ctx_create(&ctx->ct_nb); 240613a2f6bSGordon Ross if (error) 241613a2f6bSGordon Ross return (error); 242613a2f6bSGordon Ross 243613a2f6bSGordon Ross ctx->ct_dev_fd = -1; 2446b2bcd8eSGordon Ross ctx->ct_door_fd = -1; 245613a2f6bSGordon Ross ctx->ct_tran_fd = -1; 246613a2f6bSGordon Ross ctx->ct_parsedlevel = SMBL_NONE; 247613a2f6bSGordon Ross ctx->ct_minlevel = SMBL_NONE; 248613a2f6bSGordon Ross ctx->ct_maxlevel = SMBL_PATH; 249613a2f6bSGordon Ross 250613a2f6bSGordon Ross /* Fill in defaults */ 251613a2f6bSGordon Ross ctx->ct_vopt = SMBVOPT_EXT_SEC; 252613a2f6bSGordon Ross ctx->ct_owner = SMBM_ANY_OWNER; 253613a2f6bSGordon Ross ctx->ct_authflags = SMB_AT_DEFAULT; 254613a2f6bSGordon Ross ctx->ct_minauth = SMB_AT_DEFAULT; 255613a2f6bSGordon Ross 256*02d09e03SGordon Ross error = nb_ctx_setscope(ctx->ct_nb, ""); 257*02d09e03SGordon Ross if (error) 258*02d09e03SGordon Ross return (error); 259613a2f6bSGordon Ross 260613a2f6bSGordon Ross /* 261613a2f6bSGordon Ross * if the user name is not specified some other way, 262613a2f6bSGordon Ross * use the current user name (built-in default) 263613a2f6bSGordon Ross */ 264613a2f6bSGordon Ross if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) { 265*02d09e03SGordon Ross error = smb_ctx_setuser(ctx, pw.pw_name, 0); 266*02d09e03SGordon Ross if (error) 267*02d09e03SGordon Ross return (error); 268613a2f6bSGordon Ross ctx->ct_home = strdup(pw.pw_name); 269*02d09e03SGordon Ross if (ctx->ct_home == NULL) 270*02d09e03SGordon Ross return (ENOMEM); 271613a2f6bSGordon Ross } 272613a2f6bSGordon Ross 273613a2f6bSGordon Ross /* 274613a2f6bSGordon Ross * Set a built-in default domain (workgroup). 275613a2f6bSGordon Ross * Using the Windows/NT default for now. 276613a2f6bSGordon Ross */ 277*02d09e03SGordon Ross error = smb_ctx_setdomain(ctx, "WORKGROUP", 0); 278*02d09e03SGordon Ross if (error) 279*02d09e03SGordon Ross return (error); 280613a2f6bSGordon Ross 281613a2f6bSGordon Ross return (error); 282613a2f6bSGordon Ross } 283613a2f6bSGordon Ross 284613a2f6bSGordon Ross /* 285613a2f6bSGordon Ross * "Scan" the command line args to find the server name, 286613a2f6bSGordon Ross * user name, and share name, as needed. We need these 287613a2f6bSGordon Ross * before reading the RC files and/or sharectl values. 2884bff34e3Sthurlow * 2894bff34e3Sthurlow * The sequence for getting all the members filled in 2904bff34e3Sthurlow * has some tricky aspects. Here's how it works: 2914bff34e3Sthurlow * 2924bff34e3Sthurlow * The search order for options is as follows: 2934bff34e3Sthurlow * command line options 2944bff34e3Sthurlow * values parsed from UNC path (cmd) 2954bff34e3Sthurlow * values from RC file (per-user) 2964bff34e3Sthurlow * values from SMF (system-wide) 2974bff34e3Sthurlow * built-in defaults 2984bff34e3Sthurlow * 2994bff34e3Sthurlow * Normally, one would simply get all the values starting with 3004bff34e3Sthurlow * the bottom of the above list and working to the top, and 3014bff34e3Sthurlow * overwriting values as you go. But we need an exception. 3024bff34e3Sthurlow * 3034bff34e3Sthurlow * In this function, we parse the UNC path and command line options, 3044bff34e3Sthurlow * because we need (at least) the server name when we're getting the 3054bff34e3Sthurlow * SMF and RC file values. However, values we get from the command 3064bff34e3Sthurlow * should not be overwritten by SMF or RC file parsing, so we mark 3074bff34e3Sthurlow * values from the command as "from CMD" and the RC file parser 3084bff34e3Sthurlow * leaves in place any values so marked. See: SMBCF_CMD_* 3094bff34e3Sthurlow * 3104bff34e3Sthurlow * The semantics of these flags are: "This value came from the 3114bff34e3Sthurlow * current command instance, not from sources that may apply to 3124bff34e3Sthurlow * multiple commands." (Different from the old "FROMUSR" flag.) 3134bff34e3Sthurlow * 3144bff34e3Sthurlow * Note that smb_ctx_opt() is called later to handle the 3154bff34e3Sthurlow * remaining options, which should be ignored here. 3164bff34e3Sthurlow * The (magic) leading ":" in cf_getopt() makes it 3174bff34e3Sthurlow * ignore options not in the options string. 3184bff34e3Sthurlow */ 3194bff34e3Sthurlow int 320613a2f6bSGordon Ross smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv, 3214bff34e3Sthurlow int minlevel, int maxlevel, int sharetype) 3224bff34e3Sthurlow { 323613a2f6bSGordon Ross int ind, opt, error = 0; 3244bff34e3Sthurlow int aflg = 0, uflg = 0; 325613a2f6bSGordon Ross const char *arg; 3264bff34e3Sthurlow 3274bff34e3Sthurlow /* 3284bff34e3Sthurlow * Parse options, if any. Values from here too 3294bff34e3Sthurlow * are marked as "from CMD". 3304bff34e3Sthurlow */ 331613a2f6bSGordon Ross if (argv == NULL) 332613a2f6bSGordon Ross return (0); 333613a2f6bSGordon Ross 334613a2f6bSGordon Ross ctx->ct_minlevel = minlevel; 335613a2f6bSGordon Ross ctx->ct_maxlevel = maxlevel; 336613a2f6bSGordon Ross ctx->ct_shtype_req = sharetype; 337613a2f6bSGordon Ross 338613a2f6bSGordon Ross cf_opt_lock(); 339613a2f6bSGordon Ross /* Careful: no return/goto before cf_opt_unlock! */ 340613a2f6bSGordon Ross while (error == 0) { 341613a2f6bSGordon Ross opt = cf_getopt(argc, argv, STDPARAM_OPT); 342613a2f6bSGordon Ross if (opt == -1) 343613a2f6bSGordon Ross break; 3444bff34e3Sthurlow arg = cf_optarg; 345613a2f6bSGordon Ross /* NB: handle most in smb_ctx_opt */ 3464bff34e3Sthurlow switch (opt) { 3474bff34e3Sthurlow case 'A': 3484bff34e3Sthurlow aflg = 1; 3494bff34e3Sthurlow error = smb_ctx_setuser(ctx, "", TRUE); 3504bff34e3Sthurlow ctx->ct_flags |= SMBCF_NOPWD; 3514bff34e3Sthurlow break; 3524bff34e3Sthurlow case 'U': 3534bff34e3Sthurlow uflg = 1; 3544bff34e3Sthurlow error = smb_ctx_setuser(ctx, arg, TRUE); 3554bff34e3Sthurlow break; 356613a2f6bSGordon Ross default: 357613a2f6bSGordon Ross DPRINT("skip opt=%c", opt); 358613a2f6bSGordon Ross break; 3594bff34e3Sthurlow } 3604bff34e3Sthurlow } 361613a2f6bSGordon Ross ind = cf_optind; 362613a2f6bSGordon Ross arg = argv[ind]; 363613a2f6bSGordon Ross cf_optind = cf_optreset = 1; 364613a2f6bSGordon Ross cf_opt_unlock(); 365613a2f6bSGordon Ross 366613a2f6bSGordon Ross if (error) 367613a2f6bSGordon Ross return (error); 368613a2f6bSGordon Ross 3694bff34e3Sthurlow if (aflg && uflg) { 3704bff34e3Sthurlow printf(gettext("-A and -U flags are exclusive.\n")); 371613a2f6bSGordon Ross return (EINVAL); 3724bff34e3Sthurlow } 3734bff34e3Sthurlow 374613a2f6bSGordon Ross /* 375613a2f6bSGordon Ross * Parse the UNC path. Values from here are 376613a2f6bSGordon Ross * marked as "from CMD". 377613a2f6bSGordon Ross */ 378613a2f6bSGordon Ross for (; ind < argc; ind++) { 379613a2f6bSGordon Ross arg = argv[ind]; 380613a2f6bSGordon Ross if (strncmp(arg, "//", 2) != 0) 381613a2f6bSGordon Ross continue; 382613a2f6bSGordon Ross error = smb_ctx_parseunc(ctx, arg, 383613a2f6bSGordon Ross minlevel, maxlevel, sharetype, &arg); 384613a2f6bSGordon Ross if (error) 385613a2f6bSGordon Ross return (error); 386613a2f6bSGordon Ross break; 387613a2f6bSGordon Ross } 3884bff34e3Sthurlow 3894bff34e3Sthurlow return (error); 3904bff34e3Sthurlow } 3914bff34e3Sthurlow 3924bff34e3Sthurlow void 393613a2f6bSGordon Ross smb_ctx_free(smb_ctx_t *ctx) 394613a2f6bSGordon Ross { 395613a2f6bSGordon Ross smb_ctx_done(ctx); 396613a2f6bSGordon Ross free(ctx); 397613a2f6bSGordon Ross } 398613a2f6bSGordon Ross 399613a2f6bSGordon Ross void 4004bff34e3Sthurlow smb_ctx_done(struct smb_ctx *ctx) 4014bff34e3Sthurlow { 4024bff34e3Sthurlow 4034bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 4044bff34e3Sthurlow 405613a2f6bSGordon Ross if (ctx->ct_dev_fd != -1) { 406613a2f6bSGordon Ross close(ctx->ct_dev_fd); 407613a2f6bSGordon Ross ctx->ct_dev_fd = -1; 4084bff34e3Sthurlow } 4096b2bcd8eSGordon Ross if (ctx->ct_door_fd != -1) { 4106b2bcd8eSGordon Ross close(ctx->ct_door_fd); 4116b2bcd8eSGordon Ross ctx->ct_door_fd = -1; 4126b2bcd8eSGordon Ross } 413613a2f6bSGordon Ross if (ctx->ct_tran_fd != -1) { 414613a2f6bSGordon Ross close(ctx->ct_tran_fd); 415613a2f6bSGordon Ross ctx->ct_tran_fd = -1; 416613a2f6bSGordon Ross } 417613a2f6bSGordon Ross if (ctx->ct_srvaddr_s) { 418613a2f6bSGordon Ross free(ctx->ct_srvaddr_s); 419613a2f6bSGordon Ross ctx->ct_srvaddr_s = NULL; 420613a2f6bSGordon Ross } 421613a2f6bSGordon Ross if (ctx->ct_nb) { 4224bff34e3Sthurlow nb_ctx_done(ctx->ct_nb); 423613a2f6bSGordon Ross ctx->ct_nb = NULL; 424613a2f6bSGordon Ross } 425613a2f6bSGordon Ross if (ctx->ct_locname) { 426613a2f6bSGordon Ross free(ctx->ct_locname); 427613a2f6bSGordon Ross ctx->ct_locname = NULL; 428613a2f6bSGordon Ross } 429613a2f6bSGordon Ross if (ctx->ct_origshare) { 4304bff34e3Sthurlow free(ctx->ct_origshare); 431613a2f6bSGordon Ross ctx->ct_origshare = NULL; 432613a2f6bSGordon Ross } 433613a2f6bSGordon Ross if (ctx->ct_fullserver) { 4344bff34e3Sthurlow free(ctx->ct_fullserver); 435613a2f6bSGordon Ross ctx->ct_fullserver = NULL; 436613a2f6bSGordon Ross } 437613a2f6bSGordon Ross if (ctx->ct_addrinfo) { 438613a2f6bSGordon Ross freeaddrinfo(ctx->ct_addrinfo); 439613a2f6bSGordon Ross ctx->ct_addrinfo = NULL; 440613a2f6bSGordon Ross } 441613a2f6bSGordon Ross if (ctx->ct_home) 442613a2f6bSGordon Ross free(ctx->ct_home); 443613a2f6bSGordon Ross if (ctx->ct_srv_OS) { 444613a2f6bSGordon Ross free(ctx->ct_srv_OS); 445613a2f6bSGordon Ross ctx->ct_srv_OS = NULL; 446613a2f6bSGordon Ross } 447613a2f6bSGordon Ross if (ctx->ct_srv_LM) { 448613a2f6bSGordon Ross free(ctx->ct_srv_LM); 449613a2f6bSGordon Ross ctx->ct_srv_LM = NULL; 450613a2f6bSGordon Ross } 451613a2f6bSGordon Ross if (ctx->ct_mackey) { 452613a2f6bSGordon Ross free(ctx->ct_mackey); 453613a2f6bSGordon Ross ctx->ct_mackey = NULL; 454613a2f6bSGordon Ross } 4554bff34e3Sthurlow } 4564bff34e3Sthurlow 4574bff34e3Sthurlow static int 4584bff34e3Sthurlow getsubstring(const char *p, uchar_t sep, char *dest, int maxlen, 4594bff34e3Sthurlow const char **next) 4604bff34e3Sthurlow { 4614bff34e3Sthurlow int len; 4624bff34e3Sthurlow 4634bff34e3Sthurlow maxlen--; 4644bff34e3Sthurlow for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 4654bff34e3Sthurlow if (*p == 0) 4664bff34e3Sthurlow return (EINVAL); 4674bff34e3Sthurlow *dest = *p; 4684bff34e3Sthurlow } 4694bff34e3Sthurlow *dest = 0; 4704bff34e3Sthurlow *next = *p ? p + 1 : p; 4714bff34e3Sthurlow return (0); 4724bff34e3Sthurlow } 4734bff34e3Sthurlow 4744bff34e3Sthurlow /* 4754bff34e3Sthurlow * Parse the UNC path. Here we expect something like 4764bff34e3Sthurlow * "//[workgroup;][user[:password]@]host[/share[/path]]" 4774bff34e3Sthurlow * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 4784bff34e3Sthurlow * Values found here are marked as "from CMD". 4794bff34e3Sthurlow */ 4804bff34e3Sthurlow int 481613a2f6bSGordon Ross smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, 482613a2f6bSGordon Ross int minlevel, int maxlevel, int sharetype, 4834bff34e3Sthurlow const char **next) 4844bff34e3Sthurlow { 4854bff34e3Sthurlow const char *p = unc; 486613a2f6bSGordon Ross char *p1, *colon; 4874bff34e3Sthurlow char tmp[1024]; 4884bff34e3Sthurlow char tmp2[1024]; 4894bff34e3Sthurlow int error; 4904bff34e3Sthurlow 491613a2f6bSGordon Ross /* 492613a2f6bSGordon Ross * This may be called outside of _scan_argv, 493613a2f6bSGordon Ross * so make sure these get initialized. 494613a2f6bSGordon Ross */ 495613a2f6bSGordon Ross ctx->ct_minlevel = minlevel; 496613a2f6bSGordon Ross ctx->ct_maxlevel = maxlevel; 497613a2f6bSGordon Ross ctx->ct_shtype_req = sharetype; 498613a2f6bSGordon Ross 4994bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_NONE; 5004bff34e3Sthurlow if (*p++ != '/' || *p++ != '/') { 5014bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5024bff34e3Sthurlow "UNC should start with '//'"), 0); 503613a2f6bSGordon Ross error = EINVAL; 504613a2f6bSGordon Ross goto out; 5054bff34e3Sthurlow } 5064bff34e3Sthurlow p1 = tmp; 5074bff34e3Sthurlow error = getsubstring(p, ';', p1, sizeof (tmp), &p); 5084bff34e3Sthurlow if (!error) { 5094bff34e3Sthurlow if (*p1 == 0) { 5104bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5114bff34e3Sthurlow "empty workgroup name"), 0); 512613a2f6bSGordon Ross error = EINVAL; 513613a2f6bSGordon Ross goto out; 5144bff34e3Sthurlow } 5154bff34e3Sthurlow nls_str_upper(tmp, tmp); 516613a2f6bSGordon Ross error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE); 5174bff34e3Sthurlow if (error) 518613a2f6bSGordon Ross goto out; 5194bff34e3Sthurlow } 5204bff34e3Sthurlow colon = (char *)p; 5214bff34e3Sthurlow error = getsubstring(p, '@', p1, sizeof (tmp), &p); 5224bff34e3Sthurlow if (!error) { 5234bff34e3Sthurlow if (ctx->ct_maxlevel < SMBL_VC) { 5244bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5254bff34e3Sthurlow "no user name required"), 0); 526613a2f6bSGordon Ross error = EINVAL; 527613a2f6bSGordon Ross goto out; 5284bff34e3Sthurlow } 5294bff34e3Sthurlow p1 = strchr(tmp, ':'); 5304bff34e3Sthurlow if (p1) { 5314bff34e3Sthurlow colon += p1 - tmp; 5324bff34e3Sthurlow *p1++ = (char)0; 5334bff34e3Sthurlow error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE); 5344bff34e3Sthurlow if (error) 535613a2f6bSGordon Ross goto out; 5364bff34e3Sthurlow if (p - colon > 2) 5374bff34e3Sthurlow memset(colon+1, '*', p - colon - 2); 5384bff34e3Sthurlow } 5394bff34e3Sthurlow p1 = tmp; 5404bff34e3Sthurlow if (*p1 == 0) { 5414bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5424bff34e3Sthurlow "empty user name"), 0); 543613a2f6bSGordon Ross error = EINVAL; 544613a2f6bSGordon Ross goto out; 5454bff34e3Sthurlow } 5464bff34e3Sthurlow error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE); 5474bff34e3Sthurlow if (error) 548613a2f6bSGordon Ross goto out; 5494bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_VC; 5504bff34e3Sthurlow } 5514bff34e3Sthurlow error = getsubstring(p, '/', p1, sizeof (tmp), &p); 5524bff34e3Sthurlow if (error) { 5534bff34e3Sthurlow error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 5544bff34e3Sthurlow if (error) { 5554bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5564bff34e3Sthurlow "no server name found"), 0); 557613a2f6bSGordon Ross goto out; 5584bff34e3Sthurlow } 5594bff34e3Sthurlow } 5604bff34e3Sthurlow if (*p1 == 0) { 5614bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0); 562613a2f6bSGordon Ross error = EINVAL; 563613a2f6bSGordon Ross goto out; 5644bff34e3Sthurlow } 5654bff34e3Sthurlow 5664bff34e3Sthurlow /* 5674bff34e3Sthurlow * It's safe to uppercase this string, which 5684bff34e3Sthurlow * consists of ascii characters that should 5694bff34e3Sthurlow * be uppercased, %s, and ascii characters representing 5704bff34e3Sthurlow * hex digits 0-9 and A-F (already uppercased, and 5714bff34e3Sthurlow * if not uppercased they need to be). However, 5724bff34e3Sthurlow * it is NOT safe to uppercase after it has been 573613a2f6bSGordon Ross * "unpercent" converted, below! 5744bff34e3Sthurlow */ 5754bff34e3Sthurlow nls_str_upper(tmp2, tmp); 5764bff34e3Sthurlow 5774bff34e3Sthurlow /* 578613a2f6bSGordon Ross * Save ct_fullserver without case conversion. 5794bff34e3Sthurlow */ 580613a2f6bSGordon Ross if (strchr(tmp, '%')) 581613a2f6bSGordon Ross (void) unpercent(tmp); 582*02d09e03SGordon Ross error = smb_ctx_setfullserver(ctx, tmp); 5834bff34e3Sthurlow if (error) 584613a2f6bSGordon Ross goto out; 585613a2f6bSGordon Ross 586613a2f6bSGordon Ross #ifdef SMB_ST_NONE 5874bff34e3Sthurlow if (sharetype == SMB_ST_NONE) { 588613a2f6bSGordon Ross if (next) 5894bff34e3Sthurlow *next = p; 590613a2f6bSGordon Ross error = 0; 591613a2f6bSGordon Ross goto out; 5924bff34e3Sthurlow } 593613a2f6bSGordon Ross #endif 594613a2f6bSGordon Ross 5954bff34e3Sthurlow if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 5964bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0); 597613a2f6bSGordon Ross error = EINVAL; 598613a2f6bSGordon Ross goto out; 5994bff34e3Sthurlow } 6004bff34e3Sthurlow error = getsubstring(p, '/', p1, sizeof (tmp), &p); 6014bff34e3Sthurlow if (error) { 6024bff34e3Sthurlow error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 6034bff34e3Sthurlow if (error) { 6044bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6054bff34e3Sthurlow "unexpected end of line"), 0); 606613a2f6bSGordon Ross goto out; 6074bff34e3Sthurlow } 6084bff34e3Sthurlow } 6094bff34e3Sthurlow if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE && 6104bff34e3Sthurlow !(ctx->ct_flags & SMBCF_BROWSEOK)) { 6114bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0); 612613a2f6bSGordon Ross error = EINVAL; 613613a2f6bSGordon Ross goto out; 6144bff34e3Sthurlow } 615613a2f6bSGordon Ross if (next) 6164bff34e3Sthurlow *next = p; 617613a2f6bSGordon Ross if (*p1 == 0) { 618613a2f6bSGordon Ross error = 0; 619613a2f6bSGordon Ross goto out; 620613a2f6bSGordon Ross } 6214bff34e3Sthurlow error = smb_ctx_setshare(ctx, unpercent(p1), sharetype); 622613a2f6bSGordon Ross 623613a2f6bSGordon Ross out: 624613a2f6bSGordon Ross if (error == 0 && smb_debug > 0) 625613a2f6bSGordon Ross dump_ctx("after smb_ctx_parseunc", ctx); 626613a2f6bSGordon Ross 6274bff34e3Sthurlow return (error); 6284bff34e3Sthurlow } 6294bff34e3Sthurlow 630613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 6314bff34e3Sthurlow int 6324bff34e3Sthurlow smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 6334bff34e3Sthurlow { 6344bff34e3Sthurlow char *cp, *servercs, *localcs; 6354bff34e3Sthurlow int cslen = sizeof (ctx->ct_ssn.ioc_localcs); 6364bff34e3Sthurlow int scslen, lcslen, error; 6374bff34e3Sthurlow 6384bff34e3Sthurlow cp = strchr(arg, ':'); 6394bff34e3Sthurlow lcslen = cp ? (cp - arg) : 0; 6404bff34e3Sthurlow if (lcslen == 0 || lcslen >= cslen) { 6414bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6424bff34e3Sthurlow "invalid local charset specification (%s)"), 0, arg); 6434bff34e3Sthurlow return (EINVAL); 6444bff34e3Sthurlow } 6454bff34e3Sthurlow scslen = (size_t)strlen(++cp); 6464bff34e3Sthurlow if (scslen == 0 || scslen >= cslen) { 6474bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6484bff34e3Sthurlow "invalid server charset specification (%s)"), 0, arg); 6494bff34e3Sthurlow return (EINVAL); 6504bff34e3Sthurlow } 6514bff34e3Sthurlow localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 6524bff34e3Sthurlow localcs[lcslen] = 0; 6534bff34e3Sthurlow servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 6544bff34e3Sthurlow error = nls_setrecode(localcs, servercs); 6554bff34e3Sthurlow if (error == 0) 6564bff34e3Sthurlow return (0); 6574bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6584bff34e3Sthurlow "can't initialize iconv support (%s:%s)"), 6594bff34e3Sthurlow error, localcs, servercs); 6604bff34e3Sthurlow localcs[0] = 0; 6614bff34e3Sthurlow servercs[0] = 0; 6624bff34e3Sthurlow return (error); 6634bff34e3Sthurlow } 664613a2f6bSGordon Ross #endif /* KICONV_SUPPORT */ 665613a2f6bSGordon Ross 666613a2f6bSGordon Ross int 667613a2f6bSGordon Ross smb_ctx_setauthflags(struct smb_ctx *ctx, int flags) 668613a2f6bSGordon Ross { 669613a2f6bSGordon Ross ctx->ct_authflags = flags; 670613a2f6bSGordon Ross return (0); 671613a2f6bSGordon Ross } 6724bff34e3Sthurlow 6734bff34e3Sthurlow int 6744bff34e3Sthurlow smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name) 6754bff34e3Sthurlow { 676613a2f6bSGordon Ross char *p = strdup(name); 677613a2f6bSGordon Ross 678613a2f6bSGordon Ross if (p == NULL) 6794bff34e3Sthurlow return (ENOMEM); 680613a2f6bSGordon Ross if (ctx->ct_fullserver) 681613a2f6bSGordon Ross free(ctx->ct_fullserver); 682613a2f6bSGordon Ross ctx->ct_fullserver = p; 6834bff34e3Sthurlow return (0); 6844bff34e3Sthurlow } 6854bff34e3Sthurlow 6864bff34e3Sthurlow /* this routine does not uppercase the server name */ 687613a2f6bSGordon Ross int 6884bff34e3Sthurlow smb_ctx_setserver(struct smb_ctx *ctx, const char *name) 6894bff34e3Sthurlow { 6904bff34e3Sthurlow /* don't uppercase the server name */ 691613a2f6bSGordon Ross strlcpy(ctx->ct_srvname, name, 692613a2f6bSGordon Ross sizeof (ctx->ct_srvname)); 693613a2f6bSGordon Ross return (0); 6944bff34e3Sthurlow } 6954bff34e3Sthurlow 6964bff34e3Sthurlow int 6974bff34e3Sthurlow smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) 6984bff34e3Sthurlow { 6994bff34e3Sthurlow 700613a2f6bSGordon Ross if (strlen(name) >= sizeof (ctx->ct_user)) { 7014bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 7024bff34e3Sthurlow "user name '%s' too long"), 0, name); 7034bff34e3Sthurlow return (ENAMETOOLONG); 7044bff34e3Sthurlow } 7054bff34e3Sthurlow 7064bff34e3Sthurlow /* 7074bff34e3Sthurlow * Don't overwrite a value from the command line 7084bff34e3Sthurlow * with one from anywhere else. 7094bff34e3Sthurlow */ 7104bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR)) 7114bff34e3Sthurlow return (0); 7124bff34e3Sthurlow 7134bff34e3Sthurlow /* don't uppercase the username, just copy it. */ 714613a2f6bSGordon Ross strlcpy(ctx->ct_user, name, 715613a2f6bSGordon Ross sizeof (ctx->ct_user)); 7164bff34e3Sthurlow 7174bff34e3Sthurlow /* Mark this as "from the command line". */ 7184bff34e3Sthurlow if (from_cmd) 7194bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_USR; 7204bff34e3Sthurlow 7214bff34e3Sthurlow return (0); 7224bff34e3Sthurlow } 7234bff34e3Sthurlow 7244bff34e3Sthurlow /* 7254bff34e3Sthurlow * Never uppercase the workgroup 7264bff34e3Sthurlow * name here, because it might come 7274bff34e3Sthurlow * from a Windows codepage encoding. 7284bff34e3Sthurlow * 7294bff34e3Sthurlow * Don't overwrite a domain name from the 7304bff34e3Sthurlow * command line with one from anywhere else. 7314bff34e3Sthurlow * See smb_ctx_init() for notes about this. 7324bff34e3Sthurlow */ 7334bff34e3Sthurlow int 734613a2f6bSGordon Ross smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd) 7354bff34e3Sthurlow { 7364bff34e3Sthurlow 737613a2f6bSGordon Ross if (strlen(name) >= sizeof (ctx->ct_domain)) { 7384bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 7394bff34e3Sthurlow "workgroup name '%s' too long"), 0, name); 7404bff34e3Sthurlow return (ENAMETOOLONG); 7414bff34e3Sthurlow } 7424bff34e3Sthurlow 7434bff34e3Sthurlow /* 7444bff34e3Sthurlow * Don't overwrite a value from the command line 7454bff34e3Sthurlow * with one from anywhere else. 7464bff34e3Sthurlow */ 7474bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM)) 7484bff34e3Sthurlow return (0); 7494bff34e3Sthurlow 750613a2f6bSGordon Ross strlcpy(ctx->ct_domain, name, 751613a2f6bSGordon Ross sizeof (ctx->ct_domain)); 7524bff34e3Sthurlow 7534bff34e3Sthurlow /* Mark this as "from the command line". */ 7544bff34e3Sthurlow if (from_cmd) 7554bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_DOM; 7564bff34e3Sthurlow 7574bff34e3Sthurlow return (0); 7584bff34e3Sthurlow } 7594bff34e3Sthurlow 7604bff34e3Sthurlow int 7614bff34e3Sthurlow smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd) 7624bff34e3Sthurlow { 763613a2f6bSGordon Ross int err; 7644bff34e3Sthurlow 765613a2f6bSGordon Ross if (passwd == NULL) 7664bff34e3Sthurlow return (EINVAL); 767613a2f6bSGordon Ross if (strlen(passwd) >= sizeof (ctx->ct_password)) { 7684bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0); 7694bff34e3Sthurlow return (ENAMETOOLONG); 7704bff34e3Sthurlow } 7714bff34e3Sthurlow 7724bff34e3Sthurlow /* 773613a2f6bSGordon Ross * If called again after comand line parsing, 774613a2f6bSGordon Ross * don't overwrite a value from the command line 775613a2f6bSGordon Ross * with one from any stored config. 7764bff34e3Sthurlow */ 7774bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW)) 7784bff34e3Sthurlow return (0); 7794bff34e3Sthurlow 780613a2f6bSGordon Ross memset(ctx->ct_password, 0, sizeof (ctx->ct_password)); 7814bff34e3Sthurlow if (strncmp(passwd, "$$1", 3) == 0) 782*02d09e03SGordon Ross (void) smb_simpledecrypt(ctx->ct_password, passwd); 7834bff34e3Sthurlow else 784613a2f6bSGordon Ross strlcpy(ctx->ct_password, passwd, 785613a2f6bSGordon Ross sizeof (ctx->ct_password)); 786613a2f6bSGordon Ross 787613a2f6bSGordon Ross /* 788613a2f6bSGordon Ross * Compute LM hash, NT hash. 789613a2f6bSGordon Ross */ 790613a2f6bSGordon Ross if (ctx->ct_password[0]) { 791613a2f6bSGordon Ross err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password); 792613a2f6bSGordon Ross if (err != 0) 793613a2f6bSGordon Ross return (err); 794613a2f6bSGordon Ross err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password); 795613a2f6bSGordon Ross if (err != 0) 796613a2f6bSGordon Ross return (err); 797613a2f6bSGordon Ross } 7984bff34e3Sthurlow 7994bff34e3Sthurlow /* Mark this as "from the command line". */ 8004bff34e3Sthurlow if (from_cmd) 8014bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_PW; 8024bff34e3Sthurlow 8034bff34e3Sthurlow return (0); 8044bff34e3Sthurlow } 8054bff34e3Sthurlow 806613a2f6bSGordon Ross /* 807613a2f6bSGordon Ross * Use this to set NTLM auth. info (hashes) 808613a2f6bSGordon Ross * when we don't have the password. 809613a2f6bSGordon Ross */ 810613a2f6bSGordon Ross int 811613a2f6bSGordon Ross smb_ctx_setpwhash(smb_ctx_t *ctx, 812613a2f6bSGordon Ross const uchar_t *nthash, const uchar_t *lmhash) 813613a2f6bSGordon Ross { 814613a2f6bSGordon Ross 815613a2f6bSGordon Ross /* Need ct_password to be non-null. */ 816613a2f6bSGordon Ross if (ctx->ct_password[0] == '\0') 817613a2f6bSGordon Ross strlcpy(ctx->ct_password, "$HASH", 818613a2f6bSGordon Ross sizeof (ctx->ct_password)); 819613a2f6bSGordon Ross 820613a2f6bSGordon Ross /* 821613a2f6bSGordon Ross * Compute LM hash, NT hash. 822613a2f6bSGordon Ross */ 823613a2f6bSGordon Ross memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ); 824613a2f6bSGordon Ross 825613a2f6bSGordon Ross /* The LM hash is optional */ 826613a2f6bSGordon Ross if (lmhash) { 827613a2f6bSGordon Ross memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ); 828613a2f6bSGordon Ross } 829613a2f6bSGordon Ross 830613a2f6bSGordon Ross return (0); 831613a2f6bSGordon Ross } 832613a2f6bSGordon Ross 8334bff34e3Sthurlow int 8344bff34e3Sthurlow smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 8354bff34e3Sthurlow { 836613a2f6bSGordon Ross if (strlen(share) >= SMBIOC_MAX_NAME) { 8374bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 8384bff34e3Sthurlow "share name '%s' too long"), 0, share); 8394bff34e3Sthurlow return (ENAMETOOLONG); 8404bff34e3Sthurlow } 8414bff34e3Sthurlow if (ctx->ct_origshare) 8424bff34e3Sthurlow free(ctx->ct_origshare); 8434bff34e3Sthurlow if ((ctx->ct_origshare = strdup(share)) == NULL) 8444bff34e3Sthurlow return (ENOMEM); 845613a2f6bSGordon Ross 846613a2f6bSGordon Ross ctx->ct_shtype_req = stype; 847613a2f6bSGordon Ross 8484bff34e3Sthurlow return (0); 8494bff34e3Sthurlow } 8504bff34e3Sthurlow 8514bff34e3Sthurlow int 8524bff34e3Sthurlow smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 8534bff34e3Sthurlow { 8544bff34e3Sthurlow if (addr == NULL || addr[0] == 0) 8554bff34e3Sthurlow return (EINVAL); 856613a2f6bSGordon Ross if (ctx->ct_srvaddr_s) 857613a2f6bSGordon Ross free(ctx->ct_srvaddr_s); 858613a2f6bSGordon Ross if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL) 8594bff34e3Sthurlow return (ENOMEM); 8604bff34e3Sthurlow return (0); 8614bff34e3Sthurlow } 8624bff34e3Sthurlow 8638eb99b82SGordon Ross /* 8648eb99b82SGordon Ross * API for library caller to set signing enabled, required 8658eb99b82SGordon Ross * Note: if not enable, ignore require 8668eb99b82SGordon Ross */ 8678eb99b82SGordon Ross int 8688eb99b82SGordon Ross smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require) 8698eb99b82SGordon Ross { 8708eb99b82SGordon Ross ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK; 8718eb99b82SGordon Ross if (enable) { 8728eb99b82SGordon Ross ctx->ct_vopt |= SMBVOPT_SIGNING_ENABLED; 8738eb99b82SGordon Ross if (require) 8748eb99b82SGordon Ross ctx->ct_vopt |= SMBVOPT_SIGNING_REQUIRED; 8758eb99b82SGordon Ross } 8768eb99b82SGordon Ross return (0); 8778eb99b82SGordon Ross } 8788eb99b82SGordon Ross 8794bff34e3Sthurlow static int 8804bff34e3Sthurlow smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 8814bff34e3Sthurlow { 8824bff34e3Sthurlow struct group gr; 8834bff34e3Sthurlow struct passwd pw; 8844bff34e3Sthurlow char buf[NSS_BUFLEN_PASSWD]; 8854bff34e3Sthurlow char *cp; 8864bff34e3Sthurlow 8874bff34e3Sthurlow cp = strchr(pair, ':'); 8884bff34e3Sthurlow if (cp) { 8894bff34e3Sthurlow *cp++ = '\0'; 890613a2f6bSGordon Ross if (*cp && gid) { 8914bff34e3Sthurlow if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) { 8924bff34e3Sthurlow *gid = gr.gr_gid; 8934bff34e3Sthurlow } else 8944bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 8954bff34e3Sthurlow "Invalid group name %s, ignored"), 0, cp); 8964bff34e3Sthurlow } 8974bff34e3Sthurlow } 8984bff34e3Sthurlow if (*pair) { 8994bff34e3Sthurlow if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) { 9004bff34e3Sthurlow *uid = pw.pw_uid; 9014bff34e3Sthurlow } else 9024bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 9034bff34e3Sthurlow "Invalid user name %s, ignored"), 0, pair); 9044bff34e3Sthurlow } 9054bff34e3Sthurlow 9064bff34e3Sthurlow return (0); 9074bff34e3Sthurlow } 9084bff34e3Sthurlow 9094bff34e3Sthurlow /* 9104bff34e3Sthurlow * Commands use this with getopt. See: 9114bff34e3Sthurlow * STDPARAM_OPT, STDPARAM_ARGS 9124bff34e3Sthurlow * Called after smb_ctx_readrc(). 9134bff34e3Sthurlow */ 9144bff34e3Sthurlow int 9154bff34e3Sthurlow smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 9164bff34e3Sthurlow { 9174bff34e3Sthurlow int error = 0; 9184bff34e3Sthurlow char *p, *cp; 9194bff34e3Sthurlow char tmp[1024]; 9204bff34e3Sthurlow 9214bff34e3Sthurlow switch (opt) { 9224bff34e3Sthurlow case 'A': 9234bff34e3Sthurlow case 'U': 9244bff34e3Sthurlow /* Handled in smb_ctx_init() */ 9254bff34e3Sthurlow break; 9264bff34e3Sthurlow case 'I': 9274bff34e3Sthurlow error = smb_ctx_setsrvaddr(ctx, arg); 9284bff34e3Sthurlow break; 9294bff34e3Sthurlow case 'M': 930613a2f6bSGordon Ross /* share connect rights - ignored */ 9314bff34e3Sthurlow ctx->ct_flags |= SMBCF_SRIGHTS; 9324bff34e3Sthurlow break; 9334bff34e3Sthurlow case 'N': 9344bff34e3Sthurlow ctx->ct_flags |= SMBCF_NOPWD; 9354bff34e3Sthurlow break; 9364bff34e3Sthurlow case 'O': 9374bff34e3Sthurlow p = strdup(arg); 9384bff34e3Sthurlow cp = strchr(p, '/'); 939613a2f6bSGordon Ross if (cp) 940613a2f6bSGordon Ross *cp = '\0'; 941613a2f6bSGordon Ross error = smb_parse_owner(cp, &ctx->ct_owner, NULL); 9424bff34e3Sthurlow free(p); 9434bff34e3Sthurlow break; 9444bff34e3Sthurlow case 'P': 945613a2f6bSGordon Ross /* ctx->ct_vopt |= SMBCOPT_PERMANENT; */ 9464bff34e3Sthurlow break; 9474bff34e3Sthurlow case 'R': 948613a2f6bSGordon Ross /* retry count - ignored */ 9494bff34e3Sthurlow break; 9504bff34e3Sthurlow case 'T': 951613a2f6bSGordon Ross /* timeout - ignored */ 9524bff34e3Sthurlow break; 953613a2f6bSGordon Ross case 'D': /* domain */ 954613a2f6bSGordon Ross case 'W': /* workgroup (legacy alias) */ 9554bff34e3Sthurlow nls_str_upper(tmp, arg); 956613a2f6bSGordon Ross error = smb_ctx_setdomain(ctx, tmp, TRUE); 9574bff34e3Sthurlow break; 9584bff34e3Sthurlow } 9594bff34e3Sthurlow return (error); 9604bff34e3Sthurlow } 9614bff34e3Sthurlow 9624bff34e3Sthurlow 963613a2f6bSGordon Ross /* 964613a2f6bSGordon Ross * Original code injected iconv tables into the kernel. 965613a2f6bSGordon Ross * Not sure if we'll need this or not... REVISIT 966613a2f6bSGordon Ross */ 967613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 9684bff34e3Sthurlow static int 9694bff34e3Sthurlow smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl) 9704bff34e3Sthurlow { 971613a2f6bSGordon Ross int error = 0; 9724bff34e3Sthurlow 9734bff34e3Sthurlow error = kiconv_add_xlat_table(to, from, tbl); 9744bff34e3Sthurlow if (error && error != EEXIST) { 9754bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 9764bff34e3Sthurlow "can not setup kernel iconv table (%s:%s)"), 9774bff34e3Sthurlow error, from, to); 9784bff34e3Sthurlow return (error); 9794bff34e3Sthurlow } 980613a2f6bSGordon Ross return (error); 9814bff34e3Sthurlow } 982613a2f6bSGordon Ross #endif /* KICONV_SUPPORT */ 9834bff34e3Sthurlow 9844bff34e3Sthurlow /* 985613a2f6bSGordon Ross * Verify context info. before connect operation(s), 9864bff34e3Sthurlow * lookup specified server and try to fill all forgotten fields. 987613a2f6bSGordon Ross * Legacy name used by commands. 9884bff34e3Sthurlow */ 9894bff34e3Sthurlow int 9904bff34e3Sthurlow smb_ctx_resolve(struct smb_ctx *ctx) 9914bff34e3Sthurlow { 9924bff34e3Sthurlow struct smbioc_ossn *ssn = &ctx->ct_ssn; 993613a2f6bSGordon Ross int error = 0; 994613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 9954bff34e3Sthurlow uchar_t cstbl[256]; 9964bff34e3Sthurlow uint_t i; 997613a2f6bSGordon Ross #endif 9984bff34e3Sthurlow 9994bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_RESOLVED; 1000613a2f6bSGordon Ross 1001613a2f6bSGordon Ross if (ctx->ct_fullserver == NULL) { 10024bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10034bff34e3Sthurlow "no server name specified"), 0); 10044bff34e3Sthurlow return (EINVAL); 10054bff34e3Sthurlow } 1006613a2f6bSGordon Ross 1007613a2f6bSGordon Ross if (ctx->ct_minlevel >= SMBL_SHARE && 1008613a2f6bSGordon Ross ctx->ct_origshare == NULL) { 10094bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10104bff34e3Sthurlow "no share name specified for %s@%s"), 1011613a2f6bSGordon Ross 0, ssn->ssn_user, ctx->ct_fullserver); 10124bff34e3Sthurlow return (EINVAL); 10134bff34e3Sthurlow } 10144bff34e3Sthurlow error = nb_ctx_resolve(ctx->ct_nb); 10154bff34e3Sthurlow if (error) 10164bff34e3Sthurlow return (error); 1017613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 10184bff34e3Sthurlow if (ssn->ioc_localcs[0] == 0) 10194bff34e3Sthurlow strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ 10204bff34e3Sthurlow error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 10214bff34e3Sthurlow if (error) 10224bff34e3Sthurlow return (error); 10234bff34e3Sthurlow error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 10244bff34e3Sthurlow if (error) 10254bff34e3Sthurlow return (error); 10264bff34e3Sthurlow if (ssn->ioc_servercs[0] != 0) { 10274bff34e3Sthurlow for (i = 0; i < sizeof (cstbl); i++) 10284bff34e3Sthurlow cstbl[i] = i; 10294bff34e3Sthurlow nls_mem_toext(cstbl, cstbl, sizeof (cstbl)); 10304bff34e3Sthurlow error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, 10314bff34e3Sthurlow cstbl); 10324bff34e3Sthurlow if (error) 10334bff34e3Sthurlow return (error); 10344bff34e3Sthurlow for (i = 0; i < sizeof (cstbl); i++) 10354bff34e3Sthurlow cstbl[i] = i; 10364bff34e3Sthurlow nls_mem_toloc(cstbl, cstbl, sizeof (cstbl)); 10374bff34e3Sthurlow error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, 10384bff34e3Sthurlow cstbl); 10394bff34e3Sthurlow if (error) 10404bff34e3Sthurlow return (error); 10414bff34e3Sthurlow } 1042613a2f6bSGordon Ross #endif /* KICONV_SUPPORT */ 10434bff34e3Sthurlow 10444bff34e3Sthurlow /* 10456b2bcd8eSGordon Ross * Lookup the IP address and fill in ct_addrinfo. 10466b2bcd8eSGordon Ross * 10476b2bcd8eSGordon Ross * Note: smb_ctx_getaddr() returns a EAI_xxx 10486b2bcd8eSGordon Ross * error value like getaddrinfo(3), but this 10496b2bcd8eSGordon Ross * function needs to return an errno value. 10504bff34e3Sthurlow */ 1051613a2f6bSGordon Ross error = smb_ctx_getaddr(ctx); 10524bff34e3Sthurlow if (error) { 10536b2bcd8eSGordon Ross const char *ais = gai_strerror(error); 10544bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10556b2bcd8eSGordon Ross "can't get server address, %s"), 0, ais); 10566b2bcd8eSGordon Ross return (ENODATA); 10574bff34e3Sthurlow } 1058613a2f6bSGordon Ross assert(ctx->ct_addrinfo != NULL); 10594bff34e3Sthurlow 10604bff34e3Sthurlow /* 1061613a2f6bSGordon Ross * If we have a user name but no password, 1062613a2f6bSGordon Ross * check for a keychain entry. 1063613a2f6bSGordon Ross * XXX: Only for auth NTLM? 10644bff34e3Sthurlow */ 1065613a2f6bSGordon Ross if (ctx->ct_user[0] == '\0') { 10664bff34e3Sthurlow /* 1067613a2f6bSGordon Ross * No user name (anonymous session). 1068613a2f6bSGordon Ross * The minauth checks do not apply. 10694bff34e3Sthurlow */ 1070613a2f6bSGordon Ross ctx->ct_authflags = SMB_AT_ANON; 1071613a2f6bSGordon Ross } else { 10724bff34e3Sthurlow /* 1073613a2f6bSGordon Ross * Have a user name. 1074613a2f6bSGordon Ross * If we don't have a p/w yet, 1075613a2f6bSGordon Ross * try the keychain. 10764bff34e3Sthurlow */ 1077613a2f6bSGordon Ross if (ctx->ct_password[0] == '\0') 1078613a2f6bSGordon Ross (void) smb_get_keychain(ctx); 1079613a2f6bSGordon Ross /* 1080613a2f6bSGordon Ross * If we're doing p/w based auth, 1081613a2f6bSGordon Ross * that means not using Kerberos. 1082613a2f6bSGordon Ross */ 1083613a2f6bSGordon Ross if (ctx->ct_password[0] != '\0') 1084613a2f6bSGordon Ross ctx->ct_authflags &= ~SMB_AT_KRB5; 1085613a2f6bSGordon Ross /* 1086613a2f6bSGordon Ross * Mask out disallowed auth types. 1087613a2f6bSGordon Ross */ 1088613a2f6bSGordon Ross ctx->ct_authflags &= ctx->ct_minauth; 10894bff34e3Sthurlow } 1090613a2f6bSGordon Ross if (ctx->ct_authflags == 0) { 10914bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1092613a2f6bSGordon Ross "no valid auth. types"), 0); 1093613a2f6bSGordon Ross return (ENOTSUP); 10944bff34e3Sthurlow } 1095613a2f6bSGordon Ross 10964bff34e3Sthurlow ctx->ct_flags |= SMBCF_RESOLVED; 10974bff34e3Sthurlow if (smb_debug) 10984bff34e3Sthurlow dump_ctx("after smb_ctx_resolve", ctx); 10994bff34e3Sthurlow 11004bff34e3Sthurlow return (0); 11014bff34e3Sthurlow } 11024bff34e3Sthurlow 11034bff34e3Sthurlow int 11044bff34e3Sthurlow smb_open_driver() 11054bff34e3Sthurlow { 1106613a2f6bSGordon Ross int err, fd; 11074bff34e3Sthurlow uint32_t version; 11084bff34e3Sthurlow 11094bff34e3Sthurlow fd = open("/dev/"NSMB_NAME, O_RDWR); 1110613a2f6bSGordon Ross if (fd < 0) { 1111613a2f6bSGordon Ross err = errno; 11124bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1113613a2f6bSGordon Ross "failed to open driver"), err); 11144bff34e3Sthurlow return (-1); 1115613a2f6bSGordon Ross } 11164bff34e3Sthurlow 11174bff34e3Sthurlow /* 11184bff34e3Sthurlow * Check the driver version (paranoia) 11194bff34e3Sthurlow * Do this BEFORE any other ioctl calls. 11204bff34e3Sthurlow */ 1121613a2f6bSGordon Ross if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) 1122613a2f6bSGordon Ross version = 0; 11234bff34e3Sthurlow if (version != NSMB_VERSION) { 11244bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 11254bff34e3Sthurlow "incorrect driver version"), 0); 11264bff34e3Sthurlow close(fd); 11274bff34e3Sthurlow return (-1); 11284bff34e3Sthurlow } 11294bff34e3Sthurlow 1130613a2f6bSGordon Ross /* This handle controls per-process resources. */ 1131613a2f6bSGordon Ross (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 1132613a2f6bSGordon Ross 11334bff34e3Sthurlow return (fd); 11344bff34e3Sthurlow } 11354bff34e3Sthurlow 1136613a2f6bSGordon Ross int 11374bff34e3Sthurlow smb_ctx_gethandle(struct smb_ctx *ctx) 11384bff34e3Sthurlow { 1139613a2f6bSGordon Ross int fd; 11404bff34e3Sthurlow 1141613a2f6bSGordon Ross if (ctx->ct_dev_fd != -1) { 11424bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 1143613a2f6bSGordon Ross close(ctx->ct_dev_fd); 1144613a2f6bSGordon Ross ctx->ct_dev_fd = -1; 11454bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_SSNACTIVE; 11464bff34e3Sthurlow } 11474bff34e3Sthurlow 11484bff34e3Sthurlow fd = smb_open_driver(); 11494bff34e3Sthurlow if (fd < 0) 11504bff34e3Sthurlow return (ENODEV); 11514bff34e3Sthurlow 1152613a2f6bSGordon Ross ctx->ct_dev_fd = fd; 11534bff34e3Sthurlow return (0); 11544bff34e3Sthurlow } 11554bff34e3Sthurlow 1156613a2f6bSGordon Ross 1157613a2f6bSGordon Ross /* 1158613a2f6bSGordon Ross * Find or create a connection + logon session 1159613a2f6bSGordon Ross */ 11604bff34e3Sthurlow int 1161613a2f6bSGordon Ross smb_ctx_get_ssn(struct smb_ctx *ctx) 11624bff34e3Sthurlow { 1163613a2f6bSGordon Ross int err = 0; 11644bff34e3Sthurlow 1165613a2f6bSGordon Ross if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) 11664bff34e3Sthurlow return (EINVAL); 11674bff34e3Sthurlow 1168613a2f6bSGordon Ross if (ctx->ct_dev_fd < 0) { 1169613a2f6bSGordon Ross if ((err = smb_ctx_gethandle(ctx))) 1170613a2f6bSGordon Ross return (err); 11714bff34e3Sthurlow } 11724bff34e3Sthurlow 11734bff34e3Sthurlow /* 1174613a2f6bSGordon Ross * Check whether the driver already has a VC 1175613a2f6bSGordon Ross * we can use. If so, we're done! 11764bff34e3Sthurlow */ 1177613a2f6bSGordon Ross err = smb_ctx_findvc(ctx); 1178613a2f6bSGordon Ross if (err == 0) { 1179613a2f6bSGordon Ross DPRINT("found an existing VC"); 11804bff34e3Sthurlow } else { 1181613a2f6bSGordon Ross /* 1182613a2f6bSGordon Ross * This calls the IOD to create a new session. 1183613a2f6bSGordon Ross */ 1184613a2f6bSGordon Ross DPRINT("setup a new VC"); 1185613a2f6bSGordon Ross err = smb_ctx_newvc(ctx); 1186613a2f6bSGordon Ross if (err != 0) 1187613a2f6bSGordon Ross return (err); 1188613a2f6bSGordon Ross 1189613a2f6bSGordon Ross /* 1190613a2f6bSGordon Ross * Call findvc again. The new VC sould be 1191613a2f6bSGordon Ross * found in the driver this time. 1192613a2f6bSGordon Ross */ 1193613a2f6bSGordon Ross err = smb_ctx_findvc(ctx); 11944bff34e3Sthurlow } 1195613a2f6bSGordon Ross 1196613a2f6bSGordon Ross return (err); 11974bff34e3Sthurlow } 11984bff34e3Sthurlow 11994bff34e3Sthurlow /* 1200613a2f6bSGordon Ross * Get the string representation of a share "use" type, 1201613a2f6bSGordon Ross * as needed for the "service" in tree connect. 12024bff34e3Sthurlow */ 1203613a2f6bSGordon Ross static const char * 1204613a2f6bSGordon Ross smb_use_type_str(smb_use_shtype_t stype) 1205613a2f6bSGordon Ross { 1206613a2f6bSGordon Ross const char *pp; 1207613a2f6bSGordon Ross 1208613a2f6bSGordon Ross switch (stype) { 1209613a2f6bSGordon Ross default: 1210613a2f6bSGordon Ross case USE_WILDCARD: 1211613a2f6bSGordon Ross pp = "?????"; 1212613a2f6bSGordon Ross break; 1213613a2f6bSGordon Ross case USE_DISKDEV: 1214613a2f6bSGordon Ross pp = "A:"; 1215613a2f6bSGordon Ross break; 1216613a2f6bSGordon Ross case USE_SPOOLDEV: 1217613a2f6bSGordon Ross pp = "LPT1:"; 1218613a2f6bSGordon Ross break; 1219613a2f6bSGordon Ross case USE_CHARDEV: 1220613a2f6bSGordon Ross pp = "COMM"; 1221613a2f6bSGordon Ross break; 1222613a2f6bSGordon Ross case USE_IPC: 1223613a2f6bSGordon Ross pp = "IPC"; 1224613a2f6bSGordon Ross break; 1225613a2f6bSGordon Ross } 1226613a2f6bSGordon Ross return (pp); 1227613a2f6bSGordon Ross } 1228613a2f6bSGordon Ross 12294bff34e3Sthurlow /* 1230613a2f6bSGordon Ross * Find or create a tree connection 12314bff34e3Sthurlow */ 1232613a2f6bSGordon Ross int 1233613a2f6bSGordon Ross smb_ctx_get_tree(struct smb_ctx *ctx) 1234613a2f6bSGordon Ross { 1235613a2f6bSGordon Ross smbioc_tcon_t *tcon = NULL; 1236613a2f6bSGordon Ross const char *stype; 1237613a2f6bSGordon Ross int cmd, err = 0; 1238613a2f6bSGordon Ross 1239613a2f6bSGordon Ross if (ctx->ct_dev_fd < 0 || 1240613a2f6bSGordon Ross ctx->ct_origshare == NULL) { 1241613a2f6bSGordon Ross return (EINVAL); 1242613a2f6bSGordon Ross } 1243613a2f6bSGordon Ross 1244613a2f6bSGordon Ross cmd = SMBIOC_TREE_CONNECT; 1245613a2f6bSGordon Ross tcon = malloc(sizeof (*tcon)); 1246613a2f6bSGordon Ross if (tcon == NULL) 1247613a2f6bSGordon Ross return (ENOMEM); 1248613a2f6bSGordon Ross bzero(tcon, sizeof (*tcon)); 1249613a2f6bSGordon Ross tcon->tc_flags = SMBLK_CREATE; 1250613a2f6bSGordon Ross tcon->tc_opt = 0; 1251613a2f6bSGordon Ross 1252613a2f6bSGordon Ross /* The share name */ 1253613a2f6bSGordon Ross strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare, 1254613a2f6bSGordon Ross sizeof (tcon->tc_sh.sh_name)); 1255613a2f6bSGordon Ross 1256613a2f6bSGordon Ross /* The share "use" type. */ 1257613a2f6bSGordon Ross stype = smb_use_type_str(ctx->ct_shtype_req); 1258613a2f6bSGordon Ross strlcpy(tcon->tc_sh.sh_type_req, stype, 1259613a2f6bSGordon Ross sizeof (tcon->tc_sh.sh_type_req)); 1260613a2f6bSGordon Ross 1261613a2f6bSGordon Ross /* 1262613a2f6bSGordon Ross * Todo: share passwords for share-level security. 1263613a2f6bSGordon Ross * 1264613a2f6bSGordon Ross * The driver does the actual TCON call. 1265613a2f6bSGordon Ross */ 1266613a2f6bSGordon Ross if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) { 1267613a2f6bSGordon Ross err = errno; 12684bff34e3Sthurlow goto out; 12694bff34e3Sthurlow } 1270613a2f6bSGordon Ross 1271613a2f6bSGordon Ross /* 1272613a2f6bSGordon Ross * Check the returned share type 1273613a2f6bSGordon Ross */ 1274613a2f6bSGordon Ross DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret); 1275613a2f6bSGordon Ross if (ctx->ct_shtype_req != USE_WILDCARD && 1276613a2f6bSGordon Ross 0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) { 1277613a2f6bSGordon Ross smb_error(dgettext(TEXT_DOMAIN, 1278613a2f6bSGordon Ross "%s: incompatible share type"), 1279613a2f6bSGordon Ross 0, ctx->ct_origshare); 1280613a2f6bSGordon Ross err = EINVAL; 12814bff34e3Sthurlow } 12824bff34e3Sthurlow 12834bff34e3Sthurlow out: 1284613a2f6bSGordon Ross if (tcon != NULL) 1285613a2f6bSGordon Ross free(tcon); 1286613a2f6bSGordon Ross 1287613a2f6bSGordon Ross return (err); 12884bff34e3Sthurlow } 12894bff34e3Sthurlow 12904bff34e3Sthurlow /* 12914bff34e3Sthurlow * Return the hflags2 word for an smb_ctx. 12924bff34e3Sthurlow */ 12934bff34e3Sthurlow int 12944bff34e3Sthurlow smb_ctx_flags2(struct smb_ctx *ctx) 12954bff34e3Sthurlow { 12964bff34e3Sthurlow uint16_t flags2; 12974bff34e3Sthurlow 1298613a2f6bSGordon Ross if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) { 12994bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 13004bff34e3Sthurlow "can't get flags2 for a session"), errno); 13014bff34e3Sthurlow return (-1); 13024bff34e3Sthurlow } 13034bff34e3Sthurlow return (flags2); 13044bff34e3Sthurlow } 13054bff34e3Sthurlow 13064bff34e3Sthurlow /* 1307613a2f6bSGordon Ross * Get the transport level session key. 1308613a2f6bSGordon Ross * Must already have an active SMB session. 1309613a2f6bSGordon Ross */ 1310613a2f6bSGordon Ross int 1311613a2f6bSGordon Ross smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len) 1312613a2f6bSGordon Ross { 1313613a2f6bSGordon Ross if (len < SMBIOC_HASH_SZ) 1314613a2f6bSGordon Ross return (EINVAL); 1315613a2f6bSGordon Ross 1316613a2f6bSGordon Ross if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1) 1317613a2f6bSGordon Ross return (errno); 1318613a2f6bSGordon Ross 1319613a2f6bSGordon Ross return (0); 1320613a2f6bSGordon Ross } 1321613a2f6bSGordon Ross 1322613a2f6bSGordon Ross 1323613a2f6bSGordon Ross /* 1324613a2f6bSGordon Ross * RC file parsing stuff 1325613a2f6bSGordon Ross */ 1326613a2f6bSGordon Ross 1327613a2f6bSGordon Ross struct nv { 1328613a2f6bSGordon Ross char *name; 1329613a2f6bSGordon Ross int value; 1330613a2f6bSGordon Ross } minauth_table[] = { 1331613a2f6bSGordon Ross /* Allowed auth. types */ 1332613a2f6bSGordon Ross { "kerberos", SMB_AT_KRB5 }, 1333613a2f6bSGordon Ross { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 }, 1334613a2f6bSGordon Ross { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 }, 1335613a2f6bSGordon Ross { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 }, 1336613a2f6bSGordon Ross { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1| 1337613a2f6bSGordon Ross SMB_AT_ANON }, 1338613a2f6bSGordon Ross { NULL } 1339613a2f6bSGordon Ross }; 1340613a2f6bSGordon Ross 1341613a2f6bSGordon Ross 1342613a2f6bSGordon Ross /* 13434bff34e3Sthurlow * level values: 13444bff34e3Sthurlow * 0 - default 13454bff34e3Sthurlow * 1 - server 13464bff34e3Sthurlow * 2 - server:user 13474bff34e3Sthurlow * 3 - server:user:share 13484bff34e3Sthurlow */ 13494bff34e3Sthurlow static int 13504bff34e3Sthurlow smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 13514bff34e3Sthurlow { 13524bff34e3Sthurlow char *p; 13534bff34e3Sthurlow int error; 13544bff34e3Sthurlow 1355613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 13564bff34e3Sthurlow if (level > 0) { 13574bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "charsets", &p); 13584bff34e3Sthurlow if (p) { 13594bff34e3Sthurlow error = smb_ctx_setcharset(ctx, p); 13604bff34e3Sthurlow if (error) 13614bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 13624bff34e3Sthurlow "charset specification in the section '%s' ignored"), 13634bff34e3Sthurlow error, sname); 13644bff34e3Sthurlow } 13654bff34e3Sthurlow } 13664bff34e3Sthurlow #endif 13674bff34e3Sthurlow 13684bff34e3Sthurlow if (level <= 1) { 13694bff34e3Sthurlow /* Section is: [default] or [server] */ 13704bff34e3Sthurlow 13714bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "minauth", &p); 13724bff34e3Sthurlow if (p) { 13734bff34e3Sthurlow /* 13744bff34e3Sthurlow * "minauth" was set in this section; override 13754bff34e3Sthurlow * the current minimum authentication setting. 13764bff34e3Sthurlow */ 1377613a2f6bSGordon Ross struct nv *nvp; 1378613a2f6bSGordon Ross for (nvp = minauth_table; nvp->name; nvp++) 1379613a2f6bSGordon Ross if (strcmp(p, nvp->name) == 0) 1380613a2f6bSGordon Ross break; 1381613a2f6bSGordon Ross if (nvp->name) 1382613a2f6bSGordon Ross ctx->ct_minauth = nvp->value; 1383613a2f6bSGordon Ross else { 13844bff34e3Sthurlow /* 13854bff34e3Sthurlow * Unknown minimum authentication level. 13864bff34e3Sthurlow */ 13874bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 13884bff34e3Sthurlow "invalid minimum authentication level \"%s\" specified in the section %s"), 13894bff34e3Sthurlow 0, p, sname); 13904bff34e3Sthurlow return (EINVAL); 13914bff34e3Sthurlow } 13924bff34e3Sthurlow } 13934bff34e3Sthurlow 13949c9af259SGordon Ross rc_getstringptr(smb_rc, sname, "signing", &p); 13959c9af259SGordon Ross if (p) { 13969c9af259SGordon Ross /* 13979c9af259SGordon Ross * "signing" was set in this section; override 1398*02d09e03SGordon Ross * the current signing settings. Note: 1399*02d09e03SGordon Ross * setsigning flags are: enable, require 14009c9af259SGordon Ross */ 14019c9af259SGordon Ross if (strcmp(p, "disabled") == 0) { 1402*02d09e03SGordon Ross (void) smb_ctx_setsigning(ctx, FALSE, FALSE); 14039c9af259SGordon Ross } else if (strcmp(p, "enabled") == 0) { 1404*02d09e03SGordon Ross (void) smb_ctx_setsigning(ctx, TRUE, FALSE); 14059c9af259SGordon Ross } else if (strcmp(p, "required") == 0) { 1406*02d09e03SGordon Ross (void) smb_ctx_setsigning(ctx, TRUE, TRUE); 14079c9af259SGordon Ross } else { 14089c9af259SGordon Ross /* 14099c9af259SGordon Ross * Unknown "signing" value. 14109c9af259SGordon Ross */ 14119c9af259SGordon Ross smb_error(dgettext(TEXT_DOMAIN, 14129c9af259SGordon Ross "invalid signing policy \"%s\" specified in the section %s"), 14139c9af259SGordon Ross 0, p, sname); 14149c9af259SGordon Ross return (EINVAL); 14159c9af259SGordon Ross } 14169c9af259SGordon Ross } 14179c9af259SGordon Ross 14184bff34e3Sthurlow /* 14194bff34e3Sthurlow * Domain name. Allow both keywords: 14204bff34e3Sthurlow * "workgroup", "domain" 14214bff34e3Sthurlow * 14224bff34e3Sthurlow * Note: these are NOT marked "from CMD". 14234bff34e3Sthurlow * See long comment at smb_ctx_init() 14244bff34e3Sthurlow */ 14254bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "workgroup", &p); 14264bff34e3Sthurlow if (p) { 14274bff34e3Sthurlow nls_str_upper(p, p); 1428613a2f6bSGordon Ross error = smb_ctx_setdomain(ctx, p, 0); 14294bff34e3Sthurlow if (error) 14304bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14314bff34e3Sthurlow "workgroup specification in the " 14324bff34e3Sthurlow "section '%s' ignored"), error, sname); 14334bff34e3Sthurlow } 14344bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "domain", &p); 14354bff34e3Sthurlow if (p) { 14364bff34e3Sthurlow nls_str_upper(p, p); 1437613a2f6bSGordon Ross error = smb_ctx_setdomain(ctx, p, 0); 14384bff34e3Sthurlow if (error) 14394bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14404bff34e3Sthurlow "domain specification in the " 14414bff34e3Sthurlow "section '%s' ignored"), error, sname); 14424bff34e3Sthurlow } 14434bff34e3Sthurlow 14444bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "user", &p); 14454bff34e3Sthurlow if (p) { 14464bff34e3Sthurlow error = smb_ctx_setuser(ctx, p, 0); 14474bff34e3Sthurlow if (error) 14484bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14494bff34e3Sthurlow "user specification in the " 14504bff34e3Sthurlow "section '%s' ignored"), error, sname); 14514bff34e3Sthurlow } 14524bff34e3Sthurlow } 14534bff34e3Sthurlow 14544bff34e3Sthurlow if (level == 1) { 14554bff34e3Sthurlow /* Section is: [server] */ 14564bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "addr", &p); 14574bff34e3Sthurlow if (p) { 14584bff34e3Sthurlow error = smb_ctx_setsrvaddr(ctx, p); 14594bff34e3Sthurlow if (error) { 14604bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14614bff34e3Sthurlow "invalid address specified in section %s"), 14624bff34e3Sthurlow 0, sname); 14634bff34e3Sthurlow return (error); 14644bff34e3Sthurlow } 14654bff34e3Sthurlow } 14664bff34e3Sthurlow } 14674bff34e3Sthurlow 14684bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "password", &p); 14694bff34e3Sthurlow if (p) { 14704bff34e3Sthurlow error = smb_ctx_setpassword(ctx, p, 0); 14714bff34e3Sthurlow if (error) 14724bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14734bff34e3Sthurlow "password specification in the section '%s' ignored"), 14744bff34e3Sthurlow error, sname); 14754bff34e3Sthurlow } 14764bff34e3Sthurlow 14774bff34e3Sthurlow return (0); 14784bff34e3Sthurlow } 14794bff34e3Sthurlow 14804bff34e3Sthurlow /* 14814bff34e3Sthurlow * read rc file as follows: 14824bff34e3Sthurlow * 0: read [default] section 14834bff34e3Sthurlow * 1: override with [server] section 14844bff34e3Sthurlow * 2: override with [server:user] section 14854bff34e3Sthurlow * 3: override with [server:user:share] section 14864bff34e3Sthurlow * Since absence of rcfile is not fatal, silently ignore this fact. 14874bff34e3Sthurlow * smb_rc file should be closed by caller. 14884bff34e3Sthurlow */ 14894bff34e3Sthurlow int 14904bff34e3Sthurlow smb_ctx_readrc(struct smb_ctx *ctx) 14914bff34e3Sthurlow { 1492613a2f6bSGordon Ross char *home; 1493613a2f6bSGordon Ross char *sname = NULL; 1494613a2f6bSGordon Ross int sname_max; 1495613a2f6bSGordon Ross int err = 0; 14964bff34e3Sthurlow 1497613a2f6bSGordon Ross if ((home = getenv("HOME")) == NULL) 1498613a2f6bSGordon Ross home = ctx->ct_home; 1499613a2f6bSGordon Ross if ((err = smb_open_rcfile(home)) != 0) { 1500613a2f6bSGordon Ross DPRINT("smb_open_rcfile, err=%d", err); 1501613a2f6bSGordon Ross /* ignore any error here */ 1502613a2f6bSGordon Ross return (0); 1503613a2f6bSGordon Ross } 1504613a2f6bSGordon Ross 1505613a2f6bSGordon Ross sname_max = 3 * SMBIOC_MAX_NAME + 4; 1506613a2f6bSGordon Ross sname = malloc(sname_max); 1507613a2f6bSGordon Ross if (sname == NULL) { 1508613a2f6bSGordon Ross err = ENOMEM; 15094bff34e3Sthurlow goto done; 1510613a2f6bSGordon Ross } 15114bff34e3Sthurlow 15124bff34e3Sthurlow /* 15134bff34e3Sthurlow * default parameters (level=0) 15144bff34e3Sthurlow */ 15154bff34e3Sthurlow smb_ctx_readrcsection(ctx, "default", 0); 15164bff34e3Sthurlow nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 15174bff34e3Sthurlow 15184bff34e3Sthurlow /* 15194bff34e3Sthurlow * If we don't have a server name, we can't read any of the 15204bff34e3Sthurlow * [server...] sections. 15214bff34e3Sthurlow */ 1522613a2f6bSGordon Ross if (ctx->ct_fullserver == NULL) 15234bff34e3Sthurlow goto done; 15244bff34e3Sthurlow /* 15254bff34e3Sthurlow * SERVER parameters. 15264bff34e3Sthurlow */ 1527613a2f6bSGordon Ross smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1); 15284bff34e3Sthurlow 15294bff34e3Sthurlow /* 15304bff34e3Sthurlow * If we don't have a user name, we can't read any of the 15314bff34e3Sthurlow * [server:user...] sections. 15324bff34e3Sthurlow */ 1533613a2f6bSGordon Ross if (ctx->ct_user[0] == 0) 15344bff34e3Sthurlow goto done; 15354bff34e3Sthurlow /* 15364bff34e3Sthurlow * SERVER:USER parameters 15374bff34e3Sthurlow */ 1538613a2f6bSGordon Ross snprintf(sname, sname_max, "%s:%s", 1539613a2f6bSGordon Ross ctx->ct_fullserver, 1540613a2f6bSGordon Ross ctx->ct_user); 15414bff34e3Sthurlow smb_ctx_readrcsection(ctx, sname, 2); 15424bff34e3Sthurlow 1543613a2f6bSGordon Ross 15444bff34e3Sthurlow /* 15454bff34e3Sthurlow * If we don't have a share name, we can't read any of the 15464bff34e3Sthurlow * [server:user:share] sections. 15474bff34e3Sthurlow */ 1548613a2f6bSGordon Ross if (ctx->ct_origshare == NULL) 1549613a2f6bSGordon Ross goto done; 15504bff34e3Sthurlow /* 15514bff34e3Sthurlow * SERVER:USER:SHARE parameters 15524bff34e3Sthurlow */ 1553613a2f6bSGordon Ross snprintf(sname, sname_max, "%s:%s:%s", 1554613a2f6bSGordon Ross ctx->ct_fullserver, 1555613a2f6bSGordon Ross ctx->ct_user, 1556613a2f6bSGordon Ross ctx->ct_origshare); 15574bff34e3Sthurlow smb_ctx_readrcsection(ctx, sname, 3); 15584bff34e3Sthurlow 15594bff34e3Sthurlow done: 1560613a2f6bSGordon Ross if (sname) 1561613a2f6bSGordon Ross free(sname); 1562613a2f6bSGordon Ross smb_close_rcfile(); 15634bff34e3Sthurlow if (smb_debug) 15644bff34e3Sthurlow dump_ctx("after smb_ctx_readrc", ctx); 1565613a2f6bSGordon Ross if (err) 1566613a2f6bSGordon Ross DPRINT("err=%d\n", err); 15674bff34e3Sthurlow 1568613a2f6bSGordon Ross return (err); 15694bff34e3Sthurlow } 1570