1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)kerberos.c 8.3 (Berkeley) 05/30/95";
10 #endif /* not lint */
11
12 /*
13 * Copyright (C) 1990 by the Massachusetts Institute of Technology
14 *
15 * Export of this software from the United States of America is assumed
16 * to require a specific license from the United States Government.
17 * It is the responsibility of any person or organization contemplating
18 * export to obtain such a license before exporting.
19 *
20 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
21 * distribute this software and its documentation for any purpose and
22 * without fee is hereby granted, provided that the above copyright
23 * notice appear in all copies and that both that copyright notice and
24 * this permission notice appear in supporting documentation, and that
25 * the name of M.I.T. not be used in advertising or publicity pertaining
26 * to distribution of the software without specific, written prior
27 * permission. M.I.T. makes no representations about the suitability of
28 * this software for any purpose. It is provided "as is" without express
29 * or implied warranty.
30 */
31
32 #ifdef KRB4
33 #include <sys/types.h>
34 #include <arpa/telnet.h>
35 #include <stdio.h>
36 #include <des.h> /* BSD wont include this in krb.h, so we do it here */
37 #include <krb.h>
38 #ifdef __STDC__
39 #include <stdlib.h>
40 #endif
41 #ifdef NO_STRING_H
42 #include <strings.h>
43 #else
44 #include <string.h>
45 #endif
46
47 #include "encrypt.h"
48 #include "auth.h"
49 #include "misc.h"
50
51 int kerberos4_cksum P((unsigned char *, int));
52 int krb_mk_req P((KTEXT, char *, char *, char *, u_long));
53 int krb_rd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *));
54 int krb_kntoln P((AUTH_DAT *, char *));
55 int krb_get_cred P((char *, char *, char *, CREDENTIALS *));
56 int krb_get_lrealm P((char *, int));
57 int kuserok P((AUTH_DAT *, char *));
58
59 extern auth_debug_mode;
60
61 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
62 AUTHTYPE_KERBEROS_V4, };
63 static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
64 TELQUAL_NAME, };
65
66 #define KRB_AUTH 0 /* Authentication data follows */
67 #define KRB_REJECT 1 /* Rejected (reason might follow) */
68 #define KRB_ACCEPT 2 /* Accepted */
69 #define KRB_CHALLENGE 3 /* Challenge for mutual auth. */
70 #define KRB_RESPONSE 4 /* Response for mutual auth. */
71
72 #define KRB_SERVICE_NAME "rcmd"
73
74 static KTEXT_ST auth;
75 static char name[ANAME_SZ];
76 static AUTH_DAT adat = { 0 };
77 #ifdef ENCRYPTION
78 static Block session_key = { 0 };
79 static Schedule sched;
80 static Block challenge = { 0 };
81 #endif /* ENCRYPTION */
82
83 static int
Data(ap,type,d,c)84 Data(ap, type, d, c)
85 Authenticator *ap;
86 int type;
87 void *d;
88 int c;
89 {
90 unsigned char *p = str_data + 4;
91 unsigned char *cd = (unsigned char *)d;
92
93 if (c == -1)
94 c = strlen((char *)cd);
95
96 if (auth_debug_mode) {
97 printf("%s:%d: [%d] (%d)",
98 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
99 str_data[3],
100 type, c);
101 printd(d, c);
102 printf("\r\n");
103 }
104 *p++ = ap->type;
105 *p++ = ap->way;
106 *p++ = type;
107 while (c-- > 0) {
108 if ((*p++ = *cd++) == IAC)
109 *p++ = IAC;
110 }
111 *p++ = IAC;
112 *p++ = SE;
113 if (str_data[3] == TELQUAL_IS)
114 printsub('>', &str_data[2], p - (&str_data[2]));
115 return(net_write(str_data, p - str_data));
116 }
117
118 int
kerberos4_init(ap,server)119 kerberos4_init(ap, server)
120 Authenticator *ap;
121 int server;
122 {
123 FILE *fp;
124
125 if (server) {
126 str_data[3] = TELQUAL_REPLY;
127 if ((fp = fopen(KEYFILE, "r")) == NULL)
128 return(0);
129 fclose(fp);
130 } else {
131 str_data[3] = TELQUAL_IS;
132 }
133 return(1);
134 }
135
136 char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
137 int dst_realm_sz = REALM_SZ;
138
139 int
kerberos4_send(ap)140 kerberos4_send(ap)
141 Authenticator *ap;
142 {
143 KTEXT_ST auth;
144 #ifdef ENCRYPTION
145 Block enckey;
146 #endif /* ENCRYPTION */
147 char instance[INST_SZ];
148 char *realm;
149 char *krb_realmofhost();
150 char *krb_get_phost();
151 CREDENTIALS cred;
152 int r;
153
154 printf("[ Trying KERBEROS4 ... ]\n");
155 if (!UserNameRequested) {
156 if (auth_debug_mode) {
157 printf("Kerberos V4: no user name supplied\r\n");
158 }
159 return(0);
160 }
161
162 memset(instance, 0, sizeof(instance));
163
164 if (realm = krb_get_phost(RemoteHostName))
165 strncpy(instance, realm, sizeof(instance));
166
167 instance[sizeof(instance)-1] = '\0';
168
169 realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName);
170
171 if (!realm) {
172 printf("Kerberos V4: no realm for %s\r\n", RemoteHostName);
173 return(0);
174 }
175 if (r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L)) {
176 printf("mk_req failed: %s\r\n", krb_err_txt[r]);
177 return(0);
178 }
179 if (r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred)) {
180 printf("get_cred failed: %s\r\n", krb_err_txt[r]);
181 return(0);
182 }
183 if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
184 if (auth_debug_mode)
185 printf("Not enough room for user name\r\n");
186 return(0);
187 }
188 if (auth_debug_mode)
189 printf("Sent %d bytes of authentication data\r\n", auth.length);
190 if (!Data(ap, KRB_AUTH, (void *)auth.dat, auth.length)) {
191 if (auth_debug_mode)
192 printf("Not enough room for authentication data\r\n");
193 return(0);
194 }
195 #ifdef ENCRYPTION
196 /*
197 * If we are doing mutual authentication, get set up to send
198 * the challenge, and verify it when the response comes back.
199 */
200 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
201 register int i;
202
203 des_key_sched(cred.session, sched);
204 des_init_random_number_generator(cred.session);
205 des_new_random_key(session_key);
206 des_ecb_encrypt(session_key, session_key, sched, 0);
207 des_ecb_encrypt(session_key, challenge, sched, 0);
208 /*
209 * Increment the challenge by 1, and encrypt it for
210 * later comparison.
211 */
212 for (i = 7; i >= 0; --i) {
213 register int x;
214 x = (unsigned int)challenge[i] + 1;
215 challenge[i] = x; /* ignore overflow */
216 if (x < 256) /* if no overflow, all done */
217 break;
218 }
219 des_ecb_encrypt(challenge, challenge, sched, 1);
220 }
221 #endif /* ENCRYPTION */
222
223 if (auth_debug_mode) {
224 printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
225 printd(auth.dat, auth.length);
226 printf("\r\n");
227 printf("Sent Kerberos V4 credentials to server\r\n");
228 }
229 return(1);
230 }
231
232 void
kerberos4_is(ap,data,cnt)233 kerberos4_is(ap, data, cnt)
234 Authenticator *ap;
235 unsigned char *data;
236 int cnt;
237 {
238 #ifdef ENCRYPTION
239 Session_Key skey;
240 Block datablock;
241 #endif /* ENCRYPTION */
242 char realm[REALM_SZ];
243 char instance[INST_SZ];
244 int r;
245
246 if (cnt-- < 1)
247 return;
248 switch (*data++) {
249 case KRB_AUTH:
250 if (krb_get_lrealm(realm, 1) != KSUCCESS) {
251 Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1);
252 auth_finished(ap, AUTH_REJECT);
253 if (auth_debug_mode)
254 printf("No local realm\r\n");
255 return;
256 }
257 memmove((void *)auth.dat, (void *)data, auth.length = cnt);
258 if (auth_debug_mode) {
259 printf("Got %d bytes of authentication data\r\n", cnt);
260 printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
261 printd(auth.dat, auth.length);
262 printf("\r\n");
263 }
264 instance[0] = '*'; instance[1] = 0;
265 if (r = krb_rd_req(&auth, KRB_SERVICE_NAME,
266 instance, 0, &adat, "")) {
267 if (auth_debug_mode)
268 printf("Kerberos failed him as %s\r\n", name);
269 Data(ap, KRB_REJECT, (void *)krb_err_txt[r], -1);
270 auth_finished(ap, AUTH_REJECT);
271 return;
272 }
273 #ifdef ENCRYPTION
274 memmove((void *)session_key, (void *)adat.session, sizeof(Block));
275 #endif /* ENCRYPTION */
276 krb_kntoln(&adat, name);
277
278 if (UserNameRequested && !kuserok(&adat, UserNameRequested))
279 Data(ap, KRB_ACCEPT, (void *)0, 0);
280 else
281 Data(ap, KRB_REJECT,
282 (void *)"user is not authorized", -1);
283 auth_finished(ap, AUTH_USER);
284 break;
285
286 case KRB_CHALLENGE:
287 #ifndef ENCRYPTION
288 Data(ap, KRB_RESPONSE, (void *)0, 0);
289 #else /* ENCRYPTION */
290 if (!VALIDKEY(session_key)) {
291 /*
292 * We don't have a valid session key, so just
293 * send back a response with an empty session
294 * key.
295 */
296 Data(ap, KRB_RESPONSE, (void *)0, 0);
297 break;
298 }
299
300 /*
301 * Initialize the random number generator since it's
302 * used later on by the encryption routine.
303 */
304 des_init_random_number_generator(session_key);
305 des_key_sched(session_key, sched);
306 memmove((void *)datablock, (void *)data, sizeof(Block));
307 /*
308 * Take the received encrypted challenge, and encrypt
309 * it again to get a unique session_key for the
310 * ENCRYPT option.
311 */
312 des_ecb_encrypt(datablock, session_key, sched, 1);
313 skey.type = SK_DES;
314 skey.length = 8;
315 skey.data = session_key;
316 encrypt_session_key(&skey, 1);
317 /*
318 * Now decrypt the received encrypted challenge,
319 * increment by one, re-encrypt it and send it back.
320 */
321 des_ecb_encrypt(datablock, challenge, sched, 0);
322 for (r = 7; r >= 0; r--) {
323 register int t;
324 t = (unsigned int)challenge[r] + 1;
325 challenge[r] = t; /* ignore overflow */
326 if (t < 256) /* if no overflow, all done */
327 break;
328 }
329 des_ecb_encrypt(challenge, challenge, sched, 1);
330 Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge));
331 #endif /* ENCRYPTION */
332 break;
333
334 default:
335 if (auth_debug_mode)
336 printf("Unknown Kerberos option %d\r\n", data[-1]);
337 Data(ap, KRB_REJECT, 0, 0);
338 break;
339 }
340 }
341
342 void
kerberos4_reply(ap,data,cnt)343 kerberos4_reply(ap, data, cnt)
344 Authenticator *ap;
345 unsigned char *data;
346 int cnt;
347 {
348 #ifdef ENCRYPTION
349 Session_Key skey;
350 #endif /* ENCRYPTION */
351
352 if (cnt-- < 1)
353 return;
354 switch (*data++) {
355 case KRB_REJECT:
356 if (cnt > 0) {
357 printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n",
358 cnt, data);
359 } else
360 printf("[ Kerberos V4 refuses authentication ]\r\n");
361 auth_send_retry();
362 return;
363 case KRB_ACCEPT:
364 printf("[ Kerberos V4 accepts you ]\n");
365 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
366 /*
367 * Send over the encrypted challenge.
368 */
369 #ifndef ENCRYPTION
370 Data(ap, KRB_CHALLENGE, (void *)0, 0);
371 #else /* ENCRYPTION */
372 Data(ap, KRB_CHALLENGE, (void *)session_key,
373 sizeof(session_key));
374 des_ecb_encrypt(session_key, session_key, sched, 1);
375 skey.type = SK_DES;
376 skey.length = 8;
377 skey.data = session_key;
378 encrypt_session_key(&skey, 0);
379 #endif /* ENCRYPTION */
380 return;
381 }
382 auth_finished(ap, AUTH_USER);
383 return;
384 case KRB_RESPONSE:
385 #ifdef ENCRYPTION
386 /*
387 * Verify that the response to the challenge is correct.
388 */
389 if ((cnt != sizeof(Block)) ||
390 (0 != memcmp((void *)data, (void *)challenge,
391 sizeof(challenge))))
392 {
393 #endif /* ENCRYPTION */
394 printf("[ Kerberos V4 challenge failed!!! ]\r\n");
395 auth_send_retry();
396 return;
397 #ifdef ENCRYPTION
398 }
399 printf("[ Kerberos V4 challenge successful ]\r\n");
400 auth_finished(ap, AUTH_USER);
401 #endif /* ENCRYPTION */
402 break;
403 default:
404 if (auth_debug_mode)
405 printf("Unknown Kerberos option %d\r\n", data[-1]);
406 return;
407 }
408 }
409
410 int
kerberos4_status(ap,name,level)411 kerberos4_status(ap, name, level)
412 Authenticator *ap;
413 char *name;
414 int level;
415 {
416 if (level < AUTH_USER)
417 return(level);
418
419 if (UserNameRequested && !kuserok(&adat, UserNameRequested)) {
420 strcpy(name, UserNameRequested);
421 return(AUTH_VALID);
422 } else
423 return(AUTH_USER);
424 }
425
426 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
427 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
428
429 void
kerberos4_printsub(data,cnt,buf,buflen)430 kerberos4_printsub(data, cnt, buf, buflen)
431 unsigned char *data, *buf;
432 int cnt, buflen;
433 {
434 char lbuf[32];
435 register int i;
436
437 buf[buflen-1] = '\0'; /* make sure its NULL terminated */
438 buflen -= 1;
439
440 switch(data[3]) {
441 case KRB_REJECT: /* Rejected (reason might follow) */
442 strncpy((char *)buf, " REJECT ", buflen);
443 goto common;
444
445 case KRB_ACCEPT: /* Accepted (name might follow) */
446 strncpy((char *)buf, " ACCEPT ", buflen);
447 common:
448 BUMP(buf, buflen);
449 if (cnt <= 4)
450 break;
451 ADDC(buf, buflen, '"');
452 for (i = 4; i < cnt; i++)
453 ADDC(buf, buflen, data[i]);
454 ADDC(buf, buflen, '"');
455 ADDC(buf, buflen, '\0');
456 break;
457
458 case KRB_AUTH: /* Authentication data follows */
459 strncpy((char *)buf, " AUTH", buflen);
460 goto common2;
461
462 case KRB_CHALLENGE:
463 strncpy((char *)buf, " CHALLENGE", buflen);
464 goto common2;
465
466 case KRB_RESPONSE:
467 strncpy((char *)buf, " RESPONSE", buflen);
468 goto common2;
469
470 default:
471 sprintf(lbuf, " %d (unknown)", data[3]);
472 strncpy((char *)buf, lbuf, buflen);
473 common2:
474 BUMP(buf, buflen);
475 for (i = 4; i < cnt; i++) {
476 sprintf(lbuf, " %d", data[i]);
477 strncpy((char *)buf, lbuf, buflen);
478 BUMP(buf, buflen);
479 }
480 break;
481 }
482 }
483
484 int
kerberos4_cksum(d,n)485 kerberos4_cksum(d, n)
486 unsigned char *d;
487 int n;
488 {
489 int ck = 0;
490
491 /*
492 * A comment is probably needed here for those not
493 * well versed in the "C" language. Yes, this is
494 * supposed to be a "switch" with the body of the
495 * "switch" being a "while" statement. The whole
496 * purpose of the switch is to allow us to jump into
497 * the middle of the while() loop, and then not have
498 * to do any more switch()s.
499 *
500 * Some compilers will spit out a warning message
501 * about the loop not being entered at the top.
502 */
503 switch (n&03)
504 while (n > 0) {
505 case 0:
506 ck ^= (int)*d++ << 24;
507 --n;
508 case 3:
509 ck ^= (int)*d++ << 16;
510 --n;
511 case 2:
512 ck ^= (int)*d++ << 8;
513 --n;
514 case 1:
515 ck ^= (int)*d++;
516 --n;
517 }
518 return(ck);
519 }
520 #endif
521
522 #ifdef notdef
523
prkey(msg,key)524 prkey(msg, key)
525 char *msg;
526 unsigned char *key;
527 {
528 register int i;
529 printf("%s:", msg);
530 for (i = 0; i < 8; i++)
531 printf(" %3d", key[i]);
532 printf("\r\n");
533 }
534 #endif
535