]> git.cameronkatri.com Git - apple_cmds.git/commitdiff
libtelnet-13
authorCameron Katri <me@cameronkatri.com>
Mon, 10 May 2021 18:55:53 +0000 (14:55 -0400)
committerCameron Katri <me@cameronkatri.com>
Mon, 10 May 2021 18:55:53 +0000 (14:55 -0400)
25 files changed:
lib/libtelnet/LICENSE [new file with mode: 0644]
lib/libtelnet/auth-proto.h [new file with mode: 0644]
lib/libtelnet/auth.c [new file with mode: 0644]
lib/libtelnet/auth.h [new file with mode: 0644]
lib/libtelnet/enc-proto.h [new file with mode: 0644]
lib/libtelnet/enc_des.c [new file with mode: 0644]
lib/libtelnet/encrypt.c [new file with mode: 0644]
lib/libtelnet/encrypt.h [new file with mode: 0644]
lib/libtelnet/forward.c [new file with mode: 0644]
lib/libtelnet/genget.c [new file with mode: 0644]
lib/libtelnet/getent.c [new file with mode: 0644]
lib/libtelnet/kerberos.c [new file with mode: 0644]
lib/libtelnet/kerberos5.c [new file with mode: 0644]
lib/libtelnet/key-proto.h [new file with mode: 0644]
lib/libtelnet/krb4encpwd.c [new file with mode: 0644]
lib/libtelnet/libtelnet.plist [new file with mode: 0644]
lib/libtelnet/libtelnet.xcodeproj/project.pbxproj [new file with mode: 0644]
lib/libtelnet/misc-proto.h [new file with mode: 0644]
lib/libtelnet/misc.c [new file with mode: 0644]
lib/libtelnet/misc.h [new file with mode: 0644]
lib/libtelnet/pk.c [new file with mode: 0644]
lib/libtelnet/pk.h [new file with mode: 0644]
lib/libtelnet/read_password.c [new file with mode: 0644]
lib/libtelnet/rsaencpwd.c [new file with mode: 0644]
lib/libtelnet/sra.c [new file with mode: 0644]

