1323124Sdes/* $OpenBSD: auth-krb5.c,v 1.22 2016/05/04 14:22:33 markus Exp $ */ 257565Smarkm/* 357565Smarkm * Kerberos v5 authentication and ticket-passing routines. 498684Sdes * 5296781Sdes * 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" 3957565Smarkm#include "packet.h" 4092559Sdes#include "log.h" 41162856Sdes#include "buffer.h" 42295367Sdes#include "misc.h" 4392559Sdes#include "servconf.h" 4492559Sdes#include "uidswap.h" 45162856Sdes#include "key.h" 46162856Sdes#include "hostfile.h" 4792559Sdes#include "auth.h" 4857565Smarkm 4957565Smarkm#ifdef KRB5 50162856Sdes#include <errno.h> 51162856Sdes#include <unistd.h> 52162856Sdes#include <string.h> 5392559Sdes#include <krb5.h> 5457565Smarkm 5592559Sdesextern ServerOptions options; 5657565Smarkm 5792559Sdesstatic int 5892559Sdeskrb5_init(void *context) 5957565Smarkm{ 6092559Sdes Authctxt *authctxt = (Authctxt *)context; 6157565Smarkm krb5_error_code problem; 6292559Sdes 6392559Sdes if (authctxt->krb5_ctx == NULL) { 6492559Sdes problem = krb5_init_context(&authctxt->krb5_ctx); 6592559Sdes if (problem) 6692559Sdes return (problem); 6792559Sdes } 6892559Sdes return (0); 6992559Sdes} 7092559Sdes 7192559Sdesint 7292559Sdesauth_krb5_password(Authctxt *authctxt, const char *password) 7357565Smarkm{ 7498941Sdes#ifndef HEIMDAL 7598941Sdes krb5_creds creds; 7698941Sdes krb5_principal server; 77126277Sdes#endif 7892559Sdes krb5_error_code problem; 79124211Sdes krb5_ccache ccache = NULL; 80128460Sdes int len; 81204917Sdes char *client, *platform_client; 82255767Sdes const char *errmsg; 8357565Smarkm 84204917Sdes /* get platform-specific kerberos client principal name (if it exists) */ 85204917Sdes platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name); 86204917Sdes client = platform_client ? platform_client : authctxt->pw->pw_name; 87204917Sdes 8892559Sdes temporarily_use_uid(authctxt->pw); 8992559Sdes 9092559Sdes problem = krb5_init(authctxt); 9192559Sdes if (problem) 9292559Sdes goto out; 9392559Sdes 94204917Sdes problem = krb5_parse_name(authctxt->krb5_ctx, client, 9592559Sdes &authctxt->krb5_user); 9692559Sdes if (problem) 9792559Sdes goto out; 9892559Sdes 9998941Sdes#ifdef HEIMDAL 100255767Sdes# ifdef HAVE_KRB5_CC_NEW_UNIQUE 101255767Sdes problem = krb5_cc_new_unique(authctxt->krb5_ctx, 102255767Sdes krb5_mcc_ops.prefix, NULL, &ccache); 103255767Sdes# else 104124211Sdes problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); 105255767Sdes# endif 10692559Sdes if (problem) 10792559Sdes goto out; 10892559Sdes 109124211Sdes problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, 110124211Sdes authctxt->krb5_user); 11192559Sdes if (problem) 11292559Sdes goto out; 11392559Sdes 11492559Sdes restore_uid(); 115126277Sdes 11692559Sdes problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, 117124211Sdes ccache, password, 1, NULL); 118126277Sdes 11992559Sdes temporarily_use_uid(authctxt->pw); 12092559Sdes 12192559Sdes if (problem) 12292559Sdes goto out; 123126277Sdes 124255767Sdes# ifdef HAVE_KRB5_CC_NEW_UNIQUE 125255767Sdes problem = krb5_cc_new_unique(authctxt->krb5_ctx, 126255767Sdes krb5_fcc_ops.prefix, NULL, &authctxt->krb5_fwd_ccache); 127255767Sdes# else 128124211Sdes problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, 129124211Sdes &authctxt->krb5_fwd_ccache); 130255767Sdes# endif 131124211Sdes if (problem) 132124211Sdes goto out; 13392559Sdes 134124211Sdes problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, 135124211Sdes authctxt->krb5_fwd_ccache); 136124211Sdes krb5_cc_destroy(authctxt->krb5_ctx, ccache); 137124211Sdes ccache = NULL; 138124211Sdes if (problem) 139124211Sdes goto out; 140124211Sdes 14198941Sdes#else 14298941Sdes problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, 14398941Sdes authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL); 14498941Sdes if (problem) 14598941Sdes goto out; 14698941Sdes 14798941Sdes problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, 14898941Sdes KRB5_NT_SRV_HST, &server); 14998941Sdes if (problem) 15098941Sdes goto out; 15198941Sdes 15298941Sdes restore_uid(); 15398941Sdes problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, 15498941Sdes NULL, NULL, NULL); 15598941Sdes krb5_free_principal(authctxt->krb5_ctx, server); 15698941Sdes temporarily_use_uid(authctxt->pw); 15798941Sdes if (problem) 15898941Sdes goto out; 159126277Sdes 160262566Sdes if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, 161262566Sdes authctxt->pw->pw_name)) { 16298941Sdes problem = -1; 16398941Sdes goto out; 164126277Sdes } 16598941Sdes 166149753Sdes problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache); 16798941Sdes if (problem) 16898941Sdes goto out; 16998941Sdes 17098941Sdes problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, 17198941Sdes authctxt->krb5_user); 17298941Sdes if (problem) 17398941Sdes goto out; 174126277Sdes 17598941Sdes problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, 17698941Sdes &creds); 17798941Sdes if (problem) 17898941Sdes goto out; 179126277Sdes#endif 18098941Sdes 18192559Sdes authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); 18292559Sdes 183128460Sdes len = strlen(authctxt->krb5_ticket_file) + 6; 184128460Sdes authctxt->krb5_ccname = xmalloc(len); 185128460Sdes snprintf(authctxt->krb5_ccname, len, "FILE:%s", 186128460Sdes authctxt->krb5_ticket_file); 187128460Sdes 188147005Sdes#ifdef USE_PAM 189147005Sdes if (options.use_pam) 190147005Sdes do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); 191147005Sdes#endif 192147005Sdes 19392559Sdes out: 19492559Sdes restore_uid(); 195204917Sdes 196255767Sdes free(platform_client); 19792559Sdes 19892559Sdes if (problem) { 199124211Sdes if (ccache) 200124211Sdes krb5_cc_destroy(authctxt->krb5_ctx, ccache); 201124211Sdes 202255767Sdes if (authctxt->krb5_ctx != NULL && problem!=-1) { 203255767Sdes errmsg = krb5_get_error_message(authctxt->krb5_ctx, 204255767Sdes problem); 205255767Sdes debug("Kerberos password authentication failed: %s", 206255767Sdes errmsg); 207255767Sdes krb5_free_error_message(authctxt->krb5_ctx, errmsg); 208255767Sdes } else 20992559Sdes debug("Kerberos password authentication failed: %d", 21092559Sdes problem); 21192559Sdes 21292559Sdes krb5_cleanup_proc(authctxt); 21392559Sdes 21492559Sdes if (options.kerberos_or_local_passwd) 21592559Sdes return (-1); 21692559Sdes else 21792559Sdes return (0); 21892559Sdes } 219157019Sdes return (authctxt->valid ? 1 : 0); 22057565Smarkm} 22157565Smarkm 22257565Smarkmvoid 223126277Sdeskrb5_cleanup_proc(Authctxt *authctxt) 22457565Smarkm{ 22592559Sdes debug("krb5_cleanup_proc called"); 22692559Sdes if (authctxt->krb5_fwd_ccache) { 22792559Sdes krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); 22892559Sdes authctxt->krb5_fwd_ccache = NULL; 22992559Sdes } 23092559Sdes if (authctxt->krb5_user) { 23192559Sdes krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); 23292559Sdes authctxt->krb5_user = NULL; 23392559Sdes } 23492559Sdes if (authctxt->krb5_ctx) { 23592559Sdes krb5_free_context(authctxt->krb5_ctx); 23692559Sdes authctxt->krb5_ctx = NULL; 23792559Sdes } 23857565Smarkm} 23992559Sdes 240149753Sdes#ifndef HEIMDAL 241149753Sdeskrb5_error_code 242149753Sdesssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 243240075Sdes int tmpfd, ret, oerrno; 244149753Sdes char ccname[40]; 245149753Sdes mode_t old_umask; 246149753Sdes 247149753Sdes ret = snprintf(ccname, sizeof(ccname), 248149753Sdes "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); 249157019Sdes if (ret < 0 || (size_t)ret >= sizeof(ccname)) 250149753Sdes return ENOMEM; 251149753Sdes 252149753Sdes old_umask = umask(0177); 253149753Sdes tmpfd = mkstemp(ccname + strlen("FILE:")); 254240075Sdes oerrno = errno; 255149753Sdes umask(old_umask); 256149753Sdes if (tmpfd == -1) { 257240075Sdes logit("mkstemp(): %.100s", strerror(oerrno)); 258240075Sdes return oerrno; 259149753Sdes } 260149753Sdes 261149753Sdes if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { 262240075Sdes oerrno = errno; 263240075Sdes logit("fchmod(): %.100s", strerror(oerrno)); 264149753Sdes close(tmpfd); 265240075Sdes return oerrno; 266149753Sdes } 267149753Sdes close(tmpfd); 268149753Sdes 269149753Sdes return (krb5_cc_resolve(ctx, ccname, ccache)); 270149753Sdes} 271149753Sdes#endif /* !HEIMDAL */ 27257565Smarkm#endif /* KRB5 */ 273