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/contrib/telnet/libtelnet/krb4encpwd.c,v 1.7 2001/11/30 22:28:07 markm Exp $");
37
38#ifndef lint
39static 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
90int krb_mk_encpwd_req(KTEXT, char *, char *, char *, char *, char *, char *);
91int krb_rd_encpwd_req(KTEXT, char *, char *, u_long, AUTH_DAT *, char *, char *, char *, char *);
92
93extern auth_debug_mode;
94
95static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
96			  		AUTHTYPE_KRB4_ENCPWD, };
97static 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
108static	KTEXT_ST auth;
109static	char name[ANAME_SZ];
110static	char user_passwd[ANAME_SZ];
111static	AUTH_DAT adat = { 0 };
112#ifdef	ENCRYPTION
113static Block	session_key	= { 0 };
114#endif	/* ENCRYPTION */
115static char  challenge[REALM_SZ];
116
117	static int
118Data(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
153krb4encpwd_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
177krb4encpwd_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
197krb4encpwd_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
274krb4encpwd_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
333krb4encpwd_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
354krb4encpwd_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
408int passwdok(name, passwd)
409char *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
429