freebsd-skq/crypto/openssh/auth-krb5.c
Assar Westerlund cb96ab3672 Add code for being compatible with ssh.com's krb5 authentication.
It is done by using the same ssh messages for v4 and v5 authentication
(since the ssh.com does not now anything about v4) and looking at the
contents after unpacking it to see if it is v4 or v5.
Based on code from Björn Grönvall <bg@sics.se>

PR:		misc/20504
2001-03-04 02:22:04 +00:00

250 lines
4.9 KiB
C

/*
* Kerberos v5 authentication and ticket-passing routines.
*
* $FreeBSD$
*/
#include "includes.h"
#include "ssh.h"
#include "packet.h"
#include "xmalloc.h"
#ifdef KRB5
krb5_context ssh_context = NULL;
krb5_auth_context auth_context;
krb5_ccache mem_ccache = NULL; /* Credential cache for acquired ticket */
/* 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(const char* server_user, krb5_data *auth, krb5_principal *client)
{
krb5_error_code problem;
krb5_principal server = NULL;
krb5_principal tkt_client = NULL;
krb5_data reply;
krb5_ticket *ticket = NULL;
int fd;
int ret;
reply.length = 0;
problem = krb5_init();
if (problem)
return 0;
problem = krb5_auth_con_init(ssh_context, &auth_context);
if (problem) {
log("Kerberos v5 authentication failed: %.100s",
krb5_get_err_text(ssh_context, problem));
return 0;
}
fd = packet_get_connection_in();
problem = krb5_auth_con_setaddrs_from_fd(ssh_context, auth_context, &fd);
if (problem) {
ret = 0;
goto err;
}
problem = krb5_sname_to_principal(ssh_context, NULL, NULL ,
KRB5_NT_SRV_HST, &server);
if (problem) {
ret = 0;
goto err;
}
problem = krb5_rd_req(ssh_context, &auth_context, auth, server, NULL,
NULL, &ticket);
if (problem) {
ret = 0;
goto err;
}
problem = krb5_copy_principal(ssh_context, ticket->client, &tkt_client);
if (problem) {
ret = 0;
goto err;
}
/* if client wants mutual auth */
problem = krb5_mk_rep(ssh_context, auth_context, &reply);
if (problem) {
ret = 0;
goto err;
}
*client = tkt_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(ssh_context, server);
if (ticket)
krb5_free_ticket(ssh_context, ticket);
if (reply.length)
xfree(reply.data);
return ret;
}
int
auth_krb5_tgt(char *server_user, krb5_data *tgt, krb5_principal tkt_client)
{
krb5_error_code problem;
krb5_ccache ccache = NULL;
if (ssh_context == NULL) {
goto fail;
}
problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache);
if (problem) {
goto fail;
}
problem = krb5_cc_initialize(ssh_context, ccache, tkt_client);
if (problem) {
goto fail;
}
problem = krb5_rd_cred2(ssh_context, auth_context, ccache, tgt);
if (problem) {
goto fail;
}
mem_ccache = ccache;
ccache = NULL;
/*
problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache);
if (problem) {
mem_ccache = NULL;
goto fail;
}
problem = krb5_cc_destroy(ssh_context, ccache);
if (problem)
goto fail;
*/
#if 0
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
#endif
return 1;
fail:
if (ccache)
krb5_cc_destroy(ssh_context, ccache);
#if 0
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
#endif
return 0;
}
int
auth_krb5_password(struct passwd *pw, const char *password)
{
krb5_error_code problem;
krb5_ccache ccache = NULL;
krb5_principal client = NULL;
int ret;
problem = krb5_init();
if (problem)
return 0;
problem = krb5_parse_name(ssh_context, pw->pw_name, &client);
if (problem) {
ret = 0;
goto out;
}
problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache);
if (problem) {
ret = 0;
goto out;
}
problem = krb5_cc_initialize(ssh_context, ccache, client);
if (problem) {
ret = 0;
goto out;
}
problem = krb5_verify_user(ssh_context, client, ccache, password, 1, NULL);
if (problem) {
ret = 0;
goto out;
}
/*
problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache);
if (problem) {
ret = 0;
mem_ccache = NULL;
goto out;
}
*/
mem_ccache = ccache;
ccache = NULL;
ret = 1;
out:
if (client != NULL)
krb5_free_principal(ssh_context, client);
if (ccache != NULL)
krb5_cc_destroy(ssh_context, ccache);
return ret;
}
void
krb5_cleanup_proc(void *ignore)
{
extern krb5_principal tkt_client;
debug("krb5_cleanup_proc() called");
if (mem_ccache)
krb5_cc_destroy(ssh_context, mem_ccache);
if (tkt_client)
krb5_free_principal(ssh_context, tkt_client);
if (auth_context)
krb5_auth_con_free(ssh_context, auth_context);
if (ssh_context)
krb5_free_context(ssh_context);
}
int
krb5_init(void)
{
krb5_error_code problem;
static cleanup_registered = 0;
if (ssh_context == NULL) {
problem = krb5_init_context(&ssh_context);
if (problem)
return problem;
krb5_init_ets(ssh_context);
}
if (!cleanup_registered) {
fatal_add_cleanup(krb5_cleanup_proc, NULL);
cleanup_registered = 1;
}
return 0;
}
#endif /* KRB5 */