diff --git a/lib/libtelnet/LICENSE b/lib/libtelnet/LICENSE
new file mode 100644 (file)
index 0000000..f35662f
--- /dev/null
@@ -0,0 +1,79 @@
+Copyright (c) 1991, 1992, 1993
+The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+This product includes software developed by the University of
+California, Berkeley and its contributors.
+4. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+=====
+
+Copyright (C) 1990 by the Massachusetts Institute of Technology
+
+Export of this software from the United States of America is assumed
+to require a specific license from the United States Government.
+It is the responsibility of any person or organization contemplating
+export to obtain such a license before exporting.
+
+WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+distribute this software and its documentation for any purpose and
+without fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation, and that
+the name of M.I.T. not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.  M.I.T. makes no representations about the suitability of
+this software for any purpose.  It is provided "as is" without express
+or implied warranty.
+
+=====
+
+Copyright (c) 1991, 1993
+     Dave Safford.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/lib/libtelnet/auth-proto.h b/lib/libtelnet/auth-proto.h
new file mode 100644 (file)
index 0000000..6f0346a
--- /dev/null
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)auth-proto.h        8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/crypto/telnet/libtelnet/auth-proto.h,v 1.3.2.2 2002/04/13 10:59:07 markm Exp $
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifdef AUTHENTICATION
+
+Authenticator *findauthenticator(int, int);
+
+void auth_init(const char *, int);
+int auth_cmd(int, char **);
+void auth_request(void);
+void auth_send(unsigned char *, int);
+void auth_send_retry(void);
+void auth_is(unsigned char *, int);
+void auth_reply(unsigned char *, int);
+void auth_finished(Authenticator *, int);
+int auth_wait(char *);
+void auth_disable_name(char *);
+void auth_gen_printsub(unsigned char *, int, unsigned char *, int);
+void auth_name(unsigned char *, int);
+void auth_printsub(unsigned char *, int, unsigned char *, int);
+int auth_sendname(unsigned char *, int);
+void auth_encrypt_user(char *);
+int auth_disable(char *);
+int auth_enable(char *);
+int auth_togdebug(int);
+int auth_status(void);
+
+int getauthmask(char *, int *);
+
+#ifdef KRB4
+int kerberos4_init(Authenticator *, int);
+int kerberos4_send(Authenticator *);
+void kerberos4_is(Authenticator *, unsigned char *, int);
+void kerberos4_reply(Authenticator *, unsigned char *, int);
+int kerberos4_status(Authenticator *, char *, int);
+void kerberos4_printsub(unsigned char *, int, unsigned char *, int);
+#endif
+
+#ifdef KRB5
+int kerberos5_init(Authenticator *, int);
+int kerberos5_send(Authenticator *);
+void kerberos5_is(Authenticator *, unsigned char *, int);
+void kerberos5_reply(Authenticator *, unsigned char *, int);
+int kerberos5_status(Authenticator *, char *, int level);
+void kerberos5_printsub(unsigned char *, int, unsigned char *, int);
+#endif
+
+#ifdef SRA
+int sra_init(Authenticator *, int);
+int sra_send(Authenticator *);
+void sra_is(Authenticator *, unsigned char *, int);
+void sra_reply(Authenticator *, unsigned char *, int);
+int sra_status(Authenticator *, char *, int);
+void sra_printsub(unsigned char *, int, unsigned char *, int);
+#endif
+
+#endif
diff --git a/lib/libtelnet/auth.c b/lib/libtelnet/auth.c
new file mode 100644 (file)
index 0000000..f10e6ec
--- /dev/null
@@ -0,0 +1,631 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/crypto/telnet/libtelnet/auth.c,v 1.3.2.5 2002/04/13 10:59:07 markm Exp $
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/auth.c,v 1.3.2.5 2002/04/13 10:59:07 markm Exp $");
+#endif
+
+#ifndef __unused
+#define __unused        __attribute__((__unused__))
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)auth.c       8.3 (Berkeley) 5/30/95";
+#endif /* not lint */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+
+#ifdef AUTHENTICATION
+#define        AUTH_NAMES
+#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/telnet.h>
+
+#include "encrypt.h"
+#include "auth.h"
+#include "misc-proto.h"
+#include "auth-proto.h"
+
+#define        typemask(x)     ((x) > 0 ? 1 << ((x)-1) : 0)
+
+#ifdef KRB4_ENCPWD
+extern int krb4encpwd_init();
+extern int krb4encpwd_send();
+extern int krb4encpwd_is();
+extern int krb4encpwd_reply();
+extern int krb4encpwd_status();
+extern int krb4encpwd_printsub();
+#endif
+
+#ifdef RSA_ENCPWD
+extern rsaencpwd_init();
+extern rsaencpwd_send();
+extern rsaencpwd_is();
+extern rsaencpwd_reply();
+extern rsaencpwd_status();
+extern rsaencpwd_printsub();
+#endif
+
+int auth_debug_mode = 0;
+static         const char      *Name = "Noname";
+static int     Server = 0;
+static Authenticator   *authenticated = 0;
+static int     authenticating = 0;
+static int     validuser = 0;
+static unsigned char   _auth_send_data[256];
+static unsigned char   *auth_send_data;
+static int     auth_send_cnt = 0;
+
+int auth_onoff(char *type, int on);
+void auth_encrypt_user(char *name);
+
+/*
+ * Authentication types supported.  Plese note that these are stored
+ * in priority order, i.e. try the first one first.
+ */
+Authenticator authenticators[] = {
+#ifdef KRB5
+# ifdef        ENCRYPTION
+       { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
+                               kerberos5_init,
+                               kerberos5_send,
+                               kerberos5_is,
+                               kerberos5_reply,
+                               kerberos5_status,
+                               kerberos5_printsub },
+# endif        /* ENCRYPTION */
+       { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
+                               kerberos5_init,
+                               kerberos5_send,
+                               kerberos5_is,
+                               kerberos5_reply,
+                               kerberos5_status,
+                               kerberos5_printsub },
+#endif
+#ifdef KRB4
+# ifdef ENCRYPTION
+       { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
+                               kerberos4_init,
+                               kerberos4_send,
+                               kerberos4_is,
+                               kerberos4_reply,
+                               kerberos4_status,
+                               kerberos4_printsub },
+# endif        /* ENCRYPTION */
+       { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
+                               kerberos4_init,
+                               kerberos4_send,
+                               kerberos4_is,
+                               kerberos4_reply,
+                               kerberos4_status,
+                               kerberos4_printsub },
+#endif
+#ifdef KRB4_ENCPWD
+       { AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
+                               krb4encpwd_init,
+                               krb4encpwd_send,
+                               krb4encpwd_is,
+                               krb4encpwd_reply,
+                               krb4encpwd_status,
+                               krb4encpwd_printsub },
+#endif
+#ifdef RSA_ENCPWD
+       { AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
+                               rsaencpwd_init,
+                               rsaencpwd_send,
+                               rsaencpwd_is,
+                               rsaencpwd_reply,
+                               rsaencpwd_status,
+                               rsaencpwd_printsub },
+#endif
+#ifdef SRA
+       { AUTHTYPE_SRA, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
+                               sra_init,
+                               sra_send,
+                               sra_is,
+                               sra_reply,
+                               sra_status,
+                               sra_printsub },
+
+#endif
+       { 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static Authenticator NoAuth = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static int     i_support = 0;
+static int     i_wont_support = 0;
+
+Authenticator *
+findauthenticator(int type, int way)
+{
+       Authenticator *ap = authenticators;
+
+       while (ap->type && (ap->type != type || ap->way != way))
+               ++ap;
+       return(ap->type ? ap : 0);
+}
+
+void
+auth_init(const char *name, int server)
+{
+       Authenticator *ap = authenticators;
+
+       Server = server;
+       Name = name;
+
+       i_support = 0;
+       authenticated = 0;
+       authenticating = 0;
+       while (ap->type) {
+               if (!ap->init || (*ap->init)(ap, server)) {
+                       i_support |= typemask(ap->type);
+                       if (auth_debug_mode)
+                               printf(">>>%s: I support auth type %d %d\r\n",
+                                       Name,
+                                       ap->type, ap->way);
+               }
+               else if (auth_debug_mode)
+                       printf(">>>%s: Init failed: auth type %d %d\r\n",
+                               Name, ap->type, ap->way);
+               ++ap;
+       }
+}
+
+void
+auth_disable_name(char *name)
+{
+       int x;
+       for (x = 0; x < AUTHTYPE_CNT; ++x) {
+               if (AUTHTYPE_NAME(x) && !strcasecmp(name, AUTHTYPE_NAME(x))) {
+                       i_wont_support |= typemask(x);
+                       break;
+               }
+       }
+}
+
+int
+getauthmask(char *type, int *maskp)
+{
+       int x;
+
+       if (AUTHTYPE_NAME(0) && !strcasecmp(type, AUTHTYPE_NAME(0))) {
+               *maskp = -1;
+               return(1);
+       }
+
+       for (x = 1; x < AUTHTYPE_CNT; ++x) {
+               if (AUTHTYPE_NAME(x) && !strcasecmp(type, AUTHTYPE_NAME(x))) {
+                       *maskp = typemask(x);
+                       return(1);
+               }
+       }
+       return(0);
+}
+
+int
+auth_enable(char *type)
+{
+       return(auth_onoff(type, 1));
+}
+
+int
+auth_disable(char *type)
+{
+       return(auth_onoff(type, 0));
+}
+
+int
+auth_onoff(char *type, int on)
+{
+       int i, mask = -1;
+       Authenticator *ap;
+
+       if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {
+               printf("auth %s 'type'\n", on ? "enable" : "disable");
+               printf("Where 'type' is one of:\n");
+               printf("\t%s\n", AUTHTYPE_NAME(0));
+               mask = 0;
+               for (ap = authenticators; ap->type; ap++) {
+                       if ((mask & (i = typemask(ap->type))) != 0)
+                               continue;
+                       mask |= i;
+                       printf("\t%s\n", AUTHTYPE_NAME(ap->type));
+               }
+               return(0);
+       }
+
+       if (!getauthmask(type, &mask)) {
+               printf("%s: invalid authentication type\n", type);
+               return(0);
+       }
+       if (on)
+               i_wont_support &= ~mask;
+       else
+               i_wont_support |= mask;
+       return(1);
+}
+
+int
+auth_togdebug(int on)
+{
+       if (on < 0)
+               auth_debug_mode ^= 1;
+       else
+               auth_debug_mode = on;
+       printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");
+       return(1);
+}
+
+int
+auth_status(void)
+{
+       Authenticator *ap;
+       int i, mask;
+
+       if (i_wont_support == -1)
+               printf("Authentication disabled\n");
+       else
+               printf("Authentication enabled\n");
+
+       mask = 0;
+       for (ap = authenticators; ap->type; ap++) {
+               if ((mask & (i = typemask(ap->type))) != 0)
+                       continue;
+               mask |= i;
+               printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
+                       (i_wont_support & typemask(ap->type)) ?
+                                       "disabled" : "enabled");
+       }
+       return(1);
+}
+
+/*
+ * This routine is called by the server to start authentication
+ * negotiation.
+ */
+void
+auth_request(void)
+{
+       static unsigned char str_request[64] = { IAC, SB,
+                                                TELOPT_AUTHENTICATION,
+                                                TELQUAL_SEND, };
+       Authenticator *ap = authenticators;
+       unsigned char *e = str_request + 4;
+
+       if (!authenticating) {
+               authenticating = 1;
+               while (ap->type) {
+                       if (i_support & ~i_wont_support & typemask(ap->type)) {
+                               if (auth_debug_mode) {
+                                       printf(">>>%s: Sending type %d %d\r\n",
+                                               Name, ap->type, ap->way);
+                               }
+                               *e++ = ap->type;
+                               *e++ = ap->way;
+                       }
+                       ++ap;
+               }
+               *e++ = IAC;
+               *e++ = SE;
+               net_write(str_request, e - str_request);
+               printsub('>', &str_request[2], e - str_request - 2);
+       }
+}
+
+/*
+ * This is called when an AUTH SEND is received.
+ * It should never arrive on the server side (as only the server can
+ * send an AUTH SEND).
+ * You should probably respond to it if you can...
+ *
+ * If you want to respond to the types out of order (i.e. even
+ * if he sends  LOGIN KERBEROS and you support both, you respond
+ * with KERBEROS instead of LOGIN (which is against what the
+ * protocol says)) you will have to hack this code...
+ */
+void
+auth_send(unsigned char *data, int cnt)
+{
+       Authenticator *ap;
+       static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
+                                           TELQUAL_IS, AUTHTYPE_NULL, 0,
+                                           IAC, SE };
+       if (Server) {
+               if (auth_debug_mode) {
+                       printf(">>>%s: auth_send called!\r\n", Name);
+               }
+               return;
+       }
+
+       if (auth_debug_mode) {
+               printf(">>>%s: auth_send got:", Name);
+               printd(data, cnt); printf("\r\n");
+       }
+
+       /*
+        * Save the data, if it is new, so that we can continue looking
+        * at it if the authorization we try doesn't work
+        */
+       if (data < _auth_send_data ||
+           data > _auth_send_data + sizeof(_auth_send_data)) {
+               auth_send_cnt = (size_t)cnt > sizeof(_auth_send_data)
+                                       ? sizeof(_auth_send_data)
+                                       : cnt;
+               memmove((void *)_auth_send_data, (void *)data, auth_send_cnt);
+               auth_send_data = _auth_send_data;
+       } else {
+               /*
+                * This is probably a no-op, but we just make sure
+                */
+               auth_send_data = data;
+               auth_send_cnt = cnt;
+       }
+       while ((auth_send_cnt -= 2) >= 0) {
+               if (auth_debug_mode)
+                       printf(">>>%s: He supports %d\r\n",
+                               Name, *auth_send_data);
+               if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) {
+                       ap = findauthenticator(auth_send_data[0],
+                                              auth_send_data[1]);
+                       if (ap && ap->send) {
+                               if (auth_debug_mode)
+                                       printf(">>>%s: Trying %d %d\r\n",
+                                               Name, auth_send_data[0],
+                                                       auth_send_data[1]);
+                               if ((*ap->send)(ap)) {
+                                       /*
+                                        * Okay, we found one we like
+                                        * and did it.
+                                        * we can go home now.
+                                        */
+                                       if (auth_debug_mode)
+                                               printf(">>>%s: Using type %d\r\n",
+                                                       Name, *auth_send_data);
+                                       auth_send_data += 2;
+                                       return;
+                               }
+                       }
+                       /* else
+                        *      just continue on and look for the
+                        *      next one if we didn't do anything.
+                        */
+               }
+               auth_send_data += 2;
+       }
+       net_write(str_none, sizeof(str_none));
+       printsub('>', &str_none[2], sizeof(str_none) - 2);
+       if (auth_debug_mode)
+               printf(">>>%s: Sent failure message\r\n", Name);
+       auth_finished(0, AUTH_REJECT);
+}
+
+void
+auth_send_retry(void)
+{
+       /*
+        * if auth_send_cnt <= 0 then auth_send will end up rejecting
+        * the authentication and informing the other side of this.
+        */
+       auth_send(auth_send_data, auth_send_cnt);
+}
+
+void
+auth_is(unsigned char *data, int cnt)
+{
+       Authenticator *ap;
+
+       if (cnt < 2)
+               return;
+
+       if (data[0] == AUTHTYPE_NULL) {
+               auth_finished(0, AUTH_REJECT);
+               return;
+       }
+
+       if ((ap = findauthenticator(data[0], data[1]))) {
+               if (ap->is)
+                       (*ap->is)(ap, data+2, cnt-2);
+       } else if (auth_debug_mode)
+               printf(">>>%s: Invalid authentication in IS: %d\r\n",
+                       Name, *data);
+}
+
+void
+auth_reply(unsigned char *data, int cnt)
+{
+       Authenticator *ap;
+
+       if (cnt < 2)
+               return;
+
+       if ((ap = findauthenticator(data[0], data[1]))) {
+               if (ap->reply)
+                       (*ap->reply)(ap, data+2, cnt-2);
+       } else if (auth_debug_mode)
+               printf(">>>%s: Invalid authentication in SEND: %d\r\n",
+                       Name, *data);
+}
+
+void
+auth_name(unsigned char *data, int cnt)
+{
+       unsigned char savename[256];
+
+       if (cnt < 1) {
+               if (auth_debug_mode)
+                       printf(">>>%s: Empty name in NAME\r\n", Name);
+               return;
+       }
+       if ((size_t)cnt > sizeof(savename) - 1) {
+               if (auth_debug_mode)
+                       printf(">>>%s: Name in NAME (%d) exceeds %d length\r\n",
+                                       Name, cnt, (u_int)sizeof(savename)-1);
+               return;
+       }
+       memmove((void *)savename, (void *)data, cnt);
+       savename[cnt] = '\0';   /* Null terminate */
+       if (auth_debug_mode)
+               printf(">>>%s: Got NAME [%s]\r\n", Name, savename);
+#ifdef ENCRYPTION
+       auth_encrypt_user(savename);
+#endif
+}
+
+int
+auth_sendname(unsigned char *cp, int len)
+{
+       static unsigned char str_request[256+6]
+                       = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };
+       unsigned char *e = str_request + 4;
+       unsigned char *ee = &str_request[sizeof(str_request)-2];
+
+       while (--len >= 0) {
+               if ((*e++ = *cp++) == IAC)
+                       *e++ = IAC;
+               if (e >= ee)
+                       return(0);
+       }
+       *e++ = IAC;
+       *e++ = SE;
+       net_write(str_request, e - str_request);
+       printsub('>', &str_request[2], e - &str_request[2]);
+       return(1);
+}
+
+void
+auth_finished(Authenticator *ap, int result)
+{
+       if (!(authenticated = ap))
+               authenticated = &NoAuth;
+       validuser = result;
+}
+
+/* ARGSUSED */
+static void
+auth_intr(int sig __unused)
+{
+       auth_finished(0, AUTH_REJECT);
+}
+
+int
+auth_wait(char *name)
+{
+       if (auth_debug_mode)
+               printf(">>>%s: in auth_wait.\r\n", Name);
+
+       if (Server && !authenticating)
+               return(0);
+
+       (void) signal(SIGALRM, auth_intr);
+       alarm(30);
+       while (!authenticated)
+               if (telnet_spin())
+                       break;
+       alarm(0);
+       (void) signal(SIGALRM, SIG_DFL);
+
+       /*
+        * Now check to see if the user is valid or not
+        */
+       if (!authenticated || authenticated == &NoAuth)
+               return(AUTH_REJECT);
+
+       if (validuser == AUTH_VALID)
+               validuser = AUTH_USER;
+
+       if (authenticated->status)
+               validuser = (*authenticated->status)(authenticated,
+                                                    name, validuser);
+       return(validuser);
+}
+
+void
+auth_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
+{
+       Authenticator *ap;
+
+       if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
+               (*ap->printsub)(data, cnt, buf, buflen);
+       else
+               auth_gen_printsub(data, cnt, buf, buflen);
+}
+
+void
+auth_gen_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
+{
+       unsigned char *cp;
+       unsigned char tbuf[16];
+
+       cnt -= 3;
+       data += 3;
+       buf[buflen-1] = '\0';
+       buf[buflen-2] = '*';
+       buflen -= 2;
+       for (; cnt > 0; cnt--, data++) {
+               sprintf((char *)tbuf, " %d", *data);
+               for (cp = tbuf; *cp && buflen > 0; --buflen)
+                       *buf++ = *cp++;
+               if (buflen <= 0)
+                       return;
+       }
+       *buf = '\0';
+}
+#endif
diff --git a/lib/libtelnet/auth.h b/lib/libtelnet/auth.h
new file mode 100644 (file)
index 0000000..557b037
--- /dev/null
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)auth.h      8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/crypto/telnet/libtelnet/auth.h,v 1.1.1.1.8.1 2002/04/13 10:59:07 markm Exp $
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef        __AUTH__
+#define        __AUTH__
+
+#define        AUTH_REJECT     0       /* Rejected */
+#define        AUTH_UNKNOWN    1       /* We don't know who he is, but he's okay */
+#define        AUTH_OTHER      2       /* We know him, but not his name */
+#define        AUTH_USER       3       /* We know he name */
+#define        AUTH_VALID      4       /* We know him, and he needs no password */
+
+typedef struct XauthP {
+       int     type;
+       int     way;
+       int     (*init)(struct XauthP *, int);
+       int     (*send)(struct XauthP *);
+       void    (*is)(struct XauthP *, unsigned char *, int);
+       void    (*reply)(struct XauthP *, unsigned char *, int);
+       int     (*status)(struct XauthP *, char *, int);
+       void    (*printsub)(unsigned char *, int, unsigned char *, int);
+} Authenticator;
+
+#include "auth-proto.h"
+
+#define OPTS_FORWARD_CREDS           0x00000002
+#define OPTS_FORWARDABLE_CREDS       0x00000001
+
+extern int auth_debug_mode;
+#endif
diff --git a/lib/libtelnet/enc-proto.h b/lib/libtelnet/enc-proto.h
new file mode 100644 (file)
index 0000000..3c9ef88
--- /dev/null
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)enc-proto.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/crypto/telnet/libtelnet/enc-proto.h,v 1.3.2.2 2002/04/13 10:59:07 markm Exp $
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifdef ENCRYPTION
+void encrypt_init(const char *, int);
+Encryptions *findencryption(int);
+void encrypt_send_supprt(void);
+void encrypt_auto(int);
+void decrypt_auto(int);
+void encrypt_is(unsigned char *, int);
+void encrypt_reply(unsigned char *, int);
+void encrypt_start_input(int);
+void encrypt_session_key(Session_Key *, int);
+void encrypt_end_input(void);
+void encrypt_start_output(int);
+void encrypt_end_output(void);
+void encrypt_send_request_start(void);
+void encrypt_send_request_end(void);
+void encrypt_send_end(void);
+void encrypt_wait(void);
+void encrypt_send_support(void);
+void encrypt_send_keyid(int, const char *, int, int);
+void encrypt_start(unsigned char *, int);
+void encrypt_end(void);
+void encrypt_support(unsigned char *, int);
+void encrypt_request_start(unsigned char *, int);
+void encrypt_request_end(void);
+void encrypt_enc_keyid(unsigned char *, int);
+void encrypt_dec_keyid(unsigned char *, int);
+void encrypt_printsub(unsigned char *, int, unsigned char *, int);
+void encrypt_gen_printsub(unsigned char *, int, unsigned char *, int);
+void encrypt_display(void);
+
+void fb64_printsub(unsigned char *, int, unsigned char *, int, const char *);
+
+int EncryptEnable(char *, char *);
+int EncryptDisable(char *, char *);
+int EncryptStatus(void);
+int EncryptDebug(int);
+int EncryptVerbose(int);
+int EncryptAutoEnc(int);
+int EncryptAutoDec(int);
+
+void krbdes_encrypt(unsigned char *, int);
+int krbdes_decrypt(int);
+int krbdes_is(unsigned char *, int);
+int krbdes_reply(unsigned char *, int);
+void krbdes_init(int);
+int krbdes_start(int, int);
+void krbdes_session(Session_Key *, int);
+void krbdes_printsub(unsigned char *, int, unsigned char *, int);
+
+void cfb64_encrypt(unsigned char *, int);
+int cfb64_decrypt(int);
+void cfb64_init(int);
+int cfb64_start(int, int);
+int cfb64_is(unsigned char *, int);
+int cfb64_reply(unsigned char *, int);
+void cfb64_session(Session_Key *, int);
+int cfb64_keyid(int, unsigned char *, int *);
+void cfb64_printsub(unsigned char *, int, unsigned char *, int);
+
+void ofb64_encrypt(unsigned char *, int);
+int ofb64_decrypt(int);
+void ofb64_init(int);
+int ofb64_start(int, int);
+int ofb64_is(unsigned char *, int);
+int ofb64_reply(unsigned char *, int);
+void ofb64_session(Session_Key *, int);
+int ofb64_keyid(int, unsigned char *, int *);
+void ofb64_printsub(unsigned char *, int, unsigned char *, int);
+
+#endif /* ENCRYPTION */
diff --git a/lib/libtelnet/enc_des.c b/lib/libtelnet/enc_des.c
new file mode 100644 (file)
index 0000000..c6d6ea6
--- /dev/null
@@ -0,0 +1,675 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * $FreeBSD: src/crypto/telnet/libtelnet/enc_des.c,v 1.3.2.1 2002/04/13 10:59:07 markm Exp $
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/enc_des.c,v 1.3.2.1 2002/04/13 10:59:07 markm Exp $");
+#endif
+
+#ifndef __unused
+#define __unused        __attribute__((__unused__))
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)enc_des.c    8.3 (Berkeley) 5/30/95";
+#endif /* not lint */
+
+#ifdef ENCRYPTION
+# ifdef        AUTHENTICATION
+#include <arpa/telnet.h>
+#include <des.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "encrypt.h"
+#include "key-proto.h"
+#include "misc-proto.h"
+
+extern int encrypt_debug_mode;
+
+#define        CFB     0
+#define        OFB     1
+
+#define        NO_SEND_IV      1
+#define        NO_RECV_IV      2
+#define        NO_KEYID        4
+#define        IN_PROGRESS     (NO_SEND_IV|NO_RECV_IV|NO_KEYID)
+#define        SUCCESS         0
+#define        FAILED          -1
+
+
+struct fb {
+       Block krbdes_key;
+       Schedule krbdes_sched;
+       Block temp_feed;
+       unsigned char fb_feed[64];
+       int need_start;
+       int state[2];
+       int keyid[2];
+       int once;
+       struct stinfo {
+               Block           str_output;
+               Block           str_feed;
+               Block           str_iv;
+               Block           str_ikey;
+               Schedule        str_sched;
+               int             str_index;
+               int             str_flagshift;
+       } streams[2];
+};
+
+static struct fb fb[2];
+
+struct keyidlist {
+       const char *keyid;
+       int     keyidlen;
+       char    *key;
+       int     keylen;
+       int     flags;
+} keyidlist [] = {
+       { "\0", 1, 0, 0, 0 },           /* default key of zero */
+       { 0, 0, 0, 0, 0 }
+};
+
+#define        KEYFLAG_MASK    03
+
+#define        KEYFLAG_NOINIT  00
+#define        KEYFLAG_INIT    01
+#define        KEYFLAG_OK      02
+#define        KEYFLAG_BAD     03
+
+#define        KEYFLAG_SHIFT   2
+
+#define        SHIFT_VAL(a,b)  (KEYFLAG_SHIFT*((a)+((b)*2)))
+
+#define        FB64_IV         1
+#define        FB64_IV_OK      2
+#define        FB64_IV_BAD     3
+
+
+void fb64_stream_iv(Block, struct stinfo *);
+void fb64_init(struct fb *);
+static int fb64_start(struct fb *, int, int);
+int fb64_is(unsigned char *, int, struct fb *);
+int fb64_reply(unsigned char *, int, struct fb *);
+static void fb64_session(Session_Key *, int, struct fb *);
+void fb64_stream_key(Block, struct stinfo *);
+int fb64_keyid(int, unsigned char *, int *, struct fb *);
+
+void
+cfb64_init(int server __unused)
+{
+       fb64_init(&fb[CFB]);
+       fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
+       fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
+       fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
+}
+
+void
+ofb64_init(int server __unused)
+{
+       fb64_init(&fb[OFB]);
+       fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
+       fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
+       fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
+}
+
+void
+fb64_init(struct fb *fbp)
+{
+       memset((void *)fbp, 0, sizeof(*fbp));
+       fbp->state[0] = fbp->state[1] = FAILED;
+       fbp->fb_feed[0] = IAC;
+       fbp->fb_feed[1] = SB;
+       fbp->fb_feed[2] = TELOPT_ENCRYPT;
+       fbp->fb_feed[3] = ENCRYPT_IS;
+}
+
+/*
+ * Returns:
+ *     -1: some error.  Negotiation is done, encryption not ready.
+ *      0: Successful, initial negotiation all done.
+ *      1: successful, negotiation not done yet.
+ *      2: Not yet.  Other things (like getting the key from
+ *         Kerberos) have to happen before we can continue.
+ */
+int
+cfb64_start(int dir, int server)
+{
+       return(fb64_start(&fb[CFB], dir, server));
+}
+
+int
+ofb64_start(int dir, int server)
+{
+       return(fb64_start(&fb[OFB], dir, server));
+}
+
+static int
+fb64_start(struct fb *fbp, int dir, int server __unused)
+{
+       size_t x;
+       unsigned char *p;
+       int state;
+
+       switch (dir) {
+       case DIR_DECRYPT:
+               /*
+                * This is simply a request to have the other side
+                * start output (our input).  He will negotiate an
+                * IV so we need not look for it.
+                */
+               state = fbp->state[dir-1];
+               if (state == FAILED)
+                       state = IN_PROGRESS;
+               break;
+
+       case DIR_ENCRYPT:
+               state = fbp->state[dir-1];
+               if (state == FAILED)
+                       state = IN_PROGRESS;
+               else if ((state & NO_SEND_IV) == 0)
+                       break;
+
+               if (!VALIDKEY(fbp->krbdes_key)) {
+                       fbp->need_start = 1;
+                       break;
+               }
+               state &= ~NO_SEND_IV;
+               state |= NO_RECV_IV;
+               if (encrypt_debug_mode)
+                       printf("Creating new feed\r\n");
+               /*
+                * Create a random feed and send it over.
+                */
+               des_new_random_key(fbp->temp_feed);
+               des_ecb_encrypt((Block *)fbp->temp_feed, (Block *)fbp->temp_feed,
+                               fbp->krbdes_sched, 1);
+               p = fbp->fb_feed + 3;
+               *p++ = ENCRYPT_IS;
+               p++;
+               *p++ = FB64_IV;
+               for (x = 0; x < sizeof(Block); ++x) {
+                       if ((*p++ = fbp->temp_feed[x]) == IAC)
+                               *p++ = IAC;
+               }
+               *p++ = IAC;
+               *p++ = SE;
+               printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+               net_write(fbp->fb_feed, p - fbp->fb_feed);
+               break;
+       default:
+               return(FAILED);
+       }
+       return(fbp->state[dir-1] = state);
+}
+
+/*
+ * Returns:
+ *     -1: some error.  Negotiation is done, encryption not ready.
+ *      0: Successful, initial negotiation all done.
+ *      1: successful, negotiation not done yet.
+ */
+int
+cfb64_is(unsigned char *data, int cnt)
+{
+       return(fb64_is(data, cnt, &fb[CFB]));
+}
+
+int
+ofb64_is(unsigned char *data, int cnt)
+{
+       return(fb64_is(data, cnt, &fb[OFB]));
+}
+
+int
+fb64_is(unsigned char *data, int cnt, struct fb *fbp)
+{
+       unsigned char *p;
+       int state = fbp->state[DIR_DECRYPT-1];
+
+       if (cnt-- < 1)
+               goto failure;
+
+       switch (*data++) {
+       case FB64_IV:
+               if (cnt != sizeof(Block)) {
+                       if (encrypt_debug_mode)
+                               printf("CFB64: initial vector failed on size\r\n");
+                       state = FAILED;
+                       goto failure;
+               }
+
+               if (encrypt_debug_mode)
+                       printf("CFB64: initial vector received\r\n");
+
+               if (encrypt_debug_mode)
+                       printf("Initializing Decrypt stream\r\n");
+
+               fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
+
+               p = fbp->fb_feed + 3;
+               *p++ = ENCRYPT_REPLY;
+               p++;
+               *p++ = FB64_IV_OK;
+               *p++ = IAC;
+               *p++ = SE;
+               printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+               net_write(fbp->fb_feed, p - fbp->fb_feed);
+
+               state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
+               break;
+
+       default:
+               if (encrypt_debug_mode) {
+                       printf("Unknown option type: %d\r\n", *(data-1));
+                       printd(data, cnt);
+                       printf("\r\n");
+               }
+               /* FALL THROUGH */
+       failure:
+               /*
+                * We failed.  Send an FB64_IV_BAD option
+                * to the other side so it will know that
+                * things failed.
+                */
+               p = fbp->fb_feed + 3;
+               *p++ = ENCRYPT_REPLY;
+               p++;
+               *p++ = FB64_IV_BAD;
+               *p++ = IAC;
+               *p++ = SE;
+               printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+               net_write(fbp->fb_feed, p - fbp->fb_feed);
+
+               break;
+       }
+       return(fbp->state[DIR_DECRYPT-1] = state);
+}
+
+/*
+ * Returns:
+ *     -1: some error.  Negotiation is done, encryption not ready.
+ *      0: Successful, initial negotiation all done.
+ *      1: successful, negotiation not done yet.
+ */
+int
+cfb64_reply(unsigned char *data, int cnt)
+{
+       return(fb64_reply(data, cnt, &fb[CFB]));
+}
+
+int
+ofb64_reply(unsigned char *data, int cnt)
+{
+       return(fb64_reply(data, cnt, &fb[OFB]));
+}
+
+int
+fb64_reply(unsigned char *data, int cnt, struct fb *fbp)
+{
+       int state = fbp->state[DIR_ENCRYPT-1];
+
+       if (cnt-- < 1)
+               goto failure;
+
+       switch (*data++) {
+       case FB64_IV_OK:
+               fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+               if (state == FAILED)
+                       state = IN_PROGRESS;
+               state &= ~NO_RECV_IV;
+               encrypt_send_keyid(DIR_ENCRYPT, "\0", 1, 1);
+               break;
+
+       case FB64_IV_BAD:
+               memset(fbp->temp_feed, 0, sizeof(Block));
+               fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+               state = FAILED;
+               break;
+
+       default:
+               if (encrypt_debug_mode) {
+                       printf("Unknown option type: %d\r\n", data[-1]);
+                       printd(data, cnt);
+                       printf("\r\n");
+               }
+               /* FALL THROUGH */
+       failure:
+               state = FAILED;
+               break;
+       }
+       return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+void
+cfb64_session(Session_Key *key, int server)
+{
+       fb64_session(key, server, &fb[CFB]);
+}
+
+void
+ofb64_session(Session_Key *key, int server)
+{
+       fb64_session(key, server, &fb[OFB]);
+}
+
+static void
+fb64_session(Session_Key *key, int server, struct fb *fbp)
+{
+       if (!key || key->type != SK_DES) {
+               if (encrypt_debug_mode)
+                       printf("Can't set krbdes's session key (%d != %d)\r\n",
+                               key ? key->type : -1, SK_DES);
+               return;
+       }
+       memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
+
+       fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
+       fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
+
+       if (fbp->once == 0) {
+               des_set_random_generator_seed(fbp->krbdes_key);
+               fbp->once = 1;
+       }
+       des_key_sched(fbp->krbdes_key, fbp->krbdes_sched);
+       /*
+        * Now look to see if krbdes_start() was was waiting for
+        * the key to show up.  If so, go ahead an call it now
+        * that we have the key.
+        */
+       if (fbp->need_start) {
+               fbp->need_start = 0;
+               fb64_start(fbp, DIR_ENCRYPT, server);
+       }
+}
+
+/*
+ * We only accept a keyid of 0.  If we get a keyid of
+ * 0, then mark the state as SUCCESS.
+ */
+int
+cfb64_keyid(int dir, unsigned char *kp, int *lenp)
+{
+       return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
+}
+
+int
+ofb64_keyid(int dir, unsigned char *kp, int *lenp)
+{
+       return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
+}
+
+int
+fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp)
+{
+       int state = fbp->state[dir-1];
+
+       if (*lenp != 1 || (*kp != '\0')) {
+               *lenp = 0;
+               return(state);
+       }
+
+       if (state == FAILED)
+               state = IN_PROGRESS;
+
+       state &= ~NO_KEYID;
+
+       return(fbp->state[dir-1] = state);
+}
+
+void
+fb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen, const char *type)
+{
+       char lbuf[32];
+       int i;
+       char *cp;
+
+       buf[buflen-1] = '\0';           /* make sure it's NULL terminated */
+       buflen -= 1;
+
+       switch(data[2]) {
+       case FB64_IV:
+               sprintf(lbuf, "%s_IV", type);
+               cp = lbuf;
+               goto common;
+
+       case FB64_IV_OK:
+               sprintf(lbuf, "%s_IV_OK", type);
+               cp = lbuf;
+               goto common;
+
+       case FB64_IV_BAD:
+               sprintf(lbuf, "%s_IV_BAD", type);
+               cp = lbuf;
+               goto common;
+
+       default:
+               sprintf(lbuf, " %d (unknown)", data[2]);
+               cp = lbuf;
+       common:
+               for (; (buflen > 0) && (*buf = *cp++); buf++)
+                       buflen--;
+               for (i = 3; i < cnt; i++) {
+                       sprintf(lbuf, " %d", data[i]);
+                       for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
+                               buflen--;
+               }
+               break;
+       }
+}
+
+void
+cfb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
+{
+       fb64_printsub(data, cnt, buf, buflen, "CFB64");
+}
+
+void
+ofb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
+{
+       fb64_printsub(data, cnt, buf, buflen, "OFB64");
+}
+
+void
+fb64_stream_iv(Block seed, struct stinfo *stp)
+{
+
+       memmove((void *)stp->str_iv, (void *)seed, sizeof(Block));
+       memmove((void *)stp->str_output, (void *)seed, sizeof(Block));
+
+       des_key_sched(stp->str_ikey, stp->str_sched);
+
+       stp->str_index = sizeof(Block);
+}
+
+void
+fb64_stream_key(Block key, struct stinfo *stp)
+{
+       memmove((void *)stp->str_ikey, (void *)key, sizeof(Block));
+       des_key_sched(key, stp->str_sched);
+
+       memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
+
+       stp->str_index = sizeof(Block);
+}
+
+/*
+ * DES 64 bit Cipher Feedback
+ *
+ *     key --->+-----+
+ *          +->| DES |--+
+ *          |  +-----+  |
+ *         |           v
+ *  INPUT --(--------->(+)+---> DATA
+ *          |             |
+ *         +-------------+
+ *
+ *
+ * Given:
+ *     iV: Initial vector, 64 bits (8 bytes) long.
+ *     Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ *     On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ *     V0 = DES(iV, key)
+ *     On = Dn ^ Vn
+ *     V(n+1) = DES(On, key)
+ */
+
+void
+cfb64_encrypt(unsigned char *s, int c)
+{
+       struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
+       int idx;
+
+       idx = stp->str_index;
+       while (c-- > 0) {
+               if (idx == sizeof(Block)) {
+                       Block b;
+                       des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1);
+                       memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
+                       idx = 0;
+               }
+
+               /* On encryption, we store (feed ^ data) which is cypher */
+               *s = stp->str_output[idx] = (stp->str_feed[idx] ^ *s);
+               s++;
+               idx++;
+       }
+       stp->str_index = idx;
+}
+
+int
+cfb64_decrypt(int data)
+{
+       struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
+       int idx;
+
+       if (data == -1) {
+               /*
+                * Back up one byte.  It is assumed that we will
+                * never back up more than one byte.  If we do, this
+                * may or may not work.
+                */
+               if (stp->str_index)
+                       --stp->str_index;
+               return(0);
+       }
+
+       idx = stp->str_index++;
+       if (idx == sizeof(Block)) {
+               Block b;
+               des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1);
+               memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
+               stp->str_index = 1;     /* Next time will be 1 */
+               idx = 0;                /* But now use 0 */
+       }
+
+       /* On decryption we store (data) which is cypher. */
+       stp->str_output[idx] = data;
+       return(data ^ stp->str_feed[idx]);
+}
+
+/*
+ * DES 64 bit Output Feedback
+ *
+ * key --->+-----+
+ *     +->| DES |--+
+ *     |  +-----+  |
+ *     +-----------+
+ *                 v
+ *  INPUT -------->(+) ----> DATA
+ *
+ * Given:
+ *     iV: Initial vector, 64 bits (8 bytes) long.
+ *     Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ *     On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ *     V0 = DES(iV, key)
+ *     V(n+1) = DES(Vn, key)
+ *     On = Dn ^ Vn
+ */
+void
+ofb64_encrypt(unsigned char *s, int c)
+{
+       struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
+       int idx;
+
+       idx = stp->str_index;
+       while (c-- > 0) {
+               if (idx == sizeof(Block)) {
+                       Block b;
+                       des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1);
+                       memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
+                       idx = 0;
+               }
+               *s++ ^= stp->str_feed[idx];
+               idx++;
+       }
+       stp->str_index = idx;
+}
+
+int
+ofb64_decrypt(int data)
+{
+       struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
+       int idx;
+
+       if (data == -1) {
+               /*
+                * Back up one byte.  It is assumed that we will
+                * never back up more than one byte.  If we do, this
+                * may or may not work.
+                */
+               if (stp->str_index)
+                       --stp->str_index;
+               return(0);
+       }
+
+       idx = stp->str_index++;
+       if (idx == sizeof(Block)) {
+               Block b;
+               des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1);
+               memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
+               stp->str_index = 1;     /* Next time will be 1 */
+               idx = 0;                /* But now use 0 */
+       }
+
+       return(data ^ stp->str_feed[idx]);
+}
+# endif        /* AUTHENTICATION */
+#endif /* ENCRYPTION */
diff --git a/lib/libtelnet/encrypt.c b/lib/libtelnet/encrypt.c
new file mode 100644 (file)
index 0000000..4295fad
--- /dev/null
@@ -0,0 +1,961 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/encrypt.c,v 1.3.2.2 2002/04/13 10:59:07 markm Exp $");
+#endif
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)encrypt.c    8.2 (Berkeley) 5/30/95";
+#endif
+#endif /* not lint */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifdef ENCRYPTION
+
+#define        ENCRYPT_NAMES
+#include <arpa/telnet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "encrypt.h"
+#include "misc.h"
+
+#ifndef __unused
+#define __unused        __attribute__((__unused__))
+#endif
+
+/*
+ * These functions pointers point to the current routines
+ * for encrypting and decrypting data.
+ */
+void   (*encrypt_output)(unsigned char *, int);
+int    (*decrypt_input)(int);
+
+int EncryptType(char *type, char *mode);
+int EncryptStart(char *mode);
+int EncryptStop(char *mode);
+int EncryptStartInput(void);
+int EncryptStartOutput(void);
+int EncryptStopInput(void);
+int EncryptStopOutput(void);
+
+int encrypt_debug_mode = 0;
+static int decrypt_mode = 0;
+static int encrypt_mode = 0;
+static int encrypt_verbose = 0;
+static int autoencrypt = 0;
+static int autodecrypt = 0;
+static int havesessionkey = 0;
+static int Server = 0;
+static const char *Name = "Noname";
+
+#define        typemask(x)     ((x) > 0 ? 1 << ((x)-1) : 0)
+
+static long i_support_encrypt = 0
+ | typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64)
+ |0;
+static long i_support_decrypt = 0
+ | typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64)
+ |0;
+
+static long i_wont_support_encrypt = 0;
+static long i_wont_support_decrypt = 0;
+#define        I_SUPPORT_ENCRYPT       (i_support_encrypt & ~i_wont_support_encrypt)
+#define        I_SUPPORT_DECRYPT       (i_support_decrypt & ~i_wont_support_decrypt)
+
+static long remote_supports_encrypt = 0;
+static long remote_supports_decrypt = 0;
+
+static Encryptions encryptions[] = {
+    { "DES_CFB64",     ENCTYPE_DES_CFB64,
+                       cfb64_encrypt,
+                       cfb64_decrypt,
+                       cfb64_init,
+                       cfb64_start,
+                       cfb64_is,
+                       cfb64_reply,
+                       cfb64_session,
+                       cfb64_keyid,
+                       cfb64_printsub },
+    { "DES_OFB64",     ENCTYPE_DES_OFB64,
+                       ofb64_encrypt,
+                       ofb64_decrypt,
+                       ofb64_init,
+                       ofb64_start,
+                       ofb64_is,
+                       ofb64_reply,
+                       ofb64_session,
+                       ofb64_keyid,
+                       ofb64_printsub },
+    { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPT,
+                                        ENCRYPT_SUPPORT };
+static unsigned char str_suplen = 0;
+static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPT };
+static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPT, 0, IAC, SE };
+
+Encryptions *
+findencryption(int type)
+{
+       Encryptions *ep = encryptions;
+
+       if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & (unsigned)typemask(type)))
+               return(0);
+       while (ep->type && ep->type != type)
+               ++ep;
+       return(ep->type ? ep : 0);
+}
+
+static Encryptions *
+finddecryption(int type)
+{
+       Encryptions *ep = encryptions;
+
+       if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & (unsigned)typemask(type)))
+               return(0);
+       while (ep->type && ep->type != type)
+               ++ep;
+       return(ep->type ? ep : 0);
+}
+
+#define        MAXKEYLEN 64
+
+static struct key_info {
+       unsigned char keyid[MAXKEYLEN];
+       int keylen;
+       int dir;
+       int *modep;
+       Encryptions *(*getcrypt)(int);
+} ki[2] = {
+       { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption },
+       { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption },
+};
+
+static void encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len);
+
+void
+encrypt_init(const char *name, int server)
+{
+       Encryptions *ep = encryptions;
+
+       Name = name;
+       Server = server;
+       i_support_encrypt = i_support_decrypt = 0;
+       remote_supports_encrypt = remote_supports_decrypt = 0;
+       encrypt_mode = 0;
+       decrypt_mode = 0;
+       encrypt_output = 0;
+       decrypt_input = 0;
+
+       str_suplen = 4;
+
+       while (ep->type) {
+               if (encrypt_debug_mode)
+                       printf(">>>%s: I will support %s\r\n",
+                               Name, ENCTYPE_NAME(ep->type));
+               i_support_encrypt |= typemask(ep->type);
+               i_support_decrypt |= typemask(ep->type);
+               if ((i_wont_support_decrypt & typemask(ep->type)) == 0)
+                       if ((str_send[str_suplen++] = ep->type) == IAC)
+                               str_send[str_suplen++] = IAC;
+               if (ep->init)
+                       (*ep->init)(Server);
+               ++ep;
+       }
+       str_send[str_suplen++] = IAC;
+       str_send[str_suplen++] = SE;
+}
+
+static void
+encrypt_list_types(void)
+{
+       Encryptions *ep = encryptions;
+
+       printf("Valid encryption types:\n");
+       while (ep->type) {
+               printf("\t%s (%d)\r\n", ENCTYPE_NAME(ep->type), ep->type);
+               ++ep;
+       }
+}
+
+int
+EncryptEnable(char *type, char *mode)
+{
+       if (isprefix(type, "help") || isprefix(type, "?")) {
+               printf("Usage: encrypt enable <type> [input|output]\n");
+               encrypt_list_types();
+               return(0);
+       }
+       if (EncryptType(type, mode))
+               return(EncryptStart(mode));
+       return(0);
+}
+
+int
+EncryptDisable(char *type, char *mode)
+{
+       Encryptions *ep;
+       int ret = 0;
+
+       if (isprefix(type, "help") || isprefix(type, "?")) {
+               printf("Usage: encrypt disable <type> [input|output]\n");
+               encrypt_list_types();
+       } else if ((ep = (Encryptions *)genget(type, (char **)encryptions,
+                                               sizeof(Encryptions))) == 0) {
+               printf("%s: invalid encryption type\n", type);
+       } else if (Ambiguous((char **)ep)) {
+               printf("Ambiguous type '%s'\n", type);
+       } else {
+               if ((mode == 0) || (isprefix(mode, "input") ? 1 : 0)) {
+                       if (decrypt_mode == ep->type)
+                               EncryptStopInput();
+                       i_wont_support_decrypt |= typemask(ep->type);
+                       ret = 1;
+               }
+               if ((mode == 0) || (isprefix(mode, "output"))) {
+                       if (encrypt_mode == ep->type)
+                               EncryptStopOutput();
+                       i_wont_support_encrypt |= typemask(ep->type);
+                       ret = 1;
+               }
+               if (ret == 0)
+                       printf("%s: invalid encryption mode\n", mode);
+       }
+       return(ret);
+}
+
+int
+EncryptType(char *type, char *mode)
+{
+       Encryptions *ep;
+       int ret = 0;
+
+       if (isprefix(type, "help") || isprefix(type, "?")) {
+               printf("Usage: encrypt type <type> [input|output]\n");
+               encrypt_list_types();
+       } else if ((ep = (Encryptions *)genget(type, (char **)encryptions,
+                                               sizeof(Encryptions))) == 0) {
+               printf("%s: invalid encryption type\n", type);
+       } else if (Ambiguous((char **)ep)) {
+               printf("Ambiguous type '%s'\n", type);
+       } else {
+               if ((mode == 0) || isprefix(mode, "input")) {
+                       decrypt_mode = ep->type;
+                       i_wont_support_decrypt &= ~typemask(ep->type);
+                       ret = 1;
+               }
+               if ((mode == 0) || isprefix(mode, "output")) {
+                       encrypt_mode = ep->type;
+                       i_wont_support_encrypt &= ~typemask(ep->type);
+                       ret = 1;
+               }
+               if (ret == 0)
+                       printf("%s: invalid encryption mode\n", mode);
+       }
+       return(ret);
+}
+
+int
+EncryptStart(char *mode)
+{
+       int ret = 0;
+       if (mode) {
+               if (isprefix(mode, "input"))
+                       return(EncryptStartInput());
+               if (isprefix(mode, "output"))
+                       return(EncryptStartOutput());
+               if (isprefix(mode, "help") || isprefix(mode, "?")) {
+                       printf("Usage: encrypt start [input|output]\n");
+                       return(0);
+               }
+               printf("%s: invalid encryption mode 'encrypt start ?' for help\n", mode);
+               return(0);
+       }
+       ret += EncryptStartInput();
+       ret += EncryptStartOutput();
+       return(ret);
+}
+
+int
+EncryptStartInput(void)
+{
+       if (decrypt_mode) {
+               encrypt_send_request_start();
+               return(1);
+       }
+       printf("No previous decryption mode, decryption not enabled\r\n");
+       return(0);
+}
+
+int
+EncryptStartOutput(void)
+{
+       if (encrypt_mode) {
+               encrypt_start_output(encrypt_mode);
+               return(1);
+       }
+       printf("No previous encryption mode, encryption not enabled\r\n");
+       return(0);
+}
+
+int
+EncryptStop(char *mode)
+{
+       int ret = 0;
+       if (mode) {
+               if (isprefix(mode, "input"))
+                       return(EncryptStopInput());
+               if (isprefix(mode, "output"))
+                       return(EncryptStopOutput());
+               if (isprefix(mode, "help") || isprefix(mode, "?")) {
+                       printf("Usage: encrypt stop [input|output]\n");
+                       return(0);
+               }
+               printf("%s: invalid encryption mode 'encrypt stop ?' for help\n", mode);
+               return(0);
+       }
+       ret += EncryptStopInput();
+       ret += EncryptStopOutput();
+       return(ret);
+}
+
+int
+EncryptStopInput(void)
+{
+       encrypt_send_request_end();
+       return(1);
+}
+
+int
+EncryptStopOutput(void)
+{
+       encrypt_send_end();
+       return(1);
+}
+
+void
+encrypt_display(void)
+{
+       if (encrypt_output)
+               printf("Currently encrypting output with %s\r\n",
+                       ENCTYPE_NAME(encrypt_mode));
+       if (decrypt_input)
+               printf("Currently decrypting input with %s\r\n",
+                       ENCTYPE_NAME(decrypt_mode));
+}
+
+int
+EncryptStatus(void)
+{
+       if (encrypt_output)
+               printf("Currently encrypting output with %s\r\n",
+                       ENCTYPE_NAME(encrypt_mode));
+       else if (encrypt_mode) {
+               printf("Currently output is clear text.\r\n");
+               printf("Last encryption mode was %s\r\n",
+                       ENCTYPE_NAME(encrypt_mode));
+       }
+       if (decrypt_input) {
+               printf("Currently decrypting input with %s\r\n",
+                       ENCTYPE_NAME(decrypt_mode));
+       } else if (decrypt_mode) {
+               printf("Currently input is clear text.\r\n");
+               printf("Last decryption mode was %s\r\n",
+                       ENCTYPE_NAME(decrypt_mode));
+       }
+       return 1;
+}
+
+void
+encrypt_send_support(void)
+{
+       if (str_suplen) {
+               /*
+                * If the user has requested that decryption start
+                * immediatly, then send a "REQUEST START" before
+                * we negotiate the type.
+                */
+               if (!Server && autodecrypt)
+                       encrypt_send_request_start();
+               net_write(str_send, str_suplen);
+               printsub('>', &str_send[2], str_suplen - 2);
+               str_suplen = 0;
+       }
+}
+
+int
+EncryptDebug(int on)
+{
+       if (on < 0)
+               encrypt_debug_mode ^= 1;
+       else
+               encrypt_debug_mode = on;
+       printf("Encryption debugging %s\r\n",
+               encrypt_debug_mode ? "enabled" : "disabled");
+       return(1);
+}
+
+int
+EncryptVerbose(int on)
+{
+       if (on < 0)
+               encrypt_verbose ^= 1;
+       else
+               encrypt_verbose = on;
+       printf("Encryption %s verbose\r\n",
+               encrypt_verbose ? "is" : "is not");
+       return(1);
+}
+
+int
+EncryptAutoEnc(int on)
+{
+       encrypt_auto(on);
+       printf("Automatic encryption of output is %s\r\n",
+               autoencrypt ? "enabled" : "disabled");
+       return(1);
+}
+
+int
+EncryptAutoDec(int on)
+{
+       decrypt_auto(on);
+       printf("Automatic decryption of input is %s\r\n",
+               autodecrypt ? "enabled" : "disabled");
+       return(1);
+}
+
+/*
+ * Called when ENCRYPT SUPPORT is received.
+ */
+void
+encrypt_support(unsigned char *typelist, int cnt)
+{
+       int type, use_type = 0;
+       Encryptions *ep;
+
+       /*
+        * Forget anything the other side has previously told us.
+        */
+       remote_supports_decrypt = 0;
+
+       while (cnt-- > 0) {
+               type = *typelist++;
+               if (encrypt_debug_mode)
+                       printf(">>>%s: He is supporting %s (%d)\r\n",
+                               Name,
+                               ENCTYPE_NAME(type), type);
+               if ((type < ENCTYPE_CNT) &&
+                   (I_SUPPORT_ENCRYPT & typemask(type))) {
+                       remote_supports_decrypt |= typemask(type);
+                       if (use_type == 0)
+                               use_type = type;
+               }
+       }
+       if (use_type) {
+               ep = findencryption(use_type);
+               if (!ep)
+                       return;
+               type = ep->start ? (*ep->start)(DIR_ENCRYPT, Server) : 0;
+               if (encrypt_debug_mode)
+                       printf(">>>%s: (*ep->start)() returned %d\r\n",
+                                       Name, type);
+               if (type < 0)
+                       return;
+               encrypt_mode = use_type;
+               if (type == 0)
+                       encrypt_start_output(use_type);
+       }
+}
+
+void
+encrypt_is(unsigned char *data, int cnt)
+{
+       Encryptions *ep;
+       int type, ret;
+
+       if (--cnt < 0)
+               return;
+       type = *data++;
+       if (type < ENCTYPE_CNT)
+               remote_supports_encrypt |= typemask(type);
+       if (!(ep = finddecryption(type))) {
+               if (encrypt_debug_mode)
+                       printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n",
+                               Name,
+                               ENCTYPE_NAME_OK(type)
+                                       ? ENCTYPE_NAME(type) : "(unknown)",
+                               type);
+               return;
+       }
+       if (!ep->is) {
+               if (encrypt_debug_mode)
+                       printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n",
+                               Name,
+                               ENCTYPE_NAME_OK(type)
+                                       ? ENCTYPE_NAME(type) : "(unknown)",
+                               type);
+               ret = 0;
+       } else {
+               ret = (*ep->is)(data, cnt);
+               if (encrypt_debug_mode)
+                       printf("(*ep->is)(%p, %d) returned %s(%d)\n", data, cnt,
+                               (ret < 0) ? "FAIL " :
+                               (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret);
+       }
+       if (ret < 0) {
+               autodecrypt = 0;
+       } else {
+               decrypt_mode = type;
+               if (ret == 0 && autodecrypt)
+                       encrypt_send_request_start();
+       }
+}
+
+void
+encrypt_reply(unsigned char *data, int cnt)
+{
+       Encryptions *ep;
+       int ret, type;
+
+       if (--cnt < 0)
+               return;
+       type = *data++;
+       if (!(ep = findencryption(type))) {
+               if (encrypt_debug_mode)
+                       printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n",
+                               Name,
+                               ENCTYPE_NAME_OK(type)
+                                       ? ENCTYPE_NAME(type) : "(unknown)",
+                               type);
+               return;
+       }
+       if (!ep->reply) {
+               if (encrypt_debug_mode)
+                       printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n",
+                               Name,
+                               ENCTYPE_NAME_OK(type)
+                                       ? ENCTYPE_NAME(type) : "(unknown)",
+                               type);
+               ret = 0;
+       } else {
+               ret = (*ep->reply)(data, cnt);
+               if (encrypt_debug_mode)
+                       printf("(*ep->reply)(%p, %d) returned %s(%d)\n",
+                               data, cnt,
+                               (ret < 0) ? "FAIL " :
+                               (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret);
+       }
+       if (encrypt_debug_mode)
+               printf(">>>%s: encrypt_reply returned %d\n", Name, ret);
+       if (ret < 0) {
+               autoencrypt = 0;
+       } else {
+               encrypt_mode = type;
+               if (ret == 0 && autoencrypt)
+                       encrypt_start_output(type);
+       }
+}
+
+/*
+ * Called when a ENCRYPT START command is received.
+ */
+void
+encrypt_start(unsigned char *data __unused, int cnt __unused)
+{
+       Encryptions *ep;
+
+       if (!decrypt_mode) {
+               /*
+                * Something is wrong.  We should not get a START
+                * command without having already picked our
+                * decryption scheme.  Send a REQUEST-END to
+                * attempt to clear the channel...
+                */
+               printf("%s: Warning, Cannot decrypt input stream!!!\r\n", Name);
+               encrypt_send_request_end();
+               return;
+       }
+
+       if ((ep = finddecryption(decrypt_mode))) {
+               decrypt_input = ep->input;
+               if (encrypt_verbose)
+                       printf("[ Input is now decrypted with type %s ]\r\n",
+                               ENCTYPE_NAME(decrypt_mode));
+               if (encrypt_debug_mode)
+                       printf(">>>%s: Start to decrypt input with type %s\r\n",
+                               Name, ENCTYPE_NAME(decrypt_mode));
+       } else {
+               printf("%s: Warning, Cannot decrypt type %s (%d)!!!\r\n",
+                               Name,
+                               ENCTYPE_NAME_OK(decrypt_mode)
+                                       ? ENCTYPE_NAME(decrypt_mode)
+                                       : "(unknown)",
+                               decrypt_mode);
+               encrypt_send_request_end();
+       }
+}
+
+void
+encrypt_session_key( Session_Key *key, int server)
+{
+       Encryptions *ep = encryptions;
+
+       havesessionkey = 1;
+
+       while (ep->type) {
+               if (ep->session)
+                       (*ep->session)(key, server);
+               ++ep;
+       }
+}
+
+/*
+ * Called when ENCRYPT END is received.
+ */
+void
+encrypt_end(void)
+{
+       decrypt_input = 0;
+       if (encrypt_debug_mode)
+               printf(">>>%s: Input is back to clear text\r\n", Name);
+       if (encrypt_verbose)
+               printf("[ Input is now clear text ]\r\n");
+}
+
+/*
+ * Called when ENCRYPT REQUEST-END is received.
+ */
+void
+encrypt_request_end(void)
+{
+       encrypt_send_end();
+}
+
+/*
+ * Called when ENCRYPT REQUEST-START is received.  If we receive
+ * this before a type is picked, then that indicates that the
+ * other side wants us to start encrypting data as soon as we
+ * can.
+ */
+void
+encrypt_request_start(unsigned char *data __unused, int cnt __unused)
+{
+       if (encrypt_mode == 0)  {
+               if (Server)
+                       autoencrypt = 1;
+               return;
+       }
+       encrypt_start_output(encrypt_mode);
+}
+
+static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPT };
+
+void
+encrypt_enc_keyid(unsigned char *keyid, int len)
+{
+       encrypt_keyid(&ki[1], keyid, len);
+}
+
+void
+encrypt_dec_keyid(unsigned char *keyid, int len)
+{
+       encrypt_keyid(&ki[0], keyid, len);
+}
+
+void
+encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len)
+{
+       Encryptions *ep;
+       int dir = kp->dir;
+       int ret = 0;
+
+       if (len > MAXKEYLEN)
+               len = MAXKEYLEN;
+
+       if (!(ep = (*kp->getcrypt)(*kp->modep))) {
+               if (len == 0)
+                       return;
+               kp->keylen = 0;
+       } else if (len == 0) {
+               /*
+                * Empty option, indicates a failure.
+                */
+               if (kp->keylen == 0)
+                       return;
+               kp->keylen = 0;
+               if (ep->keyid)
+                       (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
+
+       } else if ((len != kp->keylen) ||
+                  (memcmp(keyid, kp->keyid, len) != 0)) {
+               /*
+                * Length or contents are different
+                */
+               kp->keylen = len;
+               memmove(kp->keyid, keyid, len);
+               if (ep->keyid)
+                       (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
+       } else {
+               if (ep->keyid)
+                       ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen);
+               if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt)
+                       encrypt_start_output(*kp->modep);
+               return;
+       }
+
+       encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0);
+}
+
+void
+encrypt_send_keyid(int dir, const char *keyid, int keylen, int saveit)
+{
+       unsigned char *strp;
+
+       str_keyid[3] = (dir == DIR_ENCRYPT)
+                       ? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID;
+       if (saveit) {
+               struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1];
+               memmove(kp->keyid, keyid, keylen);
+               kp->keylen = keylen;
+       }
+
+       for (strp = &str_keyid[4]; keylen > 0; --keylen) {
+               if ((*strp++ = *keyid++) == IAC)
+                       *strp++ = IAC;
+       }
+       *strp++ = IAC;
+       *strp++ = SE;
+       net_write(str_keyid, strp - str_keyid);
+       printsub('>', &str_keyid[2], strp - str_keyid - 2);
+}
+
+void
+encrypt_auto(int on)
+{
+       if (on < 0)
+               autoencrypt ^= 1;
+       else
+               autoencrypt = on ? 1 : 0;
+}
+
+void
+decrypt_auto(int on)
+{
+       if (on < 0)
+               autodecrypt ^= 1;
+       else
+               autodecrypt = on ? 1 : 0;
+}
+
+void
+encrypt_start_output(int type)
+{
+       Encryptions *ep;
+       unsigned char *p;
+       int i;
+
+       if (!(ep = findencryption(type))) {
+               if (encrypt_debug_mode) {
+                       printf(">>>%s: Can't encrypt with type %s (%d)\r\n",
+                               Name,
+                               ENCTYPE_NAME_OK(type)
+                                       ? ENCTYPE_NAME(type) : "(unknown)",
+                               type);
+               }
+               return;
+       }
+       if (ep->start) {
+               i = (*ep->start)(DIR_ENCRYPT, Server);
+               if (encrypt_debug_mode) {
+                       printf(">>>%s: Encrypt start: %s (%d) %s\r\n",
+                               Name,
+                               (i < 0) ? "failed" :
+                                       "initial negotiation in progress",
+                               i, ENCTYPE_NAME(type));
+               }
+               if (i)
+                       return;
+       }
+       p = str_start + 3;
+       *p++ = ENCRYPT_START;
+       for (i = 0; i < ki[0].keylen; ++i) {
+               if ((*p++ = ki[0].keyid[i]) == IAC)
+                       *p++ = IAC;
+       }
+       *p++ = IAC;
+       *p++ = SE;
+       net_write(str_start, p - str_start);
+       net_encrypt();
+       printsub('>', &str_start[2], p - &str_start[2]);
+       /*
+        * If we are already encrypting in some mode, then
+        * encrypt the ring (which includes our request) in
+        * the old mode, mark it all as "clear text" and then
+        * switch to the new mode.
+        */
+       encrypt_output = ep->output;
+       encrypt_mode = type;
+       if (encrypt_debug_mode)
+               printf(">>>%s: Started to encrypt output with type %s\r\n",
+                       Name, ENCTYPE_NAME(type));
+       if (encrypt_verbose)
+               printf("[ Output is now encrypted with type %s ]\r\n",
+                       ENCTYPE_NAME(type));
+}
+
+void
+encrypt_send_end(void)
+{
+       if (!encrypt_output)
+               return;
+
+       str_end[3] = ENCRYPT_END;
+       net_write(str_end, sizeof(str_end));
+       net_encrypt();
+       printsub('>', &str_end[2], sizeof(str_end) - 2);
+       /*
+        * Encrypt the output buffer now because it will not be done by
+        * netflush...
+        */
+       encrypt_output = 0;
+       if (encrypt_debug_mode)
+               printf(">>>%s: Output is back to clear text\r\n", Name);
+       if (encrypt_verbose)
+               printf("[ Output is now clear text ]\r\n");
+}
+
+void
+encrypt_send_request_start(void)
+{
+       unsigned char *p;
+       int i;
+
+       p = &str_start[3];
+       *p++ = ENCRYPT_REQSTART;
+       for (i = 0; i < ki[1].keylen; ++i) {
+               if ((*p++ = ki[1].keyid[i]) == IAC)
+                       *p++ = IAC;
+       }
+       *p++ = IAC;
+       *p++ = SE;
+       net_write(str_start, p - str_start);
+       printsub('>', &str_start[2], p - &str_start[2]);
+       if (encrypt_debug_mode)
+               printf(">>>%s: Request input to be encrypted\r\n", Name);
+}
+
+void
+encrypt_send_request_end(void)
+{
+       str_end[3] = ENCRYPT_REQEND;
+       net_write(str_end, sizeof(str_end));
+       printsub('>', &str_end[2], sizeof(str_end) - 2);
+
+       if (encrypt_debug_mode)
+               printf(">>>%s: Request input to be clear text\r\n", Name);
+}
+
+void
+encrypt_wait(void)
+{
+       if (encrypt_debug_mode)
+               printf(">>>%s: in encrypt_wait\r\n", Name);
+       if (!havesessionkey || !(I_SUPPORT_ENCRYPT & remote_supports_decrypt))
+               return;
+       while (autoencrypt && !encrypt_output)
+               if (telnet_spin())
+                       return;
+}
+
+void
+encrypt_gen_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
+{
+       char tbuf[16], *cp;
+
+       cnt -= 2;
+       data += 2;
+       buf[buflen-1] = '\0';
+       buf[buflen-2] = '*';
+       buflen -= 2;;
+       for (; cnt > 0; cnt--, data++) {
+               sprintf(tbuf, " %d", *data);
+               for (cp = tbuf; *cp && buflen > 0; --buflen)
+                       *buf++ = *cp++;
+               if (buflen <= 0)
+                       return;
+       }
+       *buf = '\0';
+}
+
+void
+encrypt_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
+{
+       Encryptions *ep;
+       int type = data[1];
+
+       for (ep = encryptions; ep->type && ep->type != type; ep++)
+               ;
+
+       if (ep->printsub)
+               (*ep->printsub)(data, cnt, buf, buflen);
+       else
+               encrypt_gen_printsub(data, cnt, buf, buflen);
+}
+#endif /* ENCRYPTION */
diff --git a/lib/libtelnet/encrypt.h b/lib/libtelnet/encrypt.h
new file mode 100644 (file)
index 0000000..3e262b5
--- /dev/null
@@ -0,0 +1,106 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)encrypt.h   8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/crypto/telnet/libtelnet/encrypt.h,v 1.4.2.1 2002/04/13 10:59:07 markm Exp $
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifdef ENCRYPTION
+# ifndef __ENCRYPTION__
+# define __ENCRYPTION__
+
+#define        DIR_DECRYPT             1
+#define        DIR_ENCRYPT             2
+
+#include <des.h>
+typedef        unsigned char Block[8];
+typedef unsigned char *BlockT;
+#if 0
+typedef struct { Block __; } Schedule[16];
+#else
+#define Schedule des_key_schedule
+#endif
+
+#define        VALIDKEY(key)   ( key[0] | key[1] | key[2] | key[3] | \
+                         key[4] | key[5] | key[6] | key[7])
+
+#define        SAMEKEY(k1, k2) (!bcmp((void *)k1, (void *)k2, sizeof(Block)))
+
+typedef        struct {
+       short           type;
+       int             length;
+       unsigned char   *data;
+} Session_Key;
+
+typedef struct {
+       const char *name;
+       int     type;
+       void    (*output)(unsigned char *, int);
+       int     (*input)(int);
+       void    (*init)(int);
+       int     (*start)(int, int);
+       int     (*is)(unsigned char *, int);
+       int     (*reply)(unsigned char *, int);
+       void    (*session)(Session_Key *, int);
+       int     (*keyid)(int, unsigned char *, int *);
+       void    (*printsub)(unsigned char *, int, unsigned char *, int);
+} Encryptions;
+
+#define        SK_DES          1       /* Matched Kerberos v5 KEYTYPE_DES */
+
+#include "enc-proto.h"
+
+extern int encrypt_debug_mode;
+extern int (*decrypt_input)(int);
+extern void (*encrypt_output)(unsigned char *, int);
+# endif /* __ENCRYPTION__ */
+#endif /* ENCRYPTION */
diff --git a/lib/libtelnet/forward.c b/lib/libtelnet/forward.c
new file mode 100644 (file)
index 0000000..1a3d365
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * appl/telnet/libtelnet/forward.c
+ */
+
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/* General-purpose forwarding routines. These routines may be put into */
+/* libkrb5.a to allow widespread use */ 
+
+#if defined(KERBEROS) || defined(KRB5)
+#include <stdio.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <krb5.h>
+extern char *line;             /* see sys_term.c */
+
+/* Decode, decrypt and store the forwarded creds in the local ccache. */
+krb5_error_code
+rd_and_store_for_creds(context, auth_context, inbuf, ticket)
+    krb5_context context;
+    krb5_auth_context auth_context;
+    krb5_data *inbuf;
+    krb5_ticket *ticket;
+{
+    krb5_creds **creds;
+    krb5_error_code retval;
+    char ccname[35];
+    krb5_ccache ccache = NULL;
+#if 0
+    char *tty;
+#endif
+
+    if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)))
+       return(retval);
+
+    sprintf(ccname, "FILE:/tmp/krb5cc_p%d", getpid());
+    setenv("KRB5CCNAME", ccname, 1);
+
+    if ((retval = krb5_cc_resolve(context, ccname, &ccache)))
+       goto cleanup;
+
+    if ((retval = krb5_cc_initialize(context, ccache, ticket->enc_part2->client)))
+       goto cleanup;
+
+    if ((retval = krb5_cc_store_cred(context, ccache, *creds)))
+       goto cleanup;
+
+cleanup:
+    krb5_free_creds(context, *creds);
+    return retval;
+}
+
+#endif /* defined(KRB5) && defined(FORWARD) */
diff --git a/lib/libtelnet/genget.c b/lib/libtelnet/genget.c
new file mode 100644 (file)
index 0000000..9d4e164
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/genget.c,v 1.2.8.2 2002/04/13 10:59:07 markm Exp $");
+#endif
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)genget.c     8.2 (Berkeley) 5/30/95";
+#endif
+#endif /* not lint */
+
+
+#include <ctype.h>
+
+#include "misc-proto.h"
+
+#define        LOWER(x) (isupper(x) ? tolower(x) : (x))
+/*
+ * The prefix function returns 0 if *s1 is not a prefix
+ * of *s2.  If *s1 exactly matches *s2, the negative of
+ * the length is returned.  If *s1 is a prefix of *s2,
+ * the length of *s1 is returned.
+ */
+int
+isprefix(char *s1, const char *s2)
+{
+       char *os1;
+       char c1, c2;
+
+       if (*s1 == '\0')
+               return(-1);
+       os1 = s1;
+       c1 = *s1;
+       c2 = *s2;
+       while (LOWER(c1) == LOWER(c2)) {
+               if (c1 == '\0')
+                       break;
+               c1 = *++s1;
+               c2 = *++s2;
+       }
+       return(*s1 ? 0 : (*s2 ? (s1 - os1) : (os1 - s1)));
+}
+
+static char *ambiguous;                /* special return value for command routines */
+
+char **
+genget(char *name, char **table, int stlen)
+{
+       char **c, **found;
+       int n;
+
+       if (name == 0)
+           return 0;
+
+       found = 0;
+       for (c = table; *c != 0; c = (char **)((char *)c + stlen)) {
+               if ((n = isprefix(name, *c)) == 0)
+                       continue;
+               if (n < 0)              /* exact match */
+                       return(c);
+               if (found)
+                       return(&ambiguous);
+               found = c;
+       }
+       return(found);
+}
+
+/*
+ * Function call version of Ambiguous()
+ */
+int
+Ambiguous(char **s)
+{
+       return(s == &ambiguous);
+}
diff --git a/lib/libtelnet/getent.c b/lib/libtelnet/getent.c
new file mode 100644 (file)
index 0000000..99bebbc
--- /dev/null
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/getent.c,v 1.2.6.2 2002/04/13 10:59:07 markm Exp $");
+#endif
+
+#ifndef __unused
+#define __unused        __attribute__((__unused__))
+#endif
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)getent.c   8.2 (Berkeley) 12/15/93";
+#endif
+#endif /* not lint */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "misc-proto.h"
+
+static char *area;
+static char gettytab[] = "/etc/gettytab";
+
+/*ARGSUSED*/
+int
+getent(char *cp __unused, const char *name)
+{
+       int retval;
+       char *tempnam, *dba[2] = { gettytab, NULL };
+
+       tempnam = strdup(name);
+       retval =  cgetent(&area, dba, tempnam) == 0 ? 1 : 0;
+       free(tempnam);
+       return(retval);
+}
+
+/*ARGSUSED*/
+char *
+Getstr(const char *id, char **cpp __unused)
+{
+       int retval;
+       char *answer, *tempid;
+
+       tempid = strdup(id);
+       retval = cgetstr(area, tempid, &answer);
+       free(tempid);
+       return((retval > 0) ? answer : NULL);
+}
diff --git a/lib/libtelnet/kerberos.c b/lib/libtelnet/kerberos.c
new file mode 100644 (file)
index 0000000..0cd9648
--- /dev/null
@@ -0,0 +1,519 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/kerberos.c,v 1.3.2.1 2002/04/13 10:59:07 markm Exp $");
+#endif
+
+#ifndef __unused
+#define __unused        __attribute__((__unused__))
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)kerberos.c   8.3 (Berkeley) 5/30/95";
+#endif /* not lint */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifdef KRB4
+#include <sys/types.h>
+#include <arpa/telnet.h>
+#include <des.h>       /* BSD wont include this in krb.h, so we do it here */
+#include <krb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "encrypt.h"
+#include "auth.h"
+#include "misc.h"
+
+int kerberos4_cksum(unsigned char *, int);
+int kuserok(AUTH_DAT *, char *);
+
+extern int auth_debug_mode;
+
+static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
+                                       AUTHTYPE_KERBEROS_V4, };
+
+#define        KRB_AUTH        0               /* Authentication data follows */
+#define        KRB_REJECT      1               /* Rejected (reason might follow) */
+#define        KRB_ACCEPT      2               /* Accepted */
+#define        KRB_CHALLENGE   3               /* Challenge for mutual auth. */
+#define        KRB_RESPONSE    4               /* Response for mutual auth. */
+
+static KTEXT_ST auth;
+static char name[ANAME_SZ];
+static AUTH_DAT adat = { 0, "", "", "", 0, {}, 0, 0, 0, { 0, "", 0 } };
+#ifdef ENCRYPTION
+static Block   session_key     = { 0 };
+static des_key_schedule sched;
+static Block   challenge       = { 0 };
+#endif /* ENCRYPTION */
+
+static char krb_service_name[] = "rcmd";
+static char empty[] = "";
+
+static int
+Data(Authenticator *ap, int type, const unsigned char *d, int c)
+{
+       unsigned char *p = str_data + 4;
+       const unsigned char *cd = d;
+
+       if (c == -1)
+               c = strlen(cd);
+
+       if (auth_debug_mode) {
+               printf("%s:%d: [%d] (%d)",
+                       str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
+                       str_data[3],
+                       type, c);
+               printd(d, c);
+               printf("\r\n");
+       }
+       *p++ = ap->type;
+       *p++ = ap->way;
+       *p++ = type;
+       while (c-- > 0) {
+               if ((*p++ = *cd++) == IAC)
+                       *p++ = IAC;
+       }
+       *p++ = IAC;
+       *p++ = SE;
+       if (str_data[3] == TELQUAL_IS)
+               printsub('>', &str_data[2], p - (&str_data[2]));
+       return(net_write(str_data, p - str_data));
+}
+
+int
+kerberos4_init(Authenticator *ap __unused, int server)
+{
+       FILE *fp;
+
+       if (server) {
+               str_data[3] = TELQUAL_REPLY;
+               if ((fp = fopen(KEYFILE, "r")) == NULL)
+                       return(0);
+               fclose(fp);
+       } else {
+               str_data[3] = TELQUAL_IS;
+       }
+       return(1);
+}
+
+char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
+int dst_realm_sz = REALM_SZ;
+
+int
+kerberos4_send(Authenticator *ap)
+{
+       KTEXT_ST lauth;
+       char instance[INST_SZ];
+       char *realm;
+       CREDENTIALS cred;
+       int r;
+
+       printf("[ Trying KERBEROS4 ... ]\n");
+       if (!UserNameRequested) {
+               if (auth_debug_mode) {
+                       printf("Kerberos V4: no user name supplied\r\n");
+               }
+               return(0);
+       }
+
+       memset(instance, 0, sizeof(instance));
+
+       if ((realm = krb_get_phost(RemoteHostName)))
+               strncpy(instance, realm, sizeof(instance));
+
+       instance[sizeof(instance)-1] = '\0';
+
+       realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName);
+
+       if (!realm) {
+               printf("Kerberos V4: no realm for %s\r\n", RemoteHostName);
+               return(0);
+       }
+       if ((r = krb_mk_req(&lauth, krb_service_name, instance, realm, 0L))) {
+               printf("mk_req failed: %s\r\n", krb_err_txt[r]);
+               return(0);
+       }
+       if ((r = krb_get_cred(krb_service_name, instance, realm, &cred))) {
+               printf("get_cred failed: %s\r\n", krb_err_txt[r]);
+               return(0);
+       }
+       if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
+               if (auth_debug_mode)
+                       printf("Not enough room for user name\r\n");
+               return(0);
+       }
+       if (auth_debug_mode)
+               printf("Sent %d bytes of authentication data\r\n", lauth.length);
+       if (!Data(ap, KRB_AUTH, (void *)lauth.dat, lauth.length)) {
+               if (auth_debug_mode)
+                       printf("Not enough room for authentication data\r\n");
+               return(0);
+       }
+#ifdef ENCRYPTION
+       /*
+        * If we are doing mutual authentication, get set up to send
+        * the challenge, and verify it when the response comes back.
+        */
+       if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+               register int i;
+
+               des_key_sched(cred.session, sched);
+               des_init_random_number_generator(cred.session);
+               des_new_random_key(session_key);
+               des_ecb_encrypt(&session_key, &session_key, sched, 0);
+               des_ecb_encrypt(&session_key, &challenge, sched, 0);
+               /*
+                * Increment the challenge by 1, and encrypt it for
+                * later comparison.
+                */
+               for (i = 7; i >= 0; --i) {
+                       register int x;
+                       x = (unsigned int)challenge[i] + 1;
+                       challenge[i] = x;       /* ignore overflow */
+                       if (x < 256)            /* if no overflow, all done */
+                               break;
+               }
+               des_ecb_encrypt(&challenge, &challenge, sched, 1);
+       }
+#endif /* ENCRYPTION */
+
+       if (auth_debug_mode) {
+               printf("CK: %d:", kerberos4_cksum(lauth.dat, lauth.length));
+               printd(lauth.dat, lauth.length);
+               printf("\r\n");
+               printf("Sent Kerberos V4 credentials to server\r\n");
+       }
+       return(1);
+}
+
+void
+kerberos4_is(Authenticator *ap, unsigned char *data, int cnt)
+{
+#ifdef ENCRYPTION
+       Session_Key skey;
+       Block datablock;
+#endif /* ENCRYPTION */
+       char realm[REALM_SZ];
+       char instance[INST_SZ];
+       int r;
+
+       if (cnt-- < 1)
+               return;
+       switch (*data++) {
+       case KRB_AUTH:
+               if (krb_get_lrealm(realm, 1) != KSUCCESS) {
+                       Data(ap, KRB_REJECT, "No local V4 Realm.", -1);
+                       auth_finished(ap, AUTH_REJECT);
+                       if (auth_debug_mode)
+                               printf("No local realm\r\n");
+                       return;
+               }
+               memmove((void *)auth.dat, (void *)data, auth.length = cnt);
+               if (auth_debug_mode) {
+                       printf("Got %d bytes of authentication data\r\n", cnt);
+                       printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
+                       printd(auth.dat, auth.length);
+                       printf("\r\n");
+               }
+               instance[0] = '*'; instance[1] = 0;
+               if ((r = krb_rd_req(&auth, krb_service_name,
+                                  instance, 0, &adat, empty))) {
+                       if (auth_debug_mode)
+                               printf("Kerberos failed him as %s\r\n", name);
+                       Data(ap, KRB_REJECT, krb_err_txt[r], -1);
+                       auth_finished(ap, AUTH_REJECT);
+                       return;
+               }
+#ifdef ENCRYPTION
+               memmove((void *)session_key, (void *)adat.session, sizeof(Block));
+#endif /* ENCRYPTION */
+               strncpy (name, adat.pname, ANAME_SZ-1);
+               name[ANAME_SZ-1] = '\0';
+
+               if (UserNameRequested && !kuserok(&adat, UserNameRequested))
+                       Data(ap, KRB_ACCEPT, NULL, 0);
+               else
+                       Data(ap, KRB_REJECT, "user is not authorized", -1);
+               auth_finished(ap, AUTH_USER);
+               break;
+
+       case KRB_CHALLENGE:
+#ifndef        ENCRYPTION
+               Data(ap, KRB_RESPONSE, NULL, 0);
+#else  /* ENCRYPTION */
+               if (!VALIDKEY(session_key)) {
+                       /*
+                        * We don't have a valid session key, so just
+                        * send back a response with an empty session
+                        * key.
+                        */
+                       Data(ap, KRB_RESPONSE, NULL, 0);
+                       break;
+               }
+
+               /*
+                * Initialize the random number generator since it's
+                * used later on by the encryption routine.
+                */
+               des_init_random_number_generator(session_key);
+               des_key_sched(session_key, sched);
+               memmove((void *)datablock, (void *)data, sizeof(Block));
+               /*
+                * Take the received encrypted challenge, and encrypt
+                * it again to get a unique session_key for the
+                * ENCRYPT option.
+                */
+               des_ecb_encrypt(&datablock, &session_key, sched, 1);
+               skey.type = SK_DES;
+               skey.length = 8;
+               skey.data = session_key;
+               encrypt_session_key(&skey, 1);
+               /*
+                * Now decrypt the received encrypted challenge,
+                * increment by one, re-encrypt it and send it back.
+                */
+               des_ecb_encrypt(&datablock, &challenge, sched, 0);
+               for (r = 7; r >= 0; r--) {
+                       register int t;
+                       t = (unsigned int)challenge[r] + 1;
+                       challenge[r] = t;       /* ignore overflow */
+                       if (t < 256)            /* if no overflow, all done */
+                               break;
+               }
+               des_ecb_encrypt(&challenge, &challenge, sched, 1);
+               Data(ap, KRB_RESPONSE, challenge, sizeof(challenge));
+#endif /* ENCRYPTION */
+               break;
+
+       default:
+               if (auth_debug_mode)
+                       printf("Unknown Kerberos option %d\r\n", data[-1]);
+               Data(ap, KRB_REJECT, NULL, 0);
+               break;
+       }
+}
+
+void
+kerberos4_reply(Authenticator *ap, unsigned char *data, int cnt)
+{
+#ifdef ENCRYPTION
+       Session_Key skey;
+#endif /* ENCRYPTION */
+
+       if (cnt-- < 1)
+               return;
+       switch (*data++) {
+       case KRB_REJECT:
+               if (cnt > 0) {
+                       printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n",
+                               cnt, data);
+               } else
+                       printf("[ Kerberos V4 refuses authentication ]\r\n");
+               auth_send_retry();
+               return;
+       case KRB_ACCEPT:
+               printf("[ Kerberos V4 accepts you ]\n");
+               if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+                       /*
+                        * Send over the encrypted challenge.
+                        */
+#ifndef        ENCRYPTION
+                       Data(ap, KRB_CHALLENGE, NULL, 0);
+#else  /* ENCRYPTION */
+                       Data(ap, KRB_CHALLENGE, session_key,
+                                               sizeof(session_key));
+                       des_ecb_encrypt(&session_key, &session_key, sched, 1);
+                       skey.type = SK_DES;
+                       skey.length = 8;
+                       skey.data = session_key;
+                       encrypt_session_key(&skey, 0);
+#endif /* ENCRYPTION */
+                       return;
+               }
+               auth_finished(ap, AUTH_USER);
+               return;
+       case KRB_RESPONSE:
+#ifdef ENCRYPTION
+               /*
+                * Verify that the response to the challenge is correct.
+                */
+               if ((cnt != sizeof(Block)) ||
+                   (0 != memcmp((void *)data, (void *)challenge,
+                                               sizeof(challenge))))
+               {
+#endif /* ENCRYPTION */
+                       printf("[ Kerberos V4 challenge failed!!! ]\r\n");
+                       auth_send_retry();
+                       return;
+#ifdef ENCRYPTION
+               }
+               printf("[ Kerberos V4 challenge successful ]\r\n");
+               auth_finished(ap, AUTH_USER);
+#endif /* ENCRYPTION */
+               break;
+       default:
+               if (auth_debug_mode)
+                       printf("Unknown Kerberos option %d\r\n", data[-1]);
+               return;
+       }
+}
+
+int
+kerberos4_status(Authenticator *ap __unused, char *nam, int level)
+{
+       if (level < AUTH_USER)
+               return(level);
+
+       if (UserNameRequested && !kuserok(&adat, UserNameRequested)) {
+               strcpy(nam, UserNameRequested);
+               return(AUTH_VALID);
+       } else
+               return(AUTH_USER);
+}
+
+#define        BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
+#define        ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
+
+void
+kerberos4_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
+{
+       char lbuf[32];
+       register int i;
+
+       buf[buflen-1] = '\0';           /* make sure its NULL terminated */
+       buflen -= 1;
+
+       switch(data[3]) {
+       case KRB_REJECT:                /* Rejected (reason might follow) */
+               strncpy((char *)buf, " REJECT ", buflen);
+               goto common;
+
+       case KRB_ACCEPT:                /* Accepted (name might follow) */
+               strncpy((char *)buf, " ACCEPT ", buflen);
+       common:
+               BUMP(buf, buflen);
+               if (cnt <= 4)
+                       break;
+               ADDC(buf, buflen, '"');
+               for (i = 4; i < cnt; i++)
+                       ADDC(buf, buflen, data[i]);
+               ADDC(buf, buflen, '"');
+               ADDC(buf, buflen, '\0');
+               break;
+
+       case KRB_AUTH:                  /* Authentication data follows */
+               strncpy((char *)buf, " AUTH", buflen);
+               goto common2;
+
+       case KRB_CHALLENGE:
+               strncpy((char *)buf, " CHALLENGE", buflen);
+               goto common2;
+
+       case KRB_RESPONSE:
+               strncpy((char *)buf, " RESPONSE", buflen);
+               goto common2;
+
+       default:
+               sprintf(lbuf, " %d (unknown)", data[3]);
+               strncpy((char *)buf, lbuf, buflen);
+       common2:
+               BUMP(buf, buflen);
+               for (i = 4; i < cnt; i++) {
+                       sprintf(lbuf, " %d", data[i]);
+                       strncpy((char *)buf, lbuf, buflen);
+                       BUMP(buf, buflen);
+               }
+               break;
+       }
+}
+
+int
+kerberos4_cksum(unsigned char *d, int n)
+{
+       int ck = 0;
+
+       /*
+        * A comment is probably needed here for those not
+        * well versed in the "C" language.  Yes, this is
+        * supposed to be a "switch" with the body of the
+        * "switch" being a "while" statement.  The whole
+        * purpose of the switch is to allow us to jump into
+        * the middle of the while() loop, and then not have
+        * to do any more switch()s.
+        *
+        * Some compilers will spit out a warning message
+        * about the loop not being entered at the top.
+        */
+       switch (n&03)
+       do {
+       case 0:
+               ck ^= (int)*d++ << 24;
+               --n;
+       case 3:
+               ck ^= (int)*d++ << 16;
+               --n;
+       case 2:
+               ck ^= (int)*d++ << 8;
+               --n;
+       case 1:
+               ck ^= (int)*d++;
+               --n;
+       } while (n > 0);
+       return(ck);
+}
+#endif
diff --git a/lib/libtelnet/kerberos5.c b/lib/libtelnet/kerberos5.c
new file mode 100644 (file)
index 0000000..55c68ca
--- /dev/null
@@ -0,0 +1,888 @@
+/*
+ *     appl/telnet/libtelnet/kerberos5.c
+ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)kerberos5.c    8.1 (Berkeley) 6/4/93 */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+
+#ifdef KRB5
+#include <arpa/telnet.h>
+#include <stdio.h>
+#define KRB5_DEPRECATED 1 /* krb5_auth_con_getremotesubkey */
+#include <krb5.h>
+#include "com_err.h"
+#include <netdb.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <sys/errno.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern char *malloc();
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "encrypt.h"
+#include "auth.h"
+#include "misc.h"
+
+extern int auth_debug_mode;
+extern int net;
+
+#ifdef FORWARD
+int forward_flags = 0;  /* Flags get set in telnet/main.c on -f and -F */
+
+void kerberos5_forward();
+krb5_error_code
+rd_and_store_for_creds(krb5_context context, krb5_auth_context auth_context, krb5_data *inbuf, krb5_ticket *ticket);
+
+#endif /* FORWARD */
+
+static unsigned char str_data[8192] = {IAC, SB, TELOPT_AUTHENTICATION, 0,
+                                       AUTHTYPE_KERBEROS_V5, };
+/*static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
+                                       TELQUAL_NAME, };*/
+
+#define AUTH_ENCRYPT_OFF        0
+#define AUTH_ENCRYPT_ON         4
+#define AUTH_ENCRYPT_MASK       4
+
+#define        KRB_AUTH                0       /* Authentication data follows */
+#define        KRB_REJECT              1       /* Rejected (reason might follow) */
+#define        KRB_ACCEPT              2       /* Accepted */
+#define        KRB_RESPONSE            3       /* Response for mutual auth. */
+
+#ifdef FORWARD
+#define KRB_FORWARD            4       /* Forwarded credentials follow */
+#define KRB_FORWARD_ACCEPT             5       /* Forwarded credentials accepted */
+#define KRB_FORWARD_REJECT             6       /* Forwarded credentials rejected */
+#endif /* FORWARD */
+
+krb5_auth_context auth_context = 0;
+
+static krb5_data auth;
+       /* telnetd gets session key from here */
+static krb5_ticket * ticket = NULL;
+/* telnet matches the AP_REQ and AP_REP with this */
+
+/* some compilers can't hack void *, so we use the Kerberos krb5_pointer,
+   which is either void * or char *, depending on the compiler. */
+
+#define Voidptr krb5_pointer
+
+krb5_keyblock  *session_key = 0;
+char *         telnet_srvtab = NULL;
+char *         telnet_krb5_realm = NULL;
+
+       static int
+Data(ap, type, d, c)
+       Authenticator *ap;
+       int type;
+       Voidptr d;
+       int c;
+{
+        unsigned char *p = str_data + 4;
+       unsigned char *cd = (unsigned char *)d;
+       size_t spaceleft = sizeof(str_data) - 4;
+
+       if (c == -1)
+               c = strlen((char *)cd);
+
+        if (auth_debug_mode) {
+                printf("%s:%d: [%d] (%d)",
+                        str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
+                        str_data[3],
+                        type, c);
+                printd(d, c);
+                printf("\r\n");
+        }
+       *p++ = ap->type;
+       *p++ = ap->way;
+       *p++ = type;
+       spaceleft -= 3;
+        while (c-- > 0) {
+               if ((*p++ = *cd++) == IAC) {
+                       *p++ = IAC;
+                       spaceleft--;
+               }
+               if ((--spaceleft < 4) && c) {
+                       errno = ENOMEM;
+                       return -1;
+               }
+        }
+        *p++ = IAC;
+        *p++ = SE;
+       if (str_data[3] == TELQUAL_IS)
+               printsub('>', &str_data[2], p - &str_data[2]);
+        return(net_write(str_data, p - str_data));
+}
+
+krb5_context telnet_context = 0;
+int
+kerberos5_init(ap, server)
+       Authenticator *ap;
+       int server;
+{
+       krb5_error_code retval;
+       
+       if (server)
+               str_data[3] = TELQUAL_REPLY;
+       else
+               str_data[3] = TELQUAL_IS;
+       if (telnet_context == 0) {
+               retval = krb5_init_context(&telnet_context);
+               if (retval)
+                       return 0;
+       }
+       return(1);
+}
+
+void
+kerberos5_cleanup()
+{
+    krb5_error_code retval;
+    krb5_ccache ccache;
+    char *ccname;
+    
+    if (telnet_context == 0)
+       return;
+
+    ccname = getenv("KRB5CCNAME");
+    if (ccname) {
+       retval = krb5_cc_resolve(telnet_context, ccname, &ccache);
+       if (!retval)
+           retval = krb5_cc_destroy(telnet_context, ccache);
+    }
+
+    krb5_free_context(telnet_context);
+    telnet_context = 0;
+}
+
+
+       int
+kerberos5_send(ap)
+       Authenticator *ap;
+{
+       krb5_error_code r;
+       krb5_ccache ccache;
+       krb5_creds creds;               /* telnet gets session key from here */
+       krb5_creds * new_creds = 0;
+       int ap_opts;
+       char type_check[2];
+       krb5_data check_data;
+
+#ifdef ENCRYPTION
+       krb5_keyblock *newkey = 0;
+#endif /* ENCRYPTION */
+
+        if (!UserNameRequested) {
+                if (auth_debug_mode) {
+                        printf(
+                       "telnet: Kerberos V5: no user name supplied\r\n");
+                }
+                return(0);
+        }
+
+       if ((r = krb5_cc_default(telnet_context, &ccache))) {
+               if (auth_debug_mode) {
+                   printf(
+                   "telnet: Kerberos V5: could not get default ccache\r\n");
+               }
+               return(0);
+       }
+
+       memset((char *)&creds, 0, sizeof(creds));
+       if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName,
+                                        "host", KRB5_NT_SRV_HST,
+                                        &creds.server))) {
+           if (auth_debug_mode)
+               printf("telnet: Kerberos V5: error while constructing service name: %s\r\n", error_message(r));
+           return(0);
+       }
+
+       if (telnet_krb5_realm != NULL) {
+           krb5_data rdata;
+
+           rdata.length = strlen(telnet_krb5_realm);
+           rdata.data = (char *) malloc(rdata.length + 1);
+           if (rdata.data == NULL) {
+               fprintf(stderr, "malloc failed\n");
+               return(0);
+           }
+           strcpy(rdata.data, telnet_krb5_realm);
+           krb5_princ_set_realm(telnet_context, creds.server, &rdata);
+       }
+
+       if ((r = krb5_cc_get_principal(telnet_context, ccache,
+                                      &creds.client))) {
+               if (auth_debug_mode) {
+                       printf(
+                       "telnet: Kerberos V5: failure on principal (%s)\r\n",
+                               error_message(r));
+               }
+               krb5_free_cred_contents(telnet_context, &creds);
+               return(0);
+       }
+
+       creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC;
+       if ((r = krb5_get_credentials(telnet_context, 0,
+                                     ccache, &creds, &new_creds))) {
+               if (auth_debug_mode) {
+                       printf(
+                       "telnet: Kerberos V5: failure on credentials(%s)\r\n",
+                              error_message(r));
+               }
+               krb5_free_cred_contents(telnet_context, &creds);
+               return(0);
+       }
+
+       if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
+           ap_opts = AP_OPTS_MUTUAL_REQUIRED;
+       else
+           ap_opts = 0;
+
+#ifdef ENCRYPTION
+       ap_opts |= AP_OPTS_USE_SUBKEY;
+#endif /* ENCRYPTION */
+           
+       if (auth_context) {
+           krb5_auth_con_free(telnet_context, auth_context);
+           auth_context = 0;
+       }
+       if ((r = krb5_auth_con_init(telnet_context, &auth_context))) {
+           if (auth_debug_mode) {
+               printf("Kerberos V5: failed to init auth_context (%s)\r\n",
+                      error_message(r));
+           }
+           return(0);
+       }
+       
+       krb5_auth_con_setflags(telnet_context, auth_context,
+                              KRB5_AUTH_CONTEXT_RET_TIME);
+       
+       type_check[0] = ap->type;
+       type_check[1] = ap->way;
+       check_data.magic = KV5M_DATA;
+       check_data.length = 2;
+       check_data.data = (char *) &type_check;
+
+       r = krb5_mk_req_extended(telnet_context, &auth_context, ap_opts,
+                                &check_data, new_creds, &auth);
+
+#ifdef ENCRYPTION
+       krb5_auth_con_getlocalsubkey(telnet_context, auth_context, &newkey);
+       if (session_key) {
+               krb5_free_keyblock(telnet_context, session_key);
+               session_key = 0;
+       }
+
+       if (newkey) {
+           /* keep the key in our private storage, but don't use it
+              yet---see kerberos5_reply() below */
+           if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) &&
+               (newkey-> enctype != ENCTYPE_DES_CBC_MD5)) {
+               if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) ||
+                   (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5))
+                   /* use the session key in credentials instead */
+                   krb5_copy_keyblock(telnet_context,&new_creds->keyblock,
+                                      &session_key);
+               else
+                   /* XXX ? */;
+           } else {
+               krb5_copy_keyblock(telnet_context, newkey, &session_key);
+           }
+           krb5_free_keyblock(telnet_context, newkey);
+       }
+#endif /* ENCRYPTION */
+       krb5_free_cred_contents(telnet_context, &creds);
+       krb5_free_creds(telnet_context, new_creds);
+       if (r) {
+               if (auth_debug_mode) {
+                       printf("telnet: Kerberos V5: mk_req failed (%s)\r\n",
+                              error_message(r));
+               }
+               return(0);
+       }
+
+        if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
+                if (auth_debug_mode)
+                        printf("telnet: Not enough room for user name\r\n");
+                return(0);
+        }
+       if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
+               if (auth_debug_mode)
+                   printf(
+                   "telnet: Not enough room for authentication data\r\n");
+               return(0);
+       }
+       if (auth_debug_mode) {
+               printf("telnet: Sent Kerberos V5 credentials to server\r\n");
+       }
+       return(1);
+}
+
+       void
+kerberos5_is(ap, data, cnt)
+       Authenticator *ap;
+       unsigned char *data;
+       int cnt;
+{
+       int r = 0;
+       krb5_principal server;
+       krb5_keyblock *newkey = NULL;
+       krb5_keytab keytabid = 0;
+       krb5_data outbuf;
+#ifdef ENCRYPTION
+       Session_Key skey;
+#endif
+       char errbuf[320];
+       char *name;
+       char *getenv();
+       krb5_data inbuf;
+       krb5_authenticator *authenticator;
+
+       if (cnt-- < 1)
+               return;
+       switch (*data++) {
+       case KRB_AUTH:
+               auth.data = (char *)data;
+               auth.length = cnt;
+
+               if (!r && !auth_context)
+                   r = krb5_auth_con_init(telnet_context, &auth_context);
+               if (!r) {
+                   krb5_rcache rcache;
+                   
+                   r = krb5_auth_con_getrcache(telnet_context, auth_context,
+                                               &rcache);
+                   if (!r && !rcache) {
+                       r = krb5_sname_to_principal(telnet_context, 0, 0,
+                                                   KRB5_NT_SRV_HST, &server);
+                       if (!r) {
+                           r = krb5_get_server_rcache(telnet_context,
+                                       krb5_princ_component(telnet_context,
+                                                            server, 0),
+                                                      &rcache);
+                           krb5_free_principal(telnet_context, server);
+                       }
+                   }
+                   if (!r)
+                       r = krb5_auth_con_setrcache(telnet_context,
+                                                   auth_context, rcache);
+               }
+               if (!r && telnet_srvtab)
+                   r = krb5_kt_resolve(telnet_context, 
+                                       telnet_srvtab, &keytabid);
+               if (!r)
+                   r = krb5_rd_req(telnet_context, &auth_context, &auth,
+                                   NULL, keytabid, NULL, &ticket);
+               if (r) {
+                       (void) strcpy(errbuf, "krb5_rd_req failed: ");
+                       errbuf[sizeof(errbuf) - 1] = '\0';
+                       (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+                       goto errout;
+               }
+
+               /*
+                * 256 bytes should be much larger than any reasonable
+                * first component of a service name especially since
+                * the default is of length 4.
+                */
+               if (krb5_princ_component(telnet_context,ticket->server,0)->length < 256) {
+                   char princ[256];
+                   strncpy(princ,      
+                           krb5_princ_component(telnet_context, ticket->server,0)->data,
+                           krb5_princ_component(telnet_context, ticket->server,0)->length);
+                   princ[krb5_princ_component(telnet_context, 
+                                              ticket->server,0)->length] = '\0';
+                   if (strcmp("host", princ)) {
+                        if(strlen(princ) < sizeof(errbuf) - 39) {
+                            (void) sprintf(errbuf, "incorrect service name: \"%s\" != \"host\"",
+                                           princ);
+                        } else {
+                            (void) sprintf(errbuf, "incorrect service name: principal != \"host\"");
+                        }
+                       goto errout;
+                   }
+               } else {
+                   (void) strcpy(errbuf, "service name too long");
+                   goto errout;
+               }
+
+               r = krb5_auth_con_getauthenticator(telnet_context,
+                                                  auth_context,
+                                                  &authenticator);
+               if (r) {
+                   (void) strcpy(errbuf,
+                                 "krb5_auth_con_getauthenticator failed: ");
+                   errbuf[sizeof(errbuf) - 1] = '\0';
+                   (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+                   goto errout;
+               }
+               if ((ap->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON &&
+                   !authenticator->checksum) {
+                       (void) strcpy(errbuf,
+                               "authenticator is missing required checksum");
+                       goto errout;
+               }
+               if (authenticator->checksum) {
+                   char type_check[2];
+                   krb5_checksum *cksum = authenticator->checksum;
+                   krb5_keyblock *key;
+
+                   type_check[0] = ap->type;
+                   type_check[1] = ap->way;
+
+                   r = krb5_auth_con_getkey(telnet_context, auth_context,
+                                            &key);
+                   if (r) {
+                       (void) strcpy(errbuf, "krb5_auth_con_getkey failed: ");
+                       errbuf[sizeof(errbuf) - 1] = '\0';
+                       (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+                       goto errout;
+                   }
+                   r = krb5_verify_checksum(telnet_context,
+                                            cksum->checksum_type, cksum,
+                                            &type_check, 2, key->contents,
+                                            key->length);
+               /*
+                * Note that krb5_verify_checksum() will fail if a pre-
+                * MIT Kerberos Beta 5 client is attempting to connect
+                * to this server (Beta 6 or later). There is not way to
+                * fix this without compromising encryption. It would be
+                * reasonable to add a -i option to telnetd to ignore
+                * checksums (like in klogind). Such an option is not
+                * present at this time.
+                */
+                   if (r) {
+                       (void) strcpy(errbuf,
+                                     "checksum verification failed: ");
+                       errbuf[sizeof(errbuf) - 1] = '\0';
+                       (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+                       goto errout;
+                   }
+                   krb5_free_keyblock(telnet_context, key);
+               }
+               krb5_free_authenticator(telnet_context, authenticator);
+               if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+                   /* do ap_rep stuff here */
+                   if ((r = krb5_mk_rep(telnet_context, auth_context,
+                                        &outbuf))) {
+                       (void) strcpy(errbuf, "Make reply failed: ");
+                       errbuf[sizeof(errbuf) - 1] = '\0';
+                       (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+                       goto errout;
+                   }
+
+                   Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
+               } 
+               if (krb5_unparse_name(telnet_context, 
+                                     ticket->enc_part2 ->client,
+                                     &name))
+                       name = 0;
+               Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
+               if (auth_debug_mode) {
+                       printf(
+                       "telnetd: Kerberos5 identifies him as ``%s''\r\n",
+                                                       name ? name : "");
+               }
+                auth_finished(ap, AUTH_USER);
+               
+               if (name)
+                   free(name);
+               krb5_auth_con_getremotesubkey(telnet_context, auth_context,
+                                             &newkey);
+               if (session_key) {
+                   krb5_free_keyblock(telnet_context, session_key);
+                   session_key = 0;
+               }
+               if (newkey) {
+                   krb5_copy_keyblock(telnet_context, newkey, &session_key);
+                   krb5_free_keyblock(telnet_context, newkey);
+               } else {
+                   krb5_copy_keyblock(telnet_context,
+                                      ticket->enc_part2->session,
+                                      &session_key);
+               }
+               
+#ifdef ENCRYPTION
+               skey.type = SK_DES;
+               skey.length = 8;
+               skey.data = session_key->contents;
+               encrypt_session_key(&skey, 1);
+#endif
+               break;
+#ifdef FORWARD
+       case KRB_FORWARD:
+               inbuf.length = cnt;
+               inbuf.data = (char *)data;
+               if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context, 
+                       net, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) || 
+                   (r = rd_and_store_for_creds(telnet_context, auth_context,
+                          &inbuf, ticket))) {
+
+                   char errbuf[128];
+                   
+                   (void) strcpy(errbuf, "Read forwarded creds failed: ");
+                   errbuf[sizeof(errbuf) - 1] = '\0';
+                   (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+                   Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
+                   if (auth_debug_mode)
+                     printf(
+                       "telnetd: Could not read forwarded credentials\r\n");
+               }
+               else 
+                 Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
+                 if (auth_debug_mode)
+                   printf("telnetd: Forwarded credentials obtained\r\n");
+               break;
+#endif /* FORWARD */
+       default:
+               if (auth_debug_mode)
+                       printf("telnetd: Unknown Kerberos option %d\r\n",
+                       data[-1]);
+               Data(ap, KRB_REJECT, 0, 0);
+               break;
+       }
+       return;
+       
+    errout:
+       {
+           char eerrbuf[329];
+
+           strcpy(eerrbuf, "telnetd: ");
+           eerrbuf[sizeof(eerrbuf) - 1] = '\0';
+           strncat(eerrbuf, errbuf, sizeof(eerrbuf) - 1 - strlen(eerrbuf));
+           Data(ap, KRB_REJECT, eerrbuf, -1);
+       }
+       if (auth_debug_mode)
+           printf("telnetd: %s\r\n", errbuf);
+       syslog(LOG_ERR, "%s", errbuf);
+       if (auth_context) {
+           krb5_auth_con_free(telnet_context, auth_context);
+           auth_context = 0;
+       }
+       return;
+}
+
+       void
+kerberos5_reply(ap, data, cnt)
+       Authenticator *ap;
+       unsigned char *data;
+       int cnt;
+{
+#ifdef ENCRYPTION
+        Session_Key skey;
+#endif
+       static int mutual_complete = 0;
+
+       if (cnt-- < 1)
+               return;
+       switch (*data++) {
+       case KRB_REJECT:
+               if (cnt > 0) {
+                       printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
+                               cnt, data);
+               } else
+                       printf("[ Kerberos V5 refuses authentication ]\r\n");
+               auth_send_retry();
+               return;
+       case KRB_ACCEPT:
+               if (!mutual_complete) {
+                   if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+                       printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
+                       auth_send_retry();
+                       return;
+                   }
+#ifdef ENCRYPTION
+                   if (session_key) {
+                       skey.type = SK_DES;
+                       skey.length = 8;
+                       skey.data = session_key->contents;
+                       encrypt_session_key(&skey, 0);
+                   }
+#endif /* ENCRYPTION */
+               }
+               if (cnt)
+                   printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
+               else
+                   printf("[ Kerberos V5 accepts you ]\r\n");
+               auth_finished(ap, AUTH_USER);
+#ifdef FORWARD
+               if (forward_flags & OPTS_FORWARD_CREDS)
+                 kerberos5_forward(ap);
+#endif /* FORWARD */
+               break;
+       case KRB_RESPONSE:
+               if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+                   /* the rest of the reply should contain a krb_ap_rep */
+                   krb5_ap_rep_enc_part *reply;
+                   krb5_data inbuf;
+                   krb5_error_code r;
+
+                   inbuf.length = cnt;
+                   inbuf.data = (char *)data;
+
+                   if ((r = krb5_rd_rep(telnet_context, auth_context, &inbuf,
+                                        &reply))) {
+                       printf("[ Mutual authentication failed: %s ]\r\n",
+                              error_message(r));
+                       auth_send_retry();
+                       return;
+                   }
+                   krb5_free_ap_rep_enc_part(telnet_context, reply);
+#ifdef ENCRYPTION
+                   if (session_key) {
+                       skey.type = SK_DES;
+                       skey.length = 8;
+                       skey.data = session_key->contents;
+                       encrypt_session_key(&skey, 0);
+                     }
+#endif /* ENCRYPTION */
+                   mutual_complete = 1;
+               }
+               return;
+#ifdef FORWARD
+       case KRB_FORWARD_ACCEPT:
+               printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
+               return;
+       case KRB_FORWARD_REJECT:
+               printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
+                               cnt, data);
+               return;
+#endif /* FORWARD */
+       default:
+               if (auth_debug_mode)
+                       printf("Unknown Kerberos option %d\r\n", data[-1]);
+               return;
+       }
+       return;
+}
+
+       int
+kerberos5_status(ap, name, level)
+       Authenticator *ap;
+       char *name;
+       int level;
+{
+       if (level < AUTH_USER)
+               return(level);
+
+       if (UserNameRequested &&
+           krb5_kuserok(telnet_context, ticket->enc_part2->client, 
+                        UserNameRequested))
+       {
+               /* the name buffer comes from telnetd/telnetd{-ktd}.c */
+               strncpy(name, UserNameRequested, 255);
+               name[255] = '\0';
+               return(AUTH_VALID);
+       } else
+               return(AUTH_USER);
+}
+
+#define        BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
+#define        ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
+
+       void
+kerberos5_printsub(data, cnt, buf, buflen)
+       unsigned char *data, *buf;
+       int cnt, buflen;
+{
+       char lbuf[32];
+       register int i;
+
+       buf[buflen-1] = '\0';           /* make sure its NULL terminated */
+       buflen -= 1;
+
+       switch(data[3]) {
+       case KRB_REJECT:                /* Rejected (reason might follow) */
+               strncpy((char *)buf, " REJECT ", buflen);
+               goto common;
+
+       case KRB_ACCEPT:                /* Accepted (name might follow) */
+               strncpy((char *)buf, " ACCEPT ", buflen);
+       common:
+               BUMP(buf, buflen);
+               if (cnt <= 4)
+                       break;
+               ADDC(buf, buflen, '"');
+               for (i = 4; i < cnt; i++)
+                       ADDC(buf, buflen, data[i]);
+               ADDC(buf, buflen, '"');
+               ADDC(buf, buflen, '\0');
+               break;
+
+
+       case KRB_AUTH:                  /* Authentication data follows */
+               strncpy((char *)buf, " AUTH", buflen);
+               goto common2;
+
+       case KRB_RESPONSE:
+               strncpy((char *)buf, " RESPONSE", buflen);
+               goto common2;
+
+#ifdef FORWARD
+       case KRB_FORWARD:               /* Forwarded credentials follow */
+               strncpy((char *)buf, " FORWARD", buflen);
+               goto common2;
+
+       case KRB_FORWARD_ACCEPT:               /* Forwarded credentials accepted */
+               strncpy((char *)buf, " FORWARD_ACCEPT", buflen);
+               goto common2;
+
+       case KRB_FORWARD_REJECT:               /* Forwarded credentials rejected */
+                                              /* (reason might follow) */
+               strncpy((char *)buf, " FORWARD_REJECT", buflen);
+               goto common2;
+#endif /* FORWARD */
+
+       default:
+               sprintf(lbuf, " %d (unknown)", data[3]);
+               strncpy((char *)buf, lbuf, buflen);
+       common2:
+               BUMP(buf, buflen);
+               for (i = 4; i < cnt; i++) {
+                       sprintf(lbuf, " %d", data[i]);
+                       strncpy((char *)buf, lbuf, buflen);
+                       BUMP(buf, buflen);
+               }
+               break;
+       }
+}
+
+#ifdef FORWARD
+
+void
+kerberos5_forward(ap)
+     Authenticator *ap;
+{
+    krb5_error_code r;
+    krb5_ccache ccache;
+    krb5_principal client = 0;
+    krb5_principal server = 0;
+    krb5_data forw_creds;
+
+    forw_creds.data = 0;
+
+    if ((r = krb5_cc_default(telnet_context, &ccache))) {
+       if (auth_debug_mode) 
+           printf("Kerberos V5: could not get default ccache - %s\r\n",
+                  error_message(r));
+       return;
+    }
+
+    if ((r = krb5_cc_get_principal(telnet_context, ccache, &client))) {
+       if (auth_debug_mode) 
+           printf("Kerberos V5: could not get default principal - %s\r\n",
+                  error_message(r));
+       goto cleanup;
+    }
+
+    if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName, "host",
+                                    KRB5_NT_SRV_HST, &server))) {
+       if (auth_debug_mode) 
+           printf("Kerberos V5: could not make server principal - %s\r\n",
+                  error_message(r));
+       goto cleanup;
+    }
+
+    if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context, net,
+                           KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) {
+       if (auth_debug_mode)
+           printf("Kerberos V5: could not gen local full address - %s\r\n",
+                   error_message(r));
+       goto cleanup;
+    }
+
+    if ((r = krb5_fwd_tgt_creds(telnet_context, auth_context, 0, client,
+                               server, ccache,
+                               forward_flags & OPTS_FORWARDABLE_CREDS,
+                               &forw_creds))) {
+       if (auth_debug_mode) 
+           printf("Kerberos V5: error getting forwarded creds - %s\r\n",
+                  error_message(r));
+       goto cleanup;
+    }
+    
+    /* Send forwarded credentials */
+    if (!Data(ap, KRB_FORWARD, forw_creds.data, forw_creds.length)) {
+       if (auth_debug_mode)
+           printf("Not enough room for authentication data\r\n");
+    } else {
+       if (auth_debug_mode)
+           printf("Forwarded local Kerberos V5 credentials to server\r\n");
+    }
+    
+cleanup:
+    if (client)
+       krb5_free_principal(telnet_context, client);
+    if (server)
+       krb5_free_principal(telnet_context, server);
+    if (forw_creds.data)
+       free(forw_creds.data);
+    krb5_cc_close(telnet_context, ccache);
+}
+#endif /* FORWARD */
+
+#endif /* KRB5 */
diff --git a/lib/libtelnet/key-proto.h b/lib/libtelnet/key-proto.h
new file mode 100644 (file)
index 0000000..1e4d772
--- /dev/null
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)key-proto.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * $FreeBSD: src/crypto/telnet/libtelnet/key-proto.h,v 1.1.1.1.8.1 2002/04/13 10:59:07 markm Exp $
+ */
+
+#ifndef        __KEY_PROTO__
+#define        __KEY_PROTO__
+
+int key_file_exists(void);
+void key_lookup(unsigned char *, Block);
+void key_stream_init(Block, Block, int);
+unsigned char key_stream(int, int);
+#endif
diff --git a/lib/libtelnet/krb4encpwd.c b/lib/libtelnet/krb4encpwd.c
new file mode 100644 (file)
index 0000000..6af7bf6
--- /dev/null
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/krb4encpwd.c,v 1.3.2.1 2002/04/13 10:59:07 markm Exp $");
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)krb4encpwd.c 8.3 (Berkeley) 5/30/95";
+#endif /* not lint */
+
+
+#ifdef KRB4_ENCPWD
+/*
+ * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION
+ * ALL RIGHTS RESERVED
+ *
+ * "Digital Equipment Corporation authorizes the reproduction,
+ * distribution and modification of this software subject to the following
+ * restrictions:
+ *
+ * 1.  Any partial or whole copy of this software, or any modification
+ * thereof, must include this copyright notice in its entirety.
+ *
+ * 2.  This software is supplied "as is" with no warranty of any kind,
+ * expressed or implied, for any purpose, including any warranty of fitness
+ * or merchantibility.  DIGITAL assumes no responsibility for the use or
+ * reliability of this software, nor promises to provide any form of
+ * support for it on any basis.
+ *
+ * 3.  Distribution of this software is authorized only if no profit or
+ * remuneration of any kind is received in exchange for such distribution.
+ *
+ * 4.  This software produces public key authentication certificates
+ * bearing an expiration date established by DIGITAL and RSA Data
+ * Security, Inc.  It may cease to generate certificates after the expiration
+ * date.  Any modification of this software that changes or defeats
+ * the expiration date or its effect is unauthorized.
+ *
+ * 5.  Software that will renew or extend the expiration date of
+ * authentication certificates produced by this software may be obtained
+ * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA
+ * 94065, (415)595-8782, or from DIGITAL"
+ *
+ */
+
+#include <sys/types.h>
+#include <openssl/des.h>
+#include <arpa/telnet.h>
+#include <krb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "encrypt.h"
+#include "auth.h"
+#include "misc.h"
+
+int krb_mk_encpwd_req(KTEXT, char *, char *, char *, char *, char *, char *);
+int krb_rd_encpwd_req(KTEXT, char *, char *, u_long, AUTH_DAT *, char *, char *, char *, char *);
+
+extern auth_debug_mode;
+
+static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
+                                       AUTHTYPE_KRB4_ENCPWD, };
+static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
+                                       TELQUAL_NAME, };
+
+#define        KRB4_ENCPWD_AUTH        0       /* Authentication data follows */
+#define        KRB4_ENCPWD_REJECT      1       /* Rejected (reason might follow) */
+#define KRB4_ENCPWD_ACCEPT     2       /* Accepted */
+#define        KRB4_ENCPWD_CHALLENGE   3       /* Challenge for mutual auth. */
+#define        KRB4_ENCPWD_ACK         4       /* Acknowledge */
+
+#define KRB_SERVICE_NAME    "rcmd"
+
+static KTEXT_ST auth;
+static char name[ANAME_SZ];
+static char user_passwd[ANAME_SZ];
+static AUTH_DAT adat = { 0 };
+#ifdef ENCRYPTION
+static Block   session_key     = { 0 };
+#endif /* ENCRYPTION */
+static char  challenge[REALM_SZ];
+
+       static int
+Data(ap, type, d, c)
+       Authenticator *ap;
+       int type;
+       void *d;
+       int c;
+{
+       unsigned char *p = str_data + 4;
+       unsigned char *cd = (unsigned char *)d;
+
+       if (c == -1)
+               c = strlen((char *)cd);
+
+       if (0) {
+               printf("%s:%d: [%d] (%d)",
+                       str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
+                       str_data[3],
+                       type, c);
+               printd(d, c);
+               printf("\r\n");
+       }
+       *p++ = ap->type;
+       *p++ = ap->way;
+       *p++ = type;
+       while (c-- > 0) {
+               if ((*p++ = *cd++) == IAC)
+                       *p++ = IAC;
+       }
+       *p++ = IAC;
+       *p++ = SE;
+       if (str_data[3] == TELQUAL_IS)
+               printsub('>', &str_data[2], p - (&str_data[2]));
+       return(net_write(str_data, p - str_data));
+}
+
+       int
+krb4encpwd_init(ap, server)
+       Authenticator *ap;
+       int server;
+{
+       char hostname[80], *cp, *realm;
+       C_Block skey;
+
+       if (server) {
+               str_data[3] = TELQUAL_REPLY;
+       } else {
+               str_data[3] = TELQUAL_IS;
+               gethostname(hostname, sizeof(hostname));
+               realm = krb_realmofhost(hostname);
+               cp = strchr(hostname, '.');
+               if (*cp != NULL) *cp = NULL;
+               if (read_service_key(KRB_SERVICE_NAME, hostname, realm, 0,
+                                       KEYFILE, (char *)skey)) {
+                 return(0);
+               }
+       }
+       return(1);
+}
+
+       int
+krb4encpwd_send(ap)
+       Authenticator *ap;
+{
+
+       printf("[ Trying KRB4ENCPWD ... ]\n");
+       if (!UserNameRequested) {
+               return(0);
+       }
+       if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
+               return(0);
+       }
+
+       if (!Data(ap, KRB4_ENCPWD_ACK, (void *)NULL, 0)) {
+               return(0);
+       }
+
+       return(1);
+}
+
+       void
+krb4encpwd_is(ap, data, cnt)
+       Authenticator *ap;
+       unsigned char *data;
+       int cnt;
+{
+       Session_Key skey;
+       Block datablock;
+       char  r_passwd[ANAME_SZ], r_user[ANAME_SZ];
+       char  lhostname[ANAME_SZ], *cp;
+       int r;
+       time_t now;
+
+       if (cnt-- < 1)
+               return;
+       switch (*data++) {
+       case KRB4_ENCPWD_AUTH:
+               memmove((void *)auth.dat, (void *)data, auth.length = cnt);
+
+               gethostname(lhostname, sizeof(lhostname));
+               if ((cp = strchr(lhostname, '.')) != 0)  *cp = '\0';
+
+               if (r = krb_rd_encpwd_req(&auth, KRB_SERVICE_NAME, lhostname, 0, &adat, NULL, challenge, r_user, r_passwd)) {
+                       Data(ap, KRB4_ENCPWD_REJECT, (void *)"Auth failed", -1);
+                       auth_finished(ap, AUTH_REJECT);
+                       return;
+               }
+               auth_encrypt_userpwd(r_passwd);
+               if (passwdok(UserNameRequested, UserPassword) == 0) {
+                 /*
+                  *  illegal username and password
+                  */
+                 Data(ap, KRB4_ENCPWD_REJECT, (void *)"Illegal password", -1);
+                 auth_finished(ap, AUTH_REJECT);
+                 return;
+               }
+
+               memmove((void *)session_key, (void *)adat.session, sizeof(Block));
+               Data(ap, KRB4_ENCPWD_ACCEPT, (void *)0, 0);
+               auth_finished(ap, AUTH_USER);
+               break;
+
+       case KRB4_ENCPWD_CHALLENGE:
+               /*
+                *  Take the received random challenge text and save
+                *  for future authentication.
+                */
+               memmove((void *)challenge, (void *)data, sizeof(Block));
+               break;
+
+
+       case KRB4_ENCPWD_ACK:
+               /*
+                *  Receive ack, if mutual then send random challenge
+                */
+
+               /*
+                * If we are doing mutual authentication, get set up to send
+                * the challenge, and verify it when the response comes back.
+                */
+
+               if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+                 register int i;
+
+                 time(&now);
+                 sprintf(challenge, "%x", now);
+                 Data(ap, KRB4_ENCPWD_CHALLENGE, (void *)challenge, strlen(challenge));
+               }
+               break;
+
+       default:
+               Data(ap, KRB4_ENCPWD_REJECT, 0, 0);
+               break;
+       }
+}
+
+
+       void
+krb4encpwd_reply(ap, data, cnt)
+       Authenticator *ap;
+       unsigned char *data;
+       int cnt;
+{
+       Session_Key skey;
+       KTEXT_ST krb_token;
+       Block enckey;
+       CREDENTIALS cred;
+       int r;
+       char    randchal[REALM_SZ], instance[ANAME_SZ], *cp;
+       char    hostname[80], *realm;
+
+       if (cnt-- < 1)
+               return;
+       switch (*data++) {
+       case KRB4_ENCPWD_REJECT:
+               if (cnt > 0) {
+                       printf("[ KRB4_ENCPWD refuses authentication because %.*s ]\r\n",
+                               cnt, data);
+               } else
+                       printf("[ KRB4_ENCPWD refuses authentication ]\r\n");
+               auth_send_retry();
+               return;
+       case KRB4_ENCPWD_ACCEPT:
+               printf("[ KRB4_ENCPWD accepts you ]\n");
+               auth_finished(ap, AUTH_USER);
+               return;
+       case KRB4_ENCPWD_CHALLENGE:
+               /*
+                * Verify that the response to the challenge is correct.
+                */
+
+               gethostname(hostname, sizeof(hostname));
+               realm = krb_realmofhost(hostname);
+               memmove((void *)challenge, (void *)data, cnt);
+               memset(user_passwd, 0, sizeof(user_passwd));
+               local_des_read_pw_string(user_passwd, sizeof(user_passwd)-1, "Password: ", 0);
+               UserPassword = user_passwd;
+               Challenge = challenge;
+               strcpy(instance, RemoteHostName);
+               if ((cp = strchr(instance, '.')) != 0)  *cp = '\0';
+
+               if (r = krb_mk_encpwd_req(&krb_token, KRB_SERVICE_NAME, instance, realm, Challenge, UserNameRequested, user_passwd)) {
+                 krb_token.length = 0;
+               }
+
+               if (!Data(ap, KRB4_ENCPWD_AUTH, (void *)krb_token.dat, krb_token.length)) {
+                 return;
+               }
+
+               break;
+
+       default:
+               return;
+       }
+}
+
+       int
+krb4encpwd_status(ap, name, level)
+       Authenticator *ap;
+       char *name;
+       int level;
+{
+
+       if (level < AUTH_USER)
+               return(level);
+
+       if (UserNameRequested && passwdok(UserNameRequested, UserPassword)) {
+               strcpy(name, UserNameRequested);
+               return(AUTH_VALID);
+       } else {
+               return(AUTH_USER);
+       }
+}
+
+#define        BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
+#define        ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
+
+       void
+krb4encpwd_printsub(data, cnt, buf, buflen)
+       unsigned char *data, *buf;
+       int cnt, buflen;
+{
+       char lbuf[32];
+       register int i;
+
+       buf[buflen-1] = '\0';           /* make sure its NULL terminated */
+       buflen -= 1;
+
+       switch(data[3]) {
+       case KRB4_ENCPWD_REJECT:        /* Rejected (reason might follow) */
+               strncpy((char *)buf, " REJECT ", buflen);
+               goto common;
+
+       case KRB4_ENCPWD_ACCEPT:        /* Accepted (name might follow) */
+               strncpy((char *)buf, " ACCEPT ", buflen);
+       common:
+               BUMP(buf, buflen);
+               if (cnt <= 4)
+                       break;
+               ADDC(buf, buflen, '"');
+               for (i = 4; i < cnt; i++)
+                       ADDC(buf, buflen, data[i]);
+               ADDC(buf, buflen, '"');
+               ADDC(buf, buflen, '\0');
+               break;
+
+       case KRB4_ENCPWD_AUTH:          /* Authentication data follows */
+               strncpy((char *)buf, " AUTH", buflen);
+               goto common2;
+
+       case KRB4_ENCPWD_CHALLENGE:
+               strncpy((char *)buf, " CHALLENGE", buflen);
+               goto common2;
+
+       case KRB4_ENCPWD_ACK:
+               strncpy((char *)buf, " ACK", buflen);
+               goto common2;
+
+       default:
+               sprintf(lbuf, " %d (unknown)", data[3]);
+               strncpy((char *)buf, lbuf, buflen);
+       common2:
+               BUMP(buf, buflen);
+               for (i = 4; i < cnt; i++) {
+                       sprintf(lbuf, " %d", data[i]);
+                       strncpy((char *)buf, lbuf, buflen);
+                       BUMP(buf, buflen);
+               }
+               break;
+       }
+}
+
+int passwdok(name, passwd)
+char *name, *passwd;
+{
+  char *crypt();
+  char *salt, *p;
+  struct passwd *pwd;
+  int   passwdok_status = 0;
+
+  if (pwd = getpwnam(name))
+    salt = pwd->pw_passwd;
+  else salt = "xx";
+
+  p = crypt(passwd, salt);
+
+  if (pwd && !strcmp(p, pwd->pw_passwd)) {
+    passwdok_status = 1;
+  } else passwdok_status = 0;
+  return(passwdok_status);
+}
+
+#endif
diff --git a/lib/libtelnet/libtelnet.plist b/lib/libtelnet/libtelnet.plist
new file mode 100644 (file)
index 0000000..2a9597a
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+       <dict>
+               <key>OpenSourceImportDate</key>
+               <string>2002-05-20</string>
+               <key>OpenSourceLicense</key>
+               <string>BSD</string>
+               <key>OpenSourceLicenseFile</key>
+               <string>libtelnet.txt</string>
+               <key>OpenSourceProject</key>
+               <string>libtelnet</string>
+               <key>OpenSourceVersion</key>
+               <string>2002-05-20</string>
+               <key>OpenSourceCVS</key>
+               <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co lib/libtelnet</string>
+               <key>OpenSourceWebsiteURL</key>
+               <string>http://www.freebsd.org/</string>
+       </dict>
+</array>
+</plist>
diff --git a/lib/libtelnet/libtelnet.xcodeproj/project.pbxproj b/lib/libtelnet/libtelnet.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..d409c11
--- /dev/null
@@ -0,0 +1,313 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 45;
+       objects = {
+
+/* Begin PBXBuildFile section */
+               FD32B4470FF01C38000846C1 /* libtelnet.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD99230C0FEB057C00E57170 /* libtelnet.plist */; };
+               FD32B44C0FF01C49000846C1 /* LICENSE in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD99230D0FEB057C00E57170 /* LICENSE */; };
+               FD9923170FEB057C00E57170 /* auth-proto.h in Headers */ = {isa = PBXBuildFile; fileRef = FD9922FC0FEB057C00E57170 /* auth-proto.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               FD9923180FEB057C00E57170 /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9922FD0FEB057C00E57170 /* auth.c */; };
+               FD9923190FEB057C00E57170 /* auth.h in Headers */ = {isa = PBXBuildFile; fileRef = FD9922FE0FEB057C00E57170 /* auth.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               FD99231A0FEB057C00E57170 /* enc_des.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923010FEB057C00E57170 /* enc_des.c */; };
+               FD99231B0FEB057C00E57170 /* enc-proto.h in Headers */ = {isa = PBXBuildFile; fileRef = FD9923020FEB057C00E57170 /* enc-proto.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               FD99231C0FEB057C00E57170 /* encrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923030FEB057C00E57170 /* encrypt.c */; };
+               FD99231D0FEB057C00E57170 /* encrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = FD9923040FEB057C00E57170 /* encrypt.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               FD99231E0FEB057C00E57170 /* forward.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923050FEB057C00E57170 /* forward.c */; };
+               FD99231F0FEB057C00E57170 /* genget.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923060FEB057C00E57170 /* genget.c */; };
+               FD9923200FEB057C00E57170 /* getent.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923070FEB057C00E57170 /* getent.c */; };
+               FD9923210FEB057C00E57170 /* kerberos.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923080FEB057C00E57170 /* kerberos.c */; };
+               FD9923220FEB057C00E57170 /* kerberos5.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923090FEB057C00E57170 /* kerberos5.c */; };
+               FD9923240FEB057C00E57170 /* krb4encpwd.c in Sources */ = {isa = PBXBuildFile; fileRef = FD99230B0FEB057C00E57170 /* krb4encpwd.c */; };
+               FD9923260FEB057C00E57170 /* misc-proto.h in Headers */ = {isa = PBXBuildFile; fileRef = FD99230F0FEB057C00E57170 /* misc-proto.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               FD9923270FEB057C00E57170 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923100FEB057C00E57170 /* misc.c */; };
+               FD9923280FEB057C00E57170 /* misc.h in Headers */ = {isa = PBXBuildFile; fileRef = FD9923110FEB057C00E57170 /* misc.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               FD99232B0FEB057C00E57170 /* read_password.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923140FEB057C00E57170 /* read_password.c */; };
+               FD99232C0FEB057C00E57170 /* rsaencpwd.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923150FEB057C00E57170 /* rsaencpwd.c */; };
+               FD99232D0FEB057C00E57170 /* sra.c in Sources */ = {isa = PBXBuildFile; fileRef = FD9923160FEB057C00E57170 /* sra.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+               FD32B4460FF01C2D000846C1 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/local/OpenSourceVersions;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               FD32B4470FF01C38000846C1 /* libtelnet.plist in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               FD32B44B0FF01C41000846C1 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/local/OpenSourceLicenses;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               FD32B44C0FF01C49000846C1 /* LICENSE in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+               D2AAC046055464E500DB518D /* libtelnet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtelnet.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               FD9922FC0FEB057C00E57170 /* auth-proto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "auth-proto.h"; sourceTree = "<group>"; };
+               FD9922FD0FEB057C00E57170 /* auth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = auth.c; sourceTree = "<group>"; };
+               FD9922FE0FEB057C00E57170 /* auth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = auth.h; sourceTree = "<group>"; };
+               FD9923010FEB057C00E57170 /* enc_des.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = enc_des.c; sourceTree = "<group>"; };
+               FD9923020FEB057C00E57170 /* enc-proto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "enc-proto.h"; sourceTree = "<group>"; };
+               FD9923030FEB057C00E57170 /* encrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = encrypt.c; sourceTree = "<group>"; };
+               FD9923040FEB057C00E57170 /* encrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = encrypt.h; sourceTree = "<group>"; };
+               FD9923050FEB057C00E57170 /* forward.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = forward.c; sourceTree = "<group>"; };
+               FD9923060FEB057C00E57170 /* genget.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = genget.c; sourceTree = "<group>"; };
+               FD9923070FEB057C00E57170 /* getent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = getent.c; sourceTree = "<group>"; };
+               FD9923080FEB057C00E57170 /* kerberos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kerberos.c; sourceTree = "<group>"; };
+               FD9923090FEB057C00E57170 /* kerberos5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kerberos5.c; sourceTree = "<group>"; };
+               FD99230A0FEB057C00E57170 /* key-proto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "key-proto.h"; sourceTree = "<group>"; };
+               FD99230B0FEB057C00E57170 /* krb4encpwd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = krb4encpwd.c; sourceTree = "<group>"; };
+               FD99230C0FEB057C00E57170 /* libtelnet.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = libtelnet.plist; sourceTree = "<group>"; };
+               FD99230D0FEB057C00E57170 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
+               FD99230F0FEB057C00E57170 /* misc-proto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "misc-proto.h"; sourceTree = "<group>"; };
+               FD9923100FEB057C00E57170 /* misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+               FD9923110FEB057C00E57170 /* misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = misc.h; sourceTree = "<group>"; };
+               FD9923120FEB057C00E57170 /* pk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pk.c; sourceTree = "<group>"; };
+               FD9923130FEB057C00E57170 /* pk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pk.h; sourceTree = "<group>"; };
+               FD9923140FEB057C00E57170 /* read_password.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = read_password.c; sourceTree = "<group>"; };
+               FD9923150FEB057C00E57170 /* rsaencpwd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rsaencpwd.c; sourceTree = "<group>"; };
+               FD9923160FEB057C00E57170 /* sra.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sra.c; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               D289987405E68DCB004EDB86 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               08FB7794FE84155DC02AAC07 /* libtelnet */ = {
+                       isa = PBXGroup;
+                       children = (
+                               08FB7795FE84155DC02AAC07 /* Source */,
+                               C6A0FF2B0290797F04C91782 /* Documentation */,
+                               1AB674ADFE9D54B511CA2CBB /* Products */,
+                       );
+                       name = libtelnet;
+                       sourceTree = "<group>";
+               };
+               08FB7795FE84155DC02AAC07 /* Source */ = {
+                       isa = PBXGroup;
+                       children = (
+                               FD9922FC0FEB057C00E57170 /* auth-proto.h */,
+                               FD9922FE0FEB057C00E57170 /* auth.h */,
+                               FD9923020FEB057C00E57170 /* enc-proto.h */,
+                               FD9923040FEB057C00E57170 /* encrypt.h */,
+                               FD99230A0FEB057C00E57170 /* key-proto.h */,
+                               FD99230F0FEB057C00E57170 /* misc-proto.h */,
+                               FD9923110FEB057C00E57170 /* misc.h */,
+                               FD9923130FEB057C00E57170 /* pk.h */,
+                               FD9922FD0FEB057C00E57170 /* auth.c */,
+                               FD9923010FEB057C00E57170 /* enc_des.c */,
+                               FD9923030FEB057C00E57170 /* encrypt.c */,
+                               FD9923050FEB057C00E57170 /* forward.c */,
+                               FD9923060FEB057C00E57170 /* genget.c */,
+                               FD9923070FEB057C00E57170 /* getent.c */,
+                               FD9923080FEB057C00E57170 /* kerberos.c */,
+                               FD9923090FEB057C00E57170 /* kerberos5.c */,
+                               FD99230B0FEB057C00E57170 /* krb4encpwd.c */,
+                               FD9923100FEB057C00E57170 /* misc.c */,
+                               FD9923120FEB057C00E57170 /* pk.c */,
+                               FD9923140FEB057C00E57170 /* read_password.c */,
+                               FD9923150FEB057C00E57170 /* rsaencpwd.c */,
+                               FD9923160FEB057C00E57170 /* sra.c */,
+                       );
+                       name = Source;
+                       sourceTree = "<group>";
+               };
+               1AB674ADFE9D54B511CA2CBB /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               D2AAC046055464E500DB518D /* libtelnet.a */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               C6A0FF2B0290797F04C91782 /* Documentation */ = {
+                       isa = PBXGroup;
+                       children = (
+                               FD99230C0FEB057C00E57170 /* libtelnet.plist */,
+                               FD99230D0FEB057C00E57170 /* LICENSE */,
+                       );
+                       name = Documentation;
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+               D2AAC043055464E500DB518D /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FD9923190FEB057C00E57170 /* auth.h in Headers */,
+                               FD9923170FEB057C00E57170 /* auth-proto.h in Headers */,
+                               FD99231D0FEB057C00E57170 /* encrypt.h in Headers */,
+                               FD99231B0FEB057C00E57170 /* enc-proto.h in Headers */,
+                               FD9923280FEB057C00E57170 /* misc.h in Headers */,
+                               FD9923260FEB057C00E57170 /* misc-proto.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+               D2AAC045055464E500DB518D /* libtelnet */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "libtelnet" */;
+                       buildPhases = (
+                               D2AAC043055464E500DB518D /* Headers */,
+                               D2AAC044055464E500DB518D /* Sources */,
+                               D289987405E68DCB004EDB86 /* Frameworks */,
+                               FD32B4460FF01C2D000846C1 /* CopyFiles */,
+                               FD32B44B0FF01C41000846C1 /* CopyFiles */,
+                               FD32B4530FF01CD9000846C1 /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = libtelnet;
+                       productName = libtelnet;
+                       productReference = D2AAC046055464E500DB518D /* libtelnet.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               08FB7793FE84155DC02AAC07 /* Project object */ = {
+                       isa = PBXProject;
+                       buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "libtelnet" */;
+                       compatibilityVersion = "Xcode 3.1";
+                       hasScannedForEncodings = 1;
+                       mainGroup = 08FB7794FE84155DC02AAC07 /* libtelnet */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       targets = (
+                               D2AAC045055464E500DB518D /* libtelnet */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+               FD32B4530FF01CD9000846C1 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "set -ex\nmv ${DSTROOT}/usr/local/OpenSourceLicenses/LICENSE ${DSTROOT}/usr/local/OpenSourceLicenses/libtelnet.txt";
+                       showEnvVarsInLog = 0;
+               };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               D2AAC044055464E500DB518D /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               FD9923180FEB057C00E57170 /* auth.c in Sources */,
+                               FD99231A0FEB057C00E57170 /* enc_des.c in Sources */,
+                               FD99231C0FEB057C00E57170 /* encrypt.c in Sources */,
+                               FD99231E0FEB057C00E57170 /* forward.c in Sources */,
+                               FD99231F0FEB057C00E57170 /* genget.c in Sources */,
+                               FD9923200FEB057C00E57170 /* getent.c in Sources */,
+                               FD9923210FEB057C00E57170 /* kerberos.c in Sources */,
+                               FD9923220FEB057C00E57170 /* kerberos5.c in Sources */,
+                               FD9923240FEB057C00E57170 /* krb4encpwd.c in Sources */,
+                               FD9923270FEB057C00E57170 /* misc.c in Sources */,
+                               FD99232B0FEB057C00E57170 /* read_password.c in Sources */,
+                               FD99232C0FEB057C00E57170 /* rsaencpwd.c in Sources */,
+                               FD99232D0FEB057C00E57170 /* sra.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+               1DEB91ED08733DB70010E9CD /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = /usr/local/lib;
+                               PRODUCT_NAME = telnet;
+                               PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/libtelnet;
+                       };
+                       name = Release;
+               };
+               1DEB91F108733DB70010E9CD /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               DEAD_CODE_STRIPPING = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "__FBSDID=__RCSID",
+                                       HAS_CGETENT,
+                                       AUTHENTICATION,
+                                       RSA,
+                                       KRB5,
+                                       FORWARD,
+                                       HAVE_STDLIB_H,
+                               );
+                               "GCC_PREPROCESSOR_DEFINITIONS[sdk=iphone*]" = (
+                                       "__FBSDID=__RCSID",
+                                       HAS_CGETENT,
+                                       AUTHENTICATION,
+                                       RSA,
+                                       FORWARD,
+                                       HAVE_STDLIB_H,
+                               );
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               PREBINDING = NO;
+                               USE_HEADERMAP = NO;
+                       };
+                       name = Release;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "libtelnet" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1DEB91ED08733DB70010E9CD /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "libtelnet" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1DEB91F108733DB70010E9CD /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/lib/libtelnet/misc-proto.h b/lib/libtelnet/misc-proto.h
new file mode 100644 (file)
index 0000000..511a1bf
--- /dev/null
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)misc-proto.h        8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/crypto/telnet/libtelnet/misc-proto.h,v 1.1.1.1.8.1 2002/04/13 10:59:07 markm Exp $
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef        __MISC_PROTO__
+#define        __MISC_PROTO__
+
+void auth_encrypt_init(char *, char *, const char *, int);
+void auth_encrypt_connect(int);
+void printd(const unsigned char *, int);
+
+int isprefix(char *, const char *);
+char **genget(char *, char **, int);
+int Ambiguous(char **);
+
+int getent(char *, const char *);
+char *Getstr(const char *, char **);
+
+/*
+ * These functions are imported from the application
+ */
+int net_write(unsigned char *, int);
+void net_encrypt(void);
+int telnet_spin(void);
+char *telnet_getenv(char *);
+char *telnet_gets(const char *, char *, int, int);
+void printsub(char, unsigned char *, int);
+#endif
diff --git a/lib/libtelnet/misc.c b/lib/libtelnet/misc.c
new file mode 100644 (file)
index 0000000..6eac32e
--- /dev/null
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/misc.c,v 1.2.8.2 2002/04/13 10:59:07 markm Exp $");
+#endif
+
+#ifndef __unused
+#define __unused        __attribute__((__unused__))
+#endif
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)misc.c       8.1 (Berkeley) 6/4/93";
+#endif
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "misc.h"
+#ifdef AUTHENTICATION
+#include "auth.h"
+#endif
+#ifdef ENCRYPTION
+#include "encrypt.h"
+#endif /* ENCRYPTION */
+
+char *RemoteHostName;
+char *LocalHostName;
+char *UserNameRequested = 0;
+int ConnectedCount = 0;
+
+#ifndef AUTHENTICATION
+#define undef1 __unused
+#else
+#define undef1
+#endif
+
+void
+auth_encrypt_init(char *local, char *remote, const char *name undef1, int server undef1)
+{
+       RemoteHostName = remote;
+       LocalHostName = local;
+#ifdef AUTHENTICATION
+       auth_init(name, server);
+#endif
+#ifdef ENCRYPTION
+       encrypt_init(name, server);
+#endif /* ENCRYPTION */
+       if (UserNameRequested) {
+               free(UserNameRequested);
+               UserNameRequested = 0;
+       }
+}
+
+#ifdef ENCRYPTION
+void
+auth_encrypt_user(char *name)
+{
+       if (UserNameRequested)
+               free(UserNameRequested);
+       UserNameRequested = name ? strdup(name) : 0;
+}
+
+void
+auth_encrypt_connect(int cnt __unused)
+{
+}
+#endif /* ENCRYPTION */
+
+void
+printd(const unsigned char *data, int cnt)
+{
+       if (cnt > 16)
+               cnt = 16;
+       while (cnt-- > 0) {
+               printf(" %02x", *data);
+               ++data;
+       }
+}
diff --git a/lib/libtelnet/misc.h b/lib/libtelnet/misc.h
new file mode 100644 (file)
index 0000000..41ffa7f
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)misc.h      8.1 (Berkeley) 6/4/93
+ */
+
+extern char *UserNameRequested;
+extern char *LocalHostName;
+extern char *RemoteHostName;
+extern int ConnectedCount;
+extern int ReservedPort;
+
+#include "misc-proto.h"
diff --git a/lib/libtelnet/pk.c b/lib/libtelnet/pk.c
new file mode 100644 (file)
index 0000000..56444ed
--- /dev/null
@@ -0,0 +1,269 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *      Dave Safford.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/pk.c,v 1.2.2.3 2002/04/13 10:59:07 markm Exp $");
+
+/* public key routines */
+/* functions:
+       genkeys(char *public, char *secret)
+       common_key(char *secret, char *public, desData *deskey)
+        pk_encode(char *in, *out, DesData *deskey);
+        pk_decode(char *in, *out, DesData *deskey);
+      where
+       char public[HEXKEYBYTES + 1];
+       char secret[HEXKEYBYTES + 1];
+ */
+
+#include <sys/time.h>
+#include <openssl/des.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mp.h"
+#include "pk.h"
+static void adjust(char keyout[HEXKEYBYTES+1], char *keyin);
+
+/*
+ * Choose top 128 bits of the common key to use as our idea key.
+ */
+static void
+extractideakey(MINT *ck, IdeaData *ideakey)
+{
+        MINT *a;
+        MINT *z;
+        short r;
+        int i;
+        short base = (1 << 8);
+        char *k;
+
+        z = itom(0);
+        a = itom(0);
+        madd(ck, z, a);
+        for (i = 0; i < ((KEYSIZE - 128) / 8); i++) {
+                sdiv(a, base, a, &r);
+        }
+        k = (char *)ideakey;
+        for (i = 0; i < 16; i++) {
+                sdiv(a, base, a, &r);
+                *k++ = r;
+        }
+       mfree(z);
+        mfree(a);
+}
+
+/*
+ * Choose middle 64 bits of the common key to use as our des key, possibly
+ * overwriting the lower order bits by setting parity. 
+ */
+static void
+extractdeskey(MINT *ck, DesData *deskey)
+{
+        MINT *a;
+        MINT *z;
+        short r;
+        int i;
+        short base = (1 << 8);
+        char *k;
+
+        z = itom(0);
+        a = itom(0);
+        madd(ck, z, a);
+        for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
+                sdiv(a, base, a, &r);
+        }
+        k = (char *)deskey;
+        for (i = 0; i < 8; i++) {
+                sdiv(a, base, a, &r);
+                *k++ = r;
+        }
+       mfree(z);
+        mfree(a);
+}
+
+/*
+ * get common key from my secret key and his public key
+ */
+void
+common_key(char *xsecret, char *xpublic, IdeaData *ideakey, DesData *deskey)
+{
+        MINT *public;
+        MINT *secret;
+        MINT *common;
+       MINT *modulus = xtom(HEXMODULUS);
+
+        public = xtom(xpublic);
+        secret = xtom(xsecret);
+        common = itom(0);
+        pow(public, secret, modulus, common);
+        extractdeskey(common, deskey);
+        extractideakey(common, ideakey);
+       des_set_odd_parity(deskey);
+        mfree(common);
+        mfree(secret);
+        mfree(public);
+       mfree(modulus);
+}
+
+/*
+ * Generate a seed
+ */
+static void
+getseed(char *seed, int seedsize)
+{
+       int i;
+
+       srandomdev();
+       for (i = 0; i < seedsize; i++) {
+               seed[i] = random() & 0xff;
+       }
+}
+
+/*
+ * Generate a random public/secret key pair
+ */
+void
+genkeys(char *public, char *secret)
+{
+        size_t i;
+#       define BASEBITS (8*sizeof(short) - 1)
+#       define BASE (1 << BASEBITS)
+        MINT *pk = itom(0);
+        MINT *sk = itom(0);
+        MINT *tmp;
+        MINT *base = itom(BASE);
+        MINT *root = itom(PROOT);
+        MINT *modulus = xtom(HEXMODULUS);
+        short r;
+        unsigned short seed[KEYSIZE/BASEBITS + 1];
+        char *xkey;
+
+        getseed((char *)seed, sizeof(seed));    
+        for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
+                r = seed[i] % BASE;
+                tmp = itom(r);
+                mult(sk, base, sk);
+                madd(sk, tmp, sk);
+                mfree(tmp);  
+        }
+        tmp = itom(0);
+        mdiv(sk, modulus, tmp, sk);
+        mfree(tmp);
+        pow(root, sk, modulus, pk); 
+        xkey = mtox(sk);   
+        adjust(secret, xkey);
+        xkey = mtox(pk);
+        adjust(public, xkey);
+        mfree(sk);
+        mfree(base);
+        mfree(pk);
+        mfree(root);
+        mfree(modulus);
+} 
+
+/*
+ * Adjust the input key so that it is 0-filled on the left
+ */
+static void
+adjust(char keyout[HEXKEYBYTES+1], char *keyin)
+{
+        char *p;
+        char *s;
+
+        for (p = keyin; *p; p++) 
+                ;
+        for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
+                *s = *p;
+        }
+        while (s >= keyout) {
+                *s-- = '0';
+        }
+}
+
+static char hextab[17] = "0123456789ABCDEF";
+
+/* given a DES key, cbc encrypt and translate input to terminated hex */
+void
+pk_encode(char *in, char *out, DesData *key)
+{
+       char buf[256];
+       DesData i;
+       des_key_schedule k;
+       int l,op,deslen;
+
+       memset(&i,0,sizeof(i));
+       memset(buf,0,sizeof(buf));
+       deslen = ((strlen(in) + 7)/8)*8;
+       des_key_sched(key, k);
+       des_cbc_encrypt(in,buf,deslen, k,&i,DES_ENCRYPT);
+       for (l=0,op=0;l<deslen;l++) {
+               out[op++] = hextab[(buf[l] & 0xf0) >> 4];
+               out[op++] = hextab[(buf[l] & 0x0f)];
+       }
+       out[op] = '\0';
+}
+
+/* given a DES key, translate input from hex and decrypt */
+void
+pk_decode(char *in, char *out, DesData *key)
+{
+       char buf[256];
+       DesData i;
+       des_key_schedule k;
+       int n1,n2,op;
+       size_t l;
+
+       memset(&i,0,sizeof(i));
+       memset(buf,0,sizeof(buf));
+       for (l=0,op=0;l<strlen(in)/2;l++,op+=2) {
+               if(in[op] == '0' && in[op+1] == '0') {
+                       buf[l] = '\0';
+                       break;
+               }
+               if (in[op] > '9')
+                       n1 = in[op] - 'A' + 10;
+               else
+                       n1 = in[op] - '0';
+               if (in[op+1] > '9')
+                       n2 = in[op+1] - 'A' + 10;
+               else
+                       n2 = in[op+1] - '0';
+               buf[l] = n1*16 +n2;
+       }
+       des_key_sched(key, k);
+       des_cbc_encrypt(buf,out,strlen(in)/2, k,&i,DES_DECRYPT);
+       out[strlen(in)/2] = '\0';
+}
diff --git a/lib/libtelnet/pk.h b/lib/libtelnet/pk.h
new file mode 100644 (file)
index 0000000..401728a
--- /dev/null
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *      Dave Safford.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * $FreeBSD: src/crypto/telnet/libtelnet/pk.h,v 1.1.2.3 2002/04/13 10:59:07 markm Exp $
+ */
+
+/* header for the des routines that we will use */
+
+typedef unsigned char byte, DesData[ 8], IdeaData[16];
+#define DesKeys des_key_schedule
+
+#define DES_DECRYPT 0
+#define DES_ENCRYPT 1
+
+/* public key routines */
+/* functions:
+       genkeys(char *public, char *secret)
+       common_key(char *secret, char *public, desData *deskey)
+      where
+       char public[HEXKEYBYTES + 1];
+       char secret[HEXKEYBYTES + 1];
+ */
+
+#define HEXMODULUS "d4a0ba0250b6fd2ec626e7efd637df76c716e22d0944b88b"
+#define HEXKEYBYTES 48
+#define KEYSIZE 192
+#define KEYBYTES 24
+#define PROOT 3
+
+extern void genkeys(char *public, char *secret);
+extern void common_key(char *secret, char *public, IdeaData *common,
+  DesData *deskey);
+extern void pk_encode(char *in, char *out, DesData *deskey);
+extern void pk_decode(char *in, char *out, DesData *deskey);
diff --git a/lib/libtelnet/read_password.c b/lib/libtelnet/read_password.c
new file mode 100644 (file)
index 0000000..b8ab104
--- /dev/null
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/read_password.c,v 1.1.1.1.8.2 2002/04/13 10:59:07 markm Exp $");
+#endif
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)read_password.c    8.3 (Berkeley) 5/30/95";
+#endif
+#endif /* not lint */
+
+/*
+ * $Source: /Users/Shared/libtelnet/libtelnet/read_password.c,v $
+ * $Author: nicolai $
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * This routine prints the supplied string to standard
+ * output as a prompt, and reads a password string without
+ * echoing.
+ */
+
+#if    defined(RSA_ENCPWD) || defined(KRB4_ENCPWD)
+
+#include <stdio.h>
+#include <strings.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <setjmp.h>
+
+static jmp_buf env;
+
+/*** Routines ****************************************************** */
+/*
+ * This version just returns the string, doesn't map to key.
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+
+int
+local_des_read_pw_string(s,max,prompt,verify)
+    char *s;
+    int        max;
+    char *prompt;
+    int        verify;
+{
+    int ok = 0;
+    char *ptr;
+
+    jmp_buf old_env;
+    struct sgttyb tty_state;
+    char key_string[BUFSIZ];
+
+    if (max > BUFSIZ) {
+       return -1;
+    }
+
+    /* XXX assume jmp_buf is typedef'ed to an array */
+    memmove((char *)env, (char *)old_env, sizeof(env));
+    if (setjmp(env))
+       goto lose;
+
+    /* save terminal state*/
+    if (ioctl(0,TIOCGETP,(char *)&tty_state) == -1)
+       return -1;
+/*
+    push_signals();
+*/
+    /* Turn off echo */
+    tty_state.sg_flags &= ~ECHO;
+    if (ioctl(0,TIOCSETP,(char *)&tty_state) == -1)
+       return -1;
+    while (!ok) {
+       (void) printf("%s", prompt);
+       (void) fflush(stdout);
+       while (!fgets(s, max, stdin));
+
+       if ((ptr = strchr(s, '\n')))
+           *ptr = '\0';
+       if (verify) {
+           printf("\nVerifying, please re-enter %s",prompt);
+           (void) fflush(stdout);
+           if (!fgets(key_string, sizeof(key_string), stdin)) {
+               clearerr(stdin);
+               continue;
+           }
+           if ((ptr = strchr(key_string, '\n')))
+           *ptr = '\0';
+           if (strcmp(s,key_string)) {
+               printf("\n\07\07Mismatch - try again\n");
+               (void) fflush(stdout);
+               continue;
+           }
+       }
+       ok = 1;
+    }
+
+lose:
+    if (!ok)
+       memset(s, 0, max);
+    printf("\n");
+    /* turn echo back on */
+    tty_state.sg_flags |= ECHO;
+    if (ioctl(0,TIOCSETP,(char *)&tty_state))
+       ok = 0;
+/*
+    pop_signals();
+*/
+    memmove((char *)old_env, (char *)env, sizeof(env));
+    if (verify)
+       memset(key_string, 0, sizeof (key_string));
+    s[max-1] = 0;              /* force termination */
+    return !ok;                        /* return nonzero if not okay */
+}
+#endif /* defined(RSA_ENCPWD) || defined(KRB4_ENCPWD) */
diff --git a/lib/libtelnet/rsaencpwd.c b/lib/libtelnet/rsaencpwd.c
new file mode 100644 (file)
index 0000000..60242a2
--- /dev/null
@@ -0,0 +1,475 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/rsaencpwd.c,v 1.1.1.1.8.1 2002/04/13 10:59:07 markm Exp $");
+
+#ifndef lint
+static char sccsid[] = "@(#)rsaencpwd.c        8.3 (Berkeley) 5/30/95";
+#endif /* not lint */
+
+
+#ifdef RSA_ENCPWD
+/*
+ * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION
+ * ALL RIGHTS RESERVED
+ *
+ * "Digital Equipment Corporation authorizes the reproduction,
+ * distribution and modification of this software subject to the following
+ * restrictions:
+ *
+ * 1.  Any partial or whole copy of this software, or any modification
+ * thereof, must include this copyright notice in its entirety.
+ *
+ * 2.  This software is supplied "as is" with no warranty of any kind,
+ * expressed or implied, for any purpose, including any warranty of fitness
+ * or merchantibility.  DIGITAL assumes no responsibility for the use or
+ * reliability of this software, nor promises to provide any form of
+ * support for it on any basis.
+ *
+ * 3.  Distribution of this software is authorized only if no profit or
+ * remuneration of any kind is received in exchange for such distribution.
+ *
+ * 4.  This software produces public key authentication certificates
+ * bearing an expiration date established by DIGITAL and RSA Data
+ * Security, Inc.  It may cease to generate certificates after the expiration
+ * date.  Any modification of this software that changes or defeats
+ * the expiration date or its effect is unauthorized.
+ *
+ * 5.  Software that will renew or extend the expiration date of
+ * authentication certificates produced by this software may be obtained
+ * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA
+ * 94065, (415)595-8782, or from DIGITAL"
+ *
+ */
+
+#include <sys/types.h>
+#include <arpa/telnet.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "encrypt.h"
+#include "auth.h"
+#include "misc.h"
+#include "cdc.h"
+
+extern auth_debug_mode;
+
+static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
+                                       AUTHTYPE_RSA_ENCPWD, };
+static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
+                                       TELQUAL_NAME, };
+
+#define        RSA_ENCPWD_AUTH 0       /* Authentication data follows */
+#define        RSA_ENCPWD_REJECT       1       /* Rejected (reason might follow) */
+#define RSA_ENCPWD_ACCEPT      2       /* Accepted */
+#define        RSA_ENCPWD_CHALLENGEKEY 3       /* Challenge and public key */
+
+#define NAME_SZ   40
+#define CHAL_SZ   20
+#define PWD_SZ    40
+
+static KTEXT_ST auth;
+static char name[NAME_SZ];
+static char user_passwd[PWD_SZ];
+static  char key_file[2*NAME_SZ];
+static  char lhostname[NAME_SZ];
+static char  challenge[CHAL_SZ];
+static int   challenge_len;
+
+       static int
+Data(ap, type, d, c)
+       Authenticator *ap;
+       int type;
+       void *d;
+       int c;
+{
+       unsigned char *p = str_data + 4;
+       unsigned char *cd = (unsigned char *)d;
+
+       if (c == -1)
+               c = strlen((char *)cd);
+
+       if (0) {
+               printf("%s:%d: [%d] (%d)",
+                       str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
+                       str_data[3],
+                       type, c);
+               printd(d, c);
+               printf("\r\n");
+       }
+       *p++ = ap->type;
+       *p++ = ap->way;
+       if (type != NULL) *p++ = type;
+       while (c-- > 0) {
+               if ((*p++ = *cd++) == IAC)
+                       *p++ = IAC;
+       }
+       *p++ = IAC;
+       *p++ = SE;
+       if (str_data[3] == TELQUAL_IS)
+               printsub('>', &str_data[2], p - (&str_data[2]));
+       return(net_write(str_data, p - str_data));
+}
+
+       int
+rsaencpwd_init(ap, server)
+       Authenticator *ap;
+       int server;
+{
+       char  *cp;
+       FILE  *fp;
+
+       if (server) {
+               str_data[3] = TELQUAL_REPLY;
+               memset(key_file, 0, sizeof(key_file));
+               gethostname(lhostname, sizeof(lhostname));
+               if ((cp = strchr(lhostname, '.')) != 0)  *cp = '\0';
+               strcpy(key_file, "/etc/.");
+               strcat(key_file, lhostname);
+               strcat(key_file, "_privkey");
+               if ((fp=fopen(key_file, "r"))==NULL) return(0);
+               fclose(fp);
+       } else {
+               str_data[3] = TELQUAL_IS;
+       }
+       return(1);
+}
+
+       int
+rsaencpwd_send(ap)
+       Authenticator *ap;
+{
+
+       printf("[ Trying RSAENCPWD ... ]\n");
+       if (!UserNameRequested) {
+               return(0);
+       }
+       if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
+               return(0);
+       }
+       if (!Data(ap, NULL, (void *)NULL, 0)) {
+               return(0);
+       }
+
+
+       return(1);
+}
+
+       void
+rsaencpwd_is(ap, data, cnt)
+       Authenticator *ap;
+       unsigned char *data;
+       int cnt;
+{
+       Session_Key skey;
+       Block datablock;
+       char  r_passwd[PWD_SZ], r_user[NAME_SZ];
+       char  *cp, key[160];
+       char  chalkey[160], *ptr;
+       FILE  *fp;
+       int r, i, j, chalkey_len, len;
+       time_t now;
+
+       cnt--;
+       switch (*data++) {
+       case RSA_ENCPWD_AUTH:
+               memmove((void *)auth.dat, (void *)data, auth.length = cnt);
+
+               if ((fp=fopen(key_file, "r"))==NULL) {
+                 Data(ap, RSA_ENCPWD_REJECT, (void *)"Auth failed", -1);
+                 auth_finished(ap, AUTH_REJECT);
+                 return;
+               }
+               /*
+                *  get privkey
+                */
+               fscanf(fp, "%x;", &len);
+               for (i=0;i<len;i++) {
+                 j = getc(fp);  key[i]=j;
+               }
+               fclose(fp);
+
+               r = accept_rsa_encpwd(&auth, key, challenge,
+                                     challenge_len, r_passwd);
+               if (r < 0) {
+                 Data(ap, RSA_ENCPWD_REJECT, (void *)"Auth failed", -1);
+                 auth_finished(ap, AUTH_REJECT);
+                 return;
+               }
+               auth_encrypt_userpwd(r_passwd);
+               if (rsaencpwd_passwdok(UserNameRequested, UserPassword) == 0) {
+                 /*
+                  *  illegal username and password
+                  */
+                 Data(ap, RSA_ENCPWD_REJECT, (void *)"Illegal password", -1);
+                 auth_finished(ap, AUTH_REJECT);
+                 return;
+               }
+
+               Data(ap, RSA_ENCPWD_ACCEPT, (void *)0, 0);
+               auth_finished(ap, AUTH_USER);
+               break;
+
+
+       case IAC:
+
+               /*
+                * If we are doing mutual authentication, get set up to send
+                * the challenge, and verify it when the response comes back.
+                */
+               if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY) {
+                 register int i;
+
+
+                 time(&now);
+                 if ((now % 2) == 0) {
+                   sprintf(challenge, "%x", now);
+                   challenge_len = strlen(challenge);
+                 } else {
+                   strcpy(challenge, "randchal");
+                   challenge_len = 8;
+                 }
+
+                 if ((fp=fopen(key_file, "r"))==NULL) {
+                   Data(ap, RSA_ENCPWD_REJECT, (void *)"Auth failed", -1);
+                   auth_finished(ap, AUTH_REJECT);
+                   return;
+                 }
+                 /*
+                  *  skip privkey
+                  */
+                 fscanf(fp, "%x;", &len);
+                 for (i=0;i<len;i++) {
+                   j = getc(fp);
+                 }
+                 /*
+                  * get pubkey
+                  */
+                 fscanf(fp, "%x;", &len);
+                 for (i=0;i<len;i++) {
+                   j = getc(fp);  key[i]=j;
+                 }
+                 fclose(fp);
+                 chalkey[0] = 0x30;
+                 ptr = (char *) &chalkey[1];
+                 chalkey_len = 1+NumEncodeLengthOctets(i)+i+1+NumEncodeLengthOctets(challenge_len)+challenge_len;
+                 EncodeLength(ptr, chalkey_len);
+                 ptr +=NumEncodeLengthOctets(chalkey_len);
+                 *ptr++ = 0x04;  /* OCTET STRING */
+                 *ptr++ = challenge_len;
+                 memmove(ptr, challenge, challenge_len);
+                 ptr += challenge_len;
+                 *ptr++ = 0x04;  /* OCTET STRING */
+                 EncodeLength(ptr, i);
+                 ptr += NumEncodeLengthOctets(i);
+                 memmove(ptr, key, i);
+                 chalkey_len = 1+NumEncodeLengthOctets(chalkey_len)+chalkey_len;
+                 Data(ap, RSA_ENCPWD_CHALLENGEKEY, (void *)chalkey, chalkey_len);
+               }
+               break;
+
+       default:
+               Data(ap, RSA_ENCPWD_REJECT, 0, 0);
+               break;
+       }
+}
+
+
+       void
+rsaencpwd_reply(ap, data, cnt)
+       Authenticator *ap;
+       unsigned char *data;
+       int cnt;
+{
+       Session_Key skey;
+       KTEXT_ST token;
+       Block enckey;
+       int r, pubkey_len;
+       char    randchal[CHAL_SZ], *cp;
+       char    chalkey[160], pubkey[128], *ptr;
+
+       if (cnt-- < 1)
+               return;
+       switch (*data++) {
+       case RSA_ENCPWD_REJECT:
+               if (cnt > 0) {
+                       printf("[ RSA_ENCPWD refuses authentication because %.*s ]\r\n",
+                               cnt, data);
+               } else
+                       printf("[ RSA_ENCPWD refuses authentication ]\r\n");
+               auth_send_retry();
+               return;
+       case RSA_ENCPWD_ACCEPT:
+               printf("[ RSA_ENCPWD accepts you ]\n");
+               auth_finished(ap, AUTH_USER);
+               return;
+       case RSA_ENCPWD_CHALLENGEKEY:
+               /*
+                * Verify that the response to the challenge is correct.
+                */
+
+               memmove((void *)chalkey, (void *)data, cnt);
+               ptr = (char *) &chalkey[0];
+               ptr += DecodeHeaderLength(chalkey);
+               if (*ptr != 0x04) {
+                 return;
+               }
+               *ptr++;
+               challenge_len = DecodeValueLength(ptr);
+               ptr += NumEncodeLengthOctets(challenge_len);
+               memmove(challenge, ptr, challenge_len);
+               ptr += challenge_len;
+               if (*ptr != 0x04) {
+                 return;
+               }
+               *ptr++;
+               pubkey_len = DecodeValueLength(ptr);
+               ptr += NumEncodeLengthOctets(pubkey_len);
+               memmove(pubkey, ptr, pubkey_len);
+               memset(user_passwd, 0, sizeof(user_passwd));
+               local_des_read_pw_string(user_passwd, sizeof(user_passwd)-1, "Password: ", 0);
+               UserPassword = user_passwd;
+               Challenge = challenge;
+               r = init_rsa_encpwd(&token, user_passwd, challenge, challenge_len, pubkey);
+               if (r < 0) {
+                 token.length = 1;
+               }
+
+               if (!Data(ap, RSA_ENCPWD_AUTH, (void *)token.dat, token.length)) {
+                 return;
+               }
+
+               break;
+
+       default:
+               return;
+       }
+}
+
+       int
+rsaencpwd_status(ap, name, level)
+       Authenticator *ap;
+       char *name;
+       int level;
+{
+
+       if (level < AUTH_USER)
+               return(level);
+
+       if (UserNameRequested && rsaencpwd_passwdok(UserNameRequested, UserPassword)) {
+               strcpy(name, UserNameRequested);
+               return(AUTH_VALID);
+       } else {
+               return(AUTH_USER);
+       }
+}
+
+#define        BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
+#define        ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
+
+       void
+rsaencpwd_printsub(data, cnt, buf, buflen)
+       unsigned char *data, *buf;
+       int cnt, buflen;
+{
+       char lbuf[32];
+       register int i;
+
+       buf[buflen-1] = '\0';           /* make sure its NULL terminated */
+       buflen -= 1;
+
+       switch(data[3]) {
+       case RSA_ENCPWD_REJECT: /* Rejected (reason might follow) */
+               strncpy((char *)buf, " REJECT ", buflen);
+               goto common;
+
+       case RSA_ENCPWD_ACCEPT: /* Accepted (name might follow) */
+               strncpy((char *)buf, " ACCEPT ", buflen);
+       common:
+               BUMP(buf, buflen);
+               if (cnt <= 4)
+                       break;
+               ADDC(buf, buflen, '"');
+               for (i = 4; i < cnt; i++)
+                       ADDC(buf, buflen, data[i]);
+               ADDC(buf, buflen, '"');
+               ADDC(buf, buflen, '\0');
+               break;
+
+       case RSA_ENCPWD_AUTH:           /* Authentication data follows */
+               strncpy((char *)buf, " AUTH", buflen);
+               goto common2;
+
+       case RSA_ENCPWD_CHALLENGEKEY:
+               strncpy((char *)buf, " CHALLENGEKEY", buflen);
+               goto common2;
+
+       default:
+               sprintf(lbuf, " %d (unknown)", data[3]);
+               strncpy((char *)buf, lbuf, buflen);
+       common2:
+               BUMP(buf, buflen);
+               for (i = 4; i < cnt; i++) {
+                       sprintf(lbuf, " %d", data[i]);
+                       strncpy((char *)buf, lbuf, buflen);
+                       BUMP(buf, buflen);
+               }
+               break;
+       }
+}
+
+int rsaencpwd_passwdok(name, passwd)
+char *name, *passwd;
+{
+  char *crypt();
+  char *salt, *p;
+  struct passwd *pwd;
+  int   passwdok_status = 0;
+
+  if (pwd = getpwnam(name))
+    salt = pwd->pw_passwd;
+  else salt = "xx";
+
+  p = crypt(passwd, salt);
+
+  if (pwd && !strcmp(p, pwd->pw_passwd)) {
+    passwdok_status = 1;
+  } else passwdok_status = 0;
+  return(passwdok_status);
+}
+
+#endif
diff --git a/lib/libtelnet/sra.c b/lib/libtelnet/sra.c
new file mode 100644 (file)
index 0000000..c85abbf
--- /dev/null
@@ -0,0 +1,604 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *      Dave Safford.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef __FBSDID
+__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/sra.c,v 1.1.2.7 2002/05/16 08:46:49 markm Exp $");
+#endif
+
+#ifdef SRA
+#ifdef ENCRYPTION
+#include <sys/types.h>
+#include <arpa/telnet.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <ttyent.h>
+
+#ifndef NOPAM
+#include <security/pam_appl.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "auth.h"
+#include "misc.h"
+#include "encrypt.h"
+#include "pk.h"
+
+char pka[HEXKEYBYTES+1], ska[HEXKEYBYTES+1], pkb[HEXKEYBYTES+1];
+char *user, *pass, *xuser, *xpass;
+DesData ck;
+IdeaData ik;
+
+extern int auth_debug_mode;
+extern char line[];
+
+static int sra_valid = 0;
+static int passwd_sent = 0;
+
+static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
+                                       AUTHTYPE_SRA, };
+
+#define SRA_KEY        0
+#define SRA_USER 1
+#define SRA_CONTINUE 2
+#define SRA_PASS 3
+#define SRA_ACCEPT 4
+#define SRA_REJECT 5
+
+static int check_user(char *, char *);
+
+/* support routine to send out authentication message */
+static int
+Data(Authenticator *ap, int type, void *d, int c)
+{
+        unsigned char *p = str_data + 4;
+       unsigned char *cd = (unsigned char *)d;
+
+       if (c == -1)
+               c = strlen((char *)cd);
+
+        if (auth_debug_mode) {
+                printf("%s:%d: [%d] (%d)",
+                        str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
+                        str_data[3],
+                        type, c);
+                printd(d, c);
+                printf("\r\n");
+        }
+       *p++ = ap->type;
+       *p++ = ap->way;
+       *p++ = type;
+        while (c-- > 0) {
+                if ((*p++ = *cd++) == IAC)
+                        *p++ = IAC;
+        }
+        *p++ = IAC;
+        *p++ = SE;
+       if (str_data[3] == TELQUAL_IS)
+               printsub('>', &str_data[2], p - (&str_data[2]));
+        return(net_write(str_data, p - str_data));
+}
+
+int
+sra_init(Authenticator *ap __unused, int server)
+{
+       if (server)
+               str_data[3] = TELQUAL_REPLY;
+       else
+               str_data[3] = TELQUAL_IS;
+
+       user = (char *)malloc(256);
+       xuser = (char *)malloc(513);
+       pass = (char *)malloc(256);
+       xpass = (char *)malloc(513);
+
+       if (user == NULL || xuser == NULL || pass == NULL || xpass ==
+       NULL)
+               return 0; /* malloc failed */
+
+       passwd_sent = 0;
+       
+       genkeys(pka,ska);
+       return(1);
+}
+
+/* client received a go-ahead for sra */
+int
+sra_send(Authenticator *ap)
+{
+       /* send PKA */
+
+       if (auth_debug_mode)
+               printf("Sent PKA to server.\r\n" );
+       printf("Trying SRA secure login:\r\n");
+       if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
+               if (auth_debug_mode)
+                       printf("Not enough room for authentication data\r\n");
+               return(0);
+       }
+
+       return(1);
+}
+
+/* server received an IS -- could be SRA KEY, USER, or PASS */
+void
+sra_is(Authenticator *ap, unsigned char *data, int cnt)
+{
+       int valid;
+       Session_Key skey;
+
+       if (cnt-- < 1)
+               goto bad;
+       switch (*data++) {
+
+       case SRA_KEY:
+               if (cnt < HEXKEYBYTES) {
+                       Data(ap, SRA_REJECT, (void *)0, 0);
+                       auth_finished(ap, AUTH_USER);
+                       if (auth_debug_mode) {
+                               printf("SRA user rejected for bad PKB\r\n");
+                       }
+                       return;
+               }
+               if (auth_debug_mode)
+                       printf("Sent pka\r\n");
+               if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
+                       if (auth_debug_mode)
+                               printf("Not enough room\r\n");
+                       return;
+               }
+               memcpy(pkb,data,HEXKEYBYTES);
+               pkb[HEXKEYBYTES] = '\0';
+               common_key(ska,pkb,&ik,&ck);
+               return;
+
+       case SRA_USER:
+               /* decode KAB(u) */
+               if (cnt > 512) /* Attempted buffer overflow */
+                       break;
+               memcpy(xuser,data,cnt);
+               xuser[cnt] = '\0';
+               pk_decode(xuser,user,&ck);
+               auth_encrypt_user(user);
+               Data(ap, SRA_CONTINUE, (void *)0, 0);
+
+               return;
+
+       case SRA_PASS:
+               if (cnt > 512) /* Attempted buffer overflow */
+                       break;
+               /* decode KAB(P) */
+               memcpy(xpass,data,cnt);
+               xpass[cnt] = '\0';
+               pk_decode(xpass,pass,&ck);
+
+               /* check user's password */
+               valid = check_user(user,pass);
+
+               if(valid) {
+                       Data(ap, SRA_ACCEPT, (void *)0, 0);
+                       skey.data = ck;
+                       skey.type = SK_DES;
+                       skey.length = 8;
+                       encrypt_session_key(&skey, 1);
+
+                       sra_valid = 1;
+                       auth_finished(ap, AUTH_VALID);
+                       if (auth_debug_mode) {
+                               printf("SRA user accepted\r\n");
+                       }
+               }
+               else {
+                       Data(ap, SRA_CONTINUE, (void *)0, 0);
+/*
+                       Data(ap, SRA_REJECT, (void *)0, 0);
+                       sra_valid = 0;
+                       auth_finished(ap, AUTH_REJECT);
+*/
+                       if (auth_debug_mode) {
+                               printf("SRA user failed\r\n");
+                       }
+               }
+               return;
+
+       default:
+               if (auth_debug_mode)
+                       printf("Unknown SRA option %d\r\n", data[-1]);
+       }
+bad:
+       Data(ap, SRA_REJECT, 0, 0);
+       sra_valid = 0;
+       auth_finished(ap, AUTH_REJECT);
+}
+
+/* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
+void
+sra_reply(Authenticator *ap, unsigned char *data, int cnt)
+{
+       char uprompt[256],tuser[256];
+       Session_Key skey;
+       size_t i;
+
+       if (cnt-- < 1)
+               return;
+       switch (*data++) {
+
+       case SRA_KEY:
+               /* calculate common key */
+               if (cnt < HEXKEYBYTES) {
+                       if (auth_debug_mode) {
+                               printf("SRA user rejected for bad PKB\r\n");
+                       }
+                       return;
+               }
+               memcpy(pkb,data,HEXKEYBYTES);
+               pkb[HEXKEYBYTES] = '\0';                
+
+               common_key(ska,pkb,&ik,&ck);
+
+       enc_user:
+
+               /* encode user */
+               memset(tuser,0,sizeof(tuser));
+               sprintf(uprompt,"User (%s): ",UserNameRequested);
+               telnet_gets(uprompt,tuser,255,1);
+               if (tuser[0] == '\n' || tuser[0] == '\r' )
+                       strcpy(user,UserNameRequested);
+               else {
+                       /* telnet_gets leaves the newline on */
+                       for(i=0;i<sizeof(tuser);i++) {
+                               if (tuser[i] == '\n') {
+                                       tuser[i] = '\0';
+                                       break;
+                               }
+                       }
+                       strcpy(user,tuser);
+               }
+               pk_encode(user,xuser,&ck);
+
+               /* send it off */
+               if (auth_debug_mode)
+                       printf("Sent KAB(U)\r\n");
+               if (!Data(ap, SRA_USER, (void *)xuser, strlen(xuser))) {
+                       if (auth_debug_mode)
+                               printf("Not enough room\r\n");
+                       return;
+               }
+               break;
+
+       case SRA_CONTINUE:
+               if (passwd_sent) {
+                       passwd_sent = 0;
+                       printf("[ SRA login failed ]\r\n");
+                       goto enc_user;
+               }
+               /* encode password */
+               memset(pass,0,sizeof(pass));
+               telnet_gets("Password: ",pass,255,0);
+               pk_encode(pass,xpass,&ck);
+               /* send it off */
+               if (auth_debug_mode)
+                       printf("Sent KAB(P)\r\n");
+               if (!Data(ap, SRA_PASS, (void *)xpass, strlen(xpass))) {
+                       if (auth_debug_mode)
+                               printf("Not enough room\r\n");
+                       return;
+               }
+               passwd_sent = 1;
+               break;
+
+       case SRA_REJECT:
+               printf("[ SRA refuses authentication ]\r\n");
+               printf("Trying plaintext login:\r\n");
+               auth_finished(0,AUTH_REJECT);
+               return;
+
+       case SRA_ACCEPT:
+               printf("[ SRA accepts you ]\r\n");
+               skey.data = ck;
+               skey.type = SK_DES;
+               skey.length = 8;
+               encrypt_session_key(&skey, 0);
+
+               auth_finished(ap, AUTH_VALID);
+               return;
+       default:
+               if (auth_debug_mode)
+                       printf("Unknown SRA option %d\r\n", data[-1]);
+               return;
+       }
+}
+
+int
+sra_status(Authenticator *ap __unused, char *name, int level)
+{
+       if (level < AUTH_USER)
+               return(level);
+       if (UserNameRequested && sra_valid) {
+               strcpy(name, UserNameRequested);
+               return(AUTH_VALID);
+       } else
+               return(AUTH_USER);
+}
+
+#define        BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
+#define        ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
+
+void
+sra_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
+{
+       char lbuf[32];
+       int i;
+
+       buf[buflen-1] = '\0';           /* make sure its NULL terminated */
+       buflen -= 1;
+
+       switch(data[3]) {
+
+       case SRA_CONTINUE:
+               strncpy((char *)buf, " CONTINUE ", buflen);
+               goto common;
+
+       case SRA_REJECT:                /* Rejected (reason might follow) */
+               strncpy((char *)buf, " REJECT ", buflen);
+               goto common;
+
+       case SRA_ACCEPT:                /* Accepted (name might follow) */
+               strncpy((char *)buf, " ACCEPT ", buflen);
+
+       common:
+               BUMP(buf, buflen);
+               if (cnt <= 4)
+                       break;
+               ADDC(buf, buflen, '"');
+               for (i = 4; i < cnt; i++)
+                       ADDC(buf, buflen, data[i]);
+               ADDC(buf, buflen, '"');
+               ADDC(buf, buflen, '\0');
+               break;
+
+       case SRA_KEY:                   /* Authentication data follows */
+               strncpy((char *)buf, " KEY ", buflen);
+               goto common2;
+
+       case SRA_USER:
+               strncpy((char *)buf, " USER ", buflen);
+               goto common2;
+
+       case SRA_PASS:
+               strncpy((char *)buf, " PASS ", buflen);
+               goto common2;
+
+       default:
+               sprintf(lbuf, " %d (unknown)", data[3]);
+               strncpy((char *)buf, lbuf, buflen);
+       common2:
+               BUMP(buf, buflen);
+               for (i = 4; i < cnt; i++) {
+                       sprintf(lbuf, " %d", data[i]);
+                       strncpy((char *)buf, lbuf, buflen);
+                       BUMP(buf, buflen);
+               }
+               break;
+       }
+}
+
+static int
+isroot(const char *usr)
+{
+       struct passwd *pwd;
+
+       if ((pwd=getpwnam(usr))==NULL)
+               return 0;
+       return (!pwd->pw_uid);
+}
+
+static int
+rootterm(char *ttyn)
+{
+       struct ttyent *t;
+
+       return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
+}
+
+#ifdef NOPAM
+static int
+check_user(char *name, char *cred)
+{
+       char *cp;
+       char *xpasswd, *salt;
+
+       if (isroot(name) && !rootterm(line))
+       {
+               crypt("AA","*"); /* Waste some time to simulate success */
+               return(0);
+       }
+
+       if (pw = sgetpwnam(name)) {
+               if (pw->pw_shell == NULL) {
+                       pw = (struct passwd *) NULL;
+                       return(0);
+               }
+
+               salt = pw->pw_passwd;
+               xpasswd = crypt(cred, salt);
+               /* The strcmp does not catch null passwords! */
+               if (pw == NULL || *pw->pw_passwd == '\0' ||
+                       strcmp(xpasswd, pw->pw_passwd)) {
+                       pw = (struct passwd *) NULL;
+                       return(0);
+               }
+               return(1);
+       }
+       return(0);
+}
+#else
+
+/*
+ * The following is stolen from ftpd, which stole it from the imap-uw
+ * PAM module and login.c. It is needed because we can't really
+ * "converse" with the user, having already gone to the trouble of
+ * getting their username and password through an encrypted channel.
+ */
+
+#define COPY_STRING(s) (s ? strdup(s):NULL)
+
+struct cred_t {
+       const char *uname;
+       const char *pass;
+};
+typedef struct cred_t cred_t;
+
+static int
+auth_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata)
+{
+       int i;
+       cred_t *cred = (cred_t *) appdata;
+       struct pam_response *reply =
+               malloc(sizeof(struct pam_response) * num_msg);
+
+       if (reply == NULL)
+               return PAM_BUF_ERR;
+
+       for (i = 0; i < num_msg; i++) {
+               switch (msg[i]->msg_style) {
+               case PAM_PROMPT_ECHO_ON:        /* assume want user name */
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       reply[i].resp = COPY_STRING(cred->uname);
+                       /* PAM frees resp. */
+                       break;
+               case PAM_PROMPT_ECHO_OFF:       /* assume want password */
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       reply[i].resp = COPY_STRING(cred->pass);
+                       /* PAM frees resp. */
+                       break;
+               case PAM_TEXT_INFO:
+               case PAM_ERROR_MSG:
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       reply[i].resp = NULL;
+                       break;
+               default:                        /* unknown message style */
+                       free(reply);
+                       return PAM_CONV_ERR;
+               }
+       }
+
+       *resp = reply;
+       return PAM_SUCCESS;
+}
+
+/*
+ * The PAM version as a side effect may put a new username in *name.
+ */
+static int
+check_user(char *name, char *cred)
+{
+       pam_handle_t *pamh = NULL;
+       const void *item;
+       int rval;
+       int e;
+       cred_t auth_cred = { name, cred };
+       struct pam_conv conv = { &auth_conv, &auth_cred };
+
+       e = pam_start("telnetd", name, &conv, &pamh);
+       if (e != PAM_SUCCESS) {
+               syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
+               return 0;
+       }
+
+#if 0 /* Where can we find this value? */
+       e = pam_set_item(pamh, PAM_RHOST, remotehost);
+       if (e != PAM_SUCCESS) {
+               syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
+                       pam_strerror(pamh, e));
+               return 0;
+       }
+#endif
+
+       e = pam_authenticate(pamh, 0);
+       switch (e) {
+       case PAM_SUCCESS:
+               /*
+                * With PAM we support the concept of a "template"
+                * user.  The user enters a login name which is
+                * authenticated by PAM, usually via a remote service
+                * such as RADIUS or TACACS+.  If authentication
+                * succeeds, a different but related "template" name
+                * is used for setting the credentials, shell, and
+                * home directory.  The name the user enters need only
+                * exist on the remote authentication server, but the
+                * template name must be present in the local password
+                * database.
+                *
+                * This is supported by two various mechanisms in the
+                * individual modules.  However, from the application's
+                * point of view, the template user is always passed
+                * back as a changed value of the PAM_USER item.
+                */
+               if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
+                   PAM_SUCCESS) {
+                       strcpy(name, item);
+               } else
+                       syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
+                       pam_strerror(pamh, e));
+               if (isroot(name) && !rootterm(line))
+                       rval = 0;
+               else
+                       rval = 1;
+               break;
+
+       case PAM_AUTH_ERR:
+       case PAM_USER_UNKNOWN:
+       case PAM_MAXTRIES:
+               rval = 0;
+       break;
+
+       default:
+               syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
+               rval = 0;
+               break;
+       }
+
+       if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
+               syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
+               rval = 0;
+       }
+       return rval;
+}
+
+#endif
+
+#endif /* ENCRYPTION */
+#endif /* SRA */