129088Smarkm/*-
229088Smarkm * Copyright (c) 1991, 1993
329088Smarkm *	The Regents of the University of California.  All rights reserved.
429088Smarkm *
529088Smarkm * Redistribution and use in source and binary forms, with or without
629088Smarkm * modification, are permitted provided that the following conditions
729088Smarkm * are met:
829088Smarkm * 1. Redistributions of source code must retain the above copyright
929088Smarkm *    notice, this list of conditions and the following disclaimer.
1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1129088Smarkm *    notice, this list of conditions and the following disclaimer in the
1229088Smarkm *    documentation and/or other materials provided with the distribution.
1329088Smarkm * 3. All advertising materials mentioning features or use of this software
1429088Smarkm *    must display the following acknowledgement:
1529088Smarkm *	This product includes software developed by the University of
1629088Smarkm *	California, Berkeley and its contributors.
1729088Smarkm * 4. Neither the name of the University nor the names of its contributors
1829088Smarkm *    may be used to endorse or promote products derived from this software
1929088Smarkm *    without specific prior written permission.
2029088Smarkm *
2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129088Smarkm * SUCH DAMAGE.
3229088Smarkm */
3329088Smarkm
3429088Smarkm/*
3529088Smarkm * Copyright (C) 1990 by the Massachusetts Institute of Technology
3629088Smarkm *
3729088Smarkm * Export of this software from the United States of America may
3829088Smarkm * require a specific license from the United States Government.
3929088Smarkm * It is the responsibility of any person or organization contemplating
4029088Smarkm * export to obtain such a license before exporting.
4129088Smarkm *
4229088Smarkm * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
4329088Smarkm * distribute this software and its documentation for any purpose and
4429088Smarkm * without fee is hereby granted, provided that the above copyright
4529088Smarkm * notice appear in all copies and that both that copyright notice and
4629088Smarkm * this permission notice appear in supporting documentation, and that
4729088Smarkm * the name of M.I.T. not be used in advertising or publicity pertaining
4829088Smarkm * to distribution of the software without specific, written prior
4929088Smarkm * permission.  M.I.T. makes no representations about the suitability of
5029088Smarkm * this software for any purpose.  It is provided "as is" without express
5129088Smarkm * or implied warranty.
5229088Smarkm */
5329088Smarkm
5487139Smarkm#include <sys/cdefs.h>
5529088Smarkm
5687139Smarkm__FBSDID("$FreeBSD$");
5787139Smarkm
5829088Smarkm#ifdef	KRB5
5987139Smarkm
6029088Smarkm#include <arpa/telnet.h>
6181965Smarkm#include <stdio.h>
6281965Smarkm#include <stdlib.h>
6381965Smarkm#include <string.h>
6487139Smarkm#include <unistd.h>
6587139Smarkm#include <netdb.h>
6687139Smarkm#include <ctype.h>
6787139Smarkm#include <pwd.h>
6887139Smarkm#define Authenticator k5_Authenticator
6987139Smarkm#include <krb5.h>
7087139Smarkm#undef Authenticator
7129088Smarkm
7229088Smarkm#include "encrypt.h"
7329088Smarkm#include "auth.h"
7429088Smarkm#include "misc.h"
7529088Smarkm
7629088Smarkmint forward_flags = 0;  /* Flags get set in telnet/main.c on -f and -F */
7729088Smarkm
7829088Smarkm/* These values need to be the same as those defined in telnet/main.c. */
7929088Smarkm/* Either define them in both places, or put in some common header file. */
8029088Smarkm#define OPTS_FORWARD_CREDS	0x00000002
8129088Smarkm#define OPTS_FORWARDABLE_CREDS	0x00000001
8229088Smarkm
8387139Smarkmvoid kerberos5_forward (Authenticator *);
8429088Smarkm
8529088Smarkmstatic unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
8629088Smarkm			  		AUTHTYPE_KERBEROS_V5, };
8729088Smarkm
8829088Smarkm#define	KRB_AUTH		0	/* Authentication data follows */
8929088Smarkm#define	KRB_REJECT		1	/* Rejected (reason might follow) */
9029088Smarkm#define	KRB_ACCEPT		2	/* Accepted */
9129088Smarkm#define	KRB_RESPONSE		3	/* Response for mutual auth. */
9229088Smarkm
9329088Smarkm#define KRB_FORWARD     	4       /* Forwarded credentials follow */
9429088Smarkm#define KRB_FORWARD_ACCEPT     	5       /* Forwarded credentials accepted */
9529088Smarkm#define KRB_FORWARD_REJECT     	6       /* Forwarded credentials rejected */
9629088Smarkm
9729088Smarkmstatic	krb5_data auth;
9887139Smarkmstatic  krb5_ticket *ticket;
9929088Smarkm
10087139Smarkmstatic krb5_context context;
10187139Smarkmstatic krb5_auth_context auth_context;
10229088Smarkm
103233932Sstasstatic void
104233932Sstasprint_krb5_error(krb5_context context, krb5_error_code code, const char *msg)
105233932Sstas{
106233932Sstas	const char *error_message;
107233932Sstas
108233932Sstas	error_message = krb5_get_error_message(context, code);
109233932Sstas	printf(msg, error_message);
110233932Sstas	krb5_free_error_message(context, error_message);
111233932Sstas}
112233932Sstas
11387139Smarkmstatic int
11487139SmarkmData(Authenticator *ap, int type, const char *d, int c)
11587139Smarkm{
11687139Smarkm    unsigned char *p = str_data + 4;
11787139Smarkm    const unsigned char *cd = d;
11829088Smarkm
11987139Smarkm    if (c == -1)
12087139Smarkm	c = strlen(cd);
12129088Smarkm
12287139Smarkm    if (auth_debug_mode) {
12387139Smarkm	printf("%s:%d: [%d] (%d)",
12487139Smarkm	       str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
12587139Smarkm	       str_data[3],
12687139Smarkm	       type, c);
12787139Smarkm	printd(d, c);
12887139Smarkm	printf("\r\n");
12987139Smarkm    }
13087139Smarkm    *p++ = ap->type;
13187139Smarkm    *p++ = ap->way;
13287139Smarkm    *p++ = type;
13387139Smarkm    while (c-- > 0) {
13487139Smarkm	if ((*p++ = *cd++) == IAC)
13587139Smarkm	    *p++ = IAC;
13687139Smarkm    }
13787139Smarkm    *p++ = IAC;
13887139Smarkm    *p++ = SE;
13987139Smarkm    if (str_data[3] == TELQUAL_IS)
14087139Smarkm	printsub('>', &str_data[2], p - &str_data[2]);
14187139Smarkm    return(net_write(str_data, p - str_data));
14287139Smarkm}
14387139Smarkm
14487139Smarkmint
14587139Smarkmkerberos5_init(Authenticator *ap __unused, int server)
14629088Smarkm{
14787139Smarkm    krb5_error_code ret;
14829088Smarkm
14987139Smarkm    ret = krb5_init_context(&context);
15087139Smarkm    if (ret)
15187139Smarkm	return 0;
15287139Smarkm    if (server) {
15387139Smarkm	krb5_keytab kt;
15487139Smarkm	krb5_kt_cursor cursor;
15529088Smarkm
15687139Smarkm	ret = krb5_kt_default(context, &kt);
15787139Smarkm	if (ret)
15887139Smarkm	    return 0;
15987139Smarkm
16087139Smarkm	ret = krb5_kt_start_seq_get (context, kt, &cursor);
16187139Smarkm	if (ret) {
16287139Smarkm	    krb5_kt_close (context, kt);
16387139Smarkm	    return 0;
16429088Smarkm	}
16587139Smarkm	krb5_kt_end_seq_get (context, kt, &cursor);
16687139Smarkm	krb5_kt_close (context, kt);
16729088Smarkm
16887139Smarkm	str_data[3] = TELQUAL_REPLY;
16987139Smarkm    } else
17087139Smarkm	str_data[3] = TELQUAL_IS;
17187139Smarkm    return(1);
17229088Smarkm}
17329088Smarkm
17487139Smarkmextern int net;
17587139Smarkm
17687139Smarkmstatic int
17787139Smarkmkerberos5_send(const char *name, Authenticator *ap)
17829088Smarkm{
17987139Smarkm    krb5_error_code ret;
18087139Smarkm    krb5_ccache ccache;
18187139Smarkm    int ap_opts;
18287139Smarkm    krb5_data cksum_data;
18387139Smarkm    char foo[2];
18487139Smarkm
18587139Smarkm    if (!UserNameRequested) {
18687139Smarkm	if (auth_debug_mode) {
18787139Smarkm	    printf("Kerberos V5: no user name supplied\r\n");
18887139Smarkm	}
18987139Smarkm	return(0);
19087139Smarkm    }
19187139Smarkm
19287139Smarkm    ret = krb5_cc_default(context, &ccache);
19387139Smarkm    if (ret) {
19487139Smarkm	if (auth_debug_mode) {
195233932Sstas	    print_krb5_error(context, ret, "Kerberos V5: could not get default ccache: %s\r\n");
19687139Smarkm	}
19787139Smarkm	return 0;
19887139Smarkm    }
19987139Smarkm
20087139Smarkm    if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
20187139Smarkm	ap_opts = AP_OPTS_MUTUAL_REQUIRED;
20287139Smarkm    else
20387139Smarkm	ap_opts = 0;
204111946Snectar    ap_opts |= AP_OPTS_USE_SUBKEY;
20587139Smarkm
20687139Smarkm    ret = krb5_auth_con_init (context, &auth_context);
20787139Smarkm    if (ret) {
20887139Smarkm	if (auth_debug_mode) {
209233932Sstas	    print_krb5_error(context, ret, "Kerberos V5: krb5_auth_con_init failed (%s)\r\n");
21087139Smarkm	}
21187139Smarkm	return(0);
21287139Smarkm    }
21329088Smarkm
21487139Smarkm    ret = krb5_auth_con_setaddrs_from_fd (context,
21587139Smarkm					  auth_context,
21687139Smarkm					  &net);
21787139Smarkm    if (ret) {
21887139Smarkm	if (auth_debug_mode) {
219233932Sstas	    print_krb5_error(context, ret, "Kerberos V5:"
220233932Sstas		    " krb5_auth_con_setaddrs_from_fd failed (%s)\r\n");
22187139Smarkm	}
22287139Smarkm	return(0);
22387139Smarkm    }
22429088Smarkm
22590931Snectar    krb5_auth_con_setkeytype (context, auth_context, KEYTYPE_DES);
22629088Smarkm
22787139Smarkm    foo[0] = ap->type;
22887139Smarkm    foo[1] = ap->way;
22929088Smarkm
23087139Smarkm    cksum_data.length = sizeof(foo);
23187139Smarkm    cksum_data.data   = foo;
23229088Smarkm
23329088Smarkm
23487139Smarkm    {
23587139Smarkm	krb5_principal service;
23687139Smarkm	char sname[128];
23729088Smarkm
23829088Smarkm
23987139Smarkm	ret = krb5_sname_to_principal (context,
24087139Smarkm				       RemoteHostName,
24187139Smarkm				       NULL,
24287139Smarkm				       KRB5_NT_SRV_HST,
24387139Smarkm				       &service);
24487139Smarkm	if(ret) {
24587139Smarkm	    if (auth_debug_mode) {
246233932Sstas		const char *err_str;
247233932Sstas
248233932Sstas		err_str = krb5_get_error_message(context, ret);
249233932Sstas		printf("Kerberosr V5:"
25087139Smarkm			" krb5_sname_to_principal(%s) failed (%s)\r\n",
251233932Sstas			RemoteHostName, err_str);
252233932Sstas		krb5_free_error_message(context, err_str);
25387139Smarkm	    }
25487139Smarkm	    return 0;
25529088Smarkm	}
25687139Smarkm	ret = krb5_unparse_name_fixed(context, service, sname, sizeof(sname));
25787139Smarkm	if(ret) {
25887139Smarkm	    if (auth_debug_mode) {
259233932Sstas		print_krb5_error(context, ret, "Kerberos V5:"
260233932Sstas			" krb5_unparse_name_fixed failed (%s)\r\n");
26187139Smarkm	    }
26287139Smarkm	    return 0;
26387139Smarkm	}
26487139Smarkm	printf("[ Trying %s (%s)... ]\r\n", name, sname);
26587139Smarkm	ret = krb5_mk_req_exact(context, &auth_context, ap_opts,
26687139Smarkm				service,
26787139Smarkm				&cksum_data, ccache, &auth);
26887139Smarkm	krb5_free_principal (context, service);
26929088Smarkm
27087139Smarkm    }
27187139Smarkm    if (ret) {
27287139Smarkm	if (1 || auth_debug_mode) {
273233932Sstas	    print_krb5_error(context, ret, "Kerberos V5: mk_req failed (%s)\r\n");
27429088Smarkm	}
27587139Smarkm	return(0);
27687139Smarkm    }
27729088Smarkm
27887139Smarkm    if (!auth_sendname((unsigned char *)UserNameRequested,
27987139Smarkm		       strlen(UserNameRequested))) {
28087139Smarkm	if (auth_debug_mode)
28187139Smarkm	    printf("Not enough room for user name\r\n");
28287139Smarkm	return(0);
28387139Smarkm    }
28487139Smarkm    if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
28587139Smarkm	if (auth_debug_mode)
28687139Smarkm	    printf("Not enough room for authentication data\r\n");
28787139Smarkm	return(0);
28887139Smarkm    }
28987139Smarkm    if (auth_debug_mode) {
29087139Smarkm	printf("Sent Kerberos V5 credentials to server\r\n");
29187139Smarkm    }
29287139Smarkm    return(1);
29387139Smarkm}
29429088Smarkm
29587139Smarkmint
29687139Smarkmkerberos5_send_mutual(Authenticator *ap)
29787139Smarkm{
29887139Smarkm    return kerberos5_send("mutual KERBEROS5", ap);
29987139Smarkm}
30029088Smarkm
30187139Smarkmint
30287139Smarkmkerberos5_send_oneway(Authenticator *ap)
30387139Smarkm{
30487139Smarkm    return kerberos5_send("KERBEROS5", ap);
30587139Smarkm}
30687139Smarkm
30787139Smarkmvoid
30887139Smarkmkerberos5_is(Authenticator *ap, unsigned char *data, int cnt)
30987139Smarkm{
31087139Smarkm    krb5_error_code ret;
31187139Smarkm    krb5_data outbuf;
31287139Smarkm    krb5_keyblock *key_block;
31387139Smarkm    char *name;
31487139Smarkm    krb5_principal server;
31587139Smarkm    int zero = 0;
31687139Smarkm
31787139Smarkm    if (cnt-- < 1)
31887139Smarkm	return;
31987139Smarkm    switch (*data++) {
32087139Smarkm    case KRB_AUTH:
32187139Smarkm	auth.data = (char *)data;
32287139Smarkm	auth.length = cnt;
32387139Smarkm
32487139Smarkm	auth_context = NULL;
32587139Smarkm
32687139Smarkm	ret = krb5_auth_con_init (context, &auth_context);
32787139Smarkm	if (ret) {
32887139Smarkm	    Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1);
32987139Smarkm	    auth_finished(ap, AUTH_REJECT);
33087139Smarkm	    if (auth_debug_mode)
331233932Sstas		print_krb5_error(context, ret, "Kerberos V5: krb5_auth_con_init failed (%s)\r\n");
33287139Smarkm	    return;
33329088Smarkm	}
33429088Smarkm
33587139Smarkm	ret = krb5_auth_con_setaddrs_from_fd (context,
33687139Smarkm					      auth_context,
33787139Smarkm					      &zero);
33887139Smarkm	if (ret) {
33987139Smarkm	    Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1);
34087139Smarkm	    auth_finished(ap, AUTH_REJECT);
34187139Smarkm	    if (auth_debug_mode)
342233932Sstas		print_krb5_error(context, ret, "Kerberos V5: "
343233932Sstas		       "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n");
34487139Smarkm	    return;
34529088Smarkm	}
34629088Smarkm
34787139Smarkm	ret = krb5_sock_to_principal (context,
34887139Smarkm				      0,
34987139Smarkm				      "host",
35087139Smarkm				      KRB5_NT_SRV_HST,
35187139Smarkm				      &server);
35287139Smarkm	if (ret) {
35387139Smarkm	    Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1);
35487139Smarkm	    auth_finished(ap, AUTH_REJECT);
35587139Smarkm	    if (auth_debug_mode)
356233932Sstas		print_krb5_error(context, ret, "Kerberos V5: "
357233932Sstas		       "krb5_sock_to_principal failed (%s)\r\n");
35887139Smarkm	    return;
35987139Smarkm	}
36029088Smarkm
36187139Smarkm	ret = krb5_rd_req(context,
36287139Smarkm			  &auth_context,
36387139Smarkm			  &auth,
36487139Smarkm			  server,
36587139Smarkm			  NULL,
36687139Smarkm			  NULL,
36787139Smarkm			  &ticket);
36829088Smarkm
36987139Smarkm	krb5_free_principal (context, server);
37087139Smarkm	if (ret) {
37187139Smarkm	    char *errbuf;
372233932Sstas	    const char *err_str;
37387139Smarkm
374233932Sstas	    err_str = krb5_get_error_message(context, ret);
37587139Smarkm	    asprintf(&errbuf,
376233932Sstas		     "Read req failed: %s", err_str);
377233932Sstas	    krb5_free_error_message(context, err_str);
37887139Smarkm	    Data(ap, KRB_REJECT, errbuf, -1);
37987139Smarkm	    if (auth_debug_mode)
38087139Smarkm		printf("%s\r\n", errbuf);
38187139Smarkm	    free (errbuf);
38287139Smarkm	    return;
38329088Smarkm	}
38487139Smarkm
38587139Smarkm	{
38687139Smarkm	    char foo[2];
38787139Smarkm
38887139Smarkm	    foo[0] = ap->type;
38987139Smarkm	    foo[1] = ap->way;
39087139Smarkm
39187139Smarkm	    ret = krb5_verify_authenticator_checksum(context,
39287139Smarkm						     auth_context,
39387139Smarkm						     foo,
39487139Smarkm						     sizeof(foo));
39529088Smarkm
39687139Smarkm	    if (ret) {
39787139Smarkm		char *errbuf;
398233932Sstas		const char *err_str;
399233932Sstas
400233932Sstas		err_str = krb5_get_error_message(context, ret);
401233932Sstas		asprintf(&errbuf, "Bad checksum: %s", err_str);
402233932Sstas		krb5_free_error_message(context, err_str);
40387139Smarkm		Data(ap, KRB_REJECT, errbuf, -1);
40429088Smarkm		if (auth_debug_mode)
40587139Smarkm		    printf ("%s\r\n", errbuf);
40687139Smarkm		free(errbuf);
40787139Smarkm		return;
40887139Smarkm	    }
40929088Smarkm	}
41087139Smarkm	ret = krb5_auth_con_getremotesubkey (context,
41187139Smarkm					     auth_context,
41287139Smarkm					     &key_block);
41387139Smarkm
41487139Smarkm	if (ret) {
41587139Smarkm	    Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1);
41687139Smarkm	    auth_finished(ap, AUTH_REJECT);
41787139Smarkm	    if (auth_debug_mode)
418233932Sstas		print_krb5_error(context, ret, "Kerberos V5: "
419233932Sstas		       "krb5_auth_con_getremotesubkey failed (%s)\r\n");
42087139Smarkm	    return;
42129088Smarkm	}
42229088Smarkm
423111946Snectar	if (key_block == NULL) {
424111946Snectar	    ret = krb5_auth_con_getkey(context,
425111946Snectar				       auth_context,
426111946Snectar				       &key_block);
427111946Snectar	}
428111946Snectar	if (ret) {
429111946Snectar	    Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1);
430111946Snectar	    auth_finished(ap, AUTH_REJECT);
431111946Snectar	    if (auth_debug_mode)
432233932Sstas		print_krb5_error(context, ret, "Kerberos V5: "
433233932Sstas		       "krb5_auth_con_getkey failed (%s)\r\n");
434111946Snectar	    return;
435111946Snectar	}
436111946Snectar	if (key_block == NULL) {
437111946Snectar	    Data(ap, KRB_REJECT, "no subkey received", -1);
438111946Snectar	    auth_finished(ap, AUTH_REJECT);
439111946Snectar	    if (auth_debug_mode)
440111946Snectar		printf("Kerberos V5: "
441111946Snectar		       "krb5_auth_con_getremotesubkey returned NULL key\r\n");
442111946Snectar	    return;
443111946Snectar	}
444111946Snectar
44587139Smarkm	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
44687139Smarkm	    ret = krb5_mk_rep(context, auth_context, &outbuf);
44787139Smarkm	    if (ret) {
44887139Smarkm		Data(ap, KRB_REJECT,
44987139Smarkm		     "krb5_mk_rep failed", -1);
45087139Smarkm		auth_finished(ap, AUTH_REJECT);
45187139Smarkm		if (auth_debug_mode)
452233932Sstas		    print_krb5_error(context, ret, "Kerberos V5: "
453233932Sstas			   "krb5_mk_rep failed (%s)\r\n");
45429088Smarkm		return;
45587139Smarkm	    }
45687139Smarkm	    Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
45787139Smarkm	}
45887139Smarkm	if (krb5_unparse_name(context, ticket->client, &name))
45987139Smarkm	    name = 0;
46029088Smarkm
46187139Smarkm	if(UserNameRequested && krb5_kuserok(context,
46287139Smarkm					     ticket->client,
46387139Smarkm					     UserNameRequested)) {
46487139Smarkm	    Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
46587139Smarkm	    if (auth_debug_mode) {
46687139Smarkm		printf("Kerberos5 identifies him as ``%s''\r\n",
46787139Smarkm		       name ? name : "");
46887139Smarkm	    }
46929088Smarkm
47087139Smarkm	    if(key_block->keytype == ETYPE_DES_CBC_MD5 ||
47187139Smarkm	       key_block->keytype == ETYPE_DES_CBC_MD4 ||
47287139Smarkm	       key_block->keytype == ETYPE_DES_CBC_CRC) {
47387139Smarkm		Session_Key skey;
47429088Smarkm
47587139Smarkm		skey.type = SK_DES;
47687139Smarkm		skey.length = 8;
47787139Smarkm		skey.data = key_block->keyvalue.data;
47887139Smarkm		encrypt_session_key(&skey, 0);
47987139Smarkm	    }
48029088Smarkm
48187139Smarkm	} else {
48287139Smarkm	    char *msg;
48329088Smarkm
48487139Smarkm	    asprintf (&msg, "user `%s' is not authorized to "
48587139Smarkm		      "login as `%s'",
48687139Smarkm		      name ? name : "<unknown>",
48787139Smarkm		      UserNameRequested ? UserNameRequested : "<nobody>");
48887139Smarkm	    if (msg == NULL)
48987139Smarkm		Data(ap, KRB_REJECT, NULL, 0);
49087139Smarkm	    else {
49187139Smarkm		Data(ap, KRB_REJECT, (void *)msg, -1);
49287139Smarkm		free(msg);
49387139Smarkm	    }
49487139Smarkm	    auth_finished (ap, AUTH_REJECT);
49587139Smarkm	    krb5_free_keyblock_contents(context, key_block);
49687139Smarkm	    break;
49787139Smarkm	}
49887139Smarkm	auth_finished(ap, AUTH_USER);
49987139Smarkm	krb5_free_keyblock_contents(context, key_block);
50087139Smarkm
50187139Smarkm	break;
50287139Smarkm    case KRB_FORWARD: {
50387139Smarkm	struct passwd *pwd;
50487139Smarkm	char ccname[1024];	/* XXX */
50587139Smarkm	krb5_data inbuf;
50687139Smarkm	krb5_ccache ccache;
50787139Smarkm	inbuf.data = (char *)data;
50887139Smarkm	inbuf.length = cnt;
50929088Smarkm
51087139Smarkm	pwd = getpwnam (UserNameRequested);
51187139Smarkm	if (pwd == NULL)
51287139Smarkm	    break;
51329088Smarkm
51487139Smarkm	snprintf (ccname, sizeof(ccname),
51587139Smarkm		  "FILE:/tmp/krb5cc_%u", pwd->pw_uid);
51629088Smarkm
51787139Smarkm	ret = krb5_cc_resolve (context, ccname, &ccache);
51887139Smarkm	if (ret) {
51987139Smarkm	    if (auth_debug_mode)
520233932Sstas		print_krb5_error(context, ret, "Kerberos V5: could not get ccache: %s\r\n");
52187139Smarkm	    break;
52287139Smarkm	}
52329088Smarkm
52487139Smarkm	ret = krb5_cc_initialize (context,
52587139Smarkm				  ccache,
52687139Smarkm				  ticket->client);
52787139Smarkm	if (ret) {
52887139Smarkm	    if (auth_debug_mode)
529233932Sstas		print_krb5_error(context, ret, "Kerberos V5: could not init ccache: %s\r\n");
53087139Smarkm	    break;
53187139Smarkm	}
53229088Smarkm
53387139Smarkm#if defined(DCE)
53487139Smarkm	esetenv("KRB5CCNAME", ccname, 1);
53587139Smarkm#endif
53687139Smarkm	ret = krb5_rd_cred2 (context,
53787139Smarkm			     auth_context,
53887139Smarkm			     ccache,
53987139Smarkm			     &inbuf);
54087139Smarkm	if(ret) {
54187139Smarkm	    char *errbuf;
542233932Sstas	    const char *err_str;
54329088Smarkm
544233932Sstas	    err_str = krb5_get_error_message(context, ret);
54587139Smarkm	    asprintf (&errbuf,
546233932Sstas		      "Read forwarded creds failed: %s", err_str);
547233932Sstas	    krb5_free_error_message(context, err_str);
54887139Smarkm	    if(errbuf == NULL)
54987139Smarkm		Data(ap, KRB_FORWARD_REJECT, NULL, 0);
55087139Smarkm	    else
55187139Smarkm		Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
55287139Smarkm	    if (auth_debug_mode)
55387139Smarkm		printf("Could not read forwarded credentials: %s\r\n",
55487139Smarkm		       errbuf);
55587139Smarkm	    free (errbuf);
55687139Smarkm	} else {
55787139Smarkm	    Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
55887139Smarkm#if defined(DCE)
55987139Smarkm	    dfsfwd = 1;
56087139Smarkm#endif
56129088Smarkm	}
56287139Smarkm	chown (ccname + 5, pwd->pw_uid, -1);
56387139Smarkm	if (auth_debug_mode)
56487139Smarkm	    printf("Forwarded credentials obtained\r\n");
56587139Smarkm	break;
56687139Smarkm    }
56787139Smarkm    default:
56887139Smarkm	if (auth_debug_mode)
56987139Smarkm	    printf("Unknown Kerberos option %d\r\n", data[-1]);
57087139Smarkm	Data(ap, KRB_REJECT, 0, 0);
57187139Smarkm	break;
57287139Smarkm    }
57329088Smarkm}
57429088Smarkm
57587139Smarkmvoid
57687139Smarkmkerberos5_reply(Authenticator *ap, unsigned char *data, int cnt)
57729088Smarkm{
57887139Smarkm    static int mutual_complete = 0;
57987139Smarkm
58087139Smarkm    if (cnt-- < 1)
58187139Smarkm	return;
58287139Smarkm    switch (*data++) {
58387139Smarkm    case KRB_REJECT:
58487139Smarkm	if (cnt > 0) {
58587139Smarkm	    printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
58687139Smarkm		   cnt, data);
58787139Smarkm	} else
58887139Smarkm	    printf("[ Kerberos V5 refuses authentication ]\r\n");
58987139Smarkm	auth_send_retry();
59087139Smarkm	return;
59187139Smarkm    case KRB_ACCEPT: {
59287139Smarkm	krb5_error_code ret;
59329088Smarkm	Session_Key skey;
59487139Smarkm	krb5_keyblock *keyblock;
59587139Smarkm
59687139Smarkm	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
59787139Smarkm	    !mutual_complete) {
59887139Smarkm	    printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
59987139Smarkm	    auth_send_retry();
60087139Smarkm	    return;
60187139Smarkm	}
60287139Smarkm	if (cnt)
60387139Smarkm	    printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
60487139Smarkm	else
60587139Smarkm	    printf("[ Kerberos V5 accepts you ]\r\n");
60687139Smarkm
60787139Smarkm	ret = krb5_auth_con_getlocalsubkey (context,
60887139Smarkm					    auth_context,
60987139Smarkm					    &keyblock);
61087139Smarkm	if (ret)
61187139Smarkm	    ret = krb5_auth_con_getkey (context,
61287139Smarkm					auth_context,
61387139Smarkm					&keyblock);
61487139Smarkm	if(ret) {
615233932Sstas	    print_krb5_error(context, ret, "[ krb5_auth_con_getkey: %s ]\r\n");
61687139Smarkm	    auth_send_retry();
61787139Smarkm	    return;
61887139Smarkm	}
61987139Smarkm
62087139Smarkm	skey.type = SK_DES;
62187139Smarkm	skey.length = 8;
62287139Smarkm	skey.data = keyblock->keyvalue.data;
62387139Smarkm	encrypt_session_key(&skey, 0);
62487139Smarkm	krb5_free_keyblock_contents (context, keyblock);
62587139Smarkm	auth_finished(ap, AUTH_USER);
62687139Smarkm	if (forward_flags & OPTS_FORWARD_CREDS)
62787139Smarkm	    kerberos5_forward(ap);
62887139Smarkm	break;
62987139Smarkm    }
63087139Smarkm    case KRB_RESPONSE:
63187139Smarkm	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
63287139Smarkm	    /* the rest of the reply should contain a krb_ap_rep */
63387139Smarkm	  krb5_ap_rep_enc_part *reply;
63487139Smarkm	  krb5_data inbuf;
63587139Smarkm	  krb5_error_code ret;
63687139Smarkm
63787139Smarkm	  inbuf.length = cnt;
63887139Smarkm	  inbuf.data = (char *)data;
63929088Smarkm
64087139Smarkm	  ret = krb5_rd_rep(context, auth_context, &inbuf, &reply);
64187139Smarkm	  if (ret) {
642233932Sstas	      print_krb5_error(context, ret, "[ Mutual authentication failed: %s ]\r\n");
64387139Smarkm	      auth_send_retry();
64487139Smarkm	      return;
64587139Smarkm	  }
64687139Smarkm	  krb5_free_ap_rep_enc_part(context, reply);
64787139Smarkm	  mutual_complete = 1;
64829088Smarkm	}
64987139Smarkm	return;
65087139Smarkm    case KRB_FORWARD_ACCEPT:
65187139Smarkm	printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
65287139Smarkm	return;
65387139Smarkm    case KRB_FORWARD_REJECT:
65487139Smarkm	printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
65587139Smarkm	       cnt, data);
65687139Smarkm	return;
65787139Smarkm    default:
65887139Smarkm	if (auth_debug_mode)
65987139Smarkm	    printf("Unknown Kerberos option %d\r\n", data[-1]);
66087139Smarkm	return;
66187139Smarkm    }
66229088Smarkm}
66329088Smarkm
66487139Smarkmint
66587139Smarkmkerberos5_status(Authenticator *ap __unused, char *name, int level)
66629088Smarkm{
66787139Smarkm    if (level < AUTH_USER)
66887139Smarkm	return(level);
66929088Smarkm
67087139Smarkm    if (UserNameRequested &&
67187139Smarkm	krb5_kuserok(context,
67287139Smarkm		     ticket->client,
67387139Smarkm		     UserNameRequested))
67429088Smarkm	{
67587139Smarkm	    strcpy(name, UserNameRequested);
67687139Smarkm	    return(AUTH_VALID);
67729088Smarkm	} else
67887139Smarkm	    return(AUTH_USER);
67929088Smarkm}
68029088Smarkm
68129088Smarkm#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
68229088Smarkm#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
68329088Smarkm
68487139Smarkmvoid
68587139Smarkmkerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
68629088Smarkm{
68787139Smarkm    int i;
68829088Smarkm
68987139Smarkm    buf[buflen-1] = '\0';		/* make sure its NULL terminated */
69087139Smarkm    buflen -= 1;
69129088Smarkm
69287139Smarkm    switch(data[3]) {
69387139Smarkm    case KRB_REJECT:		/* Rejected (reason might follow) */
69487139Smarkm	strlcpy((char *)buf, " REJECT ", buflen);
69587139Smarkm	goto common;
69629088Smarkm
69787139Smarkm    case KRB_ACCEPT:		/* Accepted (name might follow) */
69887139Smarkm	strlcpy((char *)buf, " ACCEPT ", buflen);
69987139Smarkm    common:
70087139Smarkm	BUMP(buf, buflen);
70187139Smarkm	if (cnt <= 4)
70287139Smarkm	    break;
70387139Smarkm	ADDC(buf, buflen, '"');
70487139Smarkm	for (i = 4; i < cnt; i++)
70587139Smarkm	    ADDC(buf, buflen, data[i]);
70687139Smarkm	ADDC(buf, buflen, '"');
70787139Smarkm	ADDC(buf, buflen, '\0');
70887139Smarkm	break;
70929088Smarkm
71029088Smarkm
71187139Smarkm    case KRB_AUTH:			/* Authentication data follows */
71287139Smarkm	strlcpy((char *)buf, " AUTH", buflen);
71387139Smarkm	goto common2;
71429088Smarkm
71587139Smarkm    case KRB_RESPONSE:
71687139Smarkm	strlcpy((char *)buf, " RESPONSE", buflen);
71787139Smarkm	goto common2;
71829088Smarkm
71987139Smarkm    case KRB_FORWARD:		/* Forwarded credentials follow */
72087139Smarkm	strlcpy((char *)buf, " FORWARD", buflen);
72187139Smarkm	goto common2;
72229088Smarkm
72387139Smarkm    case KRB_FORWARD_ACCEPT:	/* Forwarded credentials accepted */
72487139Smarkm	strlcpy((char *)buf, " FORWARD_ACCEPT", buflen);
72587139Smarkm	goto common2;
72629088Smarkm
72787139Smarkm    case KRB_FORWARD_REJECT:	/* Forwarded credentials rejected */
72887139Smarkm	/* (reason might follow) */
72987139Smarkm	strlcpy((char *)buf, " FORWARD_REJECT", buflen);
73087139Smarkm	goto common2;
73129088Smarkm
73287139Smarkm    default:
73387139Smarkm	snprintf(buf, buflen, " %d (unknown)", data[3]);
73487139Smarkm    common2:
73587139Smarkm	BUMP(buf, buflen);
73687139Smarkm	for (i = 4; i < cnt; i++) {
73787139Smarkm	    snprintf(buf, buflen, " %d", data[i]);
73887139Smarkm	    BUMP(buf, buflen);
73929088Smarkm	}
74087139Smarkm	break;
74187139Smarkm    }
74229088Smarkm}
74329088Smarkm
74487139Smarkmvoid
74587139Smarkmkerberos5_forward(Authenticator *ap)
74629088Smarkm{
74787139Smarkm    krb5_error_code ret;
74887139Smarkm    krb5_ccache     ccache;
74987139Smarkm    krb5_creds      creds;
75087139Smarkm    krb5_kdc_flags  flags;
75187139Smarkm    krb5_data       out_data;
75287139Smarkm    krb5_principal  principal;
75329088Smarkm
75487139Smarkm    ret = krb5_cc_default (context, &ccache);
75587139Smarkm    if (ret) {
75629088Smarkm	if (auth_debug_mode)
757233932Sstas	    print_krb5_error(context, ret, "KerberosV5: could not get default ccache: %s\r\n");
75829088Smarkm	return;
75929088Smarkm    }
76029088Smarkm
76187139Smarkm    ret = krb5_cc_get_principal (context, ccache, &principal);
76287139Smarkm    if (ret) {
76329088Smarkm	if (auth_debug_mode)
764233932Sstas	    print_krb5_error(context, ret, "KerberosV5: could not get principal: %s\r\n");
76529088Smarkm	return;
76629088Smarkm    }
76729088Smarkm
76887139Smarkm    memset (&creds, 0, sizeof(creds));
76929088Smarkm
77087139Smarkm    creds.client = principal;
77187139Smarkm
77287139Smarkm    ret = krb5_build_principal (context,
77387139Smarkm				&creds.server,
77487139Smarkm				strlen(principal->realm),
77587139Smarkm				principal->realm,
77687139Smarkm				"krbtgt",
77787139Smarkm				principal->realm,
77887139Smarkm				NULL);
77929088Smarkm
78087139Smarkm    if (ret) {
78129088Smarkm	if (auth_debug_mode)
782233932Sstas	    print_krb5_error(context, ret, "KerberosV5: could not get principal: %s\r\n");
78329088Smarkm	return;
78429088Smarkm    }
78529088Smarkm
78687139Smarkm    creds.times.endtime = 0;
78787139Smarkm
78887139Smarkm    flags.i = 0;
78987139Smarkm    flags.b.forwarded = 1;
79087139Smarkm    if (forward_flags & OPTS_FORWARDABLE_CREDS)
79187139Smarkm	flags.b.forwardable = 1;
79287139Smarkm
79387139Smarkm    ret = krb5_get_forwarded_creds (context,
79487139Smarkm				    auth_context,
79587139Smarkm				    ccache,
79687139Smarkm				    flags.i,
79787139Smarkm				    RemoteHostName,
79887139Smarkm				    &creds,
79987139Smarkm				    &out_data);
80087139Smarkm    if (ret) {
80129088Smarkm	if (auth_debug_mode)
802233932Sstas	    print_krb5_error(context, ret, "Kerberos V5: error getting forwarded creds: %s\r\n");
80329088Smarkm	return;
80429088Smarkm    }
80529088Smarkm
80687139Smarkm    if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) {
80729088Smarkm	if (auth_debug_mode)
80887139Smarkm	    printf("Not enough room for authentication data\r\n");
80987139Smarkm    } else {
81029088Smarkm	if (auth_debug_mode)
81187139Smarkm	    printf("Forwarded local Kerberos V5 credentials to server\r\n");
81229088Smarkm    }
81387139Smarkm}
81429088Smarkm
81587139Smarkm#if defined(DCE)
81687139Smarkm/* if this was a K5 authentication try and join a PAG for the user. */
81787139Smarkmvoid
81887139Smarkmkerberos5_dfspag(void)
81987139Smarkm{
82087139Smarkm    if (dfsk5ok) {
82187139Smarkm	dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client,
82287139Smarkm			      UserNameRequested);
82387139Smarkm    }
82429088Smarkm}
82587139Smarkm#endif
82629088Smarkm
82729088Smarkm#endif /* KRB5 */
828