1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 5*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 6*0Sstevel@tonic-gate * are met: 7*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 8*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 9*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 10*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 11*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 14*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16*0Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17*0Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19*0Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20*0Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21*0Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22*0Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23*0Sstevel@tonic-gate */ 24*0Sstevel@tonic-gate /* 25*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 26*0Sstevel@tonic-gate * Use is subject to license terms. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include "includes.h" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #ifdef GSSAPI 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include "includes.h" 36*0Sstevel@tonic-gate #include "ssh.h" 37*0Sstevel@tonic-gate #include "ssh2.h" 38*0Sstevel@tonic-gate #include "xmalloc.h" 39*0Sstevel@tonic-gate #include "buffer.h" 40*0Sstevel@tonic-gate #include "bufaux.h" 41*0Sstevel@tonic-gate #include "packet.h" 42*0Sstevel@tonic-gate #include "compat.h" 43*0Sstevel@tonic-gate #include <openssl/evp.h> 44*0Sstevel@tonic-gate #include "cipher.h" 45*0Sstevel@tonic-gate #include "kex.h" 46*0Sstevel@tonic-gate #include "auth.h" 47*0Sstevel@tonic-gate #include "log.h" 48*0Sstevel@tonic-gate #include "channels.h" 49*0Sstevel@tonic-gate #include "session.h" 50*0Sstevel@tonic-gate #include "dispatch.h" 51*0Sstevel@tonic-gate #include "servconf.h" 52*0Sstevel@tonic-gate #include "uidswap.h" 53*0Sstevel@tonic-gate #include "compat.h" 54*0Sstevel@tonic-gate #include "monitor_wrap.h" 55*0Sstevel@tonic-gate #include <pwd.h> 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate #include "ssh-gss.h" 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate extern char **environ; 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate extern ServerOptions options; 62*0Sstevel@tonic-gate extern u_char *session_id2; 63*0Sstevel@tonic-gate extern int session_id2_len; 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate Gssctxt *xxx_gssctxt; 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate void 68*0Sstevel@tonic-gate ssh_gssapi_server_kex_hook(Kex *kex, char **proposal) 69*0Sstevel@tonic-gate { 70*0Sstevel@tonic-gate gss_OID_set mechs = GSS_C_NULL_OID_SET; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate if (kex == NULL || !kex->server) 73*0Sstevel@tonic-gate fatal("INTERNAL ERROR (%s)", __func__); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate ssh_gssapi_server_mechs(&mechs); 76*0Sstevel@tonic-gate ssh_gssapi_modify_kex(kex, mechs, proposal); 77*0Sstevel@tonic-gate } 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate void 80*0Sstevel@tonic-gate ssh_gssapi_server_mechs(gss_OID_set *mechs) 81*0Sstevel@tonic-gate { 82*0Sstevel@tonic-gate static gss_OID_set supported = GSS_C_NULL_OID_SET; 83*0Sstevel@tonic-gate gss_OID_set s, acquired, indicated = GSS_C_NULL_OID_SET; 84*0Sstevel@tonic-gate gss_cred_id_t creds; 85*0Sstevel@tonic-gate OM_uint32 maj, min; 86*0Sstevel@tonic-gate int i; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate if (!mechs) { 89*0Sstevel@tonic-gate (void) gss_release_oid_set(&min, &supported); 90*0Sstevel@tonic-gate return; 91*0Sstevel@tonic-gate } 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate if (supported != GSS_C_NULL_OID_SET) { 94*0Sstevel@tonic-gate *mechs = supported; 95*0Sstevel@tonic-gate return; 96*0Sstevel@tonic-gate } 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate *mechs = GSS_C_NULL_OID_SET; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate maj = gss_create_empty_oid_set(&min, &s); 101*0Sstevel@tonic-gate if (GSS_ERROR(maj)) { 102*0Sstevel@tonic-gate debug("Could not allocate GSS-API resources (%s)", 103*0Sstevel@tonic-gate ssh_gssapi_last_error(NULL, &maj, &min)); 104*0Sstevel@tonic-gate return; 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate maj = gss_indicate_mechs(&min, &indicated); 108*0Sstevel@tonic-gate if (GSS_ERROR(maj)) { 109*0Sstevel@tonic-gate debug("No GSS-API mechanisms are installed"); 110*0Sstevel@tonic-gate return; 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated, 114*0Sstevel@tonic-gate GSS_C_ACCEPT, &creds, &acquired, NULL); 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate if (GSS_ERROR(maj)) 117*0Sstevel@tonic-gate debug("Failed to acquire GSS-API credentials for any " 118*0Sstevel@tonic-gate "mechanisms (%s)", 119*0Sstevel@tonic-gate ssh_gssapi_last_error(NULL, &maj, &min)); 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate (void) gss_release_oid_set(&min, &indicated); 122*0Sstevel@tonic-gate (void) gss_release_cred(&min, &creds); 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate if (acquired == GSS_C_NULL_OID_SET || acquired->count == 0) 125*0Sstevel@tonic-gate return; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate for (i = 0 ; i < acquired->count ; i++ ) { 128*0Sstevel@tonic-gate if (ssh_gssapi_is_spnego(&acquired->elements[i])) 129*0Sstevel@tonic-gate continue; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate maj = gss_add_oid_set_member(&min, &acquired->elements[i], &s); 132*0Sstevel@tonic-gate if (GSS_ERROR(maj)) { 133*0Sstevel@tonic-gate debug("Could not allocate GSS-API resources (%s)", 134*0Sstevel@tonic-gate ssh_gssapi_last_error(NULL, &maj, &min)); 135*0Sstevel@tonic-gate return; 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate (void) gss_release_oid_set(&min, &acquired); 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate if (s->count) { 141*0Sstevel@tonic-gate supported = s; 142*0Sstevel@tonic-gate *mechs = s; 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* Wrapper around accept_sec_context 147*0Sstevel@tonic-gate * Requires that the context contains: 148*0Sstevel@tonic-gate * oid 149*0Sstevel@tonic-gate * credentials (from ssh_gssapi_acquire_cred) 150*0Sstevel@tonic-gate */ 151*0Sstevel@tonic-gate /* Priviledged */ 152*0Sstevel@tonic-gate OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_t recv_tok, 153*0Sstevel@tonic-gate gss_buffer_t send_tok) 154*0Sstevel@tonic-gate { 155*0Sstevel@tonic-gate /* 156*0Sstevel@tonic-gate * Acquiring a cred for the ctx->desired_mech for GSS_C_NO_NAME 157*0Sstevel@tonic-gate * may well be probably better than using GSS_C_NO_CREDENTIAL 158*0Sstevel@tonic-gate * and then checking that ctx->desired_mech agrees with 159*0Sstevel@tonic-gate * ctx->actual_mech... 160*0Sstevel@tonic-gate */ 161*0Sstevel@tonic-gate ctx->major=gss_accept_sec_context(&ctx->minor, 162*0Sstevel@tonic-gate &ctx->context, 163*0Sstevel@tonic-gate GSS_C_NO_CREDENTIAL, 164*0Sstevel@tonic-gate recv_tok, 165*0Sstevel@tonic-gate GSS_C_NO_CHANNEL_BINDINGS, 166*0Sstevel@tonic-gate &ctx->src_name, 167*0Sstevel@tonic-gate &ctx->actual_mech, 168*0Sstevel@tonic-gate send_tok, 169*0Sstevel@tonic-gate &ctx->flags, 170*0Sstevel@tonic-gate NULL, 171*0Sstevel@tonic-gate &ctx->deleg_creds); 172*0Sstevel@tonic-gate if (GSS_ERROR(ctx->major)) 173*0Sstevel@tonic-gate ssh_gssapi_error(ctx, "accepting security context"); 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate if (ctx->major == GSS_S_CONTINUE_NEEDED && send_tok->length == 0) 176*0Sstevel@tonic-gate fatal("Zero length GSS context token output when continue needed"); 177*0Sstevel@tonic-gate else if (GSS_ERROR(ctx->major) && send_tok->length == 0) 178*0Sstevel@tonic-gate debug2("Zero length GSS context error token output"); 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate if (ctx->major == GSS_S_COMPLETE && 181*0Sstevel@tonic-gate ctx->desired_mech != GSS_C_NULL_OID && 182*0Sstevel@tonic-gate (ctx->desired_mech->length != ctx->actual_mech->length || 183*0Sstevel@tonic-gate memcmp(ctx->desired_mech->elements, 184*0Sstevel@tonic-gate ctx->actual_mech->elements, 185*0Sstevel@tonic-gate ctx->desired_mech->length) != 0)) { 186*0Sstevel@tonic-gate gss_OID_set supported; 187*0Sstevel@tonic-gate OM_uint32 min; 188*0Sstevel@tonic-gate int present = 0; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate debug("The client did not use the GSS-API mechanism it asked for"); 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate /* Let it slide as long as the mech is supported */ 193*0Sstevel@tonic-gate ssh_gssapi_server_mechs(&supported); 194*0Sstevel@tonic-gate if (supported != GSS_C_NULL_OID_SET) 195*0Sstevel@tonic-gate (void) gss_test_oid_set_member(&min, 196*0Sstevel@tonic-gate ctx->actual_mech, 197*0Sstevel@tonic-gate supported, &present); 198*0Sstevel@tonic-gate if (!present) 199*0Sstevel@tonic-gate ctx->major = GSS_S_BAD_MECH; 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate if (ctx->deleg_creds) 203*0Sstevel@tonic-gate debug("Received delegated GSS credentials"); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate if (ctx->major == GSS_S_COMPLETE) { 206*0Sstevel@tonic-gate ctx->major = gss_inquire_context(&ctx->minor, ctx->context, 207*0Sstevel@tonic-gate NULL, &ctx->dst_name, NULL, NULL, 208*0Sstevel@tonic-gate NULL, NULL, &ctx->established); 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate if (GSS_ERROR(ctx->major)) { 211*0Sstevel@tonic-gate ssh_gssapi_error(ctx, "inquiring established sec context"); 212*0Sstevel@tonic-gate return (ctx->major); 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate xxx_gssctxt = ctx; 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate return (ctx->major); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate /* As user - called through fatal cleanup hook */ 223*0Sstevel@tonic-gate void 224*0Sstevel@tonic-gate ssh_gssapi_cleanup_creds(Gssctxt *ctx) 225*0Sstevel@tonic-gate { 226*0Sstevel@tonic-gate #ifdef HAVE_GSS_STORE_CRED 227*0Sstevel@tonic-gate /* pam_setcred() will take care of this */ 228*0Sstevel@tonic-gate return; 229*0Sstevel@tonic-gate #else 230*0Sstevel@tonic-gate return; 231*0Sstevel@tonic-gate /*#error "Portability broken in cleanup of stored creds"*/ 232*0Sstevel@tonic-gate #endif /* HAVE_GSS_STORE_CRED */ 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate void 236*0Sstevel@tonic-gate ssh_gssapi_storecreds(Gssctxt *ctx, Authctxt *authctxt) 237*0Sstevel@tonic-gate { 238*0Sstevel@tonic-gate #ifdef USE_PAM 239*0Sstevel@tonic-gate char **penv, **tmp_env; 240*0Sstevel@tonic-gate #endif /* USE_PAM */ 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate if (authctxt == NULL) { 243*0Sstevel@tonic-gate error("Missing context while storing GSS-API credentials"); 244*0Sstevel@tonic-gate return; 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate if (ctx == NULL && xxx_gssctxt == NULL) 248*0Sstevel@tonic-gate return; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if (ctx == NULL) 251*0Sstevel@tonic-gate ctx = xxx_gssctxt; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate if (!options.gss_cleanup_creds || 254*0Sstevel@tonic-gate ctx->deleg_creds == GSS_C_NO_CREDENTIAL) { 255*0Sstevel@tonic-gate debug3("Not storing delegated GSS credentials" 256*0Sstevel@tonic-gate " (none delegated)"); 257*0Sstevel@tonic-gate return; 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate if (!authctxt->valid || authctxt->pw == NULL) { 261*0Sstevel@tonic-gate debug3("Not storing delegated GSS credentials" 262*0Sstevel@tonic-gate " for invalid user"); 263*0Sstevel@tonic-gate return; 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate debug("Storing delegated GSS-API credentials"); 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate /* 269*0Sstevel@tonic-gate * The GSS-API has a flaw in that it does not provide a 270*0Sstevel@tonic-gate * mechanism by which delegated credentials can be made 271*0Sstevel@tonic-gate * available for acquisition by GSS_Acquire_cred() et. al.; 272*0Sstevel@tonic-gate * gss_store_cred() is the proposed GSS-API extension for 273*0Sstevel@tonic-gate * generically storing delegated credentials. 274*0Sstevel@tonic-gate * 275*0Sstevel@tonic-gate * gss_store_cred() does not speak to how credential stores are 276*0Sstevel@tonic-gate * referenced. Generically this may be done by switching to the 277*0Sstevel@tonic-gate * user context of the user in whose default credential store we 278*0Sstevel@tonic-gate * wish to place delegated credentials. But environment 279*0Sstevel@tonic-gate * variables could conceivably affect the choice of credential 280*0Sstevel@tonic-gate * store as well, and perhaps in a mechanism-specific manner. 281*0Sstevel@tonic-gate * 282*0Sstevel@tonic-gate * SUNW -- On Solaris the euid selects the current credential 283*0Sstevel@tonic-gate * store, but PAM modules could select alternate stores by 284*0Sstevel@tonic-gate * setting, for example, KRB5CCNAME, so we also use the PAM 285*0Sstevel@tonic-gate * environment temporarily. 286*0Sstevel@tonic-gate */ 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate #ifdef HAVE_GSS_STORE_CRED 289*0Sstevel@tonic-gate #ifdef USE_PAM 290*0Sstevel@tonic-gate /* 291*0Sstevel@tonic-gate * PAM may have set mechanism-specific variables (e.g., 292*0Sstevel@tonic-gate * KRB5CCNAME). fetch_pam_environment() protects against LD_* 293*0Sstevel@tonic-gate * and other environment variables. 294*0Sstevel@tonic-gate */ 295*0Sstevel@tonic-gate penv = fetch_pam_environment(authctxt); 296*0Sstevel@tonic-gate tmp_env = environ; 297*0Sstevel@tonic-gate environ = penv; 298*0Sstevel@tonic-gate #endif /* USE_PAM */ 299*0Sstevel@tonic-gate if (authctxt->pw->pw_uid != geteuid()) { 300*0Sstevel@tonic-gate temporarily_use_uid(authctxt->pw); 301*0Sstevel@tonic-gate ctx->major = gss_store_cred(&ctx->minor, ctx->deleg_creds, 302*0Sstevel@tonic-gate GSS_C_INITIATE, GSS_C_NULL_OID, 0, 303*0Sstevel@tonic-gate ctx->default_creds, NULL, NULL); 304*0Sstevel@tonic-gate restore_uid(); 305*0Sstevel@tonic-gate } else { 306*0Sstevel@tonic-gate /* only when logging in as the privileged user used by sshd */ 307*0Sstevel@tonic-gate ctx->major = gss_store_cred(&ctx->minor, ctx->deleg_creds, 308*0Sstevel@tonic-gate GSS_C_INITIATE, GSS_C_NULL_OID, 0, 309*0Sstevel@tonic-gate ctx->default_creds, NULL, NULL); 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate #ifdef USE_PAM 312*0Sstevel@tonic-gate environ = tmp_env; 313*0Sstevel@tonic-gate free_pam_environment(penv); 314*0Sstevel@tonic-gate #endif /* USE_PAM */ 315*0Sstevel@tonic-gate if (GSS_ERROR(ctx->major)) 316*0Sstevel@tonic-gate ssh_gssapi_error(ctx, "storing delegated credentials"); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate #else 319*0Sstevel@tonic-gate #ifdef KRB5_GSS 320*0Sstevel@tonic-gate #error "MIT/Heimdal krb5-specific code missing in ssh_gssapi_storecreds()" 321*0Sstevel@tonic-gate if (ssh_gssapi_is_krb5(ctx->mech)) 322*0Sstevel@tonic-gate ssh_gssapi_krb5_storecreds(ctx); 323*0Sstevel@tonic-gate #endif /* KRB5_GSS */ 324*0Sstevel@tonic-gate #ifdef GSI_GSS 325*0Sstevel@tonic-gate #error "GSI krb5-specific code missing in ssh_gssapi_storecreds()" 326*0Sstevel@tonic-gate if (ssh_gssapi_is_gsi(ctx->mech)) 327*0Sstevel@tonic-gate ssh_gssapi_krb5_storecreds(ctx); 328*0Sstevel@tonic-gate #endif /* GSI_GSS */ 329*0Sstevel@tonic-gate /*#error "Mechanism-specific code missing in ssh_gssapi_storecreds()"*/ 330*0Sstevel@tonic-gate return; 331*0Sstevel@tonic-gate #endif /* HAVE_GSS_STORE_CRED */ 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate void 335*0Sstevel@tonic-gate ssh_gssapi_do_child(Gssctxt *ctx, char ***envp, u_int *envsizep) 336*0Sstevel@tonic-gate { 337*0Sstevel@tonic-gate /* 338*0Sstevel@tonic-gate * MIT/Heimdal/GSI specific code goes here. 339*0Sstevel@tonic-gate * 340*0Sstevel@tonic-gate * On Solaris there's nothing to do here as the GSS store and 341*0Sstevel@tonic-gate * related environment variables are to be set by PAM, if at all 342*0Sstevel@tonic-gate * (no environment variables are needed to address the default 343*0Sstevel@tonic-gate * credential store -- the euid does that). 344*0Sstevel@tonic-gate */ 345*0Sstevel@tonic-gate #ifdef KRB5_GSS 346*0Sstevel@tonic-gate #error "MIT/Heimdal krb5-specific code missing in ssh_gssapi_storecreds()" 347*0Sstevel@tonic-gate #endif /* KRB5_GSS */ 348*0Sstevel@tonic-gate #ifdef GSI_GSS 349*0Sstevel@tonic-gate #error "GSI krb5-specific code missing in ssh_gssapi_storecreds()" 350*0Sstevel@tonic-gate #endif /* GSI_GSS */ 351*0Sstevel@tonic-gate return; 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate int 355*0Sstevel@tonic-gate ssh_gssapi_userok(Gssctxt *ctx, char *user) 356*0Sstevel@tonic-gate { 357*0Sstevel@tonic-gate if (ctx == NULL) { 358*0Sstevel@tonic-gate debug3("INTERNAL ERROR: %s", __func__); 359*0Sstevel@tonic-gate return (0); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate if (user == NULL || *user == '\0') 363*0Sstevel@tonic-gate return (0); 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate #ifdef HAVE___GSS_USEROK 366*0Sstevel@tonic-gate { 367*0Sstevel@tonic-gate int user_ok = 0; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate ctx->major = __gss_userok(&ctx->minor, ctx->src_name, user, 370*0Sstevel@tonic-gate &user_ok); 371*0Sstevel@tonic-gate if (GSS_ERROR(ctx->major)) { 372*0Sstevel@tonic-gate debug2("__GSS_userok() failed"); 373*0Sstevel@tonic-gate return (0); 374*0Sstevel@tonic-gate } 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate if (user_ok) 377*0Sstevel@tonic-gate return (1); 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate /* fall through */ 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate #else 382*0Sstevel@tonic-gate #ifdef GSSAPI_SIMPLE_USEROK 383*0Sstevel@tonic-gate { 384*0Sstevel@tonic-gate /* Mechanism-generic */ 385*0Sstevel@tonic-gate OM_uint32 min; 386*0Sstevel@tonic-gate gss_buffer_desc buf, ename1, ename2; 387*0Sstevel@tonic-gate gss_name_t iname, cname; 388*0Sstevel@tonic-gate int eql; 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate buf.value = user; 391*0Sstevel@tonic-gate buf.length = strlen(user); 392*0Sstevel@tonic-gate ctx->major = gss_import_name(&ctx->minor, &buf, 393*0Sstevel@tonic-gate GSS_C_NULL_OID, &iname); 394*0Sstevel@tonic-gate if (GSS_ERROR(ctx->major)) { 395*0Sstevel@tonic-gate ssh_gssapi_error(ctx, 396*0Sstevel@tonic-gate "importing name for authorizing initiator"); 397*0Sstevel@tonic-gate goto failed_simple_userok; 398*0Sstevel@tonic-gate } 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate ctx->major = gss_canonicalize_name(&ctx->minor, iname, 401*0Sstevel@tonic-gate ctx->actual_mech, &cname); 402*0Sstevel@tonic-gate (void) gss_release_name(&min, &iname); 403*0Sstevel@tonic-gate if (GSS_ERROR(ctx->major)) { 404*0Sstevel@tonic-gate ssh_gssapi_error(ctx, "canonicalizing name"); 405*0Sstevel@tonic-gate goto failed_simple_userok; 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate ctx->major = gss_export_name(&ctx->minor, cname, &ename1); 409*0Sstevel@tonic-gate (void) gss_release_name(&min, &cname); 410*0Sstevel@tonic-gate if (GSS_ERROR(ctx->major)) { 411*0Sstevel@tonic-gate ssh_gssapi_error(ctx, "exporting name"); 412*0Sstevel@tonic-gate goto failed_simple_userok; 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate ctx->major = gss_export_name(&ctx->minor, ctx->src_name, 416*0Sstevel@tonic-gate &ename2); 417*0Sstevel@tonic-gate if (GSS_ERROR(ctx->major)) { 418*0Sstevel@tonic-gate ssh_gssapi_error(ctx, 419*0Sstevel@tonic-gate "exporting client principal name"); 420*0Sstevel@tonic-gate (void) gss_release_buffer(&min, &ename1); 421*0Sstevel@tonic-gate goto failed_simple_userok; 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate eql = (ename1.length == ename2.length && 425*0Sstevel@tonic-gate memcmp(ename1.value, ename2.value, ename1.length) == 0); 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate (void) gss_release_buffer(&min, &ename1); 428*0Sstevel@tonic-gate (void) gss_release_buffer(&min, &ename2); 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate if (eql) 431*0Sstevel@tonic-gate return (1); 432*0Sstevel@tonic-gate /* fall through */ 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate failed_simple_userok: 435*0Sstevel@tonic-gate #endif /* GSSAPI_SIMPLE_USEROK */ 436*0Sstevel@tonic-gate #ifdef HAVE_GSSCRED_API 437*0Sstevel@tonic-gate { 438*0Sstevel@tonic-gate /* Mechanism-generic, Solaris-specific */ 439*0Sstevel@tonic-gate OM_uint32 maj; 440*0Sstevel@tonic-gate uid_t uid; 441*0Sstevel@tonic-gate struct passwd *pw; 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate maj = gsscred_name_to_unix_cred(ctx->src_name, 444*0Sstevel@tonic-gate ctx->actual_mech, &uid, NULL, NULL, NULL); 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate if (GSS_ERROR(maj)) 447*0Sstevel@tonic-gate goto failed_simple_gsscred_userok; 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate if ((pw = getpwnam(user)) == NULL) 450*0Sstevel@tonic-gate goto failed_simple_gsscred_userok; 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate if (pw->pw_uid == uid) 453*0Sstevel@tonic-gate return (1); 454*0Sstevel@tonic-gate /* fall through */ 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate failed_simple_gsscred_userok: 457*0Sstevel@tonic-gate #endif /* HAVE_GSSCRED_API */ 458*0Sstevel@tonic-gate #ifdef KRB5_GSS 459*0Sstevel@tonic-gate if (ssh_gssapi_is_krb5(ctx->mech)) 460*0Sstevel@tonic-gate if (ssh_gssapi_krb5_userok(ctx->src_name, user)) 461*0Sstevel@tonic-gate return (1); 462*0Sstevel@tonic-gate #endif /* KRB5_GSS */ 463*0Sstevel@tonic-gate #ifdef GSI_GSS 464*0Sstevel@tonic-gate if (ssh_gssapi_is_gsi(ctx->mech)) 465*0Sstevel@tonic-gate if (ssh_gssapi_gsi_userok(ctx->src_name, user)) 466*0Sstevel@tonic-gate return (1); 467*0Sstevel@tonic-gate #endif /* GSI_GSS */ 468*0Sstevel@tonic-gate #endif /* HAVE___GSS_USEROK */ 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate /* default to not authorized */ 471*0Sstevel@tonic-gate return (0); 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate char * 475*0Sstevel@tonic-gate ssh_gssapi_localname(Gssctxt *ctx) 476*0Sstevel@tonic-gate { 477*0Sstevel@tonic-gate if (ctx == NULL) { 478*0Sstevel@tonic-gate debug3("INTERNAL ERROR: %s", __func__); 479*0Sstevel@tonic-gate return (NULL); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate debug2("Mapping initiator GSS-API principal to local username"); 483*0Sstevel@tonic-gate #ifdef HAVE_GSSCRED_API 484*0Sstevel@tonic-gate { 485*0Sstevel@tonic-gate /* Mechanism-generic, Solaris-specific */ 486*0Sstevel@tonic-gate OM_uint32 maj; 487*0Sstevel@tonic-gate uid_t uid; 488*0Sstevel@tonic-gate struct passwd *pw; 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate if (ctx->src_name == GSS_C_NO_NAME) 491*0Sstevel@tonic-gate goto failed_gsscred_localname; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate maj = gsscred_name_to_unix_cred(ctx->src_name, 494*0Sstevel@tonic-gate ctx->actual_mech, &uid, NULL, NULL, NULL); 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate if (GSS_ERROR(maj)) 497*0Sstevel@tonic-gate goto failed_gsscred_localname; 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate if ((pw = getpwuid(uid)) == NULL) 500*0Sstevel@tonic-gate goto failed_gsscred_localname; 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate debug2("Mapped the initiator to: %s", pw->pw_name); 503*0Sstevel@tonic-gate return (xstrdup(pw->pw_name)); 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate failed_gsscred_localname: 506*0Sstevel@tonic-gate #endif /* HAVE_GSSCRED_API */ 507*0Sstevel@tonic-gate #ifdef KRB5_GSS 508*0Sstevel@tonic-gate #error "ssh_gssapi_krb5_localname() not implemented" 509*0Sstevel@tonic-gate if (ssh_gssapi_is_krb5(ctx->mech)) 510*0Sstevel@tonic-gate return (ssh_gssapi_krb5_localname(ctx->src_name)); 511*0Sstevel@tonic-gate #endif /* KRB5_GSS */ 512*0Sstevel@tonic-gate #ifdef GSI_GSS 513*0Sstevel@tonic-gate #error "ssh_gssapi_gsi_localname() not implemented" 514*0Sstevel@tonic-gate if (ssh_gssapi_is_gsi(ctx->mech)) 515*0Sstevel@tonic-gate return (ssh_gssapi_gsi_localname(ctx->src_name)); 516*0Sstevel@tonic-gate #endif /* GSI_GSS */ 517*0Sstevel@tonic-gate return (NULL); 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate #endif /*GSSAPI */ 520