2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * Copyright (C) 1990 by the Massachusetts Institute of Technology
37 * Export of this software from the United States of America is assumed
38 * to require a specific license from the United States Government.
39 * It is the responsibility of any person or organization contemplating
40 * export to obtain such a license before exporting.
42 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
43 * distribute this software and its documentation for any purpose and
44 * without fee is hereby granted, provided that the above copyright
45 * notice appear in all copies and that both that copyright notice and
46 * this permission notice appear in supporting documentation, and that
47 * the name of M.I.T. not be used in advertising or publicity pertaining
48 * to distribution of the software without specific, written prior
49 * permission. M.I.T. makes no representations about the suitability of
50 * this software for any purpose. It is provided "as is" without express
51 * or implied warranty.
58 RCSID("$Id: kerberos.c,v 1.54 2001/08/22 20:30:22 assar Exp $");
61 #ifdef HAVE_SYS_TYPES_H
62 #include <sys/types.h>
64 #ifdef HAVE_ARPA_TELNET_H
65 #include <arpa/telnet.h>
82 int kerberos4_cksum (unsigned char *, int);
83 extern int auth_debug_mode
;
85 static unsigned char str_data
[2048] = { IAC
, SB
, TELOPT_AUTHENTICATION
, 0,
86 AUTHTYPE_KERBEROS_V4
, };
88 #define KRB_AUTH 0 /* Authentication data follows */
89 #define KRB_REJECT 1 /* Rejected (reason might follow) */
90 #define KRB_ACCEPT 2 /* Accepted */
91 #define KRB_CHALLENGE 3 /* Challenge for mutual auth. */
92 #define KRB_RESPONSE 4 /* Response for mutual auth. */
94 #define KRB_FORWARD 5 /* */
95 #define KRB_FORWARD_ACCEPT 6 /* */
96 #define KRB_FORWARD_REJECT 7 /* */
98 #define KRB_SERVICE_NAME "rcmd"
100 static KTEXT_ST auth
;
101 static char name
[ANAME_SZ
];
102 static AUTH_DAT adat
;
103 static des_cblock session_key
;
104 static des_cblock cred_session
;
105 static des_key_schedule sched
;
106 static des_cblock challenge
;
107 static int auth_done
; /* XXX */
109 static int pack_cred(CREDENTIALS
*cred
, unsigned char *buf
);
110 static int unpack_cred(unsigned char *buf
, int len
, CREDENTIALS
*cred
);
114 Data(Authenticator
*ap
, int type
, const void *d
, int c
)
116 unsigned char *p
= str_data
+ 4;
117 const unsigned char *cd
= (const unsigned char *)d
;
120 c
= strlen((const char *)cd
);
122 if (auth_debug_mode
) {
123 printf("%s:%d: [%d] (%d)",
124 str_data
[3] == TELQUAL_IS
? ">>>IS" : ">>>REPLY",
134 if ((*p
++ = *cd
++) == IAC
)
139 if (str_data
[3] == TELQUAL_IS
)
140 printsub('>', &str_data
[2], p
- (&str_data
[2]));
141 return(telnet_net_write(str_data
, p
- str_data
));
145 kerberos4_init(Authenticator
*ap
, int server
)
150 str_data
[3] = TELQUAL_REPLY
;
151 if ((fp
= fopen(KEYFILE
, "r")) == NULL
)
155 str_data
[3] = TELQUAL_IS
;
160 char dst_realm_buf
[REALM_SZ
], *dest_realm
= NULL
;
161 int dst_realm_sz
= REALM_SZ
;
164 kerberos4_send(char *name
, Authenticator
*ap
)
167 char instance
[INST_SZ
];
172 if (!UserNameRequested
) {
173 if (auth_debug_mode
) {
174 printf("Kerberos V4: no user name supplied\r\n");
179 memset(instance
, 0, sizeof(instance
));
182 krb_get_phost(RemoteHostName
),
185 realm
= dest_realm
? dest_realm
: krb_realmofhost(RemoteHostName
);
188 printf("Kerberos V4: no realm for %s\r\n", RemoteHostName
);
191 printf("[ Trying %s (%s.%s@%s) ... ]\r\n", name
,
192 KRB_SERVICE_NAME
, instance
, realm
);
193 r
= krb_mk_req(&auth
, KRB_SERVICE_NAME
, instance
, realm
, 0L);
195 printf("mk_req failed: %s\r\n", krb_get_err_text(r
));
198 r
= krb_get_cred(KRB_SERVICE_NAME
, instance
, realm
, &cred
);
200 printf("get_cred failed: %s\r\n", krb_get_err_text(r
));
203 if (!auth_sendname((unsigned char*)UserNameRequested
,
204 strlen(UserNameRequested
))) {
206 printf("Not enough room for user name\r\n");
210 printf("Sent %d bytes of authentication data\r\n", auth
.length
);
211 if (!Data(ap
, KRB_AUTH
, (void *)auth
.dat
, auth
.length
)) {
213 printf("Not enough room for authentication data\r\n");
217 /* create challenge */
218 if ((ap
->way
& AUTH_HOW_MASK
)==AUTH_HOW_MUTUAL
) {
221 des_key_sched(&cred
.session
, sched
);
222 memcpy (&cred_session
, &cred
.session
, sizeof(cred_session
));
224 des_init_random_number_generator(&cred
.session
);
226 des_new_random_key(&session_key
);
227 des_ecb_encrypt(&session_key
, &session_key
, sched
, 0);
228 des_ecb_encrypt(&session_key
, &challenge
, sched
, 0);
232 Some CERT Advisory thinks this is a bad thing...
234 des_init_random_number_generator(&cred.session);
235 des_new_random_key(&challenge);
236 des_ecb_encrypt(&challenge, &session_key, sched, 1);
240 * Increment the challenge by 1, and encrypt it for
243 for (i
= 7; i
>= 0; --i
)
244 if(++challenge
[i
] != 0) /* No carry! */
246 des_ecb_encrypt(&challenge
, &challenge
, sched
, 1);
251 if (auth_debug_mode
) {
252 printf("CK: %d:", kerberos4_cksum(auth
.dat
, auth
.length
));
253 printd(auth
.dat
, auth
.length
);
255 printf("Sent Kerberos V4 credentials to server\r\n");
260 kerberos4_send_mutual(Authenticator
*ap
)
262 return kerberos4_send("mutual KERBEROS4", ap
);
266 kerberos4_send_oneway(Authenticator
*ap
)
268 return kerberos4_send("KERBEROS4", ap
);
272 kerberos4_is(Authenticator
*ap
, unsigned char *data
, int cnt
)
274 struct sockaddr_in addr
;
275 char realm
[REALM_SZ
];
276 char instance
[INST_SZ
];
284 if (krb_get_lrealm(realm
, 1) != KSUCCESS
) {
285 Data(ap
, KRB_REJECT
, (void *)"No local V4 Realm.", -1);
286 auth_finished(ap
, AUTH_REJECT
);
288 printf("No local realm\r\n");
291 memmove(auth
.dat
, data
, auth
.length
= cnt
);
292 if (auth_debug_mode
) {
293 printf("Got %d bytes of authentication data\r\n", cnt
);
294 printf("CK: %d:", kerberos4_cksum(auth
.dat
, auth
.length
));
295 printd(auth
.dat
, auth
.length
);
298 k_getsockinst(0, instance
, sizeof(instance
));
299 addr_len
= sizeof(addr
);
300 if(getpeername(0, (struct sockaddr
*)&addr
, &addr_len
) < 0) {
302 printf("getpeername failed\r\n");
303 Data(ap
, KRB_REJECT
, "getpeername failed", -1);
304 auth_finished(ap
, AUTH_REJECT
);
307 if (addr
.sin_family
!= AF_INET
) {
309 printf("unknown address family: %d\r\n", addr
.sin_family
);
310 Data(ap
, KRB_REJECT
, "bad address family", -1);
311 auth_finished(ap
, AUTH_REJECT
);
315 r
= krb_rd_req(&auth
, KRB_SERVICE_NAME
,
316 instance
, addr
.sin_addr
.s_addr
, &adat
, "");
319 printf("Kerberos failed him as %s\r\n", name
);
320 Data(ap
, KRB_REJECT
, (void *)krb_get_err_text(r
), -1);
321 auth_finished(ap
, AUTH_REJECT
);
324 /* save the session key */
325 memmove(session_key
, adat
.session
, sizeof(adat
.session
));
326 krb_kntoln(&adat
, name
);
328 if (UserNameRequested
&& !kuserok(&adat
, UserNameRequested
)){
330 struct passwd
*pw
= getpwnam(UserNameRequested
);
333 snprintf(ts
, sizeof(ts
),
336 (unsigned)pw
->pw_uid
);
337 esetenv("KRBTKFILE", ts
, 1);
340 syslog(LOG_INFO
|LOG_AUTH
,
341 "ROOT Kerberos login from %s on %s\n",
342 krb_unparse_name_long(adat
.pname
,
347 Data(ap
, KRB_ACCEPT
, NULL
, 0);
351 asprintf (&msg
, "user `%s' is not authorized to "
353 krb_unparse_name_long(adat
.pname
,
356 UserNameRequested
? UserNameRequested
: "<nobody>");
358 Data(ap
, KRB_REJECT
, NULL
, 0);
360 Data(ap
, KRB_REJECT
, (void *)msg
, -1);
363 auth_finished(ap
, AUTH_REJECT
);
366 auth_finished(ap
, AUTH_USER
);
371 Data(ap
, KRB_RESPONSE
, NULL
, 0);
373 if(!VALIDKEY(session_key
)){
374 Data(ap
, KRB_RESPONSE
, NULL
, 0);
377 des_key_sched(&session_key
, sched
);
383 memmove(d_block
, data
, sizeof(d_block
));
385 /* make a session key for encryption */
386 des_ecb_encrypt(&d_block
, &session_key
, sched
, 1);
389 skey
.data
=session_key
;
390 encrypt_session_key(&skey
, 1);
392 /* decrypt challenge, add one and encrypt it */
393 des_ecb_encrypt(&d_block
, &challenge
, sched
, 0);
394 for (i
= 7; i
>= 0; i
--)
395 if(++challenge
[i
] != 0)
397 des_ecb_encrypt(&challenge
, &challenge
, sched
, 1);
398 Data(ap
, KRB_RESPONSE
, (void *)challenge
, sizeof(challenge
));
406 unsigned char netcred
[sizeof(CREDENTIALS
)];
409 if(cnt
> sizeof(cred
))
412 memcpy (session_key
, adat
.session
, sizeof(session_key
));
413 des_set_key(&session_key
, ks
);
414 des_pcbc_encrypt((void*)data
, (void*)netcred
, cnt
,
415 ks
, &session_key
, DES_DECRYPT
);
416 unpack_cred(netcred
, cnt
, &cred
);
418 if(strcmp(cred
.service
, KRB_TICKET_GRANTING_TICKET
) ||
419 strncmp(cred
.instance
, cred
.realm
, sizeof(cred
.instance
)) ||
420 cred
.lifetime
< 0 || cred
.lifetime
> 255 ||
421 cred
.kvno
< 0 || cred
.kvno
> 255 ||
422 cred
.issue_date
< 0 ||
423 cred
.issue_date
> time(0) + CLOCK_SKEW
||
424 strncmp(cred
.pname
, adat
.pname
, sizeof(cred
.pname
)) ||
425 strncmp(cred
.pinst
, adat
.pinst
, sizeof(cred
.pinst
))){
426 Data(ap
, KRB_FORWARD_REJECT
, "Bad credentials", -1);
428 if((ret
= tf_setup(&cred
,
430 cred
.pinst
)) == KSUCCESS
){
431 struct passwd
*pw
= getpwnam(UserNameRequested
);
434 chown(tkt_string(), pw
->pw_uid
, pw
->pw_gid
);
435 Data(ap
, KRB_FORWARD_ACCEPT
, 0, 0);
437 Data(ap
, KRB_FORWARD_REJECT
,
438 krb_get_err_text(ret
), -1);
442 memset(data
, 0, cnt
);
443 memset(ks
, 0, sizeof(ks
));
444 memset(&cred
, 0, sizeof(cred
));
451 printf("Unknown Kerberos option %d\r\n", data
[-1]);
452 Data(ap
, KRB_REJECT
, 0, 0);
458 kerberos4_reply(Authenticator
*ap
, unsigned char *data
, int cnt
)
466 if(auth_done
){ /* XXX Ick! */
467 printf("[ Kerberos V4 received unknown opcode ]\r\n");
469 printf("[ Kerberos V4 refuses authentication ");
471 printf("because %.*s ", cnt
, data
);
477 printf("[ Kerberos V4 accepts you ]\r\n");
479 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) {
481 * Send over the encrypted challenge.
483 Data(ap
, KRB_CHALLENGE
, session_key
,
484 sizeof(session_key
));
485 des_ecb_encrypt(&session_key
, &session_key
, sched
, 1);
488 skey
.data
= session_key
;
489 encrypt_session_key(&skey
, 0);
491 kerberos4_forward(ap
, &cred_session
);
495 auth_finished(ap
, AUTH_USER
);
498 /* make sure the response is correct */
499 if ((cnt
!= sizeof(des_cblock
)) ||
500 (memcmp(data
, challenge
, sizeof(challenge
)))){
501 printf("[ Kerberos V4 challenge failed!!! ]\r\n");
505 printf("[ Kerberos V4 challenge successful ]\r\n");
506 auth_finished(ap
, AUTH_USER
);
508 case KRB_FORWARD_ACCEPT
:
509 printf("[ Kerberos V4 accepted forwarded credentials ]\r\n");
511 case KRB_FORWARD_REJECT
:
512 printf("[ Kerberos V4 rejected forwarded credentials: `%.*s']\r\n",
517 printf("Unknown Kerberos option %d\r\n", data
[-1]);
523 kerberos4_status(Authenticator
*ap
, char *name
, size_t name_sz
, int level
)
525 if (level
< AUTH_USER
)
528 if (UserNameRequested
&& !kuserok(&adat
, UserNameRequested
)) {
529 strlcpy(name
, UserNameRequested
, name_sz
);
535 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
536 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
539 kerberos4_printsub(unsigned char *data
, int cnt
, unsigned char *buf
, int buflen
)
543 buf
[buflen
-1] = '\0'; /* make sure its NULL terminated */
547 case KRB_REJECT
: /* Rejected (reason might follow) */
548 strlcpy((char *)buf
, " REJECT ", buflen
);
551 case KRB_ACCEPT
: /* Accepted (name might follow) */
552 strlcpy((char *)buf
, " ACCEPT ", buflen
);
557 ADDC(buf
, buflen
, '"');
558 for (i
= 4; i
< cnt
; i
++)
559 ADDC(buf
, buflen
, data
[i
]);
560 ADDC(buf
, buflen
, '"');
561 ADDC(buf
, buflen
, '\0');
564 case KRB_AUTH
: /* Authentication data follows */
565 strlcpy((char *)buf
, " AUTH", buflen
);
569 strlcpy((char *)buf
, " CHALLENGE", buflen
);
573 strlcpy((char *)buf
, " RESPONSE", buflen
);
577 snprintf((char*)buf
, buflen
, " %d (unknown)", data
[3]);
580 for (i
= 4; i
< cnt
; i
++) {
581 snprintf((char*)buf
, buflen
, " %d", data
[i
]);
589 kerberos4_cksum(unsigned char *d
, int n
)
594 * A comment is probably needed here for those not
595 * well versed in the "C" language. Yes, this is
596 * supposed to be a "switch" with the body of the
597 * "switch" being a "while" statement. The whole
598 * purpose of the switch is to allow us to jump into
599 * the middle of the while() loop, and then not have
600 * to do any more switch()s.
602 * Some compilers will spit out a warning message
603 * about the loop not being entered at the top.
608 ck
^= (int)*d
++ << 24;
611 ck
^= (int)*d
++ << 16;
614 ck
^= (int)*d
++ << 8;
624 pack_cred(CREDENTIALS
*cred
, unsigned char *buf
)
626 unsigned char *p
= buf
;
628 memcpy (p
, cred
->service
, ANAME_SZ
);
630 memcpy (p
, cred
->instance
, INST_SZ
);
632 memcpy (p
, cred
->realm
, REALM_SZ
);
634 memcpy(p
, cred
->session
, 8);
636 p
+= KRB_PUT_INT(cred
->lifetime
, p
, 4, 4);
637 p
+= KRB_PUT_INT(cred
->kvno
, p
, 4, 4);
638 p
+= KRB_PUT_INT(cred
->ticket_st
.length
, p
, 4, 4);
639 memcpy(p
, cred
->ticket_st
.dat
, cred
->ticket_st
.length
);
640 p
+= cred
->ticket_st
.length
;
641 p
+= KRB_PUT_INT(0, p
, 4, 4);
642 p
+= KRB_PUT_INT(cred
->issue_date
, p
, 4, 4);
643 memcpy (p
, cred
->pname
, ANAME_SZ
);
645 memcpy (p
, cred
->pinst
, INST_SZ
);
651 unpack_cred(unsigned char *buf
, int len
, CREDENTIALS
*cred
)
653 char *p
= (char*)buf
;
656 strncpy (cred
->service
, p
, ANAME_SZ
);
657 cred
->service
[ANAME_SZ
- 1] = '\0';
659 strncpy (cred
->instance
, p
, INST_SZ
);
660 cred
->instance
[INST_SZ
- 1] = '\0';
662 strncpy (cred
->realm
, p
, REALM_SZ
);
663 cred
->realm
[REALM_SZ
- 1] = '\0';
666 memcpy(cred
->session
, p
, 8);
668 p
+= krb_get_int(p
, &tmp
, 4, 0);
669 cred
->lifetime
= tmp
;
670 p
+= krb_get_int(p
, &tmp
, 4, 0);
673 p
+= krb_get_int(p
, &cred
->ticket_st
.length
, 4, 0);
674 memcpy(cred
->ticket_st
.dat
, p
, cred
->ticket_st
.length
);
675 p
+= cred
->ticket_st
.length
;
676 p
+= krb_get_int(p
, &tmp
, 4, 0);
677 cred
->ticket_st
.mbz
= 0;
678 p
+= krb_get_int(p
, (u_int32_t
*)&cred
->issue_date
, 4, 0);
680 strncpy (cred
->pname
, p
, ANAME_SZ
);
681 cred
->pname
[ANAME_SZ
- 1] = '\0';
683 strncpy (cred
->pinst
, p
, INST_SZ
);
684 cred
->pinst
[INST_SZ
- 1] = '\0';
691 kerberos4_forward(Authenticator
*ap
, void *v
)
693 des_cblock
*key
= (des_cblock
*)v
;
698 unsigned char netcred
[sizeof(CREDENTIALS
)];
701 realm
= krb_realmofhost(RemoteHostName
);
704 memset(&cred
, 0, sizeof(cred
));
705 ret
= krb_get_cred(KRB_TICKET_GRANTING_TICKET
,
711 des_set_key(key
, ks
);
712 len
= pack_cred(&cred
, netcred
);
713 des_pcbc_encrypt((void*)netcred
, (void*)netcred
, len
,
714 ks
, key
, DES_ENCRYPT
);
715 memset(ks
, 0, sizeof(ks
));
716 Data(ap
, KRB_FORWARD
, netcred
, len
);
717 memset(netcred
, 0, sizeof(netcred
));