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