aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libtelnet/kerberos5.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libtelnet/kerberos5.c')
-rw-r--r--lib/libtelnet/kerberos5.c888
1 files changed, 888 insertions, 0 deletions
diff --git a/lib/libtelnet/kerberos5.c b/lib/libtelnet/kerberos5.c
new file mode 100644
index 0000000..55c68ca
--- /dev/null
+++ b/lib/libtelnet/kerberos5.c
@@ -0,0 +1,888 @@
+/*
+ * appl/telnet/libtelnet/kerberos5.c
+ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+/* based on @(#)kerberos5.c 8.1 (Berkeley) 6/4/93 */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+
+#ifdef KRB5
+#include <arpa/telnet.h>
+#include <stdio.h>
+#define KRB5_DEPRECATED 1 /* krb5_auth_con_getremotesubkey */
+#include <krb5.h>
+#include "com_err.h"
+#include <netdb.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <sys/errno.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern char *malloc();
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include "encrypt.h"
+#include "auth.h"
+#include "misc.h"
+
+extern int auth_debug_mode;
+extern int net;
+
+#ifdef FORWARD
+int forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */
+
+void kerberos5_forward();
+krb5_error_code
+rd_and_store_for_creds(krb5_context context, krb5_auth_context auth_context, krb5_data *inbuf, krb5_ticket *ticket);
+
+#endif /* FORWARD */
+
+static unsigned char str_data[8192] = {IAC, SB, TELOPT_AUTHENTICATION, 0,
+ AUTHTYPE_KERBEROS_V5, };
+/*static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
+ TELQUAL_NAME, };*/
+
+#define AUTH_ENCRYPT_OFF 0
+#define AUTH_ENCRYPT_ON 4
+#define AUTH_ENCRYPT_MASK 4
+
+#define KRB_AUTH 0 /* Authentication data follows */
+#define KRB_REJECT 1 /* Rejected (reason might follow) */
+#define KRB_ACCEPT 2 /* Accepted */
+#define KRB_RESPONSE 3 /* Response for mutual auth. */
+
+#ifdef FORWARD
+#define KRB_FORWARD 4 /* Forwarded credentials follow */
+#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */
+#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */
+#endif /* FORWARD */
+
+krb5_auth_context auth_context = 0;
+
+static krb5_data auth;
+ /* telnetd gets session key from here */
+static krb5_ticket * ticket = NULL;
+/* telnet matches the AP_REQ and AP_REP with this */
+
+/* some compilers can't hack void *, so we use the Kerberos krb5_pointer,
+ which is either void * or char *, depending on the compiler. */
+
+#define Voidptr krb5_pointer
+
+krb5_keyblock *session_key = 0;
+char * telnet_srvtab = NULL;
+char * telnet_krb5_realm = NULL;
+
+ static int
+Data(ap, type, d, c)
+ Authenticator *ap;
+ int type;
+ Voidptr d;
+ int c;
+{
+ unsigned char *p = str_data + 4;
+ unsigned char *cd = (unsigned char *)d;
+ size_t spaceleft = sizeof(str_data) - 4;
+
+ if (c == -1)
+ c = strlen((char *)cd);
+
+ if (auth_debug_mode) {
+ printf("%s:%d: [%d] (%d)",
+ str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
+ str_data[3],
+ type, c);
+ printd(d, c);
+ printf("\r\n");
+ }
+ *p++ = ap->type;
+ *p++ = ap->way;
+ *p++ = type;
+ spaceleft -= 3;
+ while (c-- > 0) {
+ if ((*p++ = *cd++) == IAC) {
+ *p++ = IAC;
+ spaceleft--;
+ }
+ if ((--spaceleft < 4) && c) {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ *p++ = IAC;
+ *p++ = SE;
+ if (str_data[3] == TELQUAL_IS)
+ printsub('>', &str_data[2], p - &str_data[2]);
+ return(net_write(str_data, p - str_data));
+}
+
+krb5_context telnet_context = 0;
+int
+kerberos5_init(ap, server)
+ Authenticator *ap;
+ int server;
+{
+ krb5_error_code retval;
+
+ if (server)
+ str_data[3] = TELQUAL_REPLY;
+ else
+ str_data[3] = TELQUAL_IS;
+ if (telnet_context == 0) {
+ retval = krb5_init_context(&telnet_context);
+ if (retval)
+ return 0;
+ }
+ return(1);
+}
+
+void
+kerberos5_cleanup()
+{
+ krb5_error_code retval;
+ krb5_ccache ccache;
+ char *ccname;
+
+ if (telnet_context == 0)
+ return;
+
+ ccname = getenv("KRB5CCNAME");
+ if (ccname) {
+ retval = krb5_cc_resolve(telnet_context, ccname, &ccache);
+ if (!retval)
+ retval = krb5_cc_destroy(telnet_context, ccache);
+ }
+
+ krb5_free_context(telnet_context);
+ telnet_context = 0;
+}
+
+
+ int
+kerberos5_send(ap)
+ Authenticator *ap;
+{
+ krb5_error_code r;
+ krb5_ccache ccache;
+ krb5_creds creds; /* telnet gets session key from here */
+ krb5_creds * new_creds = 0;
+ int ap_opts;
+ char type_check[2];
+ krb5_data check_data;
+
+#ifdef ENCRYPTION
+ krb5_keyblock *newkey = 0;
+#endif /* ENCRYPTION */
+
+ if (!UserNameRequested) {
+ if (auth_debug_mode) {
+ printf(
+ "telnet: Kerberos V5: no user name supplied\r\n");
+ }
+ return(0);
+ }
+
+ if ((r = krb5_cc_default(telnet_context, &ccache))) {
+ if (auth_debug_mode) {
+ printf(
+ "telnet: Kerberos V5: could not get default ccache\r\n");
+ }
+ return(0);
+ }
+
+ memset((char *)&creds, 0, sizeof(creds));
+ if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName,
+ "host", KRB5_NT_SRV_HST,
+ &creds.server))) {
+ if (auth_debug_mode)
+ printf("telnet: Kerberos V5: error while constructing service name: %s\r\n", error_message(r));
+ return(0);
+ }
+
+ if (telnet_krb5_realm != NULL) {
+ krb5_data rdata;
+
+ rdata.length = strlen(telnet_krb5_realm);
+ rdata.data = (char *) malloc(rdata.length + 1);
+ if (rdata.data == NULL) {
+ fprintf(stderr, "malloc failed\n");
+ return(0);
+ }
+ strcpy(rdata.data, telnet_krb5_realm);
+ krb5_princ_set_realm(telnet_context, creds.server, &rdata);
+ }
+
+ if ((r = krb5_cc_get_principal(telnet_context, ccache,
+ &creds.client))) {
+ if (auth_debug_mode) {
+ printf(
+ "telnet: Kerberos V5: failure on principal (%s)\r\n",
+ error_message(r));
+ }
+ krb5_free_cred_contents(telnet_context, &creds);
+ return(0);
+ }
+
+ creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC;
+ if ((r = krb5_get_credentials(telnet_context, 0,
+ ccache, &creds, &new_creds))) {
+ if (auth_debug_mode) {
+ printf(
+ "telnet: Kerberos V5: failure on credentials(%s)\r\n",
+ error_message(r));
+ }
+ krb5_free_cred_contents(telnet_context, &creds);
+ return(0);
+ }
+
+ if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
+ ap_opts = AP_OPTS_MUTUAL_REQUIRED;
+ else
+ ap_opts = 0;
+
+#ifdef ENCRYPTION
+ ap_opts |= AP_OPTS_USE_SUBKEY;
+#endif /* ENCRYPTION */
+
+ if (auth_context) {
+ krb5_auth_con_free(telnet_context, auth_context);
+ auth_context = 0;
+ }
+ if ((r = krb5_auth_con_init(telnet_context, &auth_context))) {
+ if (auth_debug_mode) {
+ printf("Kerberos V5: failed to init auth_context (%s)\r\n",
+ error_message(r));
+ }
+ return(0);
+ }
+
+ krb5_auth_con_setflags(telnet_context, auth_context,
+ KRB5_AUTH_CONTEXT_RET_TIME);
+
+ type_check[0] = ap->type;
+ type_check[1] = ap->way;
+ check_data.magic = KV5M_DATA;
+ check_data.length = 2;
+ check_data.data = (char *) &type_check;
+
+ r = krb5_mk_req_extended(telnet_context, &auth_context, ap_opts,
+ &check_data, new_creds, &auth);
+
+#ifdef ENCRYPTION
+ krb5_auth_con_getlocalsubkey(telnet_context, auth_context, &newkey);
+ if (session_key) {
+ krb5_free_keyblock(telnet_context, session_key);
+ session_key = 0;
+ }
+
+ if (newkey) {
+ /* keep the key in our private storage, but don't use it
+ yet---see kerberos5_reply() below */
+ if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) &&
+ (newkey-> enctype != ENCTYPE_DES_CBC_MD5)) {
+ if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) ||
+ (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5))
+ /* use the session key in credentials instead */
+ krb5_copy_keyblock(telnet_context,&new_creds->keyblock,
+ &session_key);
+ else
+ /* XXX ? */;
+ } else {
+ krb5_copy_keyblock(telnet_context, newkey, &session_key);
+ }
+ krb5_free_keyblock(telnet_context, newkey);
+ }
+#endif /* ENCRYPTION */
+ krb5_free_cred_contents(telnet_context, &creds);
+ krb5_free_creds(telnet_context, new_creds);
+ if (r) {
+ if (auth_debug_mode) {
+ printf("telnet: Kerberos V5: mk_req failed (%s)\r\n",
+ error_message(r));
+ }
+ return(0);
+ }
+
+ if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
+ if (auth_debug_mode)
+ printf("telnet: Not enough room for user name\r\n");
+ return(0);
+ }
+ if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
+ if (auth_debug_mode)
+ printf(
+ "telnet: Not enough room for authentication data\r\n");
+ return(0);
+ }
+ if (auth_debug_mode) {
+ printf("telnet: Sent Kerberos V5 credentials to server\r\n");
+ }
+ return(1);
+}
+
+ void
+kerberos5_is(ap, data, cnt)
+ Authenticator *ap;
+ unsigned char *data;
+ int cnt;
+{
+ int r = 0;
+ krb5_principal server;
+ krb5_keyblock *newkey = NULL;
+ krb5_keytab keytabid = 0;
+ krb5_data outbuf;
+#ifdef ENCRYPTION
+ Session_Key skey;
+#endif
+ char errbuf[320];
+ char *name;
+ char *getenv();
+ krb5_data inbuf;
+ krb5_authenticator *authenticator;
+
+ if (cnt-- < 1)
+ return;
+ switch (*data++) {
+ case KRB_AUTH:
+ auth.data = (char *)data;
+ auth.length = cnt;
+
+ if (!r && !auth_context)
+ r = krb5_auth_con_init(telnet_context, &auth_context);
+ if (!r) {
+ krb5_rcache rcache;
+
+ r = krb5_auth_con_getrcache(telnet_context, auth_context,
+ &rcache);
+ if (!r && !rcache) {
+ r = krb5_sname_to_principal(telnet_context, 0, 0,
+ KRB5_NT_SRV_HST, &server);
+ if (!r) {
+ r = krb5_get_server_rcache(telnet_context,
+ krb5_princ_component(telnet_context,
+ server, 0),
+ &rcache);
+ krb5_free_principal(telnet_context, server);
+ }
+ }
+ if (!r)
+ r = krb5_auth_con_setrcache(telnet_context,
+ auth_context, rcache);
+ }
+ if (!r && telnet_srvtab)
+ r = krb5_kt_resolve(telnet_context,
+ telnet_srvtab, &keytabid);
+ if (!r)
+ r = krb5_rd_req(telnet_context, &auth_context, &auth,
+ NULL, keytabid, NULL, &ticket);
+ if (r) {
+ (void) strcpy(errbuf, "krb5_rd_req failed: ");
+ errbuf[sizeof(errbuf) - 1] = '\0';
+ (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+ goto errout;
+ }
+
+ /*
+ * 256 bytes should be much larger than any reasonable
+ * first component of a service name especially since
+ * the default is of length 4.
+ */
+ if (krb5_princ_component(telnet_context,ticket->server,0)->length < 256) {
+ char princ[256];
+ strncpy(princ,
+ krb5_princ_component(telnet_context, ticket->server,0)->data,
+ krb5_princ_component(telnet_context, ticket->server,0)->length);
+ princ[krb5_princ_component(telnet_context,
+ ticket->server,0)->length] = '\0';
+ if (strcmp("host", princ)) {
+ if(strlen(princ) < sizeof(errbuf) - 39) {
+ (void) sprintf(errbuf, "incorrect service name: \"%s\" != \"host\"",
+ princ);
+ } else {
+ (void) sprintf(errbuf, "incorrect service name: principal != \"host\"");
+ }
+ goto errout;
+ }
+ } else {
+ (void) strcpy(errbuf, "service name too long");
+ goto errout;
+ }
+
+ r = krb5_auth_con_getauthenticator(telnet_context,
+ auth_context,
+ &authenticator);
+ if (r) {
+ (void) strcpy(errbuf,
+ "krb5_auth_con_getauthenticator failed: ");
+ errbuf[sizeof(errbuf) - 1] = '\0';
+ (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+ goto errout;
+ }
+ if ((ap->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON &&
+ !authenticator->checksum) {
+ (void) strcpy(errbuf,
+ "authenticator is missing required checksum");
+ goto errout;
+ }
+ if (authenticator->checksum) {
+ char type_check[2];
+ krb5_checksum *cksum = authenticator->checksum;
+ krb5_keyblock *key;
+
+ type_check[0] = ap->type;
+ type_check[1] = ap->way;
+
+ r = krb5_auth_con_getkey(telnet_context, auth_context,
+ &key);
+ if (r) {
+ (void) strcpy(errbuf, "krb5_auth_con_getkey failed: ");
+ errbuf[sizeof(errbuf) - 1] = '\0';
+ (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+ goto errout;
+ }
+ r = krb5_verify_checksum(telnet_context,
+ cksum->checksum_type, cksum,
+ &type_check, 2, key->contents,
+ key->length);
+ /*
+ * Note that krb5_verify_checksum() will fail if a pre-
+ * MIT Kerberos Beta 5 client is attempting to connect
+ * to this server (Beta 6 or later). There is not way to
+ * fix this without compromising encryption. It would be
+ * reasonable to add a -i option to telnetd to ignore
+ * checksums (like in klogind). Such an option is not
+ * present at this time.
+ */
+ if (r) {
+ (void) strcpy(errbuf,
+ "checksum verification failed: ");
+ errbuf[sizeof(errbuf) - 1] = '\0';
+ (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+ goto errout;
+ }
+ krb5_free_keyblock(telnet_context, key);
+ }
+ krb5_free_authenticator(telnet_context, authenticator);
+ if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+ /* do ap_rep stuff here */
+ if ((r = krb5_mk_rep(telnet_context, auth_context,
+ &outbuf))) {
+ (void) strcpy(errbuf, "Make reply failed: ");
+ errbuf[sizeof(errbuf) - 1] = '\0';
+ (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+ goto errout;
+ }
+
+ Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
+ }
+ if (krb5_unparse_name(telnet_context,
+ ticket->enc_part2 ->client,
+ &name))
+ name = 0;
+ Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
+ if (auth_debug_mode) {
+ printf(
+ "telnetd: Kerberos5 identifies him as ``%s''\r\n",
+ name ? name : "");
+ }
+ auth_finished(ap, AUTH_USER);
+
+ if (name)
+ free(name);
+ krb5_auth_con_getremotesubkey(telnet_context, auth_context,
+ &newkey);
+ if (session_key) {
+ krb5_free_keyblock(telnet_context, session_key);
+ session_key = 0;
+ }
+ if (newkey) {
+ krb5_copy_keyblock(telnet_context, newkey, &session_key);
+ krb5_free_keyblock(telnet_context, newkey);
+ } else {
+ krb5_copy_keyblock(telnet_context,
+ ticket->enc_part2->session,
+ &session_key);
+ }
+
+#ifdef ENCRYPTION
+ skey.type = SK_DES;
+ skey.length = 8;
+ skey.data = session_key->contents;
+ encrypt_session_key(&skey, 1);
+#endif
+ break;
+#ifdef FORWARD
+ case KRB_FORWARD:
+ inbuf.length = cnt;
+ inbuf.data = (char *)data;
+ if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context,
+ net, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) ||
+ (r = rd_and_store_for_creds(telnet_context, auth_context,
+ &inbuf, ticket))) {
+
+ char errbuf[128];
+
+ (void) strcpy(errbuf, "Read forwarded creds failed: ");
+ errbuf[sizeof(errbuf) - 1] = '\0';
+ (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+ Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
+ if (auth_debug_mode)
+ printf(
+ "telnetd: Could not read forwarded credentials\r\n");
+ }
+ else
+ Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
+ if (auth_debug_mode)
+ printf("telnetd: Forwarded credentials obtained\r\n");
+ break;
+#endif /* FORWARD */
+ default:
+ if (auth_debug_mode)
+ printf("telnetd: Unknown Kerberos option %d\r\n",
+ data[-1]);
+ Data(ap, KRB_REJECT, 0, 0);
+ break;
+ }
+ return;
+
+ errout:
+ {
+ char eerrbuf[329];
+
+ strcpy(eerrbuf, "telnetd: ");
+ eerrbuf[sizeof(eerrbuf) - 1] = '\0';
+ strncat(eerrbuf, errbuf, sizeof(eerrbuf) - 1 - strlen(eerrbuf));
+ Data(ap, KRB_REJECT, eerrbuf, -1);
+ }
+ if (auth_debug_mode)
+ printf("telnetd: %s\r\n", errbuf);
+ syslog(LOG_ERR, "%s", errbuf);
+ if (auth_context) {
+ krb5_auth_con_free(telnet_context, auth_context);
+ auth_context = 0;
+ }
+ return;
+}
+
+ void
+kerberos5_reply(ap, data, cnt)
+ Authenticator *ap;
+ unsigned char *data;
+ int cnt;
+{
+#ifdef ENCRYPTION
+ Session_Key skey;
+#endif
+ static int mutual_complete = 0;
+
+ if (cnt-- < 1)
+ return;
+ switch (*data++) {
+ case KRB_REJECT:
+ if (cnt > 0) {
+ printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
+ cnt, data);
+ } else
+ printf("[ Kerberos V5 refuses authentication ]\r\n");
+ auth_send_retry();
+ return;
+ case KRB_ACCEPT:
+ if (!mutual_complete) {
+ if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+ printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
+ auth_send_retry();
+ return;
+ }
+#ifdef ENCRYPTION
+ if (session_key) {
+ skey.type = SK_DES;
+ skey.length = 8;
+ skey.data = session_key->contents;
+ encrypt_session_key(&skey, 0);
+ }
+#endif /* ENCRYPTION */
+ }
+ if (cnt)
+ printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
+ else
+ printf("[ Kerberos V5 accepts you ]\r\n");
+ auth_finished(ap, AUTH_USER);
+#ifdef FORWARD
+ if (forward_flags & OPTS_FORWARD_CREDS)
+ kerberos5_forward(ap);
+#endif /* FORWARD */
+ break;
+ case KRB_RESPONSE:
+ if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+ /* the rest of the reply should contain a krb_ap_rep */
+ krb5_ap_rep_enc_part *reply;
+ krb5_data inbuf;
+ krb5_error_code r;
+
+ inbuf.length = cnt;
+ inbuf.data = (char *)data;
+
+ if ((r = krb5_rd_rep(telnet_context, auth_context, &inbuf,
+ &reply))) {
+ printf("[ Mutual authentication failed: %s ]\r\n",
+ error_message(r));
+ auth_send_retry();
+ return;
+ }
+ krb5_free_ap_rep_enc_part(telnet_context, reply);
+#ifdef ENCRYPTION
+ if (session_key) {
+ skey.type = SK_DES;
+ skey.length = 8;
+ skey.data = session_key->contents;
+ encrypt_session_key(&skey, 0);
+ }
+#endif /* ENCRYPTION */
+ mutual_complete = 1;
+ }
+ return;
+#ifdef FORWARD
+ case KRB_FORWARD_ACCEPT:
+ printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
+ return;
+ case KRB_FORWARD_REJECT:
+ printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
+ cnt, data);
+ return;
+#endif /* FORWARD */
+ default:
+ if (auth_debug_mode)
+ printf("Unknown Kerberos option %d\r\n", data[-1]);
+ return;
+ }
+ return;
+}
+
+ int
+kerberos5_status(ap, name, level)
+ Authenticator *ap;
+ char *name;
+ int level;
+{
+ if (level < AUTH_USER)
+ return(level);
+
+ if (UserNameRequested &&
+ krb5_kuserok(telnet_context, ticket->enc_part2->client,
+ UserNameRequested))
+ {
+ /* the name buffer comes from telnetd/telnetd{-ktd}.c */
+ strncpy(name, UserNameRequested, 255);
+ name[255] = '\0';
+ return(AUTH_VALID);
+ } else
+ return(AUTH_USER);
+}
+
+#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
+#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
+
+ void
+kerberos5_printsub(data, cnt, buf, buflen)
+ unsigned char *data, *buf;
+ int cnt, buflen;
+{
+ char lbuf[32];
+ register int i;
+
+ buf[buflen-1] = '\0'; /* make sure its NULL terminated */
+ buflen -= 1;
+
+ switch(data[3]) {
+ case KRB_REJECT: /* Rejected (reason might follow) */
+ strncpy((char *)buf, " REJECT ", buflen);
+ goto common;
+
+ case KRB_ACCEPT: /* Accepted (name might follow) */
+ strncpy((char *)buf, " ACCEPT ", buflen);
+ common:
+ BUMP(buf, buflen);
+ if (cnt <= 4)
+ break;
+ ADDC(buf, buflen, '"');
+ for (i = 4; i < cnt; i++)
+ ADDC(buf, buflen, data[i]);
+ ADDC(buf, buflen, '"');
+ ADDC(buf, buflen, '\0');
+ break;
+
+
+ case KRB_AUTH: /* Authentication data follows */
+ strncpy((char *)buf, " AUTH", buflen);
+ goto common2;
+
+ case KRB_RESPONSE:
+ strncpy((char *)buf, " RESPONSE", buflen);
+ goto common2;
+
+#ifdef FORWARD
+ case KRB_FORWARD: /* Forwarded credentials follow */
+ strncpy((char *)buf, " FORWARD", buflen);
+ goto common2;
+
+ case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */
+ strncpy((char *)buf, " FORWARD_ACCEPT", buflen);
+ goto common2;
+
+ case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */
+ /* (reason might follow) */
+ strncpy((char *)buf, " FORWARD_REJECT", buflen);
+ goto common2;
+#endif /* FORWARD */
+
+ default:
+ sprintf(lbuf, " %d (unknown)", data[3]);
+ strncpy((char *)buf, lbuf, buflen);
+ common2:
+ BUMP(buf, buflen);
+ for (i = 4; i < cnt; i++) {
+ sprintf(lbuf, " %d", data[i]);
+ strncpy((char *)buf, lbuf, buflen);
+ BUMP(buf, buflen);
+ }
+ break;
+ }
+}
+
+#ifdef FORWARD
+
+void
+kerberos5_forward(ap)
+ Authenticator *ap;
+{
+ krb5_error_code r;
+ krb5_ccache ccache;
+ krb5_principal client = 0;
+ krb5_principal server = 0;
+ krb5_data forw_creds;
+
+ forw_creds.data = 0;
+
+ if ((r = krb5_cc_default(telnet_context, &ccache))) {
+ if (auth_debug_mode)
+ printf("Kerberos V5: could not get default ccache - %s\r\n",
+ error_message(r));
+ return;
+ }
+
+ if ((r = krb5_cc_get_principal(telnet_context, ccache, &client))) {
+ if (auth_debug_mode)
+ printf("Kerberos V5: could not get default principal - %s\r\n",
+ error_message(r));
+ goto cleanup;
+ }
+
+ if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName, "host",
+ KRB5_NT_SRV_HST, &server))) {
+ if (auth_debug_mode)
+ printf("Kerberos V5: could not make server principal - %s\r\n",
+ error_message(r));
+ goto cleanup;
+ }
+
+ if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context, net,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) {
+ if (auth_debug_mode)
+ printf("Kerberos V5: could not gen local full address - %s\r\n",
+ error_message(r));
+ goto cleanup;
+ }
+
+ if ((r = krb5_fwd_tgt_creds(telnet_context, auth_context, 0, client,
+ server, ccache,
+ forward_flags & OPTS_FORWARDABLE_CREDS,
+ &forw_creds))) {
+ if (auth_debug_mode)
+ printf("Kerberos V5: error getting forwarded creds - %s\r\n",
+ error_message(r));
+ goto cleanup;
+ }
+
+ /* Send forwarded credentials */
+ if (!Data(ap, KRB_FORWARD, forw_creds.data, forw_creds.length)) {
+ if (auth_debug_mode)
+ printf("Not enough room for authentication data\r\n");
+ } else {
+ if (auth_debug_mode)
+ printf("Forwarded local Kerberos V5 credentials to server\r\n");
+ }
+
+cleanup:
+ if (client)
+ krb5_free_principal(telnet_context, client);
+ if (server)
+ krb5_free_principal(telnet_context, server);
+ if (forw_creds.data)
+ free(forw_creds.data);
+ krb5_cc_close(telnet_context, ccache);
+}
+#endif /* FORWARD */
+
+#endif /* KRB5 */