HardenedBSD/crypto/openssh/auth-krb5.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

274 lines
6.9 KiB
C
Raw Normal View History

2021-04-23 21:13:32 +02:00
/* $OpenBSD: auth-krb5.c,v 1.24 2021/04/03 06:18:40 djm Exp $ */
2002-03-18 10:55:03 +01:00
/*
* Kerberos v5 authentication and ticket-passing routines.
2002-06-23 16:01:54 +02:00
*
2016-03-10 21:10:25 +01:00
* From: FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar
2002-03-18 10:55:03 +01:00
*/
2002-06-23 16:01:54 +02:00
/*
* Copyright (c) 2002 Daniel Kouril. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
2002-03-18 10:55:03 +01:00
#include "includes.h"
2006-09-30 15:29:51 +02:00
#include <sys/types.h>
#include <pwd.h>
#include <stdarg.h>
#include "xmalloc.h"
2002-03-18 10:55:03 +01:00
#include "ssh.h"
#include "packet.h"
#include "log.h"
2018-08-28 12:47:58 +02:00
#include "sshbuf.h"
#include "sshkey.h"
2015-01-05 17:09:55 +01:00
#include "misc.h"
2002-03-18 10:55:03 +01:00
#include "servconf.h"
#include "uidswap.h"
2006-09-30 15:29:51 +02:00
#include "hostfile.h"
2002-03-18 10:55:03 +01:00
#include "auth.h"
#ifdef KRB5
2006-09-30 15:29:51 +02:00
#include <errno.h>
#include <unistd.h>
#include <string.h>
2002-03-18 10:55:03 +01:00
#include <krb5.h>
extern ServerOptions options;
static int
krb5_init(void *context)
{
Authctxt *authctxt = (Authctxt *)context;
krb5_error_code problem;
if (authctxt->krb5_ctx == NULL) {
problem = krb5_init_context(&authctxt->krb5_ctx);
if (problem)
return (problem);
}
return (0);
}
int
auth_krb5_password(Authctxt *authctxt, const char *password)
{
2002-06-28 00:31:32 +02:00
#ifndef HEIMDAL
krb5_creds creds;
krb5_principal server;
2004-02-26 11:38:49 +01:00
#endif
2002-03-18 10:55:03 +01:00
krb5_error_code problem;
2004-01-07 12:10:17 +01:00
krb5_ccache ccache = NULL;
2004-04-20 11:35:04 +02:00
int len;
2010-03-08 12:19:52 +01:00
char *client, *platform_client;
2013-09-18 19:27:38 +02:00
const char *errmsg;
2010-03-08 12:19:52 +01:00
/* get platform-specific kerberos client principal name (if it exists) */
platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name);
client = platform_client ? platform_client : authctxt->pw->pw_name;
2002-03-18 10:55:03 +01:00
temporarily_use_uid(authctxt->pw);
problem = krb5_init(authctxt);
if (problem)
goto out;
2010-03-08 12:19:52 +01:00
problem = krb5_parse_name(authctxt->krb5_ctx, client,
2002-03-18 10:55:03 +01:00
&authctxt->krb5_user);
if (problem)
goto out;
2002-06-28 00:31:32 +02:00
#ifdef HEIMDAL
2013-09-18 19:27:38 +02:00
# ifdef HAVE_KRB5_CC_NEW_UNIQUE
problem = krb5_cc_new_unique(authctxt->krb5_ctx,
2021-04-23 21:13:32 +02:00
krb5_mcc_ops.prefix, NULL, &ccache);
2013-09-18 19:27:38 +02:00
# else
2004-01-07 12:10:17 +01:00
problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache);
2013-09-18 19:27:38 +02:00
# endif
2002-03-18 10:55:03 +01:00
if (problem)
goto out;
2004-01-07 12:10:17 +01:00
problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
authctxt->krb5_user);
2002-03-18 10:55:03 +01:00
if (problem)
goto out;
restore_uid();
2004-02-26 11:38:49 +01:00
2002-03-18 10:55:03 +01:00
problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
2004-01-07 12:10:17 +01:00
ccache, password, 1, NULL);
2004-02-26 11:38:49 +01:00
2002-03-18 10:55:03 +01:00
temporarily_use_uid(authctxt->pw);
if (problem)
goto out;
2004-02-26 11:38:49 +01:00
2013-09-18 19:27:38 +02:00
# ifdef HAVE_KRB5_CC_NEW_UNIQUE
problem = krb5_cc_new_unique(authctxt->krb5_ctx,
2021-04-23 21:13:32 +02:00
krb5_fcc_ops.prefix, NULL, &authctxt->krb5_fwd_ccache);
2013-09-18 19:27:38 +02:00
# else
2004-01-07 12:10:17 +01:00
problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops,
&authctxt->krb5_fwd_ccache);
2013-09-18 19:27:38 +02:00
# endif
2004-01-07 12:10:17 +01:00
if (problem)
goto out;
problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache,
authctxt->krb5_fwd_ccache);
krb5_cc_destroy(authctxt->krb5_ctx, ccache);
ccache = NULL;
if (problem)
goto out;
2002-03-18 10:55:03 +01:00
2002-06-28 00:31:32 +02:00
#else
problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds,
authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL);
if (problem)
goto out;
problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL,
KRB5_NT_SRV_HST, &server);
if (problem)
goto out;
restore_uid();
problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server,
NULL, NULL, NULL);
krb5_free_principal(authctxt->krb5_ctx, server);
temporarily_use_uid(authctxt->pw);
if (problem)
goto out;
2004-02-26 11:38:49 +01:00
2014-01-30 11:56:49 +01:00
if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
authctxt->pw->pw_name)) {
2002-06-28 00:31:32 +02:00
problem = -1;
goto out;
2004-02-26 11:38:49 +01:00
}
2002-06-28 00:31:32 +02:00
2021-04-23 21:13:32 +02:00
problem = ssh_krb5_cc_gen(authctxt->krb5_ctx,
&authctxt->krb5_fwd_ccache);
2002-06-28 00:31:32 +02:00
if (problem)
goto out;
2021-04-23 21:13:32 +02:00
problem = krb5_cc_initialize(authctxt->krb5_ctx,
authctxt->krb5_fwd_ccache, authctxt->krb5_user);
2002-06-28 00:31:32 +02:00
if (problem)
goto out;
2004-02-26 11:38:49 +01:00
2021-04-23 21:13:32 +02:00
problem = krb5_cc_store_cred(authctxt->krb5_ctx,
authctxt->krb5_fwd_ccache, &creds);
2002-06-28 00:31:32 +02:00
if (problem)
goto out;
2004-02-26 11:38:49 +01:00
#endif
2002-06-28 00:31:32 +02:00
2002-03-18 10:55:03 +01:00
authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
2004-04-20 11:35:04 +02:00
len = strlen(authctxt->krb5_ticket_file) + 6;
authctxt->krb5_ccname = xmalloc(len);
snprintf(authctxt->krb5_ccname, len, "FILE:%s",
authctxt->krb5_ticket_file);
2005-06-05 17:40:50 +02:00
#ifdef USE_PAM
if (options.use_pam)
do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname);
#endif
2002-03-18 10:55:03 +01:00
out:
restore_uid();
2010-03-08 12:19:52 +01:00
2013-09-18 19:27:38 +02:00
free(platform_client);
2002-03-18 10:55:03 +01:00
if (problem) {
2004-01-07 12:10:17 +01:00
if (ccache)
krb5_cc_destroy(authctxt->krb5_ctx, ccache);
2013-09-18 19:27:38 +02:00
if (authctxt->krb5_ctx != NULL && problem!=-1) {
errmsg = krb5_get_error_message(authctxt->krb5_ctx,
problem);
2021-04-23 21:13:32 +02:00
debug("Kerberos password authentication failed: %s",
2013-09-18 19:27:38 +02:00
errmsg);
krb5_free_error_message(authctxt->krb5_ctx, errmsg);
} else
2002-03-18 10:55:03 +01:00
debug("Kerberos password authentication failed: %d",
problem);
krb5_cleanup_proc(authctxt);
if (options.kerberos_or_local_passwd)
return (-1);
else
return (0);
}
2006-03-22 20:46:12 +01:00
return (authctxt->valid ? 1 : 0);
2002-03-18 10:55:03 +01:00
}
void
2004-02-26 11:38:49 +01:00
krb5_cleanup_proc(Authctxt *authctxt)
2002-03-18 10:55:03 +01:00
{
debug("krb5_cleanup_proc called");
if (authctxt->krb5_fwd_ccache) {
krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
authctxt->krb5_fwd_ccache = NULL;
}
if (authctxt->krb5_user) {
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
authctxt->krb5_user = NULL;
}
if (authctxt->krb5_ctx) {
krb5_free_context(authctxt->krb5_ctx);
authctxt->krb5_ctx = NULL;
}
}
2005-09-03 08:59:33 +02:00
#ifndef HEIMDAL
krb5_error_code
ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
2012-08-29 17:55:54 +02:00
int tmpfd, ret, oerrno;
2005-09-03 08:59:33 +02:00
char ccname[40];
mode_t old_umask;
ret = snprintf(ccname, sizeof(ccname),
"FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
2006-03-22 20:46:12 +01:00
if (ret < 0 || (size_t)ret >= sizeof(ccname))
2005-09-03 08:59:33 +02:00
return ENOMEM;
old_umask = umask(0177);
tmpfd = mkstemp(ccname + strlen("FILE:"));
2012-08-29 17:55:54 +02:00
oerrno = errno;
2005-09-03 08:59:33 +02:00
umask(old_umask);
if (tmpfd == -1) {
2012-08-29 17:55:54 +02:00
logit("mkstemp(): %.100s", strerror(oerrno));
return oerrno;
2005-09-03 08:59:33 +02:00
}
if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
2012-08-29 17:55:54 +02:00
oerrno = errno;
logit("fchmod(): %.100s", strerror(oerrno));
2005-09-03 08:59:33 +02:00
close(tmpfd);
2012-08-29 17:55:54 +02:00
return oerrno;
2005-09-03 08:59:33 +02:00
}
close(tmpfd);
return (krb5_cc_resolve(ctx, ccname, ccache));
}
#endif /* !HEIMDAL */
2002-03-18 10:55:03 +01:00
#endif /* KRB5 */