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 2004 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 #include "monitor_wrap.h" 47 48 #include <netdb.h> 49 50 #include "ssh-gss.h" 51 52 void 53 ssh_gssapi_client_kex_hook(Kex *kex, char **proposal) 54 { 55 gss_OID_set mechs = GSS_C_NULL_OID_SET; 56 57 if (kex == NULL || kex->serverhost == NULL) 58 fatal("INTERNAL ERROR (%s)", __func__); 59 60 ssh_gssapi_client_mechs(kex->serverhost, &mechs); 61 ssh_gssapi_modify_kex(kex, mechs, proposal); 62 } 63 64 void 65 ssh_gssapi_client_mechs(const char *server_host, gss_OID_set *mechs) 66 { 67 gss_OID_set indicated = GSS_C_NULL_OID_SET; 68 gss_OID_set acquired, supported; 69 gss_OID mech; 70 gss_cred_id_t creds; 71 Gssctxt *ctxt = NULL; 72 gss_buffer_desc tok; 73 OM_uint32 maj, min; 74 int i; 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 debug("Failed to allocate resources (%s) for GSS-API", 89 ssh_gssapi_last_error(NULL, &maj, &min)); 90 (void) gss_release_oid_set(&min, &indicated); 91 return; 92 } 93 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated, 94 GSS_C_INITIATE, &creds, &acquired, NULL); 95 96 if (GSS_ERROR(maj)) { 97 debug("Failed to acquire GSS-API credentials for any " 98 "mechanisms (%s)", 99 ssh_gssapi_last_error(NULL, &maj, &min)); 100 (void) gss_release_oid_set(&min, &indicated); 101 (void) gss_release_oid_set(&min, &supported); 102 return; 103 } 104 (void) gss_release_cred(&min, &creds); 105 106 for (i = 0 ; i < acquired->count ; i++) { 107 mech = &acquired->elements[i]; 108 109 if (ssh_gssapi_is_spnego(mech)) 110 continue; 111 112 ssh_gssapi_build_ctx(&ctxt, 1, mech); 113 if (!ctxt) 114 continue; 115 116 /* 117 * This is useful for mechs like Kerberos, which can 118 * detect unknown target princs here, but not for 119 * mechs like SPKM, which cannot detect unknown princs 120 * until context tokens are actually exchanged. 121 * 122 * 'Twould be useful to have a test that could save us 123 * the bother of trying this for SPKM and the such... 124 */ 125 maj = ssh_gssapi_init_ctx(ctxt, server_host, 0, 126 NULL, &tok); 127 if (GSS_ERROR(maj)) { 128 debug("Skipping GSS-API mechanism %s (%s)", 129 ssh_gssapi_oid_to_name(mech), 130 ssh_gssapi_last_error(ctxt, NULL, NULL)); 131 continue; 132 } 133 134 (void) gss_release_buffer(&min, &tok); 135 136 maj = gss_add_oid_set_member(&min, mech, &supported); 137 if (GSS_ERROR(maj)) 138 debug("Failed to allocate resources (%s) for GSS-API", 139 ssh_gssapi_last_error(NULL, &maj, &min)); 140 } 141 142 *mechs = supported; 143 } 144 145 146 /* Wrapper to init_sec_context 147 * Requires that the context contains: 148 * oid 149 * server name (from ssh_gssapi_import_name) 150 */ 151 OM_uint32 152 ssh_gssapi_init_ctx(Gssctxt *ctx, const char *server_host, int deleg_creds, 153 gss_buffer_t recv_tok, gss_buffer_t send_tok) 154 { 155 int flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG; 156 157 debug("%s(%p, %s, %d, %p, %p)", __func__, ctx, server_host, 158 deleg_creds, recv_tok, send_tok); 159 160 if (deleg_creds) { 161 flags |= GSS_C_DELEG_FLAG; 162 debug("Delegating GSS-API credentials"); 163 } 164 165 /* Build target principal */ 166 if (ctx->desired_name == GSS_C_NO_NAME && 167 !ssh_gssapi_import_name(ctx, server_host)) 168 return ctx->major; 169 170 ctx->major=gss_init_sec_context(&ctx->minor, 171 GSS_C_NO_CREDENTIAL, 172 &ctx->context, 173 ctx->desired_name, 174 ctx->desired_mech, 175 flags, 176 0, /* default lifetime */ 177 NULL, /* no channel bindings */ 178 recv_tok, 179 NULL, /* actual mech type */ 180 send_tok, 181 &ctx->flags, 182 NULL); /* actual lifetime */ 183 184 if (GSS_ERROR(ctx->major)) 185 ssh_gssapi_error(ctx, "calling GSS_Init_sec_context()"); 186 187 return(ctx->major); 188 } 189 #endif /* GSSAPI */ 190