1 |
/* |
/* Copyright (C) 2002 Free Software Foundation, Inc. |
2 |
* $Source$ |
|
3 |
* $Author$ |
This file is part of GNU Inetutils. |
4 |
* $Id$ |
|
5 |
*/ |
GNU Inetutils is free software; you can redistribute it and/or modify |
6 |
|
it under the terms of the GNU General Public License as published by |
7 |
|
the Free Software Foundation; either version 2, or (at your option) |
8 |
|
any later version. |
9 |
|
|
10 |
|
GNU Inetutils is distributed in the hope that it will be useful, |
11 |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE. See the |
13 |
|
GNU General Public License for more details. |
14 |
|
|
15 |
|
You should have received a copy of the GNU General Public License |
16 |
|
along with GNU Inetutils; see the file COPYING. If not, write to |
17 |
|
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 |
|
Boston, MA 02111-1307, USA. */ |
19 |
|
|
20 |
#ifdef HAVE_CONFIG_H |
#ifdef HAVE_CONFIG_H |
21 |
#include <config.h> |
#include <config.h> |
22 |
#endif |
#endif |
23 |
|
|
24 |
#if !defined(lint) && !defined(SABER) |
#ifdef KRB5 |
25 |
static |
#include <stdlib.h> |
|
const |
|
|
char rcsid_kerberos5_c[] = "$Id$"; |
|
|
#endif /* lint */ |
|
|
|
|
|
/*- |
|
|
* Copyright (c) 1991, 1993 |
|
|
* The Regents of the University of California. All rights reserved. |
|
|
* |
|
|
* Redistribution and use in source and binary forms, with or without |
|
|
* modification, are permitted provided that the following conditions |
|
|
* are met: |
|
|
* 1. Redistributions of source code must retain the above copyright |
|
|
* notice, this list of conditions and the following disclaimer. |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
|
* notice, this list of conditions and the following disclaimer in the |
|
|
* documentation and/or other materials provided with the distribution. |
|
|
* 4. Neither the name of the University nor the names of its contributors |
|
|
* may be used to endorse or promote products derived from this software |
|
|
* without specific prior written permission. |
|
|
* |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
|
* SUCH DAMAGE. |
|
|
*/ |
|
|
|
|
|
#ifndef lint |
|
|
static char sccsid[] = "@(#)kerberos5.c 8.3 (Berkeley) 5/30/95"; |
|
|
#endif /* not lint */ |
|
|
|
|
|
/* |
|
|
* Copyright (C) 1990 by the Massachusetts Institute of Technology |
|
|
* |
|
|
* Export of this software from the United States of America may |
|
|
* require a specific license from the United States Government. |
|
|
* It is the responsibility of any person or organization contemplating |
|
|
* export to obtain such a license before exporting. |
|
|
* |
|
|
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and |
|
|
* distribute this software and its documentation for any purpose and |
|
|
* without fee is hereby granted, provided that the above copyright |
|
|
* notice appear in all copies and that both that copyright notice and |
|
|
* this permission notice appear in supporting documentation, and that |
|
|
* the name of M.I.T. not be used in advertising or publicity pertaining |
|
|
* to distribution of the software without specific, written prior |
|
|
* permission. M.I.T. makes no representations about the suitability of |
|
|
* this software for any purpose. It is provided "as is" without express |
|
|
* or implied warranty. |
|
|
*/ |
|
|
|
|
|
|
|
|
#ifdef KRB5 |
|
|
#include <arpa/telnet.h> |
|
26 |
#include <stdio.h> |
#include <stdio.h> |
27 |
#include <krb5/krb5.h> |
#include <arpa/telnet.h> |
28 |
#include <krb5/asn1.h> |
#include <krb5.h> |
29 |
#include <krb5/crc-32.h> |
#include <assert.h> |
30 |
#include <krb5/los-proto.h> |
|
|
#include <krb5/ext-proto.h> |
|
31 |
#include <com_err.h> |
#include <com_err.h> |
32 |
#include <netdb.h> |
#include <netdb.h> |
33 |
#include <ctype.h> |
#include <ctype.h> |
34 |
|
#include <syslog.h> |
35 |
|
#ifdef HAVE_STRING_H |
36 |
|
# include <string.h> |
37 |
|
#else |
38 |
|
# include <strings.h> |
39 |
|
#endif |
40 |
|
|
|
/* kerberos 5 include files (ext-proto.h) will get an appropriate stdlib.h |
|
|
and string.h/strings.h */ |
|
|
|
|
|
#include "encrypt.h" |
|
41 |
#include "auth.h" |
#include "auth.h" |
42 |
#include "misc.h" |
#include "misc.h" |
43 |
|
|
44 |
extern auth_debug_mode; |
#ifndef KRB5_ENV_CCNAME |
45 |
|
# define KRB5_ENV_CCNAME "KRB5CCNAME" |
46 |
|
#endif |
47 |
|
|
48 |
|
#ifdef FORWARD |
49 |
|
/* FIXME: This is set directly from telnet/main.c */ |
50 |
|
int forward_flags = 0; |
51 |
|
extern int net; /*FIXME*/ |
52 |
|
|
53 |
|
void kerberos5_forward (); |
54 |
|
#endif /* FORWARD */ |
55 |
|
|
56 |
|
static unsigned char str_data[2048] = { IAC, SB, TELOPT_AUTHENTICATION, 0, |
57 |
|
AUTHTYPE_KERBEROS_V5, }; |
58 |
|
|
59 |
|
#define KRB_AUTH 0 /* Authentication data follows */ |
60 |
|
#define KRB_REJECT 1 /* Rejected (reason might follow) */ |
61 |
|
#define KRB_ACCEPT 2 /* Accepted */ |
62 |
|
#define KRB_RESPONSE 3 /* Response for mutual auth. */ |
63 |
|
#define KRB_FORWARD 4 /* Forwarded credentials follow */ |
64 |
|
#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ |
65 |
|
#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ |
66 |
|
|
67 |
|
krb5_auth_context auth_context = 0; |
68 |
|
krb5_context telnet_context = 0; |
69 |
|
|
70 |
|
static krb5_data auth; /* session key for telnet */ |
71 |
|
static krb5_ticket *ticket = NULL; /* telnet matches the AP_REQ and |
72 |
|
AP_REP with this */ |
73 |
|
|
74 |
|
krb5_keyblock *session_key = 0; |
75 |
|
char *telnet_srvtab = NULL; |
76 |
|
char *telnet_krb5_realm = NULL; |
77 |
|
|
78 |
|
#define DEBUG(c) if (auth_debug_mode) printf c |
79 |
|
|
80 |
|
static int |
81 |
|
Data (Authenticator *ap, int type, krb5_pointer d, int c) |
82 |
|
{ |
83 |
|
unsigned char *p = str_data + 4; |
84 |
|
unsigned char *cd = (unsigned char *) d; |
85 |
|
|
86 |
|
if (c == -1) |
87 |
|
c = strlen (cd); |
88 |
|
|
89 |
|
if (auth_debug_mode) |
90 |
|
{ |
91 |
|
printf ("%s:%d: [%d] (%d)", |
92 |
|
str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", |
93 |
|
str_data[3], |
94 |
|
type, c); |
95 |
|
printd (d, c); |
96 |
|
printf ("\r\n"); |
97 |
|
} |
98 |
|
|
99 |
|
*p++ = ap->type; |
100 |
|
*p++ = ap->way; |
101 |
|
*p++ = type; |
102 |
|
|
103 |
|
while (c-- > 0) { |
104 |
|
if ((*p++ = *cd++) == IAC) |
105 |
|
*p++ = IAC; |
106 |
|
} |
107 |
|
*p++ = IAC; |
108 |
|
*p++ = SE; |
109 |
|
if (str_data[3] == TELQUAL_IS) |
110 |
|
printsub ('>', &str_data[2], p - &str_data[2]); |
111 |
|
return (net_write (str_data, p - str_data)); |
112 |
|
} |
113 |
|
|
114 |
|
/* FIXME: Reverse return code! */ |
115 |
|
int |
116 |
|
kerberos5_init (Authenticator *ap, int server) |
117 |
|
{ |
118 |
|
str_data[3] = server ? TELQUAL_REPLY : TELQUAL_IS; |
119 |
|
if (telnet_context == 0 && krb5_init_context(&telnet_context)) |
120 |
|
return 0; |
121 |
|
return 1; |
122 |
|
} |
123 |
|
|
124 |
|
void |
125 |
|
kerberos5_cleanup () |
126 |
|
{ |
127 |
|
krb5_ccache ccache; |
128 |
|
char *ccname; |
129 |
|
|
130 |
|
if (telnet_context == 0) |
131 |
|
return; |
132 |
|
|
133 |
|
ccname = getenv (KRB5_ENV_CCNAME); |
134 |
|
if (ccname) |
135 |
|
{ |
136 |
|
if (!krb5_cc_resolve (telnet_context, ccname, &ccache)) |
137 |
|
krb5_cc_destroy (telnet_context, ccache); |
138 |
|
} |
139 |
|
|
140 |
#ifdef FORWARD |
krb5_free_context (telnet_context); |
141 |
int forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */ |
telnet_context = 0; |
142 |
|
} |
143 |
|
|
144 |
/* These values need to be the same as those defined in telnet/main.c. */ |
#ifdef ENCRYPTION |
145 |
/* Either define them in both places, or put in some common header file. */ |
|
146 |
#define OPTS_FORWARD_CREDS 0x00000002 |
void |
147 |
#define OPTS_FORWARDABLE_CREDS 0x00000001 |
encryption_init (krb5_creds *creds) |
148 |
|
{ |
149 |
void kerberos5_forward(); |
krb5_keyblock *newkey = 0; |
150 |
|
|
151 |
#endif /* FORWARD */ |
krb5_auth_con_getlocalsubkey (telnet_context, auth_context, &newkey); |
152 |
|
if (session_key) |
153 |
static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, |
{ |
154 |
AUTHTYPE_KERBEROS_V5, }; |
krb5_free_keyblock (telnet_context, session_key); |
155 |
/*static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, |
session_key = 0; |
156 |
TELQUAL_NAME, };*/ |
} |
157 |
|
|
158 |
#define KRB_AUTH 0 /* Authentication data follows */ |
if (newkey) |
159 |
#define KRB_REJECT 1 /* Rejected (reason might follow) */ |
{ |
160 |
#define KRB_ACCEPT 2 /* Accepted */ |
switch (newkey->enctype) |
161 |
#define KRB_RESPONSE 3 /* Response for mutual auth. */ |
{ |
162 |
|
case ENCTYPE_DES_CBC_CRC: |
163 |
#ifdef FORWARD |
case ENCTYPE_DES_CBC_MD5: |
164 |
#define KRB_FORWARD 4 /* Forwarded credentials follow */ |
krb5_copy_keyblock (telnet_context, newkey, &session_key); |
165 |
#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ |
break; |
166 |
#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ |
|
167 |
#endif /* FORWARD */ |
default: |
168 |
|
switch (creds->keyblock.enctype) |
169 |
static krb5_data auth; |
{ |
170 |
/* telnetd gets session key from here */ |
case ENCTYPE_DES_CBC_CRC: |
171 |
static krb5_tkt_authent *authdat = NULL; |
case ENCTYPE_DES_CBC_MD5: |
172 |
/* telnet matches the AP_REQ and AP_REP with this */ |
krb5_copy_keyblock (telnet_context, &creds->keyblock, |
173 |
static krb5_authenticator authenticator; |
&session_key); |
174 |
|
break; |
175 |
/* some compilers can't hack void *, so we use the Kerberos krb5_pointer, |
|
176 |
which is either void * or char *, depending on the compiler. */ |
default: |
177 |
|
DEBUG(("can't determine which keyblock to use")); |
178 |
#define Voidptr krb5_pointer |
/*FIXME: abort?*/ |
|
|
|
|
Block session_key; |
|
|
|
|
|
static int |
|
|
Data(ap, type, d, c) |
|
|
Authenticator *ap; |
|
|
int type; |
|
|
Voidptr d; |
|
|
int c; |
|
|
{ |
|
|
unsigned char *p = str_data + 4; |
|
|
unsigned char *cd = (unsigned char *)d; |
|
|
|
|
|
if (c == -1) |
|
|
c = strlen((char *)cd); |
|
|
|
|
|
if (auth_debug_mode) { |
|
|
printf("%s:%d: [%d] (%d)", |
|
|
str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", |
|
|
str_data[3], |
|
|
type, c); |
|
|
printd(d, c); |
|
|
printf("\r\n"); |
|
|
} |
|
|
*p++ = ap->type; |
|
|
*p++ = ap->way; |
|
|
*p++ = type; |
|
|
while (c-- > 0) { |
|
|
if ((*p++ = *cd++) == IAC) |
|
|
*p++ = IAC; |
|
|
} |
|
|
*p++ = IAC; |
|
|
*p++ = SE; |
|
|
if (str_data[3] == TELQUAL_IS) |
|
|
printsub('>', &str_data[2], p - &str_data[2]); |
|
|
return(net_write(str_data, p - str_data)); |
|
|
} |
|
|
|
|
|
int |
|
|
kerberos5_init(ap, server) |
|
|
Authenticator *ap; |
|
|
int server; |
|
|
{ |
|
|
if (server) |
|
|
str_data[3] = TELQUAL_REPLY; |
|
|
else |
|
|
str_data[3] = TELQUAL_IS; |
|
|
krb5_init_ets(); |
|
|
return(1); |
|
|
} |
|
|
|
|
|
int |
|
|
kerberos5_send(ap) |
|
|
Authenticator *ap; |
|
|
{ |
|
|
char **realms; |
|
|
char *name; |
|
|
char *p1, *p2; |
|
|
krb5_checksum ksum; |
|
|
krb5_octet sum[CRC32_CKSUM_LENGTH]; |
|
|
krb5_principal server; |
|
|
krb5_error_code r; |
|
|
krb5_ccache ccache; |
|
|
krb5_creds creds; /* telnet gets session key from here */ |
|
|
extern krb5_flags krb5_kdc_default_options; |
|
|
int ap_opts; |
|
|
|
|
|
#ifdef ENCRYPTION |
|
|
krb5_keyblock *newkey = 0; |
|
|
#endif /* ENCRYPTION */ |
|
|
|
|
|
ksum.checksum_type = CKSUMTYPE_CRC32; |
|
|
ksum.contents = sum; |
|
|
ksum.length = sizeof(sum); |
|
|
memset((Voidptr )sum, 0, sizeof(sum)); |
|
|
|
|
|
if (!UserNameRequested) { |
|
|
if (auth_debug_mode) { |
|
|
printf("Kerberos V5: no user name supplied\r\n"); |
|
|
} |
|
|
return(0); |
|
|
} |
|
|
|
|
|
if (r = krb5_cc_default(&ccache)) { |
|
|
if (auth_debug_mode) { |
|
|
printf("Kerberos V5: could not get default ccache\r\n"); |
|
|
} |
|
|
return(0); |
|
|
} |
|
|
|
|
|
if ((name = malloc(strlen(RemoteHostName)+1)) == NULL) { |
|
|
if (auth_debug_mode) |
|
|
printf("Out of memory for hostname in Kerberos V5\r\n"); |
|
|
return(0); |
|
|
} |
|
|
|
|
|
if (r = krb5_get_host_realm(RemoteHostName, &realms)) { |
|
|
if (auth_debug_mode) |
|
|
printf("Kerberos V5: no realm for %s\r\n", RemoteHostName); |
|
|
free(name); |
|
|
return(0); |
|
|
} |
|
|
|
|
|
p1 = RemoteHostName; |
|
|
p2 = name; |
|
|
|
|
|
while (*p2 = *p1++) { |
|
|
if (isupper(*p2)) |
|
|
*p2 |= 040; |
|
|
++p2; |
|
|
} |
|
|
|
|
|
if (r = krb5_build_principal_ext(&server, |
|
|
strlen(realms[0]), realms[0], |
|
|
4, "host", |
|
|
p2 - name, name, |
|
|
0)) { |
|
|
if (auth_debug_mode) { |
|
|
printf("Kerberos V5: failure setting up principal (%s)\r\n", |
|
|
error_message(r)); |
|
|
} |
|
|
free(name); |
|
|
krb5_free_host_realm(realms); |
|
|
return(0); |
|
|
} |
|
|
|
|
|
|
|
|
memset((char *)&creds, 0, sizeof(creds)); |
|
|
creds.server = server; |
|
|
|
|
|
if (r = krb5_cc_get_principal(ccache, &creds.client)) { |
|
|
if (auth_debug_mode) { |
|
|
printf("Kerberos V5: failure on principal (%s)\r\n", |
|
|
error_message(r)); |
|
|
} |
|
|
free(name); |
|
|
krb5_free_principal(server); |
|
|
krb5_free_host_realm(realms); |
|
|
return(0); |
|
|
} |
|
|
|
|
|
if (r = krb5_get_credentials(krb5_kdc_default_options, ccache, &creds)) { |
|
|
if (auth_debug_mode) { |
|
|
printf("Kerberos V5: failure on credentials(%d)\r\n",r); |
|
|
} |
|
|
free(name); |
|
|
krb5_free_host_realm(realms); |
|
|
krb5_free_principal(server); |
|
|
return(0); |
|
|
} |
|
|
|
|
|
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) |
|
|
ap_opts = AP_OPTS_MUTUAL_REQUIRED; |
|
|
else |
|
|
ap_opts = 0; |
|
|
|
|
|
r = krb5_mk_req_extended(ap_opts, &ksum, krb5_kdc_default_options, 0, |
|
|
#ifdef ENCRYPTION |
|
|
&newkey, |
|
|
#else /* ENCRYPTION */ |
|
|
0, |
|
|
#endif /* ENCRYPTION */ |
|
|
ccache, &creds, &authenticator, &auth); |
|
|
/* don't let the key get freed if we clean up the authenticator */ |
|
|
authenticator.subkey = 0; |
|
|
|
|
|
free(name); |
|
|
krb5_free_host_realm(realms); |
|
|
krb5_free_principal(server); |
|
|
#ifdef ENCRYPTION |
|
|
if (newkey) { |
|
|
/* keep the key in our private storage, but don't use it |
|
|
yet---see kerberos5_reply() below */ |
|
|
if (newkey->keytype != KEYTYPE_DES) { |
|
|
if (creds.keyblock.keytype == KEYTYPE_DES) |
|
|
/* use the session key in credentials instead */ |
|
|
memmove((char *)session_key, |
|
|
(char *)creds.keyblock.contents, sizeof(Block)); |
|
|
else |
|
|
/* XXX ? */; |
|
|
} else { |
|
|
memmove((char *)session_key, (char *)newkey->contents, |
|
|
sizeof(Block)); |
|
179 |
} |
} |
|
krb5_free_keyblock(newkey); |
|
180 |
} |
} |
181 |
#endif /* ENCRYPTION */ |
|
182 |
if (r) { |
krb5_free_keyblock(telnet_context, newkey); |
183 |
if (auth_debug_mode) { |
} |
184 |
printf("Kerberos V5: mk_req failed (%s)\r\n", |
} |
185 |
error_message(r)); |
|
186 |
} |
#else |
187 |
return(0); |
# define encryption_init(c) |
188 |
} |
#endif |
189 |
|
|
190 |
if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { |
int |
191 |
if (auth_debug_mode) |
kerberos5_send (Authenticator *ap) |
192 |
printf("Not enough room for user name\r\n"); |
{ |
193 |
return(0); |
krb5_error_code r; |
194 |
} |
krb5_ccache ccache; |
195 |
if (!Data(ap, KRB_AUTH, auth.data, auth.length)) { |
krb5_creds creds; |
196 |
if (auth_debug_mode) |
krb5_creds *new_creds = 0; |
197 |
printf("Not enough room for authentication data\r\n"); |
int ap_opts; |
198 |
return(0); |
char type_check[2]; |
199 |
} |
krb5_data check_data; |
200 |
if (auth_debug_mode) { |
|
201 |
printf("Sent Kerberos V5 credentials to server\r\n"); |
if (!UserNameRequested) |
202 |
} |
{ |
203 |
return(1); |
DEBUG(("telnet: Kerberos V5: no user name supplied\r\n")); |
204 |
} |
return 0; |
205 |
|
} |
206 |
void |
|
207 |
kerberos5_is(ap, data, cnt) |
if ((r = krb5_cc_default (telnet_context, &ccache))) |
208 |
Authenticator *ap; |
{ |
209 |
unsigned char *data; |
DEBUG(("telnet: Kerberos V5: could not get default ccache\r\n")); |
210 |
int cnt; |
return 0; |
211 |
{ |
} |
212 |
int r; |
|
213 |
struct hostent *hp; |
memset (&creds, 0, sizeof (creds)); |
214 |
char *p1, *p2; |
if ((r = krb5_sname_to_principal (telnet_context, RemoteHostName, |
215 |
static char *realm = NULL; |
"host", KRB5_NT_SRV_HST, |
216 |
krb5_principal server; |
&creds.server))) |
217 |
krb5_ap_rep_enc_part reply; |
{ |
218 |
krb5_data outbuf; |
DEBUG(("telnet: Kerberos V5: error while constructing service name: %s\r\n", |
219 |
|
error_message(r))); |
220 |
|
return 0; |
221 |
|
} |
222 |
|
|
223 |
|
if (telnet_krb5_realm) |
224 |
|
{ |
225 |
|
krb5_data rdata; |
226 |
|
|
227 |
|
rdata.length = strlen (telnet_krb5_realm); |
228 |
|
rdata.data = malloc (rdata.length + 1); |
229 |
|
assert (rdata.data); |
230 |
|
strcpy (rdata.data, telnet_krb5_realm); |
231 |
|
krb5_princ_set_realm (telnet_context, creds.server, &rdata); |
232 |
|
} |
233 |
|
|
234 |
|
if ((r = krb5_cc_get_principal (telnet_context, ccache, |
235 |
|
&creds.client))) |
236 |
|
{ |
237 |
|
DEBUG(("telnet: Kerberos V5: failure on principal (%s)\r\n", |
238 |
|
error_message(r))); |
239 |
|
krb5_free_cred_contents (telnet_context, &creds); |
240 |
|
return 0; |
241 |
|
} |
242 |
|
|
243 |
|
creds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; |
244 |
|
if ((r = krb5_get_credentials (telnet_context, 0, |
245 |
|
ccache, &creds, &new_creds))) |
246 |
|
{ |
247 |
|
DEBUG(("telnet: Kerberos V5: failure on credentials(%s)\r\n", |
248 |
|
error_message(r))); |
249 |
|
krb5_free_cred_contents (telnet_context, &creds); |
250 |
|
return 0; |
251 |
|
} |
252 |
|
|
253 |
|
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) |
254 |
|
ap_opts = AP_OPTS_MUTUAL_REQUIRED; |
255 |
|
else |
256 |
|
ap_opts = 0; |
257 |
|
|
258 |
#ifdef ENCRYPTION |
#ifdef ENCRYPTION |
259 |
Session_Key skey; |
ap_opts |= AP_OPTS_USE_SUBKEY; |
260 |
#endif /* ENCRYPTION */ |
#endif |
261 |
char *name; |
|
262 |
char *getenv(); |
if (auth_context) |
263 |
krb5_data inbuf; |
{ |
264 |
|
krb5_auth_con_free (telnet_context, auth_context); |
265 |
if (cnt-- < 1) |
auth_context = 0; |
266 |
return; |
} |
267 |
switch (*data++) { |
|
268 |
case KRB_AUTH: |
if ((r = krb5_auth_con_init (telnet_context, &auth_context))) |
269 |
auth.data = (char *)data; |
{ |
270 |
auth.length = cnt; |
DEBUG(("Kerberos V5: failed to init auth_context (%s)\r\n", |
271 |
|
error_message(r))); |
272 |
if (!(hp = gethostbyname(LocalHostName))) { |
return 0; |
273 |
if (auth_debug_mode) |
} |
274 |
printf("Cannot resolve local host name\r\n"); |
|
275 |
Data(ap, KRB_REJECT, "Unknown local hostname.", -1); |
krb5_auth_con_setflags (telnet_context, auth_context, |
276 |
auth_finished(ap, AUTH_REJECT); |
KRB5_AUTH_CONTEXT_RET_TIME); |
277 |
return; |
|
278 |
} |
type_check[0] = ap->type; |
279 |
|
type_check[1] = ap->way; |
280 |
if (!realm && (krb5_get_default_realm(&realm))) { |
check_data.magic = KV5M_DATA; |
281 |
if (auth_debug_mode) |
check_data.length = 2; |
282 |
printf("Could not get default realm\r\n"); |
check_data.data = (char *) &type_check; |
283 |
Data(ap, KRB_REJECT, "Could not get default realm.", -1); |
|
284 |
auth_finished(ap, AUTH_REJECT); |
r = krb5_mk_req_extended (telnet_context, &auth_context, ap_opts, |
285 |
return; |
&check_data, new_creds, &auth); |
286 |
} |
|
287 |
|
encryption_init (new_creds); |
288 |
if ((name = malloc(strlen(hp->h_name)+1)) == NULL) { |
|
289 |
if (auth_debug_mode) |
krb5_free_cred_contents (telnet_context, &creds); |
290 |
printf("Out of memory for hostname in Kerberos V5\r\n"); |
krb5_free_creds (telnet_context, new_creds); |
291 |
Data(ap, KRB_REJECT, "Out of memory.", -1); |
if (r) |
292 |
auth_finished(ap, AUTH_REJECT); |
{ |
293 |
return; |
DEBUG(("telnet: Kerberos V5: mk_req failed (%s)\r\n", |
294 |
} |
error_message(r))); |
295 |
|
return 0; |
296 |
p1 = hp->h_name; |
} |
297 |
p2 = name; |
|
298 |
|
if (!auth_sendname (UserNameRequested, strlen (UserNameRequested))) |
299 |
while (*p2 = *p1++) { |
{ |
300 |
if (isupper(*p2)) |
DEBUG(("telnet: Not enough room for user name\r\n")); |
301 |
*p2 |= 040; |
return 0; |
302 |
++p2; |
} |
303 |
} |
|
304 |
|
if (!Data (ap, KRB_AUTH, auth.data, auth.length)) |
305 |
if (authdat) |
{ |
306 |
krb5_free_tkt_authent(authdat); |
DEBUG(("telnet: Not enough room for authentication data\r\n")); |
307 |
|
return 0; |
308 |
r = krb5_build_principal_ext(&server, |
} |
309 |
strlen(realm), realm, |
|
310 |
4, "host", |
DEBUG(("telnet: Sent Kerberos V5 credentials to server\r\n")); |
311 |
p2 - name, name, |
|
312 |
0); |
return 1; |
313 |
if (!r) { |
} |
|
r = krb5_rd_req_simple(&auth, server, 0, &authdat); |
|
|
krb5_free_principal(server); |
|
|
} |
|
|
if (r) { |
|
|
char errbuf[128]; |
|
|
|
|
|
errout: |
|
|
authdat = 0; |
|
|
(void) strcpy(errbuf, "Read req failed: "); |
|
|
(void) strcat(errbuf, error_message(r)); |
|
|
Data(ap, KRB_REJECT, errbuf, -1); |
|
|
if (auth_debug_mode) |
|
|
printf("%s\r\n", errbuf); |
|
|
return; |
|
|
} |
|
|
free(name); |
|
|
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { |
|
|
/* do ap_rep stuff here */ |
|
|
reply.ctime = authdat->authenticator->ctime; |
|
|
reply.cusec = authdat->authenticator->cusec; |
|
|
reply.subkey = 0; /* use the one he gave us, so don't |
|
|
need to return one here */ |
|
|
reply.seq_number = 0; /* we don't do seq #'s. */ |
|
|
|
|
|
if (r = krb5_mk_rep(&reply, |
|
|
authdat->authenticator->subkey ? |
|
|
authdat->authenticator->subkey : |
|
|
authdat->ticket->enc_part2->session, |
|
|
&outbuf)) { |
|
|
goto errout; |
|
|
} |
|
|
Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); |
|
|
} |
|
|
if (krb5_unparse_name(authdat->ticket->enc_part2 ->client, |
|
|
&name)) |
|
|
name = 0; |
|
|
Data(ap, KRB_ACCEPT, name, name ? -1 : 0); |
|
|
if (auth_debug_mode) { |
|
|
printf("Kerberos5 identifies him as ``%s''\r\n", |
|
|
name ? name : ""); |
|
|
} |
|
|
auth_finished(ap, AUTH_USER); |
|
|
|
|
|
free(name); |
|
|
if (authdat->authenticator->subkey && |
|
|
authdat->authenticator->subkey->keytype == KEYTYPE_DES) { |
|
|
memmove((Voidptr )session_key, |
|
|
(Voidptr )authdat->authenticator->subkey->contents, |
|
|
sizeof(Block)); |
|
|
} else if (authdat->ticket->enc_part2->session->keytype == |
|
|
KEYTYPE_DES) { |
|
|
memmove((Voidptr )session_key, |
|
|
(Voidptr )authdat->ticket->enc_part2->session->contents, |
|
|
sizeof(Block)); |
|
|
} else |
|
|
break; |
|
314 |
|
|
315 |
#ifdef ENCRYPTION |
#ifdef ENCRYPTION |
316 |
skey.type = SK_DES; |
void |
317 |
skey.length = 8; |
telnet_encrypt_key (Session_Key *skey) |
318 |
skey.data = session_key; |
{ |
319 |
encrypt_session_key(&skey, 1); |
if (session_key) |
320 |
#endif /* ENCRYPTION */ |
{ |
321 |
break; |
skey->type = SK_DES; |
322 |
#ifdef FORWARD |
skey->length = 8; |
323 |
case KRB_FORWARD: |
skey->data = session_key->contents; |
324 |
inbuf.data = (char *)data; |
encrypt_session_key (skey, 0); |
325 |
inbuf.length = cnt; |
} |
326 |
if (r = rd_and_store_for_creds(&inbuf, authdat->ticket, |
} |
327 |
UserNameRequested)) { |
#else |
328 |
char errbuf[128]; |
# define telnet_encrypt_key(s) |
329 |
|
#endif |
|
(void) strcpy(errbuf, "Read forwarded creds failed: "); |
|
|
(void) strcat(errbuf, error_message(r)); |
|
|
Data(ap, KRB_FORWARD_REJECT, errbuf, -1); |
|
|
if (auth_debug_mode) |
|
|
printf("Could not read forwarded credentials\r\n"); |
|
|
} |
|
|
else |
|
|
Data(ap, KRB_FORWARD_ACCEPT, 0, 0); |
|
|
if (auth_debug_mode) |
|
|
printf("Forwarded credentials obtained\r\n"); |
|
|
break; |
|
|
#endif /* FORWARD */ |
|
|
default: |
|
|
if (auth_debug_mode) |
|
|
printf("Unknown Kerberos option %d\r\n", data[-1]); |
|
|
Data(ap, KRB_REJECT, 0, 0); |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
void |
|
|
kerberos5_reply(ap, data, cnt) |
|
|
Authenticator *ap; |
|
|
unsigned char *data; |
|
|
int cnt; |
|
|
{ |
|
|
Session_Key skey; |
|
|
static int mutual_complete = 0; |
|
|
|
|
|
if (cnt-- < 1) |
|
|
return; |
|
|
switch (*data++) { |
|
|
case KRB_REJECT: |
|
|
if (cnt > 0) { |
|
|
printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", |
|
|
cnt, data); |
|
|
} else |
|
|
printf("[ Kerberos V5 refuses authentication ]\r\n"); |
|
|
auth_send_retry(); |
|
|
return; |
|
|
case KRB_ACCEPT: |
|
|
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && |
|
|
!mutual_complete) { |
|
|
printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\n"); |
|
|
auth_send_retry(); |
|
|
return; |
|
|
} |
|
|
if (cnt) |
|
|
printf("[ Kerberos V5 accepts you as ``%.*s'' ]\n", cnt, data); |
|
|
else |
|
|
printf("[ Kerberos V5 accepts you ]\n"); |
|
|
auth_finished(ap, AUTH_USER); |
|
|
#ifdef FORWARD |
|
|
if (forward_flags & OPTS_FORWARD_CREDS) |
|
|
kerberos5_forward(ap); |
|
|
#endif /* FORWARD */ |
|
|
break; |
|
|
case KRB_RESPONSE: |
|
|
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { |
|
|
/* the rest of the reply should contain a krb_ap_rep */ |
|
|
krb5_ap_rep_enc_part *reply; |
|
|
krb5_data inbuf; |
|
|
krb5_error_code r; |
|
|
krb5_keyblock tmpkey; |
|
|
|
|
|
inbuf.length = cnt; |
|
|
inbuf.data = (char *)data; |
|
|
|
|
|
tmpkey.keytype = KEYTYPE_DES; |
|
|
tmpkey.contents = session_key; |
|
|
tmpkey.length = sizeof(Block); |
|
|
|
|
|
if (r = krb5_rd_rep(&inbuf, &tmpkey, &reply)) { |
|
|
printf("[ Mutual authentication failed: %s ]\n", |
|
|
error_message(r)); |
|
|
auth_send_retry(); |
|
|
return; |
|
|
} |
|
|
if (reply->ctime != authenticator.ctime || |
|
|
reply->cusec != authenticator.cusec) { |
|
|
printf("[ Mutual authentication failed (mismatched KRB_AP_REP) ]\n"); |
|
|
auth_send_retry(); |
|
|
return; |
|
|
} |
|
|
krb5_free_ap_rep_enc_part(reply); |
|
|
#ifdef ENCRYPTION |
|
|
skey.type = SK_DES; |
|
|
skey.length = 8; |
|
|
skey.data = session_key; |
|
|
encrypt_session_key(&skey, 0); |
|
|
#endif /* ENCRYPTION */ |
|
|
mutual_complete = 1; |
|
|
} |
|
|
return; |
|
|
#ifdef FORWARD |
|
|
case KRB_FORWARD_ACCEPT: |
|
|
printf("[ Kerberos V5 accepted forwarded credentials ]\n"); |
|
|
return; |
|
|
case KRB_FORWARD_REJECT: |
|
|
printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n", |
|
|
cnt, data); |
|
|
return; |
|
|
#endif /* FORWARD */ |
|
|
default: |
|
|
if (auth_debug_mode) |
|
|
printf("Unknown Kerberos option %d\r\n", data[-1]); |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
int |
|
|
kerberos5_status(ap, name, level) |
|
|
Authenticator *ap; |
|
|
char *name; |
|
|
int level; |
|
|
{ |
|
|
if (level < AUTH_USER) |
|
|
return(level); |
|
|
|
|
|
if (UserNameRequested && |
|
|
krb5_kuserok(authdat->ticket->enc_part2->client, UserNameRequested)) |
|
|
{ |
|
|
strcpy(name, UserNameRequested); |
|
|
return(AUTH_VALID); |
|
|
} else |
|
|
return(AUTH_USER); |
|
|
} |
|
|
|
|
|
#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} |
|
|
#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} |
|
|
|
|
|
void |
|
|
kerberos5_printsub(data, cnt, buf, buflen) |
|
|
unsigned char *data, *buf; |
|
|
int cnt, buflen; |
|
|
{ |
|
|
char lbuf[32]; |
|
|
register int i; |
|
|
|
|
|
buf[buflen-1] = '\0'; /* make sure its NULL terminated */ |
|
|
buflen -= 1; |
|
|
|
|
|
switch(data[3]) { |
|
|
case KRB_REJECT: /* Rejected (reason might follow) */ |
|
|
strncpy((char *)buf, " REJECT ", buflen); |
|
|
goto common; |
|
|
|
|
|
case KRB_ACCEPT: /* Accepted (name might follow) */ |
|
|
strncpy((char *)buf, " ACCEPT ", buflen); |
|
|
common: |
|
|
BUMP(buf, buflen); |
|
|
if (cnt <= 4) |
|
|
break; |
|
|
ADDC(buf, buflen, '"'); |
|
|
for (i = 4; i < cnt; i++) |
|
|
ADDC(buf, buflen, data[i]); |
|
|
ADDC(buf, buflen, '"'); |
|
|
ADDC(buf, buflen, '\0'); |
|
|
break; |
|
|
|
|
|
|
|
|
case KRB_AUTH: /* Authentication data follows */ |
|
|
strncpy((char *)buf, " AUTH", buflen); |
|
|
goto common2; |
|
|
|
|
|
case KRB_RESPONSE: |
|
|
strncpy((char *)buf, " RESPONSE", buflen); |
|
|
goto common2; |
|
|
|
|
|
#ifdef FORWARD |
|
|
case KRB_FORWARD: /* Forwarded credentials follow */ |
|
|
strncpy((char *)buf, " FORWARD", buflen); |
|
|
goto common2; |
|
|
|
|
|
case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */ |
|
|
strncpy((char *)buf, " FORWARD_ACCEPT", buflen); |
|
|
goto common2; |
|
|
|
|
|
case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */ |
|
|
/* (reason might follow) */ |
|
|
strncpy((char *)buf, " FORWARD_REJECT", buflen); |
|
|
goto common2; |
|
|
#endif /* FORWARD */ |
|
330 |
|
|
331 |
default: |
void |
332 |
sprintf(lbuf, " %d (unknown)", data[3]); |
kerberos5_reply (Authenticator *ap, unsigned char *data, int cnt) |
333 |
strncpy((char *)buf, lbuf, buflen); |
{ |
334 |
common2: |
#ifdef ENCRYPTION |
335 |
BUMP(buf, buflen); |
Session_Key skey; |
336 |
for (i = 4; i < cnt; i++) { |
#endif |
337 |
sprintf(lbuf, " %d", data[i]); |
static int mutual_complete = 0; |
338 |
strncpy((char *)buf, lbuf, buflen); |
|
339 |
BUMP(buf, buflen); |
if (cnt-- < 1) |
340 |
} |
return; |
341 |
break; |
|
342 |
} |
switch (*data++) |
343 |
} |
{ |
344 |
|
case KRB_REJECT: |
345 |
#ifdef FORWARD |
if (cnt > 0) |
346 |
void |
printf ("[ Kerberos V5 refuses authentication because %.*s ]\r\n", |
347 |
kerberos5_forward(ap) |
cnt, data); |
348 |
Authenticator *ap; |
else |
349 |
{ |
printf ("[ Kerberos V5 refuses authentication ]\r\n"); |
350 |
struct hostent *hp; |
auth_send_retry(); |
351 |
krb5_creds *local_creds; |
return; |
352 |
krb5_error_code r; |
|
353 |
krb5_data forw_creds; |
case KRB_ACCEPT: |
354 |
extern krb5_cksumtype krb5_kdc_req_sumtype; |
if (!mutual_complete) |
355 |
krb5_ccache ccache; |
{ |
356 |
int i; |
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) |
357 |
|
{ |
358 |
if (!(local_creds = (krb5_creds *) |
printf ("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); |
359 |
calloc(1, sizeof(*local_creds)))) { |
auth_send_retry (); |
360 |
if (auth_debug_mode) |
break; |
361 |
printf("Kerberos V5: could not allocate memory for credentials\r\n"); |
} |
362 |
return; |
telnet_encrypt_key (&skey); |
363 |
} |
} |
364 |
|
|
365 |
if (r = krb5_sname_to_principal(RemoteHostName, "host", 1, |
if (cnt) |
366 |
&local_creds->server)) { |
printf ("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data); |
367 |
if (auth_debug_mode) |
else |
368 |
printf("Kerberos V5: could not build server name - %s\r\n", |
printf ("[ Kerberos V5 accepts you ]\r\n"); |
369 |
error_message(r)); |
auth_finished(ap, AUTH_USER); |
370 |
krb5_free_creds(local_creds); |
#ifdef FORWARD |
371 |
return; |
if (forward_flags & OPTS_FORWARD_CREDS) |
372 |
} |
kerberos5_forward (ap); |
373 |
|
#endif |
374 |
if (r = krb5_cc_default(&ccache)) { |
break; |
375 |
if (auth_debug_mode) |
|
376 |
printf("Kerberos V5: could not get default ccache - %s\r\n", |
case KRB_RESPONSE: |
377 |
error_message(r)); |
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) |
378 |
krb5_free_creds(local_creds); |
{ |
379 |
return; |
krb5_ap_rep_enc_part *reply; |
380 |
} |
krb5_data inbuf; |
381 |
|
krb5_error_code r; |
382 |
if (r = krb5_cc_get_principal(ccache, &local_creds->client)) { |
|
383 |
if (auth_debug_mode) |
inbuf.length = cnt; |
384 |
printf("Kerberos V5: could not get default principal - %s\r\n", |
inbuf.data = (char *)data; |
385 |
error_message(r)); |
|
386 |
krb5_free_creds(local_creds); |
if ((r = krb5_rd_rep (telnet_context, auth_context, &inbuf, |
387 |
return; |
&reply))) |
388 |
} |
{ |
389 |
|
printf ("[ Mutual authentication failed: %s ]\r\n", |
390 |
/* Get ticket from credentials cache */ |
error_message (r)); |
391 |
if (r = krb5_get_credentials(KRB5_GC_CACHED, ccache, local_creds)) { |
auth_send_retry (); |
392 |
if (auth_debug_mode) |
break; |
393 |
printf("Kerberos V5: could not obtain credentials - %s\r\n", |
} |
394 |
error_message(r)); |
|
395 |
krb5_free_creds(local_creds); |
krb5_free_ap_rep_enc_part (telnet_context, reply); |
396 |
return; |
telnet_encrypt_key (&skey); |
397 |
} |
mutual_complete = 1; |
398 |
|
} |
399 |
if (r = get_for_creds(ETYPE_DES_CBC_CRC, |
break; |
400 |
krb5_kdc_req_sumtype, |
|
401 |
RemoteHostName, |
#ifdef FORWARD |
402 |
local_creds->client, |
case KRB_FORWARD_ACCEPT: |
403 |
&local_creds->keyblock, |
printf ("[ Kerberos V5 accepted forwarded credentials ]\r\n"); |
404 |
forward_flags & OPTS_FORWARDABLE_CREDS, |
break; |
405 |
&forw_creds)) { |
|
406 |
if (auth_debug_mode) |
case KRB_FORWARD_REJECT: |
407 |
printf("Kerberos V5: error getting forwarded creds - %s\r\n", |
printf ("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n", |
408 |
error_message(r)); |
cnt, data); |
409 |
krb5_free_creds(local_creds); |
break; |
410 |
return; |
#endif /* FORWARD */ |
411 |
} |
|
412 |
|
default: |
413 |
/* Send forwarded credentials */ |
DEBUG(("Unknown Kerberos option %d\r\n", data[-1])); |
414 |
if (!Data(ap, KRB_FORWARD, forw_creds.data, forw_creds.length)) { |
} |
415 |
if (auth_debug_mode) |
} |
416 |
printf("Not enough room for authentication data\r\n"); |
|
417 |
} |
int |
418 |
else { |
kerberos5_status (Authenticator *ap, char *name, int level) |
419 |
if (auth_debug_mode) |
{ |
420 |
printf("Forwarded local Kerberos V5 credentials to server\r\n"); |
if (level < AUTH_USER) |
421 |
|
return level; |
422 |
|
|
423 |
|
if (UserNameRequested |
424 |
|
&& krb5_kuserok (telnet_context, ticket->enc_part2->client, |
425 |
|
UserNameRequested)) |
426 |
|
{ |
427 |
|
/* FIXME: Check buffer length */ |
428 |
|
strcpy (name, UserNameRequested); |
429 |
|
return AUTH_VALID; |
430 |
|
} |
431 |
|
return AUTH_USER; |
432 |
|
} |
433 |
|
|
434 |
|
int |
435 |
|
kerberos5_is_auth (Authenticator *ap, unsigned char *data, int cnt, |
436 |
|
char *errbuf, int errbuflen) |
437 |
|
{ |
438 |
|
int r = 0; |
439 |
|
krb5_keytab keytabid = 0; |
440 |
|
krb5_authenticator *authenticator; |
441 |
|
char *name; |
442 |
|
krb5_data outbuf; |
443 |
|
krb5_keyblock *newkey = NULL; |
444 |
|
krb5_principal server; |
445 |
|
|
446 |
|
#ifdef ENCRYPTION |
447 |
|
Session_Key skey; |
448 |
|
#endif |
449 |
|
|
450 |
|
auth.data = (char *)data; |
451 |
|
auth.length = cnt; |
452 |
|
|
453 |
|
if (!r && !auth_context) |
454 |
|
r = krb5_auth_con_init (telnet_context, &auth_context); |
455 |
|
if (!r) |
456 |
|
{ |
457 |
|
krb5_rcache rcache; |
458 |
|
|
459 |
|
r = krb5_auth_con_getrcache (telnet_context, auth_context, |
460 |
|
&rcache); |
461 |
|
if (!r && !rcache) |
462 |
|
{ |
463 |
|
r = krb5_sname_to_principal(telnet_context, 0, 0, |
464 |
|
KRB5_NT_SRV_HST, &server); |
465 |
|
if (!r) |
466 |
|
{ |
467 |
|
r = krb5_get_server_rcache(telnet_context, |
468 |
|
krb5_princ_component (telnet_context, |
469 |
|
server, 0), |
470 |
|
&rcache); |
471 |
|
krb5_free_principal (telnet_context, server); |
472 |
|
} |
473 |
|
} |
474 |
|
if (!r) |
475 |
|
r = krb5_auth_con_setrcache (telnet_context, |
476 |
|
auth_context, rcache); |
477 |
|
} |
478 |
|
|
479 |
|
if (!r && telnet_srvtab) |
480 |
|
r = krb5_kt_resolve (telnet_context, telnet_srvtab, &keytabid); |
481 |
|
if (!r) |
482 |
|
r = krb5_rd_req (telnet_context, &auth_context, &auth, |
483 |
|
NULL, keytabid, NULL, &ticket); |
484 |
|
if (r) |
485 |
|
{ |
486 |
|
snprintf (errbuf, errbuflen, "krb5_rd_req failed: %s", |
487 |
|
error_message (r)); |
488 |
|
return r; |
489 |
|
} |
490 |
|
|
491 |
|
/* 256 bytes should be much larger than any reasonable |
492 |
|
first component of a service name especially since |
493 |
|
the default is of length 4. */ |
494 |
|
if (krb5_princ_component (telnet_context,ticket->server,0)->length < 256) |
495 |
|
{ |
496 |
|
char princ[256]; |
497 |
|
strncpy (princ, |
498 |
|
krb5_princ_component (telnet_context, ticket->server,0)->data, |
499 |
|
krb5_princ_component (telnet_context, ticket->server,0)->length); |
500 |
|
princ[krb5_princ_component (telnet_context, |
501 |
|
ticket->server,0)->length] = '\0'; |
502 |
|
if (strcmp ("host", princ)) |
503 |
|
{ |
504 |
|
snprintf(errbuf, errbuflen, |
505 |
|
"incorrect service name: \"%s\" != \"host\"", |
506 |
|
princ); |
507 |
|
return 1; |
508 |
|
} |
509 |
|
} |
510 |
|
else |
511 |
|
{ |
512 |
|
strncpy (errbuf, "service name too long", errbuflen); |
513 |
|
return 1; |
514 |
|
} |
515 |
|
|
516 |
|
r = krb5_auth_con_getauthenticator (telnet_context, |
517 |
|
auth_context, |
518 |
|
&authenticator); |
519 |
|
if (r) |
520 |
|
{ |
521 |
|
snprintf (errbuf, errbuflen, |
522 |
|
"krb5_auth_con_getauthenticator failed: %s", |
523 |
|
error_message (r)); |
524 |
|
return 1; |
525 |
} |
} |
526 |
|
|
527 |
krb5_free_creds(local_creds); |
#ifdef AUTH_ENCRYPT_MASK |
528 |
|
if ((ap->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON |
529 |
|
&& !authenticator->checksum) |
530 |
|
{ |
531 |
|
snprintf (errbuf, errbuflen, |
532 |
|
"authenticator is missing required checksum"); |
533 |
|
return 1; |
534 |
|
} |
535 |
|
#endif |
536 |
|
|
537 |
|
if (authenticator->checksum) |
538 |
|
{ |
539 |
|
char type_check[2]; |
540 |
|
krb5_checksum *cksum = authenticator->checksum; |
541 |
|
krb5_keyblock *key; |
542 |
|
|
543 |
|
type_check[0] = ap->type; |
544 |
|
type_check[1] = ap->way; |
545 |
|
|
546 |
|
r = krb5_auth_con_getkey (telnet_context, auth_context, |
547 |
|
&key); |
548 |
|
if (r) |
549 |
|
{ |
550 |
|
snprintf (errbuf, errbuflen, |
551 |
|
"krb5_auth_con_getkey failed: %s", |
552 |
|
error_message (r)); |
553 |
|
return 1; |
554 |
|
} |
555 |
|
|
556 |
|
r = krb5_verify_checksum (telnet_context, |
557 |
|
cksum->checksum_type, cksum, |
558 |
|
&type_check, 2, key->contents, |
559 |
|
key->length); |
560 |
|
|
561 |
|
if (r) |
562 |
|
{ |
563 |
|
snprintf (errbuf, errbuflen, |
564 |
|
"checksum verification failed: %s", |
565 |
|
error_message (r)); |
566 |
|
return 1; |
567 |
|
} |
568 |
|
krb5_free_keyblock (telnet_context, key); |
569 |
|
} |
570 |
|
|
571 |
|
krb5_free_authenticator (telnet_context, authenticator); |
572 |
|
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) |
573 |
|
{ |
574 |
|
if ((r = krb5_mk_rep (telnet_context, auth_context, |
575 |
|
&outbuf))) |
576 |
|
{ |
577 |
|
snprintf (errbuf, errbuflen, "Make reply failed: %s", |
578 |
|
error_message(r)); |
579 |
|
return 1; |
580 |
|
} |
581 |
|
|
582 |
|
Data (ap, KRB_RESPONSE, outbuf.data, outbuf.length); |
583 |
|
} |
584 |
|
|
585 |
|
if (krb5_unparse_name (telnet_context, ticket->enc_part2 ->client, &name)) |
586 |
|
name = 0; |
587 |
|
|
588 |
|
Data (ap, KRB_ACCEPT, name, name ? -1 : 0); |
589 |
|
DEBUG(("telnetd: Kerberos5 identifies him as ``%s''\r\n", |
590 |
|
name ? name : "")); |
591 |
|
auth_finished (ap, AUTH_USER); |
592 |
|
|
593 |
|
if (name) |
594 |
|
free (name); |
595 |
|
krb5_auth_con_getremotesubkey (telnet_context, auth_context, &newkey); |
596 |
|
|
597 |
|
if (session_key) |
598 |
|
{ |
599 |
|
krb5_free_keyblock (telnet_context, session_key); |
600 |
|
session_key = 0; |
601 |
|
} |
602 |
|
|
603 |
|
if (newkey) |
604 |
|
{ |
605 |
|
krb5_copy_keyblock (telnet_context, newkey, &session_key); |
606 |
|
krb5_free_keyblock (telnet_context, newkey); |
607 |
|
} |
608 |
|
else |
609 |
|
{ |
610 |
|
krb5_copy_keyblock (telnet_context, ticket->enc_part2->session, |
611 |
|
&session_key); |
612 |
|
} |
613 |
|
telnet_encrypt_key (&skey); |
614 |
|
return 0; |
615 |
} |
} |
|
#endif /* FORWARD */ |
|
616 |
|
|
617 |
|
#ifdef FORWARD |
618 |
|
int |
619 |
|
kerberos5_is_forward (Authenticator *ap, unsigned char *data, int cnt, |
620 |
|
char *errbuf, int errbuflen) |
621 |
|
{ |
622 |
|
int r = 0; |
623 |
|
krb5_data inbuf; |
624 |
|
|
625 |
|
inbuf.length = cnt; |
626 |
|
inbuf.data = (char *)data; |
627 |
|
if ((r = krb5_auth_con_genaddrs (telnet_context, auth_context, |
628 |
|
net, |
629 |
|
KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) |
630 |
|
|| (r = rd_and_store_for_creds(telnet_context, auth_context, |
631 |
|
&inbuf, ticket))) |
632 |
|
{ |
633 |
|
snprintf (errbuf, errbuflen, "Read forwarded creds failed: %s", |
634 |
|
error_message (r)); |
635 |
|
Data (ap, KRB_FORWARD_REJECT, errbuf, -1); |
636 |
|
DEBUG(("Could not read forwarded credentials\r\n")); |
637 |
|
} |
638 |
|
else |
639 |
|
{ |
640 |
|
Data(ap, KRB_FORWARD_ACCEPT, 0, 0); |
641 |
|
DEBUG(("Forwarded credentials obtained\r\n")); |
642 |
|
} |
643 |
|
return r; |
644 |
|
} |
645 |
|
#else |
646 |
|
# define kerberos5_is_forward(ap,data,cnt,errbuf,errbuflen) 0 |
647 |
|
#endif |
648 |
|
|
649 |
|
void |
650 |
|
kerberos5_is (Authenticator *ap, unsigned char *data, int cnt) |
651 |
|
{ |
652 |
|
int r = 0; |
653 |
|
char errbuf[512]; |
654 |
|
|
655 |
|
if (cnt-- < 1) |
656 |
|
return; |
657 |
|
errbuf[0] = 0; |
658 |
|
switch (*data++) |
659 |
|
{ |
660 |
|
case KRB_AUTH: |
661 |
|
r = kerberos5_is_auth (ap, data, cnt, errbuf, sizeof errbuf); |
662 |
|
break; |
663 |
|
|
664 |
|
case KRB_FORWARD: |
665 |
|
r = kerberos5_is_forward (ap, data, cnt, errbuf, sizeof errbuf); |
666 |
|
break; |
667 |
|
|
668 |
|
default: |
669 |
|
DEBUG(("Unknown Kerberos option %d\r\n", |
670 |
|
data[-1])); |
671 |
|
Data(ap, KRB_REJECT, 0, 0); |
672 |
|
break; |
673 |
|
} |
674 |
|
|
675 |
|
if (r) |
676 |
|
{ |
677 |
|
if (!errbuf[0]) |
678 |
|
snprintf (errbuf, sizeof errbuf, |
679 |
|
"kerberos_is: %s", error_message(r)); |
680 |
|
Data (ap, KRB_REJECT, errbuf, -1); |
681 |
|
DEBUG(("%s\r\n", errbuf)); |
682 |
|
syslog (LOG_ERR, "%s", errbuf); |
683 |
|
if (auth_context) |
684 |
|
{ |
685 |
|
krb5_auth_con_free (telnet_context, auth_context); |
686 |
|
auth_context = 0; |
687 |
|
} |
688 |
|
} |
689 |
|
} |
690 |
|
|
691 |
|
static char * |
692 |
|
req_type_str (int type) |
693 |
|
{ |
694 |
|
switch (type) |
695 |
|
{ |
696 |
|
case KRB_REJECT: |
697 |
|
return "REJECT"; |
698 |
|
|
699 |
|
case KRB_ACCEPT: |
700 |
|
return "ACCEPT"; |
701 |
|
|
702 |
|
case KRB_AUTH: |
703 |
|
return "AUTH"; |
704 |
|
|
705 |
|
case KRB_RESPONSE: |
706 |
|
return "RESPONSE"; |
707 |
|
|
708 |
|
case KRB_FORWARD: |
709 |
|
return "FORWARD"; |
710 |
|
|
711 |
|
case KRB_FORWARD_ACCEPT: |
712 |
|
return "FORWARD_ACCEPT"; |
713 |
|
|
714 |
|
case KRB_FORWARD_REJECT: |
715 |
|
return "FORWARD_REJECT"; |
716 |
|
|
717 |
|
} |
718 |
|
return NULL; |
719 |
|
} |
720 |
|
|
721 |
|
#define ADDC(p,l,c) if ((l) > 0) {*(p)++ = (c); --(l);} |
722 |
|
|
723 |
|
void |
724 |
|
kerberos5_printsub (unsigned char *data, int cnt, |
725 |
|
unsigned char *buf, int buflen) |
726 |
|
{ |
727 |
|
char *p; |
728 |
|
int i; |
729 |
|
|
730 |
|
buf[buflen-1] = '\0'; /* make sure its NULL terminated */ |
731 |
|
buflen -= 1; |
732 |
|
|
733 |
|
p = req_type_str (data[3]); |
734 |
|
if (!p) |
735 |
|
{ |
736 |
|
int l = snprintf (buf, buflen, " %d (unknown)", data[3]); |
737 |
|
buf += l; |
738 |
|
buflen -= l; |
739 |
|
} |
740 |
|
else |
741 |
|
{ |
742 |
|
while (buflen > 0 && (*buf++ = *p++) != 0) |
743 |
|
buflen--; |
744 |
|
} |
745 |
|
|
746 |
|
switch (data[3]) |
747 |
|
{ |
748 |
|
case KRB_REJECT: /* Rejected (reason might follow) */ |
749 |
|
case KRB_ACCEPT: /* Accepted (username might follow) */ |
750 |
|
if (cnt <= 4) |
751 |
|
break; |
752 |
|
ADDC(buf, buflen, '"'); |
753 |
|
for (i = 4; i < cnt; i++) |
754 |
|
ADDC(buf, buflen, data[i]); |
755 |
|
ADDC(buf, buflen, '"'); |
756 |
|
ADDC(buf, buflen, '\0'); |
757 |
|
break; |
758 |
|
|
759 |
|
case KRB_AUTH: |
760 |
|
case KRB_RESPONSE: |
761 |
|
case KRB_FORWARD: |
762 |
|
case KRB_FORWARD_ACCEPT: |
763 |
|
case KRB_FORWARD_REJECT: |
764 |
|
for (i = 4; buflen > 0 && i < cnt; i++) |
765 |
|
{ |
766 |
|
int l = snprintf (buf, buflen, " %d", data[i]); |
767 |
|
buf += l; |
768 |
|
buflen -= l; |
769 |
|
} |
770 |
|
} |
771 |
|
} |
772 |
|
|
773 |
|
#ifdef FORWARD |
774 |
|
|
775 |
|
void |
776 |
|
kerberos5_forward (Authenticator *ap) |
777 |
|
{ |
778 |
|
krb5_error_code r; |
779 |
|
krb5_ccache ccache; |
780 |
|
krb5_principal client = 0; |
781 |
|
krb5_principal server = 0; |
782 |
|
krb5_data forw_creds; |
783 |
|
|
784 |
|
forw_creds.data = 0; |
785 |
|
|
786 |
|
if ((r = krb5_cc_default (telnet_context, &ccache))) |
787 |
|
{ |
788 |
|
DEBUG(("Kerberos V5: could not get default ccache - %s\r\n", |
789 |
|
error_message(r))); |
790 |
|
return; |
791 |
|
} |
792 |
|
|
793 |
|
for (;;) /* Fake loop */ |
794 |
|
{ |
795 |
|
if ((r = krb5_cc_get_principal (telnet_context, ccache, &client))) |
796 |
|
{ |
797 |
|
DEBUG(("Kerberos V5: could not get default principal - %s\r\n", |
798 |
|
error_message(r))); |
799 |
|
break; |
800 |
|
} |
801 |
|
if ((r = krb5_sname_to_principal (telnet_context, RemoteHostName, "host", |
802 |
|
KRB5_NT_SRV_HST, &server))) |
803 |
|
{ |
804 |
|
DEBUG(("Kerberos V5: could not make server principal - %s\r\n", |
805 |
|
error_message(r))); |
806 |
|
break; |
807 |
|
} |
808 |
|
if ((r = krb5_auth_con_genaddrs (telnet_context, auth_context, net, |
809 |
|
KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) |
810 |
|
{ |
811 |
|
DEBUG(("Kerberos V5: could not gen local full address - %s\r\n", |
812 |
|
error_message(r))); |
813 |
|
break; |
814 |
|
} |
815 |
|
if ((r = krb5_fwd_tgt_creds (telnet_context, auth_context, 0, client, |
816 |
|
server, ccache, |
817 |
|
forward_flags & OPTS_FORWARDABLE_CREDS, |
818 |
|
&forw_creds))) |
819 |
|
{ |
820 |
|
DEBUG(("Kerberos V5: error getting forwarded creds - %s\r\n", |
821 |
|
error_message(r))); |
822 |
|
break; |
823 |
|
} |
824 |
|
|
825 |
|
/* Send forwarded credentials */ |
826 |
|
if (!Data(ap, KRB_FORWARD, forw_creds.data, forw_creds.length)) |
827 |
|
{ |
828 |
|
DEBUG(("Not enough room for authentication data\r\n")); |
829 |
|
} |
830 |
|
else |
831 |
|
{ |
832 |
|
DEBUG(("Forwarded local Kerberos V5 credentials to server\r\n")); |
833 |
|
} |
834 |
|
break; |
835 |
|
} |
836 |
|
|
837 |
|
if (client) |
838 |
|
krb5_free_principal(telnet_context, client); |
839 |
|
if (server) |
840 |
|
krb5_free_principal(telnet_context, server); |
841 |
|
if (forw_creds.data) |
842 |
|
free(forw_creds.data); |
843 |
|
krb5_cc_close(telnet_context, ccache); |
844 |
|
} |
845 |
|
#endif |
846 |
|
|
847 |
#endif /* KRB5 */ |
#endif /* KRB5 */ |