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("$Heimdal: kerberos.c 22071 2007-11-14 20:04:50Z lha $"
62 #ifdef HAVE_SYS_TYPES_H
63 #include <sys/types.h>
65 #ifdef HAVE_ARPA_TELNET_H
66 #include <arpa/telnet.h>
83 int kerberos4_cksum (unsigned char *, int);
84 extern int auth_debug_mode
;
86 static unsigned char str_data
[2048] = { IAC
, SB
, TELOPT_AUTHENTICATION
, 0,
87 AUTHTYPE_KERBEROS_V4
, };
89 #define KRB_AUTH 0 /* Authentication data follows */
90 #define KRB_REJECT 1 /* Rejected (reason might follow) */
91 #define KRB_ACCEPT 2 /* Accepted */
92 #define KRB_CHALLENGE 3 /* Challenge for mutual auth. */
93 #define KRB_RESPONSE 4 /* Response for mutual auth. */
95 #define KRB_FORWARD 5 /* */
96 #define KRB_FORWARD_ACCEPT 6 /* */
97 #define KRB_FORWARD_REJECT 7 /* */
99 #define KRB_SERVICE_NAME "rcmd"
101 static KTEXT_ST auth
;
102 static char name
[ANAME_SZ
];
103 static AUTH_DAT adat
;
104 static des_cblock session_key
;
105 static des_cblock cred_session
;
106 static des_key_schedule sched
;
107 static des_cblock challenge
;
108 static int auth_done
; /* XXX */
110 static int pack_cred(CREDENTIALS
*cred
, unsigned char *buf
);
111 static int unpack_cred(unsigned char *buf
, int len
, CREDENTIALS
*cred
);
115 Data(Authenticator
*ap
, int type
, const void *d
, int c
)
117 unsigned char *p
= str_data
+ 4;
118 const unsigned char *cd
= (const unsigned char *)d
;
121 c
= strlen((const char *)cd
);
123 if (auth_debug_mode
) {
124 printf("%s:%d: [%d] (%d)",
125 str_data
[3] == TELQUAL_IS
? ">>>IS" : ">>>REPLY",
135 if ((*p
++ = *cd
++) == IAC
)
140 if (str_data
[3] == TELQUAL_IS
)
141 printsub('>', &str_data
[2], p
- (&str_data
[2]));
142 return(telnet_net_write(str_data
, p
- str_data
));
146 kerberos4_init(Authenticator
*ap
, int server
)
151 str_data
[3] = TELQUAL_REPLY
;
152 if ((fp
= fopen(KEYFILE
, "r")) == NULL
)
156 str_data
[3] = TELQUAL_IS
;
161 char dst_realm_buf
[REALM_SZ
], *dest_realm
= NULL
;
162 int dst_realm_sz
= REALM_SZ
;
165 kerberos4_send(char *name
, Authenticator
*ap
)
168 char instance
[INST_SZ
];
173 if (!UserNameRequested
) {
174 if (auth_debug_mode
) {
175 printf("Kerberos V4: no user name supplied\r\n");
180 memset(instance
, 0, sizeof(instance
));
183 krb_get_phost(RemoteHostName
),
186 realm
= dest_realm
? dest_realm
: krb_realmofhost(RemoteHostName
);
189 printf("Kerberos V4: no realm for %s\r\n", RemoteHostName
);
192 printf("[ Trying %s (%s.%s@%s) ... ]\r\n", name
,
193 KRB_SERVICE_NAME
, instance
, realm
);
194 r
= krb_mk_req(&auth
, KRB_SERVICE_NAME
, instance
, realm
, 0L);
196 printf("mk_req failed: %s\r\n", krb_get_err_text(r
));
199 r
= krb_get_cred(KRB_SERVICE_NAME
, instance
, realm
, &cred
);
201 printf("get_cred failed: %s\r\n", krb_get_err_text(r
));
204 if (!auth_sendname((unsigned char*)UserNameRequested
,
205 strlen(UserNameRequested
))) {
207 printf("Not enough room for user name\r\n");
211 printf("Sent %d bytes of authentication data\r\n", auth
.length
);
212 if (!Data(ap
, KRB_AUTH
, (void *)auth
.dat
, auth
.length
)) {
214 printf("Not enough room for authentication data\r\n");
218 /* create challenge */
219 if ((ap
->way
& AUTH_HOW_MASK
)==AUTH_HOW_MUTUAL
) {
222 des_key_sched(&cred
.session
, sched
);
223 memcpy (&cred_session
, &cred
.session
, sizeof(cred_session
));
225 des_init_random_number_generator(&cred
.session
);
227 des_new_random_key(&session_key
);
228 des_ecb_encrypt(&session_key
, &session_key
, sched
, 0);
229 des_ecb_encrypt(&session_key
, &challenge
, sched
, 0);
233 Some CERT Advisory thinks this is a bad thing...
235 des_init_random_number_generator(&cred.session);
236 des_new_random_key(&challenge);
237 des_ecb_encrypt(&challenge, &session_key, sched, 1);
241 * Increment the challenge by 1, and encrypt it for
244 for (i
= 7; i
>= 0; --i
)
245 if(++challenge
[i
] != 0) /* No carry! */
247 des_ecb_encrypt(&challenge
, &challenge
, sched
, 1);
252 if (auth_debug_mode
) {
253 printf("CK: %d:", kerberos4_cksum(auth
.dat
, auth
.length
));
254 printd(auth
.dat
, auth
.length
);
256 printf("Sent Kerberos V4 credentials to server\r\n");
261 kerberos4_send_mutual(Authenticator
*ap
)
263 return kerberos4_send("mutual KERBEROS4", ap
);
267 kerberos4_send_oneway(Authenticator
*ap
)
269 return kerberos4_send("KERBEROS4", ap
);
273 kerberos4_is(Authenticator
*ap
, unsigned char *data
, int cnt
)
275 struct sockaddr_in addr
;
276 char realm
[REALM_SZ
];
277 char instance
[INST_SZ
];
285 if (krb_get_lrealm(realm
, 1) != KSUCCESS
) {
286 Data(ap
, KRB_REJECT
, (void *)"No local V4 Realm.", -1);
287 auth_finished(ap
, AUTH_REJECT
);
289 printf("No local realm\r\n");
292 memmove(auth
.dat
, data
, auth
.length
= cnt
);
293 if (auth_debug_mode
) {
294 printf("Got %d bytes of authentication data\r\n", cnt
);
295 printf("CK: %d:", kerberos4_cksum(auth
.dat
, auth
.length
));
296 printd(auth
.dat
, auth
.length
);
299 k_getsockinst(0, instance
, sizeof(instance
));
300 addr_len
= sizeof(addr
);
301 if(getpeername(0, (struct sockaddr
*)&addr
, &addr_len
) < 0) {
303 printf("getpeername failed\r\n");
304 Data(ap
, KRB_REJECT
, "getpeername failed", -1);
305 auth_finished(ap
, AUTH_REJECT
);
308 if (addr
.sin_family
!= AF_INET
) {
310 printf("unknown address family: %d\r\n", addr
.sin_family
);
311 Data(ap
, KRB_REJECT
, "bad address family", -1);
312 auth_finished(ap
, AUTH_REJECT
);
316 r
= krb_rd_req(&auth
, KRB_SERVICE_NAME
,
317 instance
, addr
.sin_addr
.s_addr
, &adat
, "");
320 printf("Kerberos failed him as %s\r\n", name
);
321 Data(ap
, KRB_REJECT
, (void *)krb_get_err_text(r
), -1);
322 auth_finished(ap
, AUTH_REJECT
);
325 /* save the session key */
326 memmove(session_key
, adat
.session
, sizeof(adat
.session
));
327 krb_kntoln(&adat
, name
);
329 if (UserNameRequested
&& !kuserok(&adat
, UserNameRequested
)){
331 struct passwd
*pw
= getpwnam(UserNameRequested
);
334 snprintf(ts
, sizeof(ts
),
337 (unsigned)pw
->pw_uid
);
338 esetenv("KRBTKFILE", ts
, 1);
341 syslog(LOG_INFO
|LOG_AUTH
,
342 "ROOT Kerberos login from %s on %s\n",
343 krb_unparse_name_long(adat
.pname
,
348 Data(ap
, KRB_ACCEPT
, NULL
, 0);
353 ret
= asprintf (&msg
, "user `%s' is not authorized to "
355 krb_unparse_name_long(adat
.pname
,
358 UserNameRequested
? UserNameRequested
: "<nobody>");
360 Data(ap
, KRB_REJECT
, NULL
, 0);
362 Data(ap
, KRB_REJECT
, (void *)msg
, -1);
365 auth_finished(ap
, AUTH_REJECT
);
368 auth_finished(ap
, AUTH_USER
);
373 Data(ap
, KRB_RESPONSE
, NULL
, 0);
375 if(!VALIDKEY(session_key
)){
376 Data(ap
, KRB_RESPONSE
, NULL
, 0);
379 des_key_sched(&session_key
, sched
);
385 memmove(d_block
, data
, sizeof(d_block
));
387 /* make a session key for encryption */
388 des_ecb_encrypt(&d_block
, &session_key
, sched
, 1);
391 skey
.data
=session_key
;
392 encrypt_session_key(&skey
, 1);
394 /* decrypt challenge, add one and encrypt it */
395 des_ecb_encrypt(&d_block
, &challenge
, sched
, 0);
396 for (i
= 7; i
>= 0; i
--)
397 if(++challenge
[i
] != 0)
399 des_ecb_encrypt(&challenge
, &challenge
, sched
, 1);
400 Data(ap
, KRB_RESPONSE
, (void *)challenge
, sizeof(challenge
));
408 unsigned char netcred
[sizeof(CREDENTIALS
)];
411 if(cnt
> sizeof(cred
))
414 memcpy (session_key
, adat
.session
, sizeof(session_key
));
415 des_set_key(&session_key
, ks
);
416 des_pcbc_encrypt((void*)data
, (void*)netcred
, cnt
,
417 ks
, &session_key
, DES_DECRYPT
);
418 unpack_cred(netcred
, cnt
, &cred
);
420 if(strcmp(cred
.service
, KRB_TICKET_GRANTING_TICKET
) ||
421 strncmp(cred
.instance
, cred
.realm
, sizeof(cred
.instance
)) ||
422 cred
.lifetime
< 0 || cred
.lifetime
> 255 ||
423 cred
.kvno
< 0 || cred
.kvno
> 255 ||
424 cred
.issue_date
< 0 ||
425 cred
.issue_date
> time(0) + CLOCK_SKEW
||
426 strncmp(cred
.pname
, adat
.pname
, sizeof(cred
.pname
)) ||
427 strncmp(cred
.pinst
, adat
.pinst
, sizeof(cred
.pinst
))){
428 Data(ap
, KRB_FORWARD_REJECT
, "Bad credentials", -1);
430 if((ret
= tf_setup(&cred
,
432 cred
.pinst
)) == KSUCCESS
){
433 struct passwd
*pw
= getpwnam(UserNameRequested
);
436 chown(tkt_string(), pw
->pw_uid
, pw
->pw_gid
);
437 Data(ap
, KRB_FORWARD_ACCEPT
, 0, 0);
439 Data(ap
, KRB_FORWARD_REJECT
,
440 krb_get_err_text(ret
), -1);
444 memset(data
, 0, cnt
);
445 memset(&ks
, 0, sizeof(ks
));
446 memset(&cred
, 0, sizeof(cred
));
453 printf("Unknown Kerberos option %d\r\n", data
[-1]);
454 Data(ap
, KRB_REJECT
, 0, 0);
460 kerberos4_reply(Authenticator
*ap
, unsigned char *data
, int cnt
)
468 if(auth_done
){ /* XXX Ick! */
469 printf("[ Kerberos V4 received unknown opcode ]\r\n");
471 printf("[ Kerberos V4 refuses authentication ");
473 printf("because %.*s ", cnt
, data
);
479 printf("[ Kerberos V4 accepts you ]\r\n");
481 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) {
483 * Send over the encrypted challenge.
485 Data(ap
, KRB_CHALLENGE
, session_key
,
486 sizeof(session_key
));
487 des_ecb_encrypt(&session_key
, &session_key
, sched
, 1);
490 skey
.data
= session_key
;
491 encrypt_session_key(&skey
, 0);
493 kerberos4_forward(ap
, &cred_session
);
497 auth_finished(ap
, AUTH_USER
);
500 /* make sure the response is correct */
501 if ((cnt
!= sizeof(des_cblock
)) ||
502 (memcmp(data
, challenge
, sizeof(challenge
)))){
503 printf("[ Kerberos V4 challenge failed!!! ]\r\n");
507 printf("[ Kerberos V4 challenge successful ]\r\n");
508 auth_finished(ap
, AUTH_USER
);
510 case KRB_FORWARD_ACCEPT
:
511 printf("[ Kerberos V4 accepted forwarded credentials ]\r\n");
513 case KRB_FORWARD_REJECT
:
514 printf("[ Kerberos V4 rejected forwarded credentials: `%.*s']\r\n",
519 printf("Unknown Kerberos option %d\r\n", data
[-1]);
525 kerberos4_status(Authenticator
*ap
, char *name
, size_t name_sz
, int level
)
527 if (level
< AUTH_USER
)
530 if (UserNameRequested
&& !kuserok(&adat
, UserNameRequested
)) {
531 strlcpy(name
, UserNameRequested
, name_sz
);
537 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
538 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
541 kerberos4_printsub(unsigned char *data
, int cnt
, unsigned char *buf
, int buflen
)
545 buf
[buflen
-1] = '\0'; /* make sure it's NULL terminated */
549 case KRB_REJECT
: /* Rejected (reason might follow) */
550 strlcpy((char *)buf
, " REJECT ", buflen
);
553 case KRB_ACCEPT
: /* Accepted (name might follow) */
554 strlcpy((char *)buf
, " ACCEPT ", buflen
);
559 ADDC(buf
, buflen
, '"');
560 for (i
= 4; i
< cnt
; i
++)
561 ADDC(buf
, buflen
, data
[i
]);
562 ADDC(buf
, buflen
, '"');
563 ADDC(buf
, buflen
, '\0');
566 case KRB_AUTH
: /* Authentication data follows */
567 strlcpy((char *)buf
, " AUTH", buflen
);
571 strlcpy((char *)buf
, " CHALLENGE", buflen
);
575 strlcpy((char *)buf
, " RESPONSE", buflen
);
579 snprintf((char*)buf
, buflen
, " %d (unknown)", data
[3]);
582 for (i
= 4; i
< cnt
; i
++) {
583 snprintf((char*)buf
, buflen
, " %d", data
[i
]);
591 kerberos4_cksum(unsigned char *d
, int n
)
596 * A comment is probably needed here for those not
597 * well versed in the "C" language. Yes, this is
598 * supposed to be a "switch" with the body of the
599 * "switch" being a "while" statement. The whole
600 * purpose of the switch is to allow us to jump into
601 * the middle of the while() loop, and then not have
602 * to do any more switch()s.
604 * Some compilers will spit out a warning message
605 * about the loop not being entered at the top.
610 ck
^= (int)*d
++ << 24;
613 ck
^= (int)*d
++ << 16;
616 ck
^= (int)*d
++ << 8;
626 pack_cred(CREDENTIALS
*cred
, unsigned char *buf
)
628 unsigned char *p
= buf
;
630 memcpy (p
, cred
->service
, ANAME_SZ
);
632 memcpy (p
, cred
->instance
, INST_SZ
);
634 memcpy (p
, cred
->realm
, REALM_SZ
);
636 memcpy(p
, cred
->session
, 8);
638 p
+= KRB_PUT_INT(cred
->lifetime
, p
, 4, 4);
639 p
+= KRB_PUT_INT(cred
->kvno
, p
, 4, 4);
640 p
+= KRB_PUT_INT(cred
->ticket_st
.length
, p
, 4, 4);
641 memcpy(p
, cred
->ticket_st
.dat
, cred
->ticket_st
.length
);
642 p
+= cred
->ticket_st
.length
;
643 p
+= KRB_PUT_INT(0, p
, 4, 4);
644 p
+= KRB_PUT_INT(cred
->issue_date
, p
, 4, 4);
645 memcpy (p
, cred
->pname
, ANAME_SZ
);
647 memcpy (p
, cred
->pinst
, INST_SZ
);
653 unpack_cred(unsigned char *buf
, int len
, CREDENTIALS
*cred
)
655 char *p
= (char*)buf
;
658 strncpy (cred
->service
, p
, ANAME_SZ
);
659 cred
->service
[ANAME_SZ
- 1] = '\0';
661 strncpy (cred
->instance
, p
, INST_SZ
);
662 cred
->instance
[INST_SZ
- 1] = '\0';
664 strncpy (cred
->realm
, p
, REALM_SZ
);
665 cred
->realm
[REALM_SZ
- 1] = '\0';
668 memcpy(cred
->session
, p
, 8);
670 p
+= krb_get_int(p
, &tmp
, 4, 0);
671 cred
->lifetime
= tmp
;
672 p
+= krb_get_int(p
, &tmp
, 4, 0);
675 p
+= krb_get_int(p
, &cred
->ticket_st
.length
, 4, 0);
676 memcpy(cred
->ticket_st
.dat
, p
, cred
->ticket_st
.length
);
677 p
+= cred
->ticket_st
.length
;
678 p
+= krb_get_int(p
, &tmp
, 4, 0);
679 cred
->ticket_st
.mbz
= 0;
680 p
+= krb_get_int(p
, (uint32_t *)&cred
->issue_date
, 4, 0);
682 strncpy (cred
->pname
, p
, ANAME_SZ
);
683 cred
->pname
[ANAME_SZ
- 1] = '\0';
685 strncpy (cred
->pinst
, p
, INST_SZ
);
686 cred
->pinst
[INST_SZ
- 1] = '\0';
693 kerberos4_forward(Authenticator
*ap
, void *v
)
695 des_cblock
*key
= (des_cblock
*)v
;
700 unsigned char netcred
[sizeof(CREDENTIALS
)];
703 realm
= krb_realmofhost(RemoteHostName
);
706 memset(&cred
, 0, sizeof(cred
));
707 ret
= krb_get_cred(KRB_TICKET_GRANTING_TICKET
,
713 des_set_key(key
, ks
);
714 len
= pack_cred(&cred
, netcred
);
715 des_pcbc_encrypt((void*)netcred
, (void*)netcred
, len
,
716 ks
, key
, DES_ENCRYPT
);
717 memset(&ks
, 0, sizeof(ks
));
718 Data(ap
, KRB_FORWARD
, netcred
, len
);
719 memset(netcred
, 0, sizeof(netcred
));