]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/telnet/libtelnet/kerberos.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.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. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31
32 __FBSDID("$FreeBSD$");
33
34 #ifndef lint
35 static const char sccsid[] = "@(#)kerberos.c    8.3 (Berkeley) 5/30/95";
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 <openssl/des.h>        /* BSD wont include this in krb.h, so we do it here */
62 #include <krb.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66
67 #include "encrypt.h"
68 #include "auth.h"
69 #include "misc.h"
70
71 int kerberos4_cksum(unsigned char *, int);
72 int kuserok(AUTH_DAT *, char *);
73
74 extern int auth_debug_mode;
75
76 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
77                                         AUTHTYPE_KERBEROS_V4, };
78
79 #define KRB_AUTH        0               /* Authentication data follows */
80 #define KRB_REJECT      1               /* Rejected (reason might follow) */
81 #define KRB_ACCEPT      2               /* Accepted */
82 #define KRB_CHALLENGE   3               /* Challenge for mutual auth. */
83 #define KRB_RESPONSE    4               /* Response for mutual auth. */
84
85 static  KTEXT_ST auth;
86 static  char name[ANAME_SZ];
87 static  AUTH_DAT adat = { 0, "", "", "", 0, {}, 0, 0, 0, { 0, "", 0 } };
88 #ifdef  ENCRYPTION
89 static Block    session_key     = { 0 };
90 static DES_key_schedule sched;
91 static Block    challenge       = { 0 };
92 #endif  /* ENCRYPTION */
93
94 static char krb_service_name[] = "rcmd";
95 static char empty[] = "";
96
97 static int
98 Data(Authenticator *ap, int type, const unsigned char *d, int c)
99 {
100         unsigned char *p = str_data + 4;
101         const unsigned char *cd = d;
102
103         if (c == -1)
104                 c = strlen(cd);
105
106         if (auth_debug_mode) {
107                 printf("%s:%d: [%d] (%d)",
108                         str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
109                         str_data[3],
110                         type, c);
111                 printd(d, c);
112                 printf("\r\n");
113         }
114         *p++ = ap->type;
115         *p++ = ap->way;
116         *p++ = type;
117         while (c-- > 0) {
118                 if ((*p++ = *cd++) == IAC)
119                         *p++ = IAC;
120         }
121         *p++ = IAC;
122         *p++ = SE;
123         if (str_data[3] == TELQUAL_IS)
124                 printsub('>', &str_data[2], p - (&str_data[2]));
125         return(net_write(str_data, p - str_data));
126 }
127
128 int
129 kerberos4_init(Authenticator *ap __unused, int server)
130 {
131         FILE *fp;
132
133         if (server) {
134                 str_data[3] = TELQUAL_REPLY;
135                 if ((fp = fopen(KEYFILE, "r")) == NULL)
136                         return(0);
137                 fclose(fp);
138         } else {
139                 str_data[3] = TELQUAL_IS;
140         }
141         return(1);
142 }
143
144 char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
145 int dst_realm_sz = REALM_SZ;
146
147 int
148 kerberos4_send(Authenticator *ap)
149 {
150         KTEXT_ST lauth;
151         char instance[INST_SZ];
152         char *realm;
153         CREDENTIALS cred;
154         int r;
155
156         printf("[ Trying KERBEROS4 ... ]\n");
157         if (!UserNameRequested) {
158                 if (auth_debug_mode) {
159                         printf("Kerberos V4: no user name supplied\r\n");
160                 }
161                 return(0);
162         }
163
164         memset(instance, 0, sizeof(instance));
165
166         if ((realm = krb_get_phost(RemoteHostName)))
167                 strncpy(instance, realm, sizeof(instance));
168
169         instance[sizeof(instance)-1] = '\0';
170
171         realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName);
172
173         if (!realm) {
174                 printf("Kerberos V4: no realm for %s\r\n", RemoteHostName);
175                 return(0);
176         }
177         if ((r = krb_mk_req(&lauth, krb_service_name, instance, realm, 0L))) {
178                 printf("mk_req failed: %s\r\n", krb_err_txt[r]);
179                 return(0);
180         }
181         if ((r = krb_get_cred(krb_service_name, instance, realm, &cred))) {
182                 printf("get_cred failed: %s\r\n", krb_err_txt[r]);
183                 return(0);
184         }
185         if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
186                 if (auth_debug_mode)
187                         printf("Not enough room for user name\r\n");
188                 return(0);
189         }
190         if (auth_debug_mode)
191                 printf("Sent %d bytes of authentication data\r\n", lauth.length);
192         if (!Data(ap, KRB_AUTH, (void *)lauth.dat, lauth.length)) {
193                 if (auth_debug_mode)
194                         printf("Not enough room for authentication data\r\n");
195                 return(0);
196         }
197 #ifdef  ENCRYPTION
198         /*
199          * If we are doing mutual authentication, get set up to send
200          * the challenge, and verify it when the response comes back.
201          */
202         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
203                 register int i;
204
205                 DES_key_sched(&cred.session, sched);
206                 DES_random_key(&session_key);
207                 DES_ecb_encrypt(&session_key, &session_key, sched, 0);
208                 DES_ecb_encrypt(&session_key, &challenge, sched, 0);
209                 /*
210                  * Increment the challenge by 1, and encrypt it for
211                  * later comparison.
212                  */
213                 for (i = 7; i >= 0; --i) {
214                         register int x;
215                         x = (unsigned int)challenge[i] + 1;
216                         challenge[i] = x;       /* ignore overflow */
217                         if (x < 256)            /* if no overflow, all done */
218                                 break;
219                 }
220                 DES_ecb_encrypt(&challenge, &challenge, sched, 1);
221         }
222 #endif  /* ENCRYPTION */
223
224         if (auth_debug_mode) {
225                 printf("CK: %d:", kerberos4_cksum(lauth.dat, lauth.length));
226                 printd(lauth.dat, lauth.length);
227                 printf("\r\n");
228                 printf("Sent Kerberos V4 credentials to server\r\n");
229         }
230         return(1);
231 }
232
233 void
234 kerberos4_is(Authenticator *ap, unsigned char *data, int cnt)
235 {
236 #ifdef  ENCRYPTION
237         Session_Key skey;
238         Block datablock;
239 #endif  /* ENCRYPTION */
240         char realm[REALM_SZ];
241         char instance[INST_SZ];
242         int r;
243
244         if (cnt-- < 1)
245                 return;
246         switch (*data++) {
247         case KRB_AUTH:
248                 if (krb_get_lrealm(realm, 1) != KSUCCESS) {
249                         Data(ap, KRB_REJECT, "No local V4 Realm.", -1);
250                         auth_finished(ap, AUTH_REJECT);
251                         if (auth_debug_mode)
252                                 printf("No local realm\r\n");
253                         return;
254                 }
255                 memmove((void *)auth.dat, (void *)data, auth.length = cnt);
256                 if (auth_debug_mode) {
257                         printf("Got %d bytes of authentication data\r\n", cnt);
258                         printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
259                         printd(auth.dat, auth.length);
260                         printf("\r\n");
261                 }
262                 instance[0] = '*'; instance[1] = 0;
263                 if ((r = krb_rd_req(&auth, krb_service_name,
264                                    instance, 0, &adat, empty))) {
265                         if (auth_debug_mode)
266                                 printf("Kerberos failed him as %s\r\n", name);
267                         Data(ap, KRB_REJECT, krb_err_txt[r], -1);
268                         auth_finished(ap, AUTH_REJECT);
269                         return;
270                 }
271 #ifdef  ENCRYPTION
272                 memmove((void *)session_key, (void *)adat.session, sizeof(Block));
273 #endif  /* ENCRYPTION */
274                 krb_kntoln(&adat, name);
275
276                 if (UserNameRequested && !kuserok(&adat, UserNameRequested))
277                         Data(ap, KRB_ACCEPT, NULL, 0);
278                 else
279                         Data(ap, KRB_REJECT, "user is not authorized", -1);
280                 auth_finished(ap, AUTH_USER);
281                 break;
282
283         case KRB_CHALLENGE:
284 #ifndef ENCRYPTION
285                 Data(ap, KRB_RESPONSE, NULL, 0);
286 #else   /* ENCRYPTION */
287                 if (!VALIDKEY(session_key)) {
288                         /*
289                          * We don't have a valid session key, so just
290                          * send back a response with an empty session
291                          * key.
292                          */
293                         Data(ap, KRB_RESPONSE, NULL, 0);
294                         break;
295                 }
296
297                 DES_key_sched(&session_key, sched);
298                 memmove((void *)datablock, (void *)data, sizeof(Block));
299                 /*
300                  * Take the received encrypted challenge, and encrypt
301                  * it again to get a unique session_key for the
302                  * ENCRYPT option.
303                  */
304                 DES_ecb_encrypt(&datablock, &session_key, sched, 1);
305                 skey.type = SK_DES;
306                 skey.length = 8;
307                 skey.data = session_key;
308                 encrypt_session_key(&skey, 1);
309                 /*
310                  * Now decrypt the received encrypted challenge,
311                  * increment by one, re-encrypt it and send it back.
312                  */
313                 DES_ecb_encrypt(&datablock, &challenge, sched, 0);
314                 for (r = 7; r >= 0; r--) {
315                         register int t;
316                         t = (unsigned int)challenge[r] + 1;
317                         challenge[r] = t;       /* ignore overflow */
318                         if (t < 256)            /* if no overflow, all done */
319                                 break;
320                 }
321                 DES_ecb_encrypt(&challenge, &challenge, sched, 1);
322                 Data(ap, KRB_RESPONSE, challenge, sizeof(challenge));
323 #endif  /* ENCRYPTION */
324                 break;
325
326         default:
327                 if (auth_debug_mode)
328                         printf("Unknown Kerberos option %d\r\n", data[-1]);
329                 Data(ap, KRB_REJECT, NULL, 0);
330                 break;
331         }
332 }
333
334 void
335 kerberos4_reply(Authenticator *ap, unsigned char *data, int cnt)
336 {
337 #ifdef  ENCRYPTION
338         Session_Key skey;
339 #endif  /* ENCRYPTION */
340
341         if (cnt-- < 1)
342                 return;
343         switch (*data++) {
344         case KRB_REJECT:
345                 if (cnt > 0) {
346                         printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n",
347                                 cnt, data);
348                 } else
349                         printf("[ Kerberos V4 refuses authentication ]\r\n");
350                 auth_send_retry();
351                 return;
352         case KRB_ACCEPT:
353                 printf("[ Kerberos V4 accepts you ]\n");
354                 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
355                         /*
356                          * Send over the encrypted challenge.
357                          */
358 #ifndef ENCRYPTION
359                         Data(ap, KRB_CHALLENGE, NULL, 0);
360 #else   /* ENCRYPTION */
361                         Data(ap, KRB_CHALLENGE, session_key,
362                                                 sizeof(session_key));
363                         DES_ecb_encrypt(&session_key, &session_key, sched, 1);
364                         skey.type = SK_DES;
365                         skey.length = 8;
366                         skey.data = session_key;
367                         encrypt_session_key(&skey, 0);
368 #endif  /* ENCRYPTION */
369                         return;
370                 }
371                 auth_finished(ap, AUTH_USER);
372                 return;
373         case KRB_RESPONSE:
374 #ifdef  ENCRYPTION
375                 /*
376                  * Verify that the response to the challenge is correct.
377                  */
378                 if ((cnt != sizeof(Block)) ||
379                     (0 != memcmp((void *)data, (void *)challenge,
380                                                 sizeof(challenge))))
381                 {
382 #endif  /* ENCRYPTION */
383                         printf("[ Kerberos V4 challenge failed!!! ]\r\n");
384                         auth_send_retry();
385                         return;
386 #ifdef  ENCRYPTION
387                 }
388                 printf("[ Kerberos V4 challenge successful ]\r\n");
389                 auth_finished(ap, AUTH_USER);
390 #endif  /* ENCRYPTION */
391                 break;
392         default:
393                 if (auth_debug_mode)
394                         printf("Unknown Kerberos option %d\r\n", data[-1]);
395                 return;
396         }
397 }
398
399 int
400 kerberos4_status(Authenticator *ap __unused, char *nam, int level)
401 {
402         if (level < AUTH_USER)
403                 return(level);
404
405         if (UserNameRequested && !kuserok(&adat, UserNameRequested)) {
406                 strcpy(nam, UserNameRequested);
407                 return(AUTH_VALID);
408         } else
409                 return(AUTH_USER);
410 }
411
412 #define BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
413 #define ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
414
415 void
416 kerberos4_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
417 {
418         char lbuf[32];
419         register int i;
420
421         buf[buflen-1] = '\0';           /* make sure its NULL terminated */
422         buflen -= 1;
423
424         switch(data[3]) {
425         case KRB_REJECT:                /* Rejected (reason might follow) */
426                 strncpy((char *)buf, " REJECT ", buflen);
427                 goto common;
428
429         case KRB_ACCEPT:                /* Accepted (name might follow) */
430                 strncpy((char *)buf, " ACCEPT ", buflen);
431         common:
432                 BUMP(buf, buflen);
433                 if (cnt <= 4)
434                         break;
435                 ADDC(buf, buflen, '"');
436                 for (i = 4; i < cnt; i++)
437                         ADDC(buf, buflen, data[i]);
438                 ADDC(buf, buflen, '"');
439                 ADDC(buf, buflen, '\0');
440                 break;
441
442         case KRB_AUTH:                  /* Authentication data follows */
443                 strncpy((char *)buf, " AUTH", buflen);
444                 goto common2;
445
446         case KRB_CHALLENGE:
447                 strncpy((char *)buf, " CHALLENGE", buflen);
448                 goto common2;
449
450         case KRB_RESPONSE:
451                 strncpy((char *)buf, " RESPONSE", buflen);
452                 goto common2;
453
454         default:
455                 sprintf(lbuf, " %d (unknown)", data[3]);
456                 strncpy((char *)buf, lbuf, buflen);
457         common2:
458                 BUMP(buf, buflen);
459                 for (i = 4; i < cnt; i++) {
460                         sprintf(lbuf, " %d", data[i]);
461                         strncpy((char *)buf, lbuf, buflen);
462                         BUMP(buf, buflen);
463                 }
464                 break;
465         }
466 }
467
468 int
469 kerberos4_cksum(unsigned char *d, int n)
470 {
471         int ck = 0;
472
473         /*
474          * A comment is probably needed here for those not
475          * well versed in the "C" language.  Yes, this is
476          * supposed to be a "switch" with the body of the
477          * "switch" being a "while" statement.  The whole
478          * purpose of the switch is to allow us to jump into
479          * the middle of the while() loop, and then not have
480          * to do any more switch()s.
481          *
482          * Some compilers will spit out a warning message
483          * about the loop not being entered at the top.
484          */
485         switch (n&03)
486         while (n > 0) {
487         case 0:
488                 ck ^= (int)*d++ << 24;
489                 --n;
490         case 3:
491                 ck ^= (int)*d++ << 16;
492                 --n;
493         case 2:
494                 ck ^= (int)*d++ << 8;
495                 --n;
496         case 1:
497                 ck ^= (int)*d++;
498                 --n;
499         }
500         return(ck);
501 }
502 #endif