157416Smarkm/*-
257416Smarkm * Copyright (c) 1991, 1993
357416Smarkm *	The Regents of the University of California.  All rights reserved.
457416Smarkm *
557416Smarkm * Redistribution and use in source and binary forms, with or without
657416Smarkm * modification, are permitted provided that the following conditions
757416Smarkm * are met:
857416Smarkm * 1. Redistributions of source code must retain the above copyright
957416Smarkm *    notice, this list of conditions and the following disclaimer.
1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1157416Smarkm *    notice, this list of conditions and the following disclaimer in the
1257416Smarkm *    documentation and/or other materials provided with the distribution.
1357416Smarkm * 3. All advertising materials mentioning features or use of this software
1457416Smarkm *    must display the following acknowledgement:
1557416Smarkm *	This product includes software developed by the University of
1657416Smarkm *	California, Berkeley and its contributors.
1757416Smarkm * 4. Neither the name of the University nor the names of its contributors
1857416Smarkm *    may be used to endorse or promote products derived from this software
1957416Smarkm *    without specific prior written permission.
2057416Smarkm *
2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2457416Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3157416Smarkm * SUCH DAMAGE.
3257416Smarkm */
3357416Smarkm
3457416Smarkm/*
3557416Smarkm * Copyright (C) 1990 by the Massachusetts Institute of Technology
3657416Smarkm *
3757416Smarkm * Export of this software from the United States of America may
3857416Smarkm * require a specific license from the United States Government.
3957416Smarkm * It is the responsibility of any person or organization contemplating
4057416Smarkm * export to obtain such a license before exporting.
4157416Smarkm *
4257416Smarkm * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
4357416Smarkm * distribute this software and its documentation for any purpose and
4457416Smarkm * without fee is hereby granted, provided that the above copyright
4557416Smarkm * notice appear in all copies and that both that copyright notice and
4657416Smarkm * this permission notice appear in supporting documentation, and that
4757416Smarkm * the name of M.I.T. not be used in advertising or publicity pertaining
4857416Smarkm * to distribution of the software without specific, written prior
4957416Smarkm * permission.  M.I.T. makes no representations about the suitability of
5057416Smarkm * this software for any purpose.  It is provided "as is" without express
5157416Smarkm * or implied warranty.
5257416Smarkm */
5357416Smarkm
5457416Smarkm#include <config.h>
5557416Smarkm
56233294SstasRCSID("$Id$");
5757416Smarkm
5857416Smarkm#ifdef	KRB5
5957416Smarkm
6057416Smarkm#include <arpa/telnet.h>
6157416Smarkm#include <stdio.h>
6257416Smarkm#include <stdlib.h>
6357416Smarkm#include <string.h>
6457416Smarkm#include <unistd.h>
6557416Smarkm#include <netdb.h>
6657416Smarkm#include <ctype.h>
6757416Smarkm#include <pwd.h>
6857416Smarkm#define Authenticator k5_Authenticator
6957416Smarkm#include <krb5.h>
7057416Smarkm#undef Authenticator
7157416Smarkm#include <roken.h>
7257416Smarkm#ifdef SOCKS
7357416Smarkm#include <socks.h>
7457416Smarkm#endif
7557416Smarkm
7657416Smarkm
7757416Smarkm#include "encrypt.h"
7857416Smarkm#include "auth.h"
7957416Smarkm#include "misc.h"
8057416Smarkm
8172445Sassar#if defined(DCE)
8272445Sassarint dfsk5ok = 0;
8372445Sassarint dfspag = 0;
8472445Sassarint dfsfwd = 0;
8572445Sassar#endif
8672445Sassar
8757416Smarkmint forward_flags = 0;  /* Flags get set in telnet/main.c on -f and -F */
8857416Smarkm
89102644Snectarint forward(int);
90102644Snectarint forwardable(int);
91102644Snectar
9257416Smarkm/* These values need to be the same as those defined in telnet/main.c. */
9357416Smarkm/* Either define them in both places, or put in some common header file. */
9457416Smarkm#define OPTS_FORWARD_CREDS	0x00000002
9557416Smarkm#define OPTS_FORWARDABLE_CREDS	0x00000001
9657416Smarkm
97102644Snectar
9857416Smarkmvoid kerberos5_forward (Authenticator *);
9957416Smarkm
100142403Snectarstatic unsigned char str_data[4] = { IAC, SB, TELOPT_AUTHENTICATION, 0 };
10157416Smarkm
10257416Smarkm#define	KRB_AUTH		0	/* Authentication data follows */
10357416Smarkm#define	KRB_REJECT		1	/* Rejected (reason might follow) */
10457416Smarkm#define	KRB_ACCEPT		2	/* Accepted */
10557416Smarkm#define	KRB_RESPONSE		3	/* Response for mutual auth. */
10657416Smarkm
10757416Smarkm#define KRB_FORWARD     	4       /* Forwarded credentials follow */
10857416Smarkm#define KRB_FORWARD_ACCEPT     	5       /* Forwarded credentials accepted */
10957416Smarkm#define KRB_FORWARD_REJECT     	6       /* Forwarded credentials rejected */
11057416Smarkm
11157416Smarkmstatic	krb5_data auth;
11257416Smarkmstatic  krb5_ticket *ticket;
11357416Smarkm
11457416Smarkmstatic krb5_context context;
11557416Smarkmstatic krb5_auth_context auth_context;
11657416Smarkm
11757416Smarkmstatic int
118178825SdfrData(Authenticator *ap, int type, const void *d, int c)
11957416Smarkm{
120178825Sdfr    const unsigned char *cp, *cd = d;
121142403Snectar    unsigned char *p0, *p;
122142403Snectar    size_t len = sizeof(str_data) + 3 + 2;
123142403Snectar    int ret;
12457416Smarkm
12557416Smarkm    if (c == -1)
126178825Sdfr	c = strlen((const char*)cd);
12757416Smarkm
128178825Sdfr    for (cp = cd; cp - cd < c; cp++, len++)
129178825Sdfr	if (*cp == IAC)
130142403Snectar	    len++;
131142403Snectar
132142403Snectar    p0 = malloc(len);
133142403Snectar    if (p0 == NULL)
134142403Snectar	return 0;
135233294Sstas
136142403Snectar    memcpy(p0, str_data, sizeof(str_data));
137142403Snectar    p = p0 + sizeof(str_data);
138233294Sstas
13957416Smarkm    if (auth_debug_mode) {
14057416Smarkm	printf("%s:%d: [%d] (%d)",
14157416Smarkm	       str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
14257416Smarkm	       str_data[3],
14357416Smarkm	       type, c);
14457416Smarkm	printd(d, c);
14557416Smarkm	printf("\r\n");
14657416Smarkm    }
14757416Smarkm    *p++ = ap->type;
14857416Smarkm    *p++ = ap->way;
14957416Smarkm    *p++ = type;
15057416Smarkm    while (c-- > 0) {
15157416Smarkm	if ((*p++ = *cd++) == IAC)
15257416Smarkm	    *p++ = IAC;
15357416Smarkm    }
15457416Smarkm    *p++ = IAC;
15557416Smarkm    *p++ = SE;
15657416Smarkm    if (str_data[3] == TELQUAL_IS)
157142403Snectar	printsub('>', &p0[2], len - 2);
158142403Snectar    ret = telnet_net_write(p0, len);
159142403Snectar    free(p0);
160142403Snectar    return ret;
16157416Smarkm}
16257416Smarkm
16357416Smarkmint
16457416Smarkmkerberos5_init(Authenticator *ap, int server)
16557416Smarkm{
16672445Sassar    krb5_error_code ret;
16772445Sassar
16872445Sassar    ret = krb5_init_context(&context);
16972445Sassar    if (ret)
17072445Sassar	return 0;
17172445Sassar    if (server) {
17272445Sassar	krb5_keytab kt;
17372445Sassar	krb5_kt_cursor cursor;
17472445Sassar
17572445Sassar	ret = krb5_kt_default(context, &kt);
17672445Sassar	if (ret)
17772445Sassar	    return 0;
17872445Sassar
17972445Sassar	ret = krb5_kt_start_seq_get (context, kt, &cursor);
18072445Sassar	if (ret) {
18172445Sassar	    krb5_kt_close (context, kt);
18272445Sassar	    return 0;
18372445Sassar	}
18472445Sassar	krb5_kt_end_seq_get (context, kt, &cursor);
18572445Sassar	krb5_kt_close (context, kt);
18672445Sassar
18757416Smarkm	str_data[3] = TELQUAL_REPLY;
18872445Sassar    } else
18957416Smarkm	str_data[3] = TELQUAL_IS;
19057416Smarkm    return(1);
19157416Smarkm}
19257416Smarkm
19372445Sassarextern int net;
19457416Smarkmstatic int
19557416Smarkmkerberos5_send(char *name, Authenticator *ap)
19657416Smarkm{
19757416Smarkm    krb5_error_code ret;
19857416Smarkm    krb5_ccache ccache;
19957416Smarkm    int ap_opts;
20057416Smarkm    krb5_data cksum_data;
201178825Sdfr    char ap_msg[2];
202233294Sstas
20357416Smarkm    if (!UserNameRequested) {
20457416Smarkm	if (auth_debug_mode) {
20557416Smarkm	    printf("Kerberos V5: no user name supplied\r\n");
20657416Smarkm	}
20757416Smarkm	return(0);
20857416Smarkm    }
209233294Sstas
21057416Smarkm    ret = krb5_cc_default(context, &ccache);
21157416Smarkm    if (ret) {
21257416Smarkm	if (auth_debug_mode) {
21357416Smarkm	    printf("Kerberos V5: could not get default ccache: %s\r\n",
21457416Smarkm		   krb5_get_err_text (context, ret));
21557416Smarkm	}
21657416Smarkm	return 0;
21757416Smarkm    }
218233294Sstas
21957416Smarkm    if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
22057416Smarkm	ap_opts = AP_OPTS_MUTUAL_REQUIRED;
22157416Smarkm    else
22257416Smarkm	ap_opts = 0;
223103423Snectar
224103423Snectar    ap_opts |= AP_OPTS_USE_SUBKEY;
225233294Sstas
22657416Smarkm    ret = krb5_auth_con_init (context, &auth_context);
22757416Smarkm    if (ret) {
22857416Smarkm	if (auth_debug_mode) {
22957416Smarkm	    printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n",
23057416Smarkm		   krb5_get_err_text(context, ret));
23157416Smarkm	}
23257416Smarkm	return(0);
23357416Smarkm    }
23457416Smarkm
23557416Smarkm    ret = krb5_auth_con_setaddrs_from_fd (context,
23657416Smarkm					  auth_context,
23757416Smarkm					  &net);
23857416Smarkm    if (ret) {
23957416Smarkm	if (auth_debug_mode) {
24057416Smarkm	    printf ("Kerberos V5:"
24157416Smarkm		    " krb5_auth_con_setaddrs_from_fd failed (%s)\r\n",
24257416Smarkm		    krb5_get_err_text(context, ret));
24357416Smarkm	}
24457416Smarkm	return(0);
24557416Smarkm    }
24657416Smarkm
247233294Sstas    krb5_auth_con_setkeytype (context, auth_context, KRB5_ENCTYPE_DES_CBC_CRC);
24857416Smarkm
249178825Sdfr    ap_msg[0] = ap->type;
250178825Sdfr    ap_msg[1] = ap->way;
25157416Smarkm
252178825Sdfr    cksum_data.length = sizeof(ap_msg);
253178825Sdfr    cksum_data.data   = ap_msg;
25457416Smarkm
25572445Sassar
25672445Sassar    {
25772445Sassar	krb5_principal service;
25872445Sassar	char sname[128];
25972445Sassar
26072445Sassar
26172445Sassar	ret = krb5_sname_to_principal (context,
26272445Sassar				       RemoteHostName,
26372445Sassar				       NULL,
26472445Sassar				       KRB5_NT_SRV_HST,
26572445Sassar				       &service);
26672445Sassar	if(ret) {
26772445Sassar	    if (auth_debug_mode) {
26872445Sassar		printf ("Kerberos V5:"
26972445Sassar			" krb5_sname_to_principal(%s) failed (%s)\r\n",
27072445Sassar			RemoteHostName, krb5_get_err_text(context, ret));
27172445Sassar	    }
27272445Sassar	    return 0;
27372445Sassar	}
27472445Sassar	ret = krb5_unparse_name_fixed(context, service, sname, sizeof(sname));
27572445Sassar	if(ret) {
27672445Sassar	    if (auth_debug_mode) {
27772445Sassar		printf ("Kerberos V5:"
27872445Sassar			" krb5_unparse_name_fixed failed (%s)\r\n",
27972445Sassar			krb5_get_err_text(context, ret));
28072445Sassar	    }
28172445Sassar	    return 0;
28272445Sassar	}
28372445Sassar	printf("[ Trying %s (%s)... ]\r\n", name, sname);
28472445Sassar	ret = krb5_mk_req_exact(context, &auth_context, ap_opts,
285233294Sstas				service,
28672445Sassar				&cksum_data, ccache, &auth);
28772445Sassar	krb5_free_principal (context, service);
28872445Sassar
28972445Sassar    }
29057416Smarkm    if (ret) {
29157416Smarkm	if (1 || auth_debug_mode) {
29257416Smarkm	    printf("Kerberos V5: mk_req failed (%s)\r\n",
29357416Smarkm		   krb5_get_err_text(context, ret));
29457416Smarkm	}
29557416Smarkm	return(0);
29657416Smarkm    }
29757416Smarkm
29857416Smarkm    if (!auth_sendname((unsigned char *)UserNameRequested,
29957416Smarkm		       strlen(UserNameRequested))) {
30057416Smarkm	if (auth_debug_mode)
30157416Smarkm	    printf("Not enough room for user name\r\n");
30257416Smarkm	return(0);
30357416Smarkm    }
30457416Smarkm    if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
30557416Smarkm	if (auth_debug_mode)
30657416Smarkm	    printf("Not enough room for authentication data\r\n");
30757416Smarkm	return(0);
30857416Smarkm    }
30957416Smarkm    if (auth_debug_mode) {
31057416Smarkm	printf("Sent Kerberos V5 credentials to server\r\n");
31157416Smarkm    }
31257416Smarkm    return(1);
31357416Smarkm}
31457416Smarkm
31557416Smarkmint
31657416Smarkmkerberos5_send_mutual(Authenticator *ap)
31757416Smarkm{
31857416Smarkm    return kerberos5_send("mutual KERBEROS5", ap);
31957416Smarkm}
32057416Smarkm
32157416Smarkmint
32257416Smarkmkerberos5_send_oneway(Authenticator *ap)
32357416Smarkm{
32457416Smarkm    return kerberos5_send("KERBEROS5", ap);
32557416Smarkm}
32657416Smarkm
327178825Sdfrstatic void log_message(const char *fmt, ...)
328178825Sdfr{
329178825Sdfr    va_list ap;
330178825Sdfr    va_start(ap, fmt);
331178825Sdfr    if (auth_debug_mode) {
332178825Sdfr	va_start(ap, fmt);
333178825Sdfr	vfprintf(stdout, fmt, ap);
334178825Sdfr	va_end(ap);
335178825Sdfr	fprintf(stdout, "\r\n");
336178825Sdfr    }
337178825Sdfr    va_start(ap, fmt);
338178825Sdfr    vsyslog(LOG_NOTICE, fmt, ap);
339178825Sdfr    va_end(ap);
340178825Sdfr}
341178825Sdfr
34257416Smarkmvoid
34357416Smarkmkerberos5_is(Authenticator *ap, unsigned char *data, int cnt)
34457416Smarkm{
34557416Smarkm    krb5_error_code ret;
34657416Smarkm    krb5_data outbuf;
34757416Smarkm    krb5_keyblock *key_block;
34857416Smarkm    char *name;
34957416Smarkm    krb5_principal server;
35057416Smarkm    int zero = 0;
35157416Smarkm
35257416Smarkm    if (cnt-- < 1)
35357416Smarkm	return;
35457416Smarkm    switch (*data++) {
35557416Smarkm    case KRB_AUTH:
35657416Smarkm	auth.data = (char *)data;
35757416Smarkm	auth.length = cnt;
35857416Smarkm
35957416Smarkm	auth_context = NULL;
36057416Smarkm
36157416Smarkm	ret = krb5_auth_con_init (context, &auth_context);
36257416Smarkm	if (ret) {
36357416Smarkm	    Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1);
36457416Smarkm	    auth_finished(ap, AUTH_REJECT);
365178825Sdfr	    log_message("Kerberos V5: krb5_auth_con_init failed (%s)",
366178825Sdfr			krb5_get_err_text(context, ret));
36757416Smarkm	    return;
36857416Smarkm	}
36957416Smarkm
37057416Smarkm	ret = krb5_auth_con_setaddrs_from_fd (context,
37157416Smarkm					      auth_context,
37257416Smarkm					      &zero);
37357416Smarkm	if (ret) {
37457416Smarkm	    Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1);
37557416Smarkm	    auth_finished(ap, AUTH_REJECT);
376178825Sdfr	    log_message("Kerberos V5: "
377178825Sdfr			"krb5_auth_con_setaddrs_from_fd failed (%s)",
378178825Sdfr			krb5_get_err_text(context, ret));
37957416Smarkm	    return;
38057416Smarkm	}
38157416Smarkm
38257416Smarkm	ret = krb5_sock_to_principal (context,
38357416Smarkm				      0,
38457416Smarkm				      "host",
38557416Smarkm				      KRB5_NT_SRV_HST,
38657416Smarkm				      &server);
38757416Smarkm	if (ret) {
38857416Smarkm	    Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1);
38957416Smarkm	    auth_finished(ap, AUTH_REJECT);
390178825Sdfr	    log_message("Kerberos V5: "
391178825Sdfr			"krb5_sock_to_principal failed (%s)",
392178825Sdfr			krb5_get_err_text(context, ret));
39357416Smarkm	    return;
39457416Smarkm	}
39557416Smarkm
39657416Smarkm	ret = krb5_rd_req(context,
39757416Smarkm			  &auth_context,
398233294Sstas			  &auth,
39957416Smarkm			  server,
40057416Smarkm			  NULL,
40157416Smarkm			  NULL,
40257416Smarkm			  &ticket);
40372445Sassar
40457416Smarkm	krb5_free_principal (context, server);
40557416Smarkm	if (ret) {
406178825Sdfr	    const char *errbuf2 = "Read req failed";
40757416Smarkm	    char *errbuf;
408178825Sdfr	    int ret2;
40957416Smarkm
410178825Sdfr	    ret2 = asprintf(&errbuf,
411178825Sdfr			    "Read req failed: %s",
412178825Sdfr			    krb5_get_err_text(context, ret));
413178825Sdfr	    if (ret2 != -1)
414178825Sdfr		errbuf2 = errbuf;
415178825Sdfr	    Data(ap, KRB_REJECT, errbuf2, -1);
416178825Sdfr	    log_message("%s", errbuf2);
417178825Sdfr	    if (ret2 != -1)
418178825Sdfr		free (errbuf);
41957416Smarkm	    return;
42057416Smarkm	}
421233294Sstas
42257416Smarkm	{
423178825Sdfr	    char ap_msg[2];
424233294Sstas
425178825Sdfr	    ap_msg[0] = ap->type;
426178825Sdfr	    ap_msg[1] = ap->way;
427233294Sstas
42857416Smarkm	    ret = krb5_verify_authenticator_checksum(context,
42957416Smarkm						     auth_context,
430233294Sstas						     ap_msg,
431178825Sdfr						     sizeof(ap_msg));
43257416Smarkm
43357416Smarkm	    if (ret) {
434178825Sdfr		const char *errbuf2 = "Bad checksum";
43557416Smarkm		char *errbuf;
436178825Sdfr		int ret2;
437178825Sdfr
438233294Sstas		ret2 = asprintf(&errbuf, "Bad checksum: %s",
439178825Sdfr				krb5_get_err_text(context, ret));
440178825Sdfr		if (ret2 != -1)
441178825Sdfr		    errbuf2 = errbuf;
442178825Sdfr		Data(ap, KRB_REJECT, errbuf2, -1);
443178825Sdfr		log_message("%s", errbuf2);
444178825Sdfr		if (ret2 != -1)
445178825Sdfr		    free(errbuf);
44657416Smarkm		return;
44757416Smarkm	    }
44857416Smarkm	}
44957416Smarkm	ret = krb5_auth_con_getremotesubkey (context,
45057416Smarkm					     auth_context,
45157416Smarkm					     &key_block);
45257416Smarkm
45357416Smarkm	if (ret) {
45457416Smarkm	    Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1);
45557416Smarkm	    auth_finished(ap, AUTH_REJECT);
456178825Sdfr	    log_message("Kerberos V5: "
457178825Sdfr			"krb5_auth_con_getremotesubkey failed (%s)",
458178825Sdfr			krb5_get_err_text(context, ret));
45957416Smarkm	    return;
46057416Smarkm	}
46157416Smarkm
462107207Snectar	if (key_block == NULL) {
463107207Snectar	    ret = krb5_auth_con_getkey(context,
464107207Snectar				       auth_context,
465107207Snectar				       &key_block);
466107207Snectar	}
467107207Snectar	if (ret) {
468107207Snectar	    Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1);
469107207Snectar	    auth_finished(ap, AUTH_REJECT);
470178825Sdfr	    log_message("Kerberos V5: "
471178825Sdfr			"krb5_auth_con_getkey failed (%s)",
472178825Sdfr			krb5_get_err_text(context, ret));
473107207Snectar	    return;
474107207Snectar	}
475107207Snectar	if (key_block == NULL) {
476107207Snectar	    Data(ap, KRB_REJECT, "no subkey received", -1);
477107207Snectar	    auth_finished(ap, AUTH_REJECT);
478178825Sdfr	    log_message("Kerberos V5: "
479178825Sdfr			"krb5_auth_con_getremotesubkey returned NULL key");
480107207Snectar	    return;
481107207Snectar	}
482107207Snectar
48357416Smarkm	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
48472445Sassar	    ret = krb5_mk_rep(context, auth_context, &outbuf);
48557416Smarkm	    if (ret) {
48657416Smarkm		Data(ap, KRB_REJECT,
48757416Smarkm		     "krb5_mk_rep failed", -1);
48857416Smarkm		auth_finished(ap, AUTH_REJECT);
489178825Sdfr		log_message("Kerberos V5: "
490178825Sdfr			    "krb5_mk_rep failed (%s)",
491178825Sdfr			    krb5_get_err_text(context, ret));
492233294Sstas		krb5_free_keyblock(context, key_block);
49357416Smarkm		return;
49457416Smarkm	    }
49557416Smarkm	    Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
49657416Smarkm	}
49757416Smarkm	if (krb5_unparse_name(context, ticket->client, &name))
49857416Smarkm	    name = 0;
49957416Smarkm
50057416Smarkm	if(UserNameRequested && krb5_kuserok(context,
50157416Smarkm					     ticket->client,
50257416Smarkm					     UserNameRequested)) {
50357416Smarkm	    Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
504178825Sdfr	    log_message("%s accepted as user %s from %s",
505233294Sstas			name ? name : "<unknown>",
506178825Sdfr			UserNameRequested ? UserNameRequested : "<unknown>",
507178825Sdfr			RemoteHostName ? RemoteHostName : "<unknown>");
50857416Smarkm
50957416Smarkm	    if(key_block->keytype == ETYPE_DES_CBC_MD5 ||
51057416Smarkm	       key_block->keytype == ETYPE_DES_CBC_MD4 ||
51157416Smarkm	       key_block->keytype == ETYPE_DES_CBC_CRC) {
51257416Smarkm		Session_Key skey;
51357416Smarkm
51457416Smarkm		skey.type = SK_DES;
51557416Smarkm		skey.length = 8;
51657416Smarkm		skey.data = key_block->keyvalue.data;
51757416Smarkm		encrypt_session_key(&skey, 0);
51857416Smarkm	    }
51957416Smarkm
52057416Smarkm	} else {
521178825Sdfr	    const char *msg2 = "user is not authorized to login";
52257416Smarkm	    char *msg;
52357416Smarkm
524178825Sdfr	    ret = asprintf (&msg, "user `%s' is not authorized to "
525233294Sstas			    "login as `%s'",
526178825Sdfr			    name ? name : "<unknown>",
527178825Sdfr			    UserNameRequested ? UserNameRequested : "<nobody>");
528178825Sdfr	    if (ret != -1)
529178825Sdfr		msg2 = msg;
530178825Sdfr	    Data(ap, KRB_REJECT, (void *)msg2, -1);
531178825Sdfr	    if (ret != -1)
53257416Smarkm		free(msg);
53357416Smarkm	    auth_finished (ap, AUTH_REJECT);
534233294Sstas	    krb5_free_keyblock(context, key_block);
53557416Smarkm	    break;
53657416Smarkm	}
53757416Smarkm	auth_finished(ap, AUTH_USER);
538233294Sstas	krb5_free_keyblock(context, key_block);
539233294Sstas
54057416Smarkm	break;
54157416Smarkm    case KRB_FORWARD: {
54257416Smarkm	struct passwd *pwd;
54357416Smarkm	char ccname[1024];	/* XXX */
54457416Smarkm	krb5_data inbuf;
54557416Smarkm	krb5_ccache ccache;
54657416Smarkm	inbuf.data = (char *)data;
54757416Smarkm	inbuf.length = cnt;
54857416Smarkm
54957416Smarkm	pwd = getpwnam (UserNameRequested);
55057416Smarkm	if (pwd == NULL)
55157416Smarkm	    break;
55257416Smarkm
55357416Smarkm	snprintf (ccname, sizeof(ccname),
554178825Sdfr		  "FILE:/tmp/krb5cc_%lu", (unsigned long)pwd->pw_uid);
55557416Smarkm
55657416Smarkm	ret = krb5_cc_resolve (context, ccname, &ccache);
55757416Smarkm	if (ret) {
558178825Sdfr	    log_message("Kerberos V5: could not get ccache: %s",
55957416Smarkm			krb5_get_err_text(context, ret));
56057416Smarkm	    break;
56157416Smarkm	}
56257416Smarkm
56357416Smarkm	ret = krb5_cc_initialize (context,
56457416Smarkm				  ccache,
56557416Smarkm				  ticket->client);
56657416Smarkm	if (ret) {
567178825Sdfr	    log_message("Kerberos V5: could not init ccache: %s",
56857416Smarkm			krb5_get_err_text(context, ret));
56957416Smarkm	    break;
57057416Smarkm	}
57157416Smarkm
57272445Sassar#if defined(DCE)
57372445Sassar	esetenv("KRB5CCNAME", ccname, 1);
57472445Sassar#endif
57572445Sassar	ret = krb5_rd_cred2 (context,
57672445Sassar			     auth_context,
57772445Sassar			     ccache,
57872445Sassar			     &inbuf);
57957416Smarkm	if(ret) {
580178825Sdfr	    const char *errbuf2 = "Read forwarded creds failed";
58157416Smarkm	    char *errbuf;
582178825Sdfr	    int ret2;
58357416Smarkm
584178825Sdfr	    ret2 = asprintf (&errbuf,
585178825Sdfr			     "Read forwarded creds failed: %s",
586178825Sdfr			     krb5_get_err_text (context, ret));
587178825Sdfr	    if (ret2 != -1)
588178825Sdfr		errbuf2 = errbuf;
589178825Sdfr	    Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
590178825Sdfr	    log_message("Could not read forwarded credentials: %s", errbuf);
591178825Sdfr
592178825Sdfr	    if (ret2 != -1)
593178825Sdfr		free (errbuf);
59472445Sassar	} else {
59557416Smarkm	    Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
59672445Sassar#if defined(DCE)
59772445Sassar	    dfsfwd = 1;
59872445Sassar#endif
59972445Sassar	}
60057416Smarkm	chown (ccname + 5, pwd->pw_uid, -1);
601178825Sdfr	log_message("Forwarded credentials obtained");
60257416Smarkm	break;
60357416Smarkm    }
60457416Smarkm    default:
605178825Sdfr	log_message("Unknown Kerberos option %d", data[-1]);
60657416Smarkm	Data(ap, KRB_REJECT, 0, 0);
60757416Smarkm	break;
60857416Smarkm    }
60957416Smarkm}
61057416Smarkm
61157416Smarkmvoid
61257416Smarkmkerberos5_reply(Authenticator *ap, unsigned char *data, int cnt)
61357416Smarkm{
61457416Smarkm    static int mutual_complete = 0;
61557416Smarkm
61657416Smarkm    if (cnt-- < 1)
61757416Smarkm	return;
61857416Smarkm    switch (*data++) {
61957416Smarkm    case KRB_REJECT:
62057416Smarkm	if (cnt > 0) {
62157416Smarkm	    printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
62257416Smarkm		   cnt, data);
62357416Smarkm	} else
62457416Smarkm	    printf("[ Kerberos V5 refuses authentication ]\r\n");
62557416Smarkm	auth_send_retry();
62657416Smarkm	return;
62757416Smarkm    case KRB_ACCEPT: {
62857416Smarkm	krb5_error_code ret;
62957416Smarkm	Session_Key skey;
63057416Smarkm	krb5_keyblock *keyblock;
631233294Sstas
63257416Smarkm	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
63357416Smarkm	    !mutual_complete) {
63457416Smarkm	    printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
63557416Smarkm	    auth_send_retry();
63657416Smarkm	    return;
63757416Smarkm	}
63857416Smarkm	if (cnt)
63957416Smarkm	    printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
64057416Smarkm	else
64157416Smarkm	    printf("[ Kerberos V5 accepts you ]\r\n");
642233294Sstas
64357416Smarkm	ret = krb5_auth_con_getlocalsubkey (context,
64457416Smarkm					    auth_context,
64557416Smarkm					    &keyblock);
64657416Smarkm	if (ret)
64757416Smarkm	    ret = krb5_auth_con_getkey (context,
64857416Smarkm					auth_context,
64957416Smarkm					&keyblock);
65057416Smarkm	if(ret) {
65157416Smarkm	    printf("[ krb5_auth_con_getkey: %s ]\r\n",
65257416Smarkm		   krb5_get_err_text(context, ret));
65357416Smarkm	    auth_send_retry();
65457416Smarkm	    return;
65557416Smarkm	}
656233294Sstas
65757416Smarkm	skey.type = SK_DES;
65857416Smarkm	skey.length = 8;
65957416Smarkm	skey.data = keyblock->keyvalue.data;
66057416Smarkm	encrypt_session_key(&skey, 0);
661233294Sstas	krb5_free_keyblock (context, keyblock);
66257416Smarkm	auth_finished(ap, AUTH_USER);
66357416Smarkm	if (forward_flags & OPTS_FORWARD_CREDS)
66457416Smarkm	    kerberos5_forward(ap);
66557416Smarkm	break;
66657416Smarkm    }
66757416Smarkm    case KRB_RESPONSE:
66857416Smarkm	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
66957416Smarkm	    /* the rest of the reply should contain a krb_ap_rep */
67057416Smarkm	  krb5_ap_rep_enc_part *reply;
67157416Smarkm	  krb5_data inbuf;
67257416Smarkm	  krb5_error_code ret;
673233294Sstas
67457416Smarkm	  inbuf.length = cnt;
67557416Smarkm	  inbuf.data = (char *)data;
67657416Smarkm
67757416Smarkm	  ret = krb5_rd_rep(context, auth_context, &inbuf, &reply);
67857416Smarkm	  if (ret) {
67957416Smarkm	      printf("[ Mutual authentication failed: %s ]\r\n",
68057416Smarkm		     krb5_get_err_text (context, ret));
68157416Smarkm	      auth_send_retry();
68257416Smarkm	      return;
68357416Smarkm	  }
68457416Smarkm	  krb5_free_ap_rep_enc_part(context, reply);
68557416Smarkm	  mutual_complete = 1;
68657416Smarkm	}
68757416Smarkm	return;
68857416Smarkm    case KRB_FORWARD_ACCEPT:
68957416Smarkm	printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
69057416Smarkm	return;
69157416Smarkm    case KRB_FORWARD_REJECT:
69257416Smarkm	printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
69357416Smarkm	       cnt, data);
69457416Smarkm	return;
69557416Smarkm    default:
69657416Smarkm	if (auth_debug_mode)
69757416Smarkm	    printf("Unknown Kerberos option %d\r\n", data[-1]);
69857416Smarkm	return;
69957416Smarkm    }
70057416Smarkm}
70157416Smarkm
70257416Smarkmint
70357416Smarkmkerberos5_status(Authenticator *ap, char *name, size_t name_sz, int level)
70457416Smarkm{
70557416Smarkm    if (level < AUTH_USER)
70657416Smarkm	return(level);
70757416Smarkm
70857416Smarkm    if (UserNameRequested &&
70957416Smarkm	krb5_kuserok(context,
71057416Smarkm		     ticket->client,
71157416Smarkm		     UserNameRequested))
71257416Smarkm	{
71357416Smarkm	    strlcpy(name, UserNameRequested, name_sz);
71472445Sassar#if defined(DCE)
71572445Sassar	    dfsk5ok = 1;
71672445Sassar#endif
71757416Smarkm	    return(AUTH_VALID);
71857416Smarkm	} else
71957416Smarkm	    return(AUTH_USER);
72057416Smarkm}
72157416Smarkm
72257416Smarkm#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
72357416Smarkm#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
72457416Smarkm
72557416Smarkmvoid
726233294Sstaskerberos5_printsub(unsigned char *data, size_t cnt,
727233294Sstas		   unsigned char *buf, size_t buflen)
72857416Smarkm{
72957416Smarkm    int i;
73057416Smarkm
731178825Sdfr    buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
73257416Smarkm    buflen -= 1;
73357416Smarkm
73457416Smarkm    switch(data[3]) {
73557416Smarkm    case KRB_REJECT:		/* Rejected (reason might follow) */
73657416Smarkm	strlcpy((char *)buf, " REJECT ", buflen);
73757416Smarkm	goto common;
73857416Smarkm
73957416Smarkm    case KRB_ACCEPT:		/* Accepted (name might follow) */
74057416Smarkm	strlcpy((char *)buf, " ACCEPT ", buflen);
74157416Smarkm    common:
74257416Smarkm	BUMP(buf, buflen);
74357416Smarkm	if (cnt <= 4)
74457416Smarkm	    break;
74557416Smarkm	ADDC(buf, buflen, '"');
74657416Smarkm	for (i = 4; i < cnt; i++)
74757416Smarkm	    ADDC(buf, buflen, data[i]);
74857416Smarkm	ADDC(buf, buflen, '"');
74957416Smarkm	ADDC(buf, buflen, '\0');
75057416Smarkm	break;
75157416Smarkm
75257416Smarkm
75357416Smarkm    case KRB_AUTH:			/* Authentication data follows */
75457416Smarkm	strlcpy((char *)buf, " AUTH", buflen);
75557416Smarkm	goto common2;
75657416Smarkm
75757416Smarkm    case KRB_RESPONSE:
75857416Smarkm	strlcpy((char *)buf, " RESPONSE", buflen);
75957416Smarkm	goto common2;
76057416Smarkm
76157416Smarkm    case KRB_FORWARD:		/* Forwarded credentials follow */
76257416Smarkm	strlcpy((char *)buf, " FORWARD", buflen);
76357416Smarkm	goto common2;
76457416Smarkm
76557416Smarkm    case KRB_FORWARD_ACCEPT:	/* Forwarded credentials accepted */
76657416Smarkm	strlcpy((char *)buf, " FORWARD_ACCEPT", buflen);
76757416Smarkm	goto common2;
76857416Smarkm
76957416Smarkm    case KRB_FORWARD_REJECT:	/* Forwarded credentials rejected */
77057416Smarkm	/* (reason might follow) */
77157416Smarkm	strlcpy((char *)buf, " FORWARD_REJECT", buflen);
77257416Smarkm	goto common2;
77357416Smarkm
77457416Smarkm    default:
77590926Snectar	snprintf((char*)buf, buflen, " %d (unknown)", data[3]);
77657416Smarkm    common2:
77757416Smarkm	BUMP(buf, buflen);
77857416Smarkm	for (i = 4; i < cnt; i++) {
77990926Snectar	    snprintf((char*)buf, buflen, " %d", data[i]);
78057416Smarkm	    BUMP(buf, buflen);
78157416Smarkm	}
78257416Smarkm	break;
78357416Smarkm    }
78457416Smarkm}
78557416Smarkm
78657416Smarkmvoid
78757416Smarkmkerberos5_forward(Authenticator *ap)
78857416Smarkm{
78957416Smarkm    krb5_error_code ret;
79057416Smarkm    krb5_ccache     ccache;
79157416Smarkm    krb5_creds      creds;
792178825Sdfr    KDCOptions	    flags;
79357416Smarkm    krb5_data       out_data;
79457416Smarkm    krb5_principal  principal;
79557416Smarkm
79657416Smarkm    ret = krb5_cc_default (context, &ccache);
79757416Smarkm    if (ret) {
79857416Smarkm	if (auth_debug_mode)
79957416Smarkm	    printf ("KerberosV5: could not get default ccache: %s\r\n",
80057416Smarkm		    krb5_get_err_text (context, ret));
80157416Smarkm	return;
80257416Smarkm    }
80357416Smarkm
80457416Smarkm    ret = krb5_cc_get_principal (context, ccache, &principal);
80557416Smarkm    if (ret) {
80657416Smarkm	if (auth_debug_mode)
80757416Smarkm	    printf ("KerberosV5: could not get principal: %s\r\n",
80857416Smarkm		    krb5_get_err_text (context, ret));
80957416Smarkm	return;
81057416Smarkm    }
81157416Smarkm
81257416Smarkm    memset (&creds, 0, sizeof(creds));
81357416Smarkm
81457416Smarkm    creds.client = principal;
81557416Smarkm
816233294Sstas    ret = krb5_make_principal(context,
817233294Sstas			      &creds.server,
818233294Sstas			      principal->realm,
819233294Sstas			      "krbtgt",
820233294Sstas			      principal->realm,
821233294Sstas			      NULL);
822233294Sstas
82357416Smarkm    if (ret) {
82457416Smarkm	if (auth_debug_mode)
82557416Smarkm	    printf ("KerberosV5: could not get principal: %s\r\n",
82657416Smarkm		    krb5_get_err_text (context, ret));
82757416Smarkm	return;
82857416Smarkm    }
82957416Smarkm
83057416Smarkm    creds.times.endtime = 0;
83157416Smarkm
832178825Sdfr    memset(&flags, 0, sizeof(flags));
833178825Sdfr    flags.forwarded = 1;
83457416Smarkm    if (forward_flags & OPTS_FORWARDABLE_CREDS)
835178825Sdfr	flags.forwardable = 1;
83657416Smarkm
83757416Smarkm    ret = krb5_get_forwarded_creds (context,
83857416Smarkm				    auth_context,
83957416Smarkm				    ccache,
840178825Sdfr				    KDCOptions2int(flags),
84157416Smarkm				    RemoteHostName,
84257416Smarkm				    &creds,
84357416Smarkm				    &out_data);
84457416Smarkm    if (ret) {
84557416Smarkm	if (auth_debug_mode)
84657416Smarkm	    printf ("Kerberos V5: error getting forwarded creds: %s\r\n",
84757416Smarkm		    krb5_get_err_text (context, ret));
84857416Smarkm	return;
84957416Smarkm    }
85057416Smarkm
85157416Smarkm    if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) {
85257416Smarkm	if (auth_debug_mode)
85357416Smarkm	    printf("Not enough room for authentication data\r\n");
85457416Smarkm    } else {
85557416Smarkm	if (auth_debug_mode)
85657416Smarkm	    printf("Forwarded local Kerberos V5 credentials to server\r\n");
85757416Smarkm    }
85857416Smarkm}
85957416Smarkm
86072445Sassar#if defined(DCE)
86172445Sassar/* if this was a K5 authentication try and join a PAG for the user. */
86272445Sassarvoid
86372445Sassarkerberos5_dfspag(void)
86472445Sassar{
86572445Sassar    if (dfsk5ok) {
86672445Sassar	dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client,
86772445Sassar			      UserNameRequested);
86872445Sassar    }
86972445Sassar}
87072445Sassar#endif
87172445Sassar
872102644Snectarint
873102644Snectarkerberos5_set_forward(int on)
874102644Snectar{
875102644Snectar    if(on == 0)
876102644Snectar	forward_flags &= ~OPTS_FORWARD_CREDS;
877102644Snectar    if(on == 1)
878102644Snectar	forward_flags |= OPTS_FORWARD_CREDS;
879102644Snectar    if(on == -1)
880102644Snectar	forward_flags ^= OPTS_FORWARD_CREDS;
881102644Snectar    return 0;
882102644Snectar}
883102644Snectar
884102644Snectarint
885102644Snectarkerberos5_set_forwardable(int on)
886102644Snectar{
887102644Snectar    if(on == 0)
888102644Snectar	forward_flags &= ~OPTS_FORWARDABLE_CREDS;
889102644Snectar    if(on == 1)
890102644Snectar	forward_flags |= OPTS_FORWARDABLE_CREDS;
891102644Snectar    if(on == -1)
892102644Snectar	forward_flags ^= OPTS_FORWARDABLE_CREDS;
893102644Snectar    return 0;
894102644Snectar}
895102644Snectar
89657416Smarkm#endif /* KRB5 */
897