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 2007 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, 128 NULL, &tok); 129 if (GSS_ERROR(maj)) { 130 errmsg = ssh_gssapi_last_error(ctxt, NULL, NULL); 131 debug("Skipping GSS-API mechanism %s (%s)", 132 ssh_gssapi_oid_to_name(mech), errmsg); 133 xfree(errmsg); 134 continue; 135 } 136 137 (void) gss_release_buffer(&min, &tok); 138 139 maj = gss_add_oid_set_member(&min, mech, &supported); 140 if (GSS_ERROR(maj)) { 141 errmsg = ssh_gssapi_last_error(NULL, &maj, &min); 142 debug("Failed to allocate resources (%s) for GSS-API", 143 errmsg); 144 xfree(errmsg); 145 } 146 } 147 148 *mechs = supported; 149 } 150 151 152 /* Wrapper to init_sec_context 153 * Requires that the context contains: 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 ctx->major=gss_init_sec_context(&ctx->minor, 177 GSS_C_NO_CREDENTIAL, 178 &ctx->context, 179 ctx->desired_name, 180 ctx->desired_mech, 181 flags, 182 0, /* default lifetime */ 183 NULL, /* no channel bindings */ 184 recv_tok, 185 NULL, /* actual mech type */ 186 send_tok, 187 &ctx->flags, 188 NULL); /* actual lifetime */ 189 190 if (GSS_ERROR(ctx->major)) 191 ssh_gssapi_error(ctx, "calling GSS_Init_sec_context()"); 192 193 return(ctx->major); 194 } 195 #endif /* GSSAPI */ 196