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