1*4bff34e3Sthurlow /* 2*4bff34e3Sthurlow * Copyright (c) 2000, Boris Popov 3*4bff34e3Sthurlow * All rights reserved. 4*4bff34e3Sthurlow * 5*4bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 6*4bff34e3Sthurlow * modification, are permitted provided that the following conditions 7*4bff34e3Sthurlow * are met: 8*4bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 9*4bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 10*4bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 11*4bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 12*4bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 13*4bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 14*4bff34e3Sthurlow * must display the following acknowledgement: 15*4bff34e3Sthurlow * This product includes software developed by Boris Popov. 16*4bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 17*4bff34e3Sthurlow * may be used to endorse or promote products derived from this software 18*4bff34e3Sthurlow * without specific prior written permission. 19*4bff34e3Sthurlow * 20*4bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21*4bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22*4bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23*4bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24*4bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25*4bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26*4bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27*4bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28*4bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29*4bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30*4bff34e3Sthurlow * SUCH DAMAGE. 31*4bff34e3Sthurlow * 32*4bff34e3Sthurlow * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $ 33*4bff34e3Sthurlow */ 34*4bff34e3Sthurlow 35*4bff34e3Sthurlow #pragma ident "%Z%%M% %I% %E% SMI" 36*4bff34e3Sthurlow 37*4bff34e3Sthurlow #include <sys/param.h> 38*4bff34e3Sthurlow #include <sys/ioctl.h> 39*4bff34e3Sthurlow #include <sys/time.h> 40*4bff34e3Sthurlow #include <sys/mount.h> 41*4bff34e3Sthurlow #include <sys/types.h> 42*4bff34e3Sthurlow #include <sys/byteorder.h> 43*4bff34e3Sthurlow 44*4bff34e3Sthurlow #include <fcntl.h> 45*4bff34e3Sthurlow #include <ctype.h> 46*4bff34e3Sthurlow #include <errno.h> 47*4bff34e3Sthurlow #include <stdio.h> 48*4bff34e3Sthurlow #include <string.h> 49*4bff34e3Sthurlow #include <strings.h> 50*4bff34e3Sthurlow #include <stdlib.h> 51*4bff34e3Sthurlow #include <pwd.h> 52*4bff34e3Sthurlow #include <grp.h> 53*4bff34e3Sthurlow #include <unistd.h> 54*4bff34e3Sthurlow #include <libintl.h> 55*4bff34e3Sthurlow #include <assert.h> 56*4bff34e3Sthurlow #include <nss_dbdefs.h> 57*4bff34e3Sthurlow 58*4bff34e3Sthurlow #include <kerberosv5/krb5.h> 59*4bff34e3Sthurlow #include <kerberosv5/com_err.h> 60*4bff34e3Sthurlow 61*4bff34e3Sthurlow extern uid_t real_uid, eff_uid; 62*4bff34e3Sthurlow 63*4bff34e3Sthurlow #define NB_NEEDRESOLVER 64*4bff34e3Sthurlow 65*4bff34e3Sthurlow #include <netsmb/smb_lib.h> 66*4bff34e3Sthurlow #include <netsmb/netbios.h> 67*4bff34e3Sthurlow #include <netsmb/nb_lib.h> 68*4bff34e3Sthurlow #include <netsmb/smb_dev.h> 69*4bff34e3Sthurlow #include <cflib.h> 70*4bff34e3Sthurlow #include <charsets.h> 71*4bff34e3Sthurlow 72*4bff34e3Sthurlow #include <spnego.h> 73*4bff34e3Sthurlow #include "derparse.h" 74*4bff34e3Sthurlow 75*4bff34e3Sthurlow extern MECH_OID g_stcMechOIDList []; 76*4bff34e3Sthurlow 77*4bff34e3Sthurlow #define POWEROF2(x) (((x) & ((x)-1)) == 0) 78*4bff34e3Sthurlow 79*4bff34e3Sthurlow /* These two may be set by commands. */ 80*4bff34e3Sthurlow int smb_debug, smb_verbose; 81*4bff34e3Sthurlow 82*4bff34e3Sthurlow /* 83*4bff34e3Sthurlow * This used to call the DCE/RPC code. 84*4bff34e3Sthurlow * We want more strict layering than this. 85*4bff34e3Sthurlow * The redirector should simply export a 86*4bff34e3Sthurlow * remote pipe API, comsumed by dce rpc. 87*4bff34e3Sthurlow * Make it a no-op for now. 88*4bff34e3Sthurlow */ 89*4bff34e3Sthurlow #if 0 90*4bff34e3Sthurlow #include <rpc_cleanup.h> 91*4bff34e3Sthurlow #else 92*4bff34e3Sthurlow static void 93*4bff34e3Sthurlow rpc_cleanup_smbctx(struct smb_ctx *ctx) 94*4bff34e3Sthurlow { 95*4bff34e3Sthurlow } 96*4bff34e3Sthurlow #endif 97*4bff34e3Sthurlow 98*4bff34e3Sthurlow void 99*4bff34e3Sthurlow dump_ctx_flags(int flags) 100*4bff34e3Sthurlow { 101*4bff34e3Sthurlow printf(" Flags: "); 102*4bff34e3Sthurlow if (flags == 0) 103*4bff34e3Sthurlow printf("0"); 104*4bff34e3Sthurlow if (flags & SMBCF_NOPWD) 105*4bff34e3Sthurlow printf("NOPWD "); 106*4bff34e3Sthurlow if (flags & SMBCF_SRIGHTS) 107*4bff34e3Sthurlow printf("SRIGHTS "); 108*4bff34e3Sthurlow if (flags & SMBCF_LOCALE) 109*4bff34e3Sthurlow printf("LOCALE "); 110*4bff34e3Sthurlow if (flags & SMBCF_CMD_DOM) 111*4bff34e3Sthurlow printf("CMD_DOM "); 112*4bff34e3Sthurlow if (flags & SMBCF_CMD_USR) 113*4bff34e3Sthurlow printf("CMD_USR "); 114*4bff34e3Sthurlow if (flags & SMBCF_CMD_PW) 115*4bff34e3Sthurlow printf("CMD_PW "); 116*4bff34e3Sthurlow if (flags & SMBCF_RESOLVED) 117*4bff34e3Sthurlow printf("RESOLVED "); 118*4bff34e3Sthurlow if (flags & SMBCF_KCBAD) 119*4bff34e3Sthurlow printf("KCBAD "); 120*4bff34e3Sthurlow if (flags & SMBCF_KCFOUND) 121*4bff34e3Sthurlow printf("KCFOUND "); 122*4bff34e3Sthurlow if (flags & SMBCF_BROWSEOK) 123*4bff34e3Sthurlow printf("BROWSEOK "); 124*4bff34e3Sthurlow if (flags & SMBCF_AUTHREQ) 125*4bff34e3Sthurlow printf("AUTHREQ "); 126*4bff34e3Sthurlow if (flags & SMBCF_KCSAVE) 127*4bff34e3Sthurlow printf("KCSAVE "); 128*4bff34e3Sthurlow if (flags & SMBCF_XXX) 129*4bff34e3Sthurlow printf("XXX "); 130*4bff34e3Sthurlow if (flags & SMBCF_SSNACTIVE) 131*4bff34e3Sthurlow printf("SSNACTIVE "); 132*4bff34e3Sthurlow if (flags & SMBCF_KCDOMAIN) 133*4bff34e3Sthurlow printf("KCDOMAIN "); 134*4bff34e3Sthurlow printf("\n"); 135*4bff34e3Sthurlow } 136*4bff34e3Sthurlow 137*4bff34e3Sthurlow void 138*4bff34e3Sthurlow dump_ctx_ssn(struct smbioc_ossn *ssn) 139*4bff34e3Sthurlow { 140*4bff34e3Sthurlow printf(" srvname=\"%s\", dom=\"%s\", user=\"%s\", password=%s\n", 141*4bff34e3Sthurlow ssn->ioc_srvname, ssn->ioc_workgroup, ssn->ioc_user, 142*4bff34e3Sthurlow ssn->ioc_password[0] ? "(non-null)" : "NULL"); 143*4bff34e3Sthurlow printf(" timeout=%d, retry=%d, owner=%d, group=%d\n", 144*4bff34e3Sthurlow ssn->ioc_timeout, ssn->ioc_retrycount, 145*4bff34e3Sthurlow ssn->ioc_owner, ssn->ioc_group); 146*4bff34e3Sthurlow } 147*4bff34e3Sthurlow 148*4bff34e3Sthurlow void 149*4bff34e3Sthurlow dump_ctx_sh(struct smbioc_oshare *sh) 150*4bff34e3Sthurlow { 151*4bff34e3Sthurlow printf(" share_name=\"%s\", share_pw=\"%s\"\n", 152*4bff34e3Sthurlow sh->ioc_share, sh->ioc_password); 153*4bff34e3Sthurlow } 154*4bff34e3Sthurlow 155*4bff34e3Sthurlow void 156*4bff34e3Sthurlow dump_ctx(char *where, struct smb_ctx *ctx) 157*4bff34e3Sthurlow { 158*4bff34e3Sthurlow printf("context %s:\n", where); 159*4bff34e3Sthurlow dump_ctx_flags(ctx->ct_flags); 160*4bff34e3Sthurlow 161*4bff34e3Sthurlow printf(" localname=\"%s\"", ctx->ct_locname); 162*4bff34e3Sthurlow 163*4bff34e3Sthurlow if (ctx->ct_fullserver) 164*4bff34e3Sthurlow printf(" fullserver=\"%s\"", ctx->ct_fullserver); 165*4bff34e3Sthurlow else 166*4bff34e3Sthurlow printf(" fullserver=NULL"); 167*4bff34e3Sthurlow 168*4bff34e3Sthurlow if (ctx->ct_srvaddr) 169*4bff34e3Sthurlow printf(" srvaddr=\"%s\"\n", ctx->ct_srvaddr); 170*4bff34e3Sthurlow else 171*4bff34e3Sthurlow printf(" srvaddr=NULL\n"); 172*4bff34e3Sthurlow 173*4bff34e3Sthurlow dump_ctx_ssn(&ctx->ct_ssn); 174*4bff34e3Sthurlow dump_ctx_sh(&ctx->ct_sh); 175*4bff34e3Sthurlow } 176*4bff34e3Sthurlow 177*4bff34e3Sthurlow /* 178*4bff34e3Sthurlow * Initialize an smb_ctx struct. 179*4bff34e3Sthurlow * 180*4bff34e3Sthurlow * The sequence for getting all the members filled in 181*4bff34e3Sthurlow * has some tricky aspects. Here's how it works: 182*4bff34e3Sthurlow * 183*4bff34e3Sthurlow * The search order for options is as follows: 184*4bff34e3Sthurlow * command line options 185*4bff34e3Sthurlow * values parsed from UNC path (cmd) 186*4bff34e3Sthurlow * values from RC file (per-user) 187*4bff34e3Sthurlow * values from SMF (system-wide) 188*4bff34e3Sthurlow * built-in defaults 189*4bff34e3Sthurlow * 190*4bff34e3Sthurlow * Normally, one would simply get all the values starting with 191*4bff34e3Sthurlow * the bottom of the above list and working to the top, and 192*4bff34e3Sthurlow * overwriting values as you go. But we need an exception. 193*4bff34e3Sthurlow * 194*4bff34e3Sthurlow * In this function, we parse the UNC path and command line options, 195*4bff34e3Sthurlow * because we need (at least) the server name when we're getting the 196*4bff34e3Sthurlow * SMF and RC file values. However, values we get from the command 197*4bff34e3Sthurlow * should not be overwritten by SMF or RC file parsing, so we mark 198*4bff34e3Sthurlow * values from the command as "from CMD" and the RC file parser 199*4bff34e3Sthurlow * leaves in place any values so marked. See: SMBCF_CMD_* 200*4bff34e3Sthurlow * 201*4bff34e3Sthurlow * The semantics of these flags are: "This value came from the 202*4bff34e3Sthurlow * current command instance, not from sources that may apply to 203*4bff34e3Sthurlow * multiple commands." (Different from the old "FROMUSR" flag.) 204*4bff34e3Sthurlow * 205*4bff34e3Sthurlow * Note that smb_ctx_opt() is called later to handle the 206*4bff34e3Sthurlow * remaining options, which should be ignored here. 207*4bff34e3Sthurlow * The (magic) leading ":" in cf_getopt() makes it 208*4bff34e3Sthurlow * ignore options not in the options string. 209*4bff34e3Sthurlow */ 210*4bff34e3Sthurlow int 211*4bff34e3Sthurlow smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[], 212*4bff34e3Sthurlow int minlevel, int maxlevel, int sharetype) 213*4bff34e3Sthurlow { 214*4bff34e3Sthurlow int opt, error = 0; 215*4bff34e3Sthurlow const char *arg, *cp; 216*4bff34e3Sthurlow struct passwd pw; 217*4bff34e3Sthurlow char pwbuf[NSS_BUFLEN_PASSWD]; 218*4bff34e3Sthurlow int aflg = 0, uflg = 0; 219*4bff34e3Sthurlow 220*4bff34e3Sthurlow bzero(ctx, sizeof (*ctx)); 221*4bff34e3Sthurlow if (sharetype == SMB_ST_DISK) 222*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_BROWSEOK; 223*4bff34e3Sthurlow error = nb_ctx_create(&ctx->ct_nb); 224*4bff34e3Sthurlow if (error) 225*4bff34e3Sthurlow return (error); 226*4bff34e3Sthurlow 227*4bff34e3Sthurlow ctx->ct_fd = -1; 228*4bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_NONE; 229*4bff34e3Sthurlow ctx->ct_minlevel = minlevel; 230*4bff34e3Sthurlow ctx->ct_maxlevel = maxlevel; 231*4bff34e3Sthurlow 232*4bff34e3Sthurlow ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE | SMBVOPT_MINAUTH_NTLM; 233*4bff34e3Sthurlow ctx->ct_ssn.ioc_timeout = 15; 234*4bff34e3Sthurlow ctx->ct_ssn.ioc_retrycount = 4; 235*4bff34e3Sthurlow ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER; 236*4bff34e3Sthurlow ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP; 237*4bff34e3Sthurlow ctx->ct_ssn.ioc_mode = SMBM_EXEC; 238*4bff34e3Sthurlow ctx->ct_ssn.ioc_rights = SMBM_DEFAULT; 239*4bff34e3Sthurlow 240*4bff34e3Sthurlow ctx->ct_sh.ioc_opt = SMBVOPT_CREATE; 241*4bff34e3Sthurlow ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 242*4bff34e3Sthurlow ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 243*4bff34e3Sthurlow ctx->ct_sh.ioc_mode = SMBM_EXEC; 244*4bff34e3Sthurlow ctx->ct_sh.ioc_rights = SMBM_DEFAULT; 245*4bff34e3Sthurlow ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; 246*4bff34e3Sthurlow ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; 247*4bff34e3Sthurlow 248*4bff34e3Sthurlow nb_ctx_setscope(ctx->ct_nb, ""); 249*4bff34e3Sthurlow 250*4bff34e3Sthurlow /* 251*4bff34e3Sthurlow * if the user name is not specified some other way, 252*4bff34e3Sthurlow * use the current user name (built-in default) 253*4bff34e3Sthurlow */ 254*4bff34e3Sthurlow if (getpwuid_r(geteuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) 255*4bff34e3Sthurlow smb_ctx_setuser(ctx, pw.pw_name, 0); 256*4bff34e3Sthurlow 257*4bff34e3Sthurlow /* 258*4bff34e3Sthurlow * Set a built-in default domain (workgroup). 259*4bff34e3Sthurlow * XXX: What's the best default? Use "?" instead? 260*4bff34e3Sthurlow * Using the Windows/NT default for now. 261*4bff34e3Sthurlow */ 262*4bff34e3Sthurlow smb_ctx_setworkgroup(ctx, "WORKGROUP", 0); 263*4bff34e3Sthurlow 264*4bff34e3Sthurlow /* 265*4bff34e3Sthurlow * Parse the UNC path. Values from here are 266*4bff34e3Sthurlow * marked as "from CMD". 267*4bff34e3Sthurlow */ 268*4bff34e3Sthurlow if (argv == NULL) 269*4bff34e3Sthurlow goto done; 270*4bff34e3Sthurlow for (opt = 1; opt < argc; opt++) { 271*4bff34e3Sthurlow cp = argv[opt]; 272*4bff34e3Sthurlow if (strncmp(cp, "//", 2) != 0) 273*4bff34e3Sthurlow continue; 274*4bff34e3Sthurlow error = smb_ctx_parseunc(ctx, cp, sharetype, &cp); 275*4bff34e3Sthurlow if (error) 276*4bff34e3Sthurlow return (error); 277*4bff34e3Sthurlow break; 278*4bff34e3Sthurlow } 279*4bff34e3Sthurlow 280*4bff34e3Sthurlow /* 281*4bff34e3Sthurlow * Parse options, if any. Values from here too 282*4bff34e3Sthurlow * are marked as "from CMD". 283*4bff34e3Sthurlow */ 284*4bff34e3Sthurlow while (error == 0 && (opt = cf_getopt(argc, argv, ":AU:E:L:")) != -1) { 285*4bff34e3Sthurlow arg = cf_optarg; 286*4bff34e3Sthurlow switch (opt) { 287*4bff34e3Sthurlow case 'A': 288*4bff34e3Sthurlow aflg = 1; 289*4bff34e3Sthurlow error = smb_ctx_setuser(ctx, "", TRUE); 290*4bff34e3Sthurlow error = smb_ctx_setpassword(ctx, "", TRUE); 291*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_NOPWD; 292*4bff34e3Sthurlow break; 293*4bff34e3Sthurlow case 'E': 294*4bff34e3Sthurlow #if 0 /* We don't support any "charset" stuff. (ignore -E) */ 295*4bff34e3Sthurlow error = smb_ctx_setcharset(ctx, arg); 296*4bff34e3Sthurlow if (error) 297*4bff34e3Sthurlow return (error); 298*4bff34e3Sthurlow #endif 299*4bff34e3Sthurlow break; 300*4bff34e3Sthurlow case 'L': 301*4bff34e3Sthurlow #if 0 /* Use the standard environment variables (ignore -L) */ 302*4bff34e3Sthurlow error = nls_setlocale(optarg); 303*4bff34e3Sthurlow if (error) 304*4bff34e3Sthurlow break; 305*4bff34e3Sthurlow #endif 306*4bff34e3Sthurlow break; 307*4bff34e3Sthurlow case 'U': 308*4bff34e3Sthurlow uflg = 1; 309*4bff34e3Sthurlow error = smb_ctx_setuser(ctx, arg, TRUE); 310*4bff34e3Sthurlow break; 311*4bff34e3Sthurlow } 312*4bff34e3Sthurlow } 313*4bff34e3Sthurlow if (aflg && uflg) { 314*4bff34e3Sthurlow printf(gettext("-A and -U flags are exclusive.\n")); 315*4bff34e3Sthurlow return (1); 316*4bff34e3Sthurlow } 317*4bff34e3Sthurlow cf_optind = cf_optreset = 1; 318*4bff34e3Sthurlow 319*4bff34e3Sthurlow done: 320*4bff34e3Sthurlow if (smb_debug) 321*4bff34e3Sthurlow dump_ctx("after smb_ctx_init", ctx); 322*4bff34e3Sthurlow 323*4bff34e3Sthurlow return (error); 324*4bff34e3Sthurlow } 325*4bff34e3Sthurlow 326*4bff34e3Sthurlow void 327*4bff34e3Sthurlow smb_ctx_done(struct smb_ctx *ctx) 328*4bff34e3Sthurlow { 329*4bff34e3Sthurlow 330*4bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 331*4bff34e3Sthurlow 332*4bff34e3Sthurlow /* Kerberos stuff. See smb_ctx_krb5init() */ 333*4bff34e3Sthurlow if (ctx->ct_krb5ctx) { 334*4bff34e3Sthurlow if (ctx->ct_krb5cp) 335*4bff34e3Sthurlow krb5_free_principal(ctx->ct_krb5ctx, ctx->ct_krb5cp); 336*4bff34e3Sthurlow krb5_free_context(ctx->ct_krb5ctx); 337*4bff34e3Sthurlow } 338*4bff34e3Sthurlow 339*4bff34e3Sthurlow if (ctx->ct_fd != -1) 340*4bff34e3Sthurlow close(ctx->ct_fd); 341*4bff34e3Sthurlow #if 0 /* XXX: not pointers anymore */ 342*4bff34e3Sthurlow if (&ctx->ct_ssn.ioc_server) 343*4bff34e3Sthurlow nb_snbfree(&ctx->ct_ssn.ioc_server); 344*4bff34e3Sthurlow if (&ctx->ct_ssn.ioc_local) 345*4bff34e3Sthurlow nb_snbfree(&ctx->ct_ssn.ioc_local); 346*4bff34e3Sthurlow #endif 347*4bff34e3Sthurlow if (ctx->ct_srvaddr) 348*4bff34e3Sthurlow free(ctx->ct_srvaddr); 349*4bff34e3Sthurlow if (ctx->ct_nb) 350*4bff34e3Sthurlow nb_ctx_done(ctx->ct_nb); 351*4bff34e3Sthurlow if (ctx->ct_secblob) 352*4bff34e3Sthurlow free(ctx->ct_secblob); 353*4bff34e3Sthurlow if (ctx->ct_origshare) 354*4bff34e3Sthurlow free(ctx->ct_origshare); 355*4bff34e3Sthurlow if (ctx->ct_fullserver) 356*4bff34e3Sthurlow free(ctx->ct_fullserver); 357*4bff34e3Sthurlow } 358*4bff34e3Sthurlow 359*4bff34e3Sthurlow static int 360*4bff34e3Sthurlow getsubstring(const char *p, uchar_t sep, char *dest, int maxlen, 361*4bff34e3Sthurlow const char **next) 362*4bff34e3Sthurlow { 363*4bff34e3Sthurlow int len; 364*4bff34e3Sthurlow 365*4bff34e3Sthurlow maxlen--; 366*4bff34e3Sthurlow for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { 367*4bff34e3Sthurlow if (*p == 0) 368*4bff34e3Sthurlow return (EINVAL); 369*4bff34e3Sthurlow *dest = *p; 370*4bff34e3Sthurlow } 371*4bff34e3Sthurlow *dest = 0; 372*4bff34e3Sthurlow *next = *p ? p + 1 : p; 373*4bff34e3Sthurlow return (0); 374*4bff34e3Sthurlow } 375*4bff34e3Sthurlow 376*4bff34e3Sthurlow /* 377*4bff34e3Sthurlow * Parse the UNC path. Here we expect something like 378*4bff34e3Sthurlow * "//[workgroup;][user[:password]@]host[/share[/path]]" 379*4bff34e3Sthurlow * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 380*4bff34e3Sthurlow * Values found here are marked as "from CMD". 381*4bff34e3Sthurlow */ 382*4bff34e3Sthurlow int 383*4bff34e3Sthurlow smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, 384*4bff34e3Sthurlow const char **next) 385*4bff34e3Sthurlow { 386*4bff34e3Sthurlow const char *p = unc; 387*4bff34e3Sthurlow char *p1, *colon, *servername; 388*4bff34e3Sthurlow char tmp[1024]; 389*4bff34e3Sthurlow char tmp2[1024]; 390*4bff34e3Sthurlow int error; 391*4bff34e3Sthurlow 392*4bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_NONE; 393*4bff34e3Sthurlow if (*p++ != '/' || *p++ != '/') { 394*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 395*4bff34e3Sthurlow "UNC should start with '//'"), 0); 396*4bff34e3Sthurlow return (EINVAL); 397*4bff34e3Sthurlow } 398*4bff34e3Sthurlow p1 = tmp; 399*4bff34e3Sthurlow error = getsubstring(p, ';', p1, sizeof (tmp), &p); 400*4bff34e3Sthurlow if (!error) { 401*4bff34e3Sthurlow if (*p1 == 0) { 402*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 403*4bff34e3Sthurlow "empty workgroup name"), 0); 404*4bff34e3Sthurlow return (EINVAL); 405*4bff34e3Sthurlow } 406*4bff34e3Sthurlow nls_str_upper(tmp, tmp); 407*4bff34e3Sthurlow error = smb_ctx_setworkgroup(ctx, unpercent(tmp), TRUE); 408*4bff34e3Sthurlow if (error) 409*4bff34e3Sthurlow return (error); 410*4bff34e3Sthurlow } 411*4bff34e3Sthurlow colon = (char *)p; 412*4bff34e3Sthurlow error = getsubstring(p, '@', p1, sizeof (tmp), &p); 413*4bff34e3Sthurlow if (!error) { 414*4bff34e3Sthurlow if (ctx->ct_maxlevel < SMBL_VC) { 415*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 416*4bff34e3Sthurlow "no user name required"), 0); 417*4bff34e3Sthurlow return (EINVAL); 418*4bff34e3Sthurlow } 419*4bff34e3Sthurlow p1 = strchr(tmp, ':'); 420*4bff34e3Sthurlow if (p1) { 421*4bff34e3Sthurlow colon += p1 - tmp; 422*4bff34e3Sthurlow *p1++ = (char)0; 423*4bff34e3Sthurlow error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE); 424*4bff34e3Sthurlow if (error) 425*4bff34e3Sthurlow return (error); 426*4bff34e3Sthurlow if (p - colon > 2) 427*4bff34e3Sthurlow memset(colon+1, '*', p - colon - 2); 428*4bff34e3Sthurlow } 429*4bff34e3Sthurlow p1 = tmp; 430*4bff34e3Sthurlow if (*p1 == 0) { 431*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 432*4bff34e3Sthurlow "empty user name"), 0); 433*4bff34e3Sthurlow return (EINVAL); 434*4bff34e3Sthurlow } 435*4bff34e3Sthurlow error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE); 436*4bff34e3Sthurlow if (error) 437*4bff34e3Sthurlow return (error); 438*4bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_VC; 439*4bff34e3Sthurlow } 440*4bff34e3Sthurlow error = getsubstring(p, '/', p1, sizeof (tmp), &p); 441*4bff34e3Sthurlow if (error) { 442*4bff34e3Sthurlow error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 443*4bff34e3Sthurlow if (error) { 444*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 445*4bff34e3Sthurlow "no server name found"), 0); 446*4bff34e3Sthurlow return (error); 447*4bff34e3Sthurlow } 448*4bff34e3Sthurlow } 449*4bff34e3Sthurlow if (*p1 == 0) { 450*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0); 451*4bff34e3Sthurlow return (EINVAL); 452*4bff34e3Sthurlow } 453*4bff34e3Sthurlow 454*4bff34e3Sthurlow 455*4bff34e3Sthurlow /* 456*4bff34e3Sthurlow * It's safe to uppercase this string, which 457*4bff34e3Sthurlow * consists of ascii characters that should 458*4bff34e3Sthurlow * be uppercased, %s, and ascii characters representing 459*4bff34e3Sthurlow * hex digits 0-9 and A-F (already uppercased, and 460*4bff34e3Sthurlow * if not uppercased they need to be). However, 461*4bff34e3Sthurlow * it is NOT safe to uppercase after it has been 462*4bff34e3Sthurlow * converted, below! 463*4bff34e3Sthurlow */ 464*4bff34e3Sthurlow 465*4bff34e3Sthurlow nls_str_upper(tmp2, tmp); 466*4bff34e3Sthurlow 467*4bff34e3Sthurlow /* 468*4bff34e3Sthurlow * scan for % in the string. 469*4bff34e3Sthurlow * If we find one, convert 470*4bff34e3Sthurlow * to the assumed codepage. 471*4bff34e3Sthurlow */ 472*4bff34e3Sthurlow 473*4bff34e3Sthurlow if (strchr(tmp2, '%')) { 474*4bff34e3Sthurlow /* use the 1st buffer, we don't need the old string */ 475*4bff34e3Sthurlow servername = tmp; 476*4bff34e3Sthurlow if (!(servername = convert_utf8_to_wincs(unpercent(tmp2)))) { 477*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "bad server name"), 0); 478*4bff34e3Sthurlow return (EINVAL); 479*4bff34e3Sthurlow } 480*4bff34e3Sthurlow /* 481*4bff34e3Sthurlow * Converts utf8 to win equivalent of 482*4bff34e3Sthurlow * what is configured on this machine. 483*4bff34e3Sthurlow * Note that we are assuming this is the 484*4bff34e3Sthurlow * encoding used on the server, and that 485*4bff34e3Sthurlow * assumption might be incorrect. This is 486*4bff34e3Sthurlow * the best we can do now, and we should 487*4bff34e3Sthurlow * move to use port 445 to avoid having 488*4bff34e3Sthurlow * to worry about server codepages. 489*4bff34e3Sthurlow */ 490*4bff34e3Sthurlow } else /* no conversion needed */ 491*4bff34e3Sthurlow servername = tmp2; 492*4bff34e3Sthurlow 493*4bff34e3Sthurlow smb_ctx_setserver(ctx, servername); 494*4bff34e3Sthurlow error = smb_ctx_setfullserver(ctx, servername); 495*4bff34e3Sthurlow 496*4bff34e3Sthurlow if (error) 497*4bff34e3Sthurlow return (error); 498*4bff34e3Sthurlow if (sharetype == SMB_ST_NONE) { 499*4bff34e3Sthurlow *next = p; 500*4bff34e3Sthurlow return (0); 501*4bff34e3Sthurlow } 502*4bff34e3Sthurlow if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { 503*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0); 504*4bff34e3Sthurlow return (EINVAL); 505*4bff34e3Sthurlow } 506*4bff34e3Sthurlow error = getsubstring(p, '/', p1, sizeof (tmp), &p); 507*4bff34e3Sthurlow if (error) { 508*4bff34e3Sthurlow error = getsubstring(p, '\0', p1, sizeof (tmp), &p); 509*4bff34e3Sthurlow if (error) { 510*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 511*4bff34e3Sthurlow "unexpected end of line"), 0); 512*4bff34e3Sthurlow return (error); 513*4bff34e3Sthurlow } 514*4bff34e3Sthurlow } 515*4bff34e3Sthurlow if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE && 516*4bff34e3Sthurlow !(ctx->ct_flags & SMBCF_BROWSEOK)) { 517*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0); 518*4bff34e3Sthurlow return (EINVAL); 519*4bff34e3Sthurlow } 520*4bff34e3Sthurlow *next = p; 521*4bff34e3Sthurlow if (*p1 == 0) 522*4bff34e3Sthurlow return (0); 523*4bff34e3Sthurlow error = smb_ctx_setshare(ctx, unpercent(p1), sharetype); 524*4bff34e3Sthurlow return (error); 525*4bff34e3Sthurlow } 526*4bff34e3Sthurlow 527*4bff34e3Sthurlow int 528*4bff34e3Sthurlow smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) 529*4bff34e3Sthurlow { 530*4bff34e3Sthurlow char *cp, *servercs, *localcs; 531*4bff34e3Sthurlow int cslen = sizeof (ctx->ct_ssn.ioc_localcs); 532*4bff34e3Sthurlow int scslen, lcslen, error; 533*4bff34e3Sthurlow 534*4bff34e3Sthurlow cp = strchr(arg, ':'); 535*4bff34e3Sthurlow lcslen = cp ? (cp - arg) : 0; 536*4bff34e3Sthurlow if (lcslen == 0 || lcslen >= cslen) { 537*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 538*4bff34e3Sthurlow "invalid local charset specification (%s)"), 0, arg); 539*4bff34e3Sthurlow return (EINVAL); 540*4bff34e3Sthurlow } 541*4bff34e3Sthurlow scslen = (size_t)strlen(++cp); 542*4bff34e3Sthurlow if (scslen == 0 || scslen >= cslen) { 543*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 544*4bff34e3Sthurlow "invalid server charset specification (%s)"), 0, arg); 545*4bff34e3Sthurlow return (EINVAL); 546*4bff34e3Sthurlow } 547*4bff34e3Sthurlow localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); 548*4bff34e3Sthurlow localcs[lcslen] = 0; 549*4bff34e3Sthurlow servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); 550*4bff34e3Sthurlow error = nls_setrecode(localcs, servercs); 551*4bff34e3Sthurlow if (error == 0) 552*4bff34e3Sthurlow return (0); 553*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 554*4bff34e3Sthurlow "can't initialize iconv support (%s:%s)"), 555*4bff34e3Sthurlow error, localcs, servercs); 556*4bff34e3Sthurlow localcs[0] = 0; 557*4bff34e3Sthurlow servercs[0] = 0; 558*4bff34e3Sthurlow return (error); 559*4bff34e3Sthurlow } 560*4bff34e3Sthurlow 561*4bff34e3Sthurlow int 562*4bff34e3Sthurlow smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name) 563*4bff34e3Sthurlow { 564*4bff34e3Sthurlow ctx->ct_fullserver = strdup(name); 565*4bff34e3Sthurlow if (ctx->ct_fullserver == NULL) 566*4bff34e3Sthurlow return (ENOMEM); 567*4bff34e3Sthurlow return (0); 568*4bff34e3Sthurlow } 569*4bff34e3Sthurlow 570*4bff34e3Sthurlow /* 571*4bff34e3Sthurlow * XXX TODO FIXME etc etc 572*4bff34e3Sthurlow * If the call to nbns_getnodestatus(...) fails we can try one of two other 573*4bff34e3Sthurlow * methods; use a name of "*SMBSERVER", which is supported by Samba (at least) 574*4bff34e3Sthurlow * or, as a last resort, try the "truncate-at-dot" heuristic. 575*4bff34e3Sthurlow * And the heuristic really should attempt truncation at 576*4bff34e3Sthurlow * each dot in turn, left to right. 577*4bff34e3Sthurlow * 578*4bff34e3Sthurlow * These fallback heuristics should be triggered when the attempt to open the 579*4bff34e3Sthurlow * session fails instead of in the code below. 580*4bff34e3Sthurlow * 581*4bff34e3Sthurlow * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt 582*4bff34e3Sthurlow */ 583*4bff34e3Sthurlow int 584*4bff34e3Sthurlow smb_ctx_getnbname(struct smb_ctx *ctx, struct sockaddr *sap) 585*4bff34e3Sthurlow { 586*4bff34e3Sthurlow char server[SMB_MAXSRVNAMELEN + 1]; 587*4bff34e3Sthurlow char workgroup[SMB_MAXUSERNAMELEN + 1]; 588*4bff34e3Sthurlow int error; 589*4bff34e3Sthurlow #if 0 590*4bff34e3Sthurlow char *dot; 591*4bff34e3Sthurlow #endif 592*4bff34e3Sthurlow 593*4bff34e3Sthurlow server[0] = workgroup[0] = '\0'; 594*4bff34e3Sthurlow error = nbns_getnodestatus(sap, ctx->ct_nb, server, workgroup); 595*4bff34e3Sthurlow if (error == 0) { 596*4bff34e3Sthurlow /* 597*4bff34e3Sthurlow * Used to set our domain name to be the same as 598*4bff34e3Sthurlow * the server's domain name. Unnecessary at best, 599*4bff34e3Sthurlow * and wrong for accounts in a trusted domain. 600*4bff34e3Sthurlow */ 601*4bff34e3Sthurlow #ifdef APPLE 602*4bff34e3Sthurlow if (workgroup[0] && !ctx->ct_ssn.ioc_workgroup[0]) 603*4bff34e3Sthurlow smb_ctx_setworkgroup(ctx, workgroup, 0); 604*4bff34e3Sthurlow #endif 605*4bff34e3Sthurlow if (server[0]) 606*4bff34e3Sthurlow smb_ctx_setserver(ctx, server); 607*4bff34e3Sthurlow } else { 608*4bff34e3Sthurlow if (smb_verbose) 609*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 610*4bff34e3Sthurlow "Failed to get NetBIOS node status."), 0); 611*4bff34e3Sthurlow if (ctx->ct_ssn.ioc_srvname[0] == (char)0) 612*4bff34e3Sthurlow smb_ctx_setserver(ctx, "*SMBSERVER"); 613*4bff34e3Sthurlow } 614*4bff34e3Sthurlow #if 0 615*4bff34e3Sthurlow if (server[0] == (char)0) { 616*4bff34e3Sthurlow dot = strchr(ctx->ct_fullserver, '.'); 617*4bff34e3Sthurlow if (dot) 618*4bff34e3Sthurlow *dot = '\0'; 619*4bff34e3Sthurlow if (strlen(ctx->ct_fullserver) <= SMB_MAXSRVNAMELEN) { 620*4bff34e3Sthurlow /* 621*4bff34e3Sthurlow * don't uppercase the server name. it comes from 622*4bff34e3Sthurlow * NBNS and uppercasing can clobber the characters 623*4bff34e3Sthurlow */ 624*4bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_srvname, ctx->ct_fullserver); 625*4bff34e3Sthurlow error = 0; 626*4bff34e3Sthurlow } else { 627*4bff34e3Sthurlow error = -1; 628*4bff34e3Sthurlow } 629*4bff34e3Sthurlow if (dot) 630*4bff34e3Sthurlow *dot = '.'; 631*4bff34e3Sthurlow } 632*4bff34e3Sthurlow #endif 633*4bff34e3Sthurlow return (error); 634*4bff34e3Sthurlow } 635*4bff34e3Sthurlow 636*4bff34e3Sthurlow /* this routine does not uppercase the server name */ 637*4bff34e3Sthurlow void 638*4bff34e3Sthurlow smb_ctx_setserver(struct smb_ctx *ctx, const char *name) 639*4bff34e3Sthurlow { 640*4bff34e3Sthurlow /* don't uppercase the server name */ 641*4bff34e3Sthurlow if (strlen(name) > SMB_MAXSRVNAMELEN) { /* NB limit is 15 */ 642*4bff34e3Sthurlow ctx->ct_ssn.ioc_srvname[0] = '\0'; 643*4bff34e3Sthurlow } else 644*4bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_srvname, name); 645*4bff34e3Sthurlow } 646*4bff34e3Sthurlow 647*4bff34e3Sthurlow int 648*4bff34e3Sthurlow smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) 649*4bff34e3Sthurlow { 650*4bff34e3Sthurlow 651*4bff34e3Sthurlow if (strlen(name) >= SMB_MAXUSERNAMELEN) { 652*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 653*4bff34e3Sthurlow "user name '%s' too long"), 0, name); 654*4bff34e3Sthurlow return (ENAMETOOLONG); 655*4bff34e3Sthurlow } 656*4bff34e3Sthurlow 657*4bff34e3Sthurlow /* 658*4bff34e3Sthurlow * Don't overwrite a value from the command line 659*4bff34e3Sthurlow * with one from anywhere else. 660*4bff34e3Sthurlow */ 661*4bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR)) 662*4bff34e3Sthurlow return (0); 663*4bff34e3Sthurlow 664*4bff34e3Sthurlow /* don't uppercase the username, just copy it. */ 665*4bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_user, name); 666*4bff34e3Sthurlow 667*4bff34e3Sthurlow /* Mark this as "from the command line". */ 668*4bff34e3Sthurlow if (from_cmd) 669*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_USR; 670*4bff34e3Sthurlow 671*4bff34e3Sthurlow return (0); 672*4bff34e3Sthurlow } 673*4bff34e3Sthurlow 674*4bff34e3Sthurlow /* 675*4bff34e3Sthurlow * Never uppercase the workgroup 676*4bff34e3Sthurlow * name here, because it might come 677*4bff34e3Sthurlow * from a Windows codepage encoding. 678*4bff34e3Sthurlow * 679*4bff34e3Sthurlow * Don't overwrite a domain name from the 680*4bff34e3Sthurlow * command line with one from anywhere else. 681*4bff34e3Sthurlow * See smb_ctx_init() for notes about this. 682*4bff34e3Sthurlow */ 683*4bff34e3Sthurlow int 684*4bff34e3Sthurlow smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd) 685*4bff34e3Sthurlow { 686*4bff34e3Sthurlow 687*4bff34e3Sthurlow if (strlen(name) >= SMB_MAXUSERNAMELEN) { 688*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 689*4bff34e3Sthurlow "workgroup name '%s' too long"), 0, name); 690*4bff34e3Sthurlow return (ENAMETOOLONG); 691*4bff34e3Sthurlow } 692*4bff34e3Sthurlow 693*4bff34e3Sthurlow /* 694*4bff34e3Sthurlow * Don't overwrite a value from the command line 695*4bff34e3Sthurlow * with one from anywhere else. 696*4bff34e3Sthurlow */ 697*4bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM)) 698*4bff34e3Sthurlow return (0); 699*4bff34e3Sthurlow 700*4bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_workgroup, name); 701*4bff34e3Sthurlow 702*4bff34e3Sthurlow /* Mark this as "from the command line". */ 703*4bff34e3Sthurlow if (from_cmd) 704*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_DOM; 705*4bff34e3Sthurlow 706*4bff34e3Sthurlow return (0); 707*4bff34e3Sthurlow } 708*4bff34e3Sthurlow 709*4bff34e3Sthurlow int 710*4bff34e3Sthurlow smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd) 711*4bff34e3Sthurlow { 712*4bff34e3Sthurlow 713*4bff34e3Sthurlow if (passwd == NULL) /* XXX Huh? */ 714*4bff34e3Sthurlow return (EINVAL); 715*4bff34e3Sthurlow if (strlen(passwd) >= SMB_MAXPASSWORDLEN) { 716*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0); 717*4bff34e3Sthurlow return (ENAMETOOLONG); 718*4bff34e3Sthurlow } 719*4bff34e3Sthurlow 720*4bff34e3Sthurlow /* 721*4bff34e3Sthurlow * Don't overwrite a value from the command line 722*4bff34e3Sthurlow * with one from anywhere else. 723*4bff34e3Sthurlow */ 724*4bff34e3Sthurlow if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW)) 725*4bff34e3Sthurlow return (0); 726*4bff34e3Sthurlow 727*4bff34e3Sthurlow if (strncmp(passwd, "$$1", 3) == 0) 728*4bff34e3Sthurlow smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); 729*4bff34e3Sthurlow else 730*4bff34e3Sthurlow strcpy(ctx->ct_ssn.ioc_password, passwd); 731*4bff34e3Sthurlow strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); 732*4bff34e3Sthurlow 733*4bff34e3Sthurlow /* Mark this as "from the command line". */ 734*4bff34e3Sthurlow if (from_cmd) 735*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_CMD_PW; 736*4bff34e3Sthurlow 737*4bff34e3Sthurlow return (0); 738*4bff34e3Sthurlow } 739*4bff34e3Sthurlow 740*4bff34e3Sthurlow int 741*4bff34e3Sthurlow smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) 742*4bff34e3Sthurlow { 743*4bff34e3Sthurlow if (strlen(share) >= SMB_MAXSHARENAMELEN) { 744*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 745*4bff34e3Sthurlow "share name '%s' too long"), 0, share); 746*4bff34e3Sthurlow return (ENAMETOOLONG); 747*4bff34e3Sthurlow } 748*4bff34e3Sthurlow if (ctx->ct_origshare) 749*4bff34e3Sthurlow free(ctx->ct_origshare); 750*4bff34e3Sthurlow if ((ctx->ct_origshare = strdup(share)) == NULL) 751*4bff34e3Sthurlow return (ENOMEM); 752*4bff34e3Sthurlow nls_str_upper(ctx->ct_sh.ioc_share, share); 753*4bff34e3Sthurlow if (share[0] != 0) 754*4bff34e3Sthurlow ctx->ct_parsedlevel = SMBL_SHARE; 755*4bff34e3Sthurlow ctx->ct_sh.ioc_stype = stype; 756*4bff34e3Sthurlow return (0); 757*4bff34e3Sthurlow } 758*4bff34e3Sthurlow 759*4bff34e3Sthurlow int 760*4bff34e3Sthurlow smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) 761*4bff34e3Sthurlow { 762*4bff34e3Sthurlow if (addr == NULL || addr[0] == 0) 763*4bff34e3Sthurlow return (EINVAL); 764*4bff34e3Sthurlow if (ctx->ct_srvaddr) 765*4bff34e3Sthurlow free(ctx->ct_srvaddr); 766*4bff34e3Sthurlow if ((ctx->ct_srvaddr = strdup(addr)) == NULL) 767*4bff34e3Sthurlow return (ENOMEM); 768*4bff34e3Sthurlow return (0); 769*4bff34e3Sthurlow } 770*4bff34e3Sthurlow 771*4bff34e3Sthurlow static int 772*4bff34e3Sthurlow smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) 773*4bff34e3Sthurlow { 774*4bff34e3Sthurlow struct group gr; 775*4bff34e3Sthurlow struct passwd pw; 776*4bff34e3Sthurlow char buf[NSS_BUFLEN_PASSWD]; 777*4bff34e3Sthurlow char *cp; 778*4bff34e3Sthurlow 779*4bff34e3Sthurlow cp = strchr(pair, ':'); 780*4bff34e3Sthurlow if (cp) { 781*4bff34e3Sthurlow *cp++ = '\0'; 782*4bff34e3Sthurlow if (*cp) { 783*4bff34e3Sthurlow if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) { 784*4bff34e3Sthurlow *gid = gr.gr_gid; 785*4bff34e3Sthurlow } else 786*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 787*4bff34e3Sthurlow "Invalid group name %s, ignored"), 0, cp); 788*4bff34e3Sthurlow } 789*4bff34e3Sthurlow } 790*4bff34e3Sthurlow if (*pair) { 791*4bff34e3Sthurlow if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) { 792*4bff34e3Sthurlow *uid = pw.pw_uid; 793*4bff34e3Sthurlow } else 794*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 795*4bff34e3Sthurlow "Invalid user name %s, ignored"), 0, pair); 796*4bff34e3Sthurlow } 797*4bff34e3Sthurlow 798*4bff34e3Sthurlow return (0); 799*4bff34e3Sthurlow } 800*4bff34e3Sthurlow 801*4bff34e3Sthurlow /* 802*4bff34e3Sthurlow * Commands use this with getopt. See: 803*4bff34e3Sthurlow * STDPARAM_OPT, STDPARAM_ARGS 804*4bff34e3Sthurlow * Called after smb_ctx_readrc(). 805*4bff34e3Sthurlow */ 806*4bff34e3Sthurlow int 807*4bff34e3Sthurlow smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) 808*4bff34e3Sthurlow { 809*4bff34e3Sthurlow int error = 0; 810*4bff34e3Sthurlow char *p, *cp; 811*4bff34e3Sthurlow char tmp[1024]; 812*4bff34e3Sthurlow 813*4bff34e3Sthurlow switch (opt) { 814*4bff34e3Sthurlow case 'A': 815*4bff34e3Sthurlow case 'U': 816*4bff34e3Sthurlow /* Handled in smb_ctx_init() */ 817*4bff34e3Sthurlow break; 818*4bff34e3Sthurlow case 'I': 819*4bff34e3Sthurlow error = smb_ctx_setsrvaddr(ctx, arg); 820*4bff34e3Sthurlow break; 821*4bff34e3Sthurlow case 'M': 822*4bff34e3Sthurlow ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8); 823*4bff34e3Sthurlow if (*cp == '/') { 824*4bff34e3Sthurlow ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8); 825*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_SRIGHTS; 826*4bff34e3Sthurlow } 827*4bff34e3Sthurlow break; 828*4bff34e3Sthurlow case 'N': 829*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_NOPWD; 830*4bff34e3Sthurlow break; 831*4bff34e3Sthurlow case 'O': 832*4bff34e3Sthurlow p = strdup(arg); 833*4bff34e3Sthurlow cp = strchr(p, '/'); 834*4bff34e3Sthurlow if (cp) { 835*4bff34e3Sthurlow *cp++ = '\0'; 836*4bff34e3Sthurlow error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner, 837*4bff34e3Sthurlow &ctx->ct_sh.ioc_group); 838*4bff34e3Sthurlow } 839*4bff34e3Sthurlow if (*p && error == 0) { 840*4bff34e3Sthurlow error = smb_parse_owner(cp, &ctx->ct_ssn.ioc_owner, 841*4bff34e3Sthurlow &ctx->ct_ssn.ioc_group); 842*4bff34e3Sthurlow } 843*4bff34e3Sthurlow free(p); 844*4bff34e3Sthurlow break; 845*4bff34e3Sthurlow case 'P': 846*4bff34e3Sthurlow /* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT; */ 847*4bff34e3Sthurlow break; 848*4bff34e3Sthurlow case 'R': 849*4bff34e3Sthurlow ctx->ct_ssn.ioc_retrycount = atoi(arg); 850*4bff34e3Sthurlow break; 851*4bff34e3Sthurlow case 'T': 852*4bff34e3Sthurlow ctx->ct_ssn.ioc_timeout = atoi(arg); 853*4bff34e3Sthurlow break; 854*4bff34e3Sthurlow case 'W': 855*4bff34e3Sthurlow nls_str_upper(tmp, arg); 856*4bff34e3Sthurlow error = smb_ctx_setworkgroup(ctx, tmp, TRUE); 857*4bff34e3Sthurlow break; 858*4bff34e3Sthurlow } 859*4bff34e3Sthurlow return (error); 860*4bff34e3Sthurlow } 861*4bff34e3Sthurlow 862*4bff34e3Sthurlow #if 0 863*4bff34e3Sthurlow static void 864*4bff34e3Sthurlow smb_hexdump(const uchar_t *buf, int len) { 865*4bff34e3Sthurlow int ofs = 0; 866*4bff34e3Sthurlow 867*4bff34e3Sthurlow while (len--) { 868*4bff34e3Sthurlow if (ofs % 16 == 0) 869*4bff34e3Sthurlow printf("\n%02X: ", ofs); 870*4bff34e3Sthurlow printf("%02x ", *buf++); 871*4bff34e3Sthurlow ofs++; 872*4bff34e3Sthurlow } 873*4bff34e3Sthurlow printf("\n"); 874*4bff34e3Sthurlow } 875*4bff34e3Sthurlow #endif 876*4bff34e3Sthurlow 877*4bff34e3Sthurlow 878*4bff34e3Sthurlow static int 879*4bff34e3Sthurlow smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl) 880*4bff34e3Sthurlow { 881*4bff34e3Sthurlow int error; 882*4bff34e3Sthurlow 883*4bff34e3Sthurlow /* 884*4bff34e3Sthurlow * Not able to find out what is the work of this routine till 885*4bff34e3Sthurlow * now. Still investigating. 886*4bff34e3Sthurlow * REVISIT 887*4bff34e3Sthurlow */ 888*4bff34e3Sthurlow #ifdef KICONV_SUPPORT 889*4bff34e3Sthurlow error = kiconv_add_xlat_table(to, from, tbl); 890*4bff34e3Sthurlow if (error && error != EEXIST) { 891*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 892*4bff34e3Sthurlow "can not setup kernel iconv table (%s:%s)"), 893*4bff34e3Sthurlow error, from, to); 894*4bff34e3Sthurlow return (error); 895*4bff34e3Sthurlow } 896*4bff34e3Sthurlow #endif 897*4bff34e3Sthurlow return (0); 898*4bff34e3Sthurlow } 899*4bff34e3Sthurlow 900*4bff34e3Sthurlow /* 901*4bff34e3Sthurlow * Verify context before connect operation(s), 902*4bff34e3Sthurlow * lookup specified server and try to fill all forgotten fields. 903*4bff34e3Sthurlow */ 904*4bff34e3Sthurlow int 905*4bff34e3Sthurlow smb_ctx_resolve(struct smb_ctx *ctx) 906*4bff34e3Sthurlow { 907*4bff34e3Sthurlow struct smbioc_ossn *ssn = &ctx->ct_ssn; 908*4bff34e3Sthurlow struct smbioc_oshare *sh = &ctx->ct_sh; 909*4bff34e3Sthurlow struct nb_name nn; 910*4bff34e3Sthurlow struct sockaddr *sap; 911*4bff34e3Sthurlow struct sockaddr_nb *salocal, *saserver; 912*4bff34e3Sthurlow char *cp; 913*4bff34e3Sthurlow uchar_t cstbl[256]; 914*4bff34e3Sthurlow uint_t i; 915*4bff34e3Sthurlow int error = 0; 916*4bff34e3Sthurlow int browseok = ctx->ct_flags & SMBCF_BROWSEOK; 917*4bff34e3Sthurlow int renego = 0; 918*4bff34e3Sthurlow 919*4bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_RESOLVED; 920*4bff34e3Sthurlow if (isatty(STDIN_FILENO)) 921*4bff34e3Sthurlow browseok = 0; 922*4bff34e3Sthurlow if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == 0) { 923*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 924*4bff34e3Sthurlow "no server name specified"), 0); 925*4bff34e3Sthurlow return (EINVAL); 926*4bff34e3Sthurlow } 927*4bff34e3Sthurlow if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0 && 928*4bff34e3Sthurlow !browseok) { 929*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 930*4bff34e3Sthurlow "no share name specified for %s@%s"), 931*4bff34e3Sthurlow 0, ssn->ioc_user, ssn->ioc_srvname); 932*4bff34e3Sthurlow return (EINVAL); 933*4bff34e3Sthurlow } 934*4bff34e3Sthurlow error = nb_ctx_resolve(ctx->ct_nb); 935*4bff34e3Sthurlow if (error) 936*4bff34e3Sthurlow return (error); 937*4bff34e3Sthurlow if (ssn->ioc_localcs[0] == 0) 938*4bff34e3Sthurlow strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ 939*4bff34e3Sthurlow error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); 940*4bff34e3Sthurlow if (error) 941*4bff34e3Sthurlow return (error); 942*4bff34e3Sthurlow error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); 943*4bff34e3Sthurlow if (error) 944*4bff34e3Sthurlow return (error); 945*4bff34e3Sthurlow if (ssn->ioc_servercs[0] != 0) { 946*4bff34e3Sthurlow for (i = 0; i < sizeof (cstbl); i++) 947*4bff34e3Sthurlow cstbl[i] = i; 948*4bff34e3Sthurlow nls_mem_toext(cstbl, cstbl, sizeof (cstbl)); 949*4bff34e3Sthurlow error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, 950*4bff34e3Sthurlow cstbl); 951*4bff34e3Sthurlow if (error) 952*4bff34e3Sthurlow return (error); 953*4bff34e3Sthurlow for (i = 0; i < sizeof (cstbl); i++) 954*4bff34e3Sthurlow cstbl[i] = i; 955*4bff34e3Sthurlow nls_mem_toloc(cstbl, cstbl, sizeof (cstbl)); 956*4bff34e3Sthurlow error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, 957*4bff34e3Sthurlow cstbl); 958*4bff34e3Sthurlow if (error) 959*4bff34e3Sthurlow return (error); 960*4bff34e3Sthurlow } 961*4bff34e3Sthurlow /* 962*4bff34e3Sthurlow * If we have an explicit address set for the server in 963*4bff34e3Sthurlow * an "addr=X" setting in .nsmbrc or SMF, just try using a 964*4bff34e3Sthurlow * gethostbyname() lookup for it. 965*4bff34e3Sthurlow */ 966*4bff34e3Sthurlow if (ctx->ct_srvaddr) { 967*4bff34e3Sthurlow error = nb_resolvehost_in(ctx->ct_srvaddr, &sap); 968*4bff34e3Sthurlow if (error == 0) 969*4bff34e3Sthurlow (void) smb_ctx_getnbname(ctx, sap); 970*4bff34e3Sthurlow } else 971*4bff34e3Sthurlow error = -1; 972*4bff34e3Sthurlow 973*4bff34e3Sthurlow /* 974*4bff34e3Sthurlow * Next try a gethostbyname() lookup on the original user- 975*4bff34e3Sthurlow * specified server name. This is similar to Windows 976*4bff34e3Sthurlow * NBT option "Use DNS for name resolution." 977*4bff34e3Sthurlow */ 978*4bff34e3Sthurlow if (error && ctx->ct_fullserver) { 979*4bff34e3Sthurlow error = nb_resolvehost_in(ctx->ct_fullserver, &sap); 980*4bff34e3Sthurlow if (error == 0) 981*4bff34e3Sthurlow (void) smb_ctx_getnbname(ctx, sap); 982*4bff34e3Sthurlow } 983*4bff34e3Sthurlow 984*4bff34e3Sthurlow /* 985*4bff34e3Sthurlow * Finally, try the shorter, upper-cased ssn->ioc_srvname 986*4bff34e3Sthurlow * with a NBNS/WINS lookup if the "nbns_enable" property is 987*4bff34e3Sthurlow * true (the default). nbns_resolvename() may unicast to the 988*4bff34e3Sthurlow * "nbns" server or broadcast on the subnet. 989*4bff34e3Sthurlow */ 990*4bff34e3Sthurlow if (error && ssn->ioc_srvname[0] && 991*4bff34e3Sthurlow ctx->ct_nb->nb_flags & NBCF_NS_ENABLE) { 992*4bff34e3Sthurlow error = nbns_resolvename(ssn->ioc_srvname, 993*4bff34e3Sthurlow ctx->ct_nb, &sap); 994*4bff34e3Sthurlow /* 995*4bff34e3Sthurlow * Used to get the NetBIOS node status here. 996*4bff34e3Sthurlow * Not necessary (we have the NetBIOS name). 997*4bff34e3Sthurlow */ 998*4bff34e3Sthurlow } 999*4bff34e3Sthurlow if (error) { 1000*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1001*4bff34e3Sthurlow "can't get server address"), error); 1002*4bff34e3Sthurlow return (error); 1003*4bff34e3Sthurlow } 1004*4bff34e3Sthurlow 1005*4bff34e3Sthurlow /* XXX: no nls_str_upper(ssn->ioc_srvname) here? */ 1006*4bff34e3Sthurlow 1007*4bff34e3Sthurlow assert(sizeof (nn.nn_name) == sizeof (ssn->ioc_srvname)); 1008*4bff34e3Sthurlow memcpy(nn.nn_name, ssn->ioc_srvname, NB_NAMELEN); 1009*4bff34e3Sthurlow nn.nn_type = NBT_SERVER; 1010*4bff34e3Sthurlow nn.nn_scope = ctx->ct_nb->nb_scope; 1011*4bff34e3Sthurlow 1012*4bff34e3Sthurlow error = nb_sockaddr(sap, &nn, &saserver); 1013*4bff34e3Sthurlow memcpy(&ctx->ct_srvinaddr, sap, sizeof (struct sockaddr_in)); 1014*4bff34e3Sthurlow nb_snbfree(sap); 1015*4bff34e3Sthurlow if (error) { 1016*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1017*4bff34e3Sthurlow "can't allocate server address"), error); 1018*4bff34e3Sthurlow return (error); 1019*4bff34e3Sthurlow } 1020*4bff34e3Sthurlow /* We know it's a NetBIOS address here. */ 1021*4bff34e3Sthurlow bcopy(saserver, &ssn->ioc_server.nb, 1022*4bff34e3Sthurlow sizeof (struct sockaddr_nb)); 1023*4bff34e3Sthurlow if (ctx->ct_locname[0] == 0) { 1024*4bff34e3Sthurlow error = nb_getlocalname(ctx->ct_locname, 1025*4bff34e3Sthurlow SMB_MAXUSERNAMELEN + 1); 1026*4bff34e3Sthurlow if (error) { 1027*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1028*4bff34e3Sthurlow "can't get local name"), error); 1029*4bff34e3Sthurlow return (error); 1030*4bff34e3Sthurlow } 1031*4bff34e3Sthurlow nls_str_upper(ctx->ct_locname, ctx->ct_locname); 1032*4bff34e3Sthurlow } 1033*4bff34e3Sthurlow 1034*4bff34e3Sthurlow /* XXX: no nls_str_upper(ctx->ct_locname); here? */ 1035*4bff34e3Sthurlow 1036*4bff34e3Sthurlow memcpy(nn.nn_name, ctx->ct_locname, NB_NAMELEN); 1037*4bff34e3Sthurlow nn.nn_type = NBT_WKSTA; 1038*4bff34e3Sthurlow nn.nn_scope = ctx->ct_nb->nb_scope; 1039*4bff34e3Sthurlow 1040*4bff34e3Sthurlow error = nb_sockaddr(NULL, &nn, &salocal); 1041*4bff34e3Sthurlow if (error) { 1042*4bff34e3Sthurlow nb_snbfree((struct sockaddr *)saserver); 1043*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1044*4bff34e3Sthurlow "can't allocate local address"), error); 1045*4bff34e3Sthurlow return (error); 1046*4bff34e3Sthurlow } 1047*4bff34e3Sthurlow 1048*4bff34e3Sthurlow /* We know it's a NetBIOS address here. */ 1049*4bff34e3Sthurlow bcopy(salocal, &ssn->ioc_local.nb, 1050*4bff34e3Sthurlow sizeof (struct sockaddr_nb)); 1051*4bff34e3Sthurlow 1052*4bff34e3Sthurlow error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, 1053*4bff34e3Sthurlow ssn->ioc_workgroup); 1054*4bff34e3Sthurlow if (error) 1055*4bff34e3Sthurlow return (error); 1056*4bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_AUTHREQ; 1057*4bff34e3Sthurlow if (!ctx->ct_secblob && browseok && !sh->ioc_share[0] && 1058*4bff34e3Sthurlow !(ctx->ct_flags & SMBCF_XXX)) { 1059*4bff34e3Sthurlow /* assert: anon share list is subset of overall server shares */ 1060*4bff34e3Sthurlow error = smb_browse(ctx, 1); 1061*4bff34e3Sthurlow if (error) /* user cancel or other error? */ 1062*4bff34e3Sthurlow return (error); 1063*4bff34e3Sthurlow /* 1064*4bff34e3Sthurlow * A share was selected, authenticate button was pressed, 1065*4bff34e3Sthurlow * or anon-authentication failed getting browse list. 1066*4bff34e3Sthurlow */ 1067*4bff34e3Sthurlow } 1068*4bff34e3Sthurlow if ((ctx->ct_secblob == NULL) && (ctx->ct_flags & SMBCF_AUTHREQ || 1069*4bff34e3Sthurlow (ssn->ioc_password[0] == '\0' && 1070*4bff34e3Sthurlow !(ctx->ct_flags & SMBCF_NOPWD)))) { 1071*4bff34e3Sthurlow reauth: 1072*4bff34e3Sthurlow /* 1073*4bff34e3Sthurlow * This function is implemented in both 1074*4bff34e3Sthurlow * ui-apple.c and ui-sun.c so let's try to 1075*4bff34e3Sthurlow * keep the same interface. Not sure why 1076*4bff34e3Sthurlow * they didn't just pass ssn here. 1077*4bff34e3Sthurlow */ 1078*4bff34e3Sthurlow error = smb_get_authentication( 1079*4bff34e3Sthurlow ssn->ioc_workgroup, sizeof (ssn->ioc_workgroup) - 1, 1080*4bff34e3Sthurlow ssn->ioc_user, sizeof (ssn->ioc_user) - 1, 1081*4bff34e3Sthurlow ssn->ioc_password, sizeof (ssn->ioc_password) - 1, 1082*4bff34e3Sthurlow ssn->ioc_srvname, ctx); 1083*4bff34e3Sthurlow if (error) 1084*4bff34e3Sthurlow return (error); 1085*4bff34e3Sthurlow } 1086*4bff34e3Sthurlow /* 1087*4bff34e3Sthurlow * if we have a session it is either anonymous 1088*4bff34e3Sthurlow * or from a stale authentication. re-negotiating 1089*4bff34e3Sthurlow * gets us ready for a fresh session 1090*4bff34e3Sthurlow */ 1091*4bff34e3Sthurlow if (ctx->ct_flags & SMBCF_SSNACTIVE || renego) { 1092*4bff34e3Sthurlow renego = 0; 1093*4bff34e3Sthurlow /* don't clobber workgroup name, pass null arg */ 1094*4bff34e3Sthurlow error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, NULL); 1095*4bff34e3Sthurlow if (error) 1096*4bff34e3Sthurlow return (error); 1097*4bff34e3Sthurlow } 1098*4bff34e3Sthurlow if (browseok && !sh->ioc_share[0]) { 1099*4bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_AUTHREQ; 1100*4bff34e3Sthurlow error = smb_browse(ctx, 0); 1101*4bff34e3Sthurlow if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) { 1102*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1103*4bff34e3Sthurlow "smb_ctx_resolve: bad keychain entry"), 0); 1104*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_KCBAD; 1105*4bff34e3Sthurlow renego = 1; 1106*4bff34e3Sthurlow goto reauth; 1107*4bff34e3Sthurlow } 1108*4bff34e3Sthurlow if (error) /* auth, user cancel, or other error */ 1109*4bff34e3Sthurlow return (error); 1110*4bff34e3Sthurlow /* 1111*4bff34e3Sthurlow * Re-authenticate button was pressed? 1112*4bff34e3Sthurlow */ 1113*4bff34e3Sthurlow if (ctx->ct_flags & SMBCF_AUTHREQ) 1114*4bff34e3Sthurlow goto reauth; 1115*4bff34e3Sthurlow if (!sh->ioc_share[0] && !(ctx->ct_flags & SMBCF_XXX)) { 1116*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1117*4bff34e3Sthurlow "no share specified for %s@%s"), 1118*4bff34e3Sthurlow 0, ssn->ioc_user, ssn->ioc_srvname); 1119*4bff34e3Sthurlow return (EINVAL); 1120*4bff34e3Sthurlow } 1121*4bff34e3Sthurlow } 1122*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_RESOLVED; 1123*4bff34e3Sthurlow 1124*4bff34e3Sthurlow if (smb_debug) 1125*4bff34e3Sthurlow dump_ctx("after smb_ctx_resolve", ctx); 1126*4bff34e3Sthurlow 1127*4bff34e3Sthurlow return (0); 1128*4bff34e3Sthurlow } 1129*4bff34e3Sthurlow 1130*4bff34e3Sthurlow int 1131*4bff34e3Sthurlow smb_open_driver() 1132*4bff34e3Sthurlow { 1133*4bff34e3Sthurlow char buf[20]; 1134*4bff34e3Sthurlow int err, fd, i; 1135*4bff34e3Sthurlow uint32_t version; 1136*4bff34e3Sthurlow 1137*4bff34e3Sthurlow /* 1138*4bff34e3Sthurlow * First try to open as clone 1139*4bff34e3Sthurlow */ 1140*4bff34e3Sthurlow fd = open("/dev/"NSMB_NAME, O_RDWR); 1141*4bff34e3Sthurlow if (fd >= 0) 1142*4bff34e3Sthurlow goto opened; 1143*4bff34e3Sthurlow 1144*4bff34e3Sthurlow err = errno; /* from open */ 1145*4bff34e3Sthurlow #ifdef APPLE 1146*4bff34e3Sthurlow /* 1147*4bff34e3Sthurlow * well, no clone capabilities available - we have to scan 1148*4bff34e3Sthurlow * all devices in order to get free one 1149*4bff34e3Sthurlow */ 1150*4bff34e3Sthurlow for (i = 0; i < 1024; i++) { 1151*4bff34e3Sthurlow snprintf(buf, sizeof (buf), "/dev/%s%d", NSMB_NAME, i); 1152*4bff34e3Sthurlow fd = open(buf, O_RDWR); 1153*4bff34e3Sthurlow if (fd >= 0) 1154*4bff34e3Sthurlow goto opened; 1155*4bff34e3Sthurlow if (i && POWEROF2(i+1)) 1156*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1157*4bff34e3Sthurlow "%d failures to open smb device"), errno, i+1); 1158*4bff34e3Sthurlow } 1159*4bff34e3Sthurlow err = ENOENT; 1160*4bff34e3Sthurlow #endif 1161*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1162*4bff34e3Sthurlow "failed to open %s"), err, "/dev/" NSMB_NAME); 1163*4bff34e3Sthurlow return (-1); 1164*4bff34e3Sthurlow 1165*4bff34e3Sthurlow opened: 1166*4bff34e3Sthurlow /* 1167*4bff34e3Sthurlow * Check the driver version (paranoia) 1168*4bff34e3Sthurlow * Do this BEFORE any other ioctl calls. 1169*4bff34e3Sthurlow */ 1170*4bff34e3Sthurlow if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) { 1171*4bff34e3Sthurlow err = errno; 1172*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1173*4bff34e3Sthurlow "failed to get driver version"), err); 1174*4bff34e3Sthurlow close(fd); 1175*4bff34e3Sthurlow return (-1); 1176*4bff34e3Sthurlow } 1177*4bff34e3Sthurlow if (version != NSMB_VERSION) { 1178*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1179*4bff34e3Sthurlow "incorrect driver version"), 0); 1180*4bff34e3Sthurlow close(fd); 1181*4bff34e3Sthurlow return (-1); 1182*4bff34e3Sthurlow } 1183*4bff34e3Sthurlow 1184*4bff34e3Sthurlow return (fd); 1185*4bff34e3Sthurlow } 1186*4bff34e3Sthurlow 1187*4bff34e3Sthurlow static int 1188*4bff34e3Sthurlow smb_ctx_gethandle(struct smb_ctx *ctx) 1189*4bff34e3Sthurlow { 1190*4bff34e3Sthurlow int err, fd; 1191*4bff34e3Sthurlow 1192*4bff34e3Sthurlow if (ctx->ct_fd != -1) { 1193*4bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 1194*4bff34e3Sthurlow close(ctx->ct_fd); 1195*4bff34e3Sthurlow ctx->ct_fd = -1; 1196*4bff34e3Sthurlow ctx->ct_flags &= ~SMBCF_SSNACTIVE; 1197*4bff34e3Sthurlow } 1198*4bff34e3Sthurlow 1199*4bff34e3Sthurlow fd = smb_open_driver(); 1200*4bff34e3Sthurlow if (fd < 0) 1201*4bff34e3Sthurlow return (ENODEV); 1202*4bff34e3Sthurlow 1203*4bff34e3Sthurlow ctx->ct_fd = fd; 1204*4bff34e3Sthurlow return (0); 1205*4bff34e3Sthurlow } 1206*4bff34e3Sthurlow 1207*4bff34e3Sthurlow int 1208*4bff34e3Sthurlow smb_ctx_ioctl(struct smb_ctx *ctx, int inum, struct smbioc_lookup *rqp) 1209*4bff34e3Sthurlow { 1210*4bff34e3Sthurlow size_t siz = DEF_SEC_TOKEN_LEN; 1211*4bff34e3Sthurlow int rc = 0; 1212*4bff34e3Sthurlow struct sockaddr sap1, sap2; 1213*4bff34e3Sthurlow int i; 1214*4bff34e3Sthurlow 1215*4bff34e3Sthurlow if (rqp->ioc_ssn.ioc_outtok) 1216*4bff34e3Sthurlow free(rqp->ioc_ssn.ioc_outtok); 1217*4bff34e3Sthurlow rqp->ioc_ssn.ioc_outtoklen = siz; 1218*4bff34e3Sthurlow rqp->ioc_ssn.ioc_outtok = malloc(siz+1); 1219*4bff34e3Sthurlow if (rqp->ioc_ssn.ioc_outtok == NULL) 1220*4bff34e3Sthurlow return (ENOMEM); 1221*4bff34e3Sthurlow bzero(rqp->ioc_ssn.ioc_outtok, siz+1); 1222*4bff34e3Sthurlow /* Note: No longer put length in outtok[0] */ 1223*4bff34e3Sthurlow /* *((int *)rqp->ioc_ssn.ioc_outtok) = (int)siz; */ 1224*4bff34e3Sthurlow 1225*4bff34e3Sthurlow seteuid(eff_uid); /* restore setuid root briefly */ 1226*4bff34e3Sthurlow if (ioctl(ctx->ct_fd, inum, rqp) == -1) { 1227*4bff34e3Sthurlow rc = errno; 1228*4bff34e3Sthurlow goto out; 1229*4bff34e3Sthurlow } 1230*4bff34e3Sthurlow if (rqp->ioc_ssn.ioc_outtoklen <= siz) 1231*4bff34e3Sthurlow goto out; 1232*4bff34e3Sthurlow 1233*4bff34e3Sthurlow /* 1234*4bff34e3Sthurlow * Operation completed, but our output token wasn't large enough. 1235*4bff34e3Sthurlow * The re-call below only pulls the token from the kernel. 1236*4bff34e3Sthurlow */ 1237*4bff34e3Sthurlow siz = rqp->ioc_ssn.ioc_outtoklen; 1238*4bff34e3Sthurlow free(rqp->ioc_ssn.ioc_outtok); 1239*4bff34e3Sthurlow rqp->ioc_ssn.ioc_outtok = malloc(siz + 1); 1240*4bff34e3Sthurlow if (rqp->ioc_ssn.ioc_outtok == NULL) { 1241*4bff34e3Sthurlow rc = ENOMEM; 1242*4bff34e3Sthurlow goto out; 1243*4bff34e3Sthurlow } 1244*4bff34e3Sthurlow bzero(rqp->ioc_ssn.ioc_outtok, siz+1); 1245*4bff34e3Sthurlow /* Note: No longer put length in outtok[0] */ 1246*4bff34e3Sthurlow /* *((int *)rqp->ioc_ssn.ioc_outtok) = siz; */ 1247*4bff34e3Sthurlow if (ioctl(ctx->ct_fd, inum, rqp) == -1) 1248*4bff34e3Sthurlow rc = errno; 1249*4bff34e3Sthurlow out: 1250*4bff34e3Sthurlow seteuid(real_uid); /* and back to real user */ 1251*4bff34e3Sthurlow return (rc); 1252*4bff34e3Sthurlow } 1253*4bff34e3Sthurlow 1254*4bff34e3Sthurlow 1255*4bff34e3Sthurlow /* 1256*4bff34e3Sthurlow * adds a GSSAPI wrapper 1257*4bff34e3Sthurlow */ 1258*4bff34e3Sthurlow char * 1259*4bff34e3Sthurlow smb_ctx_tkt2gtok(uchar_t *tkt, ulong_t tktlen, 1260*4bff34e3Sthurlow uchar_t **gtokp, ulong_t *gtoklenp) 1261*4bff34e3Sthurlow { 1262*4bff34e3Sthurlow ulong_t bloblen = tktlen; 1263*4bff34e3Sthurlow ulong_t len; 1264*4bff34e3Sthurlow uchar_t krbapreq[2] = "\x01\x00"; /* see RFC 1964 */ 1265*4bff34e3Sthurlow char *failure; 1266*4bff34e3Sthurlow uchar_t *blob = NULL; /* result */ 1267*4bff34e3Sthurlow uchar_t *b; 1268*4bff34e3Sthurlow 1269*4bff34e3Sthurlow bloblen += sizeof (krbapreq); 1270*4bff34e3Sthurlow bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen; 1271*4bff34e3Sthurlow len = bloblen; 1272*4bff34e3Sthurlow bloblen = ASNDerCalcTokenLength(bloblen, bloblen); 1273*4bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok malloc"); 1274*4bff34e3Sthurlow if (!(blob = malloc(bloblen))) 1275*4bff34e3Sthurlow goto out; 1276*4bff34e3Sthurlow b = blob; 1277*4bff34e3Sthurlow b += ASNDerWriteToken(b, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, len); 1278*4bff34e3Sthurlow b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5); 1279*4bff34e3Sthurlow memcpy(b, krbapreq, sizeof (krbapreq)); 1280*4bff34e3Sthurlow b += sizeof (krbapreq); 1281*4bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok insanity check"); 1282*4bff34e3Sthurlow if (b + tktlen != blob + bloblen) 1283*4bff34e3Sthurlow goto out; 1284*4bff34e3Sthurlow memcpy(b, tkt, tktlen); 1285*4bff34e3Sthurlow *gtoklenp = bloblen; 1286*4bff34e3Sthurlow *gtokp = blob; 1287*4bff34e3Sthurlow failure = NULL; 1288*4bff34e3Sthurlow out:; 1289*4bff34e3Sthurlow if (blob && failure) 1290*4bff34e3Sthurlow free(blob); 1291*4bff34e3Sthurlow return (failure); 1292*4bff34e3Sthurlow } 1293*4bff34e3Sthurlow 1294*4bff34e3Sthurlow 1295*4bff34e3Sthurlow /* 1296*4bff34e3Sthurlow * Initialization for Kerberos, pulled out of smb_ctx_principal2tkt. 1297*4bff34e3Sthurlow * This just gets our cached credentials, if we have any. 1298*4bff34e3Sthurlow * Based on the "klist" command. 1299*4bff34e3Sthurlow */ 1300*4bff34e3Sthurlow char * 1301*4bff34e3Sthurlow smb_ctx_krb5init(struct smb_ctx *ctx) 1302*4bff34e3Sthurlow { 1303*4bff34e3Sthurlow char *failure; 1304*4bff34e3Sthurlow krb5_error_code kerr; 1305*4bff34e3Sthurlow krb5_context kctx = NULL; 1306*4bff34e3Sthurlow krb5_ccache kcc = NULL; 1307*4bff34e3Sthurlow krb5_principal kprin = NULL; 1308*4bff34e3Sthurlow 1309*4bff34e3Sthurlow kerr = krb5_init_context(&kctx); 1310*4bff34e3Sthurlow if (kerr) { 1311*4bff34e3Sthurlow failure = "krb5_init_context"; 1312*4bff34e3Sthurlow goto out; 1313*4bff34e3Sthurlow } 1314*4bff34e3Sthurlow ctx->ct_krb5ctx = kctx; 1315*4bff34e3Sthurlow 1316*4bff34e3Sthurlow /* non-default would instead use krb5_cc_resolve */ 1317*4bff34e3Sthurlow kerr = krb5_cc_default(kctx, &kcc); 1318*4bff34e3Sthurlow if (kerr) { 1319*4bff34e3Sthurlow failure = "krb5_cc_default"; 1320*4bff34e3Sthurlow goto out; 1321*4bff34e3Sthurlow } 1322*4bff34e3Sthurlow ctx->ct_krb5cc = kcc; 1323*4bff34e3Sthurlow 1324*4bff34e3Sthurlow /* 1325*4bff34e3Sthurlow * Get the client principal (ticket), 1326*4bff34e3Sthurlow * or find out if we don't have one. 1327*4bff34e3Sthurlow */ 1328*4bff34e3Sthurlow kerr = krb5_cc_get_principal(kctx, kcc, &kprin); 1329*4bff34e3Sthurlow if (kerr) { 1330*4bff34e3Sthurlow failure = "krb5_cc_get_principal"; 1331*4bff34e3Sthurlow goto out; 1332*4bff34e3Sthurlow } 1333*4bff34e3Sthurlow ctx->ct_krb5cp = kprin; 1334*4bff34e3Sthurlow 1335*4bff34e3Sthurlow if (smb_verbose) { 1336*4bff34e3Sthurlow fprintf(stderr, gettext("Ticket cache: %s:%s\n"), 1337*4bff34e3Sthurlow krb5_cc_get_type(kctx, kcc), 1338*4bff34e3Sthurlow krb5_cc_get_name(kctx, kcc)); 1339*4bff34e3Sthurlow } 1340*4bff34e3Sthurlow failure = NULL; 1341*4bff34e3Sthurlow 1342*4bff34e3Sthurlow out: 1343*4bff34e3Sthurlow return (failure); 1344*4bff34e3Sthurlow } 1345*4bff34e3Sthurlow 1346*4bff34e3Sthurlow 1347*4bff34e3Sthurlow /* 1348*4bff34e3Sthurlow * See "Windows 2000 Kerberos Interoperability" paper by 1349*4bff34e3Sthurlow * Christopher Nebergall. RC4 HMAC is the W2K default but 1350*4bff34e3Sthurlow * Samba support lagged (not due to Samba itself, but due to OS' 1351*4bff34e3Sthurlow * Kerberos implementations.) 1352*4bff34e3Sthurlow * 1353*4bff34e3Sthurlow * Only session enc type should matter, not ticket enc type, 1354*4bff34e3Sthurlow * per Sam Hartman on krbdev. 1355*4bff34e3Sthurlow * 1356*4bff34e3Sthurlow * Preauthentication failure topics in krb-protocol may help here... 1357*4bff34e3Sthurlow * try "John Brezak" and/or "Clifford Neuman" too. 1358*4bff34e3Sthurlow */ 1359*4bff34e3Sthurlow static krb5_enctype kenctypes[] = { 1360*4bff34e3Sthurlow ENCTYPE_ARCFOUR_HMAC, /* defined in Tiger krb5.h */ 1361*4bff34e3Sthurlow ENCTYPE_DES_CBC_MD5, 1362*4bff34e3Sthurlow ENCTYPE_DES_CBC_CRC, 1363*4bff34e3Sthurlow ENCTYPE_NULL 1364*4bff34e3Sthurlow }; 1365*4bff34e3Sthurlow 1366*4bff34e3Sthurlow /* 1367*4bff34e3Sthurlow * Obtain a kerberos ticket... 1368*4bff34e3Sthurlow * (if TLD != "gov" then pray first) 1369*4bff34e3Sthurlow */ 1370*4bff34e3Sthurlow char * 1371*4bff34e3Sthurlow smb_ctx_principal2tkt( 1372*4bff34e3Sthurlow struct smb_ctx *ctx, char *prin, 1373*4bff34e3Sthurlow uchar_t **tktp, ulong_t *tktlenp) 1374*4bff34e3Sthurlow { 1375*4bff34e3Sthurlow char *failure; 1376*4bff34e3Sthurlow krb5_context kctx = NULL; 1377*4bff34e3Sthurlow krb5_error_code kerr; 1378*4bff34e3Sthurlow krb5_ccache kcc = NULL; 1379*4bff34e3Sthurlow krb5_principal kprin = NULL, cprn = NULL; 1380*4bff34e3Sthurlow krb5_creds kcreds, *kcredsp = NULL; 1381*4bff34e3Sthurlow krb5_auth_context kauth = NULL; 1382*4bff34e3Sthurlow krb5_data kdata, kdata0; 1383*4bff34e3Sthurlow uchar_t *tkt; 1384*4bff34e3Sthurlow 1385*4bff34e3Sthurlow memset((char *)&kcreds, 0, sizeof (kcreds)); 1386*4bff34e3Sthurlow kdata0.length = 0; 1387*4bff34e3Sthurlow 1388*4bff34e3Sthurlow /* These shoud have been done in smb_ctx_krb5init() */ 1389*4bff34e3Sthurlow if (ctx->ct_krb5ctx == NULL || 1390*4bff34e3Sthurlow ctx->ct_krb5cc == NULL || 1391*4bff34e3Sthurlow ctx->ct_krb5cp == NULL) { 1392*4bff34e3Sthurlow failure = "smb_ctx_krb5init"; 1393*4bff34e3Sthurlow goto out; 1394*4bff34e3Sthurlow } 1395*4bff34e3Sthurlow kctx = ctx->ct_krb5ctx; 1396*4bff34e3Sthurlow kcc = ctx->ct_krb5cc; 1397*4bff34e3Sthurlow cprn = ctx->ct_krb5cp; 1398*4bff34e3Sthurlow 1399*4bff34e3Sthurlow failure = "krb5_set_default_tgs_enctypes"; 1400*4bff34e3Sthurlow if ((kerr = krb5_set_default_tgs_enctypes(kctx, kenctypes))) 1401*4bff34e3Sthurlow goto out; 1402*4bff34e3Sthurlow /* 1403*4bff34e3Sthurlow * The following is an unrolling of krb5_mk_req. Something like: 1404*4bff34e3Sthurlow * krb5_mk_req(kctx, &kauth, 0, service(prin), hostname(prin), 1405*4bff34e3Sthurlow * &kdata0, kcc, &kdata);) 1406*4bff34e3Sthurlow * ...except we needed krb5_parse_name not krb5_sname_to_principal. 1407*4bff34e3Sthurlow */ 1408*4bff34e3Sthurlow failure = "krb5_parse_name"; 1409*4bff34e3Sthurlow if ((kerr = krb5_parse_name(kctx, prin, &kprin))) 1410*4bff34e3Sthurlow goto out; 1411*4bff34e3Sthurlow failure = "krb5_copy_principal(server)"; 1412*4bff34e3Sthurlow if ((kerr = krb5_copy_principal(kctx, kprin, &kcreds.server))) 1413*4bff34e3Sthurlow goto out; 1414*4bff34e3Sthurlow failure = "krb5_copy_principal(client)"; 1415*4bff34e3Sthurlow if ((kerr = krb5_copy_principal(kctx, cprn, &kcreds.client))) 1416*4bff34e3Sthurlow goto out; 1417*4bff34e3Sthurlow failure = "krb5_get_credentials"; 1418*4bff34e3Sthurlow if ((kerr = krb5_get_credentials(kctx, 0, kcc, &kcreds, &kcredsp))) 1419*4bff34e3Sthurlow goto out; 1420*4bff34e3Sthurlow failure = "krb5_mk_req_extended"; 1421*4bff34e3Sthurlow if ((kerr = krb5_mk_req_extended(kctx, &kauth, 0, &kdata0, kcredsp, 1422*4bff34e3Sthurlow &kdata))) 1423*4bff34e3Sthurlow goto out; 1424*4bff34e3Sthurlow failure = "malloc"; 1425*4bff34e3Sthurlow if (!(tkt = malloc(kdata.length))) { 1426*4bff34e3Sthurlow krb5_free_data_contents(kctx, &kdata); 1427*4bff34e3Sthurlow goto out; 1428*4bff34e3Sthurlow } 1429*4bff34e3Sthurlow *tktlenp = kdata.length; 1430*4bff34e3Sthurlow memcpy(tkt, kdata.data, kdata.length); 1431*4bff34e3Sthurlow krb5_free_data_contents(kctx, &kdata); 1432*4bff34e3Sthurlow *tktp = tkt; 1433*4bff34e3Sthurlow failure = NULL; 1434*4bff34e3Sthurlow out:; 1435*4bff34e3Sthurlow if (kerr) { 1436*4bff34e3Sthurlow if (!failure) 1437*4bff34e3Sthurlow failure = "smb_ctx_principal2tkt"; 1438*4bff34e3Sthurlow /* 1439*4bff34e3Sthurlow * Avoid logging the typical "No credentials cache found" 1440*4bff34e3Sthurlow */ 1441*4bff34e3Sthurlow if (kerr != KRB5_FCC_NOFILE || 1442*4bff34e3Sthurlow strcmp(failure, "krb5_cc_get_principal")) 1443*4bff34e3Sthurlow com_err(__progname, kerr, failure); 1444*4bff34e3Sthurlow } 1445*4bff34e3Sthurlow if (kauth) 1446*4bff34e3Sthurlow krb5_auth_con_free(kctx, kauth); 1447*4bff34e3Sthurlow if (kcredsp) 1448*4bff34e3Sthurlow krb5_free_creds(kctx, kcredsp); 1449*4bff34e3Sthurlow if (kcreds.server || kcreds.client) 1450*4bff34e3Sthurlow krb5_free_cred_contents(kctx, &kcreds); 1451*4bff34e3Sthurlow if (kprin) 1452*4bff34e3Sthurlow krb5_free_principal(kctx, kprin); 1453*4bff34e3Sthurlow 1454*4bff34e3Sthurlow /* Free kctx in smb_ctx_done */ 1455*4bff34e3Sthurlow 1456*4bff34e3Sthurlow return (failure); 1457*4bff34e3Sthurlow } 1458*4bff34e3Sthurlow 1459*4bff34e3Sthurlow char * 1460*4bff34e3Sthurlow smb_ctx_principal2blob( 1461*4bff34e3Sthurlow struct smb_ctx *ctx, 1462*4bff34e3Sthurlow smbioc_ossn_t *ssn, 1463*4bff34e3Sthurlow char *prin) 1464*4bff34e3Sthurlow { 1465*4bff34e3Sthurlow int rc = 0; 1466*4bff34e3Sthurlow char *failure; 1467*4bff34e3Sthurlow uchar_t *tkt = NULL; 1468*4bff34e3Sthurlow ulong_t tktlen; 1469*4bff34e3Sthurlow uchar_t *gtok = NULL; /* gssapi token */ 1470*4bff34e3Sthurlow ulong_t gtoklen; /* gssapi token length */ 1471*4bff34e3Sthurlow SPNEGO_TOKEN_HANDLE stok = NULL; /* spnego token */ 1472*4bff34e3Sthurlow void *blob = NULL; /* result */ 1473*4bff34e3Sthurlow ulong_t bloblen; /* result length */ 1474*4bff34e3Sthurlow 1475*4bff34e3Sthurlow if ((failure = smb_ctx_principal2tkt(ctx, prin, &tkt, &tktlen))) 1476*4bff34e3Sthurlow goto out; 1477*4bff34e3Sthurlow if ((failure = smb_ctx_tkt2gtok(tkt, tktlen, >ok, >oklen))) 1478*4bff34e3Sthurlow goto out; 1479*4bff34e3Sthurlow /* 1480*4bff34e3Sthurlow * RFC says to send NegTokenTarg now. So does MS docs. But 1481*4bff34e3Sthurlow * win2k gives ERRbaduid if we do... we must send 1482*4bff34e3Sthurlow * another NegTokenInit now! 1483*4bff34e3Sthurlow */ 1484*4bff34e3Sthurlow failure = "spnegoCreateNegTokenInit"; 1485*4bff34e3Sthurlow if ((rc = spnegoCreateNegTokenInit(spnego_mech_oid_Kerberos_V5_Legacy, 1486*4bff34e3Sthurlow 0, gtok, gtoklen, NULL, 0, &stok))) 1487*4bff34e3Sthurlow goto out; 1488*4bff34e3Sthurlow failure = "spnegoTokenGetBinary(NULL)"; 1489*4bff34e3Sthurlow rc = spnegoTokenGetBinary(stok, NULL, &bloblen); 1490*4bff34e3Sthurlow if (rc != SPNEGO_E_BUFFER_TOO_SMALL) 1491*4bff34e3Sthurlow goto out; 1492*4bff34e3Sthurlow failure = "malloc"; 1493*4bff34e3Sthurlow if (!(blob = malloc((size_t)bloblen))) 1494*4bff34e3Sthurlow goto out; 1495*4bff34e3Sthurlow /* No longer store length at start of blob. */ 1496*4bff34e3Sthurlow /* *blob = bloblen; */ 1497*4bff34e3Sthurlow failure = "spnegoTokenGetBinary"; 1498*4bff34e3Sthurlow if ((rc = spnegoTokenGetBinary(stok, blob, &bloblen))) 1499*4bff34e3Sthurlow goto out; 1500*4bff34e3Sthurlow ssn->ioc_intoklen = bloblen; 1501*4bff34e3Sthurlow ssn->ioc_intok = blob; 1502*4bff34e3Sthurlow failure = NULL; 1503*4bff34e3Sthurlow out:; 1504*4bff34e3Sthurlow if (rc) { 1505*4bff34e3Sthurlow /* XXX better is to embed rc in failure */ 1506*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1507*4bff34e3Sthurlow "spnego principal2blob error %d"), 0, -rc); 1508*4bff34e3Sthurlow if (!failure) 1509*4bff34e3Sthurlow failure = "spnego"; 1510*4bff34e3Sthurlow } 1511*4bff34e3Sthurlow if (blob && failure) 1512*4bff34e3Sthurlow free(blob); 1513*4bff34e3Sthurlow if (stok) 1514*4bff34e3Sthurlow spnegoFreeData(stok); 1515*4bff34e3Sthurlow if (gtok) 1516*4bff34e3Sthurlow free(gtok); 1517*4bff34e3Sthurlow if (tkt) 1518*4bff34e3Sthurlow free(tkt); 1519*4bff34e3Sthurlow return (failure); 1520*4bff34e3Sthurlow } 1521*4bff34e3Sthurlow 1522*4bff34e3Sthurlow 1523*4bff34e3Sthurlow #if 0 1524*4bff34e3Sthurlow void 1525*4bff34e3Sthurlow prblob(uchar_t *b, size_t len) 1526*4bff34e3Sthurlow { 1527*4bff34e3Sthurlow while (len--) 1528*4bff34e3Sthurlow fprintf(stderr, "%02x", *b++); 1529*4bff34e3Sthurlow fprintf(stderr, "\n"); 1530*4bff34e3Sthurlow } 1531*4bff34e3Sthurlow #endif 1532*4bff34e3Sthurlow 1533*4bff34e3Sthurlow 1534*4bff34e3Sthurlow /* 1535*4bff34e3Sthurlow * We navigate the SPNEGO & ASN1 encoding to find a kerberos principal 1536*4bff34e3Sthurlow * Note: driver no longer puts length at start of blob. 1537*4bff34e3Sthurlow */ 1538*4bff34e3Sthurlow char * 1539*4bff34e3Sthurlow smb_ctx_blob2principal( 1540*4bff34e3Sthurlow struct smb_ctx *ctx, 1541*4bff34e3Sthurlow smbioc_ossn_t *ssn, 1542*4bff34e3Sthurlow char **prinp) 1543*4bff34e3Sthurlow { 1544*4bff34e3Sthurlow uchar_t *blob = ssn->ioc_outtok; 1545*4bff34e3Sthurlow size_t len = ssn->ioc_outtoklen; 1546*4bff34e3Sthurlow int rc = 0; 1547*4bff34e3Sthurlow SPNEGO_TOKEN_HANDLE stok = NULL; 1548*4bff34e3Sthurlow int indx = 0; 1549*4bff34e3Sthurlow char *failure; 1550*4bff34e3Sthurlow uchar_t flags = 0; 1551*4bff34e3Sthurlow unsigned long plen = 0; 1552*4bff34e3Sthurlow uchar_t *prin; 1553*4bff34e3Sthurlow 1554*4bff34e3Sthurlow #if 0 1555*4bff34e3Sthurlow fprintf(stderr, "blob from negotiate:\n"); 1556*4bff34e3Sthurlow prblob(blob, len); 1557*4bff34e3Sthurlow #endif 1558*4bff34e3Sthurlow 1559*4bff34e3Sthurlow /* Skip the GUID */ 1560*4bff34e3Sthurlow assert(len >= SMB_GUIDLEN); 1561*4bff34e3Sthurlow blob += SMB_GUIDLEN; 1562*4bff34e3Sthurlow len -= SMB_GUIDLEN; 1563*4bff34e3Sthurlow 1564*4bff34e3Sthurlow failure = "spnegoInitFromBinary"; 1565*4bff34e3Sthurlow if ((rc = spnegoInitFromBinary(blob, len, &stok))) 1566*4bff34e3Sthurlow goto out; 1567*4bff34e3Sthurlow /* 1568*4bff34e3Sthurlow * Needn't use new Kerberos OID - the Legacy one is fine. 1569*4bff34e3Sthurlow */ 1570*4bff34e3Sthurlow failure = "spnegoIsMechTypeAvailable"; 1571*4bff34e3Sthurlow if (spnegoIsMechTypeAvailable(stok, spnego_mech_oid_Kerberos_V5_Legacy, 1572*4bff34e3Sthurlow &indx)) 1573*4bff34e3Sthurlow goto out; 1574*4bff34e3Sthurlow /* 1575*4bff34e3Sthurlow * Ignoring optional context flags for now. May want to pass 1576*4bff34e3Sthurlow * them to krb5 layer. XXX 1577*4bff34e3Sthurlow */ 1578*4bff34e3Sthurlow if (!spnegoGetContextFlags(stok, &flags)) 1579*4bff34e3Sthurlow fprintf(stderr, dgettext(TEXT_DOMAIN, 1580*4bff34e3Sthurlow "spnego context flags 0x%x\n"), flags); 1581*4bff34e3Sthurlow failure = "spnegoGetMechListMIC(NULL)"; 1582*4bff34e3Sthurlow rc = spnegoGetMechListMIC(stok, NULL, &plen); 1583*4bff34e3Sthurlow if (rc != SPNEGO_E_BUFFER_TOO_SMALL) 1584*4bff34e3Sthurlow goto out; 1585*4bff34e3Sthurlow failure = "malloc"; 1586*4bff34e3Sthurlow if (!(prin = malloc(plen + 1))) 1587*4bff34e3Sthurlow goto out; 1588*4bff34e3Sthurlow failure = "spnegoGetMechListMIC"; 1589*4bff34e3Sthurlow if ((rc = spnegoGetMechListMIC(stok, prin, &plen))) { 1590*4bff34e3Sthurlow free(prin); 1591*4bff34e3Sthurlow goto out; 1592*4bff34e3Sthurlow } 1593*4bff34e3Sthurlow prin[plen] = '\0'; 1594*4bff34e3Sthurlow *prinp = (char *)prin; 1595*4bff34e3Sthurlow failure = NULL; 1596*4bff34e3Sthurlow out:; 1597*4bff34e3Sthurlow if (stok) 1598*4bff34e3Sthurlow spnegoFreeData(stok); 1599*4bff34e3Sthurlow if (rc) { 1600*4bff34e3Sthurlow /* XXX better is to embed rc in failure */ 1601*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1602*4bff34e3Sthurlow "spnego blob2principal error %d"), 0, -rc); 1603*4bff34e3Sthurlow if (!failure) 1604*4bff34e3Sthurlow failure = "spnego"; 1605*4bff34e3Sthurlow } 1606*4bff34e3Sthurlow return (failure); 1607*4bff34e3Sthurlow } 1608*4bff34e3Sthurlow 1609*4bff34e3Sthurlow 1610*4bff34e3Sthurlow int 1611*4bff34e3Sthurlow smb_ctx_negotiate(struct smb_ctx *ctx, int level, int flags, char *workgroup) 1612*4bff34e3Sthurlow { 1613*4bff34e3Sthurlow struct smbioc_lookup rq; 1614*4bff34e3Sthurlow int error = 0; 1615*4bff34e3Sthurlow char *failure = NULL; 1616*4bff34e3Sthurlow char *principal = NULL; 1617*4bff34e3Sthurlow char c; 1618*4bff34e3Sthurlow int i; 1619*4bff34e3Sthurlow ssize_t *outtoklen; 1620*4bff34e3Sthurlow uchar_t *blob; 1621*4bff34e3Sthurlow 1622*4bff34e3Sthurlow /* 1623*4bff34e3Sthurlow * We leave ct_secblob set iff extended security 1624*4bff34e3Sthurlow * negotiation succeeds. 1625*4bff34e3Sthurlow */ 1626*4bff34e3Sthurlow if (ctx->ct_secblob) { 1627*4bff34e3Sthurlow free(ctx->ct_secblob); 1628*4bff34e3Sthurlow ctx->ct_secblob = NULL; 1629*4bff34e3Sthurlow } 1630*4bff34e3Sthurlow #ifdef XXX 1631*4bff34e3Sthurlow if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 1632*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1633*4bff34e3Sthurlow "smb_ctx_lookup() data is not resolved"), 0); 1634*4bff34e3Sthurlow return (EINVAL); 1635*4bff34e3Sthurlow } 1636*4bff34e3Sthurlow #endif 1637*4bff34e3Sthurlow if ((error = smb_ctx_gethandle(ctx))) 1638*4bff34e3Sthurlow return (error); 1639*4bff34e3Sthurlow 1640*4bff34e3Sthurlow bzero(&rq, sizeof (rq)); 1641*4bff34e3Sthurlow bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 1642*4bff34e3Sthurlow bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 1643*4bff34e3Sthurlow 1644*4bff34e3Sthurlow /* 1645*4bff34e3Sthurlow * Find out if we have a Kerberos ticket, 1646*4bff34e3Sthurlow * and only offer SPNEGO if we have one. 1647*4bff34e3Sthurlow */ 1648*4bff34e3Sthurlow failure = smb_ctx_krb5init(ctx); 1649*4bff34e3Sthurlow if (failure) { 1650*4bff34e3Sthurlow if (smb_verbose) 1651*4bff34e3Sthurlow smb_error(failure, 0); 1652*4bff34e3Sthurlow goto out; 1653*4bff34e3Sthurlow } 1654*4bff34e3Sthurlow 1655*4bff34e3Sthurlow rq.ioc_flags = flags; 1656*4bff34e3Sthurlow rq.ioc_level = level; 1657*4bff34e3Sthurlow rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC; 1658*4bff34e3Sthurlow error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq); 1659*4bff34e3Sthurlow if (error) { 1660*4bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "negotiate failed"); 1661*4bff34e3Sthurlow smb_error(failure, error); 1662*4bff34e3Sthurlow if (error == ETIMEDOUT) 1663*4bff34e3Sthurlow return (error); 1664*4bff34e3Sthurlow goto out; 1665*4bff34e3Sthurlow } 1666*4bff34e3Sthurlow /* 1667*4bff34e3Sthurlow * If the server capabilities did not include 1668*4bff34e3Sthurlow * SMB_CAP_EXT_SECURITY then the driver clears 1669*4bff34e3Sthurlow * the flag SMBVOPT_EXT_SEC for us. 1670*4bff34e3Sthurlow * XXX: should add the capabilities to ioc_ssn 1671*4bff34e3Sthurlow * XXX: see comment in driver - smb_usr.c 1672*4bff34e3Sthurlow */ 1673*4bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "SPNEGO unsupported"); 1674*4bff34e3Sthurlow if ((rq.ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC) == 0) { 1675*4bff34e3Sthurlow if (smb_verbose) 1676*4bff34e3Sthurlow smb_error(failure, 0); 1677*4bff34e3Sthurlow /* 1678*4bff34e3Sthurlow * Do regular (old style) NTLM or NTLMv2 1679*4bff34e3Sthurlow * Nothing more to do here in negotiate. 1680*4bff34e3Sthurlow */ 1681*4bff34e3Sthurlow return (0); 1682*4bff34e3Sthurlow } 1683*4bff34e3Sthurlow 1684*4bff34e3Sthurlow /* 1685*4bff34e3Sthurlow * Capabilities DO include SMB_CAP_EXT_SECURITY, 1686*4bff34e3Sthurlow * so this should be an SPNEGO security blob. 1687*4bff34e3Sthurlow * Parse the ASN.1/DER, prepare response(s). 1688*4bff34e3Sthurlow * XXX: Handle STATUS_MORE_PROCESSING_REQUIRED? 1689*4bff34e3Sthurlow * XXX: Requires additional session setup calls. 1690*4bff34e3Sthurlow */ 1691*4bff34e3Sthurlow if (rq.ioc_ssn.ioc_outtoklen <= SMB_GUIDLEN) 1692*4bff34e3Sthurlow goto out; 1693*4bff34e3Sthurlow /* some servers send padding junk */ 1694*4bff34e3Sthurlow blob = rq.ioc_ssn.ioc_outtok; 1695*4bff34e3Sthurlow if (blob[0] == 0) 1696*4bff34e3Sthurlow goto out; 1697*4bff34e3Sthurlow 1698*4bff34e3Sthurlow failure = smb_ctx_blob2principal( 1699*4bff34e3Sthurlow ctx, &rq.ioc_ssn, &principal); 1700*4bff34e3Sthurlow if (failure) 1701*4bff34e3Sthurlow goto out; 1702*4bff34e3Sthurlow failure = smb_ctx_principal2blob( 1703*4bff34e3Sthurlow ctx, &rq.ioc_ssn, principal); 1704*4bff34e3Sthurlow if (failure) 1705*4bff34e3Sthurlow goto out; 1706*4bff34e3Sthurlow 1707*4bff34e3Sthurlow /* Success! Save the blob to send next. */ 1708*4bff34e3Sthurlow ctx->ct_secblob = rq.ioc_ssn.ioc_intok; 1709*4bff34e3Sthurlow ctx->ct_secbloblen = rq.ioc_ssn.ioc_intoklen; 1710*4bff34e3Sthurlow rq.ioc_ssn.ioc_intok = NULL; 1711*4bff34e3Sthurlow 1712*4bff34e3Sthurlow out: 1713*4bff34e3Sthurlow if (principal) 1714*4bff34e3Sthurlow free(principal); 1715*4bff34e3Sthurlow if (rq.ioc_ssn.ioc_intok) 1716*4bff34e3Sthurlow free(rq.ioc_ssn.ioc_intok); 1717*4bff34e3Sthurlow if (rq.ioc_ssn.ioc_outtok) 1718*4bff34e3Sthurlow free(rq.ioc_ssn.ioc_outtok); 1719*4bff34e3Sthurlow if (!failure) 1720*4bff34e3Sthurlow return (0); /* Success! */ 1721*4bff34e3Sthurlow 1722*4bff34e3Sthurlow /* 1723*4bff34e3Sthurlow * Negotiate failed with "extended security". 1724*4bff34e3Sthurlow * 1725*4bff34e3Sthurlow * XXX: If we are doing SPNEGO correctly, 1726*4bff34e3Sthurlow * we should never get here unless the user 1727*4bff34e3Sthurlow * supplied invalid authentication data, 1728*4bff34e3Sthurlow * or we saw some kind of protocol error. 1729*4bff34e3Sthurlow * 1730*4bff34e3Sthurlow * XXX: The error message below should be 1731*4bff34e3Sthurlow * XXX: unconditional (remove "if verbose") 1732*4bff34e3Sthurlow * XXX: but not until we have "NTLMSSP" 1733*4bff34e3Sthurlow * Avoid spew for anticipated failure modes 1734*4bff34e3Sthurlow * but enable this with the verbose flag 1735*4bff34e3Sthurlow */ 1736*4bff34e3Sthurlow if (smb_verbose) { 1737*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1738*4bff34e3Sthurlow "%s (extended security negotiate)"), error, failure); 1739*4bff34e3Sthurlow } 1740*4bff34e3Sthurlow 1741*4bff34e3Sthurlow /* 1742*4bff34e3Sthurlow * XXX: Try again using NTLM (or NTLMv2) 1743*4bff34e3Sthurlow * XXX: Normal clients don't do this. 1744*4bff34e3Sthurlow * XXX: Should just return an error, but 1745*4bff34e3Sthurlow * keep the fall-back to NTLM for now. 1746*4bff34e3Sthurlow * 1747*4bff34e3Sthurlow * Start over with a new connection. 1748*4bff34e3Sthurlow */ 1749*4bff34e3Sthurlow if ((error = smb_ctx_gethandle(ctx))) 1750*4bff34e3Sthurlow return (error); 1751*4bff34e3Sthurlow bzero(&rq, sizeof (rq)); 1752*4bff34e3Sthurlow bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 1753*4bff34e3Sthurlow bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 1754*4bff34e3Sthurlow rq.ioc_flags = flags; 1755*4bff34e3Sthurlow rq.ioc_level = level; 1756*4bff34e3Sthurlow /* Note: NO SMBVOPT_EXT_SEC */ 1757*4bff34e3Sthurlow error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq); 1758*4bff34e3Sthurlow if (error) { 1759*4bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "negotiate failed"); 1760*4bff34e3Sthurlow smb_error(failure, error); 1761*4bff34e3Sthurlow rpc_cleanup_smbctx(ctx); 1762*4bff34e3Sthurlow close(ctx->ct_fd); 1763*4bff34e3Sthurlow ctx->ct_fd = -1; 1764*4bff34e3Sthurlow return (error); 1765*4bff34e3Sthurlow } 1766*4bff34e3Sthurlow 1767*4bff34e3Sthurlow /* 1768*4bff34e3Sthurlow * Used to copy the workgroup out of the SMB_NEGOTIATE response 1769*4bff34e3Sthurlow * here, to default our domain name to be the same as the server. 1770*4bff34e3Sthurlow * Not a good idea: Unnecessary at best, and sometimes wrong, i.e. 1771*4bff34e3Sthurlow * when our account is in a trusted domain. 1772*4bff34e3Sthurlow */ 1773*4bff34e3Sthurlow 1774*4bff34e3Sthurlow return (error); 1775*4bff34e3Sthurlow } 1776*4bff34e3Sthurlow 1777*4bff34e3Sthurlow 1778*4bff34e3Sthurlow int 1779*4bff34e3Sthurlow smb_ctx_tdis(struct smb_ctx *ctx) 1780*4bff34e3Sthurlow { 1781*4bff34e3Sthurlow struct smbioc_lookup rq; /* XXX may be used, someday */ 1782*4bff34e3Sthurlow int error = 0; 1783*4bff34e3Sthurlow 1784*4bff34e3Sthurlow if (ctx->ct_fd < 0) { 1785*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1786*4bff34e3Sthurlow "tree disconnect without handle?!"), 0); 1787*4bff34e3Sthurlow return (EINVAL); 1788*4bff34e3Sthurlow } 1789*4bff34e3Sthurlow if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) { 1790*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1791*4bff34e3Sthurlow "tree disconnect without session?!"), 0); 1792*4bff34e3Sthurlow return (EINVAL); 1793*4bff34e3Sthurlow } 1794*4bff34e3Sthurlow bzero(&rq, sizeof (rq)); 1795*4bff34e3Sthurlow bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 1796*4bff34e3Sthurlow bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 1797*4bff34e3Sthurlow if (ioctl(ctx->ct_fd, SMBIOC_TDIS, &rq) == -1) { 1798*4bff34e3Sthurlow error = errno; 1799*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1800*4bff34e3Sthurlow "tree disconnect failed"), error); 1801*4bff34e3Sthurlow } 1802*4bff34e3Sthurlow return (error); 1803*4bff34e3Sthurlow } 1804*4bff34e3Sthurlow 1805*4bff34e3Sthurlow 1806*4bff34e3Sthurlow int 1807*4bff34e3Sthurlow smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) 1808*4bff34e3Sthurlow { 1809*4bff34e3Sthurlow struct smbioc_lookup rq; 1810*4bff34e3Sthurlow int error = 0; 1811*4bff34e3Sthurlow char *failure = NULL; 1812*4bff34e3Sthurlow 1813*4bff34e3Sthurlow if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { 1814*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1815*4bff34e3Sthurlow "smb_ctx_lookup() data is not resolved"), 0); 1816*4bff34e3Sthurlow return (EINVAL); 1817*4bff34e3Sthurlow } 1818*4bff34e3Sthurlow if (ctx->ct_fd < 0) { 1819*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1820*4bff34e3Sthurlow "handle from smb_ctx_nego() gone?!"), 0); 1821*4bff34e3Sthurlow return (EINVAL); 1822*4bff34e3Sthurlow } 1823*4bff34e3Sthurlow if (!(flags & SMBLK_CREATE)) 1824*4bff34e3Sthurlow return (0); 1825*4bff34e3Sthurlow bzero(&rq, sizeof (rq)); 1826*4bff34e3Sthurlow bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); 1827*4bff34e3Sthurlow bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); 1828*4bff34e3Sthurlow rq.ioc_flags = flags; 1829*4bff34e3Sthurlow rq.ioc_level = level; 1830*4bff34e3Sthurlow 1831*4bff34e3Sthurlow /* 1832*4bff34e3Sthurlow * Iff we have a security blob, we're using 1833*4bff34e3Sthurlow * extended security... 1834*4bff34e3Sthurlow */ 1835*4bff34e3Sthurlow if (ctx->ct_secblob) { 1836*4bff34e3Sthurlow rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC; 1837*4bff34e3Sthurlow if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) { 1838*4bff34e3Sthurlow rq.ioc_ssn.ioc_intok = ctx->ct_secblob; 1839*4bff34e3Sthurlow rq.ioc_ssn.ioc_intoklen = ctx->ct_secbloblen; 1840*4bff34e3Sthurlow error = smb_ctx_ioctl(ctx, SMBIOC_SSNSETUP, &rq); 1841*4bff34e3Sthurlow } 1842*4bff34e3Sthurlow rq.ioc_ssn.ioc_intok = NULL; 1843*4bff34e3Sthurlow if (error) { 1844*4bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, 1845*4bff34e3Sthurlow "session setup failed"); 1846*4bff34e3Sthurlow } else { 1847*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_SSNACTIVE; 1848*4bff34e3Sthurlow if ((error = smb_ctx_ioctl(ctx, SMBIOC_TCON, &rq))) 1849*4bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, 1850*4bff34e3Sthurlow "tree connect failed"); 1851*4bff34e3Sthurlow } 1852*4bff34e3Sthurlow if (rq.ioc_ssn.ioc_intok) 1853*4bff34e3Sthurlow free(rq.ioc_ssn.ioc_intok); 1854*4bff34e3Sthurlow if (rq.ioc_ssn.ioc_outtok) 1855*4bff34e3Sthurlow free(rq.ioc_ssn.ioc_outtok); 1856*4bff34e3Sthurlow if (!failure) 1857*4bff34e3Sthurlow return (0); 1858*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1859*4bff34e3Sthurlow "%s (extended security lookup2)"), error, failure); 1860*4bff34e3Sthurlow /* unwise to failback to NTLM now */ 1861*4bff34e3Sthurlow return (error); 1862*4bff34e3Sthurlow } 1863*4bff34e3Sthurlow 1864*4bff34e3Sthurlow /* 1865*4bff34e3Sthurlow * Otherwise we're doing plain old NTLM 1866*4bff34e3Sthurlow */ 1867*4bff34e3Sthurlow seteuid(eff_uid); /* restore setuid root briefly */ 1868*4bff34e3Sthurlow if ((ctx->ct_flags & SMBCF_SSNACTIVE) == 0) { 1869*4bff34e3Sthurlow /* 1870*4bff34e3Sthurlow * This is the magic that tells the driver to 1871*4bff34e3Sthurlow * copy the password from the keychain, and 1872*4bff34e3Sthurlow * whether to use the system name or the 1873*4bff34e3Sthurlow * account domain to lookup the keychain. 1874*4bff34e3Sthurlow */ 1875*4bff34e3Sthurlow if (ctx->ct_flags & SMBCF_KCFOUND) 1876*4bff34e3Sthurlow rq.ioc_ssn.ioc_opt |= SMBVOPT_USE_KEYCHAIN; 1877*4bff34e3Sthurlow if (ctx->ct_flags & SMBCF_KCDOMAIN) 1878*4bff34e3Sthurlow rq.ioc_ssn.ioc_opt |= SMBVOPT_KC_DOMAIN; 1879*4bff34e3Sthurlow if (ioctl(ctx->ct_fd, SMBIOC_SSNSETUP, &rq) < 0) { 1880*4bff34e3Sthurlow error = errno; 1881*4bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "session setup"); 1882*4bff34e3Sthurlow goto out; 1883*4bff34e3Sthurlow } 1884*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_SSNACTIVE; 1885*4bff34e3Sthurlow } 1886*4bff34e3Sthurlow if (ioctl(ctx->ct_fd, SMBIOC_TCON, &rq) == -1) { 1887*4bff34e3Sthurlow error = errno; 1888*4bff34e3Sthurlow failure = dgettext(TEXT_DOMAIN, "tree connect"); 1889*4bff34e3Sthurlow } 1890*4bff34e3Sthurlow 1891*4bff34e3Sthurlow out: 1892*4bff34e3Sthurlow seteuid(real_uid); /* and back to real user */ 1893*4bff34e3Sthurlow if (failure) { 1894*4bff34e3Sthurlow error = errno; 1895*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1896*4bff34e3Sthurlow "%s phase failed"), error, failure); 1897*4bff34e3Sthurlow } 1898*4bff34e3Sthurlow return (error); 1899*4bff34e3Sthurlow } 1900*4bff34e3Sthurlow 1901*4bff34e3Sthurlow /* 1902*4bff34e3Sthurlow * Return the hflags2 word for an smb_ctx. 1903*4bff34e3Sthurlow */ 1904*4bff34e3Sthurlow int 1905*4bff34e3Sthurlow smb_ctx_flags2(struct smb_ctx *ctx) 1906*4bff34e3Sthurlow { 1907*4bff34e3Sthurlow uint16_t flags2; 1908*4bff34e3Sthurlow 1909*4bff34e3Sthurlow if (ioctl(ctx->ct_fd, SMBIOC_FLAGS2, &flags2) == -1) { 1910*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1911*4bff34e3Sthurlow "can't get flags2 for a session"), errno); 1912*4bff34e3Sthurlow return (-1); 1913*4bff34e3Sthurlow } 1914*4bff34e3Sthurlow printf(dgettext(TEXT_DOMAIN, "Flags2 value is %d\n"), flags2); 1915*4bff34e3Sthurlow return (flags2); 1916*4bff34e3Sthurlow } 1917*4bff34e3Sthurlow 1918*4bff34e3Sthurlow /* 1919*4bff34e3Sthurlow * level values: 1920*4bff34e3Sthurlow * 0 - default 1921*4bff34e3Sthurlow * 1 - server 1922*4bff34e3Sthurlow * 2 - server:user 1923*4bff34e3Sthurlow * 3 - server:user:share 1924*4bff34e3Sthurlow */ 1925*4bff34e3Sthurlow static int 1926*4bff34e3Sthurlow smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) 1927*4bff34e3Sthurlow { 1928*4bff34e3Sthurlow char *p; 1929*4bff34e3Sthurlow int error; 1930*4bff34e3Sthurlow 1931*4bff34e3Sthurlow #ifdef NOT_DEFINED 1932*4bff34e3Sthurlow if (level > 0) { 1933*4bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "charsets", &p); 1934*4bff34e3Sthurlow if (p) { 1935*4bff34e3Sthurlow error = smb_ctx_setcharset(ctx, p); 1936*4bff34e3Sthurlow if (error) 1937*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1938*4bff34e3Sthurlow "charset specification in the section '%s' ignored"), 1939*4bff34e3Sthurlow error, sname); 1940*4bff34e3Sthurlow } 1941*4bff34e3Sthurlow } 1942*4bff34e3Sthurlow #endif 1943*4bff34e3Sthurlow 1944*4bff34e3Sthurlow if (level <= 1) { 1945*4bff34e3Sthurlow /* Section is: [default] or [server] */ 1946*4bff34e3Sthurlow 1947*4bff34e3Sthurlow rc_getint(smb_rc, sname, "timeout", 1948*4bff34e3Sthurlow &ctx->ct_ssn.ioc_timeout); 1949*4bff34e3Sthurlow 1950*4bff34e3Sthurlow #ifdef NOT_DEFINED 1951*4bff34e3Sthurlow rc_getint(smb_rc, sname, "retry_count", 1952*4bff34e3Sthurlow &ctx->ct_ssn.ioc_retrycount); 1953*4bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "use_negprot_domain", &p); 1954*4bff34e3Sthurlow if (p && strcmp(p, "NO") == 0) 1955*4bff34e3Sthurlow ctx->ct_flags |= SMBCF_NONEGDOM; 1956*4bff34e3Sthurlow #endif 1957*4bff34e3Sthurlow 1958*4bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "minauth", &p); 1959*4bff34e3Sthurlow if (p) { 1960*4bff34e3Sthurlow /* 1961*4bff34e3Sthurlow * "minauth" was set in this section; override 1962*4bff34e3Sthurlow * the current minimum authentication setting. 1963*4bff34e3Sthurlow */ 1964*4bff34e3Sthurlow ctx->ct_ssn.ioc_opt &= ~SMBVOPT_MINAUTH; 1965*4bff34e3Sthurlow if (strcmp(p, "kerberos") == 0) { 1966*4bff34e3Sthurlow /* 1967*4bff34e3Sthurlow * Don't fall back to NTLMv2, NTLMv1, or 1968*4bff34e3Sthurlow * a clear text password. 1969*4bff34e3Sthurlow */ 1970*4bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_KERBEROS; 1971*4bff34e3Sthurlow } else if (strcmp(p, "ntlmv2") == 0) { 1972*4bff34e3Sthurlow /* 1973*4bff34e3Sthurlow * Don't fall back to NTLMv1 or a clear 1974*4bff34e3Sthurlow * text password. 1975*4bff34e3Sthurlow */ 1976*4bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLMV2; 1977*4bff34e3Sthurlow } else if (strcmp(p, "ntlm") == 0) { 1978*4bff34e3Sthurlow /* 1979*4bff34e3Sthurlow * Don't send the LM response over the wire. 1980*4bff34e3Sthurlow */ 1981*4bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLM; 1982*4bff34e3Sthurlow } else if (strcmp(p, "lm") == 0) { 1983*4bff34e3Sthurlow /* 1984*4bff34e3Sthurlow * Fail if the server doesn't do encrypted 1985*4bff34e3Sthurlow * passwords. 1986*4bff34e3Sthurlow */ 1987*4bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_LM; 1988*4bff34e3Sthurlow } else if (strcmp(p, "none") == 0) { 1989*4bff34e3Sthurlow /* 1990*4bff34e3Sthurlow * Anything goes. 1991*4bff34e3Sthurlow * (The following statement should be 1992*4bff34e3Sthurlow * optimized away.) 1993*4bff34e3Sthurlow */ 1994*4bff34e3Sthurlow /* LINTED */ 1995*4bff34e3Sthurlow ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NONE; 1996*4bff34e3Sthurlow } else { 1997*4bff34e3Sthurlow /* 1998*4bff34e3Sthurlow * Unknown minimum authentication level. 1999*4bff34e3Sthurlow */ 2000*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 2001*4bff34e3Sthurlow "invalid minimum authentication level \"%s\" specified in the section %s"), 2002*4bff34e3Sthurlow 0, p, sname); 2003*4bff34e3Sthurlow return (EINVAL); 2004*4bff34e3Sthurlow } 2005*4bff34e3Sthurlow } 2006*4bff34e3Sthurlow 2007*4bff34e3Sthurlow /* 2008*4bff34e3Sthurlow * Domain name. Allow both keywords: 2009*4bff34e3Sthurlow * "workgroup", "domain" 2010*4bff34e3Sthurlow * 2011*4bff34e3Sthurlow * Note: these are NOT marked "from CMD". 2012*4bff34e3Sthurlow * See long comment at smb_ctx_init() 2013*4bff34e3Sthurlow */ 2014*4bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "workgroup", &p); 2015*4bff34e3Sthurlow if (p) { 2016*4bff34e3Sthurlow nls_str_upper(p, p); 2017*4bff34e3Sthurlow error = smb_ctx_setworkgroup(ctx, p, 0); 2018*4bff34e3Sthurlow if (error) 2019*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 2020*4bff34e3Sthurlow "workgroup specification in the " 2021*4bff34e3Sthurlow "section '%s' ignored"), error, sname); 2022*4bff34e3Sthurlow } 2023*4bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "domain", &p); 2024*4bff34e3Sthurlow if (p) { 2025*4bff34e3Sthurlow nls_str_upper(p, p); 2026*4bff34e3Sthurlow error = smb_ctx_setworkgroup(ctx, p, 0); 2027*4bff34e3Sthurlow if (error) 2028*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 2029*4bff34e3Sthurlow "domain specification in the " 2030*4bff34e3Sthurlow "section '%s' ignored"), error, sname); 2031*4bff34e3Sthurlow } 2032*4bff34e3Sthurlow 2033*4bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "user", &p); 2034*4bff34e3Sthurlow if (p) { 2035*4bff34e3Sthurlow error = smb_ctx_setuser(ctx, p, 0); 2036*4bff34e3Sthurlow if (error) 2037*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 2038*4bff34e3Sthurlow "user specification in the " 2039*4bff34e3Sthurlow "section '%s' ignored"), error, sname); 2040*4bff34e3Sthurlow } 2041*4bff34e3Sthurlow } 2042*4bff34e3Sthurlow 2043*4bff34e3Sthurlow if (level == 1) { 2044*4bff34e3Sthurlow /* Section is: [server] */ 2045*4bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "addr", &p); 2046*4bff34e3Sthurlow if (p) { 2047*4bff34e3Sthurlow error = smb_ctx_setsrvaddr(ctx, p); 2048*4bff34e3Sthurlow if (error) { 2049*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 2050*4bff34e3Sthurlow "invalid address specified in section %s"), 2051*4bff34e3Sthurlow 0, sname); 2052*4bff34e3Sthurlow return (error); 2053*4bff34e3Sthurlow } 2054*4bff34e3Sthurlow } 2055*4bff34e3Sthurlow } 2056*4bff34e3Sthurlow 2057*4bff34e3Sthurlow rc_getstringptr(smb_rc, sname, "password", &p); 2058*4bff34e3Sthurlow if (p) { 2059*4bff34e3Sthurlow error = smb_ctx_setpassword(ctx, p, 0); 2060*4bff34e3Sthurlow if (error) 2061*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 2062*4bff34e3Sthurlow "password specification in the section '%s' ignored"), 2063*4bff34e3Sthurlow error, sname); 2064*4bff34e3Sthurlow } 2065*4bff34e3Sthurlow 2066*4bff34e3Sthurlow return (0); 2067*4bff34e3Sthurlow } 2068*4bff34e3Sthurlow 2069*4bff34e3Sthurlow /* 2070*4bff34e3Sthurlow * read rc file as follows: 2071*4bff34e3Sthurlow * 0: read [default] section 2072*4bff34e3Sthurlow * 1: override with [server] section 2073*4bff34e3Sthurlow * 2: override with [server:user] section 2074*4bff34e3Sthurlow * 3: override with [server:user:share] section 2075*4bff34e3Sthurlow * Since absence of rcfile is not fatal, silently ignore this fact. 2076*4bff34e3Sthurlow * smb_rc file should be closed by caller. 2077*4bff34e3Sthurlow */ 2078*4bff34e3Sthurlow int 2079*4bff34e3Sthurlow smb_ctx_readrc(struct smb_ctx *ctx) 2080*4bff34e3Sthurlow { 2081*4bff34e3Sthurlow char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + 2082*4bff34e3Sthurlow SMB_MAXSHARENAMELEN + 4]; 2083*4bff34e3Sthurlow 2084*4bff34e3Sthurlow if (smb_open_rcfile(ctx) != 0) 2085*4bff34e3Sthurlow goto done; 2086*4bff34e3Sthurlow 2087*4bff34e3Sthurlow /* 2088*4bff34e3Sthurlow * default parameters (level=0) 2089*4bff34e3Sthurlow */ 2090*4bff34e3Sthurlow smb_ctx_readrcsection(ctx, "default", 0); 2091*4bff34e3Sthurlow nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); 2092*4bff34e3Sthurlow 2093*4bff34e3Sthurlow /* 2094*4bff34e3Sthurlow * If we don't have a server name, we can't read any of the 2095*4bff34e3Sthurlow * [server...] sections. 2096*4bff34e3Sthurlow */ 2097*4bff34e3Sthurlow if (ctx->ct_ssn.ioc_srvname[0] == 0) 2098*4bff34e3Sthurlow goto done; 2099*4bff34e3Sthurlow 2100*4bff34e3Sthurlow /* 2101*4bff34e3Sthurlow * SERVER parameters. 2102*4bff34e3Sthurlow */ 2103*4bff34e3Sthurlow smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1); 2104*4bff34e3Sthurlow 2105*4bff34e3Sthurlow /* 2106*4bff34e3Sthurlow * If we don't have a user name, we can't read any of the 2107*4bff34e3Sthurlow * [server:user...] sections. 2108*4bff34e3Sthurlow */ 2109*4bff34e3Sthurlow if (ctx->ct_ssn.ioc_user[0] == 0) 2110*4bff34e3Sthurlow goto done; 2111*4bff34e3Sthurlow 2112*4bff34e3Sthurlow /* 2113*4bff34e3Sthurlow * SERVER:USER parameters 2114*4bff34e3Sthurlow */ 2115*4bff34e3Sthurlow snprintf(sname, sizeof (sname), "%s:%s", 2116*4bff34e3Sthurlow ctx->ct_ssn.ioc_srvname, 2117*4bff34e3Sthurlow ctx->ct_ssn.ioc_user); 2118*4bff34e3Sthurlow smb_ctx_readrcsection(ctx, sname, 2); 2119*4bff34e3Sthurlow 2120*4bff34e3Sthurlow /* 2121*4bff34e3Sthurlow * If we don't have a share name, we can't read any of the 2122*4bff34e3Sthurlow * [server:user:share] sections. 2123*4bff34e3Sthurlow */ 2124*4bff34e3Sthurlow if (ctx->ct_sh.ioc_share[0] != 0) { 2125*4bff34e3Sthurlow /* 2126*4bff34e3Sthurlow * SERVER:USER:SHARE parameters 2127*4bff34e3Sthurlow */ 2128*4bff34e3Sthurlow snprintf(sname, sizeof (sname), "%s:%s:%s", 2129*4bff34e3Sthurlow ctx->ct_ssn.ioc_srvname, 2130*4bff34e3Sthurlow ctx->ct_ssn.ioc_user, 2131*4bff34e3Sthurlow ctx->ct_sh.ioc_share); 2132*4bff34e3Sthurlow smb_ctx_readrcsection(ctx, sname, 3); 2133*4bff34e3Sthurlow } 2134*4bff34e3Sthurlow 2135*4bff34e3Sthurlow done: 2136*4bff34e3Sthurlow if (smb_debug) 2137*4bff34e3Sthurlow dump_ctx("after smb_ctx_readrc", ctx); 2138*4bff34e3Sthurlow 2139*4bff34e3Sthurlow return (0); 2140*4bff34e3Sthurlow } 2141