Commit | Line | Data |
---|---|---|
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 | 9 | static 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 | ||
59 | int cksum P((unsigned char *, int)); | |
60 | int krb_mk_req P((KTEXT, char *, char *, char *, u_long)); | |
61 | int krb_rd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *)); | |
62 | int krb_kntoln P((AUTH_DAT *, char *)); | |
63 | int krb_get_cred P((char *, char *, char *, CREDENTIALS *)); | |
64 | int krb_get_lrealm P((char *, int)); | |
65 | int kuserok P((AUTH_DAT *, char *)); | |
66 | ||
67 | extern auth_debug_mode; | |
68 | ||
69 | static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, | |
70 | AUTHTYPE_KERBEROS_V4, }; | |
b7c8f459 DB |
71 | static 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 | |
80 | static KTEXT_ST auth; | |
81 | static char name[ANAME_SZ]; | |
82 | static AUTH_DAT adat = { 0 }; | |
83 | #if defined(ENCRYPT) | |
84 | static Block session_key = { 0 }; | |
85 | #endif | |
b7c8f459 DB |
86 | static Schedule sched; |
87 | static Block challange = { 0 }; | |
54b7f482 DB |
88 | |
89 | static int | |
b7c8f459 DB |
90 | Data(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 | |
125 | kerberos4_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 | ||
136 | char dst_realm_buf[REALM_SZ], *dest_realm = NULL; | |
137 | int dst_realm_sz = REALM_SZ; | |
138 | ||
139 | int | |
140 | kerberos4_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 | |
230 | kerberos4_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 | |
324 | kerberos4_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 | |
384 | kerberos4_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 | |
403 | kerberos4_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 | |
458 | cksum(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 | ||
485 | prkey(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 |