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