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 */ 192