1 /* $NetBSD: kerberos5.c,v 1.16 2006/03/19 22:56:36 christos Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Copyright (C) 1990 by the Massachusetts Institute of Technology
35 * Export of this software from the United States of America may
36 * require a specific license from the United States Government.
37 * It is the responsibility of any person or organization contemplating
38 * export to obtain such a license before exporting.
40 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
41 * distribute this software and its documentation for any purpose and
42 * without fee is hereby granted, provided that the above copyright
43 * notice appear in all copies and that both that copyright notice and
44 * this permission notice appear in supporting documentation, and that
45 * the name of M.I.T. not be used in advertising or publicity pertaining
46 * to distribution of the software without specific, written prior
47 * permission. M.I.T. makes no representations about the suitability of
48 * this software for any purpose. It is provided "as is" without express
49 * or implied warranty.
53 #include <arpa/telnet.h>
61 #define Authenticator k5_Authenticator
64 /* #include <roken.h> */
72 int forward_flags
; /* Flags get set in telnet/main.c on -f and -F */
73 int got_forwarded_creds
;/* Tell telnetd to pass -F or -f to login. */
75 int require_hwpreauth
;
77 void kerberos5_forward(Authenticator
*);
79 static unsigned char str_data
[1024] = {IAC
, SB
, TELOPT_AUTHENTICATION
, 0,
80 AUTHTYPE_KERBEROS_V5
,};
82 #define KRB_AUTH 0 /* Authentication data follows */
83 #define KRB_REJECT 1 /* Rejected (reason might follow) */
84 #define KRB_ACCEPT 2 /* Accepted */
85 #define KRB_RESPONSE 3 /* Response for mutual auth. */
87 #define KRB_FORWARD 4 /* Forwarded credentials follow */
88 #define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */
89 #define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */
91 static krb5_data auth
;
92 static krb5_ticket
*ticket
;
94 krb5_context telnet_context
;
95 static krb5_auth_context auth_context
;
98 Data(Authenticator
*ap
, int type
, void *d
, int c
)
100 unsigned char *p
= str_data
+ 4;
101 unsigned char *cd
= (unsigned char *) d
;
106 if (auth_debug_mode
) {
107 printf("%s:%d: [%d] (%d)",
108 str_data
[3] == TELQUAL_IS
? ">>>IS" : ">>>REPLY",
118 if ((*p
++ = *cd
++) == IAC
)
123 if (str_data
[3] == TELQUAL_IS
)
124 printsub('>', &str_data
[2], p
- &str_data
[2]);
125 return (telnet_net_write(str_data
, p
- str_data
));
129 kerberos5_init(Authenticator
*ap
, int server
)
133 if (telnet_context
== 0) {
134 ret
= krb5_init_context(&telnet_context
);
141 krb5_kt_cursor cursor
;
143 ret
= krb5_kt_default(telnet_context
, &kt
);
147 ret
= krb5_kt_start_seq_get(telnet_context
, kt
, &cursor
);
149 krb5_kt_close(telnet_context
, kt
);
152 krb5_kt_end_seq_get(telnet_context
, kt
, &cursor
);
153 krb5_kt_close(telnet_context
, kt
);
155 str_data
[3] = TELQUAL_REPLY
;
157 str_data
[3] = TELQUAL_IS
;
162 kerberos5_send(Authenticator
*ap
)
167 krb5_data cksum_data
;
170 printf("[ Trying KERBEROS5 ... ]\r\n");
172 if (!UserNameRequested
) {
173 if (auth_debug_mode
) {
174 printf("Kerberos V5: no user name supplied\r\n");
178 ret
= krb5_cc_default(telnet_context
, &ccache
);
180 if (auth_debug_mode
) {
182 "Kerberos V5: could not get default ccache: %s\r\n",
183 krb5_get_err_text(telnet_context
, ret
));
187 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
)
188 ap_opts
= AP_OPTS_MUTUAL_REQUIRED
;
192 ap_opts
|= AP_OPTS_USE_SUBKEY
;
194 ret
= krb5_auth_con_init(telnet_context
, &auth_context
);
196 if (auth_debug_mode
) {
198 "Kerberos V5: krb5_auth_con_init failed: %s\r\n",
199 krb5_get_err_text(telnet_context
, ret
));
203 ret
= krb5_auth_con_setaddrs_from_fd(telnet_context
,
206 if (auth_debug_mode
) {
207 printf("Kerberos V5: "
208 "krb5_auth_con_setaddrs_from_fd failed: %s\r\n",
209 krb5_get_err_text(telnet_context
, ret
));
213 krb5_auth_con_setkeytype(telnet_context
, auth_context
, KEYTYPE_DES
);
218 cksum_data
.length
= sizeof(foo
);
219 cksum_data
.data
= foo
;
220 ret
= krb5_mk_req(telnet_context
, &auth_context
, ap_opts
, "host",
221 RemoteHostName
, &cksum_data
, ccache
, &auth
);
223 if (1 || auth_debug_mode
) {
224 printf("Kerberos V5: mk_req failed (%s)\r\n",
225 krb5_get_err_text(telnet_context
, ret
));
230 if (!auth_sendname((unsigned char *) UserNameRequested
,
231 strlen(UserNameRequested
))) {
233 printf("Not enough room for user name\r\n");
236 if (!Data(ap
, KRB_AUTH
, auth
.data
, auth
.length
)) {
238 printf("Not enough room for authentication data\r\n");
241 if (auth_debug_mode
) {
242 printf("Sent Kerberos V5 credentials to server\r\n");
248 kerberos5_is(Authenticator
* ap
, unsigned char *data
, int cnt
)
252 krb5_keyblock
*key_block
;
254 krb5_principal server
;
261 auth
.data
= (char *) data
;
266 ret
= krb5_auth_con_init(telnet_context
, &auth_context
);
268 Data(ap
, KRB_REJECT
, "krb5_auth_con_init failed", -1);
269 auth_finished(ap
, AUTH_REJECT
);
271 printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n",
272 krb5_get_err_text(telnet_context
, ret
));
275 ret
= krb5_auth_con_setaddrs_from_fd(telnet_context
,
276 auth_context
, &zero
);
278 Data(ap
, KRB_REJECT
, "krb5_auth_con_setaddrs_from_fd failed", -1);
279 auth_finished(ap
, AUTH_REJECT
);
281 printf("Kerberos V5: "
282 "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n",
283 krb5_get_err_text(telnet_context
, ret
));
286 ret
= krb5_sock_to_principal(telnet_context
, 0, "host",
287 KRB5_NT_SRV_HST
, &server
);
289 Data(ap
, KRB_REJECT
, "krb5_sock_to_principal failed", -1);
290 auth_finished(ap
, AUTH_REJECT
);
292 printf("Kerberos V5: "
293 "krb5_sock_to_principal failed (%s)\r\n",
294 krb5_get_err_text(telnet_context
, ret
));
297 ret
= krb5_rd_req(telnet_context
, &auth_context
, &auth
,
298 server
, NULL
, NULL
, &ticket
);
299 krb5_free_principal(telnet_context
, server
);
305 "Read req failed: %s",
306 krb5_get_err_text(telnet_context
, ret
));
307 Data(ap
, KRB_REJECT
, errbuf
, -1);
309 printf("%s\r\n", errbuf
);
318 ret
= krb5_verify_authenticator_checksum(telnet_context
,
319 auth_context
, foo
, sizeof(foo
));
323 asprintf(&errbuf
, "Bad checksum: %s",
324 krb5_get_err_text(telnet_context
, ret
));
325 Data(ap
, KRB_REJECT
, errbuf
, -1);
327 printf("%s\r\n", errbuf
);
332 ret
= krb5_auth_con_getremotesubkey(telnet_context
,
333 auth_context
, &key_block
);
336 Data(ap
, KRB_REJECT
, "krb5_auth_con_getremotesubkey failed", -1);
337 auth_finished(ap
, AUTH_REJECT
);
339 printf("Kerberos V5: "
340 "krb5_auth_con_getremotesubkey failed (%s)\r\n",
341 krb5_get_err_text(telnet_context
, ret
));
344 if (key_block
== NULL
) {
345 ret
= krb5_auth_con_getkey(telnet_context
,
350 Data(ap
, KRB_REJECT
, "krb5_auth_con_getkey failed", -1);
351 auth_finished(ap
, AUTH_REJECT
);
353 printf("Kerberos V5: "
354 "krb5_auth_con_getkey failed (%s)\r\n",
355 krb5_get_err_text(telnet_context
, ret
));
358 if (key_block
== NULL
) {
359 Data(ap
, KRB_REJECT
, "no subkey received", -1);
360 auth_finished(ap
, AUTH_REJECT
);
362 printf("Kerberos V5: "
363 "krb5_auth_con_getremotesubkey returned NULL key\r\n");
366 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) {
367 ret
= krb5_mk_rep(telnet_context
,
368 auth_context
, &outbuf
);
371 "krb5_mk_rep failed", -1);
372 auth_finished(ap
, AUTH_REJECT
);
374 printf("Kerberos V5: "
375 "krb5_mk_rep failed (%s)\r\n",
376 krb5_get_err_text(telnet_context
,
378 krb5_free_keyblock(telnet_context
, key_block
);
381 Data(ap
, KRB_RESPONSE
, outbuf
.data
, outbuf
.length
);
383 if (krb5_unparse_name(telnet_context
, ticket
->client
, &name
))
386 if (UserNameRequested
&& krb5_kuserok(telnet_context
,
387 ticket
->client
, UserNameRequested
)) {
388 Data(ap
, KRB_ACCEPT
, name
? name
: "", name
? -1 : 0);
389 if (auth_debug_mode
) {
390 printf("Kerberos5 identifies him as ``%s''\r\n",
393 if (key_block
->keytype
== ETYPE_DES_CBC_MD5
||
394 key_block
->keytype
== ETYPE_DES_CBC_MD4
||
395 key_block
->keytype
== ETYPE_DES_CBC_CRC
) {
400 skey
.data
= key_block
->keyvalue
.data
;
401 encrypt_session_key(&skey
, 0);
406 asprintf(&msg
, "user `%s' is not authorized to "
408 name
? name
: "<unknown>",
409 UserNameRequested
? UserNameRequested
: "<nobody>");
411 Data(ap
, KRB_REJECT
, NULL
, 0);
413 Data(ap
, KRB_REJECT
, (void *) msg
, -1);
416 auth_finished(ap
, AUTH_REJECT
);
417 krb5_free_keyblock(telnet_context
, key_block
);
420 auth_finished(ap
, AUTH_USER
);
421 krb5_free_keyblock(telnet_context
, key_block
);
424 struct passwd pws
, *pwd
;
426 char ccname
[1024]; /* XXX */
429 inbuf
.data
= (char *) data
;
432 if (getpwnam_r(UserNameRequested
, &pws
, pwbuf
,
433 sizeof(pwbuf
), &pwd
) != 0 || pwd
== NULL
)
436 snprintf(ccname
, sizeof(ccname
),
437 "FILE:/tmp/krb5cc_%u", pwd
->pw_uid
);
439 ret
= krb5_cc_resolve(telnet_context
, ccname
, &ccache
);
442 printf("Kerberos V5: could not get ccache: %s\r\n",
443 krb5_get_err_text(telnet_context
,
447 ret
= krb5_cc_initialize(telnet_context
, ccache
,
451 printf("Kerberos V5: could not init ccache: %s\r\n",
452 krb5_get_err_text(telnet_context
,
456 ret
= krb5_rd_cred2(telnet_context
, auth_context
,
462 "Read forwarded creds failed: %s",
463 krb5_get_err_text(telnet_context
, ret
));
465 Data(ap
, KRB_FORWARD_REJECT
, NULL
, 0);
467 Data(ap
, KRB_FORWARD_REJECT
, errbuf
, -1);
469 printf("Could not read forwarded credentials: %s\r\n",
473 Data(ap
, KRB_FORWARD_ACCEPT
, 0, 0);
474 chown(ccname
+ 5, pwd
->pw_uid
, -1);
476 printf("Forwarded credentials obtained\r\n");
481 printf("Unknown Kerberos option %d\r\n", data
[-1]);
482 Data(ap
, KRB_REJECT
, 0, 0);
488 kerberos5_reply(Authenticator
* ap
, unsigned char *data
, int cnt
)
490 static int mutual_complete
= 0;
497 printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
500 printf("[ Kerberos V5 refuses authentication ]\r\n");
506 krb5_keyblock
*keyblock
;
508 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
&&
510 printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
515 printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt
, data
);
517 printf("[ Kerberos V5 accepts you ]\r\n");
519 ret
= krb5_auth_con_getlocalsubkey(telnet_context
,
520 auth_context
, &keyblock
);
522 ret
= krb5_auth_con_getkey(telnet_context
,
523 auth_context
, &keyblock
);
525 printf("[ krb5_auth_con_getkey: %s ]\r\n",
526 krb5_get_err_text(telnet_context
, ret
));
532 skey
.data
= keyblock
->keyvalue
.data
;
533 encrypt_session_key(&skey
, 0);
534 krb5_free_keyblock(telnet_context
, keyblock
);
535 auth_finished(ap
, AUTH_USER
);
536 if (forward_flags
& OPTS_FORWARD_CREDS
)
537 kerberos5_forward(ap
);
541 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) {
542 /* the rest of the reply should contain a krb_ap_rep */
543 krb5_ap_rep_enc_part
*reply
;
548 inbuf
.data
= (char *) data
;
550 ret
= krb5_rd_rep(telnet_context
,
551 auth_context
, &inbuf
, &reply
);
553 printf("[ Mutual authentication failed: %s ]\r\n",
554 krb5_get_err_text(telnet_context
, ret
));
558 krb5_free_ap_rep_enc_part(telnet_context
, reply
);
562 case KRB_FORWARD_ACCEPT
:
563 printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
565 case KRB_FORWARD_REJECT
:
566 printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
571 printf("Unknown Kerberos option %d\r\n", data
[-1]);
577 kerberos5_status(Authenticator
*ap
, char *name
, size_t l
, int level
)
579 if (level
< AUTH_USER
)
582 if (UserNameRequested
&&
583 krb5_kuserok(telnet_context
, ticket
->client
, UserNameRequested
)) {
584 strlcpy(name
, UserNameRequested
, l
);
589 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
590 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
593 kerberos5_printsub(unsigned char *data
, int cnt
, unsigned char *buf
, int buflen
)
597 buf
[buflen
- 1] = '\0'; /* make sure its NULL terminated */
601 case KRB_REJECT
: /* Rejected (reason might follow) */
602 strlcpy((char *) buf
, " REJECT ", buflen
);
605 case KRB_ACCEPT
: /* Accepted (name might follow) */
606 strlcpy((char *) buf
, " ACCEPT ", buflen
);
611 ADDC(buf
, buflen
, '"');
612 for (i
= 4; i
< cnt
; i
++)
613 ADDC(buf
, buflen
, data
[i
]);
614 ADDC(buf
, buflen
, '"');
615 ADDC(buf
, buflen
, '\0');
619 case KRB_AUTH
: /* Authentication data follows */
620 strlcpy((char *) buf
, " AUTH", buflen
);
624 strlcpy((char *) buf
, " RESPONSE", buflen
);
627 case KRB_FORWARD
: /* Forwarded credentials follow */
628 strlcpy((char *) buf
, " FORWARD", buflen
);
631 case KRB_FORWARD_ACCEPT
: /* Forwarded credentials accepted */
632 strlcpy((char *) buf
, " FORWARD_ACCEPT", buflen
);
635 case KRB_FORWARD_REJECT
: /* Forwarded credentials rejected */
636 /* (reason might follow) */
637 strlcpy((char *) buf
, " FORWARD_REJECT", buflen
);
641 snprintf(buf
, buflen
, " %d (unknown)", data
[3]);
644 for (i
= 4; i
< cnt
; i
++) {
645 snprintf(buf
, buflen
, " %d", data
[i
]);
653 kerberos5_forward(Authenticator
* ap
)
658 krb5_kdc_flags flags
;
660 krb5_principal principal
;
662 ret
= krb5_cc_default(telnet_context
, &ccache
);
665 printf("KerberosV5: could not get default ccache: %s\r\n",
666 krb5_get_err_text(telnet_context
, ret
));
669 ret
= krb5_cc_get_principal(telnet_context
, ccache
, &principal
);
672 printf("KerberosV5: could not get principal: %s\r\n",
673 krb5_get_err_text(telnet_context
, ret
));
676 memset(&creds
, 0, sizeof(creds
));
678 creds
.client
= principal
;
680 ret
= krb5_build_principal(telnet_context
, &creds
.server
,
681 strlen(principal
->realm
), principal
->realm
, "krbtgt",
682 principal
->realm
, NULL
);
686 printf("KerberosV5: could not get principal: %s\r\n",
687 krb5_get_err_text(telnet_context
, ret
));
690 creds
.times
.endtime
= 0;
693 flags
.b
.forwarded
= 1;
694 if (forward_flags
& OPTS_FORWARDABLE_CREDS
)
695 flags
.b
.forwardable
= 1;
697 ret
= krb5_get_forwarded_creds(telnet_context
, auth_context
,
698 ccache
, flags
.i
, RemoteHostName
, &creds
, &out_data
);
701 printf("Kerberos V5: error getting forwarded creds: %s\r\n",
702 krb5_get_err_text(telnet_context
, ret
));
705 if (!Data(ap
, KRB_FORWARD
, out_data
.data
, out_data
.length
)) {
707 printf("Not enough room for authentication data\r\n");
710 printf("Forwarded local Kerberos V5 credentials to server\r\n");