1255767Sdes/* $OpenBSD: gss-serv-krb5.c,v 1.8 2013/07/20 01:55:13 djm Exp $ */ 2124208Sdes 3124208Sdes/* 4124208Sdes * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 5124208Sdes * 6124208Sdes * Redistribution and use in source and binary forms, with or without 7124208Sdes * modification, are permitted provided that the following conditions 8124208Sdes * are met: 9124208Sdes * 1. Redistributions of source code must retain the above copyright 10124208Sdes * notice, this list of conditions and the following disclaimer. 11124208Sdes * 2. Redistributions in binary form must reproduce the above copyright 12124208Sdes * notice, this list of conditions and the following disclaimer in the 13124208Sdes * documentation and/or other materials provided with the distribution. 14124208Sdes * 15124208Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 16124208Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17124208Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18124208Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19124208Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20124208Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21124208Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22124208Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23124208Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24124208Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25124208Sdes */ 26124208Sdes 27124208Sdes#include "includes.h" 28124208Sdes 29124208Sdes#ifdef GSSAPI 30124208Sdes#ifdef KRB5 31124208Sdes 32162852Sdes#include <sys/types.h> 33162852Sdes 34162852Sdes#include <stdarg.h> 35162852Sdes#include <string.h> 36162852Sdes 37162852Sdes#include "xmalloc.h" 38162852Sdes#include "key.h" 39162852Sdes#include "hostfile.h" 40124208Sdes#include "auth.h" 41124208Sdes#include "log.h" 42124208Sdes#include "servconf.h" 43124208Sdes 44162852Sdes#include "buffer.h" 45124208Sdes#include "ssh-gss.h" 46124208Sdes 47124208Sdesextern ServerOptions options; 48124208Sdes 49124208Sdes#ifdef HEIMDAL 50126274Sdes# include <krb5.h> 51124208Sdes#endif 52255767Sdes#ifdef HAVE_GSSAPI_KRB5_H 53255767Sdes# include <gssapi_krb5.h> 54255767Sdes#elif HAVE_GSSAPI_GSSAPI_KRB5_H 55255767Sdes# include <gssapi/gssapi_krb5.h> 56255767Sdes#endif 57124208Sdes 58124208Sdesstatic krb5_context krb_context = NULL; 59124208Sdes 60124208Sdes/* Initialise the krb5 library, for the stuff that GSSAPI won't do */ 61124208Sdes 62126274Sdesstatic int 63137015Sdesssh_gssapi_krb5_init(void) 64124208Sdes{ 65124208Sdes krb5_error_code problem; 66124208Sdes 67124208Sdes if (krb_context != NULL) 68124208Sdes return 1; 69124208Sdes 70124208Sdes problem = krb5_init_context(&krb_context); 71124208Sdes if (problem) { 72124208Sdes logit("Cannot initialize krb5 context"); 73124208Sdes return 0; 74124208Sdes } 75124208Sdes 76124208Sdes return 1; 77124208Sdes} 78124208Sdes 79124208Sdes/* Check if this user is OK to login. This only works with krb5 - other 80124208Sdes * GSSAPI mechanisms will need their own. 81124208Sdes * Returns true if the user is OK to log in, otherwise returns 0 82124208Sdes */ 83124208Sdes 84124208Sdesstatic int 85124208Sdesssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) 86124208Sdes{ 87124208Sdes krb5_principal princ; 88124208Sdes int retval; 89255767Sdes const char *errmsg; 90124208Sdes 91124208Sdes if (ssh_gssapi_krb5_init() == 0) 92124208Sdes return 0; 93124208Sdes 94124208Sdes if ((retval = krb5_parse_name(krb_context, client->exportedname.value, 95124208Sdes &princ))) { 96255767Sdes errmsg = krb5_get_error_message(krb_context, retval); 97255767Sdes logit("krb5_parse_name(): %.100s", errmsg); 98255767Sdes krb5_free_error_message(krb_context, errmsg); 99124208Sdes return 0; 100124208Sdes } 101124208Sdes if (krb5_kuserok(krb_context, princ, name)) { 102124208Sdes retval = 1; 103124208Sdes logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", 104124208Sdes name, (char *)client->displayname.value); 105124208Sdes } else 106124208Sdes retval = 0; 107124208Sdes 108124208Sdes krb5_free_principal(krb_context, princ); 109124208Sdes return retval; 110124208Sdes} 111124208Sdes 112124208Sdes 113124208Sdes/* This writes out any forwarded credentials from the structure populated 114124208Sdes * during userauth. Called after we have setuid to the user */ 115124208Sdes 116124208Sdesstatic void 117124208Sdesssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) 118124208Sdes{ 119124208Sdes krb5_ccache ccache; 120124208Sdes krb5_error_code problem; 121124208Sdes krb5_principal princ; 122124208Sdes OM_uint32 maj_status, min_status; 123126274Sdes int len; 124255767Sdes const char *errmsg; 125124208Sdes 126124208Sdes if (client->creds == NULL) { 127124208Sdes debug("No credentials stored"); 128124208Sdes return; 129124208Sdes } 130124208Sdes 131124208Sdes if (ssh_gssapi_krb5_init() == 0) 132124208Sdes return; 133124208Sdes 134124208Sdes#ifdef HEIMDAL 135255767Sdes if ((problem = krb5_cc_new_unique(krb_context, krb5_fcc_ops.prefix, 136255767Sdes NULL, &ccache)) != 0) { 137255767Sdes errmsg = krb5_get_error_message(krb_context, problem); 138255767Sdes logit("krb5_cc_new_unique(): %.100s", errmsg); 139255767Sdes krb5_free_error_message(krb_context, errmsg); 140124208Sdes return; 141124208Sdes } 142124208Sdes#else 143149749Sdes if ((problem = ssh_krb5_cc_gen(krb_context, &ccache))) { 144255767Sdes errmsg = krb5_get_error_message(krb_context, problem); 145255767Sdes logit("ssh_krb5_cc_gen(): %.100s", errmsg); 146255767Sdes krb5_free_error_message(krb_context, errmsg); 147149749Sdes return; 148124208Sdes } 149124208Sdes#endif /* #ifdef HEIMDAL */ 150124208Sdes 151126274Sdes if ((problem = krb5_parse_name(krb_context, 152124208Sdes client->exportedname.value, &princ))) { 153255767Sdes errmsg = krb5_get_error_message(krb_context, problem); 154255767Sdes logit("krb5_parse_name(): %.100s", errmsg); 155255767Sdes krb5_free_error_message(krb_context, errmsg); 156124208Sdes return; 157124208Sdes } 158124208Sdes 159124208Sdes if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) { 160255767Sdes errmsg = krb5_get_error_message(krb_context, problem); 161255767Sdes logit("krb5_cc_initialize(): %.100s", errmsg); 162255767Sdes krb5_free_error_message(krb_context, errmsg); 163124208Sdes krb5_free_principal(krb_context, princ); 164124208Sdes krb5_cc_destroy(krb_context, ccache); 165124208Sdes return; 166124208Sdes } 167124208Sdes 168124208Sdes krb5_free_principal(krb_context, princ); 169124208Sdes 170126274Sdes if ((maj_status = gss_krb5_copy_ccache(&min_status, 171124208Sdes client->creds, ccache))) { 172124208Sdes logit("gss_krb5_copy_ccache() failed"); 173124208Sdes krb5_cc_destroy(krb_context, ccache); 174124208Sdes return; 175124208Sdes } 176124208Sdes 177124208Sdes client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); 178124208Sdes client->store.envvar = "KRB5CCNAME"; 179126274Sdes len = strlen(client->store.filename) + 6; 180126274Sdes client->store.envval = xmalloc(len); 181126274Sdes snprintf(client->store.envval, len, "FILE:%s", client->store.filename); 182124208Sdes 183124208Sdes#ifdef USE_PAM 184124208Sdes if (options.use_pam) 185126274Sdes do_pam_putenv(client->store.envvar, client->store.envval); 186124208Sdes#endif 187124208Sdes 188124208Sdes krb5_cc_close(krb_context, ccache); 189124208Sdes 190124208Sdes return; 191124208Sdes} 192124208Sdes 193124208Sdesssh_gssapi_mech gssapi_kerberos_mech = { 194124208Sdes "toWM5Slw5Ew8Mqkay+al2g==", 195124208Sdes "Kerberos", 196124208Sdes {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, 197124208Sdes NULL, 198124208Sdes &ssh_gssapi_krb5_userok, 199124208Sdes NULL, 200124208Sdes &ssh_gssapi_krb5_storecreds 201124208Sdes}; 202124208Sdes 203124208Sdes#endif /* KRB5 */ 204124208Sdes 205124208Sdes#endif /* GSSAPI */ 206