Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / telnet / libtelnet / krb4encpwd.c
1 /*-
2  * Copyright (c) 1992, 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: src/crypto/telnet/libtelnet/krb4encpwd.c,v 1.3.2.1 2002/04/13 10:59:07 markm Exp $");
37
38 #ifndef lint
39 static char sccsid[] = "@(#)krb4encpwd.c        8.3 (Berkeley) 5/30/95";
40 #endif /* not lint */
41
42
43 #ifdef  KRB4_ENCPWD
44 /*
45  * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION
46  * ALL RIGHTS RESERVED
47  *
48  * "Digital Equipment Corporation authorizes the reproduction,
49  * distribution and modification of this software subject to the following
50  * restrictions:
51  *
52  * 1.  Any partial or whole copy of this software, or any modification
53  * thereof, must include this copyright notice in its entirety.
54  *
55  * 2.  This software is supplied "as is" with no warranty of any kind,
56  * expressed or implied, for any purpose, including any warranty of fitness
57  * or merchantibility.  DIGITAL assumes no responsibility for the use or
58  * reliability of this software, nor promises to provide any form of
59  * support for it on any basis.
60  *
61  * 3.  Distribution of this software is authorized only if no profit or
62  * remuneration of any kind is received in exchange for such distribution.
63  *
64  * 4.  This software produces public key authentication certificates
65  * bearing an expiration date established by DIGITAL and RSA Data
66  * Security, Inc.  It may cease to generate certificates after the expiration
67  * date.  Any modification of this software that changes or defeats
68  * the expiration date or its effect is unauthorized.
69  *
70  * 5.  Software that will renew or extend the expiration date of
71  * authentication certificates produced by this software may be obtained
72  * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA
73  * 94065, (415)595-8782, or from DIGITAL"
74  *
75  */
76
77 #include <sys/types.h>
78 #include <openssl/des.h>
79 #include <arpa/telnet.h>
80 #include <krb.h>
81 #include <pwd.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <string.h>
85
86 #include "encrypt.h"
87 #include "auth.h"
88 #include "misc.h"
89
90 int krb_mk_encpwd_req(KTEXT, char *, char *, char *, char *, char *, char *);
91 int krb_rd_encpwd_req(KTEXT, char *, char *, u_long, AUTH_DAT *, char *, char *, char *, char *);
92
93 extern auth_debug_mode;
94
95 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
96                                         AUTHTYPE_KRB4_ENCPWD, };
97 static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
98                                         TELQUAL_NAME, };
99
100 #define KRB4_ENCPWD_AUTH        0       /* Authentication data follows */
101 #define KRB4_ENCPWD_REJECT      1       /* Rejected (reason might follow) */
102 #define KRB4_ENCPWD_ACCEPT      2       /* Accepted */
103 #define KRB4_ENCPWD_CHALLENGE   3       /* Challenge for mutual auth. */
104 #define KRB4_ENCPWD_ACK         4       /* Acknowledge */
105
106 #define KRB_SERVICE_NAME    "rcmd"
107
108 static  KTEXT_ST auth;
109 static  char name[ANAME_SZ];
110 static  char user_passwd[ANAME_SZ];
111 static  AUTH_DAT adat = { 0 };
112 #ifdef  ENCRYPTION
113 static Block    session_key     = { 0 };
114 #endif  /* ENCRYPTION */
115 static char  challenge[REALM_SZ];
116
117         static int
118 Data(ap, type, d, c)
119         Authenticator *ap;
120         int type;
121         void *d;
122         int c;
123 {
124         unsigned char *p = str_data + 4;
125         unsigned char *cd = (unsigned char *)d;
126
127         if (c == -1)
128                 c = strlen((char *)cd);
129
130         if (0) {
131                 printf("%s:%d: [%d] (%d)",
132                         str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
133                         str_data[3],
134                         type, c);
135                 printd(d, c);
136                 printf("\r\n");
137         }
138         *p++ = ap->type;
139         *p++ = ap->way;
140         *p++ = type;
141         while (c-- > 0) {
142                 if ((*p++ = *cd++) == IAC)
143                         *p++ = IAC;
144         }
145         *p++ = IAC;
146         *p++ = SE;
147         if (str_data[3] == TELQUAL_IS)
148                 printsub('>', &str_data[2], p - (&str_data[2]));
149         return(net_write(str_data, p - str_data));
150 }
151
152         int
153 krb4encpwd_init(ap, server)
154         Authenticator *ap;
155         int server;
156 {
157         char hostname[80], *cp, *realm;
158         C_Block skey;
159
160         if (server) {
161                 str_data[3] = TELQUAL_REPLY;
162         } else {
163                 str_data[3] = TELQUAL_IS;
164                 gethostname(hostname, sizeof(hostname));
165                 realm = krb_realmofhost(hostname);
166                 cp = strchr(hostname, '.');
167                 if (*cp != NULL) *cp = NULL;
168                 if (read_service_key(KRB_SERVICE_NAME, hostname, realm, 0,
169                                         KEYFILE, (char *)skey)) {
170                   return(0);
171                 }
172         }
173         return(1);
174 }
175
176         int
177 krb4encpwd_send(ap)
178         Authenticator *ap;
179 {
180
181         printf("[ Trying KRB4ENCPWD ... ]\n");
182         if (!UserNameRequested) {
183                 return(0);
184         }
185         if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
186                 return(0);
187         }
188
189         if (!Data(ap, KRB4_ENCPWD_ACK, (void *)NULL, 0)) {
190                 return(0);
191         }
192
193         return(1);
194 }
195
196         void
197 krb4encpwd_is(ap, data, cnt)
198         Authenticator *ap;
199         unsigned char *data;
200         int cnt;
201 {
202         Session_Key skey;
203         Block datablock;
204         char  r_passwd[ANAME_SZ], r_user[ANAME_SZ];
205         char  lhostname[ANAME_SZ], *cp;
206         int r;
207         time_t now;
208
209         if (cnt-- < 1)
210                 return;
211         switch (*data++) {
212         case KRB4_ENCPWD_AUTH:
213                 memmove((void *)auth.dat, (void *)data, auth.length = cnt);
214
215                 gethostname(lhostname, sizeof(lhostname));
216                 if ((cp = strchr(lhostname, '.')) != 0)  *cp = '\0';
217
218                 if (r = krb_rd_encpwd_req(&auth, KRB_SERVICE_NAME, lhostname, 0, &adat, NULL, challenge, r_user, r_passwd)) {
219                         Data(ap, KRB4_ENCPWD_REJECT, (void *)"Auth failed", -1);
220                         auth_finished(ap, AUTH_REJECT);
221                         return;
222                 }
223                 auth_encrypt_userpwd(r_passwd);
224                 if (passwdok(UserNameRequested, UserPassword) == 0) {
225                   /*
226                    *  illegal username and password
227                    */
228                   Data(ap, KRB4_ENCPWD_REJECT, (void *)"Illegal password", -1);
229                   auth_finished(ap, AUTH_REJECT);
230                   return;
231                 }
232
233                 memmove((void *)session_key, (void *)adat.session, sizeof(Block));
234                 Data(ap, KRB4_ENCPWD_ACCEPT, (void *)0, 0);
235                 auth_finished(ap, AUTH_USER);
236                 break;
237
238         case KRB4_ENCPWD_CHALLENGE:
239                 /*
240                  *  Take the received random challenge text and save
241                  *  for future authentication.
242                  */
243                 memmove((void *)challenge, (void *)data, sizeof(Block));
244                 break;
245
246
247         case KRB4_ENCPWD_ACK:
248                 /*
249                  *  Receive ack, if mutual then send random challenge
250                  */
251
252                 /*
253                  * If we are doing mutual authentication, get set up to send
254                  * the challenge, and verify it when the response comes back.
255                  */
256
257                 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
258                   register int i;
259
260                   time(&now);
261                   sprintf(challenge, "%x", now);
262                   Data(ap, KRB4_ENCPWD_CHALLENGE, (void *)challenge, strlen(challenge));
263                 }
264                 break;
265
266         default:
267                 Data(ap, KRB4_ENCPWD_REJECT, 0, 0);
268                 break;
269         }
270 }
271
272
273         void
274 krb4encpwd_reply(ap, data, cnt)
275         Authenticator *ap;
276         unsigned char *data;
277         int cnt;
278 {
279         Session_Key skey;
280         KTEXT_ST krb_token;
281         Block enckey;
282         CREDENTIALS cred;
283         int r;
284         char    randchal[REALM_SZ], instance[ANAME_SZ], *cp;
285         char    hostname[80], *realm;
286
287         if (cnt-- < 1)
288                 return;
289         switch (*data++) {
290         case KRB4_ENCPWD_REJECT:
291                 if (cnt > 0) {
292                         printf("[ KRB4_ENCPWD refuses authentication because %.*s ]\r\n",
293                                 cnt, data);
294                 } else
295                         printf("[ KRB4_ENCPWD refuses authentication ]\r\n");
296                 auth_send_retry();
297                 return;
298         case KRB4_ENCPWD_ACCEPT:
299                 printf("[ KRB4_ENCPWD accepts you ]\n");
300                 auth_finished(ap, AUTH_USER);
301                 return;
302         case KRB4_ENCPWD_CHALLENGE:
303                 /*
304                  * Verify that the response to the challenge is correct.
305                  */
306
307                 gethostname(hostname, sizeof(hostname));
308                 realm = krb_realmofhost(hostname);
309                 memmove((void *)challenge, (void *)data, cnt);
310                 memset(user_passwd, 0, sizeof(user_passwd));
311                 local_des_read_pw_string(user_passwd, sizeof(user_passwd)-1, "Password: ", 0);
312                 UserPassword = user_passwd;
313                 Challenge = challenge;
314                 strcpy(instance, RemoteHostName);
315                 if ((cp = strchr(instance, '.')) != 0)  *cp = '\0';
316
317                 if (r = krb_mk_encpwd_req(&krb_token, KRB_SERVICE_NAME, instance, realm, Challenge, UserNameRequested, user_passwd)) {
318                   krb_token.length = 0;
319                 }
320
321                 if (!Data(ap, KRB4_ENCPWD_AUTH, (void *)krb_token.dat, krb_token.length)) {
322                   return;
323                 }
324
325                 break;
326
327         default:
328                 return;
329         }
330 }
331
332         int
333 krb4encpwd_status(ap, name, level)
334         Authenticator *ap;
335         char *name;
336         int level;
337 {
338
339         if (level < AUTH_USER)
340                 return(level);
341
342         if (UserNameRequested && passwdok(UserNameRequested, UserPassword)) {
343                 strcpy(name, UserNameRequested);
344                 return(AUTH_VALID);
345         } else {
346                 return(AUTH_USER);
347         }
348 }
349
350 #define BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
351 #define ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
352
353         void
354 krb4encpwd_printsub(data, cnt, buf, buflen)
355         unsigned char *data, *buf;
356         int cnt, buflen;
357 {
358         char lbuf[32];
359         register int i;
360
361         buf[buflen-1] = '\0';           /* make sure its NULL terminated */
362         buflen -= 1;
363
364         switch(data[3]) {
365         case KRB4_ENCPWD_REJECT:        /* Rejected (reason might follow) */
366                 strncpy((char *)buf, " REJECT ", buflen);
367                 goto common;
368
369         case KRB4_ENCPWD_ACCEPT:        /* Accepted (name might follow) */
370                 strncpy((char *)buf, " ACCEPT ", buflen);
371         common:
372                 BUMP(buf, buflen);
373                 if (cnt <= 4)
374                         break;
375                 ADDC(buf, buflen, '"');
376                 for (i = 4; i < cnt; i++)
377                         ADDC(buf, buflen, data[i]);
378                 ADDC(buf, buflen, '"');
379                 ADDC(buf, buflen, '\0');
380                 break;
381
382         case KRB4_ENCPWD_AUTH:          /* Authentication data follows */
383                 strncpy((char *)buf, " AUTH", buflen);
384                 goto common2;
385
386         case KRB4_ENCPWD_CHALLENGE:
387                 strncpy((char *)buf, " CHALLENGE", buflen);
388                 goto common2;
389
390         case KRB4_ENCPWD_ACK:
391                 strncpy((char *)buf, " ACK", buflen);
392                 goto common2;
393
394         default:
395                 sprintf(lbuf, " %d (unknown)", data[3]);
396                 strncpy((char *)buf, lbuf, buflen);
397         common2:
398                 BUMP(buf, buflen);
399                 for (i = 4; i < cnt; i++) {
400                         sprintf(lbuf, " %d", data[i]);
401                         strncpy((char *)buf, lbuf, buflen);
402                         BUMP(buf, buflen);
403                 }
404                 break;
405         }
406 }
407
408 int passwdok(name, passwd)
409 char *name, *passwd;
410 {
411   char *crypt();
412   char *salt, *p;
413   struct passwd *pwd;
414   int   passwdok_status = 0;
415
416   if (pwd = getpwnam(name))
417     salt = pwd->pw_passwd;
418   else salt = "xx";
419
420   p = crypt(passwd, salt);
421
422   if (pwd && !strcmp(p, pwd->pw_passwd)) {
423     passwdok_status = 1;
424   } else passwdok_status = 0;
425   return(passwdok_status);
426 }
427
428 #endif