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 35*9c9af259SGordon Ross /* 36*9c9af259SGordon Ross * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37*9c9af259SGordon Ross * Use is subject to license terms. 38*9c9af259SGordon 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 614bff34e3Sthurlow #include <kerberosv5/krb5.h> 624bff34e3Sthurlow #include <kerberosv5/com_err.h> 634bff34e3Sthurlow 644bff34e3Sthurlow #include <netsmb/smb_lib.h> 654bff34e3Sthurlow #include <netsmb/netbios.h> 664bff34e3Sthurlow #include <netsmb/nb_lib.h> 674bff34e3Sthurlow #include <netsmb/smb_dev.h> 684bff34e3Sthurlow #include <cflib.h> 694bff34e3Sthurlow #include <charsets.h> 704bff34e3Sthurlow 714bff34e3Sthurlow #include <spnego.h> 724bff34e3Sthurlow #include "derparse.h" 73*9c9af259SGordon Ross #include "private.h" 744bff34e3Sthurlow 754bff34e3Sthurlow extern MECH_OID g_stcMechOIDList []; 764bff34e3Sthurlow 774bff34e3Sthurlow #define POWEROF2(x) (((x) & ((x)-1)) == 0) 784bff34e3Sthurlow 794bff34e3Sthurlow /* These two may be set by commands. */ 804bff34e3Sthurlow int smb_debug, smb_verbose; 814bff34e3Sthurlow 824bff34e3Sthurlow /* 83*9c9af259SGordon Ross * Give the RPC library a callback hook that will be 84*9c9af259SGordon Ross * called whenever we destroy or reinit an smb_ctx_t. 85*9c9af259SGordon Ross * The name rpc_cleanup_smbctx() is legacy, and was 86*9c9af259SGordon Ross * originally a direct call into the RPC code. 874bff34e3Sthurlow */ 88*9c9af259SGordon Ross static smb_ctx_close_hook_t close_hook; 894bff34e3Sthurlow static void 904bff34e3Sthurlow rpc_cleanup_smbctx(struct smb_ctx *ctx) 914bff34e3Sthurlow { 92*9c9af259SGordon Ross if (close_hook) 93*9c9af259SGordon Ross (*close_hook)(ctx); 944bff34e3Sthurlow } 95*9c9af259SGordon Ross void 96*9c9af259SGordon Ross smb_ctx_set_close_hook(smb_ctx_close_hook_t hook) 97*9c9af259SGordon Ross { 98*9c9af259SGordon Ross close_hook = hook; 99*9c9af259SGordon Ross } 1004bff34e3Sthurlow 1014bff34e3Sthurlow void 1024bff34e3Sthurlow dump_ctx_flags(int flags) 1034bff34e3Sthurlow { 1044bff34e3Sthurlow printf(" Flags: "); 1054bff34e3Sthurlow if (flags == 0) 1064bff34e3Sthurlow printf("0"); 1074bff34e3Sthurlow if (flags & SMBCF_NOPWD) 1084bff34e3Sthurlow printf("NOPWD "); 1094bff34e3Sthurlow if (flags & SMBCF_SRIGHTS) 1104bff34e3Sthurlow printf("SRIGHTS "); 1114bff34e3Sthurlow if (flags & SMBCF_LOCALE) 1124bff34e3Sthurlow printf("LOCALE "); 1134bff34e3Sthurlow if (flags & SMBCF_CMD_DOM) 1144bff34e3Sthurlow printf("CMD_DOM "); 1154bff34e3Sthurlow if (flags & SMBCF_CMD_USR) 1164bff34e3Sthurlow printf("CMD_USR "); 1174bff34e3Sthurlow if (flags & SMBCF_CMD_PW) 1184bff34e3Sthurlow printf("CMD_PW "); 1194bff34e3Sthurlow if (flags & SMBCF_RESOLVED) 1204bff34e3Sthurlow printf("RESOLVED "); 1214bff34e3Sthurlow if (flags & SMBCF_KCBAD) 1224bff34e3Sthurlow printf("KCBAD "); 1234bff34e3Sthurlow if (flags & SMBCF_KCFOUND) 1244bff34e3Sthurlow printf("KCFOUND "); 1254bff34e3Sthurlow if (flags & SMBCF_BROWSEOK) 1264bff34e3Sthurlow printf("BROWSEOK "); 1274bff34e3Sthurlow if (flags & SMBCF_AUTHREQ) 1284bff34e3Sthurlow printf("AUTHREQ "); 1294bff34e3Sthurlow if (flags & SMBCF_KCSAVE) 1304bff34e3Sthurlow printf("KCSAVE "); 1314bff34e3Sthurlow if (flags & SMBCF_XXX) 1324bff34e3Sthurlow printf("XXX "); 1334bff34e3Sthurlow if (flags & SMBCF_SSNACTIVE) 1344bff34e3Sthurlow printf("SSNACTIVE "); 1354bff34e3Sthurlow if (flags & SMBCF_KCDOMAIN) 1364bff34e3Sthurlow printf("KCDOMAIN "); 1374bff34e3Sthurlow printf("\n"); 1384bff34e3Sthurlow } 1394bff34e3Sthurlow 1404bff34e3Sthurlow void 1414bff34e3Sthurlow dump_ctx_ssn(struct smbioc_ossn *ssn) 1424bff34e3Sthurlow { 1434bff34e3Sthurlow printf(" srvname=\"%s\", dom=\"%s\", user=\"%s\", password=%s\n", 1444bff34e3Sthurlow ssn->ioc_srvname, ssn->ioc_workgroup, ssn->ioc_user, 1454bff34e3Sthurlow ssn->ioc_password[0] ? "(non-null)" : "NULL"); 1464bff34e3Sthurlow printf(" timeout=%d, retry=%d, owner=%d, group=%d\n", 1474bff34e3Sthurlow ssn->ioc_timeout, ssn->ioc_retrycount, 1484bff34e3Sthurlow ssn->ioc_owner, ssn->ioc_group); 1494bff34e3Sthurlow } 1504bff34e3Sthurlow 1514bff34e3Sthurlow void 1524bff34e3Sthurlow dump_ctx_sh(struct smbioc_oshare *sh) 1534bff34e3Sthurlow { 1544bff34e3Sthurlow printf(" share_name=\"%s\", share_pw=\"%s\"\n", 1554bff34e3Sthurlow sh->ioc_share, sh->ioc_password); 1564bff34e3Sthurlow } 1574bff34e3Sthurlow 1584bff34e3Sthurlow void 1594bff34e3Sthurlow dump_ctx(char *where, struct smb_ctx *ctx) 1604bff34e3Sthurlow { 1614bff34e3Sthurlow printf("context %s:\n", where); 1624bff34e3Sthurlow dump_ctx_flags(ctx->ct_flags); 1634bff34e3Sthurlow 1644bff34e3Sthurlow printf(" localname=\"%s\"", ctx->ct_locname); 1654bff34e3Sthurlow 1664bff34e3Sthurlow if (ctx->ct_fullserver) 1674bff34e3Sthurlow printf(" fullserver=\"%s\"", ctx->ct_fullserver); 1684bff34e3Sthurlow else 1694bff34e3Sthurlow printf(" fullserver=NULL"); 1704bff34e3Sthurlow 1714bff34e3Sthurlow if (ctx->ct_srvaddr) 1724bff34e3Sthurlow printf(" srvaddr=\"%s\"\n", ctx->ct_srvaddr); 1734bff34e3Sthurlow else 1744bff34e3Sthurlow printf(" srvaddr=NULL\n"); 1754bff34e3Sthurlow 1764bff34e3Sthurlow dump_ctx_ssn(&ctx->ct_ssn); 1774bff34e3Sthurlow dump_ctx_sh(&ctx->ct_sh); 1784bff34e3Sthurlow } 1794bff34e3Sthurlow 1804bff34e3Sthurlow /* 1814bff34e3Sthurlow * Initialize an smb_ctx struct. 1824bff34e3Sthurlow * 1834bff34e3Sthurlow * The sequence for getting all the members filled in 1844bff34e3Sthurlow * has some tricky aspects. Here's how it works: 1854bff34e3Sthurlow * 1864bff34e3Sthurlow * The search order for options is as follows: 1874bff34e3Sthurlow * command line options 1884bff34e3Sthurlow * values parsed from UNC path (cmd) 1894bff34e3Sthurlow * values from RC file (per-user) 1904bff34e3Sthurlow * values from SMF (system-wide) 1914bff34e3Sthurlow * built-in defaults 1924bff34e3Sthurlow * 1934bff34e3Sthurlow * Normally, one would simply get all the values starting with 1944bff34e3Sthurlow * the bottom of the above list and working to the top, and 1954bff34e3Sthurlow * overwriting values as you go. But we need an exception. 1964bff34e3Sthurlow * 1974bff34e3Sthurlow * In this function, we parse the UNC path and command line options, 1984bff34e3Sthurlow * because we need (at least) the server name when we're getting the 1994bff34e3Sthurlow * SMF and RC file values. However, values we get from the command 2004bff34e3Sthurlow * should not be overwritten by SMF or RC file parsing, so we mark 2014bff34e3Sthurlow * values from the command as "from CMD" and the RC file parser 2024bff34e3Sthurlow * leaves in place any values so marked. See: SMBCF_CMD_* 2034bff34e3Sthurlow * 2044bff34e3Sthurlow * The semantics of these flags are: "This value came from the 2054bff34e3Sthurlow * current command instance, not from sources that may apply to 2064bff34e3Sthurlow * multiple commands." (Different from the old "FROMUSR" flag.) 2074bff34e3Sthurlow * 2084bff34e3Sthurlow * Note that smb_ctx_opt() is called later to handle the 2094bff34e3Sthurlow * remaining options, which should be ignored here. 2104bff34e3Sthurlow * The (magic) leading ":" in cf_getopt() makes it 2114bff34e3Sthurlow * ignore options not in the options string. 2124bff34e3Sthurlow */ 2134bff34e3Sthurlow int 2144bff34e3Sthurlow smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[], 2154bff34e3Sthurlow int minlevel, int maxlevel, int sharetype) 2164bff34e3Sthurlow { 2174bff34e3Sthurlow int opt, error = 0; 2184bff34e3Sthurlow const char *arg, *cp; 2194bff34e3Sthurlow struct passwd pw; 2204bff34e3Sthurlow char pwbuf[NSS_BUFLEN_PASSWD]; 2214bff34e3Sthurlow int aflg = 0, uflg = 0; 2224bff34e3Sthurlow 2234bff34e3Sthurlow bzero(ctx, sizeof (*ctx)); 2244bff34e3Sthurlow if (sharetype == SMB_ST_DISK) 2254bff34e3Sthurlow ctx->ct_flags |= SMBCF_BROWSEOK; 2264bff34e3Sthurlow error = nb_ctx_create(&ctx->ct_nb); 2274bff34e3Sthurlow if (error) 2284bff34e3Sthurlow return (error); 2294bff34e3Sthurlow 2304bff34e3Sthurlow ctx->ct_fd = -1; 2314bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_NONE; 2324bff34e3Sthurlow ctx->ct_minlevel = minlevel; 2334bff34e3Sthurlow ctx->ct_maxlevel = maxlevel; 2344bff34e3Sthurlow 235*9c9af259SGordon Ross /* Fill in defaults */ 2364bff34e3Sthurlow ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE | SMBVOPT_MINAUTH_NTLM; 237*9c9af259SGordon Ross 2384bff34e3Sthurlow ctx->ct_ssn.ioc_timeout = 15; 2394bff34e3Sthurlow ctx->ct_ssn.ioc_retrycount = 4; 2404bff34e3Sthurlow ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER; 2414bff34e3Sthurlow ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP; 2424bff34e3Sthurlow ctx->ct_ssn.ioc_mode = SMBM_EXEC; 2434bff34e3Sthurlow ctx->ct_ssn.ioc_rights = SMBM_DEFAULT; 2444bff34e3Sthurlow 2454bff34e3Sthurlow ctx->ct_sh.ioc_opt = SMBVOPT_CREATE; 2464bff34e3Sthurlow ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 2474bff34e3Sthurlow ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 2484bff34e3Sthurlow ctx->ct_sh.ioc_mode = SMBM_EXEC; 2494bff34e3Sthurlow ctx->ct_sh.ioc_rights = SMBM_DEFAULT; 2504bff34e3Sthurlow ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 2514bff34e3Sthurlow ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 2524bff34e3Sthurlow 2534bff34e3Sthurlow nb_ctx_setscope(ctx->ct_nb, ""); 2544bff34e3Sthurlow 2554bff34e3Sthurlow /* 2564bff34e3Sthurlow * if the user name is not specified some other way, 2574bff34e3Sthurlow * use the current user name (built-in default) 2584bff34e3Sthurlow */ 2594bff34e3Sthurlow if (getpwuid_r(geteuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) 2604bff34e3Sthurlow smb_ctx_setuser(ctx, pw.pw_name, 0); 2614bff34e3Sthurlow 2624bff34e3Sthurlow /* 2634bff34e3Sthurlow * Set a built-in default domain (workgroup). 2644bff34e3Sthurlow * XXX: What's the best default? Use "?" instead? 2654bff34e3Sthurlow * Using the Windows/NT default for now. 2664bff34e3Sthurlow */ 2674bff34e3Sthurlow smb_ctx_setworkgroup(ctx, "WORKGROUP", 0); 2684bff34e3Sthurlow 2694bff34e3Sthurlow /* 2704bff34e3Sthurlow * Parse the UNC path. Values from here are 2714bff34e3Sthurlow * marked as "from CMD". 2724bff34e3Sthurlow */ 2734bff34e3Sthurlow if (argv == NULL) 2744bff34e3Sthurlow goto done; 2754bff34e3Sthurlow for (opt = 1; opt < argc; opt++) { 2764bff34e3Sthurlow cp = argv[opt]; 2774bff34e3Sthurlow if (strncmp(cp, "//", 2) != 0) 2784bff34e3Sthurlow continue; 2794bff34e3Sthurlow error = smb_ctx_parseunc(ctx, cp, sharetype, &cp); 2804bff34e3Sthurlow if (error) 2814bff34e3Sthurlow return (error); 2824bff34e3Sthurlow break; 2834bff34e3Sthurlow } 2844bff34e3Sthurlow 2854bff34e3Sthurlow /* 2864bff34e3Sthurlow * Parse options, if any. Values from here too 2874bff34e3Sthurlow * are marked as "from CMD". 2884bff34e3Sthurlow */ 2894bff34e3Sthurlow while (error == 0 && (opt = cf_getopt(argc, argv, ":AU:E:L:")) != -1) { 2904bff34e3Sthurlow arg = cf_optarg; 2914bff34e3Sthurlow switch (opt) { 2924bff34e3Sthurlow case 'A': 2934bff34e3Sthurlow aflg = 1; 2944bff34e3Sthurlow error = smb_ctx_setuser(ctx, "", TRUE); 2954bff34e3Sthurlow error = smb_ctx_setpassword(ctx, "", TRUE); 2964bff34e3Sthurlow ctx->ct_flags |= SMBCF_NOPWD; 2974bff34e3Sthurlow break; 2984bff34e3Sthurlow case 'E': 2994bff34e3Sthurlow #if 0 /* We don't support any "charset" stuff. (ignore -E) */ 3004bff34e3Sthurlow error = smb_ctx_setcharset(ctx, arg); 3014bff34e3Sthurlow if (error) 3024bff34e3Sthurlow return (error); 3034bff34e3Sthurlow #endif 3044bff34e3Sthurlow break; 3054bff34e3Sthurlow case 'L': 3064bff34e3Sthurlow #if 0 /* Use the standard environment variables (ignore -L) */ 3074bff34e3Sthurlow error = nls_setlocale(optarg); 3084bff34e3Sthurlow if (error) 3094bff34e3Sthurlow break; 3104bff34e3Sthurlow #endif 3114bff34e3Sthurlow break; 3124bff34e3Sthurlow case 'U': 3134bff34e3Sthurlow uflg = 1; 3144bff34e3Sthurlow error = smb_ctx_setuser(ctx, arg, TRUE); 3154bff34e3Sthurlow break; 3164bff34e3Sthurlow } 3174bff34e3Sthurlow } 3184bff34e3Sthurlow if (aflg && uflg) { 3194bff34e3Sthurlow printf(gettext("-A and -U flags are exclusive.\n")); 3204bff34e3Sthurlow return (1); 3214bff34e3Sthurlow } 3224bff34e3Sthurlow cf_optind = cf_optreset = 1; 3234bff34e3Sthurlow 3244bff34e3Sthurlow done: 3254bff34e3Sthurlow if (smb_debug) 3264bff34e3Sthurlow dump_ctx("after smb_ctx_init", ctx); 3274bff34e3Sthurlow 3284bff34e3Sthurlow return (error); 3294bff34e3Sthurlow } 3304bff34e3Sthurlow 3314bff34e3Sthurlow void 3324bff34e3Sthurlow smb_ctx_done(struct smb_ctx *ctx) 3334bff34e3Sthurlow { 3344bff34e3Sthurlow 3354bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 3364bff34e3Sthurlow 3374bff34e3Sthurlow /* Kerberos stuff. See smb_ctx_krb5init() */ 3384bff34e3Sthurlow if (ctx->ct_krb5ctx) { 3394bff34e3Sthurlow if (ctx->ct_krb5cp) 3404bff34e3Sthurlow krb5_free_principal(ctx->ct_krb5ctx, ctx->ct_krb5cp); 3414bff34e3Sthurlow krb5_free_context(ctx->ct_krb5ctx); 3424bff34e3Sthurlow } 3434bff34e3Sthurlow 3444bff34e3Sthurlow if (ctx->ct_fd != -1) 3454bff34e3Sthurlow close(ctx->ct_fd); 3464bff34e3Sthurlow #if 0 /* XXX: not pointers anymore */ 3474bff34e3Sthurlow if (&ctx->ct_ssn.ioc_server) 3484bff34e3Sthurlow nb_snbfree(&ctx->ct_ssn.ioc_server); 3494bff34e3Sthurlow if (&ctx->ct_ssn.ioc_local) 3504bff34e3Sthurlow nb_snbfree(&ctx->ct_ssn.ioc_local); 3514bff34e3Sthurlow #endif 3524bff34e3Sthurlow if (ctx->ct_srvaddr) 3534bff34e3Sthurlow free(ctx->ct_srvaddr); 3544bff34e3Sthurlow if (ctx->ct_nb) 3554bff34e3Sthurlow nb_ctx_done(ctx->ct_nb); 3564bff34e3Sthurlow if (ctx->ct_secblob) 3574bff34e3Sthurlow free(ctx->ct_secblob); 3584bff34e3Sthurlow if (ctx->ct_origshare) 3594bff34e3Sthurlow free(ctx->ct_origshare); 3604bff34e3Sthurlow if (ctx->ct_fullserver) 3614bff34e3Sthurlow free(ctx->ct_fullserver); 3624bff34e3Sthurlow } 3634bff34e3Sthurlow 3644bff34e3Sthurlow static int 3654bff34e3Sthurlow getsubstring(const char *p, uchar_t sep, char *dest, int maxlen, 3664bff34e3Sthurlow const char **next) 3674bff34e3Sthurlow { 3684bff34e3Sthurlow int len; 3694bff34e3Sthurlow 3704bff34e3Sthurlow maxlen--; 3714bff34e3Sthurlow for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 3724bff34e3Sthurlow if (*p == 0) 3734bff34e3Sthurlow return (EINVAL); 3744bff34e3Sthurlow *dest = *p; 3754bff34e3Sthurlow } 3764bff34e3Sthurlow *dest = 0; 3774bff34e3Sthurlow *next = *p ? p + 1 : p; 3784bff34e3Sthurlow return (0); 3794bff34e3Sthurlow } 3804bff34e3Sthurlow 3814bff34e3Sthurlow /* 3824bff34e3Sthurlow * Parse the UNC path. Here we expect something like 3834bff34e3Sthurlow * "//[workgroup;][user[:password]@]host[/share[/path]]" 3844bff34e3Sthurlow * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 3854bff34e3Sthurlow * Values found here are marked as "from CMD". 3864bff34e3Sthurlow */ 3874bff34e3Sthurlow int 3884bff34e3Sthurlow smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, 3894bff34e3Sthurlow const char **next) 3904bff34e3Sthurlow { 3914bff34e3Sthurlow const char *p = unc; 3924bff34e3Sthurlow char *p1, *colon, *servername; 3934bff34e3Sthurlow char tmp[1024]; 3944bff34e3Sthurlow char tmp2[1024]; 3954bff34e3Sthurlow int error; 3964bff34e3Sthurlow 3974bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_NONE; 3984bff34e3Sthurlow if (*p++ != '/' || *p++ != '/') { 3994bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 4004bff34e3Sthurlow "UNC should start with '//'"), 0); 4014bff34e3Sthurlow return (EINVAL); 4024bff34e3Sthurlow } 4034bff34e3Sthurlow p1 = tmp; 4044bff34e3Sthurlow error = getsubstring(p, ';', p1, sizeof (tmp), &p); 4054bff34e3Sthurlow if (!error) { 4064bff34e3Sthurlow if (*p1 == 0) { 4074bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 4084bff34e3Sthurlow "empty workgroup name"), 0); 4094bff34e3Sthurlow return (EINVAL); 4104bff34e3Sthurlow } 4114bff34e3Sthurlow nls_str_upper(tmp, tmp); 4124bff34e3Sthurlow error = smb_ctx_setworkgroup(ctx, unpercent(tmp), TRUE); 4134bff34e3Sthurlow if (error) 4144bff34e3Sthurlow return (error); 4154bff34e3Sthurlow } 4164bff34e3Sthurlow colon = (char *)p; 4174bff34e3Sthurlow error = getsubstring(p, '@', p1, sizeof (tmp), &p); 4184bff34e3Sthurlow if (!error) { 4194bff34e3Sthurlow if (ctx->ct_maxlevel < SMBL_VC) { 4204bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 4214bff34e3Sthurlow "no user name required"), 0); 4224bff34e3Sthurlow return (EINVAL); 4234bff34e3Sthurlow } 4244bff34e3Sthurlow p1 = strchr(tmp, ':'); 4254bff34e3Sthurlow if (p1) { 4264bff34e3Sthurlow colon += p1 - tmp; 4274bff34e3Sthurlow *p1++ = (char)0; 4284bff34e3Sthurlow error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE); 4294bff34e3Sthurlow if (error) 4304bff34e3Sthurlow return (error); 4314bff34e3Sthurlow if (p - colon > 2) 4324bff34e3Sthurlow memset(colon+1, '*', p - colon - 2); 4334bff34e3Sthurlow } 4344bff34e3Sthurlow p1 = tmp; 4354bff34e3Sthurlow if (*p1 == 0) { 4364bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 4374bff34e3Sthurlow "empty user name"), 0); 4384bff34e3Sthurlow return (EINVAL); 4394bff34e3Sthurlow } 4404bff34e3Sthurlow error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE); 4414bff34e3Sthurlow if (error) 4424bff34e3Sthurlow return (error); 4434bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_VC; 4444bff34e3Sthurlow } 4454bff34e3Sthurlow error = getsubstring(p, '/', p1, sizeof (tmp), &p); 4464bff34e3Sthurlow if (error) { 4474bff34e3Sthurlow error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 4484bff34e3Sthurlow if (error) { 4494bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 4504bff34e3Sthurlow "no server name found"), 0); 4514bff34e3Sthurlow return (error); 4524bff34e3Sthurlow } 4534bff34e3Sthurlow } 4544bff34e3Sthurlow if (*p1 == 0) { 4554bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0); 4564bff34e3Sthurlow return (EINVAL); 4574bff34e3Sthurlow } 4584bff34e3Sthurlow 4594bff34e3Sthurlow 4604bff34e3Sthurlow /* 4614bff34e3Sthurlow * It's safe to uppercase this string, which 4624bff34e3Sthurlow * consists of ascii characters that should 4634bff34e3Sthurlow * be uppercased, %s, and ascii characters representing 4644bff34e3Sthurlow * hex digits 0-9 and A-F (already uppercased, and 4654bff34e3Sthurlow * if not uppercased they need to be). However, 4664bff34e3Sthurlow * it is NOT safe to uppercase after it has been 4674bff34e3Sthurlow * converted, below! 4684bff34e3Sthurlow */ 4694bff34e3Sthurlow 4704bff34e3Sthurlow nls_str_upper(tmp2, tmp); 4714bff34e3Sthurlow 4724bff34e3Sthurlow /* 4734bff34e3Sthurlow * scan for % in the string. 4744bff34e3Sthurlow * If we find one, convert 4754bff34e3Sthurlow * to the assumed codepage. 4764bff34e3Sthurlow */ 4774bff34e3Sthurlow 4784bff34e3Sthurlow if (strchr(tmp2, '%')) { 4794bff34e3Sthurlow /* use the 1st buffer, we don't need the old string */ 4804bff34e3Sthurlow servername = tmp; 4814bff34e3Sthurlow if (!(servername = convert_utf8_to_wincs(unpercent(tmp2)))) { 4824bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "bad server name"), 0); 4834bff34e3Sthurlow return (EINVAL); 4844bff34e3Sthurlow } 4854bff34e3Sthurlow /* 4864bff34e3Sthurlow * Converts utf8 to win equivalent of 4874bff34e3Sthurlow * what is configured on this machine. 4884bff34e3Sthurlow * Note that we are assuming this is the 4894bff34e3Sthurlow * encoding used on the server, and that 4904bff34e3Sthurlow * assumption might be incorrect. This is 4914bff34e3Sthurlow * the best we can do now, and we should 4924bff34e3Sthurlow * move to use port 445 to avoid having 4934bff34e3Sthurlow * to worry about server codepages. 4944bff34e3Sthurlow */ 4954bff34e3Sthurlow } else /* no conversion needed */ 4964bff34e3Sthurlow servername = tmp2; 4974bff34e3Sthurlow 4984bff34e3Sthurlow smb_ctx_setserver(ctx, servername); 4994bff34e3Sthurlow error = smb_ctx_setfullserver(ctx, servername); 5004bff34e3Sthurlow 5014bff34e3Sthurlow if (error) 5024bff34e3Sthurlow return (error); 5034bff34e3Sthurlow if (sharetype == SMB_ST_NONE) { 5044bff34e3Sthurlow *next = p; 5054bff34e3Sthurlow return (0); 5064bff34e3Sthurlow } 5074bff34e3Sthurlow if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 5084bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0); 5094bff34e3Sthurlow return (EINVAL); 5104bff34e3Sthurlow } 5114bff34e3Sthurlow error = getsubstring(p, '/', p1, sizeof (tmp), &p); 5124bff34e3Sthurlow if (error) { 5134bff34e3Sthurlow error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 5144bff34e3Sthurlow if (error) { 5154bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5164bff34e3Sthurlow "unexpected end of line"), 0); 5174bff34e3Sthurlow return (error); 5184bff34e3Sthurlow } 5194bff34e3Sthurlow } 5204bff34e3Sthurlow if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE && 5214bff34e3Sthurlow !(ctx->ct_flags & SMBCF_BROWSEOK)) { 5224bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0); 5234bff34e3Sthurlow return (EINVAL); 5244bff34e3Sthurlow } 5254bff34e3Sthurlow *next = p; 5264bff34e3Sthurlow if (*p1 == 0) 5274bff34e3Sthurlow return (0); 5284bff34e3Sthurlow error = smb_ctx_setshare(ctx, unpercent(p1), sharetype); 5294bff34e3Sthurlow return (error); 5304bff34e3Sthurlow } 5314bff34e3Sthurlow 5324bff34e3Sthurlow int 5334bff34e3Sthurlow smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 5344bff34e3Sthurlow { 5354bff34e3Sthurlow char *cp, *servercs, *localcs; 5364bff34e3Sthurlow int cslen = sizeof (ctx->ct_ssn.ioc_localcs); 5374bff34e3Sthurlow int scslen, lcslen, error; 5384bff34e3Sthurlow 5394bff34e3Sthurlow cp = strchr(arg, ':'); 5404bff34e3Sthurlow lcslen = cp ? (cp - arg) : 0; 5414bff34e3Sthurlow if (lcslen == 0 || lcslen >= cslen) { 5424bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5434bff34e3Sthurlow "invalid local charset specification (%s)"), 0, arg); 5444bff34e3Sthurlow return (EINVAL); 5454bff34e3Sthurlow } 5464bff34e3Sthurlow scslen = (size_t)strlen(++cp); 5474bff34e3Sthurlow if (scslen == 0 || scslen >= cslen) { 5484bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5494bff34e3Sthurlow "invalid server charset specification (%s)"), 0, arg); 5504bff34e3Sthurlow return (EINVAL); 5514bff34e3Sthurlow } 5524bff34e3Sthurlow localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 5534bff34e3Sthurlow localcs[lcslen] = 0; 5544bff34e3Sthurlow servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 5554bff34e3Sthurlow error = nls_setrecode(localcs, servercs); 5564bff34e3Sthurlow if (error == 0) 5574bff34e3Sthurlow return (0); 5584bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5594bff34e3Sthurlow "can't initialize iconv support (%s:%s)"), 5604bff34e3Sthurlow error, localcs, servercs); 5614bff34e3Sthurlow localcs[0] = 0; 5624bff34e3Sthurlow servercs[0] = 0; 5634bff34e3Sthurlow return (error); 5644bff34e3Sthurlow } 5654bff34e3Sthurlow 5664bff34e3Sthurlow int 5674bff34e3Sthurlow smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name) 5684bff34e3Sthurlow { 5694bff34e3Sthurlow ctx->ct_fullserver = strdup(name); 5704bff34e3Sthurlow if (ctx->ct_fullserver == NULL) 5714bff34e3Sthurlow return (ENOMEM); 5724bff34e3Sthurlow return (0); 5734bff34e3Sthurlow } 5744bff34e3Sthurlow 5754bff34e3Sthurlow /* 5764bff34e3Sthurlow * XXX TODO FIXME etc etc 5774bff34e3Sthurlow * If the call to nbns_getnodestatus(...) fails we can try one of two other 5784bff34e3Sthurlow * methods; use a name of "*SMBSERVER", which is supported by Samba (at least) 5794bff34e3Sthurlow * or, as a last resort, try the "truncate-at-dot" heuristic. 5804bff34e3Sthurlow * And the heuristic really should attempt truncation at 5814bff34e3Sthurlow * each dot in turn, left to right. 5824bff34e3Sthurlow * 5834bff34e3Sthurlow * These fallback heuristics should be triggered when the attempt to open the 5844bff34e3Sthurlow * session fails instead of in the code below. 5854bff34e3Sthurlow * 5864bff34e3Sthurlow * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 5874bff34e3Sthurlow */ 5884bff34e3Sthurlow int 5894bff34e3Sthurlow smb_ctx_getnbname(struct smb_ctx *ctx, struct sockaddr *sap) 5904bff34e3Sthurlow { 5914bff34e3Sthurlow char server[SMB_MAXSRVNAMELEN + 1]; 5924bff34e3Sthurlow char workgroup[SMB_MAXUSERNAMELEN + 1]; 5934bff34e3Sthurlow int error; 5944bff34e3Sthurlow #if 0 5954bff34e3Sthurlow char *dot; 5964bff34e3Sthurlow #endif 5974bff34e3Sthurlow 5984bff34e3Sthurlow server[0] = workgroup[0] = '\0'; 5994bff34e3Sthurlow error = nbns_getnodestatus(sap, ctx->ct_nb, server, workgroup); 6004bff34e3Sthurlow if (error == 0) { 6014bff34e3Sthurlow /* 6024bff34e3Sthurlow * Used to set our domain name to be the same as 6034bff34e3Sthurlow * the server's domain name. Unnecessary at best, 6044bff34e3Sthurlow * and wrong for accounts in a trusted domain. 6054bff34e3Sthurlow */ 6064bff34e3Sthurlow #ifdef APPLE 6074bff34e3Sthurlow if (workgroup[0] && !ctx->ct_ssn.ioc_workgroup[0]) 6084bff34e3Sthurlow smb_ctx_setworkgroup(ctx, workgroup, 0); 6094bff34e3Sthurlow #endif 6104bff34e3Sthurlow if (server[0]) 6114bff34e3Sthurlow smb_ctx_setserver(ctx, server); 6124bff34e3Sthurlow } else { 6134bff34e3Sthurlow if (smb_verbose) 6144bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6154bff34e3Sthurlow "Failed to get NetBIOS node status."), 0); 6164bff34e3Sthurlow if (ctx->ct_ssn.ioc_srvname[0] == (char)0) 6174bff34e3Sthurlow smb_ctx_setserver(ctx, "*SMBSERVER"); 6184bff34e3Sthurlow } 6194bff34e3Sthurlow #if 0 6204bff34e3Sthurlow if (server[0] == (char)0) { 6214bff34e3Sthurlow dot = strchr(ctx->ct_fullserver, '.'); 6224bff34e3Sthurlow if (dot) 6234bff34e3Sthurlow *dot = '\0'; 6244bff34e3Sthurlow if (strlen(ctx->ct_fullserver) <= SMB_MAXSRVNAMELEN) { 6254bff34e3Sthurlow /* 6264bff34e3Sthurlow * don't uppercase the server name. it comes from 6274bff34e3Sthurlow * NBNS and uppercasing can clobber the characters 6284bff34e3Sthurlow */ 6294bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_srvname, ctx->ct_fullserver); 6304bff34e3Sthurlow error = 0; 6314bff34e3Sthurlow } else { 6324bff34e3Sthurlow error = -1; 6334bff34e3Sthurlow } 6344bff34e3Sthurlow if (dot) 6354bff34e3Sthurlow *dot = '.'; 6364bff34e3Sthurlow } 6374bff34e3Sthurlow #endif 6384bff34e3Sthurlow return (error); 6394bff34e3Sthurlow } 6404bff34e3Sthurlow 6414bff34e3Sthurlow /* this routine does not uppercase the server name */ 6424bff34e3Sthurlow void 6434bff34e3Sthurlow smb_ctx_setserver(struct smb_ctx *ctx, const char *name) 6444bff34e3Sthurlow { 6454bff34e3Sthurlow /* don't uppercase the server name */ 6464bff34e3Sthurlow if (strlen(name) > SMB_MAXSRVNAMELEN) { /* NB limit is 15 */ 6474bff34e3Sthurlow ctx->ct_ssn.ioc_srvname[0] = '\0'; 6484bff34e3Sthurlow } else 6494bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_srvname, name); 6504bff34e3Sthurlow } 6514bff34e3Sthurlow 6524bff34e3Sthurlow int 6534bff34e3Sthurlow smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) 6544bff34e3Sthurlow { 6554bff34e3Sthurlow 6564bff34e3Sthurlow if (strlen(name) >= SMB_MAXUSERNAMELEN) { 6574bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6584bff34e3Sthurlow "user name '%s' too long"), 0, name); 6594bff34e3Sthurlow return (ENAMETOOLONG); 6604bff34e3Sthurlow } 6614bff34e3Sthurlow 6624bff34e3Sthurlow /* 6634bff34e3Sthurlow * Don't overwrite a value from the command line 6644bff34e3Sthurlow * with one from anywhere else. 6654bff34e3Sthurlow */ 6664bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR)) 6674bff34e3Sthurlow return (0); 6684bff34e3Sthurlow 6694bff34e3Sthurlow /* don't uppercase the username, just copy it. */ 6704bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_user, name); 6714bff34e3Sthurlow 6724bff34e3Sthurlow /* Mark this as "from the command line". */ 6734bff34e3Sthurlow if (from_cmd) 6744bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_USR; 6754bff34e3Sthurlow 6764bff34e3Sthurlow return (0); 6774bff34e3Sthurlow } 6784bff34e3Sthurlow 6794bff34e3Sthurlow /* 6804bff34e3Sthurlow * Never uppercase the workgroup 6814bff34e3Sthurlow * name here, because it might come 6824bff34e3Sthurlow * from a Windows codepage encoding. 6834bff34e3Sthurlow * 6844bff34e3Sthurlow * Don't overwrite a domain name from the 6854bff34e3Sthurlow * command line with one from anywhere else. 6864bff34e3Sthurlow * See smb_ctx_init() for notes about this. 6874bff34e3Sthurlow */ 6884bff34e3Sthurlow int 6894bff34e3Sthurlow smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd) 6904bff34e3Sthurlow { 6914bff34e3Sthurlow 6924bff34e3Sthurlow if (strlen(name) >= SMB_MAXUSERNAMELEN) { 6934bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 6944bff34e3Sthurlow "workgroup name '%s' too long"), 0, name); 6954bff34e3Sthurlow return (ENAMETOOLONG); 6964bff34e3Sthurlow } 6974bff34e3Sthurlow 6984bff34e3Sthurlow /* 6994bff34e3Sthurlow * Don't overwrite a value from the command line 7004bff34e3Sthurlow * with one from anywhere else. 7014bff34e3Sthurlow */ 7024bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM)) 7034bff34e3Sthurlow return (0); 7044bff34e3Sthurlow 7054bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_workgroup, name); 7064bff34e3Sthurlow 7074bff34e3Sthurlow /* Mark this as "from the command line". */ 7084bff34e3Sthurlow if (from_cmd) 7094bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_DOM; 7104bff34e3Sthurlow 7114bff34e3Sthurlow return (0); 7124bff34e3Sthurlow } 7134bff34e3Sthurlow 7144bff34e3Sthurlow int 7154bff34e3Sthurlow smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd) 7164bff34e3Sthurlow { 7174bff34e3Sthurlow 7184bff34e3Sthurlow if (passwd == NULL) /* XXX Huh? */ 7194bff34e3Sthurlow return (EINVAL); 7204bff34e3Sthurlow if (strlen(passwd) >= SMB_MAXPASSWORDLEN) { 7214bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0); 7224bff34e3Sthurlow return (ENAMETOOLONG); 7234bff34e3Sthurlow } 7244bff34e3Sthurlow 7254bff34e3Sthurlow /* 7264bff34e3Sthurlow * Don't overwrite a value from the command line 7274bff34e3Sthurlow * with one from anywhere else. 7284bff34e3Sthurlow */ 7294bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW)) 7304bff34e3Sthurlow return (0); 7314bff34e3Sthurlow 7324bff34e3Sthurlow if (strncmp(passwd, "$$1", 3) == 0) 7334bff34e3Sthurlow smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); 7344bff34e3Sthurlow else 7354bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_password, passwd); 7364bff34e3Sthurlow strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); 7374bff34e3Sthurlow 7384bff34e3Sthurlow /* Mark this as "from the command line". */ 7394bff34e3Sthurlow if (from_cmd) 7404bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_PW; 7414bff34e3Sthurlow 7424bff34e3Sthurlow return (0); 7434bff34e3Sthurlow } 7444bff34e3Sthurlow 7454bff34e3Sthurlow int 7464bff34e3Sthurlow smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 7474bff34e3Sthurlow { 7484bff34e3Sthurlow if (strlen(share) >= SMB_MAXSHARENAMELEN) { 7494bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 7504bff34e3Sthurlow "share name '%s' too long"), 0, share); 7514bff34e3Sthurlow return (ENAMETOOLONG); 7524bff34e3Sthurlow } 7534bff34e3Sthurlow if (ctx->ct_origshare) 7544bff34e3Sthurlow free(ctx->ct_origshare); 7554bff34e3Sthurlow if ((ctx->ct_origshare = strdup(share)) == NULL) 7564bff34e3Sthurlow return (ENOMEM); 7574bff34e3Sthurlow nls_str_upper(ctx->ct_sh.ioc_share, share); 7584bff34e3Sthurlow if (share[0] != 0) 7594bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_SHARE; 7604bff34e3Sthurlow ctx->ct_sh.ioc_stype = stype; 7614bff34e3Sthurlow return (0); 7624bff34e3Sthurlow } 7634bff34e3Sthurlow 7644bff34e3Sthurlow int 7654bff34e3Sthurlow smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 7664bff34e3Sthurlow { 7674bff34e3Sthurlow if (addr == NULL || addr[0] == 0) 7684bff34e3Sthurlow return (EINVAL); 7694bff34e3Sthurlow if (ctx->ct_srvaddr) 7704bff34e3Sthurlow free(ctx->ct_srvaddr); 7714bff34e3Sthurlow if ((ctx->ct_srvaddr = strdup(addr)) == NULL) 7724bff34e3Sthurlow return (ENOMEM); 7734bff34e3Sthurlow return (0); 7744bff34e3Sthurlow } 7754bff34e3Sthurlow 7764bff34e3Sthurlow static int 7774bff34e3Sthurlow smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 7784bff34e3Sthurlow { 7794bff34e3Sthurlow struct group gr; 7804bff34e3Sthurlow struct passwd pw; 7814bff34e3Sthurlow char buf[NSS_BUFLEN_PASSWD]; 7824bff34e3Sthurlow char *cp; 7834bff34e3Sthurlow 7844bff34e3Sthurlow cp = strchr(pair, ':'); 7854bff34e3Sthurlow if (cp) { 7864bff34e3Sthurlow *cp++ = '\0'; 7874bff34e3Sthurlow if (*cp) { 7884bff34e3Sthurlow if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) { 7894bff34e3Sthurlow *gid = gr.gr_gid; 7904bff34e3Sthurlow } else 7914bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 7924bff34e3Sthurlow "Invalid group name %s, ignored"), 0, cp); 7934bff34e3Sthurlow } 7944bff34e3Sthurlow } 7954bff34e3Sthurlow if (*pair) { 7964bff34e3Sthurlow if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) { 7974bff34e3Sthurlow *uid = pw.pw_uid; 7984bff34e3Sthurlow } else 7994bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 8004bff34e3Sthurlow "Invalid user name %s, ignored"), 0, pair); 8014bff34e3Sthurlow } 8024bff34e3Sthurlow 8034bff34e3Sthurlow return (0); 8044bff34e3Sthurlow } 8054bff34e3Sthurlow 8064bff34e3Sthurlow /* 8074bff34e3Sthurlow * Commands use this with getopt. See: 8084bff34e3Sthurlow * STDPARAM_OPT, STDPARAM_ARGS 8094bff34e3Sthurlow * Called after smb_ctx_readrc(). 8104bff34e3Sthurlow */ 8114bff34e3Sthurlow int 8124bff34e3Sthurlow smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 8134bff34e3Sthurlow { 8144bff34e3Sthurlow int error = 0; 8154bff34e3Sthurlow char *p, *cp; 8164bff34e3Sthurlow char tmp[1024]; 8174bff34e3Sthurlow 8184bff34e3Sthurlow switch (opt) { 8194bff34e3Sthurlow case 'A': 8204bff34e3Sthurlow case 'U': 8214bff34e3Sthurlow /* Handled in smb_ctx_init() */ 8224bff34e3Sthurlow break; 8234bff34e3Sthurlow case 'I': 8244bff34e3Sthurlow error = smb_ctx_setsrvaddr(ctx, arg); 8254bff34e3Sthurlow break; 8264bff34e3Sthurlow case 'M': 8274bff34e3Sthurlow ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8); 8284bff34e3Sthurlow if (*cp == '/') { 8294bff34e3Sthurlow ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8); 8304bff34e3Sthurlow ctx->ct_flags |= SMBCF_SRIGHTS; 8314bff34e3Sthurlow } 8324bff34e3Sthurlow break; 8334bff34e3Sthurlow case 'N': 8344bff34e3Sthurlow ctx->ct_flags |= SMBCF_NOPWD; 8354bff34e3Sthurlow break; 8364bff34e3Sthurlow case 'O': 8374bff34e3Sthurlow p = strdup(arg); 8384bff34e3Sthurlow cp = strchr(p, '/'); 8394bff34e3Sthurlow if (cp) { 8404bff34e3Sthurlow *cp++ = '\0'; 8414bff34e3Sthurlow error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner, 8424bff34e3Sthurlow &ctx->ct_sh.ioc_group); 8434bff34e3Sthurlow } 8444bff34e3Sthurlow if (*p && error == 0) { 8454bff34e3Sthurlow error = smb_parse_owner(cp, &ctx->ct_ssn.ioc_owner, 8464bff34e3Sthurlow &ctx->ct_ssn.ioc_group); 8474bff34e3Sthurlow } 8484bff34e3Sthurlow free(p); 8494bff34e3Sthurlow break; 8504bff34e3Sthurlow case 'P': 8514bff34e3Sthurlow /* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT; */ 8524bff34e3Sthurlow break; 8534bff34e3Sthurlow case 'R': 8544bff34e3Sthurlow ctx->ct_ssn.ioc_retrycount = atoi(arg); 8554bff34e3Sthurlow break; 8564bff34e3Sthurlow case 'T': 8574bff34e3Sthurlow ctx->ct_ssn.ioc_timeout = atoi(arg); 8584bff34e3Sthurlow break; 8594bff34e3Sthurlow case 'W': 8604bff34e3Sthurlow nls_str_upper(tmp, arg); 8614bff34e3Sthurlow error = smb_ctx_setworkgroup(ctx, tmp, TRUE); 8624bff34e3Sthurlow break; 8634bff34e3Sthurlow } 8644bff34e3Sthurlow return (error); 8654bff34e3Sthurlow } 8664bff34e3Sthurlow 8674bff34e3Sthurlow #if 0 8684bff34e3Sthurlow static void 8694bff34e3Sthurlow smb_hexdump(const uchar_t *buf, int len) { 8704bff34e3Sthurlow int ofs = 0; 8714bff34e3Sthurlow 8724bff34e3Sthurlow while (len--) { 8734bff34e3Sthurlow if (ofs % 16 == 0) 8744bff34e3Sthurlow printf("\n%02X: ", ofs); 8754bff34e3Sthurlow printf("%02x ", *buf++); 8764bff34e3Sthurlow ofs++; 8774bff34e3Sthurlow } 8784bff34e3Sthurlow printf("\n"); 8794bff34e3Sthurlow } 8804bff34e3Sthurlow #endif 8814bff34e3Sthurlow 8824bff34e3Sthurlow 8834bff34e3Sthurlow static int 8844bff34e3Sthurlow smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl) 8854bff34e3Sthurlow { 8864bff34e3Sthurlow int error; 8874bff34e3Sthurlow 8884bff34e3Sthurlow /* 8894bff34e3Sthurlow * Not able to find out what is the work of this routine till 8904bff34e3Sthurlow * now. Still investigating. 8914bff34e3Sthurlow * REVISIT 8924bff34e3Sthurlow */ 8934bff34e3Sthurlow #ifdef KICONV_SUPPORT 8944bff34e3Sthurlow error = kiconv_add_xlat_table(to, from, tbl); 8954bff34e3Sthurlow if (error && error != EEXIST) { 8964bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 8974bff34e3Sthurlow "can not setup kernel iconv table (%s:%s)"), 8984bff34e3Sthurlow error, from, to); 8994bff34e3Sthurlow return (error); 9004bff34e3Sthurlow } 9014bff34e3Sthurlow #endif 9024bff34e3Sthurlow return (0); 9034bff34e3Sthurlow } 9044bff34e3Sthurlow 9054bff34e3Sthurlow /* 9064bff34e3Sthurlow * Verify context before connect operation(s), 9074bff34e3Sthurlow * lookup specified server and try to fill all forgotten fields. 9084bff34e3Sthurlow */ 9094bff34e3Sthurlow int 9104bff34e3Sthurlow smb_ctx_resolve(struct smb_ctx *ctx) 9114bff34e3Sthurlow { 9124bff34e3Sthurlow struct smbioc_ossn *ssn = &ctx->ct_ssn; 9134bff34e3Sthurlow struct smbioc_oshare *sh = &ctx->ct_sh; 9144bff34e3Sthurlow struct nb_name nn; 9154bff34e3Sthurlow struct sockaddr *sap; 9164bff34e3Sthurlow struct sockaddr_nb *salocal, *saserver; 9174bff34e3Sthurlow char *cp; 9184bff34e3Sthurlow uchar_t cstbl[256]; 9194bff34e3Sthurlow uint_t i; 9204bff34e3Sthurlow int error = 0; 9214bff34e3Sthurlow int browseok = ctx->ct_flags & SMBCF_BROWSEOK; 9224bff34e3Sthurlow int renego = 0; 9234bff34e3Sthurlow 9244bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_RESOLVED; 9254bff34e3Sthurlow if (isatty(STDIN_FILENO)) 9264bff34e3Sthurlow browseok = 0; 9274bff34e3Sthurlow if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == 0) { 9284bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 9294bff34e3Sthurlow "no server name specified"), 0); 9304bff34e3Sthurlow return (EINVAL); 9314bff34e3Sthurlow } 9324bff34e3Sthurlow if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0 && 9334bff34e3Sthurlow !browseok) { 9344bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 9354bff34e3Sthurlow "no share name specified for %s@%s"), 9364bff34e3Sthurlow 0, ssn->ioc_user, ssn->ioc_srvname); 9374bff34e3Sthurlow return (EINVAL); 9384bff34e3Sthurlow } 9394bff34e3Sthurlow error = nb_ctx_resolve(ctx->ct_nb); 9404bff34e3Sthurlow if (error) 9414bff34e3Sthurlow return (error); 9424bff34e3Sthurlow if (ssn->ioc_localcs[0] == 0) 9434bff34e3Sthurlow strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ 9444bff34e3Sthurlow error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 9454bff34e3Sthurlow if (error) 9464bff34e3Sthurlow return (error); 9474bff34e3Sthurlow error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 9484bff34e3Sthurlow if (error) 9494bff34e3Sthurlow return (error); 9504bff34e3Sthurlow if (ssn->ioc_servercs[0] != 0) { 9514bff34e3Sthurlow for (i = 0; i < sizeof (cstbl); i++) 9524bff34e3Sthurlow cstbl[i] = i; 9534bff34e3Sthurlow nls_mem_toext(cstbl, cstbl, sizeof (cstbl)); 9544bff34e3Sthurlow error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, 9554bff34e3Sthurlow cstbl); 9564bff34e3Sthurlow if (error) 9574bff34e3Sthurlow return (error); 9584bff34e3Sthurlow for (i = 0; i < sizeof (cstbl); i++) 9594bff34e3Sthurlow cstbl[i] = i; 9604bff34e3Sthurlow nls_mem_toloc(cstbl, cstbl, sizeof (cstbl)); 9614bff34e3Sthurlow error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, 9624bff34e3Sthurlow cstbl); 9634bff34e3Sthurlow if (error) 9644bff34e3Sthurlow return (error); 9654bff34e3Sthurlow } 9664bff34e3Sthurlow /* 9674bff34e3Sthurlow * If we have an explicit address set for the server in 9684bff34e3Sthurlow * an "addr=X" setting in .nsmbrc or SMF, just try using a 9694bff34e3Sthurlow * gethostbyname() lookup for it. 9704bff34e3Sthurlow */ 9714bff34e3Sthurlow if (ctx->ct_srvaddr) { 9724bff34e3Sthurlow error = nb_resolvehost_in(ctx->ct_srvaddr, &sap); 9734bff34e3Sthurlow if (error == 0) 9744bff34e3Sthurlow (void) smb_ctx_getnbname(ctx, sap); 9754bff34e3Sthurlow } else 9764bff34e3Sthurlow error = -1; 9774bff34e3Sthurlow 9784bff34e3Sthurlow /* 9794bff34e3Sthurlow * Next try a gethostbyname() lookup on the original user- 9804bff34e3Sthurlow * specified server name. This is similar to Windows 9814bff34e3Sthurlow * NBT option "Use DNS for name resolution." 9824bff34e3Sthurlow */ 9834bff34e3Sthurlow if (error && ctx->ct_fullserver) { 9844bff34e3Sthurlow error = nb_resolvehost_in(ctx->ct_fullserver, &sap); 9854bff34e3Sthurlow if (error == 0) 9864bff34e3Sthurlow (void) smb_ctx_getnbname(ctx, sap); 9874bff34e3Sthurlow } 9884bff34e3Sthurlow 9894bff34e3Sthurlow /* 9904bff34e3Sthurlow * Finally, try the shorter, upper-cased ssn->ioc_srvname 9914bff34e3Sthurlow * with a NBNS/WINS lookup if the "nbns_enable" property is 9924bff34e3Sthurlow * true (the default). nbns_resolvename() may unicast to the 9934bff34e3Sthurlow * "nbns" server or broadcast on the subnet. 9944bff34e3Sthurlow */ 9954bff34e3Sthurlow if (error && ssn->ioc_srvname[0] && 9964bff34e3Sthurlow ctx->ct_nb->nb_flags & NBCF_NS_ENABLE) { 9974bff34e3Sthurlow error = nbns_resolvename(ssn->ioc_srvname, 9984bff34e3Sthurlow ctx->ct_nb, &sap); 9994bff34e3Sthurlow /* 10004bff34e3Sthurlow * Used to get the NetBIOS node status here. 10014bff34e3Sthurlow * Not necessary (we have the NetBIOS name). 10024bff34e3Sthurlow */ 10034bff34e3Sthurlow } 10044bff34e3Sthurlow if (error) { 10054bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10064bff34e3Sthurlow "can't get server address"), error); 10074bff34e3Sthurlow return (error); 10084bff34e3Sthurlow } 10094bff34e3Sthurlow 10104bff34e3Sthurlow /* XXX: no nls_str_upper(ssn->ioc_srvname) here? */ 10114bff34e3Sthurlow 10124bff34e3Sthurlow assert(sizeof (nn.nn_name) == sizeof (ssn->ioc_srvname)); 10134bff34e3Sthurlow memcpy(nn.nn_name, ssn->ioc_srvname, NB_NAMELEN); 10144bff34e3Sthurlow nn.nn_type = NBT_SERVER; 10154bff34e3Sthurlow nn.nn_scope = ctx->ct_nb->nb_scope; 10164bff34e3Sthurlow 10174bff34e3Sthurlow error = nb_sockaddr(sap, &nn, &saserver); 10184bff34e3Sthurlow memcpy(&ctx->ct_srvinaddr, sap, sizeof (struct sockaddr_in)); 10194bff34e3Sthurlow nb_snbfree(sap); 10204bff34e3Sthurlow if (error) { 10214bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10224bff34e3Sthurlow "can't allocate server address"), error); 10234bff34e3Sthurlow return (error); 10244bff34e3Sthurlow } 10254bff34e3Sthurlow /* We know it's a NetBIOS address here. */ 10264bff34e3Sthurlow bcopy(saserver, &ssn->ioc_server.nb, 10274bff34e3Sthurlow sizeof (struct sockaddr_nb)); 10284bff34e3Sthurlow if (ctx->ct_locname[0] == 0) { 10294bff34e3Sthurlow error = nb_getlocalname(ctx->ct_locname, 10304bff34e3Sthurlow SMB_MAXUSERNAMELEN + 1); 10314bff34e3Sthurlow if (error) { 10324bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10334bff34e3Sthurlow "can't get local name"), error); 10344bff34e3Sthurlow return (error); 10354bff34e3Sthurlow } 10364bff34e3Sthurlow nls_str_upper(ctx->ct_locname, ctx->ct_locname); 10374bff34e3Sthurlow } 10384bff34e3Sthurlow 10394bff34e3Sthurlow /* XXX: no nls_str_upper(ctx->ct_locname); here? */ 10404bff34e3Sthurlow 10414bff34e3Sthurlow memcpy(nn.nn_name, ctx->ct_locname, NB_NAMELEN); 10424bff34e3Sthurlow nn.nn_type = NBT_WKSTA; 10434bff34e3Sthurlow nn.nn_scope = ctx->ct_nb->nb_scope; 10444bff34e3Sthurlow 10454bff34e3Sthurlow error = nb_sockaddr(NULL, &nn, &salocal); 10464bff34e3Sthurlow if (error) { 10474bff34e3Sthurlow nb_snbfree((struct sockaddr *)saserver); 10484bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 10494bff34e3Sthurlow "can't allocate local address"), error); 10504bff34e3Sthurlow return (error); 10514bff34e3Sthurlow } 10524bff34e3Sthurlow 10534bff34e3Sthurlow /* We know it's a NetBIOS address here. */ 10544bff34e3Sthurlow bcopy(salocal, &ssn->ioc_local.nb, 10554bff34e3Sthurlow sizeof (struct sockaddr_nb)); 10564bff34e3Sthurlow 10571b34bc4aSbs135383 error = smb_ctx_findvc(ctx, SMBL_VC, 0); 10581b34bc4aSbs135383 if (error == 0) { 10591b34bc4aSbs135383 /* re-use and existing VC */ 10601b34bc4aSbs135383 ctx->ct_flags |= SMBCF_RESOLVED | SMBCF_SSNACTIVE; 10611b34bc4aSbs135383 return (0); 10621b34bc4aSbs135383 } 10631b34bc4aSbs135383 10641b34bc4aSbs135383 /* Make a new connection via smb_ctx_negotiate()... */ 10654bff34e3Sthurlow error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, 10664bff34e3Sthurlow ssn->ioc_workgroup); 10674bff34e3Sthurlow if (error) 10684bff34e3Sthurlow return (error); 10694bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_AUTHREQ; 10704bff34e3Sthurlow if (!ctx->ct_secblob && browseok && !sh->ioc_share[0] && 10714bff34e3Sthurlow !(ctx->ct_flags & SMBCF_XXX)) { 10724bff34e3Sthurlow /* assert: anon share list is subset of overall server shares */ 10734bff34e3Sthurlow error = smb_browse(ctx, 1); 10744bff34e3Sthurlow if (error) /* user cancel or other error? */ 10754bff34e3Sthurlow return (error); 10764bff34e3Sthurlow /* 10774bff34e3Sthurlow * A share was selected, authenticate button was pressed, 10784bff34e3Sthurlow * or anon-authentication failed getting browse list. 10794bff34e3Sthurlow */ 10804bff34e3Sthurlow } 10814bff34e3Sthurlow if ((ctx->ct_secblob == NULL) && (ctx->ct_flags & SMBCF_AUTHREQ || 10824bff34e3Sthurlow (ssn->ioc_password[0] == '\0' && 10834bff34e3Sthurlow !(ctx->ct_flags & SMBCF_NOPWD)))) { 10844bff34e3Sthurlow reauth: 10854bff34e3Sthurlow /* 10864bff34e3Sthurlow * This function is implemented in both 10874bff34e3Sthurlow * ui-apple.c and ui-sun.c so let's try to 10884bff34e3Sthurlow * keep the same interface. Not sure why 10894bff34e3Sthurlow * they didn't just pass ssn here. 10904bff34e3Sthurlow */ 10914bff34e3Sthurlow error = smb_get_authentication( 10924bff34e3Sthurlow ssn->ioc_workgroup, sizeof (ssn->ioc_workgroup) - 1, 10934bff34e3Sthurlow ssn->ioc_user, sizeof (ssn->ioc_user) - 1, 10944bff34e3Sthurlow ssn->ioc_password, sizeof (ssn->ioc_password) - 1, 10954bff34e3Sthurlow ssn->ioc_srvname, ctx); 10964bff34e3Sthurlow if (error) 10974bff34e3Sthurlow return (error); 10984bff34e3Sthurlow } 10994bff34e3Sthurlow /* 11004bff34e3Sthurlow * if we have a session it is either anonymous 11014bff34e3Sthurlow * or from a stale authentication. re-negotiating 11024bff34e3Sthurlow * gets us ready for a fresh session 11034bff34e3Sthurlow */ 11044bff34e3Sthurlow if (ctx->ct_flags & SMBCF_SSNACTIVE || renego) { 11054bff34e3Sthurlow renego = 0; 11064bff34e3Sthurlow /* don't clobber workgroup name, pass null arg */ 11074bff34e3Sthurlow error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, NULL); 11084bff34e3Sthurlow if (error) 11094bff34e3Sthurlow return (error); 11104bff34e3Sthurlow } 11114bff34e3Sthurlow if (browseok && !sh->ioc_share[0]) { 11124bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_AUTHREQ; 11134bff34e3Sthurlow error = smb_browse(ctx, 0); 11144bff34e3Sthurlow if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) { 11154bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 11164bff34e3Sthurlow "smb_ctx_resolve: bad keychain entry"), 0); 11174bff34e3Sthurlow ctx->ct_flags |= SMBCF_KCBAD; 11184bff34e3Sthurlow renego = 1; 11194bff34e3Sthurlow goto reauth; 11204bff34e3Sthurlow } 11214bff34e3Sthurlow if (error) /* auth, user cancel, or other error */ 11224bff34e3Sthurlow return (error); 11234bff34e3Sthurlow /* 11244bff34e3Sthurlow * Re-authenticate button was pressed? 11254bff34e3Sthurlow */ 11264bff34e3Sthurlow if (ctx->ct_flags & SMBCF_AUTHREQ) 11274bff34e3Sthurlow goto reauth; 11284bff34e3Sthurlow if (!sh->ioc_share[0] && !(ctx->ct_flags & SMBCF_XXX)) { 11294bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 11304bff34e3Sthurlow "no share specified for %s@%s"), 11314bff34e3Sthurlow 0, ssn->ioc_user, ssn->ioc_srvname); 11324bff34e3Sthurlow return (EINVAL); 11334bff34e3Sthurlow } 11344bff34e3Sthurlow } 11354bff34e3Sthurlow ctx->ct_flags |= SMBCF_RESOLVED; 11364bff34e3Sthurlow 11374bff34e3Sthurlow if (smb_debug) 11384bff34e3Sthurlow dump_ctx("after smb_ctx_resolve", ctx); 11394bff34e3Sthurlow 11404bff34e3Sthurlow return (0); 11414bff34e3Sthurlow } 11424bff34e3Sthurlow 11434bff34e3Sthurlow int 11444bff34e3Sthurlow smb_open_driver() 11454bff34e3Sthurlow { 11464bff34e3Sthurlow char buf[20]; 11474bff34e3Sthurlow int err, fd, i; 11484bff34e3Sthurlow uint32_t version; 11494bff34e3Sthurlow 11504bff34e3Sthurlow /* 11514bff34e3Sthurlow * First try to open as clone 11524bff34e3Sthurlow */ 11534bff34e3Sthurlow fd = open("/dev/"NSMB_NAME, O_RDWR); 11544bff34e3Sthurlow if (fd >= 0) 11554bff34e3Sthurlow goto opened; 11564bff34e3Sthurlow 11574bff34e3Sthurlow err = errno; /* from open */ 11584bff34e3Sthurlow #ifdef APPLE 11594bff34e3Sthurlow /* 11604bff34e3Sthurlow * well, no clone capabilities available - we have to scan 11614bff34e3Sthurlow * all devices in order to get free one 11624bff34e3Sthurlow */ 11634bff34e3Sthurlow for (i = 0; i < 1024; i++) { 11644bff34e3Sthurlow snprintf(buf, sizeof (buf), "/dev/%s%d", NSMB_NAME, i); 11654bff34e3Sthurlow fd = open(buf, O_RDWR); 11664bff34e3Sthurlow if (fd >= 0) 11674bff34e3Sthurlow goto opened; 11684bff34e3Sthurlow if (i && POWEROF2(i+1)) 11694bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 11704bff34e3Sthurlow "%d failures to open smb device"), errno, i+1); 11714bff34e3Sthurlow } 11724bff34e3Sthurlow err = ENOENT; 11734bff34e3Sthurlow #endif 11744bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 11754bff34e3Sthurlow "failed to open %s"), err, "/dev/" NSMB_NAME); 11764bff34e3Sthurlow return (-1); 11774bff34e3Sthurlow 11784bff34e3Sthurlow opened: 11794bff34e3Sthurlow /* 11804bff34e3Sthurlow * Check the driver version (paranoia) 11814bff34e3Sthurlow * Do this BEFORE any other ioctl calls. 11824bff34e3Sthurlow */ 11834bff34e3Sthurlow if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) { 11844bff34e3Sthurlow err = errno; 11854bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 11864bff34e3Sthurlow "failed to get driver version"), err); 11874bff34e3Sthurlow close(fd); 11884bff34e3Sthurlow return (-1); 11894bff34e3Sthurlow } 11904bff34e3Sthurlow if (version != NSMB_VERSION) { 11914bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 11924bff34e3Sthurlow "incorrect driver version"), 0); 11934bff34e3Sthurlow close(fd); 11944bff34e3Sthurlow return (-1); 11954bff34e3Sthurlow } 11964bff34e3Sthurlow 11974bff34e3Sthurlow return (fd); 11984bff34e3Sthurlow } 11994bff34e3Sthurlow 12004bff34e3Sthurlow static int 12014bff34e3Sthurlow smb_ctx_gethandle(struct smb_ctx *ctx) 12024bff34e3Sthurlow { 12034bff34e3Sthurlow int err, fd; 12044bff34e3Sthurlow 12054bff34e3Sthurlow if (ctx->ct_fd != -1) { 12064bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 12074bff34e3Sthurlow close(ctx->ct_fd); 12084bff34e3Sthurlow ctx->ct_fd = -1; 12094bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_SSNACTIVE; 12104bff34e3Sthurlow } 12114bff34e3Sthurlow 12124bff34e3Sthurlow fd = smb_open_driver(); 12134bff34e3Sthurlow if (fd < 0) 12144bff34e3Sthurlow return (ENODEV); 12154bff34e3Sthurlow 12164bff34e3Sthurlow ctx->ct_fd = fd; 12174bff34e3Sthurlow return (0); 12184bff34e3Sthurlow } 12194bff34e3Sthurlow 12204bff34e3Sthurlow int 12214bff34e3Sthurlow smb_ctx_ioctl(struct smb_ctx *ctx, int inum, struct smbioc_lookup *rqp) 12224bff34e3Sthurlow { 12234bff34e3Sthurlow size_t siz = DEF_SEC_TOKEN_LEN; 12244bff34e3Sthurlow int rc = 0; 12254bff34e3Sthurlow struct sockaddr sap1, sap2; 12264bff34e3Sthurlow int i; 12274bff34e3Sthurlow 12284bff34e3Sthurlow if (rqp->ioc_ssn.ioc_outtok) 12294bff34e3Sthurlow free(rqp->ioc_ssn.ioc_outtok); 12304bff34e3Sthurlow rqp->ioc_ssn.ioc_outtoklen = siz; 12314bff34e3Sthurlow rqp->ioc_ssn.ioc_outtok = malloc(siz+1); 12324bff34e3Sthurlow if (rqp->ioc_ssn.ioc_outtok == NULL) 12334bff34e3Sthurlow return (ENOMEM); 12344bff34e3Sthurlow bzero(rqp->ioc_ssn.ioc_outtok, siz+1); 12354bff34e3Sthurlow /* Note: No longer put length in outtok[0] */ 12364bff34e3Sthurlow /* *((int *)rqp->ioc_ssn.ioc_outtok) = (int)siz; */ 12374bff34e3Sthurlow 12384bff34e3Sthurlow if (ioctl(ctx->ct_fd, inum, rqp) == -1) { 12394bff34e3Sthurlow rc = errno; 12404bff34e3Sthurlow goto out; 12414bff34e3Sthurlow } 12424bff34e3Sthurlow if (rqp->ioc_ssn.ioc_outtoklen <= siz) 12434bff34e3Sthurlow goto out; 12444bff34e3Sthurlow 12454bff34e3Sthurlow /* 12464bff34e3Sthurlow * Operation completed, but our output token wasn't large enough. 12474bff34e3Sthurlow * The re-call below only pulls the token from the kernel. 12484bff34e3Sthurlow */ 12494bff34e3Sthurlow siz = rqp->ioc_ssn.ioc_outtoklen; 12504bff34e3Sthurlow free(rqp->ioc_ssn.ioc_outtok); 12514bff34e3Sthurlow rqp->ioc_ssn.ioc_outtok = malloc(siz + 1); 12524bff34e3Sthurlow if (rqp->ioc_ssn.ioc_outtok == NULL) { 12534bff34e3Sthurlow rc = ENOMEM; 12544bff34e3Sthurlow goto out; 12554bff34e3Sthurlow } 12564bff34e3Sthurlow bzero(rqp->ioc_ssn.ioc_outtok, siz+1); 12574bff34e3Sthurlow /* Note: No longer put length in outtok[0] */ 12584bff34e3Sthurlow /* *((int *)rqp->ioc_ssn.ioc_outtok) = siz; */ 12594bff34e3Sthurlow if (ioctl(ctx->ct_fd, inum, rqp) == -1) 12604bff34e3Sthurlow rc = errno; 12614bff34e3Sthurlow out: 12624bff34e3Sthurlow return (rc); 12634bff34e3Sthurlow } 12644bff34e3Sthurlow 12651b34bc4aSbs135383 int 12661b34bc4aSbs135383 smb_ctx_findvc(struct smb_ctx *ctx, int level, int flags) 12671b34bc4aSbs135383 { 12681b34bc4aSbs135383 struct smbioc_lookup rq; 12691b34bc4aSbs135383 int error = 0; 12701b34bc4aSbs135383 12711b34bc4aSbs135383 if ((error = smb_ctx_gethandle(ctx))) 12721b34bc4aSbs135383 return (error); 12731b34bc4aSbs135383 12741b34bc4aSbs135383 bzero(&rq, sizeof (rq)); 12751b34bc4aSbs135383 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 12761b34bc4aSbs135383 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 12771b34bc4aSbs135383 12781b34bc4aSbs135383 rq.ioc_flags = flags; 12791b34bc4aSbs135383 rq.ioc_level = level; 12801b34bc4aSbs135383 12811b34bc4aSbs135383 return (smb_ctx_ioctl(ctx, SMBIOC_FINDVC, &rq)); 12821b34bc4aSbs135383 } 12834bff34e3Sthurlow 12844bff34e3Sthurlow /* 12854bff34e3Sthurlow * adds a GSSAPI wrapper 12864bff34e3Sthurlow */ 12874bff34e3Sthurlow char * 12884bff34e3Sthurlow smb_ctx_tkt2gtok(uchar_t *tkt, ulong_t tktlen, 12894bff34e3Sthurlow uchar_t **gtokp, ulong_t *gtoklenp) 12904bff34e3Sthurlow { 12914bff34e3Sthurlow ulong_t bloblen = tktlen; 12924bff34e3Sthurlow ulong_t len; 12934bff34e3Sthurlow uchar_t krbapreq[2] = "\x01\x00"; /* see RFC 1964 */ 12944bff34e3Sthurlow char *failure; 12954bff34e3Sthurlow uchar_t *blob = NULL; /* result */ 12964bff34e3Sthurlow uchar_t *b; 12974bff34e3Sthurlow 12984bff34e3Sthurlow bloblen += sizeof (krbapreq); 12994bff34e3Sthurlow bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen; 13004bff34e3Sthurlow len = bloblen; 13014bff34e3Sthurlow bloblen = ASNDerCalcTokenLength(bloblen, bloblen); 13024bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok malloc"); 13034bff34e3Sthurlow if (!(blob = malloc(bloblen))) 13044bff34e3Sthurlow goto out; 13054bff34e3Sthurlow b = blob; 13064bff34e3Sthurlow b += ASNDerWriteToken(b, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, len); 13074bff34e3Sthurlow b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5); 13084bff34e3Sthurlow memcpy(b, krbapreq, sizeof (krbapreq)); 13094bff34e3Sthurlow b += sizeof (krbapreq); 13104bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok insanity check"); 13114bff34e3Sthurlow if (b + tktlen != blob + bloblen) 13124bff34e3Sthurlow goto out; 13134bff34e3Sthurlow memcpy(b, tkt, tktlen); 13144bff34e3Sthurlow *gtoklenp = bloblen; 13154bff34e3Sthurlow *gtokp = blob; 13164bff34e3Sthurlow failure = NULL; 13174bff34e3Sthurlow out:; 13184bff34e3Sthurlow if (blob && failure) 13194bff34e3Sthurlow free(blob); 13204bff34e3Sthurlow return (failure); 13214bff34e3Sthurlow } 13224bff34e3Sthurlow 13234bff34e3Sthurlow 13244bff34e3Sthurlow /* 13254bff34e3Sthurlow * Initialization for Kerberos, pulled out of smb_ctx_principal2tkt. 13264bff34e3Sthurlow * This just gets our cached credentials, if we have any. 13274bff34e3Sthurlow * Based on the "klist" command. 13284bff34e3Sthurlow */ 13294bff34e3Sthurlow char * 13304bff34e3Sthurlow smb_ctx_krb5init(struct smb_ctx *ctx) 13314bff34e3Sthurlow { 13324bff34e3Sthurlow char *failure; 13334bff34e3Sthurlow krb5_error_code kerr; 13344bff34e3Sthurlow krb5_context kctx = NULL; 13354bff34e3Sthurlow krb5_ccache kcc = NULL; 13364bff34e3Sthurlow krb5_principal kprin = NULL; 13374bff34e3Sthurlow 13384bff34e3Sthurlow kerr = krb5_init_context(&kctx); 13394bff34e3Sthurlow if (kerr) { 13404bff34e3Sthurlow failure = "krb5_init_context"; 13414bff34e3Sthurlow goto out; 13424bff34e3Sthurlow } 13434bff34e3Sthurlow ctx->ct_krb5ctx = kctx; 13444bff34e3Sthurlow 13454bff34e3Sthurlow /* non-default would instead use krb5_cc_resolve */ 13464bff34e3Sthurlow kerr = krb5_cc_default(kctx, &kcc); 13474bff34e3Sthurlow if (kerr) { 13484bff34e3Sthurlow failure = "krb5_cc_default"; 13494bff34e3Sthurlow goto out; 13504bff34e3Sthurlow } 13514bff34e3Sthurlow ctx->ct_krb5cc = kcc; 13524bff34e3Sthurlow 13534bff34e3Sthurlow /* 13544bff34e3Sthurlow * Get the client principal (ticket), 13554bff34e3Sthurlow * or find out if we don't have one. 13564bff34e3Sthurlow */ 13574bff34e3Sthurlow kerr = krb5_cc_get_principal(kctx, kcc, &kprin); 13584bff34e3Sthurlow if (kerr) { 13594bff34e3Sthurlow failure = "krb5_cc_get_principal"; 13604bff34e3Sthurlow goto out; 13614bff34e3Sthurlow } 13624bff34e3Sthurlow ctx->ct_krb5cp = kprin; 13634bff34e3Sthurlow 13644bff34e3Sthurlow if (smb_verbose) { 13654bff34e3Sthurlow fprintf(stderr, gettext("Ticket cache: %s:%s\n"), 13664bff34e3Sthurlow krb5_cc_get_type(kctx, kcc), 13674bff34e3Sthurlow krb5_cc_get_name(kctx, kcc)); 13684bff34e3Sthurlow } 13694bff34e3Sthurlow failure = NULL; 13704bff34e3Sthurlow 13714bff34e3Sthurlow out: 13724bff34e3Sthurlow return (failure); 13734bff34e3Sthurlow } 13744bff34e3Sthurlow 13754bff34e3Sthurlow 13764bff34e3Sthurlow /* 13774bff34e3Sthurlow * See "Windows 2000 Kerberos Interoperability" paper by 13784bff34e3Sthurlow * Christopher Nebergall. RC4 HMAC is the W2K default but 13794bff34e3Sthurlow * Samba support lagged (not due to Samba itself, but due to OS' 13804bff34e3Sthurlow * Kerberos implementations.) 13814bff34e3Sthurlow * 13824bff34e3Sthurlow * Only session enc type should matter, not ticket enc type, 13834bff34e3Sthurlow * per Sam Hartman on krbdev. 13844bff34e3Sthurlow * 13854bff34e3Sthurlow * Preauthentication failure topics in krb-protocol may help here... 13864bff34e3Sthurlow * try "John Brezak" and/or "Clifford Neuman" too. 13874bff34e3Sthurlow */ 13884bff34e3Sthurlow static krb5_enctype kenctypes[] = { 13894bff34e3Sthurlow ENCTYPE_ARCFOUR_HMAC, /* defined in Tiger krb5.h */ 13904bff34e3Sthurlow ENCTYPE_DES_CBC_MD5, 13914bff34e3Sthurlow ENCTYPE_DES_CBC_CRC, 13924bff34e3Sthurlow ENCTYPE_NULL 13934bff34e3Sthurlow }; 13944bff34e3Sthurlow 13954bff34e3Sthurlow /* 13964bff34e3Sthurlow * Obtain a kerberos ticket... 13974bff34e3Sthurlow * (if TLD != "gov" then pray first) 13984bff34e3Sthurlow */ 13994bff34e3Sthurlow char * 14004bff34e3Sthurlow smb_ctx_principal2tkt( 14014bff34e3Sthurlow struct smb_ctx *ctx, char *prin, 14024bff34e3Sthurlow uchar_t **tktp, ulong_t *tktlenp) 14034bff34e3Sthurlow { 14044bff34e3Sthurlow char *failure; 14054bff34e3Sthurlow krb5_context kctx = NULL; 14064bff34e3Sthurlow krb5_error_code kerr; 14074bff34e3Sthurlow krb5_ccache kcc = NULL; 14084bff34e3Sthurlow krb5_principal kprin = NULL, cprn = NULL; 14094bff34e3Sthurlow krb5_creds kcreds, *kcredsp = NULL; 14104bff34e3Sthurlow krb5_auth_context kauth = NULL; 14114bff34e3Sthurlow krb5_data kdata, kdata0; 14124bff34e3Sthurlow uchar_t *tkt; 14134bff34e3Sthurlow 14144bff34e3Sthurlow memset((char *)&kcreds, 0, sizeof (kcreds)); 14154bff34e3Sthurlow kdata0.length = 0; 14164bff34e3Sthurlow 14174bff34e3Sthurlow /* These shoud have been done in smb_ctx_krb5init() */ 14184bff34e3Sthurlow if (ctx->ct_krb5ctx == NULL || 14194bff34e3Sthurlow ctx->ct_krb5cc == NULL || 14204bff34e3Sthurlow ctx->ct_krb5cp == NULL) { 14214bff34e3Sthurlow failure = "smb_ctx_krb5init"; 14224bff34e3Sthurlow goto out; 14234bff34e3Sthurlow } 14244bff34e3Sthurlow kctx = ctx->ct_krb5ctx; 14254bff34e3Sthurlow kcc = ctx->ct_krb5cc; 14264bff34e3Sthurlow cprn = ctx->ct_krb5cp; 14274bff34e3Sthurlow 14284bff34e3Sthurlow failure = "krb5_set_default_tgs_enctypes"; 14294bff34e3Sthurlow if ((kerr = krb5_set_default_tgs_enctypes(kctx, kenctypes))) 14304bff34e3Sthurlow goto out; 14314bff34e3Sthurlow /* 14324bff34e3Sthurlow * The following is an unrolling of krb5_mk_req. Something like: 14334bff34e3Sthurlow * krb5_mk_req(kctx, &kauth, 0, service(prin), hostname(prin), 14344bff34e3Sthurlow * &kdata0, kcc, &kdata);) 14354bff34e3Sthurlow * ...except we needed krb5_parse_name not krb5_sname_to_principal. 14364bff34e3Sthurlow */ 14374bff34e3Sthurlow failure = "krb5_parse_name"; 14384bff34e3Sthurlow if ((kerr = krb5_parse_name(kctx, prin, &kprin))) 14394bff34e3Sthurlow goto out; 14404bff34e3Sthurlow failure = "krb5_copy_principal(server)"; 14414bff34e3Sthurlow if ((kerr = krb5_copy_principal(kctx, kprin, &kcreds.server))) 14424bff34e3Sthurlow goto out; 14434bff34e3Sthurlow failure = "krb5_copy_principal(client)"; 14444bff34e3Sthurlow if ((kerr = krb5_copy_principal(kctx, cprn, &kcreds.client))) 14454bff34e3Sthurlow goto out; 14464bff34e3Sthurlow failure = "krb5_get_credentials"; 14474bff34e3Sthurlow if ((kerr = krb5_get_credentials(kctx, 0, kcc, &kcreds, &kcredsp))) 14484bff34e3Sthurlow goto out; 14494bff34e3Sthurlow failure = "krb5_mk_req_extended"; 14504bff34e3Sthurlow if ((kerr = krb5_mk_req_extended(kctx, &kauth, 0, &kdata0, kcredsp, 14514bff34e3Sthurlow &kdata))) 14524bff34e3Sthurlow goto out; 14534bff34e3Sthurlow failure = "malloc"; 14544bff34e3Sthurlow if (!(tkt = malloc(kdata.length))) { 14554bff34e3Sthurlow krb5_free_data_contents(kctx, &kdata); 14564bff34e3Sthurlow goto out; 14574bff34e3Sthurlow } 14584bff34e3Sthurlow *tktlenp = kdata.length; 14594bff34e3Sthurlow memcpy(tkt, kdata.data, kdata.length); 14604bff34e3Sthurlow krb5_free_data_contents(kctx, &kdata); 14614bff34e3Sthurlow *tktp = tkt; 14624bff34e3Sthurlow failure = NULL; 14634bff34e3Sthurlow out:; 14644bff34e3Sthurlow if (kerr) { 14654bff34e3Sthurlow if (!failure) 14664bff34e3Sthurlow failure = "smb_ctx_principal2tkt"; 14674bff34e3Sthurlow /* 14684bff34e3Sthurlow * Avoid logging the typical "No credentials cache found" 14694bff34e3Sthurlow */ 14704bff34e3Sthurlow if (kerr != KRB5_FCC_NOFILE || 14714bff34e3Sthurlow strcmp(failure, "krb5_cc_get_principal")) 14724bff34e3Sthurlow com_err(__progname, kerr, failure); 14734bff34e3Sthurlow } 14744bff34e3Sthurlow if (kauth) 14754bff34e3Sthurlow krb5_auth_con_free(kctx, kauth); 14764bff34e3Sthurlow if (kcredsp) 14774bff34e3Sthurlow krb5_free_creds(kctx, kcredsp); 14784bff34e3Sthurlow if (kcreds.server || kcreds.client) 14794bff34e3Sthurlow krb5_free_cred_contents(kctx, &kcreds); 14804bff34e3Sthurlow if (kprin) 14814bff34e3Sthurlow krb5_free_principal(kctx, kprin); 14824bff34e3Sthurlow 14834bff34e3Sthurlow /* Free kctx in smb_ctx_done */ 14844bff34e3Sthurlow 14854bff34e3Sthurlow return (failure); 14864bff34e3Sthurlow } 14874bff34e3Sthurlow 14884bff34e3Sthurlow char * 14894bff34e3Sthurlow smb_ctx_principal2blob( 14904bff34e3Sthurlow struct smb_ctx *ctx, 14914bff34e3Sthurlow smbioc_ossn_t *ssn, 14924bff34e3Sthurlow char *prin) 14934bff34e3Sthurlow { 14944bff34e3Sthurlow int rc = 0; 14954bff34e3Sthurlow char *failure; 14964bff34e3Sthurlow uchar_t *tkt = NULL; 14974bff34e3Sthurlow ulong_t tktlen; 14984bff34e3Sthurlow uchar_t *gtok = NULL; /* gssapi token */ 14994bff34e3Sthurlow ulong_t gtoklen; /* gssapi token length */ 15004bff34e3Sthurlow SPNEGO_TOKEN_HANDLE stok = NULL; /* spnego token */ 15014bff34e3Sthurlow void *blob = NULL; /* result */ 15024bff34e3Sthurlow ulong_t bloblen; /* result length */ 15034bff34e3Sthurlow 15044bff34e3Sthurlow if ((failure = smb_ctx_principal2tkt(ctx, prin, &tkt, &tktlen))) 15054bff34e3Sthurlow goto out; 15064bff34e3Sthurlow if ((failure = smb_ctx_tkt2gtok(tkt, tktlen, >ok, >oklen))) 15074bff34e3Sthurlow goto out; 15084bff34e3Sthurlow /* 15094bff34e3Sthurlow * RFC says to send NegTokenTarg now. So does MS docs. But 15104bff34e3Sthurlow * win2k gives ERRbaduid if we do... we must send 15114bff34e3Sthurlow * another NegTokenInit now! 15124bff34e3Sthurlow */ 15134bff34e3Sthurlow failure = "spnegoCreateNegTokenInit"; 15144bff34e3Sthurlow if ((rc = spnegoCreateNegTokenInit(spnego_mech_oid_Kerberos_V5_Legacy, 15154bff34e3Sthurlow 0, gtok, gtoklen, NULL, 0, &stok))) 15164bff34e3Sthurlow goto out; 15174bff34e3Sthurlow failure = "spnegoTokenGetBinary(NULL)"; 15184bff34e3Sthurlow rc = spnegoTokenGetBinary(stok, NULL, &bloblen); 15194bff34e3Sthurlow if (rc != SPNEGO_E_BUFFER_TOO_SMALL) 15204bff34e3Sthurlow goto out; 15214bff34e3Sthurlow failure = "malloc"; 15224bff34e3Sthurlow if (!(blob = malloc((size_t)bloblen))) 15234bff34e3Sthurlow goto out; 15244bff34e3Sthurlow /* No longer store length at start of blob. */ 15254bff34e3Sthurlow /* *blob = bloblen; */ 15264bff34e3Sthurlow failure = "spnegoTokenGetBinary"; 15274bff34e3Sthurlow if ((rc = spnegoTokenGetBinary(stok, blob, &bloblen))) 15284bff34e3Sthurlow goto out; 15294bff34e3Sthurlow ssn->ioc_intoklen = bloblen; 15304bff34e3Sthurlow ssn->ioc_intok = blob; 15314bff34e3Sthurlow failure = NULL; 15324bff34e3Sthurlow out:; 15334bff34e3Sthurlow if (rc) { 15344bff34e3Sthurlow /* XXX better is to embed rc in failure */ 15354bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 15364bff34e3Sthurlow "spnego principal2blob error %d"), 0, -rc); 15374bff34e3Sthurlow if (!failure) 15384bff34e3Sthurlow failure = "spnego"; 15394bff34e3Sthurlow } 15404bff34e3Sthurlow if (blob && failure) 15414bff34e3Sthurlow free(blob); 15424bff34e3Sthurlow if (stok) 15434bff34e3Sthurlow spnegoFreeData(stok); 15444bff34e3Sthurlow if (gtok) 15454bff34e3Sthurlow free(gtok); 15464bff34e3Sthurlow if (tkt) 15474bff34e3Sthurlow free(tkt); 15484bff34e3Sthurlow return (failure); 15494bff34e3Sthurlow } 15504bff34e3Sthurlow 15514bff34e3Sthurlow 15524bff34e3Sthurlow #if 0 15534bff34e3Sthurlow void 15544bff34e3Sthurlow prblob(uchar_t *b, size_t len) 15554bff34e3Sthurlow { 15564bff34e3Sthurlow while (len--) 15574bff34e3Sthurlow fprintf(stderr, "%02x", *b++); 15584bff34e3Sthurlow fprintf(stderr, "\n"); 15594bff34e3Sthurlow } 15604bff34e3Sthurlow #endif 15614bff34e3Sthurlow 15624bff34e3Sthurlow 15634bff34e3Sthurlow /* 15644bff34e3Sthurlow * We navigate the SPNEGO & ASN1 encoding to find a kerberos principal 15654bff34e3Sthurlow * Note: driver no longer puts length at start of blob. 15664bff34e3Sthurlow */ 15674bff34e3Sthurlow char * 15684bff34e3Sthurlow smb_ctx_blob2principal( 15694bff34e3Sthurlow struct smb_ctx *ctx, 15704bff34e3Sthurlow smbioc_ossn_t *ssn, 15714bff34e3Sthurlow char **prinp) 15724bff34e3Sthurlow { 15734bff34e3Sthurlow uchar_t *blob = ssn->ioc_outtok; 15744bff34e3Sthurlow size_t len = ssn->ioc_outtoklen; 15754bff34e3Sthurlow int rc = 0; 15764bff34e3Sthurlow SPNEGO_TOKEN_HANDLE stok = NULL; 15774bff34e3Sthurlow int indx = 0; 15784bff34e3Sthurlow char *failure; 15794bff34e3Sthurlow uchar_t flags = 0; 15804bff34e3Sthurlow unsigned long plen = 0; 15814bff34e3Sthurlow uchar_t *prin; 15824bff34e3Sthurlow 15834bff34e3Sthurlow #if 0 15844bff34e3Sthurlow fprintf(stderr, "blob from negotiate:\n"); 15854bff34e3Sthurlow prblob(blob, len); 15864bff34e3Sthurlow #endif 15874bff34e3Sthurlow 15884bff34e3Sthurlow /* Skip the GUID */ 15894bff34e3Sthurlow assert(len >= SMB_GUIDLEN); 15904bff34e3Sthurlow blob += SMB_GUIDLEN; 15914bff34e3Sthurlow len -= SMB_GUIDLEN; 15924bff34e3Sthurlow 15934bff34e3Sthurlow failure = "spnegoInitFromBinary"; 15944bff34e3Sthurlow if ((rc = spnegoInitFromBinary(blob, len, &stok))) 15954bff34e3Sthurlow goto out; 15964bff34e3Sthurlow /* 15974bff34e3Sthurlow * Needn't use new Kerberos OID - the Legacy one is fine. 15984bff34e3Sthurlow */ 15994bff34e3Sthurlow failure = "spnegoIsMechTypeAvailable"; 16004bff34e3Sthurlow if (spnegoIsMechTypeAvailable(stok, spnego_mech_oid_Kerberos_V5_Legacy, 16014bff34e3Sthurlow &indx)) 16024bff34e3Sthurlow goto out; 16034bff34e3Sthurlow /* 16044bff34e3Sthurlow * Ignoring optional context flags for now. May want to pass 16054bff34e3Sthurlow * them to krb5 layer. XXX 16064bff34e3Sthurlow */ 16074bff34e3Sthurlow if (!spnegoGetContextFlags(stok, &flags)) 16084bff34e3Sthurlow fprintf(stderr, dgettext(TEXT_DOMAIN, 16094bff34e3Sthurlow "spnego context flags 0x%x\n"), flags); 16104bff34e3Sthurlow failure = "spnegoGetMechListMIC(NULL)"; 16114bff34e3Sthurlow rc = spnegoGetMechListMIC(stok, NULL, &plen); 16124bff34e3Sthurlow if (rc != SPNEGO_E_BUFFER_TOO_SMALL) 16134bff34e3Sthurlow goto out; 16144bff34e3Sthurlow failure = "malloc"; 16154bff34e3Sthurlow if (!(prin = malloc(plen + 1))) 16164bff34e3Sthurlow goto out; 16174bff34e3Sthurlow failure = "spnegoGetMechListMIC"; 16184bff34e3Sthurlow if ((rc = spnegoGetMechListMIC(stok, prin, &plen))) { 16194bff34e3Sthurlow free(prin); 16204bff34e3Sthurlow goto out; 16214bff34e3Sthurlow } 16224bff34e3Sthurlow prin[plen] = '\0'; 16234bff34e3Sthurlow *prinp = (char *)prin; 16244bff34e3Sthurlow failure = NULL; 16254bff34e3Sthurlow out:; 16264bff34e3Sthurlow if (stok) 16274bff34e3Sthurlow spnegoFreeData(stok); 16284bff34e3Sthurlow if (rc) { 16294bff34e3Sthurlow /* XXX better is to embed rc in failure */ 16304bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 16314bff34e3Sthurlow "spnego blob2principal error %d"), 0, -rc); 16324bff34e3Sthurlow if (!failure) 16334bff34e3Sthurlow failure = "spnego"; 16344bff34e3Sthurlow } 16354bff34e3Sthurlow return (failure); 16364bff34e3Sthurlow } 16374bff34e3Sthurlow 16384bff34e3Sthurlow 16394bff34e3Sthurlow int 16404bff34e3Sthurlow smb_ctx_negotiate(struct smb_ctx *ctx, int level, int flags, char *workgroup) 16414bff34e3Sthurlow { 16424bff34e3Sthurlow struct smbioc_lookup rq; 16434bff34e3Sthurlow int error = 0; 16444bff34e3Sthurlow char *failure = NULL; 16454bff34e3Sthurlow char *principal = NULL; 16464bff34e3Sthurlow char c; 16474bff34e3Sthurlow int i; 16484bff34e3Sthurlow ssize_t *outtoklen; 16494bff34e3Sthurlow uchar_t *blob; 16504bff34e3Sthurlow 16514bff34e3Sthurlow /* 16524bff34e3Sthurlow * We leave ct_secblob set iff extended security 16534bff34e3Sthurlow * negotiation succeeds. 16544bff34e3Sthurlow */ 16554bff34e3Sthurlow if (ctx->ct_secblob) { 16564bff34e3Sthurlow free(ctx->ct_secblob); 16574bff34e3Sthurlow ctx->ct_secblob = NULL; 16584bff34e3Sthurlow } 16594bff34e3Sthurlow #ifdef XXX 16604bff34e3Sthurlow if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 16614bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 16624bff34e3Sthurlow "smb_ctx_lookup() data is not resolved"), 0); 16634bff34e3Sthurlow return (EINVAL); 16644bff34e3Sthurlow } 16654bff34e3Sthurlow #endif 16664bff34e3Sthurlow if ((error = smb_ctx_gethandle(ctx))) 16674bff34e3Sthurlow return (error); 16684bff34e3Sthurlow 16694bff34e3Sthurlow bzero(&rq, sizeof (rq)); 16704bff34e3Sthurlow bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 16714bff34e3Sthurlow bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 16724bff34e3Sthurlow 16734bff34e3Sthurlow /* 16744bff34e3Sthurlow * Find out if we have a Kerberos ticket, 16754bff34e3Sthurlow * and only offer SPNEGO if we have one. 16764bff34e3Sthurlow */ 16774bff34e3Sthurlow failure = smb_ctx_krb5init(ctx); 16784bff34e3Sthurlow if (failure) { 16794bff34e3Sthurlow if (smb_verbose) 16804bff34e3Sthurlow smb_error(failure, 0); 16814bff34e3Sthurlow goto out; 16824bff34e3Sthurlow } 16834bff34e3Sthurlow 16844bff34e3Sthurlow rq.ioc_flags = flags; 16854bff34e3Sthurlow rq.ioc_level = level; 16864bff34e3Sthurlow rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC; 16874bff34e3Sthurlow error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq); 16884bff34e3Sthurlow if (error) { 16894bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "negotiate failed"); 16904bff34e3Sthurlow smb_error(failure, error); 16914bff34e3Sthurlow if (error == ETIMEDOUT) 16924bff34e3Sthurlow return (error); 16934bff34e3Sthurlow goto out; 16944bff34e3Sthurlow } 16954bff34e3Sthurlow /* 16964bff34e3Sthurlow * If the server capabilities did not include 16974bff34e3Sthurlow * SMB_CAP_EXT_SECURITY then the driver clears 16984bff34e3Sthurlow * the flag SMBVOPT_EXT_SEC for us. 16994bff34e3Sthurlow * XXX: should add the capabilities to ioc_ssn 17004bff34e3Sthurlow * XXX: see comment in driver - smb_usr.c 17014bff34e3Sthurlow */ 17024bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "SPNEGO unsupported"); 17034bff34e3Sthurlow if ((rq.ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC) == 0) { 17044bff34e3Sthurlow if (smb_verbose) 17054bff34e3Sthurlow smb_error(failure, 0); 17064bff34e3Sthurlow /* 17074bff34e3Sthurlow * Do regular (old style) NTLM or NTLMv2 17084bff34e3Sthurlow * Nothing more to do here in negotiate. 17094bff34e3Sthurlow */ 17104bff34e3Sthurlow return (0); 17114bff34e3Sthurlow } 17124bff34e3Sthurlow 17134bff34e3Sthurlow /* 17144bff34e3Sthurlow * Capabilities DO include SMB_CAP_EXT_SECURITY, 17154bff34e3Sthurlow * so this should be an SPNEGO security blob. 17164bff34e3Sthurlow * Parse the ASN.1/DER, prepare response(s). 17174bff34e3Sthurlow * XXX: Handle STATUS_MORE_PROCESSING_REQUIRED? 17184bff34e3Sthurlow * XXX: Requires additional session setup calls. 17194bff34e3Sthurlow */ 17204bff34e3Sthurlow if (rq.ioc_ssn.ioc_outtoklen <= SMB_GUIDLEN) 17214bff34e3Sthurlow goto out; 17224bff34e3Sthurlow /* some servers send padding junk */ 17234bff34e3Sthurlow blob = rq.ioc_ssn.ioc_outtok; 17244bff34e3Sthurlow if (blob[0] == 0) 17254bff34e3Sthurlow goto out; 17264bff34e3Sthurlow 17274bff34e3Sthurlow failure = smb_ctx_blob2principal( 17284bff34e3Sthurlow ctx, &rq.ioc_ssn, &principal); 17294bff34e3Sthurlow if (failure) 17304bff34e3Sthurlow goto out; 17314bff34e3Sthurlow failure = smb_ctx_principal2blob( 17324bff34e3Sthurlow ctx, &rq.ioc_ssn, principal); 17334bff34e3Sthurlow if (failure) 17344bff34e3Sthurlow goto out; 17354bff34e3Sthurlow 17364bff34e3Sthurlow /* Success! Save the blob to send next. */ 17374bff34e3Sthurlow ctx->ct_secblob = rq.ioc_ssn.ioc_intok; 17384bff34e3Sthurlow ctx->ct_secbloblen = rq.ioc_ssn.ioc_intoklen; 17394bff34e3Sthurlow rq.ioc_ssn.ioc_intok = NULL; 17404bff34e3Sthurlow 17414bff34e3Sthurlow out: 17424bff34e3Sthurlow if (principal) 17434bff34e3Sthurlow free(principal); 17444bff34e3Sthurlow if (rq.ioc_ssn.ioc_intok) 17454bff34e3Sthurlow free(rq.ioc_ssn.ioc_intok); 17464bff34e3Sthurlow if (rq.ioc_ssn.ioc_outtok) 17474bff34e3Sthurlow free(rq.ioc_ssn.ioc_outtok); 17484bff34e3Sthurlow if (!failure) 17494bff34e3Sthurlow return (0); /* Success! */ 17504bff34e3Sthurlow 17514bff34e3Sthurlow /* 17524bff34e3Sthurlow * Negotiate failed with "extended security". 17534bff34e3Sthurlow * 17544bff34e3Sthurlow * XXX: If we are doing SPNEGO correctly, 17554bff34e3Sthurlow * we should never get here unless the user 17564bff34e3Sthurlow * supplied invalid authentication data, 17574bff34e3Sthurlow * or we saw some kind of protocol error. 17584bff34e3Sthurlow * 17594bff34e3Sthurlow * XXX: The error message below should be 17604bff34e3Sthurlow * XXX: unconditional (remove "if verbose") 17614bff34e3Sthurlow * XXX: but not until we have "NTLMSSP" 17624bff34e3Sthurlow * Avoid spew for anticipated failure modes 17634bff34e3Sthurlow * but enable this with the verbose flag 17644bff34e3Sthurlow */ 17654bff34e3Sthurlow if (smb_verbose) { 17664bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 17674bff34e3Sthurlow "%s (extended security negotiate)"), error, failure); 17684bff34e3Sthurlow } 17694bff34e3Sthurlow 17704bff34e3Sthurlow /* 17714bff34e3Sthurlow * XXX: Try again using NTLM (or NTLMv2) 17724bff34e3Sthurlow * XXX: Normal clients don't do this. 17734bff34e3Sthurlow * XXX: Should just return an error, but 17744bff34e3Sthurlow * keep the fall-back to NTLM for now. 17754bff34e3Sthurlow * 17764bff34e3Sthurlow * Start over with a new connection. 17774bff34e3Sthurlow */ 17784bff34e3Sthurlow if ((error = smb_ctx_gethandle(ctx))) 17794bff34e3Sthurlow return (error); 17804bff34e3Sthurlow bzero(&rq, sizeof (rq)); 17814bff34e3Sthurlow bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 17824bff34e3Sthurlow bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 17834bff34e3Sthurlow rq.ioc_flags = flags; 17844bff34e3Sthurlow rq.ioc_level = level; 17854bff34e3Sthurlow /* Note: NO SMBVOPT_EXT_SEC */ 17864bff34e3Sthurlow error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq); 17874bff34e3Sthurlow if (error) { 17884bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "negotiate failed"); 17894bff34e3Sthurlow smb_error(failure, error); 17904bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 17914bff34e3Sthurlow close(ctx->ct_fd); 17924bff34e3Sthurlow ctx->ct_fd = -1; 17934bff34e3Sthurlow return (error); 17944bff34e3Sthurlow } 17954bff34e3Sthurlow 17964bff34e3Sthurlow /* 17974bff34e3Sthurlow * Used to copy the workgroup out of the SMB_NEGOTIATE response 17984bff34e3Sthurlow * here, to default our domain name to be the same as the server. 17994bff34e3Sthurlow * Not a good idea: Unnecessary at best, and sometimes wrong, i.e. 18004bff34e3Sthurlow * when our account is in a trusted domain. 18014bff34e3Sthurlow */ 18024bff34e3Sthurlow 18034bff34e3Sthurlow return (error); 18044bff34e3Sthurlow } 18054bff34e3Sthurlow 18064bff34e3Sthurlow 18074bff34e3Sthurlow int 18084bff34e3Sthurlow smb_ctx_tdis(struct smb_ctx *ctx) 18094bff34e3Sthurlow { 18104bff34e3Sthurlow struct smbioc_lookup rq; /* XXX may be used, someday */ 18114bff34e3Sthurlow int error = 0; 18124bff34e3Sthurlow 18134bff34e3Sthurlow if (ctx->ct_fd < 0) { 18144bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 18154bff34e3Sthurlow "tree disconnect without handle?!"), 0); 18164bff34e3Sthurlow return (EINVAL); 18174bff34e3Sthurlow } 18184bff34e3Sthurlow if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) { 18194bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 18204bff34e3Sthurlow "tree disconnect without session?!"), 0); 18214bff34e3Sthurlow return (EINVAL); 18224bff34e3Sthurlow } 18234bff34e3Sthurlow bzero(&rq, sizeof (rq)); 18244bff34e3Sthurlow bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 18254bff34e3Sthurlow bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 18264bff34e3Sthurlow if (ioctl(ctx->ct_fd, SMBIOC_TDIS, &rq) == -1) { 18274bff34e3Sthurlow error = errno; 18284bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 18294bff34e3Sthurlow "tree disconnect failed"), error); 18304bff34e3Sthurlow } 18314bff34e3Sthurlow return (error); 18324bff34e3Sthurlow } 18334bff34e3Sthurlow 18344bff34e3Sthurlow 18354bff34e3Sthurlow int 18364bff34e3Sthurlow smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) 18374bff34e3Sthurlow { 18384bff34e3Sthurlow struct smbioc_lookup rq; 18394bff34e3Sthurlow int error = 0; 18404bff34e3Sthurlow char *failure = NULL; 18414bff34e3Sthurlow 18424bff34e3Sthurlow if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 18434bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 18444bff34e3Sthurlow "smb_ctx_lookup() data is not resolved"), 0); 18454bff34e3Sthurlow return (EINVAL); 18464bff34e3Sthurlow } 18474bff34e3Sthurlow if (ctx->ct_fd < 0) { 18484bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 18494bff34e3Sthurlow "handle from smb_ctx_nego() gone?!"), 0); 18504bff34e3Sthurlow return (EINVAL); 18514bff34e3Sthurlow } 18524bff34e3Sthurlow if (!(flags & SMBLK_CREATE)) 18534bff34e3Sthurlow return (0); 18544bff34e3Sthurlow bzero(&rq, sizeof (rq)); 18554bff34e3Sthurlow bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 18564bff34e3Sthurlow bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 18574bff34e3Sthurlow rq.ioc_flags = flags; 18584bff34e3Sthurlow rq.ioc_level = level; 18594bff34e3Sthurlow 18604bff34e3Sthurlow /* 18614bff34e3Sthurlow * Iff we have a security blob, we're using 18624bff34e3Sthurlow * extended security... 18634bff34e3Sthurlow */ 18644bff34e3Sthurlow if (ctx->ct_secblob) { 18654bff34e3Sthurlow rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC; 18664bff34e3Sthurlow if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) { 18674bff34e3Sthurlow rq.ioc_ssn.ioc_intok = ctx->ct_secblob; 18684bff34e3Sthurlow rq.ioc_ssn.ioc_intoklen = ctx->ct_secbloblen; 18694bff34e3Sthurlow error = smb_ctx_ioctl(ctx, SMBIOC_SSNSETUP, &rq); 18704bff34e3Sthurlow } 18714bff34e3Sthurlow rq.ioc_ssn.ioc_intok = NULL; 18724bff34e3Sthurlow if (error) { 18734bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, 18744bff34e3Sthurlow "session setup failed"); 18754bff34e3Sthurlow } else { 18764bff34e3Sthurlow ctx->ct_flags |= SMBCF_SSNACTIVE; 18774bff34e3Sthurlow if ((error = smb_ctx_ioctl(ctx, SMBIOC_TCON, &rq))) 18784bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, 18794bff34e3Sthurlow "tree connect failed"); 18804bff34e3Sthurlow } 18814bff34e3Sthurlow if (rq.ioc_ssn.ioc_intok) 18824bff34e3Sthurlow free(rq.ioc_ssn.ioc_intok); 18834bff34e3Sthurlow if (rq.ioc_ssn.ioc_outtok) 18844bff34e3Sthurlow free(rq.ioc_ssn.ioc_outtok); 18854bff34e3Sthurlow if (!failure) 18864bff34e3Sthurlow return (0); 18874bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 18884bff34e3Sthurlow "%s (extended security lookup2)"), error, failure); 18894bff34e3Sthurlow /* unwise to failback to NTLM now */ 18904bff34e3Sthurlow return (error); 18914bff34e3Sthurlow } 18924bff34e3Sthurlow 18934bff34e3Sthurlow /* 18944bff34e3Sthurlow * Otherwise we're doing plain old NTLM 18954bff34e3Sthurlow */ 18964bff34e3Sthurlow if ((ctx->ct_flags & SMBCF_SSNACTIVE) == 0) { 18974bff34e3Sthurlow /* 18984bff34e3Sthurlow * This is the magic that tells the driver to 18994bff34e3Sthurlow * copy the password from the keychain, and 19004bff34e3Sthurlow * whether to use the system name or the 19014bff34e3Sthurlow * account domain to lookup the keychain. 19024bff34e3Sthurlow */ 19034bff34e3Sthurlow if (ctx->ct_flags & SMBCF_KCFOUND) 19044bff34e3Sthurlow rq.ioc_ssn.ioc_opt |= SMBVOPT_USE_KEYCHAIN; 19054bff34e3Sthurlow if (ctx->ct_flags & SMBCF_KCDOMAIN) 19064bff34e3Sthurlow rq.ioc_ssn.ioc_opt |= SMBVOPT_KC_DOMAIN; 19074bff34e3Sthurlow if (ioctl(ctx->ct_fd, SMBIOC_SSNSETUP, &rq) < 0) { 19084bff34e3Sthurlow error = errno; 19094bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "session setup"); 19104bff34e3Sthurlow goto out; 19114bff34e3Sthurlow } 19124bff34e3Sthurlow ctx->ct_flags |= SMBCF_SSNACTIVE; 19134bff34e3Sthurlow } 19144bff34e3Sthurlow if (ioctl(ctx->ct_fd, SMBIOC_TCON, &rq) == -1) { 19154bff34e3Sthurlow error = errno; 19164bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "tree connect"); 19174bff34e3Sthurlow } 19184bff34e3Sthurlow 19194bff34e3Sthurlow out: 19204bff34e3Sthurlow if (failure) { 19214bff34e3Sthurlow error = errno; 19224bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 19234bff34e3Sthurlow "%s phase failed"), error, failure); 19244bff34e3Sthurlow } 19254bff34e3Sthurlow return (error); 19264bff34e3Sthurlow } 19274bff34e3Sthurlow 19284bff34e3Sthurlow /* 19294bff34e3Sthurlow * Return the hflags2 word for an smb_ctx. 19304bff34e3Sthurlow */ 19314bff34e3Sthurlow int 19324bff34e3Sthurlow smb_ctx_flags2(struct smb_ctx *ctx) 19334bff34e3Sthurlow { 19344bff34e3Sthurlow uint16_t flags2; 19354bff34e3Sthurlow 19364bff34e3Sthurlow if (ioctl(ctx->ct_fd, SMBIOC_FLAGS2, &flags2) == -1) { 19374bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 19384bff34e3Sthurlow "can't get flags2 for a session"), errno); 19394bff34e3Sthurlow return (-1); 19404bff34e3Sthurlow } 19414bff34e3Sthurlow return (flags2); 19424bff34e3Sthurlow } 19434bff34e3Sthurlow 19444bff34e3Sthurlow /* 19454bff34e3Sthurlow * level values: 19464bff34e3Sthurlow * 0 - default 19474bff34e3Sthurlow * 1 - server 19484bff34e3Sthurlow * 2 - server:user 19494bff34e3Sthurlow * 3 - server:user:share 19504bff34e3Sthurlow */ 19514bff34e3Sthurlow static int 19524bff34e3Sthurlow smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 19534bff34e3Sthurlow { 19544bff34e3Sthurlow char *p; 19554bff34e3Sthurlow int error; 19564bff34e3Sthurlow 19574bff34e3Sthurlow #ifdef NOT_DEFINED 19584bff34e3Sthurlow if (level > 0) { 19594bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "charsets", &p); 19604bff34e3Sthurlow if (p) { 19614bff34e3Sthurlow error = smb_ctx_setcharset(ctx, p); 19624bff34e3Sthurlow if (error) 19634bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 19644bff34e3Sthurlow "charset specification in the section '%s' ignored"), 19654bff34e3Sthurlow error, sname); 19664bff34e3Sthurlow } 19674bff34e3Sthurlow } 19684bff34e3Sthurlow #endif 19694bff34e3Sthurlow 19704bff34e3Sthurlow if (level <= 1) { 19714bff34e3Sthurlow /* Section is: [default] or [server] */ 19724bff34e3Sthurlow 19734bff34e3Sthurlow rc_getint(smb_rc, sname, "timeout", 19744bff34e3Sthurlow &ctx->ct_ssn.ioc_timeout); 19754bff34e3Sthurlow 19764bff34e3Sthurlow #ifdef NOT_DEFINED 19774bff34e3Sthurlow rc_getint(smb_rc, sname, "retry_count", 19784bff34e3Sthurlow &ctx->ct_ssn.ioc_retrycount); 19794bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "use_negprot_domain", &p); 19804bff34e3Sthurlow if (p && strcmp(p, "NO") == 0) 19814bff34e3Sthurlow ctx->ct_flags |= SMBCF_NONEGDOM; 19824bff34e3Sthurlow #endif 19834bff34e3Sthurlow 19844bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "minauth", &p); 19854bff34e3Sthurlow if (p) { 19864bff34e3Sthurlow /* 19874bff34e3Sthurlow * "minauth" was set in this section; override 19884bff34e3Sthurlow * the current minimum authentication setting. 19894bff34e3Sthurlow */ 19904bff34e3Sthurlow ctx->ct_ssn.ioc_opt &= ~SMBVOPT_MINAUTH; 19914bff34e3Sthurlow if (strcmp(p, "kerberos") == 0) { 19924bff34e3Sthurlow /* 19934bff34e3Sthurlow * Don't fall back to NTLMv2, NTLMv1, or 19944bff34e3Sthurlow * a clear text password. 19954bff34e3Sthurlow */ 19964bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_KERBEROS; 19974bff34e3Sthurlow } else if (strcmp(p, "ntlmv2") == 0) { 19984bff34e3Sthurlow /* 19994bff34e3Sthurlow * Don't fall back to NTLMv1 or a clear 20004bff34e3Sthurlow * text password. 20014bff34e3Sthurlow */ 20024bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLMV2; 20034bff34e3Sthurlow } else if (strcmp(p, "ntlm") == 0) { 20044bff34e3Sthurlow /* 20054bff34e3Sthurlow * Don't send the LM response over the wire. 20064bff34e3Sthurlow */ 20074bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLM; 20084bff34e3Sthurlow } else if (strcmp(p, "lm") == 0) { 20094bff34e3Sthurlow /* 20104bff34e3Sthurlow * Fail if the server doesn't do encrypted 20114bff34e3Sthurlow * passwords. 20124bff34e3Sthurlow */ 20134bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_LM; 20144bff34e3Sthurlow } else if (strcmp(p, "none") == 0) { 20154bff34e3Sthurlow /* 20164bff34e3Sthurlow * Anything goes. 20174bff34e3Sthurlow * (The following statement should be 20184bff34e3Sthurlow * optimized away.) 20194bff34e3Sthurlow */ 20204bff34e3Sthurlow /* LINTED */ 20214bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NONE; 20224bff34e3Sthurlow } else { 20234bff34e3Sthurlow /* 20244bff34e3Sthurlow * Unknown minimum authentication level. 20254bff34e3Sthurlow */ 20264bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 20274bff34e3Sthurlow "invalid minimum authentication level \"%s\" specified in the section %s"), 20284bff34e3Sthurlow 0, p, sname); 20294bff34e3Sthurlow return (EINVAL); 20304bff34e3Sthurlow } 20314bff34e3Sthurlow } 20324bff34e3Sthurlow 2033*9c9af259SGordon Ross rc_getstringptr(smb_rc, sname, "signing", &p); 2034*9c9af259SGordon Ross if (p) { 2035*9c9af259SGordon Ross /* 2036*9c9af259SGordon Ross * "signing" was set in this section; override 2037*9c9af259SGordon Ross * the current signing settings. 2038*9c9af259SGordon Ross */ 2039*9c9af259SGordon Ross ctx->ct_ssn.ioc_opt &= ~SMBVOPT_SIGNING_MASK; 2040*9c9af259SGordon Ross if (strcmp(p, "disabled") == 0) { 2041*9c9af259SGordon Ross /* leave flags zero (expr for lint) */ 2042*9c9af259SGordon Ross (void) ctx->ct_ssn.ioc_opt; 2043*9c9af259SGordon Ross } else if (strcmp(p, "enabled") == 0) { 2044*9c9af259SGordon Ross ctx->ct_ssn.ioc_opt |= 2045*9c9af259SGordon Ross SMBVOPT_SIGNING_ENABLED; 2046*9c9af259SGordon Ross } else if (strcmp(p, "required") == 0) { 2047*9c9af259SGordon Ross ctx->ct_ssn.ioc_opt |= 2048*9c9af259SGordon Ross SMBVOPT_SIGNING_ENABLED | 2049*9c9af259SGordon Ross SMBVOPT_SIGNING_REQUIRED; 2050*9c9af259SGordon Ross } else { 2051*9c9af259SGordon Ross /* 2052*9c9af259SGordon Ross * Unknown "signing" value. 2053*9c9af259SGordon Ross */ 2054*9c9af259SGordon Ross smb_error(dgettext(TEXT_DOMAIN, 2055*9c9af259SGordon Ross "invalid signing policy \"%s\" specified in the section %s"), 2056*9c9af259SGordon Ross 0, p, sname); 2057*9c9af259SGordon Ross return (EINVAL); 2058*9c9af259SGordon Ross } 2059*9c9af259SGordon Ross } 2060*9c9af259SGordon Ross 20614bff34e3Sthurlow /* 20624bff34e3Sthurlow * Domain name. Allow both keywords: 20634bff34e3Sthurlow * "workgroup", "domain" 20644bff34e3Sthurlow * 20654bff34e3Sthurlow * Note: these are NOT marked "from CMD". 20664bff34e3Sthurlow * See long comment at smb_ctx_init() 20674bff34e3Sthurlow */ 20684bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "workgroup", &p); 20694bff34e3Sthurlow if (p) { 20704bff34e3Sthurlow nls_str_upper(p, p); 20714bff34e3Sthurlow error = smb_ctx_setworkgroup(ctx, p, 0); 20724bff34e3Sthurlow if (error) 20734bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 20744bff34e3Sthurlow "workgroup specification in the " 20754bff34e3Sthurlow "section '%s' ignored"), error, sname); 20764bff34e3Sthurlow } 20774bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "domain", &p); 20784bff34e3Sthurlow if (p) { 20794bff34e3Sthurlow nls_str_upper(p, p); 20804bff34e3Sthurlow error = smb_ctx_setworkgroup(ctx, p, 0); 20814bff34e3Sthurlow if (error) 20824bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 20834bff34e3Sthurlow "domain specification in the " 20844bff34e3Sthurlow "section '%s' ignored"), error, sname); 20854bff34e3Sthurlow } 20864bff34e3Sthurlow 20874bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "user", &p); 20884bff34e3Sthurlow if (p) { 20894bff34e3Sthurlow error = smb_ctx_setuser(ctx, p, 0); 20904bff34e3Sthurlow if (error) 20914bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 20924bff34e3Sthurlow "user specification in the " 20934bff34e3Sthurlow "section '%s' ignored"), error, sname); 20944bff34e3Sthurlow } 20954bff34e3Sthurlow } 20964bff34e3Sthurlow 20974bff34e3Sthurlow if (level == 1) { 20984bff34e3Sthurlow /* Section is: [server] */ 20994bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "addr", &p); 21004bff34e3Sthurlow if (p) { 21014bff34e3Sthurlow error = smb_ctx_setsrvaddr(ctx, p); 21024bff34e3Sthurlow if (error) { 21034bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 21044bff34e3Sthurlow "invalid address specified in section %s"), 21054bff34e3Sthurlow 0, sname); 21064bff34e3Sthurlow return (error); 21074bff34e3Sthurlow } 21084bff34e3Sthurlow } 21094bff34e3Sthurlow } 21104bff34e3Sthurlow 21114bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "password", &p); 21124bff34e3Sthurlow if (p) { 21134bff34e3Sthurlow error = smb_ctx_setpassword(ctx, p, 0); 21144bff34e3Sthurlow if (error) 21154bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 21164bff34e3Sthurlow "password specification in the section '%s' ignored"), 21174bff34e3Sthurlow error, sname); 21184bff34e3Sthurlow } 21194bff34e3Sthurlow 21204bff34e3Sthurlow return (0); 21214bff34e3Sthurlow } 21224bff34e3Sthurlow 21234bff34e3Sthurlow /* 21244bff34e3Sthurlow * read rc file as follows: 21254bff34e3Sthurlow * 0: read [default] section 21264bff34e3Sthurlow * 1: override with [server] section 21274bff34e3Sthurlow * 2: override with [server:user] section 21284bff34e3Sthurlow * 3: override with [server:user:share] section 21294bff34e3Sthurlow * Since absence of rcfile is not fatal, silently ignore this fact. 21304bff34e3Sthurlow * smb_rc file should be closed by caller. 21314bff34e3Sthurlow */ 21324bff34e3Sthurlow int 21334bff34e3Sthurlow smb_ctx_readrc(struct smb_ctx *ctx) 21344bff34e3Sthurlow { 21354bff34e3Sthurlow char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + 21364bff34e3Sthurlow SMB_MAXSHARENAMELEN + 4]; 21374bff34e3Sthurlow 21384bff34e3Sthurlow if (smb_open_rcfile(ctx) != 0) 21394bff34e3Sthurlow goto done; 21404bff34e3Sthurlow 21414bff34e3Sthurlow /* 21424bff34e3Sthurlow * default parameters (level=0) 21434bff34e3Sthurlow */ 21444bff34e3Sthurlow smb_ctx_readrcsection(ctx, "default", 0); 21454bff34e3Sthurlow nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 21464bff34e3Sthurlow 21474bff34e3Sthurlow /* 21484bff34e3Sthurlow * If we don't have a server name, we can't read any of the 21494bff34e3Sthurlow * [server...] sections. 21504bff34e3Sthurlow */ 21514bff34e3Sthurlow if (ctx->ct_ssn.ioc_srvname[0] == 0) 21524bff34e3Sthurlow goto done; 21534bff34e3Sthurlow 21544bff34e3Sthurlow /* 21554bff34e3Sthurlow * SERVER parameters. 21564bff34e3Sthurlow */ 21574bff34e3Sthurlow smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1); 21584bff34e3Sthurlow 21594bff34e3Sthurlow /* 21604bff34e3Sthurlow * If we don't have a user name, we can't read any of the 21614bff34e3Sthurlow * [server:user...] sections. 21624bff34e3Sthurlow */ 21634bff34e3Sthurlow if (ctx->ct_ssn.ioc_user[0] == 0) 21644bff34e3Sthurlow goto done; 21654bff34e3Sthurlow 21664bff34e3Sthurlow /* 21674bff34e3Sthurlow * SERVER:USER parameters 21684bff34e3Sthurlow */ 21694bff34e3Sthurlow snprintf(sname, sizeof (sname), "%s:%s", 21704bff34e3Sthurlow ctx->ct_ssn.ioc_srvname, 21714bff34e3Sthurlow ctx->ct_ssn.ioc_user); 21724bff34e3Sthurlow smb_ctx_readrcsection(ctx, sname, 2); 21734bff34e3Sthurlow 21744bff34e3Sthurlow /* 21754bff34e3Sthurlow * If we don't have a share name, we can't read any of the 21764bff34e3Sthurlow * [server:user:share] sections. 21774bff34e3Sthurlow */ 21784bff34e3Sthurlow if (ctx->ct_sh.ioc_share[0] != 0) { 21794bff34e3Sthurlow /* 21804bff34e3Sthurlow * SERVER:USER:SHARE parameters 21814bff34e3Sthurlow */ 21824bff34e3Sthurlow snprintf(sname, sizeof (sname), "%s:%s:%s", 21834bff34e3Sthurlow ctx->ct_ssn.ioc_srvname, 21844bff34e3Sthurlow ctx->ct_ssn.ioc_user, 21854bff34e3Sthurlow ctx->ct_sh.ioc_share); 21864bff34e3Sthurlow smb_ctx_readrcsection(ctx, sname, 3); 21874bff34e3Sthurlow } 21884bff34e3Sthurlow 21894bff34e3Sthurlow done: 21904bff34e3Sthurlow if (smb_debug) 21914bff34e3Sthurlow dump_ctx("after smb_ctx_readrc", ctx); 21924bff34e3Sthurlow 21934bff34e3Sthurlow return (0); 21944bff34e3Sthurlow } 2195