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
56178825SdfrRCSID("$Id: kerberos5.c 22071 2007-11-14 20:04:50Z lha $");
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;
135142403Snectar
136142403Snectar    memcpy(p0, str_data, sizeof(str_data));
137142403Snectar    p = p0 + sizeof(str_data);
138142403Snectar
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];
20257416Smarkm
20357416Smarkm    if (!UserNameRequested) {
20457416Smarkm	if (auth_debug_mode) {
20557416Smarkm	    printf("Kerberos V5: no user name supplied\r\n");
20657416Smarkm	}
20757416Smarkm	return(0);
20857416Smarkm    }
20957416Smarkm
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    }
21857416Smarkm
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;
22557416Smarkm
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
24790926Snectar    krb5_auth_con_setkeytype (context, auth_context, KEYTYPE_DES);
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,
28572445Sassar				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,
39857416Smarkm			  &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	}
42157416Smarkm
42257416Smarkm	{
423178825Sdfr	    char ap_msg[2];
42457416Smarkm
425178825Sdfr	    ap_msg[0] = ap->type;
426178825Sdfr	    ap_msg[1] = ap->way;
42757416Smarkm
42857416Smarkm	    ret = krb5_verify_authenticator_checksum(context,
42957416Smarkm						     auth_context,
430178825Sdfr						     ap_msg,
431178825Sdfr						     sizeof(ap_msg));
43257416Smarkm
43357416Smarkm	    if (ret) {
434178825Sdfr		const char *errbuf2 = "Bad checksum";
43557416Smarkm		char *errbuf;
436178825Sdfr		int ret2;
437178825Sdfr
438178825Sdfr		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));
49257416Smarkm		return;
49357416Smarkm	    }
49457416Smarkm	    Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
49557416Smarkm	}
49657416Smarkm	if (krb5_unparse_name(context, ticket->client, &name))
49757416Smarkm	    name = 0;
49857416Smarkm
49957416Smarkm	if(UserNameRequested && krb5_kuserok(context,
50057416Smarkm					     ticket->client,
50157416Smarkm					     UserNameRequested)) {
50257416Smarkm	    Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
503178825Sdfr	    log_message("%s accepted as user %s from %s",
504178825Sdfr			name ? name : "<unknown>",
505178825Sdfr			UserNameRequested ? UserNameRequested : "<unknown>",
506178825Sdfr			RemoteHostName ? RemoteHostName : "<unknown>");
50757416Smarkm
50857416Smarkm	    if(key_block->keytype == ETYPE_DES_CBC_MD5 ||
50957416Smarkm	       key_block->keytype == ETYPE_DES_CBC_MD4 ||
51057416Smarkm	       key_block->keytype == ETYPE_DES_CBC_CRC) {
51157416Smarkm		Session_Key skey;
51257416Smarkm
51357416Smarkm		skey.type = SK_DES;
51457416Smarkm		skey.length = 8;
51557416Smarkm		skey.data = key_block->keyvalue.data;
51657416Smarkm		encrypt_session_key(&skey, 0);
51757416Smarkm	    }
51857416Smarkm
51957416Smarkm	} else {
520178825Sdfr	    const char *msg2 = "user is not authorized to login";
52157416Smarkm	    char *msg;
52257416Smarkm
523178825Sdfr	    ret = asprintf (&msg, "user `%s' is not authorized to "
524178825Sdfr			    "login as `%s'",
525178825Sdfr			    name ? name : "<unknown>",
526178825Sdfr			    UserNameRequested ? UserNameRequested : "<nobody>");
527178825Sdfr	    if (ret != -1)
528178825Sdfr		msg2 = msg;
529178825Sdfr	    Data(ap, KRB_REJECT, (void *)msg2, -1);
530178825Sdfr	    if (ret != -1)
53157416Smarkm		free(msg);
53257416Smarkm	    auth_finished (ap, AUTH_REJECT);
53357416Smarkm	    krb5_free_keyblock_contents(context, key_block);
53457416Smarkm	    break;
53557416Smarkm	}
53657416Smarkm	auth_finished(ap, AUTH_USER);
53757416Smarkm	krb5_free_keyblock_contents(context, key_block);
53857416Smarkm
53957416Smarkm	break;
54057416Smarkm    case KRB_FORWARD: {
54157416Smarkm	struct passwd *pwd;
54257416Smarkm	char ccname[1024];	/* XXX */
54357416Smarkm	krb5_data inbuf;
54457416Smarkm	krb5_ccache ccache;
54557416Smarkm	inbuf.data = (char *)data;
54657416Smarkm	inbuf.length = cnt;
54757416Smarkm
54857416Smarkm	pwd = getpwnam (UserNameRequested);
54957416Smarkm	if (pwd == NULL)
55057416Smarkm	    break;
55157416Smarkm
55257416Smarkm	snprintf (ccname, sizeof(ccname),
553178825Sdfr		  "FILE:/tmp/krb5cc_%lu", (unsigned long)pwd->pw_uid);
55457416Smarkm
55557416Smarkm	ret = krb5_cc_resolve (context, ccname, &ccache);
55657416Smarkm	if (ret) {
557178825Sdfr	    log_message("Kerberos V5: could not get ccache: %s",
55857416Smarkm			krb5_get_err_text(context, ret));
55957416Smarkm	    break;
56057416Smarkm	}
56157416Smarkm
56257416Smarkm	ret = krb5_cc_initialize (context,
56357416Smarkm				  ccache,
56457416Smarkm				  ticket->client);
56557416Smarkm	if (ret) {
566178825Sdfr	    log_message("Kerberos V5: could not init ccache: %s",
56757416Smarkm			krb5_get_err_text(context, ret));
56857416Smarkm	    break;
56957416Smarkm	}
57057416Smarkm
57172445Sassar#if defined(DCE)
57272445Sassar	esetenv("KRB5CCNAME", ccname, 1);
57372445Sassar#endif
57472445Sassar	ret = krb5_rd_cred2 (context,
57572445Sassar			     auth_context,
57672445Sassar			     ccache,
57772445Sassar			     &inbuf);
57857416Smarkm	if(ret) {
579178825Sdfr	    const char *errbuf2 = "Read forwarded creds failed";
58057416Smarkm	    char *errbuf;
581178825Sdfr	    int ret2;
58257416Smarkm
583178825Sdfr	    ret2 = asprintf (&errbuf,
584178825Sdfr			     "Read forwarded creds failed: %s",
585178825Sdfr			     krb5_get_err_text (context, ret));
586178825Sdfr	    if (ret2 != -1)
587178825Sdfr		errbuf2 = errbuf;
588178825Sdfr	    Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
589178825Sdfr	    log_message("Could not read forwarded credentials: %s", errbuf);
590178825Sdfr
591178825Sdfr	    if (ret2 != -1)
592178825Sdfr		free (errbuf);
59372445Sassar	} else {
59457416Smarkm	    Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
59572445Sassar#if defined(DCE)
59672445Sassar	    dfsfwd = 1;
59772445Sassar#endif
59872445Sassar	}
59957416Smarkm	chown (ccname + 5, pwd->pw_uid, -1);
600178825Sdfr	log_message("Forwarded credentials obtained");
60157416Smarkm	break;
60257416Smarkm    }
60357416Smarkm    default:
604178825Sdfr	log_message("Unknown Kerberos option %d", data[-1]);
60557416Smarkm	Data(ap, KRB_REJECT, 0, 0);
60657416Smarkm	break;
60757416Smarkm    }
60857416Smarkm}
60957416Smarkm
61057416Smarkmvoid
61157416Smarkmkerberos5_reply(Authenticator *ap, unsigned char *data, int cnt)
61257416Smarkm{
61357416Smarkm    static int mutual_complete = 0;
61457416Smarkm
61557416Smarkm    if (cnt-- < 1)
61657416Smarkm	return;
61757416Smarkm    switch (*data++) {
61857416Smarkm    case KRB_REJECT:
61957416Smarkm	if (cnt > 0) {
62057416Smarkm	    printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
62157416Smarkm		   cnt, data);
62257416Smarkm	} else
62357416Smarkm	    printf("[ Kerberos V5 refuses authentication ]\r\n");
62457416Smarkm	auth_send_retry();
62557416Smarkm	return;
62657416Smarkm    case KRB_ACCEPT: {
62757416Smarkm	krb5_error_code ret;
62857416Smarkm	Session_Key skey;
62957416Smarkm	krb5_keyblock *keyblock;
63057416Smarkm
63157416Smarkm	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
63257416Smarkm	    !mutual_complete) {
63357416Smarkm	    printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
63457416Smarkm	    auth_send_retry();
63557416Smarkm	    return;
63657416Smarkm	}
63757416Smarkm	if (cnt)
63857416Smarkm	    printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
63957416Smarkm	else
64057416Smarkm	    printf("[ Kerberos V5 accepts you ]\r\n");
64157416Smarkm
64257416Smarkm	ret = krb5_auth_con_getlocalsubkey (context,
64357416Smarkm					    auth_context,
64457416Smarkm					    &keyblock);
64557416Smarkm	if (ret)
64657416Smarkm	    ret = krb5_auth_con_getkey (context,
64757416Smarkm					auth_context,
64857416Smarkm					&keyblock);
64957416Smarkm	if(ret) {
65057416Smarkm	    printf("[ krb5_auth_con_getkey: %s ]\r\n",
65157416Smarkm		   krb5_get_err_text(context, ret));
65257416Smarkm	    auth_send_retry();
65357416Smarkm	    return;
65457416Smarkm	}
65557416Smarkm
65657416Smarkm	skey.type = SK_DES;
65757416Smarkm	skey.length = 8;
65857416Smarkm	skey.data = keyblock->keyvalue.data;
65957416Smarkm	encrypt_session_key(&skey, 0);
66057416Smarkm	krb5_free_keyblock_contents (context, keyblock);
66157416Smarkm	auth_finished(ap, AUTH_USER);
66257416Smarkm	if (forward_flags & OPTS_FORWARD_CREDS)
66357416Smarkm	    kerberos5_forward(ap);
66457416Smarkm	break;
66557416Smarkm    }
66657416Smarkm    case KRB_RESPONSE:
66757416Smarkm	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
66857416Smarkm	    /* the rest of the reply should contain a krb_ap_rep */
66957416Smarkm	  krb5_ap_rep_enc_part *reply;
67057416Smarkm	  krb5_data inbuf;
67157416Smarkm	  krb5_error_code ret;
67257416Smarkm
67357416Smarkm	  inbuf.length = cnt;
67457416Smarkm	  inbuf.data = (char *)data;
67557416Smarkm
67657416Smarkm	  ret = krb5_rd_rep(context, auth_context, &inbuf, &reply);
67757416Smarkm	  if (ret) {
67857416Smarkm	      printf("[ Mutual authentication failed: %s ]\r\n",
67957416Smarkm		     krb5_get_err_text (context, ret));
68057416Smarkm	      auth_send_retry();
68157416Smarkm	      return;
68257416Smarkm	  }
68357416Smarkm	  krb5_free_ap_rep_enc_part(context, reply);
68457416Smarkm	  mutual_complete = 1;
68557416Smarkm	}
68657416Smarkm	return;
68757416Smarkm    case KRB_FORWARD_ACCEPT:
68857416Smarkm	printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
68957416Smarkm	return;
69057416Smarkm    case KRB_FORWARD_REJECT:
69157416Smarkm	printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
69257416Smarkm	       cnt, data);
69357416Smarkm	return;
69457416Smarkm    default:
69557416Smarkm	if (auth_debug_mode)
69657416Smarkm	    printf("Unknown Kerberos option %d\r\n", data[-1]);
69757416Smarkm	return;
69857416Smarkm    }
69957416Smarkm}
70057416Smarkm
70157416Smarkmint
70257416Smarkmkerberos5_status(Authenticator *ap, char *name, size_t name_sz, int level)
70357416Smarkm{
70457416Smarkm    if (level < AUTH_USER)
70557416Smarkm	return(level);
70657416Smarkm
70757416Smarkm    if (UserNameRequested &&
70857416Smarkm	krb5_kuserok(context,
70957416Smarkm		     ticket->client,
71057416Smarkm		     UserNameRequested))
71157416Smarkm	{
71257416Smarkm	    strlcpy(name, UserNameRequested, name_sz);
71372445Sassar#if defined(DCE)
71472445Sassar	    dfsk5ok = 1;
71572445Sassar#endif
71657416Smarkm	    return(AUTH_VALID);
71757416Smarkm	} else
71857416Smarkm	    return(AUTH_USER);
71957416Smarkm}
72057416Smarkm
72157416Smarkm#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
72257416Smarkm#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
72357416Smarkm
72457416Smarkmvoid
72557416Smarkmkerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
72657416Smarkm{
72757416Smarkm    int i;
72857416Smarkm
729178825Sdfr    buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
73057416Smarkm    buflen -= 1;
73157416Smarkm
73257416Smarkm    switch(data[3]) {
73357416Smarkm    case KRB_REJECT:		/* Rejected (reason might follow) */
73457416Smarkm	strlcpy((char *)buf, " REJECT ", buflen);
73557416Smarkm	goto common;
73657416Smarkm
73757416Smarkm    case KRB_ACCEPT:		/* Accepted (name might follow) */
73857416Smarkm	strlcpy((char *)buf, " ACCEPT ", buflen);
73957416Smarkm    common:
74057416Smarkm	BUMP(buf, buflen);
74157416Smarkm	if (cnt <= 4)
74257416Smarkm	    break;
74357416Smarkm	ADDC(buf, buflen, '"');
74457416Smarkm	for (i = 4; i < cnt; i++)
74557416Smarkm	    ADDC(buf, buflen, data[i]);
74657416Smarkm	ADDC(buf, buflen, '"');
74757416Smarkm	ADDC(buf, buflen, '\0');
74857416Smarkm	break;
74957416Smarkm
75057416Smarkm
75157416Smarkm    case KRB_AUTH:			/* Authentication data follows */
75257416Smarkm	strlcpy((char *)buf, " AUTH", buflen);
75357416Smarkm	goto common2;
75457416Smarkm
75557416Smarkm    case KRB_RESPONSE:
75657416Smarkm	strlcpy((char *)buf, " RESPONSE", buflen);
75757416Smarkm	goto common2;
75857416Smarkm
75957416Smarkm    case KRB_FORWARD:		/* Forwarded credentials follow */
76057416Smarkm	strlcpy((char *)buf, " FORWARD", buflen);
76157416Smarkm	goto common2;
76257416Smarkm
76357416Smarkm    case KRB_FORWARD_ACCEPT:	/* Forwarded credentials accepted */
76457416Smarkm	strlcpy((char *)buf, " FORWARD_ACCEPT", buflen);
76557416Smarkm	goto common2;
76657416Smarkm
76757416Smarkm    case KRB_FORWARD_REJECT:	/* Forwarded credentials rejected */
76857416Smarkm	/* (reason might follow) */
76957416Smarkm	strlcpy((char *)buf, " FORWARD_REJECT", buflen);
77057416Smarkm	goto common2;
77157416Smarkm
77257416Smarkm    default:
77390926Snectar	snprintf((char*)buf, buflen, " %d (unknown)", data[3]);
77457416Smarkm    common2:
77557416Smarkm	BUMP(buf, buflen);
77657416Smarkm	for (i = 4; i < cnt; i++) {
77790926Snectar	    snprintf((char*)buf, buflen, " %d", data[i]);
77857416Smarkm	    BUMP(buf, buflen);
77957416Smarkm	}
78057416Smarkm	break;
78157416Smarkm    }
78257416Smarkm}
78357416Smarkm
78457416Smarkmvoid
78557416Smarkmkerberos5_forward(Authenticator *ap)
78657416Smarkm{
78757416Smarkm    krb5_error_code ret;
78857416Smarkm    krb5_ccache     ccache;
78957416Smarkm    krb5_creds      creds;
790178825Sdfr    KDCOptions	    flags;
79157416Smarkm    krb5_data       out_data;
79257416Smarkm    krb5_principal  principal;
79357416Smarkm
79457416Smarkm    ret = krb5_cc_default (context, &ccache);
79557416Smarkm    if (ret) {
79657416Smarkm	if (auth_debug_mode)
79757416Smarkm	    printf ("KerberosV5: could not get default ccache: %s\r\n",
79857416Smarkm		    krb5_get_err_text (context, ret));
79957416Smarkm	return;
80057416Smarkm    }
80157416Smarkm
80257416Smarkm    ret = krb5_cc_get_principal (context, ccache, &principal);
80357416Smarkm    if (ret) {
80457416Smarkm	if (auth_debug_mode)
80557416Smarkm	    printf ("KerberosV5: could not get principal: %s\r\n",
80657416Smarkm		    krb5_get_err_text (context, ret));
80757416Smarkm	return;
80857416Smarkm    }
80957416Smarkm
81057416Smarkm    memset (&creds, 0, sizeof(creds));
81157416Smarkm
81257416Smarkm    creds.client = principal;
81357416Smarkm
81457416Smarkm    ret = krb5_build_principal (context,
81557416Smarkm				&creds.server,
81657416Smarkm				strlen(principal->realm),
81757416Smarkm				principal->realm,
81857416Smarkm				"krbtgt",
81957416Smarkm				principal->realm,
82057416Smarkm				NULL);
82157416Smarkm
82257416Smarkm    if (ret) {
82357416Smarkm	if (auth_debug_mode)
82457416Smarkm	    printf ("KerberosV5: could not get principal: %s\r\n",
82557416Smarkm		    krb5_get_err_text (context, ret));
82657416Smarkm	return;
82757416Smarkm    }
82857416Smarkm
82957416Smarkm    creds.times.endtime = 0;
83057416Smarkm
831178825Sdfr    memset(&flags, 0, sizeof(flags));
832178825Sdfr    flags.forwarded = 1;
83357416Smarkm    if (forward_flags & OPTS_FORWARDABLE_CREDS)
834178825Sdfr	flags.forwardable = 1;
83557416Smarkm
83657416Smarkm    ret = krb5_get_forwarded_creds (context,
83757416Smarkm				    auth_context,
83857416Smarkm				    ccache,
839178825Sdfr				    KDCOptions2int(flags),
84057416Smarkm				    RemoteHostName,
84157416Smarkm				    &creds,
84257416Smarkm				    &out_data);
84357416Smarkm    if (ret) {
84457416Smarkm	if (auth_debug_mode)
84557416Smarkm	    printf ("Kerberos V5: error getting forwarded creds: %s\r\n",
84657416Smarkm		    krb5_get_err_text (context, ret));
84757416Smarkm	return;
84857416Smarkm    }
84957416Smarkm
85057416Smarkm    if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) {
85157416Smarkm	if (auth_debug_mode)
85257416Smarkm	    printf("Not enough room for authentication data\r\n");
85357416Smarkm    } else {
85457416Smarkm	if (auth_debug_mode)
85557416Smarkm	    printf("Forwarded local Kerberos V5 credentials to server\r\n");
85657416Smarkm    }
85757416Smarkm}
85857416Smarkm
85972445Sassar#if defined(DCE)
86072445Sassar/* if this was a K5 authentication try and join a PAG for the user. */
86172445Sassarvoid
86272445Sassarkerberos5_dfspag(void)
86372445Sassar{
86472445Sassar    if (dfsk5ok) {
86572445Sassar	dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client,
86672445Sassar			      UserNameRequested);
86772445Sassar    }
86872445Sassar}
86972445Sassar#endif
87072445Sassar
871102644Snectarint
872102644Snectarkerberos5_set_forward(int on)
873102644Snectar{
874102644Snectar    if(on == 0)
875102644Snectar	forward_flags &= ~OPTS_FORWARD_CREDS;
876102644Snectar    if(on == 1)
877102644Snectar	forward_flags |= OPTS_FORWARD_CREDS;
878102644Snectar    if(on == -1)
879102644Snectar	forward_flags ^= OPTS_FORWARD_CREDS;
880102644Snectar    return 0;
881102644Snectar}
882102644Snectar
883102644Snectarint
884102644Snectarkerberos5_set_forwardable(int on)
885102644Snectar{
886102644Snectar    if(on == 0)
887102644Snectar	forward_flags &= ~OPTS_FORWARDABLE_CREDS;
888102644Snectar    if(on == 1)
889102644Snectar	forward_flags |= OPTS_FORWARDABLE_CREDS;
890102644Snectar    if(on == -1)
891102644Snectar	forward_flags ^= OPTS_FORWARDABLE_CREDS;
892102644Snectar    return 0;
893102644Snectar}
894102644Snectar
89557416Smarkm#endif /* KRB5 */
896