1296853Sdes/* $OpenBSD: auth-krb5.c,v 1.21 2016/01/27 06:44:58 djm Exp $ */ 257565Smarkm/* 357565Smarkm * Kerberos v5 authentication and ticket-passing routines. 498684Sdes * 5296853Sdes * From: FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar 657565Smarkm */ 798684Sdes/* 898684Sdes * Copyright (c) 2002 Daniel Kouril. All rights reserved. 998684Sdes * 1098684Sdes * Redistribution and use in source and binary forms, with or without 1198684Sdes * modification, are permitted provided that the following conditions 1298684Sdes * are met: 1398684Sdes * 1. Redistributions of source code must retain the above copyright 1498684Sdes * notice, this list of conditions and the following disclaimer. 1598684Sdes * 2. Redistributions in binary form must reproduce the above copyright 1698684Sdes * notice, this list of conditions and the following disclaimer in the 1798684Sdes * documentation and/or other materials provided with the distribution. 1898684Sdes * 1998684Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2098684Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2198684Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2298684Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2398684Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2498684Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2598684Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2698684Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2798684Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2898684Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2998684Sdes */ 3057565Smarkm 3157565Smarkm#include "includes.h" 3292559Sdes 33162856Sdes#include <sys/types.h> 34162856Sdes#include <pwd.h> 35162856Sdes#include <stdarg.h> 36162856Sdes 37162856Sdes#include "xmalloc.h" 3857565Smarkm#include "ssh.h" 3978129Sgreen#include "ssh1.h" 4057565Smarkm#include "packet.h" 4192559Sdes#include "log.h" 42162856Sdes#include "buffer.h" 43295367Sdes#include "misc.h" 4492559Sdes#include "servconf.h" 4592559Sdes#include "uidswap.h" 46162856Sdes#include "key.h" 47162856Sdes#include "hostfile.h" 4892559Sdes#include "auth.h" 4957565Smarkm 5057565Smarkm#ifdef KRB5 51162856Sdes#include <errno.h> 52162856Sdes#include <unistd.h> 53162856Sdes#include <string.h> 5492559Sdes#include <krb5.h> 5557565Smarkm 5692559Sdesextern ServerOptions options; 5757565Smarkm 5892559Sdesstatic int 5992559Sdeskrb5_init(void *context) 6057565Smarkm{ 6192559Sdes Authctxt *authctxt = (Authctxt *)context; 6257565Smarkm krb5_error_code problem; 6392559Sdes 6492559Sdes if (authctxt->krb5_ctx == NULL) { 6592559Sdes problem = krb5_init_context(&authctxt->krb5_ctx); 6692559Sdes if (problem) 6792559Sdes return (problem); 6892559Sdes } 6992559Sdes return (0); 7092559Sdes} 7192559Sdes 7292559Sdesint 7392559Sdesauth_krb5_password(Authctxt *authctxt, const char *password) 7457565Smarkm{ 7598941Sdes#ifndef HEIMDAL 7698941Sdes krb5_creds creds; 7798941Sdes krb5_principal server; 78126277Sdes#endif 7992559Sdes krb5_error_code problem; 80124211Sdes krb5_ccache ccache = NULL; 81128460Sdes int len; 82204917Sdes char *client, *platform_client; 83255767Sdes const char *errmsg; 8457565Smarkm 85204917Sdes /* get platform-specific kerberos client principal name (if it exists) */ 86204917Sdes platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name); 87204917Sdes client = platform_client ? platform_client : authctxt->pw->pw_name; 88204917Sdes 8992559Sdes temporarily_use_uid(authctxt->pw); 9092559Sdes 9192559Sdes problem = krb5_init(authctxt); 9292559Sdes if (problem) 9392559Sdes goto out; 9492559Sdes 95204917Sdes problem = krb5_parse_name(authctxt->krb5_ctx, client, 9692559Sdes &authctxt->krb5_user); 9792559Sdes if (problem) 9892559Sdes goto out; 9992559Sdes 10098941Sdes#ifdef HEIMDAL 101255767Sdes# ifdef HAVE_KRB5_CC_NEW_UNIQUE 102255767Sdes problem = krb5_cc_new_unique(authctxt->krb5_ctx, 103255767Sdes krb5_mcc_ops.prefix, NULL, &ccache); 104255767Sdes# else 105124211Sdes problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); 106255767Sdes# endif 10792559Sdes if (problem) 10892559Sdes goto out; 10992559Sdes 110124211Sdes problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, 111124211Sdes authctxt->krb5_user); 11292559Sdes if (problem) 11392559Sdes goto out; 11492559Sdes 11592559Sdes restore_uid(); 116126277Sdes 11792559Sdes problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, 118124211Sdes ccache, password, 1, NULL); 119126277Sdes 12092559Sdes temporarily_use_uid(authctxt->pw); 12192559Sdes 12292559Sdes if (problem) 12392559Sdes goto out; 124126277Sdes 125255767Sdes# ifdef HAVE_KRB5_CC_NEW_UNIQUE 126255767Sdes problem = krb5_cc_new_unique(authctxt->krb5_ctx, 127255767Sdes krb5_fcc_ops.prefix, NULL, &authctxt->krb5_fwd_ccache); 128255767Sdes# else 129124211Sdes problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, 130124211Sdes &authctxt->krb5_fwd_ccache); 131255767Sdes# endif 132124211Sdes if (problem) 133124211Sdes goto out; 13492559Sdes 135124211Sdes problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, 136124211Sdes authctxt->krb5_fwd_ccache); 137124211Sdes krb5_cc_destroy(authctxt->krb5_ctx, ccache); 138124211Sdes ccache = NULL; 139124211Sdes if (problem) 140124211Sdes goto out; 141124211Sdes 14298941Sdes#else 14398941Sdes problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, 14498941Sdes authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL); 14598941Sdes if (problem) 14698941Sdes goto out; 14798941Sdes 14898941Sdes problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, 14998941Sdes KRB5_NT_SRV_HST, &server); 15098941Sdes if (problem) 15198941Sdes goto out; 15298941Sdes 15398941Sdes restore_uid(); 15498941Sdes problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, 15598941Sdes NULL, NULL, NULL); 15698941Sdes krb5_free_principal(authctxt->krb5_ctx, server); 15798941Sdes temporarily_use_uid(authctxt->pw); 15898941Sdes if (problem) 15998941Sdes goto out; 160126277Sdes 161262566Sdes if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, 162262566Sdes authctxt->pw->pw_name)) { 16398941Sdes problem = -1; 16498941Sdes goto out; 165126277Sdes } 16698941Sdes 167149753Sdes problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache); 16898941Sdes if (problem) 16998941Sdes goto out; 17098941Sdes 17198941Sdes problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, 17298941Sdes authctxt->krb5_user); 17398941Sdes if (problem) 17498941Sdes goto out; 175126277Sdes 17698941Sdes problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, 17798941Sdes &creds); 17898941Sdes if (problem) 17998941Sdes goto out; 180126277Sdes#endif 18198941Sdes 18292559Sdes authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); 18392559Sdes 184128460Sdes len = strlen(authctxt->krb5_ticket_file) + 6; 185128460Sdes authctxt->krb5_ccname = xmalloc(len); 186128460Sdes snprintf(authctxt->krb5_ccname, len, "FILE:%s", 187128460Sdes authctxt->krb5_ticket_file); 188128460Sdes 189147005Sdes#ifdef USE_PAM 190147005Sdes if (options.use_pam) 191147005Sdes do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); 192147005Sdes#endif 193147005Sdes 19492559Sdes out: 19592559Sdes restore_uid(); 196204917Sdes 197255767Sdes free(platform_client); 19892559Sdes 19992559Sdes if (problem) { 200124211Sdes if (ccache) 201124211Sdes krb5_cc_destroy(authctxt->krb5_ctx, ccache); 202124211Sdes 203255767Sdes if (authctxt->krb5_ctx != NULL && problem!=-1) { 204255767Sdes errmsg = krb5_get_error_message(authctxt->krb5_ctx, 205255767Sdes problem); 206255767Sdes debug("Kerberos password authentication failed: %s", 207255767Sdes errmsg); 208255767Sdes krb5_free_error_message(authctxt->krb5_ctx, errmsg); 209255767Sdes } else 21092559Sdes debug("Kerberos password authentication failed: %d", 21192559Sdes problem); 21292559Sdes 21392559Sdes krb5_cleanup_proc(authctxt); 21492559Sdes 21592559Sdes if (options.kerberos_or_local_passwd) 21692559Sdes return (-1); 21792559Sdes else 21892559Sdes return (0); 21992559Sdes } 220157019Sdes return (authctxt->valid ? 1 : 0); 22157565Smarkm} 22257565Smarkm 22357565Smarkmvoid 224126277Sdeskrb5_cleanup_proc(Authctxt *authctxt) 22557565Smarkm{ 22692559Sdes debug("krb5_cleanup_proc called"); 22792559Sdes if (authctxt->krb5_fwd_ccache) { 22892559Sdes krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); 22992559Sdes authctxt->krb5_fwd_ccache = NULL; 23092559Sdes } 23192559Sdes if (authctxt->krb5_user) { 23292559Sdes krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); 23392559Sdes authctxt->krb5_user = NULL; 23492559Sdes } 23592559Sdes if (authctxt->krb5_ctx) { 23692559Sdes krb5_free_context(authctxt->krb5_ctx); 23792559Sdes authctxt->krb5_ctx = NULL; 23892559Sdes } 23957565Smarkm} 24092559Sdes 241149753Sdes#ifndef HEIMDAL 242149753Sdeskrb5_error_code 243149753Sdesssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 244240075Sdes int tmpfd, ret, oerrno; 245149753Sdes char ccname[40]; 246149753Sdes mode_t old_umask; 247149753Sdes 248149753Sdes ret = snprintf(ccname, sizeof(ccname), 249149753Sdes "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); 250157019Sdes if (ret < 0 || (size_t)ret >= sizeof(ccname)) 251149753Sdes return ENOMEM; 252149753Sdes 253149753Sdes old_umask = umask(0177); 254149753Sdes tmpfd = mkstemp(ccname + strlen("FILE:")); 255240075Sdes oerrno = errno; 256149753Sdes umask(old_umask); 257149753Sdes if (tmpfd == -1) { 258240075Sdes logit("mkstemp(): %.100s", strerror(oerrno)); 259240075Sdes return oerrno; 260149753Sdes } 261149753Sdes 262149753Sdes if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { 263240075Sdes oerrno = errno; 264240075Sdes logit("fchmod(): %.100s", strerror(oerrno)); 265149753Sdes close(tmpfd); 266240075Sdes return oerrno; 267149753Sdes } 268149753Sdes close(tmpfd); 269149753Sdes 270149753Sdes return (krb5_cc_resolve(ctx, ccname, ccache)); 271149753Sdes} 272149753Sdes#endif /* !HEIMDAL */ 27357565Smarkm#endif /* KRB5 */ 274