X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/c12337d922ffbf376f2cbeef86e48a3b4560be9d..HEAD:/auth-krb5.c diff --git a/auth-krb5.c b/auth-krb5.c index aaf146e7..d019fe20 100644 --- a/auth-krb5.c +++ b/auth-krb5.c @@ -1,21 +1,55 @@ +/* $OpenBSD: auth-krb5.c,v 1.19 2006/08/03 03:34:41 deraadt Exp $ */ /* * Kerberos v5 authentication and ticket-passing routines. - * + * * $FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar Exp $ - * $OpenBSD: auth-krb5.c,v 1.5 2002/02/15 23:54:10 markus Exp $ + */ +/* + * 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. */ #include "includes.h" + +#include +#include +#include + +#include "xmalloc.h" #include "ssh.h" #include "ssh1.h" #include "packet.h" -#include "xmalloc.h" #include "log.h" +#include "buffer.h" #include "servconf.h" #include "uidswap.h" +#include "key.h" +#include "hostfile.h" #include "auth.h" #ifdef KRB5 +#include +#include +#include #include extern ServerOptions options; @@ -25,209 +59,136 @@ krb5_init(void *context) { Authctxt *authctxt = (Authctxt *)context; krb5_error_code problem; - static int cleanup_registered = 0; if (authctxt->krb5_ctx == NULL) { problem = krb5_init_context(&authctxt->krb5_ctx); if (problem) return (problem); - krb5_init_ets(authctxt->krb5_ctx); - } - if (!cleanup_registered) { - fatal_add_cleanup(krb5_cleanup_proc, authctxt); - cleanup_registered = 1; } return (0); } -/* - * Try krb5 authentication. server_user is passed for logging purposes - * only, in auth is received ticket, in client is returned principal - * from the ticket - */ int -auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client) +auth_krb5_password(Authctxt *authctxt, const char *password) { - krb5_error_code problem; +#ifndef HEIMDAL + krb5_creds creds; krb5_principal server; - krb5_data reply; - krb5_ticket *ticket; - int fd, ret; - - ret = 0; - server = NULL; - ticket = NULL; - reply.length = 0; - - problem = krb5_init(authctxt); - if (problem) - goto err; +#endif + krb5_error_code problem; + krb5_ccache ccache = NULL; + int len; + char *client, *platform_client; - problem = krb5_auth_con_init(authctxt->krb5_ctx, - &authctxt->krb5_auth_ctx); - if (problem) - goto err; + /* 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; - fd = packet_get_connection_in(); - problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx, - authctxt->krb5_auth_ctx, &fd); - if (problem) - goto err; + temporarily_use_uid(authctxt->pw); - problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL , - KRB5_NT_SRV_HST, &server); + problem = krb5_init(authctxt); if (problem) - goto err; + goto out; - problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx, - auth, server, NULL, NULL, &ticket); + problem = krb5_parse_name(authctxt->krb5_ctx, client, + &authctxt->krb5_user); if (problem) - goto err; + goto out; - problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client, - &authctxt->krb5_user); +#ifdef HEIMDAL + problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); if (problem) - goto err; + goto out; - /* if client wants mutual auth */ - problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, - &reply); + problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, + authctxt->krb5_user); if (problem) - goto err; - - /* Check .k5login authorization now. */ - if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, - authctxt->pw->pw_name)) - goto err; - - if (client) - krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, - client); - - packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE); - packet_put_string((char *) reply.data, reply.length); - packet_send(); - packet_write_wait(); - - ret = 1; - err: - if (server) - krb5_free_principal(authctxt->krb5_ctx, server); - if (ticket) - krb5_free_ticket(authctxt->krb5_ctx, ticket); - if (reply.length) - xfree(reply.data); - - if (problem) { - if (authctxt->krb5_ctx != NULL) - debug("Kerberos v5 authentication failed: %s", - krb5_get_err_text(authctxt->krb5_ctx, problem)); - else - debug("Kerberos v5 authentication failed: %d", - problem); - } - - return (ret); -} + goto out; -int -auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt) -{ - krb5_error_code problem; - krb5_ccache ccache = NULL; - char *pname; + restore_uid(); - if (authctxt->pw == NULL || authctxt->krb5_user == NULL) - return (0); + problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, + ccache, password, 1, NULL); temporarily_use_uid(authctxt->pw); - problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache); - if (problem) - goto fail; - - problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, - authctxt->krb5_user); if (problem) - goto fail; + goto out; - problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, - ccache, tgt); + problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, + &authctxt->krb5_fwd_ccache); if (problem) - goto fail; + goto out; - authctxt->krb5_fwd_ccache = ccache; + problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, + authctxt->krb5_fwd_ccache); + krb5_cc_destroy(authctxt->krb5_ctx, ccache); ccache = NULL; - - authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); - - problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, - &pname); if (problem) - goto fail; - - debug("Kerberos v5 TGT accepted (%s)", pname); - - restore_uid(); + goto out; - return (1); +#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; - fail: + problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, + KRB5_NT_SRV_HST, &server); if (problem) - debug("Kerberos v5 TGT passing failed: %s", - krb5_get_err_text(authctxt->krb5_ctx, problem)); - if (ccache) - krb5_cc_destroy(authctxt->krb5_ctx, ccache); + goto out; restore_uid(); - - return (0); -} - -int -auth_krb5_password(Authctxt *authctxt, const char *password) -{ - krb5_error_code problem; - - if (authctxt->pw == NULL) - return (0); - + 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); - - problem = krb5_init(authctxt); if (problem) goto out; - problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, - &authctxt->krb5_user); - if (problem) + if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) { + problem = -1; goto out; + } - problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, - &authctxt->krb5_fwd_ccache); + problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache); if (problem) goto out; - problem = krb5_cc_initialize(authctxt->krb5_ctx, - authctxt->krb5_fwd_ccache, authctxt->krb5_user); + problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, + authctxt->krb5_user); if (problem) goto out; - restore_uid(); - problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, - authctxt->krb5_fwd_ccache, password, 1, NULL); - temporarily_use_uid(authctxt->pw); - + problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, + &creds); if (problem) goto out; +#endif authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); + len = strlen(authctxt->krb5_ticket_file) + 6; + authctxt->krb5_ccname = xmalloc(len); + snprintf(authctxt->krb5_ccname, len, "FILE:%s", + authctxt->krb5_ticket_file); + +#ifdef USE_PAM + if (options.use_pam) + do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); +#endif + out: restore_uid(); + + if (platform_client != NULL) + xfree(platform_client); if (problem) { - if (authctxt->krb5_ctx != NULL) + if (ccache) + krb5_cc_destroy(authctxt->krb5_ctx, ccache); + + if (authctxt->krb5_ctx != NULL && problem!=-1) debug("Kerberos password authentication failed: %s", krb5_get_err_text(authctxt->krb5_ctx, problem)); else @@ -241,14 +202,12 @@ auth_krb5_password(Authctxt *authctxt, const char *password) else return (0); } - return (1); + return (authctxt->valid ? 1 : 0); } void -krb5_cleanup_proc(void *context) +krb5_cleanup_proc(Authctxt *authctxt) { - Authctxt *authctxt = (Authctxt *)context; - debug("krb5_cleanup_proc called"); if (authctxt->krb5_fwd_ccache) { krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); @@ -258,15 +217,40 @@ krb5_cleanup_proc(void *context) krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); authctxt->krb5_user = NULL; } - if (authctxt->krb5_auth_ctx) { - krb5_auth_con_free(authctxt->krb5_ctx, - authctxt->krb5_auth_ctx); - authctxt->krb5_auth_ctx = NULL; - } if (authctxt->krb5_ctx) { krb5_free_context(authctxt->krb5_ctx); authctxt->krb5_ctx = NULL; } } +#ifndef HEIMDAL +krb5_error_code +ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { + int tmpfd, ret; + char ccname[40]; + mode_t old_umask; + + ret = snprintf(ccname, sizeof(ccname), + "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); + if (ret < 0 || (size_t)ret >= sizeof(ccname)) + return ENOMEM; + + old_umask = umask(0177); + tmpfd = mkstemp(ccname + strlen("FILE:")); + umask(old_umask); + if (tmpfd == -1) { + logit("mkstemp(): %.100s", strerror(errno)); + return errno; + } + + if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { + logit("fchmod(): %.100s", strerror(errno)); + close(tmpfd); + return errno; + } + close(tmpfd); + + return (krb5_cc_resolve(ctx, ccname, ccache)); +} +#endif /* !HEIMDAL */ #endif /* KRB5 */