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