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