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 /* 36*430b4c46SGordon Ross * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 3715359501SGordon Ross * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 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" 689c9af259SGordon Ross #include "private.h" 69613a2f6bSGordon Ross #include "ntlm.h" 704bff34e3Sthurlow 71613a2f6bSGordon Ross #ifndef FALSE 72613a2f6bSGordon Ross #define FALSE 0 73613a2f6bSGordon Ross #endif 74613a2f6bSGordon Ross #ifndef TRUE 75613a2f6bSGordon Ross #define TRUE 1 76613a2f6bSGordon Ross #endif 774bff34e3Sthurlow 7815359501SGordon Ross struct nv { 7915359501SGordon Ross char *name; 8015359501SGordon Ross int value; 8115359501SGordon Ross }; 824bff34e3Sthurlow 834bff34e3Sthurlow /* These two may be set by commands. */ 844bff34e3Sthurlow int smb_debug, smb_verbose; 854bff34e3Sthurlow 864bff34e3Sthurlow /* 87613a2f6bSGordon Ross * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt 88613a2f6bSGordon Ross */ 89613a2f6bSGordon Ross const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:"; 90613a2f6bSGordon Ross 91613a2f6bSGordon Ross /* 92*430b4c46SGordon Ross * Defaults for new contexts (connections to servers). 93*430b4c46SGordon Ross * These are set by smbfs_set_default_... 94*430b4c46SGordon Ross */ 95*430b4c46SGordon Ross static char default_domain[SMBIOC_MAX_NAME]; 96*430b4c46SGordon Ross static char default_user[SMBIOC_MAX_NAME]; 97*430b4c46SGordon Ross 98*430b4c46SGordon Ross 99*430b4c46SGordon Ross /* 1009c9af259SGordon Ross * Give the RPC library a callback hook that will be 1019c9af259SGordon Ross * called whenever we destroy or reinit an smb_ctx_t. 1029c9af259SGordon Ross * The name rpc_cleanup_smbctx() is legacy, and was 1039c9af259SGordon Ross * originally a direct call into the RPC code. 1044bff34e3Sthurlow */ 1059c9af259SGordon Ross static smb_ctx_close_hook_t close_hook; 1064bff34e3Sthurlow static void 1074bff34e3Sthurlow rpc_cleanup_smbctx(struct smb_ctx *ctx) 1084bff34e3Sthurlow { 1099c9af259SGordon Ross if (close_hook) 1109c9af259SGordon Ross (*close_hook)(ctx); 1114bff34e3Sthurlow } 1129c9af259SGordon Ross void 1139c9af259SGordon Ross smb_ctx_set_close_hook(smb_ctx_close_hook_t hook) 1149c9af259SGordon Ross { 1159c9af259SGordon Ross close_hook = hook; 1169c9af259SGordon Ross } 1174bff34e3Sthurlow 1184bff34e3Sthurlow void 1194bff34e3Sthurlow dump_ctx_flags(int flags) 1204bff34e3Sthurlow { 1214bff34e3Sthurlow printf(" Flags: "); 1224bff34e3Sthurlow if (flags == 0) 1234bff34e3Sthurlow printf("0"); 1244bff34e3Sthurlow if (flags & SMBCF_NOPWD) 1254bff34e3Sthurlow printf("NOPWD "); 1264bff34e3Sthurlow if (flags & SMBCF_SRIGHTS) 1274bff34e3Sthurlow printf("SRIGHTS "); 1284bff34e3Sthurlow if (flags & SMBCF_LOCALE) 1294bff34e3Sthurlow printf("LOCALE "); 1304bff34e3Sthurlow if (flags & SMBCF_CMD_DOM) 1314bff34e3Sthurlow printf("CMD_DOM "); 1324bff34e3Sthurlow if (flags & SMBCF_CMD_USR) 1334bff34e3Sthurlow printf("CMD_USR "); 1344bff34e3Sthurlow if (flags & SMBCF_CMD_PW) 1354bff34e3Sthurlow printf("CMD_PW "); 1364bff34e3Sthurlow if (flags & SMBCF_RESOLVED) 1374bff34e3Sthurlow printf("RESOLVED "); 1384bff34e3Sthurlow if (flags & SMBCF_KCBAD) 1394bff34e3Sthurlow printf("KCBAD "); 1404bff34e3Sthurlow if (flags & SMBCF_KCFOUND) 1414bff34e3Sthurlow printf("KCFOUND "); 1424bff34e3Sthurlow if (flags & SMBCF_BROWSEOK) 1434bff34e3Sthurlow printf("BROWSEOK "); 1444bff34e3Sthurlow if (flags & SMBCF_AUTHREQ) 1454bff34e3Sthurlow printf("AUTHREQ "); 1464bff34e3Sthurlow if (flags & SMBCF_KCSAVE) 1474bff34e3Sthurlow printf("KCSAVE "); 1484bff34e3Sthurlow if (flags & SMBCF_XXX) 1494bff34e3Sthurlow printf("XXX "); 1504bff34e3Sthurlow if (flags & SMBCF_SSNACTIVE) 1514bff34e3Sthurlow printf("SSNACTIVE "); 1524bff34e3Sthurlow if (flags & SMBCF_KCDOMAIN) 1534bff34e3Sthurlow printf("KCDOMAIN "); 1544bff34e3Sthurlow printf("\n"); 1554bff34e3Sthurlow } 1564bff34e3Sthurlow 1574bff34e3Sthurlow void 158613a2f6bSGordon Ross dump_iod_ssn(smb_iod_ssn_t *is) 1594bff34e3Sthurlow { 160613a2f6bSGordon Ross static const char zeros[NTLM_HASH_SZ] = {0}; 161613a2f6bSGordon Ross struct smbioc_ossn *ssn = &is->iod_ossn; 1624bff34e3Sthurlow 163613a2f6bSGordon Ross printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname); 164613a2f6bSGordon Ross dump_sockaddr(&ssn->ssn_srvaddr.sa); 165613a2f6bSGordon Ross printf(" dom=\"%s\", user=\"%s\"\n", 166613a2f6bSGordon Ross ssn->ssn_domain, ssn->ssn_user); 167613a2f6bSGordon Ross printf(" ct_vopt=0x%x, ct_owner=%d\n", 168613a2f6bSGordon Ross ssn->ssn_vopt, ssn->ssn_owner); 169613a2f6bSGordon Ross printf(" ct_authflags=0x%x\n", is->iod_authflags); 170613a2f6bSGordon Ross 171613a2f6bSGordon Ross printf(" ct_nthash:"); 172613a2f6bSGordon Ross if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ)) 173613a2f6bSGordon Ross smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ); 174613a2f6bSGordon Ross else 175613a2f6bSGordon Ross printf(" {0}\n"); 176613a2f6bSGordon Ross 177613a2f6bSGordon Ross printf(" ct_lmhash:"); 178613a2f6bSGordon Ross if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ)) 179613a2f6bSGordon Ross smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ); 180613a2f6bSGordon Ross else 181613a2f6bSGordon Ross printf(" {0}\n"); 1824bff34e3Sthurlow } 1834bff34e3Sthurlow 1844bff34e3Sthurlow void 1854bff34e3Sthurlow dump_ctx(char *where, struct smb_ctx *ctx) 1864bff34e3Sthurlow { 1874bff34e3Sthurlow printf("context %s:\n", where); 1884bff34e3Sthurlow dump_ctx_flags(ctx->ct_flags); 1894bff34e3Sthurlow 190613a2f6bSGordon Ross if (ctx->ct_locname) 1914bff34e3Sthurlow printf(" localname=\"%s\"", ctx->ct_locname); 192613a2f6bSGordon Ross else 193613a2f6bSGordon Ross printf(" localname=NULL"); 1944bff34e3Sthurlow 1954bff34e3Sthurlow if (ctx->ct_fullserver) 1964bff34e3Sthurlow printf(" fullserver=\"%s\"", ctx->ct_fullserver); 1974bff34e3Sthurlow else 1984bff34e3Sthurlow printf(" fullserver=NULL"); 1994bff34e3Sthurlow 200613a2f6bSGordon Ross if (ctx->ct_srvaddr_s) 201613a2f6bSGordon Ross printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s); 2024bff34e3Sthurlow else 203613a2f6bSGordon Ross printf(" srvaddr_s=NULL\n"); 2044bff34e3Sthurlow 205613a2f6bSGordon Ross if (ctx->ct_addrinfo) 206613a2f6bSGordon Ross dump_addrinfo(ctx->ct_addrinfo); 207613a2f6bSGordon Ross else 208613a2f6bSGordon Ross printf(" ct_addrinfo = NULL\n"); 209613a2f6bSGordon Ross 210613a2f6bSGordon Ross dump_iod_ssn(&ctx->ct_iod_ssn); 211613a2f6bSGordon Ross 212613a2f6bSGordon Ross printf(" share_name=\"%s\", share_type=%d\n", 213613a2f6bSGordon Ross ctx->ct_origshare ? ctx->ct_origshare : "", 214613a2f6bSGordon Ross ctx->ct_shtype_req); 215613a2f6bSGordon Ross 216*430b4c46SGordon Ross printf(" ct_home=\"%s\"\n", ctx->ct_home); 217*430b4c46SGordon Ross printf(" ct_rpath=\"%s\"\n", ctx->ct_rpath); 218613a2f6bSGordon Ross } 219613a2f6bSGordon Ross 220613a2f6bSGordon Ross int 221613a2f6bSGordon Ross smb_ctx_alloc(struct smb_ctx **ctx_pp) 222613a2f6bSGordon Ross { 223613a2f6bSGordon Ross smb_ctx_t *ctx; 224613a2f6bSGordon Ross int err; 225613a2f6bSGordon Ross 226613a2f6bSGordon Ross ctx = malloc(sizeof (*ctx)); 227613a2f6bSGordon Ross if (ctx == NULL) 228613a2f6bSGordon Ross return (ENOMEM); 229613a2f6bSGordon Ross err = smb_ctx_init(ctx); 230613a2f6bSGordon Ross if (err != 0) { 231613a2f6bSGordon Ross free(ctx); 232613a2f6bSGordon Ross return (err); 233613a2f6bSGordon Ross } 234613a2f6bSGordon Ross *ctx_pp = ctx; 235613a2f6bSGordon Ross return (0); 2364bff34e3Sthurlow } 2374bff34e3Sthurlow 2384bff34e3Sthurlow /* 239613a2f6bSGordon Ross * Initialize an smb_ctx struct (defaults) 240613a2f6bSGordon Ross */ 241613a2f6bSGordon Ross int 242613a2f6bSGordon Ross smb_ctx_init(struct smb_ctx *ctx) 243613a2f6bSGordon Ross { 244*430b4c46SGordon Ross int error; 245613a2f6bSGordon Ross 246613a2f6bSGordon Ross bzero(ctx, sizeof (*ctx)); 247613a2f6bSGordon Ross 248613a2f6bSGordon Ross error = nb_ctx_create(&ctx->ct_nb); 249613a2f6bSGordon Ross if (error) 250613a2f6bSGordon Ross return (error); 251613a2f6bSGordon Ross 252613a2f6bSGordon Ross ctx->ct_dev_fd = -1; 2536b2bcd8eSGordon Ross ctx->ct_door_fd = -1; 254613a2f6bSGordon Ross ctx->ct_tran_fd = -1; 255613a2f6bSGordon Ross ctx->ct_parsedlevel = SMBL_NONE; 256613a2f6bSGordon Ross ctx->ct_minlevel = SMBL_NONE; 257613a2f6bSGordon Ross ctx->ct_maxlevel = SMBL_PATH; 258613a2f6bSGordon Ross 259613a2f6bSGordon Ross /* Fill in defaults */ 260613a2f6bSGordon Ross ctx->ct_vopt = SMBVOPT_EXT_SEC; 261613a2f6bSGordon Ross ctx->ct_owner = SMBM_ANY_OWNER; 262613a2f6bSGordon Ross ctx->ct_authflags = SMB_AT_DEFAULT; 263613a2f6bSGordon Ross ctx->ct_minauth = SMB_AT_DEFAULT; 264613a2f6bSGordon Ross 265613a2f6bSGordon Ross /* 266*430b4c46SGordon Ross * Default domain, user, ... 267613a2f6bSGordon Ross */ 268*430b4c46SGordon Ross strlcpy(ctx->ct_domain, default_domain, 269*430b4c46SGordon Ross sizeof (ctx->ct_domain)); 270*430b4c46SGordon Ross strlcpy(ctx->ct_user, default_user, 271*430b4c46SGordon Ross sizeof (ctx->ct_user)); 272613a2f6bSGordon Ross 273*430b4c46SGordon Ross return (0); 274613a2f6bSGordon Ross } 275613a2f6bSGordon Ross 276613a2f6bSGordon Ross /* 277613a2f6bSGordon Ross * "Scan" the command line args to find the server name, 278613a2f6bSGordon Ross * user name, and share name, as needed. We need these 279613a2f6bSGordon Ross * before reading the RC files and/or sharectl values. 2804bff34e3Sthurlow * 2814bff34e3Sthurlow * The sequence for getting all the members filled in 2824bff34e3Sthurlow * has some tricky aspects. Here's how it works: 2834bff34e3Sthurlow * 2844bff34e3Sthurlow * The search order for options is as follows: 2854bff34e3Sthurlow * command line options 2864bff34e3Sthurlow * values parsed from UNC path (cmd) 2874bff34e3Sthurlow * values from RC file (per-user) 2884bff34e3Sthurlow * values from SMF (system-wide) 2894bff34e3Sthurlow * built-in defaults 2904bff34e3Sthurlow * 2914bff34e3Sthurlow * Normally, one would simply get all the values starting with 2924bff34e3Sthurlow * the bottom of the above list and working to the top, and 2934bff34e3Sthurlow * overwriting values as you go. But we need an exception. 2944bff34e3Sthurlow * 2954bff34e3Sthurlow * In this function, we parse the UNC path and command line options, 2964bff34e3Sthurlow * because we need (at least) the server name when we're getting the 2974bff34e3Sthurlow * SMF and RC file values. However, values we get from the command 2984bff34e3Sthurlow * should not be overwritten by SMF or RC file parsing, so we mark 2994bff34e3Sthurlow * values from the command as "from CMD" and the RC file parser 3004bff34e3Sthurlow * leaves in place any values so marked. See: SMBCF_CMD_* 3014bff34e3Sthurlow * 3024bff34e3Sthurlow * The semantics of these flags are: "This value came from the 3034bff34e3Sthurlow * current command instance, not from sources that may apply to 3044bff34e3Sthurlow * multiple commands." (Different from the old "FROMUSR" flag.) 3054bff34e3Sthurlow * 3064bff34e3Sthurlow * Note that smb_ctx_opt() is called later to handle the 3074bff34e3Sthurlow * remaining options, which should be ignored here. 3084bff34e3Sthurlow * The (magic) leading ":" in cf_getopt() makes it 3094bff34e3Sthurlow * ignore options not in the options string. 3104bff34e3Sthurlow */ 3114bff34e3Sthurlow int 312613a2f6bSGordon Ross smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv, 3134bff34e3Sthurlow int minlevel, int maxlevel, int sharetype) 3144bff34e3Sthurlow { 315613a2f6bSGordon Ross int ind, opt, error = 0; 3164bff34e3Sthurlow int aflg = 0, uflg = 0; 317613a2f6bSGordon Ross const char *arg; 3184bff34e3Sthurlow 3194bff34e3Sthurlow /* 3204bff34e3Sthurlow * Parse options, if any. Values from here too 3214bff34e3Sthurlow * are marked as "from CMD". 3224bff34e3Sthurlow */ 323613a2f6bSGordon Ross if (argv == NULL) 324613a2f6bSGordon Ross return (0); 325613a2f6bSGordon Ross 326613a2f6bSGordon Ross ctx->ct_minlevel = minlevel; 327613a2f6bSGordon Ross ctx->ct_maxlevel = maxlevel; 328613a2f6bSGordon Ross ctx->ct_shtype_req = sharetype; 329613a2f6bSGordon Ross 330613a2f6bSGordon Ross cf_opt_lock(); 331613a2f6bSGordon Ross /* Careful: no return/goto before cf_opt_unlock! */ 332613a2f6bSGordon Ross while (error == 0) { 333613a2f6bSGordon Ross opt = cf_getopt(argc, argv, STDPARAM_OPT); 334613a2f6bSGordon Ross if (opt == -1) 335613a2f6bSGordon Ross break; 3364bff34e3Sthurlow arg = cf_optarg; 337613a2f6bSGordon Ross /* NB: handle most in smb_ctx_opt */ 3384bff34e3Sthurlow switch (opt) { 3394bff34e3Sthurlow case 'A': 3404bff34e3Sthurlow aflg = 1; 3414bff34e3Sthurlow error = smb_ctx_setuser(ctx, "", TRUE); 3424bff34e3Sthurlow ctx->ct_flags |= SMBCF_NOPWD; 3434bff34e3Sthurlow break; 3444bff34e3Sthurlow case 'U': 3454bff34e3Sthurlow uflg = 1; 3464bff34e3Sthurlow error = smb_ctx_setuser(ctx, arg, TRUE); 3474bff34e3Sthurlow break; 348613a2f6bSGordon Ross default: 349613a2f6bSGordon Ross DPRINT("skip opt=%c", opt); 350613a2f6bSGordon Ross break; 3514bff34e3Sthurlow } 3524bff34e3Sthurlow } 353613a2f6bSGordon Ross ind = cf_optind; 354613a2f6bSGordon Ross arg = argv[ind]; 355613a2f6bSGordon Ross cf_optind = cf_optreset = 1; 356613a2f6bSGordon Ross cf_opt_unlock(); 357613a2f6bSGordon Ross 358613a2f6bSGordon Ross if (error) 359613a2f6bSGordon Ross return (error); 360613a2f6bSGordon Ross 3614bff34e3Sthurlow if (aflg && uflg) { 3624bff34e3Sthurlow printf(gettext("-A and -U flags are exclusive.\n")); 363613a2f6bSGordon Ross return (EINVAL); 3644bff34e3Sthurlow } 3654bff34e3Sthurlow 366613a2f6bSGordon Ross /* 367613a2f6bSGordon Ross * Parse the UNC path. Values from here are 368613a2f6bSGordon Ross * marked as "from CMD". 369613a2f6bSGordon Ross */ 370613a2f6bSGordon Ross for (; ind < argc; ind++) { 371613a2f6bSGordon Ross arg = argv[ind]; 372613a2f6bSGordon Ross if (strncmp(arg, "//", 2) != 0) 373613a2f6bSGordon Ross continue; 374613a2f6bSGordon Ross error = smb_ctx_parseunc(ctx, arg, 375613a2f6bSGordon Ross minlevel, maxlevel, sharetype, &arg); 376613a2f6bSGordon Ross if (error) 377613a2f6bSGordon Ross return (error); 378613a2f6bSGordon Ross break; 379613a2f6bSGordon Ross } 3804bff34e3Sthurlow 3814bff34e3Sthurlow return (error); 3824bff34e3Sthurlow } 3834bff34e3Sthurlow 3844bff34e3Sthurlow void 385613a2f6bSGordon Ross smb_ctx_free(smb_ctx_t *ctx) 386613a2f6bSGordon Ross { 387613a2f6bSGordon Ross smb_ctx_done(ctx); 388613a2f6bSGordon Ross free(ctx); 389613a2f6bSGordon Ross } 390613a2f6bSGordon Ross 391613a2f6bSGordon Ross void 3924bff34e3Sthurlow smb_ctx_done(struct smb_ctx *ctx) 3934bff34e3Sthurlow { 3944bff34e3Sthurlow 3954bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 3964bff34e3Sthurlow 397613a2f6bSGordon Ross if (ctx->ct_dev_fd != -1) { 398613a2f6bSGordon Ross close(ctx->ct_dev_fd); 399613a2f6bSGordon Ross ctx->ct_dev_fd = -1; 4004bff34e3Sthurlow } 4016b2bcd8eSGordon Ross if (ctx->ct_door_fd != -1) { 4026b2bcd8eSGordon Ross close(ctx->ct_door_fd); 4036b2bcd8eSGordon Ross ctx->ct_door_fd = -1; 4046b2bcd8eSGordon Ross } 405613a2f6bSGordon Ross if (ctx->ct_tran_fd != -1) { 406613a2f6bSGordon Ross close(ctx->ct_tran_fd); 407613a2f6bSGordon Ross ctx->ct_tran_fd = -1; 408613a2f6bSGordon Ross } 409613a2f6bSGordon Ross if (ctx->ct_srvaddr_s) { 410613a2f6bSGordon Ross free(ctx->ct_srvaddr_s); 411613a2f6bSGordon Ross ctx->ct_srvaddr_s = NULL; 412613a2f6bSGordon Ross } 413613a2f6bSGordon Ross if (ctx->ct_nb) { 4144bff34e3Sthurlow nb_ctx_done(ctx->ct_nb); 415613a2f6bSGordon Ross ctx->ct_nb = NULL; 416613a2f6bSGordon Ross } 417613a2f6bSGordon Ross if (ctx->ct_locname) { 418613a2f6bSGordon Ross free(ctx->ct_locname); 419613a2f6bSGordon Ross ctx->ct_locname = NULL; 420613a2f6bSGordon Ross } 421613a2f6bSGordon Ross if (ctx->ct_origshare) { 4224bff34e3Sthurlow free(ctx->ct_origshare); 423613a2f6bSGordon Ross ctx->ct_origshare = NULL; 424613a2f6bSGordon Ross } 425613a2f6bSGordon Ross if (ctx->ct_fullserver) { 4264bff34e3Sthurlow free(ctx->ct_fullserver); 427613a2f6bSGordon Ross ctx->ct_fullserver = NULL; 428613a2f6bSGordon Ross } 429613a2f6bSGordon Ross if (ctx->ct_addrinfo) { 430613a2f6bSGordon Ross freeaddrinfo(ctx->ct_addrinfo); 431613a2f6bSGordon Ross ctx->ct_addrinfo = NULL; 432613a2f6bSGordon Ross } 433*430b4c46SGordon Ross if (ctx->ct_home) { 434613a2f6bSGordon Ross free(ctx->ct_home); 435*430b4c46SGordon Ross ctx->ct_home = NULL; 436*430b4c46SGordon Ross } 437*430b4c46SGordon Ross if (ctx->ct_rpath) { 438*430b4c46SGordon Ross free(ctx->ct_rpath); 439*430b4c46SGordon Ross ctx->ct_rpath = NULL; 440*430b4c46SGordon Ross } 441613a2f6bSGordon Ross if (ctx->ct_srv_OS) { 442613a2f6bSGordon Ross free(ctx->ct_srv_OS); 443613a2f6bSGordon Ross ctx->ct_srv_OS = NULL; 444613a2f6bSGordon Ross } 445613a2f6bSGordon Ross if (ctx->ct_srv_LM) { 446613a2f6bSGordon Ross free(ctx->ct_srv_LM); 447613a2f6bSGordon Ross ctx->ct_srv_LM = NULL; 448613a2f6bSGordon Ross } 449613a2f6bSGordon Ross if (ctx->ct_mackey) { 450613a2f6bSGordon Ross free(ctx->ct_mackey); 451613a2f6bSGordon Ross ctx->ct_mackey = NULL; 452613a2f6bSGordon Ross } 4534bff34e3Sthurlow } 4544bff34e3Sthurlow 4554bff34e3Sthurlow /* 4564bff34e3Sthurlow * Parse the UNC path. Here we expect something like 457*430b4c46SGordon Ross * "//[[domain;]user[:password]@]host[/share[/path]]" 4584bff34e3Sthurlow * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 4594bff34e3Sthurlow * Values found here are marked as "from CMD". 4604bff34e3Sthurlow */ 4614bff34e3Sthurlow int 462613a2f6bSGordon Ross smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, 463613a2f6bSGordon Ross int minlevel, int maxlevel, int sharetype, 4644bff34e3Sthurlow const char **next) 4654bff34e3Sthurlow { 4664bff34e3Sthurlow char tmp[1024]; 467*430b4c46SGordon Ross char *host, *share, *path; 468*430b4c46SGordon Ross char *dom, *usr, *pw, *p; 4694bff34e3Sthurlow int error; 4704bff34e3Sthurlow 471613a2f6bSGordon Ross /* 472613a2f6bSGordon Ross * This may be called outside of _scan_argv, 473613a2f6bSGordon Ross * so make sure these get initialized. 474613a2f6bSGordon Ross */ 475613a2f6bSGordon Ross ctx->ct_minlevel = minlevel; 476613a2f6bSGordon Ross ctx->ct_maxlevel = maxlevel; 477613a2f6bSGordon Ross ctx->ct_shtype_req = sharetype; 4784bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_NONE; 479*430b4c46SGordon Ross 480*430b4c46SGordon Ross dom = usr = pw = host = NULL; 481*430b4c46SGordon Ross 482*430b4c46SGordon Ross /* Work on a temporary copy, fix back slashes. */ 483*430b4c46SGordon Ross strlcpy(tmp, unc, sizeof (tmp)); 484*430b4c46SGordon Ross for (p = tmp; *p; p++) 485*430b4c46SGordon Ross if (*p == '\\') 486*430b4c46SGordon Ross *p = '/'; 487*430b4c46SGordon Ross 488*430b4c46SGordon Ross if (tmp[0] != '/' || tmp[1] != '/') { 4894bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 4904bff34e3Sthurlow "UNC should start with '//'"), 0); 491613a2f6bSGordon Ross error = EINVAL; 492613a2f6bSGordon Ross goto out; 4934bff34e3Sthurlow } 494*430b4c46SGordon Ross p = tmp + 2; /* user@host... */ 495*430b4c46SGordon Ross 496*430b4c46SGordon Ross /* Find the share part, if any. */ 497*430b4c46SGordon Ross share = strchr(p, '/'); 498*430b4c46SGordon Ross if (share) 499*430b4c46SGordon Ross *share = '\0'; 500*430b4c46SGordon Ross (void) unpercent(p); /* host component */ 501*430b4c46SGordon Ross 502*430b4c46SGordon Ross /* 503*430b4c46SGordon Ross * Parse the "host" stuff right to left: 504*430b4c46SGordon Ross * 1: trailing "@hostname" (or whole field) 505*430b4c46SGordon Ross * 2: trailing ":password" 506*430b4c46SGordon Ross * 3: trailing "domain;user" (or just user) 507*430b4c46SGordon Ross */ 508*430b4c46SGordon Ross host = strrchr(p, '@'); 509*430b4c46SGordon Ross if (host == NULL) { 510*430b4c46SGordon Ross host = p; /* no user@ prefix */ 511*430b4c46SGordon Ross } else { 512*430b4c46SGordon Ross *host++ = '\0'; 513*430b4c46SGordon Ross 514*430b4c46SGordon Ross /* may have [[domain;]user[:passwd]] */ 515*430b4c46SGordon Ross pw = strchr(p, ':'); 516*430b4c46SGordon Ross if (pw) 517*430b4c46SGordon Ross *pw++ = '\0'; 518*430b4c46SGordon Ross usr = strchr(p, ';'); 519*430b4c46SGordon Ross if (usr) { 520*430b4c46SGordon Ross *usr++ = '\0'; 521*430b4c46SGordon Ross dom = p; 522*430b4c46SGordon Ross } else 523*430b4c46SGordon Ross usr = p; 524*430b4c46SGordon Ross } 525*430b4c46SGordon Ross 526*430b4c46SGordon Ross if (*host == '\0') { 527*430b4c46SGordon Ross smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0); 528613a2f6bSGordon Ross error = EINVAL; 529613a2f6bSGordon Ross goto out; 5304bff34e3Sthurlow } 531*430b4c46SGordon Ross error = smb_ctx_setfullserver(ctx, host); 532*430b4c46SGordon Ross if (error) 533*430b4c46SGordon Ross goto out; 534*430b4c46SGordon Ross ctx->ct_parsedlevel = SMBL_VC; 535*430b4c46SGordon Ross 536*430b4c46SGordon Ross if (dom != NULL) { 537*430b4c46SGordon Ross error = smb_ctx_setdomain(ctx, dom, TRUE); 5384bff34e3Sthurlow if (error) 539613a2f6bSGordon Ross goto out; 5404bff34e3Sthurlow } 541*430b4c46SGordon Ross if (usr != NULL) { 542*430b4c46SGordon Ross if (*usr == '\0') { 543*430b4c46SGordon Ross smb_error(dgettext(TEXT_DOMAIN, 544*430b4c46SGordon Ross "empty user name"), 0); 545*430b4c46SGordon Ross error = EINVAL; 546*430b4c46SGordon Ross goto out; 547*430b4c46SGordon Ross } 5484bff34e3Sthurlow if (ctx->ct_maxlevel < SMBL_VC) { 5494bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5504bff34e3Sthurlow "no user name required"), 0); 551613a2f6bSGordon Ross error = EINVAL; 552613a2f6bSGordon Ross goto out; 5534bff34e3Sthurlow } 554*430b4c46SGordon Ross error = smb_ctx_setuser(ctx, usr, TRUE); 5554bff34e3Sthurlow if (error) 556613a2f6bSGordon Ross goto out; 5574bff34e3Sthurlow } 558*430b4c46SGordon Ross if (pw != NULL) { 559*430b4c46SGordon Ross error = smb_ctx_setpassword(ctx, pw, TRUE); 560*430b4c46SGordon Ross if (error) 561*430b4c46SGordon Ross goto out; 562*430b4c46SGordon Ross } 563*430b4c46SGordon Ross 564*430b4c46SGordon Ross if (share != NULL) { 565*430b4c46SGordon Ross /* restore the slash */ 566*430b4c46SGordon Ross *share = '/'; 567*430b4c46SGordon Ross p = share + 1; 568*430b4c46SGordon Ross 569*430b4c46SGordon Ross /* Find the path part, if any. */ 570*430b4c46SGordon Ross path = strchr(p, '/'); 571*430b4c46SGordon Ross if (path) 572*430b4c46SGordon Ross *path = '\0'; 573*430b4c46SGordon Ross (void) unpercent(p); /* share component */ 574*430b4c46SGordon Ross 575*430b4c46SGordon Ross if (*p == '\0') { 5764bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 577*430b4c46SGordon Ross "empty share name"), 0); 578613a2f6bSGordon Ross error = EINVAL; 579613a2f6bSGordon Ross goto out; 5804bff34e3Sthurlow } 581*430b4c46SGordon Ross if (ctx->ct_maxlevel < SMBL_SHARE) { 5824bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 583*430b4c46SGordon Ross "no share name required"), 0); 584613a2f6bSGordon Ross error = EINVAL; 585613a2f6bSGordon Ross goto out; 5864bff34e3Sthurlow } 5874bff34e3Sthurlow 5884bff34e3Sthurlow /* 589*430b4c46SGordon Ross * Special case UNC names like: 590*430b4c46SGordon Ross * //host/PIPE/endpoint 591*430b4c46SGordon Ross * to have share: IPC$ 5924bff34e3Sthurlow */ 593*430b4c46SGordon Ross if (strcasecmp(p, "PIPE") == 0) { 594*430b4c46SGordon Ross sharetype = USE_IPC; 595*430b4c46SGordon Ross p = "IPC$"; 596*430b4c46SGordon Ross } 597*430b4c46SGordon Ross error = smb_ctx_setshare(ctx, p, sharetype); 5984bff34e3Sthurlow if (error) 599613a2f6bSGordon Ross goto out; 600*430b4c46SGordon Ross ctx->ct_parsedlevel = SMBL_SHARE; 601613a2f6bSGordon Ross 602*430b4c46SGordon Ross if (path) { 603*430b4c46SGordon Ross /* restore the slash */ 604*430b4c46SGordon Ross *path = '/'; 605*430b4c46SGordon Ross p = path + 1; 606*430b4c46SGordon Ross (void) unpercent(p); /* remainder */ 607*430b4c46SGordon Ross free(ctx->ct_rpath); 608*430b4c46SGordon Ross ctx->ct_rpath = strdup(path); 6094bff34e3Sthurlow } 610*430b4c46SGordon Ross } else if (ctx->ct_minlevel >= SMBL_SHARE) { 6114bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0); 612613a2f6bSGordon Ross error = EINVAL; 613613a2f6bSGordon Ross goto out; 6144bff34e3Sthurlow } 615*430b4c46SGordon Ross 616613a2f6bSGordon Ross if (next) 617*430b4c46SGordon Ross *next = NULL; 618613a2f6bSGordon Ross 619613a2f6bSGordon Ross out: 620613a2f6bSGordon Ross if (error == 0 && smb_debug > 0) 621613a2f6bSGordon Ross dump_ctx("after smb_ctx_parseunc", ctx); 622613a2f6bSGordon Ross 6234bff34e3Sthurlow return (error); 6244bff34e3Sthurlow } 6254bff34e3Sthurlow 626613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 6274bff34e3Sthurlow int 6284bff34e3Sthurlow smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 6294bff34e3Sthurlow { 6304bff34e3Sthurlow char *cp, *servercs, *localcs; 6314bff34e3Sthurlow int cslen = sizeof (ctx->ct_ssn.ioc_localcs); 6324bff34e3Sthurlow int scslen, lcslen, error; 6334bff34e3Sthurlow 6344bff34e3Sthurlow cp = strchr(arg, ':'); 6354bff34e3Sthurlow lcslen = cp ? (cp - arg) : 0; 6364bff34e3Sthurlow if (lcslen == 0 || lcslen >= cslen) { 6374bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6384bff34e3Sthurlow "invalid local charset specification (%s)"), 0, arg); 6394bff34e3Sthurlow return (EINVAL); 6404bff34e3Sthurlow } 6414bff34e3Sthurlow scslen = (size_t)strlen(++cp); 6424bff34e3Sthurlow if (scslen == 0 || scslen >= cslen) { 6434bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6444bff34e3Sthurlow "invalid server charset specification (%s)"), 0, arg); 6454bff34e3Sthurlow return (EINVAL); 6464bff34e3Sthurlow } 6474bff34e3Sthurlow localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 6484bff34e3Sthurlow localcs[lcslen] = 0; 6494bff34e3Sthurlow servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 6504bff34e3Sthurlow error = nls_setrecode(localcs, servercs); 6514bff34e3Sthurlow if (error == 0) 6524bff34e3Sthurlow return (0); 6534bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6544bff34e3Sthurlow "can't initialize iconv support (%s:%s)"), 6554bff34e3Sthurlow error, localcs, servercs); 6564bff34e3Sthurlow localcs[0] = 0; 6574bff34e3Sthurlow servercs[0] = 0; 6584bff34e3Sthurlow return (error); 6594bff34e3Sthurlow } 660613a2f6bSGordon Ross #endif /* KICONV_SUPPORT */ 661613a2f6bSGordon Ross 662613a2f6bSGordon Ross int 663613a2f6bSGordon Ross smb_ctx_setauthflags(struct smb_ctx *ctx, int flags) 664613a2f6bSGordon Ross { 665613a2f6bSGordon Ross ctx->ct_authflags = flags; 666613a2f6bSGordon Ross return (0); 667613a2f6bSGordon Ross } 6684bff34e3Sthurlow 6694bff34e3Sthurlow int 6704bff34e3Sthurlow smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name) 6714bff34e3Sthurlow { 672613a2f6bSGordon Ross char *p = strdup(name); 673613a2f6bSGordon Ross 674613a2f6bSGordon Ross if (p == NULL) 6754bff34e3Sthurlow return (ENOMEM); 676613a2f6bSGordon Ross if (ctx->ct_fullserver) 677613a2f6bSGordon Ross free(ctx->ct_fullserver); 678613a2f6bSGordon Ross ctx->ct_fullserver = p; 6794bff34e3Sthurlow return (0); 6804bff34e3Sthurlow } 6814bff34e3Sthurlow 682613a2f6bSGordon Ross int 6834bff34e3Sthurlow smb_ctx_setserver(struct smb_ctx *ctx, const char *name) 6844bff34e3Sthurlow { 685613a2f6bSGordon Ross strlcpy(ctx->ct_srvname, name, 686613a2f6bSGordon Ross sizeof (ctx->ct_srvname)); 687613a2f6bSGordon Ross return (0); 6884bff34e3Sthurlow } 6894bff34e3Sthurlow 6904bff34e3Sthurlow int 6914bff34e3Sthurlow smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) 6924bff34e3Sthurlow { 6934bff34e3Sthurlow 694613a2f6bSGordon Ross if (strlen(name) >= sizeof (ctx->ct_user)) { 6954bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6964bff34e3Sthurlow "user name '%s' too long"), 0, name); 6974bff34e3Sthurlow return (ENAMETOOLONG); 6984bff34e3Sthurlow } 6994bff34e3Sthurlow 7004bff34e3Sthurlow /* 7014bff34e3Sthurlow * Don't overwrite a value from the command line 7024bff34e3Sthurlow * with one from anywhere else. 7034bff34e3Sthurlow */ 7044bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR)) 7054bff34e3Sthurlow return (0); 7064bff34e3Sthurlow 707613a2f6bSGordon Ross strlcpy(ctx->ct_user, name, 708613a2f6bSGordon Ross sizeof (ctx->ct_user)); 7094bff34e3Sthurlow 7104bff34e3Sthurlow /* Mark this as "from the command line". */ 7114bff34e3Sthurlow if (from_cmd) 7124bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_USR; 7134bff34e3Sthurlow 7144bff34e3Sthurlow return (0); 7154bff34e3Sthurlow } 7164bff34e3Sthurlow 7174bff34e3Sthurlow /* 7184bff34e3Sthurlow * Don't overwrite a domain name from the 7194bff34e3Sthurlow * command line with one from anywhere else. 7204bff34e3Sthurlow * See smb_ctx_init() for notes about this. 7214bff34e3Sthurlow */ 7224bff34e3Sthurlow int 723613a2f6bSGordon Ross smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd) 7244bff34e3Sthurlow { 7254bff34e3Sthurlow 726613a2f6bSGordon Ross if (strlen(name) >= sizeof (ctx->ct_domain)) { 7274bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 7284bff34e3Sthurlow "workgroup name '%s' too long"), 0, name); 7294bff34e3Sthurlow return (ENAMETOOLONG); 7304bff34e3Sthurlow } 7314bff34e3Sthurlow 7324bff34e3Sthurlow /* 7334bff34e3Sthurlow * Don't overwrite a value from the command line 7344bff34e3Sthurlow * with one from anywhere else. 7354bff34e3Sthurlow */ 7364bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM)) 7374bff34e3Sthurlow return (0); 7384bff34e3Sthurlow 739613a2f6bSGordon Ross strlcpy(ctx->ct_domain, name, 740613a2f6bSGordon Ross sizeof (ctx->ct_domain)); 7414bff34e3Sthurlow 7424bff34e3Sthurlow /* Mark this as "from the command line". */ 7434bff34e3Sthurlow if (from_cmd) 7444bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_DOM; 7454bff34e3Sthurlow 7464bff34e3Sthurlow return (0); 7474bff34e3Sthurlow } 7484bff34e3Sthurlow 7494bff34e3Sthurlow int 7504bff34e3Sthurlow smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd) 7514bff34e3Sthurlow { 752613a2f6bSGordon Ross int err; 7534bff34e3Sthurlow 754613a2f6bSGordon Ross if (passwd == NULL) 7554bff34e3Sthurlow return (EINVAL); 756613a2f6bSGordon Ross if (strlen(passwd) >= sizeof (ctx->ct_password)) { 7574bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0); 7584bff34e3Sthurlow return (ENAMETOOLONG); 7594bff34e3Sthurlow } 7604bff34e3Sthurlow 7614bff34e3Sthurlow /* 762613a2f6bSGordon Ross * If called again after comand line parsing, 763613a2f6bSGordon Ross * don't overwrite a value from the command line 764613a2f6bSGordon Ross * with one from any stored config. 7654bff34e3Sthurlow */ 7664bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW)) 7674bff34e3Sthurlow return (0); 7684bff34e3Sthurlow 769613a2f6bSGordon Ross memset(ctx->ct_password, 0, sizeof (ctx->ct_password)); 7704bff34e3Sthurlow if (strncmp(passwd, "$$1", 3) == 0) 77102d09e03SGordon Ross (void) smb_simpledecrypt(ctx->ct_password, passwd); 7724bff34e3Sthurlow else 773613a2f6bSGordon Ross strlcpy(ctx->ct_password, passwd, 774613a2f6bSGordon Ross sizeof (ctx->ct_password)); 775613a2f6bSGordon Ross 776613a2f6bSGordon Ross /* 777613a2f6bSGordon Ross * Compute LM hash, NT hash. 778613a2f6bSGordon Ross */ 779613a2f6bSGordon Ross if (ctx->ct_password[0]) { 780613a2f6bSGordon Ross err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password); 781613a2f6bSGordon Ross if (err != 0) 782613a2f6bSGordon Ross return (err); 783613a2f6bSGordon Ross err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password); 784613a2f6bSGordon Ross if (err != 0) 785613a2f6bSGordon Ross return (err); 786613a2f6bSGordon Ross } 7874bff34e3Sthurlow 7884bff34e3Sthurlow /* Mark this as "from the command line". */ 7894bff34e3Sthurlow if (from_cmd) 7904bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_PW; 7914bff34e3Sthurlow 7924bff34e3Sthurlow return (0); 7934bff34e3Sthurlow } 7944bff34e3Sthurlow 795613a2f6bSGordon Ross /* 796613a2f6bSGordon Ross * Use this to set NTLM auth. info (hashes) 797613a2f6bSGordon Ross * when we don't have the password. 798613a2f6bSGordon Ross */ 799613a2f6bSGordon Ross int 800613a2f6bSGordon Ross smb_ctx_setpwhash(smb_ctx_t *ctx, 801613a2f6bSGordon Ross const uchar_t *nthash, const uchar_t *lmhash) 802613a2f6bSGordon Ross { 803613a2f6bSGordon Ross 804613a2f6bSGordon Ross /* Need ct_password to be non-null. */ 805613a2f6bSGordon Ross if (ctx->ct_password[0] == '\0') 806613a2f6bSGordon Ross strlcpy(ctx->ct_password, "$HASH", 807613a2f6bSGordon Ross sizeof (ctx->ct_password)); 808613a2f6bSGordon Ross 809613a2f6bSGordon Ross /* 810613a2f6bSGordon Ross * Compute LM hash, NT hash. 811613a2f6bSGordon Ross */ 812613a2f6bSGordon Ross memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ); 813613a2f6bSGordon Ross 814613a2f6bSGordon Ross /* The LM hash is optional */ 815613a2f6bSGordon Ross if (lmhash) { 816613a2f6bSGordon Ross memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ); 817613a2f6bSGordon Ross } 818613a2f6bSGordon Ross 819613a2f6bSGordon Ross return (0); 820613a2f6bSGordon Ross } 821613a2f6bSGordon Ross 8224bff34e3Sthurlow int 8234bff34e3Sthurlow smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 8244bff34e3Sthurlow { 825613a2f6bSGordon Ross if (strlen(share) >= SMBIOC_MAX_NAME) { 8264bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 8274bff34e3Sthurlow "share name '%s' too long"), 0, share); 8284bff34e3Sthurlow return (ENAMETOOLONG); 8294bff34e3Sthurlow } 8304bff34e3Sthurlow if (ctx->ct_origshare) 8314bff34e3Sthurlow free(ctx->ct_origshare); 8324bff34e3Sthurlow if ((ctx->ct_origshare = strdup(share)) == NULL) 8334bff34e3Sthurlow return (ENOMEM); 834613a2f6bSGordon Ross 835613a2f6bSGordon Ross ctx->ct_shtype_req = stype; 836613a2f6bSGordon Ross 8374bff34e3Sthurlow return (0); 8384bff34e3Sthurlow } 8394bff34e3Sthurlow 8404bff34e3Sthurlow int 8414bff34e3Sthurlow smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 8424bff34e3Sthurlow { 8434bff34e3Sthurlow if (addr == NULL || addr[0] == 0) 8444bff34e3Sthurlow return (EINVAL); 845613a2f6bSGordon Ross if (ctx->ct_srvaddr_s) 846613a2f6bSGordon Ross free(ctx->ct_srvaddr_s); 847613a2f6bSGordon Ross if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL) 8484bff34e3Sthurlow return (ENOMEM); 8494bff34e3Sthurlow return (0); 8504bff34e3Sthurlow } 8514bff34e3Sthurlow 8528eb99b82SGordon Ross /* 8538eb99b82SGordon Ross * API for library caller to set signing enabled, required 8548eb99b82SGordon Ross * Note: if not enable, ignore require 8558eb99b82SGordon Ross */ 8568eb99b82SGordon Ross int 8578eb99b82SGordon Ross smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require) 8588eb99b82SGordon Ross { 8598eb99b82SGordon Ross ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK; 8608eb99b82SGordon Ross if (enable) { 8618eb99b82SGordon Ross ctx->ct_vopt |= SMBVOPT_SIGNING_ENABLED; 8628eb99b82SGordon Ross if (require) 8638eb99b82SGordon Ross ctx->ct_vopt |= SMBVOPT_SIGNING_REQUIRED; 8648eb99b82SGordon Ross } 8658eb99b82SGordon Ross return (0); 8668eb99b82SGordon Ross } 8678eb99b82SGordon Ross 8684bff34e3Sthurlow static int 8694bff34e3Sthurlow smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 8704bff34e3Sthurlow { 8714bff34e3Sthurlow struct group gr; 8724bff34e3Sthurlow struct passwd pw; 8734bff34e3Sthurlow char buf[NSS_BUFLEN_PASSWD]; 8744bff34e3Sthurlow char *cp; 8754bff34e3Sthurlow 8764bff34e3Sthurlow cp = strchr(pair, ':'); 8774bff34e3Sthurlow if (cp) { 8784bff34e3Sthurlow *cp++ = '\0'; 879613a2f6bSGordon Ross if (*cp && gid) { 8804bff34e3Sthurlow if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) { 8814bff34e3Sthurlow *gid = gr.gr_gid; 8824bff34e3Sthurlow } else 8834bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 8844bff34e3Sthurlow "Invalid group name %s, ignored"), 0, cp); 8854bff34e3Sthurlow } 8864bff34e3Sthurlow } 8874bff34e3Sthurlow if (*pair) { 8884bff34e3Sthurlow if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) { 8894bff34e3Sthurlow *uid = pw.pw_uid; 8904bff34e3Sthurlow } else 8914bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 8924bff34e3Sthurlow "Invalid user name %s, ignored"), 0, pair); 8934bff34e3Sthurlow } 8944bff34e3Sthurlow 8954bff34e3Sthurlow return (0); 8964bff34e3Sthurlow } 8974bff34e3Sthurlow 8984bff34e3Sthurlow /* 89915359501SGordon Ross * Suport a securty options arg, i.e. -S noext,lm,ntlm 90015359501SGordon Ross * for testing various type of authenticators. 90115359501SGordon Ross */ 90215359501SGordon Ross static struct nv 90315359501SGordon Ross sectype_table[] = { 90415359501SGordon Ross /* noext - handled below */ 90515359501SGordon Ross { "anon", SMB_AT_ANON }, 90615359501SGordon Ross { "lm", SMB_AT_LM1 }, 90715359501SGordon Ross { "ntlm", SMB_AT_NTLM1 }, 90815359501SGordon Ross { "ntlm2", SMB_AT_NTLM2 }, 90915359501SGordon Ross { "krb5", SMB_AT_KRB5 }, 91015359501SGordon Ross { NULL, 0 }, 91115359501SGordon Ross }; 91215359501SGordon Ross int 91315359501SGordon Ross smb_parse_secopts(struct smb_ctx *ctx, const char *arg) 91415359501SGordon Ross { 91515359501SGordon Ross const char *sep = ":;,"; 91615359501SGordon Ross const char *p = arg; 91715359501SGordon Ross struct nv *nv; 91815359501SGordon Ross int nlen, tlen; 91915359501SGordon Ross int authflags = 0; 92015359501SGordon Ross 92115359501SGordon Ross for (;;) { 92215359501SGordon Ross /* skip separators */ 92315359501SGordon Ross tlen = strspn(p, sep); 92415359501SGordon Ross p += tlen; 92515359501SGordon Ross 92615359501SGordon Ross nlen = strcspn(p, sep); 92715359501SGordon Ross if (nlen == 0) 92815359501SGordon Ross break; 92915359501SGordon Ross 93015359501SGordon Ross if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) { 93115359501SGordon Ross /* Don't offer extended security. */ 93215359501SGordon Ross ctx->ct_vopt &= ~SMBVOPT_EXT_SEC; 93315359501SGordon Ross p += nlen; 93415359501SGordon Ross continue; 93515359501SGordon Ross } 93615359501SGordon Ross 93715359501SGordon Ross /* This is rarely called, so not optimized. */ 93815359501SGordon Ross for (nv = sectype_table; nv->name; nv++) { 93915359501SGordon Ross tlen = strlen(nv->name); 94015359501SGordon Ross if (tlen == nlen && 0 == strncmp(p, nv->name, tlen)) 94115359501SGordon Ross break; 94215359501SGordon Ross } 94315359501SGordon Ross if (nv->name == NULL) { 94415359501SGordon Ross smb_error(dgettext(TEXT_DOMAIN, 94515359501SGordon Ross "%s: invalid security options"), 0, p); 94615359501SGordon Ross return (EINVAL); 94715359501SGordon Ross } 94815359501SGordon Ross authflags |= nv->value; 94915359501SGordon Ross p += nlen; 95015359501SGordon Ross } 95115359501SGordon Ross 95215359501SGordon Ross if (authflags) 95315359501SGordon Ross ctx->ct_authflags = authflags; 95415359501SGordon Ross 95515359501SGordon Ross return (0); 95615359501SGordon Ross } 95715359501SGordon Ross 95815359501SGordon Ross /* 9594bff34e3Sthurlow * Commands use this with getopt. See: 9604bff34e3Sthurlow * STDPARAM_OPT, STDPARAM_ARGS 9614bff34e3Sthurlow * Called after smb_ctx_readrc(). 9624bff34e3Sthurlow */ 9634bff34e3Sthurlow int 9644bff34e3Sthurlow smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 9654bff34e3Sthurlow { 9664bff34e3Sthurlow int error = 0; 9674bff34e3Sthurlow char *p, *cp; 9684bff34e3Sthurlow char tmp[1024]; 9694bff34e3Sthurlow 9704bff34e3Sthurlow switch (opt) { 9714bff34e3Sthurlow case 'A': 9724bff34e3Sthurlow case 'U': 9734bff34e3Sthurlow /* Handled in smb_ctx_init() */ 9744bff34e3Sthurlow break; 9754bff34e3Sthurlow case 'I': 9764bff34e3Sthurlow error = smb_ctx_setsrvaddr(ctx, arg); 9774bff34e3Sthurlow break; 9784bff34e3Sthurlow case 'M': 979613a2f6bSGordon Ross /* share connect rights - ignored */ 9804bff34e3Sthurlow ctx->ct_flags |= SMBCF_SRIGHTS; 9814bff34e3Sthurlow break; 9824bff34e3Sthurlow case 'N': 9834bff34e3Sthurlow ctx->ct_flags |= SMBCF_NOPWD; 9844bff34e3Sthurlow break; 9854bff34e3Sthurlow case 'O': 9864bff34e3Sthurlow p = strdup(arg); 9874bff34e3Sthurlow cp = strchr(p, '/'); 988613a2f6bSGordon Ross if (cp) 989613a2f6bSGordon Ross *cp = '\0'; 990613a2f6bSGordon Ross error = smb_parse_owner(cp, &ctx->ct_owner, NULL); 9914bff34e3Sthurlow free(p); 9924bff34e3Sthurlow break; 9934bff34e3Sthurlow case 'P': 994613a2f6bSGordon Ross /* ctx->ct_vopt |= SMBCOPT_PERMANENT; */ 9954bff34e3Sthurlow break; 9964bff34e3Sthurlow case 'R': 997613a2f6bSGordon Ross /* retry count - ignored */ 9984bff34e3Sthurlow break; 99915359501SGordon Ross case 'S': 100015359501SGordon Ross /* Security options (undocumented, just for tests) */ 100115359501SGordon Ross error = smb_parse_secopts(ctx, arg); 100215359501SGordon Ross break; 10034bff34e3Sthurlow case 'T': 1004613a2f6bSGordon Ross /* timeout - ignored */ 10054bff34e3Sthurlow break; 1006613a2f6bSGordon Ross case 'D': /* domain */ 1007613a2f6bSGordon Ross case 'W': /* workgroup (legacy alias) */ 1008613a2f6bSGordon Ross error = smb_ctx_setdomain(ctx, tmp, TRUE); 10094bff34e3Sthurlow break; 10104bff34e3Sthurlow } 10114bff34e3Sthurlow return (error); 10124bff34e3Sthurlow } 10134bff34e3Sthurlow 10144bff34e3Sthurlow 1015613a2f6bSGordon Ross /* 1016613a2f6bSGordon Ross * Original code injected iconv tables into the kernel. 1017613a2f6bSGordon Ross * Not sure if we'll need this or not... REVISIT 1018613a2f6bSGordon Ross */ 1019613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 10204bff34e3Sthurlow static int 10214bff34e3Sthurlow smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl) 10224bff34e3Sthurlow { 1023613a2f6bSGordon Ross int error = 0; 10244bff34e3Sthurlow 10254bff34e3Sthurlow error = kiconv_add_xlat_table(to, from, tbl); 10264bff34e3Sthurlow if (error && error != EEXIST) { 10274bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10284bff34e3Sthurlow "can not setup kernel iconv table (%s:%s)"), 10294bff34e3Sthurlow error, from, to); 10304bff34e3Sthurlow return (error); 10314bff34e3Sthurlow } 1032613a2f6bSGordon Ross return (error); 10334bff34e3Sthurlow } 1034613a2f6bSGordon Ross #endif /* KICONV_SUPPORT */ 10354bff34e3Sthurlow 10364bff34e3Sthurlow /* 1037613a2f6bSGordon Ross * Verify context info. before connect operation(s), 10384bff34e3Sthurlow * lookup specified server and try to fill all forgotten fields. 1039613a2f6bSGordon Ross * Legacy name used by commands. 10404bff34e3Sthurlow */ 10414bff34e3Sthurlow int 10424bff34e3Sthurlow smb_ctx_resolve(struct smb_ctx *ctx) 10434bff34e3Sthurlow { 10444bff34e3Sthurlow struct smbioc_ossn *ssn = &ctx->ct_ssn; 1045613a2f6bSGordon Ross int error = 0; 1046613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 10474bff34e3Sthurlow uchar_t cstbl[256]; 10484bff34e3Sthurlow uint_t i; 1049613a2f6bSGordon Ross #endif 10504bff34e3Sthurlow 105115359501SGordon Ross if (smb_debug) 105215359501SGordon Ross dump_ctx("before smb_ctx_resolve", ctx); 105315359501SGordon Ross 10544bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_RESOLVED; 1055613a2f6bSGordon Ross 1056613a2f6bSGordon Ross if (ctx->ct_fullserver == NULL) { 10574bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10584bff34e3Sthurlow "no server name specified"), 0); 10594bff34e3Sthurlow return (EINVAL); 10604bff34e3Sthurlow } 1061613a2f6bSGordon Ross 1062613a2f6bSGordon Ross if (ctx->ct_minlevel >= SMBL_SHARE && 1063613a2f6bSGordon Ross ctx->ct_origshare == NULL) { 10644bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10654bff34e3Sthurlow "no share name specified for %s@%s"), 1066613a2f6bSGordon Ross 0, ssn->ssn_user, ctx->ct_fullserver); 10674bff34e3Sthurlow return (EINVAL); 10684bff34e3Sthurlow } 10694bff34e3Sthurlow error = nb_ctx_resolve(ctx->ct_nb); 10704bff34e3Sthurlow if (error) 10714bff34e3Sthurlow return (error); 1072613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 10734bff34e3Sthurlow if (ssn->ioc_localcs[0] == 0) 10744bff34e3Sthurlow strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ 10754bff34e3Sthurlow error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 10764bff34e3Sthurlow if (error) 10774bff34e3Sthurlow return (error); 10784bff34e3Sthurlow error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 10794bff34e3Sthurlow if (error) 10804bff34e3Sthurlow return (error); 10814bff34e3Sthurlow if (ssn->ioc_servercs[0] != 0) { 10824bff34e3Sthurlow for (i = 0; i < sizeof (cstbl); i++) 10834bff34e3Sthurlow cstbl[i] = i; 10844bff34e3Sthurlow nls_mem_toext(cstbl, cstbl, sizeof (cstbl)); 10854bff34e3Sthurlow error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, 10864bff34e3Sthurlow cstbl); 10874bff34e3Sthurlow if (error) 10884bff34e3Sthurlow return (error); 10894bff34e3Sthurlow for (i = 0; i < sizeof (cstbl); i++) 10904bff34e3Sthurlow cstbl[i] = i; 10914bff34e3Sthurlow nls_mem_toloc(cstbl, cstbl, sizeof (cstbl)); 10924bff34e3Sthurlow error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, 10934bff34e3Sthurlow cstbl); 10944bff34e3Sthurlow if (error) 10954bff34e3Sthurlow return (error); 10964bff34e3Sthurlow } 1097613a2f6bSGordon Ross #endif /* KICONV_SUPPORT */ 10984bff34e3Sthurlow 10994bff34e3Sthurlow /* 11006b2bcd8eSGordon Ross * Lookup the IP address and fill in ct_addrinfo. 11016b2bcd8eSGordon Ross * 11026b2bcd8eSGordon Ross * Note: smb_ctx_getaddr() returns a EAI_xxx 11036b2bcd8eSGordon Ross * error value like getaddrinfo(3), but this 11046b2bcd8eSGordon Ross * function needs to return an errno value. 11054bff34e3Sthurlow */ 1106613a2f6bSGordon Ross error = smb_ctx_getaddr(ctx); 11074bff34e3Sthurlow if (error) { 11086b2bcd8eSGordon Ross const char *ais = gai_strerror(error); 11094bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1110ae3d7f90SGordon Ross "can't resolve name\"%s\", %s"), 1111ae3d7f90SGordon Ross 0, ctx->ct_fullserver, ais); 11126b2bcd8eSGordon Ross return (ENODATA); 11134bff34e3Sthurlow } 1114613a2f6bSGordon Ross assert(ctx->ct_addrinfo != NULL); 11154bff34e3Sthurlow 11164bff34e3Sthurlow /* 1117613a2f6bSGordon Ross * If we have a user name but no password, 1118613a2f6bSGordon Ross * check for a keychain entry. 1119613a2f6bSGordon Ross * XXX: Only for auth NTLM? 11204bff34e3Sthurlow */ 1121613a2f6bSGordon Ross if (ctx->ct_user[0] == '\0') { 11224bff34e3Sthurlow /* 1123613a2f6bSGordon Ross * No user name (anonymous session). 1124613a2f6bSGordon Ross * The minauth checks do not apply. 11254bff34e3Sthurlow */ 1126613a2f6bSGordon Ross ctx->ct_authflags = SMB_AT_ANON; 1127613a2f6bSGordon Ross } else { 11284bff34e3Sthurlow /* 1129613a2f6bSGordon Ross * Have a user name. 1130613a2f6bSGordon Ross * If we don't have a p/w yet, 1131613a2f6bSGordon Ross * try the keychain. 11324bff34e3Sthurlow */ 1133613a2f6bSGordon Ross if (ctx->ct_password[0] == '\0') 1134613a2f6bSGordon Ross (void) smb_get_keychain(ctx); 1135613a2f6bSGordon Ross /* 1136613a2f6bSGordon Ross * Mask out disallowed auth types. 1137613a2f6bSGordon Ross */ 1138613a2f6bSGordon Ross ctx->ct_authflags &= ctx->ct_minauth; 11394bff34e3Sthurlow } 1140613a2f6bSGordon Ross if (ctx->ct_authflags == 0) { 11414bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1142613a2f6bSGordon Ross "no valid auth. types"), 0); 1143613a2f6bSGordon Ross return (ENOTSUP); 11444bff34e3Sthurlow } 1145613a2f6bSGordon Ross 11464bff34e3Sthurlow ctx->ct_flags |= SMBCF_RESOLVED; 11474bff34e3Sthurlow if (smb_debug) 11484bff34e3Sthurlow dump_ctx("after smb_ctx_resolve", ctx); 11494bff34e3Sthurlow 11504bff34e3Sthurlow return (0); 11514bff34e3Sthurlow } 11524bff34e3Sthurlow 11534bff34e3Sthurlow int 11544bff34e3Sthurlow smb_open_driver() 11554bff34e3Sthurlow { 1156*430b4c46SGordon Ross int fd; 11574bff34e3Sthurlow 11584bff34e3Sthurlow fd = open("/dev/"NSMB_NAME, O_RDWR); 1159613a2f6bSGordon Ross if (fd < 0) { 11604bff34e3Sthurlow return (-1); 11614bff34e3Sthurlow } 11624bff34e3Sthurlow 1163613a2f6bSGordon Ross /* This handle controls per-process resources. */ 1164613a2f6bSGordon Ross (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 1165613a2f6bSGordon Ross 11664bff34e3Sthurlow return (fd); 11674bff34e3Sthurlow } 11684bff34e3Sthurlow 1169613a2f6bSGordon Ross int 11704bff34e3Sthurlow smb_ctx_gethandle(struct smb_ctx *ctx) 11714bff34e3Sthurlow { 1172*430b4c46SGordon Ross int fd, err; 1173*430b4c46SGordon Ross uint32_t version; 11744bff34e3Sthurlow 1175613a2f6bSGordon Ross if (ctx->ct_dev_fd != -1) { 11764bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 1177613a2f6bSGordon Ross close(ctx->ct_dev_fd); 1178613a2f6bSGordon Ross ctx->ct_dev_fd = -1; 11794bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_SSNACTIVE; 11804bff34e3Sthurlow } 11814bff34e3Sthurlow 11824bff34e3Sthurlow fd = smb_open_driver(); 1183*430b4c46SGordon Ross if (fd < 0) { 1184*430b4c46SGordon Ross err = errno; 1185*430b4c46SGordon Ross smb_error(dgettext(TEXT_DOMAIN, 1186*430b4c46SGordon Ross "failed to open driver"), err); 1187*430b4c46SGordon Ross return (err); 1188*430b4c46SGordon Ross } 1189*430b4c46SGordon Ross 1190*430b4c46SGordon Ross /* 1191*430b4c46SGordon Ross * Check the driver version (paranoia) 1192*430b4c46SGordon Ross */ 1193*430b4c46SGordon Ross if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) 1194*430b4c46SGordon Ross version = 0; 1195*430b4c46SGordon Ross if (version != NSMB_VERSION) { 1196*430b4c46SGordon Ross smb_error(dgettext(TEXT_DOMAIN, 1197*430b4c46SGordon Ross "incorrect driver version"), 0); 1198*430b4c46SGordon Ross close(fd); 11994bff34e3Sthurlow return (ENODEV); 1200*430b4c46SGordon Ross } 12014bff34e3Sthurlow 1202613a2f6bSGordon Ross ctx->ct_dev_fd = fd; 12034bff34e3Sthurlow return (0); 12044bff34e3Sthurlow } 12054bff34e3Sthurlow 1206613a2f6bSGordon Ross 1207613a2f6bSGordon Ross /* 1208613a2f6bSGordon Ross * Find or create a connection + logon session 1209613a2f6bSGordon Ross */ 12104bff34e3Sthurlow int 1211613a2f6bSGordon Ross smb_ctx_get_ssn(struct smb_ctx *ctx) 12124bff34e3Sthurlow { 1213613a2f6bSGordon Ross int err = 0; 12144bff34e3Sthurlow 1215613a2f6bSGordon Ross if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) 12164bff34e3Sthurlow return (EINVAL); 12174bff34e3Sthurlow 1218613a2f6bSGordon Ross if (ctx->ct_dev_fd < 0) { 1219613a2f6bSGordon Ross if ((err = smb_ctx_gethandle(ctx))) 1220613a2f6bSGordon Ross return (err); 12214bff34e3Sthurlow } 12224bff34e3Sthurlow 12234bff34e3Sthurlow /* 1224613a2f6bSGordon Ross * Check whether the driver already has a VC 1225613a2f6bSGordon Ross * we can use. If so, we're done! 12264bff34e3Sthurlow */ 1227613a2f6bSGordon Ross err = smb_ctx_findvc(ctx); 1228613a2f6bSGordon Ross if (err == 0) { 1229613a2f6bSGordon Ross DPRINT("found an existing VC"); 12304bff34e3Sthurlow } else { 1231613a2f6bSGordon Ross /* 1232613a2f6bSGordon Ross * This calls the IOD to create a new session. 1233613a2f6bSGordon Ross */ 1234613a2f6bSGordon Ross DPRINT("setup a new VC"); 1235613a2f6bSGordon Ross err = smb_ctx_newvc(ctx); 1236613a2f6bSGordon Ross if (err != 0) 1237613a2f6bSGordon Ross return (err); 1238613a2f6bSGordon Ross 1239613a2f6bSGordon Ross /* 1240613a2f6bSGordon Ross * Call findvc again. The new VC sould be 1241613a2f6bSGordon Ross * found in the driver this time. 1242613a2f6bSGordon Ross */ 1243613a2f6bSGordon Ross err = smb_ctx_findvc(ctx); 12444bff34e3Sthurlow } 1245613a2f6bSGordon Ross 1246613a2f6bSGordon Ross return (err); 12474bff34e3Sthurlow } 12484bff34e3Sthurlow 12494bff34e3Sthurlow /* 1250613a2f6bSGordon Ross * Find or create a tree connection 12514bff34e3Sthurlow */ 1252613a2f6bSGordon Ross int 1253613a2f6bSGordon Ross smb_ctx_get_tree(struct smb_ctx *ctx) 1254613a2f6bSGordon Ross { 1255613a2f6bSGordon Ross smbioc_tcon_t *tcon = NULL; 1256613a2f6bSGordon Ross int cmd, err = 0; 1257613a2f6bSGordon Ross 1258613a2f6bSGordon Ross if (ctx->ct_dev_fd < 0 || 1259613a2f6bSGordon Ross ctx->ct_origshare == NULL) { 1260613a2f6bSGordon Ross return (EINVAL); 1261613a2f6bSGordon Ross } 1262613a2f6bSGordon Ross 1263613a2f6bSGordon Ross cmd = SMBIOC_TREE_CONNECT; 1264613a2f6bSGordon Ross tcon = malloc(sizeof (*tcon)); 1265613a2f6bSGordon Ross if (tcon == NULL) 1266613a2f6bSGordon Ross return (ENOMEM); 1267613a2f6bSGordon Ross bzero(tcon, sizeof (*tcon)); 1268613a2f6bSGordon Ross tcon->tc_flags = SMBLK_CREATE; 1269613a2f6bSGordon Ross tcon->tc_opt = 0; 1270613a2f6bSGordon Ross 1271613a2f6bSGordon Ross /* The share name */ 1272613a2f6bSGordon Ross strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare, 1273613a2f6bSGordon Ross sizeof (tcon->tc_sh.sh_name)); 1274613a2f6bSGordon Ross 1275613a2f6bSGordon Ross /* The share "use" type. */ 1276*430b4c46SGordon Ross tcon->tc_sh.sh_use = ctx->ct_shtype_req; 1277613a2f6bSGordon Ross 1278613a2f6bSGordon Ross /* 1279613a2f6bSGordon Ross * Todo: share passwords for share-level security. 1280613a2f6bSGordon Ross * 1281613a2f6bSGordon Ross * The driver does the actual TCON call. 1282613a2f6bSGordon Ross */ 1283613a2f6bSGordon Ross if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) { 1284613a2f6bSGordon Ross err = errno; 12854bff34e3Sthurlow goto out; 12864bff34e3Sthurlow } 1287613a2f6bSGordon Ross 1288613a2f6bSGordon Ross /* 1289613a2f6bSGordon Ross * Check the returned share type 1290613a2f6bSGordon Ross */ 1291*430b4c46SGordon Ross DPRINT("ret. sh_type: \"%d\"", tcon->tc_sh.sh_type); 1292613a2f6bSGordon Ross if (ctx->ct_shtype_req != USE_WILDCARD && 1293*430b4c46SGordon Ross ctx->ct_shtype_req != tcon->tc_sh.sh_type) { 1294613a2f6bSGordon Ross smb_error(dgettext(TEXT_DOMAIN, 1295613a2f6bSGordon Ross "%s: incompatible share type"), 1296613a2f6bSGordon Ross 0, ctx->ct_origshare); 12974bff34e3Sthurlow } 12984bff34e3Sthurlow 12994bff34e3Sthurlow out: 1300613a2f6bSGordon Ross if (tcon != NULL) 1301613a2f6bSGordon Ross free(tcon); 1302613a2f6bSGordon Ross 1303613a2f6bSGordon Ross return (err); 13044bff34e3Sthurlow } 13054bff34e3Sthurlow 13064bff34e3Sthurlow /* 13074bff34e3Sthurlow * Return the hflags2 word for an smb_ctx. 13084bff34e3Sthurlow */ 13094bff34e3Sthurlow int 13104bff34e3Sthurlow smb_ctx_flags2(struct smb_ctx *ctx) 13114bff34e3Sthurlow { 13124bff34e3Sthurlow uint16_t flags2; 13134bff34e3Sthurlow 1314613a2f6bSGordon Ross if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) { 13154bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 13164bff34e3Sthurlow "can't get flags2 for a session"), errno); 13174bff34e3Sthurlow return (-1); 13184bff34e3Sthurlow } 13194bff34e3Sthurlow return (flags2); 13204bff34e3Sthurlow } 13214bff34e3Sthurlow 13224bff34e3Sthurlow /* 1323613a2f6bSGordon Ross * Get the transport level session key. 1324613a2f6bSGordon Ross * Must already have an active SMB session. 1325613a2f6bSGordon Ross */ 1326613a2f6bSGordon Ross int 1327*430b4c46SGordon Ross smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len) 1328613a2f6bSGordon Ross { 1329613a2f6bSGordon Ross if (len < SMBIOC_HASH_SZ) 1330613a2f6bSGordon Ross return (EINVAL); 1331613a2f6bSGordon Ross 1332*430b4c46SGordon Ross if (ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1) 1333613a2f6bSGordon Ross return (errno); 1334613a2f6bSGordon Ross 1335613a2f6bSGordon Ross return (0); 1336613a2f6bSGordon Ross } 1337613a2f6bSGordon Ross 1338613a2f6bSGordon Ross /* 1339613a2f6bSGordon Ross * RC file parsing stuff 1340613a2f6bSGordon Ross */ 1341613a2f6bSGordon Ross 134215359501SGordon Ross static struct nv 134315359501SGordon Ross minauth_table[] = { 1344613a2f6bSGordon Ross /* Allowed auth. types */ 1345613a2f6bSGordon Ross { "kerberos", SMB_AT_KRB5 }, 1346613a2f6bSGordon Ross { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 }, 1347613a2f6bSGordon Ross { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 }, 1348613a2f6bSGordon Ross { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 }, 1349613a2f6bSGordon Ross { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1| 1350613a2f6bSGordon Ross SMB_AT_ANON }, 1351613a2f6bSGordon Ross { NULL } 1352613a2f6bSGordon Ross }; 1353613a2f6bSGordon Ross 1354613a2f6bSGordon Ross 1355613a2f6bSGordon Ross /* 13564bff34e3Sthurlow * level values: 13574bff34e3Sthurlow * 0 - default 13584bff34e3Sthurlow * 1 - server 13594bff34e3Sthurlow * 2 - server:user 13604bff34e3Sthurlow * 3 - server:user:share 13614bff34e3Sthurlow */ 13624bff34e3Sthurlow static int 13634bff34e3Sthurlow smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 13644bff34e3Sthurlow { 13654bff34e3Sthurlow char *p; 13664bff34e3Sthurlow int error; 13674bff34e3Sthurlow 1368613a2f6bSGordon Ross #ifdef KICONV_SUPPORT 13694bff34e3Sthurlow if (level > 0) { 13704bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "charsets", &p); 13714bff34e3Sthurlow if (p) { 13724bff34e3Sthurlow error = smb_ctx_setcharset(ctx, p); 13734bff34e3Sthurlow if (error) 13744bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 13754bff34e3Sthurlow "charset specification in the section '%s' ignored"), 13764bff34e3Sthurlow error, sname); 13774bff34e3Sthurlow } 13784bff34e3Sthurlow } 13794bff34e3Sthurlow #endif 13804bff34e3Sthurlow 13814bff34e3Sthurlow if (level <= 1) { 13824bff34e3Sthurlow /* Section is: [default] or [server] */ 13834bff34e3Sthurlow 13844bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "minauth", &p); 13854bff34e3Sthurlow if (p) { 13864bff34e3Sthurlow /* 13874bff34e3Sthurlow * "minauth" was set in this section; override 13884bff34e3Sthurlow * the current minimum authentication setting. 13894bff34e3Sthurlow */ 1390613a2f6bSGordon Ross struct nv *nvp; 1391613a2f6bSGordon Ross for (nvp = minauth_table; nvp->name; nvp++) 1392613a2f6bSGordon Ross if (strcmp(p, nvp->name) == 0) 1393613a2f6bSGordon Ross break; 1394613a2f6bSGordon Ross if (nvp->name) 1395613a2f6bSGordon Ross ctx->ct_minauth = nvp->value; 1396613a2f6bSGordon Ross else { 13974bff34e3Sthurlow /* 13984bff34e3Sthurlow * Unknown minimum authentication level. 13994bff34e3Sthurlow */ 14004bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14014bff34e3Sthurlow "invalid minimum authentication level \"%s\" specified in the section %s"), 14024bff34e3Sthurlow 0, p, sname); 14034bff34e3Sthurlow return (EINVAL); 14044bff34e3Sthurlow } 14054bff34e3Sthurlow } 14064bff34e3Sthurlow 14079c9af259SGordon Ross rc_getstringptr(smb_rc, sname, "signing", &p); 14089c9af259SGordon Ross if (p) { 14099c9af259SGordon Ross /* 14109c9af259SGordon Ross * "signing" was set in this section; override 141102d09e03SGordon Ross * the current signing settings. Note: 141202d09e03SGordon Ross * setsigning flags are: enable, require 14139c9af259SGordon Ross */ 14149c9af259SGordon Ross if (strcmp(p, "disabled") == 0) { 141502d09e03SGordon Ross (void) smb_ctx_setsigning(ctx, FALSE, FALSE); 14169c9af259SGordon Ross } else if (strcmp(p, "enabled") == 0) { 141702d09e03SGordon Ross (void) smb_ctx_setsigning(ctx, TRUE, FALSE); 14189c9af259SGordon Ross } else if (strcmp(p, "required") == 0) { 141902d09e03SGordon Ross (void) smb_ctx_setsigning(ctx, TRUE, TRUE); 14209c9af259SGordon Ross } else { 14219c9af259SGordon Ross /* 14229c9af259SGordon Ross * Unknown "signing" value. 14239c9af259SGordon Ross */ 14249c9af259SGordon Ross smb_error(dgettext(TEXT_DOMAIN, 14259c9af259SGordon Ross "invalid signing policy \"%s\" specified in the section %s"), 14269c9af259SGordon Ross 0, p, sname); 14279c9af259SGordon Ross return (EINVAL); 14289c9af259SGordon Ross } 14299c9af259SGordon Ross } 14309c9af259SGordon Ross 14314bff34e3Sthurlow /* 14324bff34e3Sthurlow * Domain name. Allow both keywords: 14334bff34e3Sthurlow * "workgroup", "domain" 14344bff34e3Sthurlow * 14354bff34e3Sthurlow * Note: these are NOT marked "from CMD". 14364bff34e3Sthurlow * See long comment at smb_ctx_init() 14374bff34e3Sthurlow */ 14384bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "workgroup", &p); 14394bff34e3Sthurlow if (p) { 1440613a2f6bSGordon Ross error = smb_ctx_setdomain(ctx, p, 0); 14414bff34e3Sthurlow if (error) 14424bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14434bff34e3Sthurlow "workgroup specification in the " 14444bff34e3Sthurlow "section '%s' ignored"), error, sname); 14454bff34e3Sthurlow } 14464bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "domain", &p); 14474bff34e3Sthurlow if (p) { 1448613a2f6bSGordon Ross error = smb_ctx_setdomain(ctx, p, 0); 14494bff34e3Sthurlow if (error) 14504bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14514bff34e3Sthurlow "domain specification in the " 14524bff34e3Sthurlow "section '%s' ignored"), error, sname); 14534bff34e3Sthurlow } 14544bff34e3Sthurlow 14554bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "user", &p); 14564bff34e3Sthurlow if (p) { 14574bff34e3Sthurlow error = smb_ctx_setuser(ctx, p, 0); 14584bff34e3Sthurlow if (error) 14594bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14604bff34e3Sthurlow "user specification in the " 14614bff34e3Sthurlow "section '%s' ignored"), error, sname); 14624bff34e3Sthurlow } 14634bff34e3Sthurlow } 14644bff34e3Sthurlow 14654bff34e3Sthurlow if (level == 1) { 14664bff34e3Sthurlow /* Section is: [server] */ 14674bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "addr", &p); 14684bff34e3Sthurlow if (p) { 14694bff34e3Sthurlow error = smb_ctx_setsrvaddr(ctx, p); 14704bff34e3Sthurlow if (error) { 14714bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14724bff34e3Sthurlow "invalid address specified in section %s"), 14734bff34e3Sthurlow 0, sname); 14744bff34e3Sthurlow return (error); 14754bff34e3Sthurlow } 14764bff34e3Sthurlow } 14774bff34e3Sthurlow } 14784bff34e3Sthurlow 14794bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "password", &p); 14804bff34e3Sthurlow if (p) { 14814bff34e3Sthurlow error = smb_ctx_setpassword(ctx, p, 0); 14824bff34e3Sthurlow if (error) 14834bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 14844bff34e3Sthurlow "password specification in the section '%s' ignored"), 14854bff34e3Sthurlow error, sname); 14864bff34e3Sthurlow } 14874bff34e3Sthurlow 14884bff34e3Sthurlow return (0); 14894bff34e3Sthurlow } 14904bff34e3Sthurlow 14914bff34e3Sthurlow /* 14924bff34e3Sthurlow * read rc file as follows: 14934bff34e3Sthurlow * 0: read [default] section 14944bff34e3Sthurlow * 1: override with [server] section 14954bff34e3Sthurlow * 2: override with [server:user] section 14964bff34e3Sthurlow * 3: override with [server:user:share] section 14974bff34e3Sthurlow * Since absence of rcfile is not fatal, silently ignore this fact. 14984bff34e3Sthurlow * smb_rc file should be closed by caller. 14994bff34e3Sthurlow */ 15004bff34e3Sthurlow int 15014bff34e3Sthurlow smb_ctx_readrc(struct smb_ctx *ctx) 15024bff34e3Sthurlow { 1503*430b4c46SGordon Ross char pwbuf[NSS_BUFLEN_PASSWD]; 1504*430b4c46SGordon Ross struct passwd pw; 1505613a2f6bSGordon Ross char *sname = NULL; 1506613a2f6bSGordon Ross int sname_max; 1507613a2f6bSGordon Ross int err = 0; 15084bff34e3Sthurlow 1509*430b4c46SGordon Ross /* 1510*430b4c46SGordon Ross * If the user name is not specified some other way, 1511*430b4c46SGordon Ross * use the current user name. Also save the homedir. 1512*430b4c46SGordon Ross * NB: ct_home=NULL is allowed, and we don't want to 1513*430b4c46SGordon Ross * bail out with an error for a missing ct_home. 1514*430b4c46SGordon Ross */ 1515*430b4c46SGordon Ross if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) { 1516*430b4c46SGordon Ross if (ctx->ct_user[0] == 0) 1517*430b4c46SGordon Ross (void) smb_ctx_setuser(ctx, pw.pw_name, B_FALSE); 1518*430b4c46SGordon Ross if (ctx->ct_home == NULL) 1519*430b4c46SGordon Ross ctx->ct_home = strdup(pw.pw_dir); 1520*430b4c46SGordon Ross } 1521*430b4c46SGordon Ross 1522*430b4c46SGordon Ross if ((err = smb_open_rcfile(ctx->ct_home)) != 0) { 1523613a2f6bSGordon Ross DPRINT("smb_open_rcfile, err=%d", err); 1524613a2f6bSGordon Ross /* ignore any error here */ 1525613a2f6bSGordon Ross return (0); 1526613a2f6bSGordon Ross } 1527613a2f6bSGordon Ross 1528613a2f6bSGordon Ross sname_max = 3 * SMBIOC_MAX_NAME + 4; 1529613a2f6bSGordon Ross sname = malloc(sname_max); 1530613a2f6bSGordon Ross if (sname == NULL) { 1531613a2f6bSGordon Ross err = ENOMEM; 15324bff34e3Sthurlow goto done; 1533613a2f6bSGordon Ross } 15344bff34e3Sthurlow 15354bff34e3Sthurlow /* 15364bff34e3Sthurlow * default parameters (level=0) 15374bff34e3Sthurlow */ 15384bff34e3Sthurlow smb_ctx_readrcsection(ctx, "default", 0); 15394bff34e3Sthurlow nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 15404bff34e3Sthurlow 15414bff34e3Sthurlow /* 15424bff34e3Sthurlow * If we don't have a server name, we can't read any of the 15434bff34e3Sthurlow * [server...] sections. 15444bff34e3Sthurlow */ 1545613a2f6bSGordon Ross if (ctx->ct_fullserver == NULL) 15464bff34e3Sthurlow goto done; 15474bff34e3Sthurlow /* 15484bff34e3Sthurlow * SERVER parameters. 15494bff34e3Sthurlow */ 1550613a2f6bSGordon Ross smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1); 15514bff34e3Sthurlow 15524bff34e3Sthurlow /* 15534bff34e3Sthurlow * If we don't have a user name, we can't read any of the 15544bff34e3Sthurlow * [server:user...] sections. 15554bff34e3Sthurlow */ 1556613a2f6bSGordon Ross if (ctx->ct_user[0] == 0) 15574bff34e3Sthurlow goto done; 15584bff34e3Sthurlow /* 15594bff34e3Sthurlow * SERVER:USER parameters 15604bff34e3Sthurlow */ 1561613a2f6bSGordon Ross snprintf(sname, sname_max, "%s:%s", 1562613a2f6bSGordon Ross ctx->ct_fullserver, 1563613a2f6bSGordon Ross ctx->ct_user); 15644bff34e3Sthurlow smb_ctx_readrcsection(ctx, sname, 2); 15654bff34e3Sthurlow 1566613a2f6bSGordon Ross 15674bff34e3Sthurlow /* 15684bff34e3Sthurlow * If we don't have a share name, we can't read any of the 15694bff34e3Sthurlow * [server:user:share] sections. 15704bff34e3Sthurlow */ 1571613a2f6bSGordon Ross if (ctx->ct_origshare == NULL) 1572613a2f6bSGordon Ross goto done; 15734bff34e3Sthurlow /* 15744bff34e3Sthurlow * SERVER:USER:SHARE parameters 15754bff34e3Sthurlow */ 1576613a2f6bSGordon Ross snprintf(sname, sname_max, "%s:%s:%s", 1577613a2f6bSGordon Ross ctx->ct_fullserver, 1578613a2f6bSGordon Ross ctx->ct_user, 1579613a2f6bSGordon Ross ctx->ct_origshare); 15804bff34e3Sthurlow smb_ctx_readrcsection(ctx, sname, 3); 15814bff34e3Sthurlow 15824bff34e3Sthurlow done: 1583613a2f6bSGordon Ross if (sname) 1584613a2f6bSGordon Ross free(sname); 1585613a2f6bSGordon Ross smb_close_rcfile(); 15864bff34e3Sthurlow if (smb_debug) 15874bff34e3Sthurlow dump_ctx("after smb_ctx_readrc", ctx); 1588613a2f6bSGordon Ross if (err) 1589613a2f6bSGordon Ross DPRINT("err=%d\n", err); 15904bff34e3Sthurlow 1591613a2f6bSGordon Ross return (err); 15924bff34e3Sthurlow } 1593*430b4c46SGordon Ross 1594*430b4c46SGordon Ross void 1595*430b4c46SGordon Ross smbfs_set_default_domain(const char *domain) 1596*430b4c46SGordon Ross { 1597*430b4c46SGordon Ross strlcpy(default_domain, domain, sizeof (default_domain)); 1598*430b4c46SGordon Ross } 1599*430b4c46SGordon Ross 1600*430b4c46SGordon Ross void 1601*430b4c46SGordon Ross smbfs_set_default_user(const char *user) 1602*430b4c46SGordon Ross { 1603*430b4c46SGordon Ross strlcpy(default_user, user, sizeof (default_user)); 1604*430b4c46SGordon Ross } 1605