cb96ab3672
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
250 lines
4.9 KiB
C
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 */
|