1 /*
   2  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. *
   3  * Redistribution and use in source and binary forms, with or without
   4  * modification, are permitted provided that the following conditions
   5  * are met:
   6  * 1. Redistributions of source code must retain the above copyright
   7  *    notice, this list of conditions and the following disclaimer.
   8  * 2. Redistributions in binary form must reproduce the above copyright
   9  *    notice, this list of conditions and the following disclaimer in the
  10  *    documentation and/or other materials provided with the distribution.
  11  *
  12  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
  13  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  14  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  15  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  16  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  17  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  18  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  19  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  21  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22  */
  23 /*
  24  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 #include "includes.h"
  29 
  30 #ifdef GSSAPI
  31 
  32 #pragma ident   "%Z%%M% %I%     %E% SMI"
  33 
  34 #include "ssh.h"
  35 #include "ssh2.h"
  36 #include "xmalloc.h"
  37 #include "buffer.h"
  38 #include "bufaux.h"
  39 #include "packet.h"
  40 #include "compat.h"
  41 #include <openssl/evp.h>
  42 #include "cipher.h"
  43 #include "kex.h"
  44 #include "log.h"
  45 #include "compat.h"
  46 
  47 #include <netdb.h>
  48 
  49 #include "ssh-gss.h"
  50 
  51 void
  52 ssh_gssapi_client_kex_hook(Kex *kex, char **proposal)
  53 {
  54         gss_OID_set mechs = GSS_C_NULL_OID_SET;
  55 
  56         if (kex == NULL || kex->serverhost == NULL)
  57                 fatal("INTERNAL ERROR (%s)", __func__);
  58 
  59         ssh_gssapi_client_mechs(kex->serverhost, &mechs);
  60         ssh_gssapi_modify_kex(kex, mechs, proposal);
  61 }
  62 
  63 void
  64 ssh_gssapi_client_mechs(const char *server_host, gss_OID_set *mechs)
  65 {
  66         gss_OID_set     indicated = GSS_C_NULL_OID_SET;
  67         gss_OID_set     acquired, supported;
  68         gss_OID         mech;
  69         gss_cred_id_t   creds;
  70         Gssctxt         *ctxt = NULL;
  71         gss_buffer_desc tok;
  72         OM_uint32       maj, min;
  73         int             i;
  74         char            *errmsg;
  75 
  76         if (!mechs)
  77                 return;
  78         *mechs = GSS_C_NULL_OID_SET;
  79 
  80         maj = gss_indicate_mechs(&min, &indicated);
  81         if (GSS_ERROR(maj)) {
  82                 debug("No GSS-API mechanisms are installed");
  83                 return;
  84         }
  85 
  86         maj = gss_create_empty_oid_set(&min, &supported);
  87         if (GSS_ERROR(maj)) {
  88                 errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
  89                 debug("Failed to allocate resources (%s) for GSS-API", errmsg);
  90                 xfree(errmsg);
  91                 (void) gss_release_oid_set(&min, &indicated);
  92                 return;
  93         }
  94         maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated,
  95             GSS_C_INITIATE, &creds, &acquired, NULL);
  96 
  97         if (GSS_ERROR(maj)) {
  98                 errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
  99                 debug("Failed to acquire GSS-API credentials for any "
 100                     "mechanisms (%s)", errmsg);
 101                 xfree(errmsg);
 102                 (void) gss_release_oid_set(&min, &indicated);
 103                 (void) gss_release_oid_set(&min, &supported);
 104                 return;
 105         }
 106         (void) gss_release_cred(&min, &creds);
 107 
 108         for (i = 0; i < acquired->count; i++) {
 109                 mech = &acquired->elements[i];
 110 
 111                 if (ssh_gssapi_is_spnego(mech))
 112                         continue;
 113 
 114                 ssh_gssapi_build_ctx(&ctxt, 1, mech);
 115                 if (!ctxt)
 116                         continue;
 117 
 118                 /*
 119                  * This is useful for mechs like Kerberos, which can
 120                  * detect unknown target princs here, but not for
 121                  * mechs like SPKM, which cannot detect unknown princs
 122                  * until context tokens are actually exchanged.
 123                  *
 124                  * 'Twould be useful to have a test that could save us
 125                  * the bother of trying this for SPKM and the such...
 126                  */
 127                 maj = ssh_gssapi_init_ctx(ctxt, server_host, 0, NULL, &tok);
 128                 if (GSS_ERROR(maj)) {
 129                         errmsg = ssh_gssapi_last_error(ctxt, NULL, NULL);
 130                         debug("Skipping GSS-API mechanism %s (%s)",
 131                             ssh_gssapi_oid_to_name(mech), errmsg);
 132                         xfree(errmsg);
 133                         continue;
 134                 }
 135 
 136                 (void) gss_release_buffer(&min, &tok);
 137 
 138                 maj = gss_add_oid_set_member(&min, mech, &supported);
 139                 if (GSS_ERROR(maj)) {
 140                         errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
 141                         debug("Failed to allocate resources (%s) for GSS-API",
 142                             errmsg);
 143                         xfree(errmsg);
 144                 }
 145         }
 146 
 147         *mechs = supported;
 148 }
 149 
 150 
 151 /*
 152  * Wrapper to init_sec_context. Requires that the context contains:
 153  *
 154  *      oid
 155  *      server name (from ssh_gssapi_import_name)
 156  */
 157 OM_uint32
 158 ssh_gssapi_init_ctx(Gssctxt *ctx, const char *server_host, int deleg_creds,
 159                     gss_buffer_t recv_tok, gss_buffer_t send_tok)
 160 {
 161         int flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
 162 
 163         debug("%s(%p, %s, %d, %p, %p)", __func__, ctx, server_host,
 164             deleg_creds, recv_tok, send_tok);
 165 
 166         if (deleg_creds) {
 167                 flags |= GSS_C_DELEG_FLAG;
 168                 debug("Delegating GSS-API credentials");
 169         }
 170 
 171         /* Build target principal */
 172         if (ctx->desired_name == GSS_C_NO_NAME &&
 173             !ssh_gssapi_import_name(ctx, server_host)) {
 174                 return (ctx->major);
 175         }
 176 
 177         ctx->major = gss_init_sec_context(&ctx->minor, GSS_C_NO_CREDENTIAL,
 178             &ctx->context, ctx->desired_name, ctx->desired_mech, flags,
 179             0, /* default lifetime */
 180             NULL, /* no channel bindings */
 181             recv_tok,
 182             NULL, /* actual mech type */
 183             send_tok, &ctx->flags,
 184             NULL); /* actual lifetime */
 185 
 186         if (GSS_ERROR(ctx->major))
 187                 ssh_gssapi_error(ctx, "calling GSS_Init_sec_context()");
 188 
 189         return (ctx->major);
 190 }
 191 #endif /* GSSAPI */