Check retrieved TGT against local keytab, if it exists.

This commit is contained in:
aidan 2000-09-01 03:12:20 +00:00
parent 0bc8e23c3a
commit b84b9c883a
1 changed files with 144 additions and 2 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: k5login.c,v 1.14 2000/08/09 17:44:18 thorpej Exp $ */
/* $NetBSD: k5login.c,v 1.15 2000/09/01 03:12:20 aidan Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -33,12 +33,29 @@
* SUCH DAMAGE.
*/
/*
* Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)klogin.c 5.11 (Berkeley) 7/12/92";
#endif
__RCSID("$NetBSD: k5login.c,v 1.14 2000/08/09 17:44:18 thorpej Exp $");
__RCSID("$NetBSD: k5login.c,v 1.15 2000/09/01 03:12:20 aidan Exp $");
#endif /* not lint */
#ifdef KERBEROS5
@ -52,6 +69,7 @@ __RCSID("$NetBSD: k5login.c,v 1.14 2000/08/09 17:44:18 thorpej Exp $");
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define KRB5_DEFAULT_OPTIONS 0
#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */
@ -72,6 +90,7 @@ static krb5_principal me, server;
int k5_read_creds __P((char *));
int k5_write_creds __P((void));
int k5_verify_creds __P((krb5_context, krb5_ccache));
int k5login __P((struct passwd *, char *, char *, char *));
void k5destroy __P((void));
@ -82,6 +101,125 @@ void k5destroy __P((void));
#define krb5_realm_data(r) ((r).data)
#endif
/*
* Verify the Kerberos ticket-granting ticket just retrieved for the
* user. If the Kerberos server doesn't respond, assume the user is
* trying to fake us out (since we DID just get a TGT from what is
* supposedly our KDC). If the host/<host> service is unknown (i.e.,
* the local keytab doesn't have it), let her in.
*
* Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
*/
int
k5_verify_creds(c, ccache)
krb5_context c;
krb5_ccache ccache;
{
char phost[MAXHOSTNAMELEN];
int retval, have_keys;
krb5_principal princ;
krb5_keyblock *kb = 0;
krb5_error_code kerror;
krb5_data packet;
krb5_auth_context auth_context = NULL;
krb5_ticket *ticket = NULL;
kerror = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ);
if (kerror) {
com_err("login", kerror, "constructing local service name");
return (-1);
}
/* Do we have host/<host> keys? */
/* (use default keytab, kvno IGNORE_VNO to get the first match,
* and default enctype.) */
kerror = krb5_kt_read_service_key(c, NULL, princ, 0, 0, &kb);
if (kb)
krb5_free_keyblock(c, kb);
/* any failure means we don't have keys at all. */
have_keys = kerror ? 0 : 1;
/* XXX there should be a krb5 function like mk_req, but taking a full
* principal, instead of a service/hostname. (Did I miss one?) */
gethostname(phost, sizeof(phost));
phost[sizeof(phost) - 1] = '\0';
/* talk to the kdc and construct the ticket */
kerror = krb5_mk_req(c, &auth_context, 0, "host", phost,
0, ccache, &packet);
/* wipe the auth context for rd_req */
if (auth_context) {
krb5_auth_con_free(c, auth_context);
auth_context = NULL;
}
if (kerror == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
/* we have a service key, so something should be
* in the database, therefore this error packet could
* have come from an attacker. */
if (have_keys) {
retval = -1;
goto EGRESS;
}
/* but if it is unknown and we've got no key, we don't
* have any security anyhow, so it is ok. */
else {
retval = 0;
goto EGRESS;
}
}
else if (kerror) {
com_err("login", kerror,
"Unable to verify Kerberos V5 TGT: %s", phost);
syslog(LOG_NOTICE|LOG_AUTH, "Kerberos V5 TGT bad: %s",
error_message(kerror));
retval = -1;
goto EGRESS;
}
/* got ticket, try to use it */
kerror = krb5_rd_req(c, &auth_context, &packet,
princ, NULL, NULL, &ticket);
if (kerror) {
if (!have_keys) {
/* The krb5 errors aren't specified well, but I think
* these values cover the cases we expect. */
switch (kerror) {
case ENOENT: /* no keytab */
case KRB5_KT_NOTFOUND:
retval = 0;
break;
default:
/* unexpected error: fail */
retval = -1;
break;
}
}
else {
/* we have keys, so if we got any error, we could be
* under attack. */
retval = -1;
}
com_err("login", kerror, "Unable to verify host ticket");
syslog(LOG_NOTICE|LOG_AUTH, "can't verify v5 ticket: %s; %s\n",
error_message(kerror),
retval
? "keytab found, assuming failure"
: "no keytab found, assuming success");
goto EGRESS;
}
/*
* The host/<host> ticket has been received _and_ verified.
*/
retval = 1;
/* do cleanup and return */
EGRESS:
if (auth_context)
krb5_auth_con_free(c, auth_context);
krb5_free_principal(c, princ);
/* possibly ticket and packet need freeing here as well */
return (retval);
}
/*
* Attempt to read forwarded kerberos creds
*
@ -313,6 +451,10 @@ k5login(pw, instance, localhost, password)
return(1);
}
if (k5_verify_creds(kcontext, ccache) < 0) {
return(1);
}
/* Success */
notickets = 0;