Project import
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..12c29fe
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,110 @@
+#
+#    Copyright (c) 2010-2011 Nest, Inc.
+#    All rights reserved.
+#
+#    This document is the property of Nest. It is considered
+#    confidential and proprietary information.
+#
+#    This document may not be reproduced or transmitted in any form,
+#    in whole or in part, without the express written permission of
+#    Nest.
+#
+#    Description:
+#      This file is the makefile for c-kermit, a combined serial and
+#      network communication software package.
+#
+
+BuildConfigSpecialized	:= No
+BuildProductSpecialized	:= No
+
+include pre.mak
+
+PackageName		:= ckermit
+
+PackageExtension	:= tar.gz
+PackageSeparator	:= -
+
+PackagePatchArgs	:=
+
+PackageArchive		:= $(PackageName).$(PackageExtension)
+PackageSourceDir	:= $(PackageName)$(PackageSeparator)$(PackageVersion)
+
+PackageBuildMakefile	= $(call GenerateBuildPaths,makefile)
+
+CleanPaths		+= $(PackageLicenseFile)
+
+NCursesDir		:= sw/tps/ncurses
+NCursesIncDir		:= $(call GenerateResultPaths,$(NCursesDir),usr/include)
+NCursesLibDir		:= $(call GenerateResultPaths,$(NCursesDir),usr/lib)
+
+all: $(PackageDefaultGoal)
+
+# Generate the package license contents.
+
+$(PackageSourceDir)/COPYING.TXT: source
+
+$(PackageLicenseFile): $(PackageSourceDir)/COPYING.TXT
+	$(copy-result)
+
+# Extract the source from the archive and apply patches, if any.
+
+$(PackageSourceDir): $(PackageArchive) $(PackagePatchPaths)
+	$(create-directory)
+	$(call expand-archive,$(PackageArchive),$(@))
+	$(Verbose)touch $(@)
+	$(call patch-directory,$(@),$(PackagePatchArgs),$(PackagePatchPaths))
+
+# Prepare the sources.
+
+.PHONY: source
+source: | $(PackageSourceDir)
+
+# Patch the sources, if necessary.
+
+.PHONY: patch
+patch: source
+
+# Generate the package build makefile.
+
+$(PackageBuildMakefile): | $(PackageSourceDir) $(BuildDirectory)
+	$(call create-links,$(CURDIR)/$(PackageSourceDir),$(BuildDirectory))
+
+# Configure the source for building.
+
+.PHONY: configure
+configure: source $(PackageBuildMakefile)
+
+# Build the source.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+.PHONY: build
+build: configure
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+	INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	CC="$(CC)" CXX="$(CXX)" AR=$(AR) NM=$(NM) RANLIB=$(RANLIB) STRIP=$(STRIP) \
+	NCURSES_CPPFLAGS=$(call ToolGenerateIncludeArgument,$(NCursesIncDir)) \
+	NCURSES_LDFLAGS=$(call ToolGenerateLibraryPathArgument,$(NCursesLibDir)) \
+	linux-cross
+
+# Stage the build to a temporary installation area.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+.PHONY: stage
+stage: build | $(ResultDirectory)
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+	INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	DESTDIR=$(ResultDirectory) \
+	prefix=/usr \
+	MANDIR="" \
+	install
+
+clean:
+	$(Verbose)$(RM) $(RMFLAGS) -r $(PackageSourceDir)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(BuildDirectory)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(ResultDirectory)
+
+include post.mak
diff --git a/ckermit-8.0.211/COPYING.TXT b/ckermit-8.0.211/COPYING.TXT
new file mode 100644
index 0000000..da5d39e
--- /dev/null
+++ b/ckermit-8.0.211/COPYING.TXT
@@ -0,0 +1,106 @@
+THE C-KERMIT 7.0 AND 8.0 LICENSE
+
+  Last update: Thu May  1 13:52:15 2003
+
+This is the new C-Kermit 7.0 and 8.0 license.  The intention is to allow
+C-Kermit to be distributed with "free" operating systems such as GNU/Linux,
+FreeBSD, NetBSD, OpenBSD, The Hurd, etc, even when the distributions
+themselves (such as Red Hat or Caldera) might be sold and/or might include
+applications that are not free, and yet still require a license to include
+C-Kermit in or with "non-free" products such as commercial OS's, commercial
+software packages, embedded systems, and hardware (other than general-purpose
+computers preloaded with "free" operating systems), since these licenses
+furnish a large portion of the Kermit Project's funding.
+
+There have been some questions about the provision in Clause (A) that:
+
+                                                                  The
+    C-Kermit source code may not be changed without the consent of the
+    Kermit Project, which will not be unreasonably withheld (this is
+    simply a matter of keeping a consistent and supportable code base).
+
+The intention of this clause is primarily to make sure that anybody who
+makes modifications sends them back to us, since we are the ones have to
+support C-Kermit, and so we can carry them through to future releases (so
+you don't have to make the same changes again and again).
+
+Secondarily it is to protect Columbia University in the unlikely event of
+modifications made with deliberate intent to offend or cause damage.
+
+Any redistributor of C-Kermit under Clause (A) below should rest assured
+there is no intention of preventing them from constructing a distribution in
+the appropriate format (RPM or whatever) for their product or from issuing
+any patches required for their products; we simply want to be informed so we
+can maintain a consistent code base and a solid, supportable software
+package.  We are happy to work with any redistributor an any issues that
+concern them.  If you have questions, send them to kermit@columbia.edu.
+
+Note: All changes to this file since 1 January 2000 (the C-Kermit 7.0
+release date) are above; the license itself has not changed, except to
+update the most recent copyright date.
+
+(Begin)
+
+Copyright (C) 1985, 2003,
+  The Trustees of Columbia University in the City of New York.
+  All rights reserved.
+
+PERMISSIONS:
+
+The C-Kermit software may be obtained directly from the Kermit Project at
+Columbia University (or from any source explicitly licensed by the Kermit
+Project or implicitly licensed by Clause (A) below) by any individual for
+his or her OWN USE, and by any company or other organization for its own
+INTERNAL DISTRIBUTION and use, including installation on servers that are
+accessed by customers or clients, WITHOUT EXPLICIT LICENSE.
+
+Conditions for REDISTRIBUTION are as follows:
+
+(A) The C-Kermit software, in source and/or binary form, may be
+    included WITHOUT EXPLICIT LICENSE in distributions of OPERATING
+    SYSTEMS that have OSI (Open Source Initiative, www.opensource.org)
+    approved licenses, even if non-Open-Source applications (but not
+    operating systems) are included in the same distribution.  Such
+    distributions include, but are not limited to, CD-ROM, FTP site,
+    Web site, or preinstalled software on a new GENERAL-PURPOSE
+    computer, as long as the primary character of the distribution is
+    an Open Source operating system with accompanying utilities.  The
+    C-Kermit source code may not be changed without the consent of the
+    Kermit Project, which will not be unreasonably withheld (this is
+    simply a matter of keeping a consistent and supportable code base).
+
+(B) Inclusion of C-Kermit software in whole or in part, in any form, in
+    or with any product not covered by Clause (A), or its distribution
+    by any commercial enterprise to its actual or potential customers
+    or clients except as in Clause (A), requires a license from the
+    Kermit Project, Columbia University; contact kermit@columbia.edu.
+
+The name of Columbia University may not be used to endorse or promote
+products derived from or including the C-Kermit software without specific
+prior written permission.
+
+DISCLAIMER:
+
+  THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
+  TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK AS TO ITS
+  FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE TRUSTEES OF
+  COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK OF ANY KIND, EITHER
+  EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+  THE TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK SHALL NOT
+  BE LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL,
+  OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR
+  IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS
+  HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  YOU SHALL
+  INDEMNIFY AND HOLD HARMLESS THE TRUSTEES OF COLUMBIA UNIVERSITY IN
+  THE CITY OF NEW YORK, ITS EMPLOYEES AND AGENTS FROM AND AGAINST ANY
+  AND ALL CLAIMS, DEMANDS, LOSS, DAMAGE OR EXPENSE (INCLUDING
+  ATTORNEYS' FEES) ARISING OUT OF YOUR USE OF THIS SOFTWARE.
+
+The above copyright notice, permissions notice, and disclaimer may not be
+removed, altered, or obscured and shall be included in all copies of the
+C-Kermit software.  The Trustees of Columbia University in the City of
+New York reserve the right to revoke this permission if any of the terms
+of use set forth above are breached.
+
+(End)
diff --git a/ckermit-8.0.211/ck_crp.c b/ckermit-8.0.211/ck_crp.c
new file mode 100644
index 0000000..c35afd0
--- /dev/null
+++ b/ckermit-8.0.211/ck_crp.c
@@ -0,0 +1,5590 @@
+char *ckcrpv = "Encryption Engine, 8.0.114,  9 Oct 2003";
+/*
+  C K _ C R P . C  -  Cryptography for C-Kermit"
+
+  Copyright (C) 1998, 2004,
+    Trustees of Columbia University in the City of New York.
+    All rights reserved.  See the C-Kermit COPYING.TXT file or the
+    copyright text in the ckcmai.c module for disclaimer and permissions.
+
+  Author:
+  Jeffrey E Altman (jaltman@secure-endpoints.com)
+  Secure Endpoints Inc., New York City
+*/
+
+#define CK_CRP_C
+#ifdef CK_DES
+#ifdef CK_SSL
+#ifndef LIBDES
+#define LIBDES
+#endif /* LIBDES */
+#endif /* CK_SSL */
+#endif /* CK_DES */
+
+#ifdef CRYPT_DLL
+#define CK_AUTHENTICATION
+#define CK_ENCRYPTION
+#define CK_DES
+#define CK_CAST
+#ifndef LIBDES
+#define LIBDES
+#endif /* LIBDES */
+
+#define TELCMDS                         /* to define name array */
+#define TELOPTS                         /* to define name array */
+#define ENCRYPT_NAMES
+#endif /* CRYPT_DLL */
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcnet.h"
+
+#ifdef DEBUG
+#undef DEBUG
+#endif /* DEBUG */
+
+#ifdef CK_AUTHENTICATION
+#ifdef CK_ENCRYPTION
+#define ENCRYPTION
+#ifdef CK_DES
+#define DES_ENCRYPTION
+#endif /* CK_DES */
+#ifdef  CK_CAST
+#define CAST_ENCRYPTION
+#endif /* CK_CAST */
+#ifdef COMMENT
+#define CAST_EXPORT_ENCRYPTION
+#endif /* COMMENT */
+#endif /* CK_ENCRYPTION */
+#endif /* CK_AUTHENTICATION */
+
+#ifdef CK_ENCRYPTION
+
+#include "ckucmd.h"                     /* For struct keytab definition */
+#include "ckuath.h"
+#include "ckuat2.h"
+#ifdef MIT_CURRENT
+#include <krb5.h>
+#endif /* MIT_CURRENT */
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef OS2
+#include <stdarg.h>
+#ifdef OS2ONLY
+#include <os2.h>
+#endif /* OS2ONLY */
+#include "ckosyn.h"
+#else /* OS2 */
+static char * tmpstring = NULL;
+#endif /* OS2 */
+
+#ifndef CAST_OR_EXPORT
+#ifdef CAST_ENCRYPTION
+#define CAST_OR_EXPORT
+#endif /* CAST_ENCRYPTION */
+#ifdef CAST_EXPORT_ENCRYPTION
+#define CAST_OR_EXPORT
+#endif /* CAST_EXPORT_ENCRYPTION */
+#endif /* CAST_OR_EXPORT */
+
+#ifdef CRYPT_DLL
+int cmd_quoting = 0;
+
+#ifndef TELOPT_MACRO
+int
+telopt_index(opt) int opt; {
+    if ( opt >= 0 && opt <= TELOPT_SEND_URL )
+        return(opt);
+    else if ( opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT )
+        return(opt-89);
+    else
+        return(NTELOPTS);
+}
+
+int
+telopt_ok(opt) int opt; {
+    return((opt >= TELOPT_BINARY && opt <= TELOPT_SEND_URL) ||
+        (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT));
+}
+
+CHAR *
+telopt(opt) int opt; {
+    if ( telopt_ok(opt) )
+        return(telopts[telopt_index(opt)]);
+    else
+        return("UNKNOWN");
+}
+#endif /* TELOPT_MACRO */
+
+static int (*p_ttol)(char *,int)=NULL;
+static int (*p_dodebug)(int,char *,char *,long)=NULL;
+static int (*p_dohexdump)(char *,char *,int)=NULL;
+static void (*p_tn_debug)(char *)=NULL;
+static int (*p_vscrnprintf)(char *, ...)=NULL;
+static void * p_k5_context=NULL;
+static unsigned long (*p_reqtelmutex)(unsigned long)=NULL;
+static unsigned long (*p_reltelmutex)(void)=NULL;
+
+unsigned long
+RequestTelnetMutex(unsigned long x)
+{
+    if ( p_reqtelmutex )
+        return p_reqtelmutex(x);
+    return 0;
+}
+
+unsigned long
+ReleaseTelnetMutex(void)
+{
+    if ( p_reltelmutex )
+        return p_reltelmutex();
+    return 0;
+}
+
+int
+ttol(char * s, int n)
+{
+    if ( p_ttol )
+        return(p_ttol(s,n));
+    else
+        return(-1);
+}
+
+int
+dodebug(int flag, char * s1, char * s2, long n)
+{
+    if ( p_dodebug )
+        return(p_dodebug(flag,s1,s2,n));
+    else
+        return(-1);
+}
+
+int
+dohexdump( char * s1, char * s2, int n )
+{
+    if ( p_dohexdump )
+        p_dohexdump(s1,s2,n);
+    return(0);
+}
+
+void
+tn_debug( char * s )
+{
+    if ( p_tn_debug )
+        p_tn_debug(s);
+}
+
+static char myprtfstr[4096];
+int
+Vscrnprintf(const char * format, ...) {
+    int i, len, rc=0;
+    char *cp;
+    va_list ap;
+
+    va_start(ap, format);
+#ifdef NT
+    rc = _vsnprintf(myprtfstr, sizeof(myprtfstr)-1, format, ap);
+#else /* NT */
+    rc = vsprintf(myprtfstr, format, ap);
+#endif /* NT */
+    va_end(ap);
+
+    if ( p_vscrnprintf )
+        return(p_vscrnprintf(myprtfstr));
+    else
+        return(-1);
+}
+
+int
+#ifdef CK_ANSIC
+tn_hex(CHAR * buf, int buflen, CHAR * data, int datalen)
+#else /* CK_ANSIC */
+tn_hex(buf, buflen, data, datalen)
+    CHAR * buf;
+    int buflen;
+    CHAR * data;
+    int datalen;
+#endif /* CK_ANSIC */
+{
+    int i = 0, j = 0, k = 0;
+    CHAR tmp[8];
+#ifdef COMMENT
+    int was_hex = 1;
+
+    for (k=0; k < datalen; k++) {
+        if (data[k] < 32 || data[k] >= 127) {
+            sprintf(tmp,"%s%02X ",was_hex?"":"\" ",data[k]);
+            was_hex = 1;
+        } else {
+            sprintf(tmp,"%s%c",was_hex?"\"":"",data[k]);
+            was_hex = 0;
+        }
+        ckstrncat(buf,tmp,buflen);
+    }
+    if (!was_hex)
+        ckstrncat(buf,"\" ",buflen);
+#else /* COMMENT */
+    if (datalen <= 0 || data == NULL)
+        return(0);
+
+    for (i = 0; i < datalen; i++) {
+        ckstrncat(buf,"\r\n  ",buflen);
+        for (j = 0 ; (j < 16); j++) {
+            if ((i + j) < datalen)
+              sprintf(tmp,
+                      "%s%02x ",
+                      (j == 8 ? "| " : ""),
+                      (CHAR) data[i + j]
+                      );
+            else
+              sprintf(tmp,
+                      "%s   ",
+                      (j == 8 ? "| " : "")
+                      );
+            ckstrncat(buf,tmp,buflen);
+        }
+        ckstrncat(buf," ",buflen);
+        for (k = 0; (k < 16) && ((i + k) < datalen); k++) {
+            sprintf(tmp,
+                     "%s%c",
+                     (k == 8 ? " " : ""),
+                     isprint(data[i + k]) ? data[i + k] : '.'
+                     );
+            ckstrncat(buf,tmp,buflen);
+        }
+        i += j - 1;
+    } /* end for */
+    ckstrncat(buf,"\r\n  ",buflen);
+#endif /* COMMENT */
+    return(strlen(buf));
+}
+
+#ifdef COMMENT
+#define ttol        dll_ttol
+#define dodebug     dll_dodebug
+#define dohexdump   dll_dohexdump
+#define tn_debug    dll_tn_debug
+#define Vscrnprintf dll_vscrnprintf
+#endif /* COMMENT */
+
+char tn_msg[TN_MSG_LEN], hexbuf[TN_MSG_LEN];   /* from ckcnet.c */
+int deblog=1, debses=1, tn_deb=1;
+#else /* CRYPT_DLL */
+extern char tn_msg[], hexbuf[];         /* from ckcnet.c */
+extern int deblog, debses, tn_deb;
+#ifdef MIT_CURRENT
+extern krb5_context k5_context;
+#endif /* MIT_CURRENT */
+#endif /* CRYPT_DLL */
+
+#ifdef LIBDES
+#ifndef UNIX
+#define des_new_random_key            des_random_key
+#define des_set_random_generator_seed des_random_seed
+#endif /* UNIX */
+#define des_fixup_key_parity          des_set_odd_parity
+#ifdef OPENSSL_097
+#define OPENSSL_ENABLE_OLD_DES_SUPPORT
+#include <openssl/des.h>
+#endif /* OPENSSL_097 */
+#else /* LIBDES */
+#ifdef UNIX
+#define des_set_random_generator_seed(x) des_init_random_number_generator(x)
+#endif /* UNIX */
+#ifdef OS2
+#define des_new_random_key            ck_des_new_random_key
+#define des_set_random_generator_seed ck_des_set_random_generator_seed
+#define des_key_sched                 ck_des_key_sched
+#define des_ecb_encrypt               ck_des_ecb_encrypt
+#define des_string_to_key             ck_des_string_to_key
+#define des_fixup_key_parity          ck_des_fixup_key_parity
+#endif /* OS2 */
+#endif /* LIBDES */
+
+#ifdef CK_DES
+/* This code comes from Eric Young's libdes package and is not part   */
+/* of the standard MIT DES library that is part of Kerberos. However, */
+/* it is extremely useful.  So we add it here.                        */
+
+
+/* Weak and semi week keys as take from
+ * %A D.W. Davies
+ * %A W.L. Price
+ * %T Security for Computer Networks
+ * %I John Wiley & Sons
+ * %D 1984
+ * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference
+ * (and actual cblock values).
+ */
+#define NUM_WEAK_KEY    16
+static Block weak_keys[NUM_WEAK_KEY]={
+        /* weak keys */
+        {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
+        {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE},
+        {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
+        {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0},
+        /* semi-weak keys */
+        {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE},
+        {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01},
+        {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1},
+        {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E},
+        {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1},
+        {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01},
+        {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE},
+        {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E},
+        {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E},
+        {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01},
+        {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
+        {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}};
+
+int
+ck_des_is_weak_key(key)
+Block key;
+{
+    int i;
+
+    for (i=0; i<NUM_WEAK_KEY; i++) {
+        /* Added == 0 to comparision, I obviously don't run
+        * this section very often :-(, thanks to
+        * engineering@MorningStar.Com for the fix
+        * eay 93/06/29
+        * Another problem, I was comparing only the first 4
+        * bytes, 97/03/18 */
+        if (memcmp(weak_keys[i],key,sizeof(Block)) == 0)
+            return(1);
+    }
+    return(0);
+}
+
+#ifdef UNIX
+#ifdef LIBDES
+/* These functions are not part of Eric Young's DES library */
+/* _unix_time_gmt_unixsec                                  */
+/* _des_set_random_generator_seed                          */
+/* _des_fixup_key_parity   (added in 0.9.5)                */
+/* _des_new_random_key                                     */
+#include <sys/time.h>
+
+unsigned long
+unix_time_gmt_unixsec (usecptr)
+    unsigned long  *usecptr;
+{
+    struct timeval  now;
+
+    (void) gettimeofday (&now, (struct timezone *)0);
+    if (usecptr)
+        *usecptr = now.tv_usec;
+    return now.tv_sec;
+}
+
+void
+des_set_random_generator_seed(Block B)
+{
+    des_random_seed(B);
+    return;
+}
+
+#ifdef COMMENT
+/* added to openssl in 0.9.5 */
+void
+des_fixup_key_parity(Block B)
+{
+    des_set_odd_parity(B);
+    return;
+}
+#endif /* COMMENT */
+int
+des_new_random_key(Block B)
+{
+    int rc=0;
+    rc = des_random_key(B);
+    return(rc);
+}
+
+#endif /* LIBDES */
+#endif /* UNIX */
+#endif /* CK_DES */
+
+/*
+ * 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 @(#)encrypt.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.  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.
+ */
+
+#include <stdio.h>
+
+/*
+ * These function pointers point to the current routines
+ * for encrypting and decrypting data.
+ */
+static VOID     (*encrypt_output) P((unsigned char *, int));
+static int      (*decrypt_input) P((int));
+
+#ifdef DEBUG
+static int encrypt_debug_mode = 1;
+static int encrypt_verbose = 1;
+#else
+static int encrypt_verbose = 1;
+static int encrypt_debug_mode = 0;
+#endif
+
+static char dbgbuf [16384];
+
+static int decrypt_mode = 0;
+static int encrypt_mode = 0;
+static int autoencrypt = 1;
+static int autodecrypt = 1;
+static int havesessionkey = 0;
+
+static kstream EncryptKSGlobalHack = NULL;
+static int     EncryptType = ENCTYPE_ANY;
+
+#define typemask(x)     ((x) > 0 ? 1 << ((x)-1) : 0)
+
+static long i_support_encrypt =
+        typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64);
+static long i_support_decrypt =
+        typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64);
+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;
+
+/* Make sure that this list is in order of algorithm strength     */
+/* as it determines the search order for selecting specific       */
+/* encryption choices.  All CFB modes must come before OFB modes. */
+static Encryptions encryptions[] = {
+#ifdef DES_ENCRYPTION
+    { "DES3_CFB64",
+          ENCTYPE_DES3_CFB64,
+          des3_cfb64_encrypt,
+          des3_cfb64_decrypt,
+          des3_cfb64_init,
+          des3_cfb64_start,
+          des3_cfb64_is,
+          des3_cfb64_reply,
+          des3_cfb64_session,
+          des3_cfb64_keyid,
+          NULL },
+#endif /* DES_ENCRYPTION */
+#ifdef CAST_ENCRYPTION
+#ifndef CAST_EXPORT_ENCRYPTION
+    { "CAST128_CFB64",  ENCTYPE_CAST128_CFB64,
+          cast_cfb64_encrypt,
+          cast_cfb64_decrypt,
+          cast_cfb64_init,
+          cast_cfb64_start,
+          cast_cfb64_is,
+          cast_cfb64_reply,
+          cast_cfb64_session,
+          cast_cfb64_keyid,
+          NULL },
+#endif
+#endif
+#ifdef DES_ENCRYPTION
+    { "DES_CFB64",
+          ENCTYPE_DES_CFB64,
+          cfb64_encrypt,
+          cfb64_decrypt,
+          cfb64_init,
+          cfb64_start,
+          cfb64_is,
+          cfb64_reply,
+          cfb64_session,
+          cfb64_keyid,
+          NULL },
+#endif  /* DES_ENCRYPTION */
+#if defined (CAST_EXPORT_ENCRYPTION) || defined(CAST_ENCRYPTION)
+    { "CAST5_40_CFB64", ENCTYPE_CAST5_40_CFB64,
+          castexp_cfb64_encrypt,
+          castexp_cfb64_decrypt,
+          castexp_cfb64_init,
+          castexp_cfb64_start,
+          castexp_cfb64_is,
+          castexp_cfb64_reply,
+          castexp_cfb64_session,
+          castexp_cfb64_keyid,
+          NULL },
+#endif /* CAST_ENCRYPTION */
+#ifdef DES_ENCRYPTION
+    { "DES3_OFB64",
+          ENCTYPE_DES3_OFB64,
+          des3_ofb64_encrypt,
+          des3_ofb64_decrypt,
+          des3_ofb64_init,
+          des3_ofb64_start,
+          des3_ofb64_is,
+          des3_ofb64_reply,
+          des3_ofb64_session,
+          des3_ofb64_keyid,
+          NULL },
+#endif /* DES_ENCRYPTION */
+#ifdef CAST_ENCRYPTION
+#ifndef CAST_EXPORT_ENCRYPTION
+    { "CAST128_OFB64",  ENCTYPE_CAST128_OFB64,
+          cast_ofb64_encrypt,
+          cast_ofb64_decrypt,
+          cast_ofb64_init,
+          cast_ofb64_start,
+          cast_ofb64_is,
+          cast_ofb64_reply,
+          cast_ofb64_session,
+          cast_ofb64_keyid,
+          NULL },
+#endif
+#endif
+#ifdef DES_ENCRYPTION
+    { "DES_OFB64",
+          ENCTYPE_DES_OFB64,
+          ofb64_encrypt,
+          ofb64_decrypt,
+          ofb64_init,
+          ofb64_start,
+          ofb64_is,
+          ofb64_reply,
+          ofb64_session,
+          ofb64_keyid,
+          NULL },
+#endif  /* DES_ENCRYPTION */
+#if defined (CAST_EXPORT_ENCRYPTION) || defined(CAST_ENCRYPTION)
+    { "CAST5_40_OFB64", ENCTYPE_CAST5_40_OFB64,
+          castexp_ofb64_encrypt,
+          castexp_ofb64_decrypt,
+          castexp_ofb64_init,
+          castexp_ofb64_start,
+          castexp_ofb64_is,
+          castexp_ofb64_reply,
+          castexp_ofb64_session,
+          castexp_ofb64_keyid,
+          NULL },
+#endif /* CAST_ENCRYPTION */
+    { 0,0,0,0,0,0,0,0,0,0,0  }
+};
+
+int
+get_crypt_table( struct keytab ** pTable, int * pN )
+{
+    int i=0,n=0;
+
+    if ( *pTable )
+    {
+        for ( i=0 ; i < *pN ; i++ )
+            free( (*pTable)[i].kwd ) ;
+        free ( *pTable )  ;
+    }
+    *pTable = NULL;
+    *pN = 0;
+
+    /* How many encryption types do we have? */
+    while ( encryptions[n].name )
+        n++;
+
+    if ( n )
+    {
+        *pTable = malloc( sizeof(struct keytab) * (n+2) ) ;
+        if ( !(*pTable) )
+            return(0);
+
+#ifdef OS2
+        (*pTable)[0].kwd =strdup("automatic");
+#else /* OS2 */
+        makestr(&tmpstring,"automatic");
+        (*pTable)[0].kwd = tmpstring;
+        tmpstring = NULL;
+#endif /* OS2 */
+        (*pTable)[0].kwval = ENCTYPE_ANY;
+        (*pTable)[0].flgs = 0;
+#ifdef OS2
+        (*pTable)[1].kwd =strdup("none");
+#else /* OS2 */
+        makestr(&tmpstring,"none");
+        (*pTable)[1].kwd = tmpstring;
+        tmpstring = NULL;
+#endif /* OS2 */
+        (*pTable)[1].kwval = 999;
+        (*pTable)[1].flgs = 0;
+        (*pN) = 2;
+
+        for ( i=0 ; i < n ; i++ ) {
+            char * newstr = NULL, * p;
+            int newval = encryptions[i].type;
+            int j = 0, len = 0;
+
+#ifdef OS2
+            newstr = strdup(encryptions[i].name);
+            strlwr(newstr);
+#else /* OS2 */
+            makestr(&tmpstring,encryptions[i].name);
+            newstr = tmpstring;
+            tmpstring = NULL;
+            for (p = newstr; *p; p++) if (isupper(*p)) *p = tolower(*p);
+#endif /* OS2 */
+
+            for (j = 0; j < (*pN); j++) {
+                int tempval = 0;
+                char * tempstr = NULL;
+
+                if ( strcmp( (*pTable)[j].kwd, newstr ) > 0 )
+                {
+                    tempval = (*pTable)[j].kwval;
+                    tempstr = (*pTable)[j].kwd;
+                    (*pTable)[j].kwd = newstr ;
+                    (*pTable)[j].kwval = newval;
+                    newval = tempval;
+                    newstr = tempstr;
+                    (*pTable)[j].flgs = 0;
+                }
+            }
+            (*pTable)[*pN].kwd = newstr ;
+            (*pTable)[*pN].kwval = newval;
+            (*pTable)[*pN].flgs = 0 ;
+            (*pN)++ ;
+        }
+    } else {
+        *pTable = malloc( sizeof(struct keytab) * 2 ) ;
+        if ( !(*pTable) )
+            return(0);
+
+#ifdef OS2
+        (*pTable)[0].kwd =strdup("automatic");
+#else /* OS2 */
+        makestr(&tmpstring,"automatic");
+        (*pTable)[0].kwd = tmpstring;
+        tmpstring = NULL;
+#endif /* OS2 */
+        (*pTable)[0].kwval = ENCTYPE_ANY;
+        (*pTable)[0].flgs = 0;
+#ifdef OS2
+        (*pTable)[1].kwd =strdup("none");
+#else /* OS2 */
+        makestr(&tmpstring,"none");
+        (*pTable)[1].kwd = tmpstring;
+        tmpstring = NULL;
+#endif /* OS2 */
+        (*pTable)[1].kwval = 999;
+        (*pTable)[1].flgs = 0;
+        (*pN) = 2;
+    }
+    return(*pN);
+}
+
+static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPTION,
+                                      ENCRYPT_SUPPORT };
+static unsigned char str_suplen = 0;
+static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPTION };
+static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPTION, 0, IAC, SE };
+
+_PROTOTYP(int  encrypt_request_end, (VOID));
+_PROTOTYP(int  encrypt_request_start, (VOID));
+_PROTOTYP(int  encrypt_enc_keyid, (unsigned char *, int));
+_PROTOTYP(int  encrypt_dec_keyid, (unsigned char *, int));
+_PROTOTYP(int  encrypt_support, (unsigned char *, int));
+_PROTOTYP(int  encrypt_start, (unsigned char *, int));
+_PROTOTYP(int  encrypt_end, (VOID));
+
+_PROTOTYP(int encrypt_ks_stream,(struct kstream_data_block *, /* output */
+                                   struct kstream_data_block *)); /* input */
+
+_PROTOTYP(int decrypt_ks_stream,(struct kstream_data_block *, /* output */
+                                   struct kstream_data_block *)); /* input */
+
+int
+#ifdef CK_ANSIC
+encrypt_ks_stream(struct kstream_data_block *i,
+                  struct kstream_data_block *o)
+#else
+encrypt_ks_stream(i,o)
+    struct kstream_data_block *i; struct kstream_data_block *o;
+#endif
+{
+    /*
+    * this is really quite bogus, since it does an in-place encryption...
+    */
+    if (encrypt_output) {
+        encrypt_output(i->ptr, i->length);
+        return 1;
+    }
+    return 0;
+}
+
+
+int
+#ifdef CK_ANSIC
+decrypt_ks_stream(struct kstream_data_block *i,
+                  struct kstream_data_block *o)
+#else
+decrypt_ks_stream(i,o)
+    struct kstream_data_block *i; struct kstream_data_block *o;
+#endif
+{
+    unsigned int len;
+  /*
+   * this is really quite bogus, since it does an in-place decryption...
+   */
+    if (decrypt_input) {
+        for (len = 0 ; len < i->length ; len++)
+            ((unsigned char *)i->ptr)[len]
+                = decrypt_input(((unsigned char *)i->ptr)[len]);
+        return 1;
+    }
+    return 0;
+}
+
+int
+#ifdef CK_ANSIC
+decrypt_ks_hack(unsigned char *buf, int cnt)
+#else
+decrypt_ks_hack(buf,cnt) unsigned char *buf; int cnt;
+#endif
+{
+    int len;
+  /*
+   * this is really quite bogus, since it does an in-place decryption...
+   */
+    for (len = 0 ; len < cnt ; len++)
+        buf[len] = decrypt_input(buf[len]);
+
+#ifdef DEBUG
+    hexdump("decrypt ks hack", buf, cnt);
+#endif
+    return 1;
+}
+
+
+/*
+ * parsedat[0] == the suboption we might be negotiating,
+ */
+int
+#ifdef CK_ANSIC
+encrypt_parse(unsigned char *parsedat, int end_sub)
+#else
+encrypt_parse(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+    int rc = 0;
+
+    switch(parsedat[1]) {
+    case ENCRYPT_START:
+        rc = encrypt_start(parsedat + 2, end_sub - 2);
+        break;
+    case ENCRYPT_END:
+        rc = encrypt_end();
+        break;
+    case ENCRYPT_SUPPORT:
+        rc = encrypt_support(parsedat + 2, end_sub - 2);
+        break;
+    case ENCRYPT_REQSTART:
+        rc = encrypt_request_start();
+        break;
+    case ENCRYPT_REQEND:
+        /*
+        * We can always send an REQEND so that we cannot
+        * get stuck encrypting.  We should only get this
+        * if we have been able to get in the correct mode
+        * anyhow.
+        */
+        rc = encrypt_request_end();
+        break;
+    case ENCRYPT_IS:
+        rc = encrypt_is(parsedat + 2, end_sub - 2);
+        break;
+    case ENCRYPT_REPLY:
+        rc = encrypt_reply(parsedat + 2, end_sub - 2);
+        break;
+    case ENCRYPT_ENC_KEYID:
+        rc = encrypt_enc_keyid(parsedat + 2, end_sub - 2);
+        break;
+    case ENCRYPT_DEC_KEYID:
+        rc = encrypt_dec_keyid(parsedat + 2, end_sub - 2);
+        break;
+    default:
+        rc = -1;
+        break;
+    }
+    return(rc);
+}
+
+/* XXX */
+Encryptions *
+#ifdef CK_ANSIC
+findencryption(int type)
+#else
+findencryption(type) int type;
+#endif
+{
+    Encryptions *ep = encryptions;
+
+    if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type)))
+        return(0);
+    while (ep->type && ep->type != type)
+        ++ep;
+    return(ep->type ? ep : 0);
+}
+
+Encryptions *
+#ifdef CK_ANSIC
+finddecryption(int type)
+#else
+finddecryption(type) int type;
+#endif
+{
+    Encryptions *ep = encryptions;
+
+    if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & 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)();
+} ki[2] = {
+    { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption },
+    { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption },
+};
+
+VOID
+#ifdef CK_ANSIC
+encrypt_init(kstream iks, int type)
+#else
+encrypt_init(iks, type) kstream iks; int type;
+#endif
+{
+    Encryptions *ep = encryptions;
+
+    i_support_encrypt = i_support_decrypt = 0;
+    remote_supports_encrypt = remote_supports_decrypt = 0;
+    i_wont_support_encrypt = i_wont_support_decrypt = 0;
+    encrypt_mode = 0;
+    decrypt_mode = 0;
+    encrypt_output = NULL;
+    decrypt_input = NULL;
+    ki[0].keylen = 0;
+    memset(ki[0].keyid,0,MAXKEYLEN);
+    ki[1].keylen = 0;
+    memset(ki[1].keyid,0,MAXKEYLEN);
+    havesessionkey = 0;
+    autoencrypt = 1;
+    autodecrypt = 1;
+
+    EncryptKSGlobalHack = iks;
+    EncryptType = type;
+
+    str_send[0] = IAC;
+    str_send[1] = SB;
+    str_send[2] = TELOPT_ENCRYPTION;
+    str_send[3] = ENCRYPT_SUPPORT;
+    str_suplen = 4;
+
+    while (ep->type) {
+        if ( EncryptType == ENCTYPE_ANY ||
+             EncryptType == ep->type ) {
+#ifdef DEBUG
+            if (encrypt_debug_mode) {
+                sprintf(dbgbuf, ">>>I will support %s\n",
+                         ENCTYPE_NAME(ep->type));       /* safe */
+                debug(F110,"encrypt_init",dbgbuf,0);
+            }
+#endif
+            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)(0);
+        ++ep;
+    }
+    str_send[str_suplen++] = IAC;
+    str_send[str_suplen++] = SE;
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_send_support(VOID)
+#else
+encrypt_send_support()
+#endif
+{
+    Encryptions *ep = encryptions;
+
+#ifdef CK_SSL
+    if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+        return;
+#endif /* CK_SSL */
+
+    str_send[0] = IAC;
+    str_send[1] = SB;
+    str_send[2] = TELOPT_ENCRYPTION;
+    str_send[3] = ENCRYPT_SUPPORT;
+    str_suplen = 4;
+
+    while (ep->type) {
+        if ( EncryptType == ENCTYPE_ANY ||
+             EncryptType == ep->type ) {
+#ifdef DEBUG
+            if (encrypt_debug_mode) {
+                sprintf(dbgbuf, ">>>I will support %s\n",
+                         ENCTYPE_NAME(ep->type));               /* safe */
+                debug(F110,"encrypt_send_support",dbgbuf,0);
+            }
+#endif
+            if ((i_wont_support_decrypt & typemask(ep->type)) == 0)
+                if ((str_send[str_suplen++] = ep->type) == IAC)
+                    str_send[str_suplen++] = IAC;
+        }
+        ++ep;
+    }
+    str_send[str_suplen++] = IAC;
+    str_send[str_suplen++] = SE;
+
+    /*
+    * If the user has requested that decryption start
+    * immediatly, then send a "REQUEST START" before
+    * we negotiate the type.
+    */
+    if (autodecrypt)
+        encrypt_send_request_start();
+
+    if (deblog || tn_deb || debses) {
+        int i;
+        sprintf(tn_msg,"TELNET SENT SB %s SUPPORT ",
+                 TELOPT(TELOPT_ENCRYPTION));                    /* safe */
+        for ( i=4;i<str_suplen-2;i++ ) {
+            if ( str_send[i] == IAC ) {
+                ckstrncat(tn_msg,"IAC ",TN_MSG_LEN);
+                i++;
+            }
+            ckstrncat(tn_msg,ENCTYPE_NAME(str_send[i]),TN_MSG_LEN);
+            ckstrncat(tn_msg," ",TN_MSG_LEN);
+        }
+        ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+        debug(F100,tn_msg,"",0);
+        if (tn_deb || debses) tn_debug(tn_msg);
+    }
+#ifdef OS2
+    RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+    ttol(str_send, str_suplen);
+#ifdef OS2
+    ReleaseTelnetMutex();
+#endif
+
+    str_suplen = 0;
+}
+
+/*
+ * Called when ENCRYPT SUPPORT is received.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_support(unsigned char *_typelist, int _cnt)
+#else
+encrypt_support(_typelist, _cnt) unsigned char * _typelist; int _cnt;
+#endif
+{
+    register int type, use_type = 0;
+    unsigned char * typelist = _typelist;
+    int cnt = _cnt;
+    Encryptions *ep;
+
+    debug(F111,"encrypt_support","cnt",cnt);
+
+  /*
+   * Forget anything the other side has previously told us.
+   */
+    remote_supports_decrypt = 0;
+
+    while (cnt-- > 0) {
+        type = *typelist++;
+        if ( EncryptType == ENCTYPE_ANY ||
+             EncryptType == type ) {
+#ifdef DEBUG
+            if (encrypt_debug_mode) {
+                sprintf(dbgbuf, ">>>Remote supports %s (%d)\n",
+                         ENCTYPE_NAME(type), type);             /* safe */
+                debug(F110,"encrypt_support",dbgbuf,0);
+            }
+#endif
+            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) {
+            debug(F111,"encrypt_support","findencryption == NULL",use_type);
+            return(-1);
+        }
+        type = ep->start ? (*ep->start)(DIR_ENCRYPT, 0) : 0;
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            sprintf(dbgbuf, ">>>(*ep->start)() %s returned %d (%s)\n",
+                     ENCTYPE_NAME(use_type), type,
+                     ENCRYPT_NAME(type));                       /* safe */
+            debug(F110,"encrypt_support",dbgbuf,0);
+        }
+#endif
+        if (type < 0) {
+            debug(F111,"encrypt_support","type < 0",type);
+            return(-1);
+        }
+        encrypt_mode = use_type;
+        if (type == 0)
+            encrypt_start_output(use_type);
+        debug(F111,"encrypt_support","success",type);
+        return(0);
+    }
+    debug(F111,"encrypt_support","failed",use_type);
+    return(-1);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_is(unsigned char *data, int cnt)
+#else
+encrypt_is(data, cnt) unsigned char *data; int cnt;
+#endif /* CK_ANSIC */
+{
+    Encryptions *ep;
+    register int type, ret;
+
+    if (--cnt < 0)
+        return(-1);
+    type = *data++;
+    if (type < ENCTYPE_CNT)
+        remote_supports_encrypt |= typemask(type);
+    if (!(ep = finddecryption(type))) {
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            sprintf(dbgbuf, ">>>encrypt_is:  "
+                     "Can't find type %s (%d) for initial negotiation\n",
+                     ENCTYPE_NAME_OK(type)
+                     ? ENCTYPE_NAME(type) : "(unknown)",
+                     type);                                     /* safe */
+            debug(F110,"encrypt_is",dbgbuf,0);
+        }
+#endif
+        return(-1);
+    }
+    if (!ep->is) {
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            sprintf(dbgbuf, ">>>encrypt_is:  "
+                     "No initial negotiation needed for type %s (%d)\n",
+                     ENCTYPE_NAME_OK(type)
+                     ? ENCTYPE_NAME(type) : "(unknown)",
+                     type);                                     /* safe */
+            debug(F110,"encrypt_is",dbgbuf,0);
+        }
+#endif
+        ret = 0;
+    } else {
+        ret = (*ep->is)(data, cnt);
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            sprintf(dbgbuf, "encrypt_is:  "
+                     "(*ep->is)(%x, %d) returned %s(%d)\n", data, cnt,
+                     (ret < 0) ? "FAIL " :
+                     (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); /* safe */
+            debug(F110,"encrypt_is",dbgbuf,0);
+        }
+#endif
+    }
+    if (ret < 0) {
+        autodecrypt = 0;
+        return(-1);
+    } else {
+        decrypt_mode = type;
+        if (ret == 0 && autodecrypt) {
+            encrypt_send_request_start();
+        }
+    }
+    return(0);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_reply(unsigned char *data, int cnt)
+#else
+encrypt_reply(data, cnt) unsigned char *data; int cnt;
+#endif
+{
+    Encryptions *ep;
+    register int ret, type;
+
+    if (--cnt < 0)
+        return(-1);
+    type = *data++;
+    if (!(ep = findencryption(type))) {
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            sprintf(dbgbuf,
+                    ">>>Can't find type %s (%d) for initial negotiation\n",
+                     ENCTYPE_NAME_OK(type)
+                     ? ENCTYPE_NAME(type) : "(unknown)",
+                     type);                                     /* safe */
+            debug(F110,"encrypt_reply",dbgbuf,0);
+        }
+#endif
+        return(-1);
+    }
+    if (!ep->reply) {
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+      sprintf(dbgbuf, ">>>No initial negotiation needed for type %s (%d)\n",
+               ENCTYPE_NAME_OK(type)
+               ? ENCTYPE_NAME(type) : "(unknown)",
+               type);                                           /* safe */
+            debug(F110,"encrypt_reply",dbgbuf,0);
+        }
+#endif
+        ret = 0;
+    } else {
+        ret = (*ep->reply)(data, cnt);
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            sprintf(dbgbuf, "(*ep->reply)(%x, %d) returned %s(%d)\n",
+                     data, cnt,
+                     (ret < 0) ? "FAIL " :
+                     (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); /* safe */
+            debug(F110,"encrypt_reply",dbgbuf,0);
+        }
+#endif
+    }
+#ifdef DEBUG
+    if (encrypt_debug_mode) {
+        sprintf(dbgbuf, ">>>encrypt_reply returned %d\n", ret); /* safe */
+        debug(F110,"encrypt_reply",dbgbuf,0);
+    }
+#endif
+    if (ret < 0) {
+        autoencrypt = 0;
+        return(-1);
+    } else {
+        encrypt_mode = type;
+        if (ret == 0 && autoencrypt)
+            encrypt_start_output(type);
+    }
+    return(0);
+}
+
+/*
+ * Called when a ENCRYPT START command is received.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_start(unsigned char *data, int cnt)
+#else
+encrypt_start(data, cnt) unsigned char *data; int cnt;
+#endif
+{
+    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...
+        */
+        encrypt_send_request_end();
+        printf("Authentication error!\n%s\n",
+                "Warning, Cannot decrypt input stream!!!");
+        return(-1);
+    }
+
+    if (ep = finddecryption(decrypt_mode)) {
+        if ( decrypt_input != ep->input ) {
+            decrypt_input = ep->input;
+            EncryptKSGlobalHack->decrypt = decrypt_ks_stream;
+            EncryptKSGlobalHack->decrypt_type = ep->type;
+
+            if (encrypt_verbose) {
+                sprintf(dbgbuf, "Input is now decrypted with type %s",
+                         ENCTYPE_NAME(decrypt_mode));           /* safe */
+                debug(F110,"encrypt_start",dbgbuf,0);
+                printf("%s\n",dbgbuf);
+            }
+#ifdef DEBUG
+            if (encrypt_debug_mode) {
+                sprintf(dbgbuf, ">>>Start to decrypt input with type %s",
+                         ENCTYPE_NAME(decrypt_mode));           /* safe */
+                debug(F110,"ck_crp",dbgbuf,0);
+            }
+#endif
+        }
+    } else {
+        char buf[1024];
+        sprintf(buf, "Warning, Cannot decrypt type %s (%d)!!!",
+                  ENCTYPE_NAME_OK(decrypt_mode)
+                  ? ENCTYPE_NAME(decrypt_mode) : "(unknown)",
+                  decrypt_mode);                                /* safe */
+        printf("Authentication error!\n%s\n",buf);
+        encrypt_send_request_end();
+        return(-1);
+    }
+    return(0);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_dont_support(int type)
+#else
+encrypt_dont_support(type) int type;
+#endif
+{
+    i_wont_support_encrypt |= typemask(type);
+    i_wont_support_decrypt |= typemask(type);
+    return(0);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_session_key(Session_Key *key, int server)
+#else
+encrypt_session_key(key, server) Session_Key *key; int server;
+#endif
+{
+    Encryptions *ep = encryptions;
+
+    if (havesessionkey)
+        return(0);
+
+    havesessionkey = 1;
+
+    while (ep->type) {
+        debug(F111,"encrypt_session_key",ep->name,ep->type);
+        if (ep->session) {
+            if ((*ep->session)(key, server) < 0) {
+                i_wont_support_encrypt |= typemask(ep->type);
+                i_wont_support_decrypt |= typemask(ep->type);
+            }
+        }
+        ++ep;
+    }
+    debug(F111,"encrypt_session_key (done)",ep->name,ep->type);
+    return(0);
+}
+
+/*
+ * Called when ENCRYPT END is received.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_end(VOID)
+#else
+encrypt_end()
+#endif
+{
+    decrypt_input = NULL;
+    EncryptKSGlobalHack->decrypt = NULL;
+    EncryptKSGlobalHack->decrypt_type = ENCTYPE_ANY;
+#ifdef DEBUG
+    if (encrypt_debug_mode) {
+        sprintf(dbgbuf, ">>>Input is back to clear text");      /* safe */
+        debug(F110,"encrypt_end",dbgbuf,0);
+    }
+#endif
+    if (encrypt_verbose) {
+        sprintf(dbgbuf, "Input is now clear text");             /* safe */
+        debug(F110,"encrypt_end",dbgbuf,0);
+        printf("%s\n",dbgbuf);
+    }
+    return(0);
+}
+
+/*
+ * Called when ENCRYPT REQUEST-END is received.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_request_end(VOID)
+#else
+encrypt_request_end()
+#endif
+{
+    encrypt_send_end();
+    return(0);
+}
+
+/*
+ * 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.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_request_start(VOID)
+#else
+encrypt_request_start()
+#endif
+{
+    if (encrypt_mode != 0)
+        encrypt_start_output(encrypt_mode);
+    return(0);
+}
+
+static unsigned char str_keyid[(MAXKEYLEN*2)+5] = {
+    IAC, SB, TELOPT_ENCRYPTION
+};
+_PROTOTYP(int encrypt_keyid,(struct key_info *,unsigned char *,int));
+
+int
+#ifdef CK_ANSIC
+encrypt_enc_keyid(unsigned char *keyid, int len)
+#else
+encrypt_enc_keyid(keyid, len) unsigned char *keyid; int len;
+#endif
+{
+    return(encrypt_keyid(&ki[1], keyid, len));
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_dec_keyid(unsigned char *keyid, int len)
+#else
+encrypt_dec_keyid(keyid, len) unsigned char *keyid; int len;
+#endif /* CK_ANSIC */
+{
+    return(encrypt_keyid(&ki[0], keyid, len));
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len)
+#else
+encrypt_keyid(kp, keyid, len)
+    struct key_info *kp; unsigned char *keyid; int len;
+#endif
+{
+    Encryptions *ep;
+    int dir = kp->dir;
+    register int ret = 0;
+
+    if (!(ep = (*kp->getcrypt)(*kp->modep))) {
+        if (len == 0)
+            return(-1);
+        kp->keylen = 0;
+    } else if (len == 0 || len > MAXKEYLEN) {
+        /*
+        * Empty option or Key too long, indicates a failure.
+        */
+        if (kp->keylen == 0)
+            return(-1);
+        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;
+        memcpy(kp->keyid, keyid, len);          /* length < MAXKEYLEN */
+        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(0);
+    }
+
+    encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0);
+    return(0);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_send_keyid(int dir, unsigned char *keyid, int keylen, int saveit)
+#else
+encrypt_send_keyid(dir, keyid, keylen, saveit)
+     int dir; unsigned char *keyid; int keylen; int saveit;
+#endif
+{
+    unsigned char *strp;
+
+#ifdef CK_SSL
+    if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+        return(0);
+#endif /* CK_SSL */
+
+    str_keyid[3] = (dir == DIR_ENCRYPT)
+        ? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID;
+    if (saveit && keylen <= MAXKEYLEN) {
+        struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1];
+        memcpy(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;
+
+    if (deblog || tn_deb || debses) {
+        int i;
+        sprintf(tn_msg,"TELNET SENT SB %s %s ",
+                 TELOPT(TELOPT_ENCRYPTION),
+                 (dir == DIR_ENCRYPT) ? "ENC-KEYID" : "DEC-KEYID"); /* safe */
+        tn_hex(tn_msg,TN_MSG_LEN,&str_keyid[4],strp-str_keyid-2-4);
+        ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+        debug(F100,tn_msg,"",0);
+        if (tn_deb || debses) tn_debug(tn_msg);
+    }
+#ifdef OS2
+    RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+    ttol(str_keyid, strp - str_keyid);
+#ifdef OS2
+    ReleaseTelnetMutex();
+#endif
+    return(0);
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_auto(int on)
+#else
+encrypt_auto(on) int on;
+#endif
+{
+    if (on < 0)
+        autoencrypt ^= 1;
+    else
+        autoencrypt = on ? 1 : 0;
+}
+
+VOID
+#ifdef CK_ANSIC
+decrypt_auto(int on)
+#else
+decrypt_auto(on) int on;
+#endif
+{
+    if (on < 0)
+        autodecrypt ^= 1;
+    else
+        autodecrypt = on ? 1 : 0;
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_start_output(int type)
+#else
+encrypt_start_output(type) int type;
+#endif
+{
+    Encryptions *ep;
+    register unsigned char *p;
+    register int i;
+
+#ifdef CK_SSL
+    if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+        return;
+#endif /* CK_SSL */
+
+    if (!(ep = findencryption(type))) {
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            sprintf(dbgbuf, ">>>Can't encrypt with type %s (%d)\n",
+                     ENCTYPE_NAME_OK(type)
+                     ? ENCTYPE_NAME(type) : "(unknown)",
+                     type);                                     /* safe */
+            debug(F110,"encrypt_start_output",dbgbuf,0);
+        }
+#endif
+        return;
+    }
+    if (ep->start) {
+        i = (*ep->start)(DIR_ENCRYPT, 0);
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            sprintf(dbgbuf, ">>>Encrypt start: %s (%d) %s\n",
+                     (i < 0) ? "failed" :
+                     "initial negotiation in progress",
+                     i, ENCTYPE_NAME(type));                    /* safe */
+            debug(F110,"encrypt_start_output",dbgbuf,0);
+        }
+#endif
+        if (i)
+            return;
+    }
+
+    if ( encrypt_output != ep->output ) {
+        p = str_start;
+        *p++ = IAC;
+        *p++ = SB;
+        *p++ = TELOPT_ENCRYPTION;
+        *p++ = ENCRYPT_START;
+        for (i = 0; i < ki[0].keylen; ++i) {
+            if (( *p++ = ki[0].keyid[i]) == IAC)
+                *p++ = IAC;
+        }
+        *p++ = IAC;
+        *p++ = SE;
+
+        if (deblog || tn_deb || debses) {
+            int i;
+            sprintf(tn_msg,"TELNET SENT SB %s START ",
+                     TELOPT(TELOPT_ENCRYPTION));                /* safe */
+            tn_hex(tn_msg,TN_MSG_LEN,&str_start[4],p-str_start-2-4);
+            ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+            debug(F100,tn_msg,"",0);
+            if (tn_deb || debses) tn_debug(tn_msg);
+        }
+#ifdef OS2
+        RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+        ttol(str_start, p - str_start);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+
+  /*
+   * 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;
+        EncryptKSGlobalHack->encrypt = encrypt_ks_stream;
+        EncryptKSGlobalHack->encrypt_type = type;
+        encrypt_mode = type;
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            sprintf(dbgbuf, ">>>Started to encrypt output with type %s",
+                     ENCTYPE_NAME(type));                       /* safe */
+            debug(F110,"encrypt_start_output",dbgbuf,0);
+        }
+#endif
+        if (encrypt_verbose) {
+            sprintf(dbgbuf, "Output is now encrypted with type %s",
+                     ENCTYPE_NAME(type));                       /* safe */
+            debug(F110,"encrypt_start_output",dbgbuf,0);
+            printf("%s\n",dbgbuf);
+        }
+    }
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_send_end(VOID)
+#else
+encrypt_send_end()
+#endif
+{
+#ifdef CK_SSL
+    if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+        return;
+#endif /* CK_SSL */
+
+    if (!encrypt_output)
+        return;
+
+    str_end[0] = IAC;
+    str_end[1] = SB;
+    str_end[2] = TELOPT_ENCRYPTION;
+    str_end[3] = ENCRYPT_END;
+    str_end[4] = IAC;
+    str_end[5] = SE;
+
+    if (deblog || tn_deb || debses) {
+        int i;
+        sprintf(tn_msg,"TELNET SENT SB %s END IAC SE",
+                 TELOPT(TELOPT_ENCRYPTION));                    /* safe */
+        debug(F100,tn_msg,"",0);
+        if (tn_deb || debses) tn_debug(tn_msg);
+    }
+#ifdef OS2
+    RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+    ttol(str_end, sizeof(str_end));
+#ifdef OS2
+    ReleaseTelnetMutex();
+#endif
+
+    encrypt_output = 0;
+    EncryptKSGlobalHack->encrypt = NULL;
+    EncryptKSGlobalHack->encrypt_type = ENCTYPE_ANY;
+#ifdef DEBUG
+    if (encrypt_debug_mode) {
+        sprintf(dbgbuf, ">>>Output is back to clear text");     /* safe */
+        debug(F110,"encrypt_send_end",dbgbuf,0);
+    }
+#endif
+    if (encrypt_verbose) {
+        sprintf(dbgbuf, "Output is now clear text");            /* safe */
+        debug(F110,"encrypt_send_end",dbgbuf,0);
+        printf("%s\n",dbgbuf);
+    }
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_send_request_start(VOID)
+#else
+encrypt_send_request_start()
+#endif
+{
+    register unsigned char *p;
+    register int i;
+
+#ifdef CK_SSL
+    if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+        return;
+#endif /* CK_SSL */
+
+    p = str_start;
+    *p++ = IAC;
+    *p++ = SB;
+    *p++ = TELOPT_ENCRYPTION;
+    *p++ = ENCRYPT_REQSTART;
+    for (i = 0; i < ki[1].keylen; ++i) {
+        if (( *p++ = ki[1].keyid[i]) == IAC)
+            *p++ = IAC;
+    }
+    *p++ = IAC;
+    *p++ = SE;
+
+    if (deblog || tn_deb || debses) {
+        int i;
+        sprintf(tn_msg,"TELNET SENT SB %s REQUEST-START ",
+                 TELOPT(TELOPT_ENCRYPTION));                    /* safe */
+        tn_hex(tn_msg,TN_MSG_LEN,&str_start[4],p-str_start-2-4);
+        ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+        debug(F100,tn_msg,"",0);
+        if (tn_deb || debses) tn_debug(tn_msg);
+    }
+#ifdef OS2
+    RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+    ttol(str_start, p - str_start);
+#ifdef OS2
+    ReleaseTelnetMutex();
+#endif
+
+    if (encrypt_debug_mode) {
+        sprintf(dbgbuf, ">>>Request input to be encrypted\n");  /* safe */
+        debug(F110,"encrypt_send_request_start",dbgbuf,0);
+    }
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_send_request_end(VOID)
+#else
+encrypt_send_request_end()
+#endif
+{
+#ifdef CK_SSL
+    if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+        return;
+#endif /* CK_SSL */
+
+    str_end[0] = IAC;
+    str_end[1] = SB;
+    str_end[2] = TELOPT_ENCRYPTION;
+    str_end[3] = ENCRYPT_REQEND;
+    str_end[4] = IAC;
+    str_end[5] = SE;
+
+    if (deblog || tn_deb || debses) {
+        int i;
+        sprintf(tn_msg,"TELNET SENT SB %s REQEND IAC SE",
+                 TELOPT(TELOPT_ENCRYPTION));                    /* safe */
+        debug(F100,tn_msg,"",0);
+        if (tn_deb || debses) tn_debug(tn_msg);
+    }
+#ifdef OS2
+    RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+    ttol(str_end, sizeof(str_end));
+#ifdef OS2
+    ReleaseTelnetMutex();
+#endif
+
+    if (encrypt_debug_mode) {
+        sprintf(dbgbuf, ">>>Request input to be clear text\n"); /* safe */
+        debug(F110,"encrypt_send_request_end",dbgbuf,0);
+    }
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_is_encrypting(VOID)
+#else
+encrypt_is_encrypting()
+#endif
+{
+    if (encrypt_output)
+        return 1;
+    return 0;
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_is_decrypting(VOID)
+#else
+encrypt_is_decrypting()
+#endif
+{
+    if (decrypt_input)
+        return 1;
+    return 0;
+}
+
+#ifdef DEBUG
+void
+encrypt_debug(mode)
+     int mode;
+{
+    encrypt_debug_mode = mode;
+}
+#endif
+
+#ifdef CK_DES
+/*-
+ * 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 @(#)enc_des.c       8.1 (Berkeley) 6/4/93 */
+
+#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 xFAILED         -1
+
+Schedule test_sched;
+
+struct des_stinfo {
+    Block               str_output;
+    Block               str_feed;
+    Block               str_iv;
+    Block               str_ikey;
+#ifdef MIT_CURRENT
+    unsigned char       str_keybytes[8];
+    krb5_keyblock       str_key;
+#else /* MIT_CURRENT */
+    Schedule            str_sched;
+    int                 str_index;
+#endif /* MIT_CURRENT */
+    int                 str_flagshift;
+};
+
+struct des_fb {
+#ifndef MIT_CURRENT
+    Block krbdes_key;
+    Schedule krbdes_sched;
+#endif /* MIT_CURRENT */
+    Block temp_feed;
+    unsigned char fb_feed[64];
+    int need_start;
+    int state[2];
+    int keyid[2];
+    int once;
+#ifdef MIT_CURRENT
+    int validkey;
+#endif /* MIT_CURRENT */
+    struct des_stinfo  streams[2];
+};
+static struct des_fb des_fb[2];
+
+struct des3_stinfo {
+    Block               str_output;
+    Block               str_feed;
+    Block               str_iv;
+    Block               str_ikey[3];
+    Schedule            str_sched[3];
+    int                 str_index;
+    int                 str_flagshift;
+};
+
+struct des3_fb {
+#ifndef MIT_CURRENT
+    Block krbdes_key[3];
+    Schedule krbdes_sched[3];
+#endif /* MIT_CURRENT */
+    Block temp_feed;
+    unsigned char fb_feed[64];
+    int need_start;
+    int state[2];
+    int keyid[2];
+    int once;
+#ifdef MIT_CURRENT
+    int validkey;
+#endif /* MIT_CURRENT */
+    struct des3_stinfo streams[2];
+};
+static struct des3_fb des3_fb[2];
+
+struct keyidlist {
+    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
+#define FB64_CHALLENGE  4
+#define FB64_RESPONSE   5
+
+void fb64_stream_iv P((Block, struct des_stinfo *));
+void fb64_init P((struct des_fb *));
+static int fb64_start P((struct des_fb *, int, int));
+int fb64_is P((unsigned char *, int, struct des_fb *));
+int fb64_reply P((unsigned char *, int, struct des_fb *));
+static int fb64_session P((Session_Key *, int, struct des_fb *));
+void fb64_stream_key P((Block, struct des_stinfo *));
+int fb64_keyid P((int, unsigned char *, int *, struct des_fb *));
+
+#ifdef MIT_CURRENT
+static void
+#ifdef CK_ANSIC
+ecb_encrypt(struct des_stinfo *stp, Block in, Block out)
+#else /* CKANSIC */
+ecb_encrypt(stp, in, out)
+    struct des_stinfo *stp;
+    Block in;
+    Block out;
+#endif /* CK_ANSIC */
+{
+    krb5_error_code code;
+    krb5_data din;
+    krb5_enc_data dout;
+
+    din.length = 8;
+    din.data = in;
+
+    dout.ciphertext.length = 8;
+    dout.ciphertext.data = out;
+    dout.enctype = ENCTYPE_UNKNOWN;
+
+#ifdef CRYPT_DLL
+    code = krb5_c_encrypt(*p_k5_context, &stp->str_key, 0, 0,
+                           &din, &dout);
+#else /* CRYPT_DLL */
+    code = krb5_c_encrypt(k5_context, &stp->str_key, 0, 0,
+                           &din, &dout);
+#endif /* CRYPT_DLL */
+    /* XXX I'm not sure what to do if this fails */
+    if (code)
+        com_err("libtelnet", code, "encrypting stream data");
+}
+#endif /* MIT_CURRENT */
+
+void
+cfb64_init(server)
+    int server;
+{
+    fb64_init(&des_fb[CFB]);
+    des_fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
+    des_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
+    des_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
+}
+
+void
+ofb64_init(server)
+    int server;
+{
+    fb64_init(&des_fb[OFB]);
+    des_fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
+    des_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
+    des_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
+}
+
+void
+fb64_init(fbp)
+    register struct des_fb *fbp;
+{
+    memset((void *)fbp, 0, sizeof(*fbp));
+    fbp->state[0] = fbp->state[1] = xFAILED;
+    fbp->fb_feed[0] = IAC;
+    fbp->fb_feed[1] = SB;
+    fbp->fb_feed[2] = TELOPT_ENCRYPTION;
+    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(dir, server)
+    int dir;
+    int server;
+{
+    return(fb64_start(&des_fb[CFB], dir, server));
+}
+int
+ofb64_start(dir, server)
+    int dir;
+    int server;
+{
+    return(fb64_start(&des_fb[OFB], dir, server));
+}
+
+static int
+fb64_start(fbp, dir, server)
+    struct des_fb *fbp;
+    int dir;
+    int server;
+{
+    int x;
+    unsigned char *p;
+    register 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 == xFAILED)
+            state = IN_PROGRESS;
+        break;
+
+    case DIR_ENCRYPT:
+        state = fbp->state[dir-1];
+        if (state == xFAILED)
+            state = IN_PROGRESS;
+        else if ((state & NO_SEND_IV) == 0)
+            break;
+
+#ifdef MIT_CURRENT
+        if (!fbp->validkey) {
+            fbp->need_start = 1;
+            break;
+        }
+#else /* MIT_CURRENT */
+        if (!VALIDKEY(fbp->krbdes_key)) {
+            fbp->need_start = 1;
+            break;
+        }
+#endif /* MIT_CURRENT */
+        state &= ~NO_SEND_IV;
+        state |= NO_RECV_IV;
+        /*
+        * Create a random feed and send it over.
+        */
+#ifdef MIT_CURRENT
+        {
+            krb5_data d;
+            krb5_error_code code;
+
+            d.data = fbp->temp_feed;
+            d.length = sizeof(fbp->temp_feed);
+
+#ifdef CRYPT_DLL
+            if (code = krb5_c_random_make_octets(*p_k5_context,&d))
+                return(xFAILED);
+#else /* CRYPT_DLL */
+            if (code = krb5_c_random_make_octets(k5_context,&d))
+                return(xFAILED);
+#endif /* CRYPT_DLL */
+        }
+
+#else /* MIT_CURRENT */
+        des_new_random_key(fbp->temp_feed);
+        des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+                         fbp->krbdes_sched, 1);
+#endif /* MIT_CURRENT */
+        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;
+
+        if (deblog || tn_deb || debses) {
+            int i;
+            sprintf(tn_msg,
+                     "TELNET SENT SB %s IS %s FB64_IV ",
+                     TELOPT(fbp->fb_feed[2]),
+                     enctype_names[fbp->fb_feed[4]]);                   /* safe */
+            tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6);
+            ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+            debug(F100,tn_msg,"",0);
+            if (tn_deb || debses) tn_debug(tn_msg);
+        }
+#ifdef OS2
+        RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+        ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+        break;
+    default:
+        return(xFAILED);
+    }
+    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(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(fb64_is(data, cnt, &des_fb[CFB]));
+}
+
+int
+ofb64_is(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(fb64_is(data, cnt, &des_fb[OFB]));
+}
+
+int
+fb64_is(data, cnt, fbp)
+    unsigned char *data;
+    int cnt;
+    struct des_fb *fbp;
+{
+    unsigned char *p;
+    register int state = fbp->state[DIR_DECRYPT-1];
+
+    if (cnt-- < 1)
+        goto failure;
+
+#ifdef CK_SSL
+    if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+#endif /* CK_SSL */
+    switch (*data++) {
+    case FB64_IV:
+        if (cnt != sizeof(Block)) {
+#ifdef DEBUG
+            if (encrypt_debug_mode)
+                printf("CFB64: initial vector failed on size\r\n");
+#endif
+            state = xFAILED;
+            goto failure;
+        }
+
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            printf("CFB64: initial vector received\r\n");
+            printf("Initializing Decrypt stream\r\n");
+        }
+#endif
+        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;
+
+        if (deblog || tn_deb || debses) {
+            int i;
+            sprintf(tn_msg,
+                     "TELNET SENT SB %s REPLY %s FB64_IV_OK ",
+                     TELOPT(fbp->fb_feed[2]),
+                     enctype_names[fbp->fb_feed[4]]);           /* safe */
+            tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6);
+            ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+            debug(F100,tn_msg,"",0);
+            if (tn_deb || debses) tn_debug(tn_msg);
+        }
+#ifdef OS2
+        RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+        ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+        state = IN_PROGRESS;
+        break;
+
+    default:
+#if 0
+        if (encrypt_debug_mode) {
+            printf("Unknown option type: %d\r\n", *(data-1));
+            printf("\r\n");
+        }
+#endif
+        /* 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;
+
+        if (deblog || tn_deb || debses) {
+            int i;
+            sprintf(tn_msg,
+                     "TELNET SENT SB %s REPLY %s FB64_IV_BAD ",
+                     TELOPT(fbp->fb_feed[2]),
+                     enctype_names[fbp->fb_feed[4]]);           /* safe */
+            tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6);
+            ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+            debug(F100,tn_msg,"",0);
+            if (tn_deb || debses) tn_debug(tn_msg);
+        }
+#ifdef OS2
+        RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+        ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+        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(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(fb64_reply(data, cnt, &des_fb[CFB]));
+}
+int
+ofb64_reply(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(fb64_reply(data, cnt, &des_fb[OFB]));
+}
+
+
+int
+fb64_reply(data, cnt, fbp)
+    unsigned char *data;
+    int cnt;
+    struct des_fb *fbp;
+{
+    register 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 == xFAILED)
+            state = IN_PROGRESS;
+        state &= ~NO_RECV_IV;
+        encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\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 = xFAILED;
+        break;
+
+    default:
+#if 0
+        if (encrypt_debug_mode) {
+            printf("Unknown option type: %d\r\n", data[-1]);
+            printf("\r\n");
+        }
+#endif
+        /* FALL THROUGH */
+      failure:
+        state = xFAILED;
+        break;
+    }
+    return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+int
+cfb64_session(key, server)
+    Session_Key *key;
+    int server;
+{
+    return(fb64_session(key, server, &des_fb[CFB]));
+}
+
+int
+ofb64_session(key, server)
+    Session_Key *key;
+    int server;
+{
+    return(fb64_session(key, server, &des_fb[OFB]));
+}
+
+static int
+fb64_session(key, server, fbp)
+    Session_Key *key;
+    int server;
+    struct des_fb *fbp;
+{
+    int rc=0;
+    int use2keys;
+    struct des_stinfo * s_stream;
+    struct des_stinfo * c_stream;
+
+    if(server) {
+        s_stream = &fbp->streams[DIR_ENCRYPT-1];
+        c_stream = &fbp->streams[DIR_DECRYPT-1];
+    }
+    else {
+        s_stream = &fbp->streams[DIR_DECRYPT-1];
+        c_stream = &fbp->streams[DIR_ENCRYPT-1];
+    }
+
+    if (!key || key->length < sizeof(Block)) {
+        CHAR buf[80];
+        sprintf(buf,"Can't set DES session key (%d < %d)",
+                key ? key->length : 0, sizeof(Block));          /* safe */
+#ifdef DEBUG
+        if (encrypt_debug_mode)
+            printf("%s\r\n",buf);
+#endif
+        debug(F110,"fb64_session",buf,0);
+        return(-1);
+    }
+    use2keys = (key->type == SK_DES ||
+                 key->length < 2 * sizeof(Block)) ? 0 : 1;
+#ifdef MIT_CURRENT
+    if(use2keys) {
+        memcpy((void *) fbp->keybytes,
+                 (void *) (key->data + sizeof(Block)), sizeof(Block));
+        des_fixup_key_parity(fbp->);
+        fb64_stream_key(fbp->krbdes_key, s_stream);
+    }
+
+    memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
+    if (key->type != SK_DES)
+        des_fixup_key_parity(fbp->krbdes_key);
+
+    if(!use2keys)
+        fb64_stream_key(fbp->krbdes_key, s_stream);
+    fb64_stream_key(fbp->krbdes_key, c_stream);
+    fbp->validkey = 1;
+
+    fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1]);
+    fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1]);
+#else /* MIT_CURRENT */
+    if(use2keys) {
+        memcpy((void *) fbp->krbdes_key,
+                 (void *) (key->data + sizeof(Block)), sizeof(Block));
+        des_fixup_key_parity(fbp->krbdes_key);
+        fb64_stream_key(fbp->krbdes_key, s_stream);
+    }
+
+    memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
+    if (key->type != SK_DES)
+        des_fixup_key_parity(fbp->krbdes_key);
+
+    if(!use2keys)
+        fb64_stream_key(fbp->krbdes_key, s_stream);
+    fb64_stream_key(fbp->krbdes_key, c_stream);
+
+    if (fbp->once == 0) {
+        des_set_random_generator_seed(fbp->krbdes_key);
+        fbp->once = 1;
+    }
+
+    memset(fbp->krbdes_sched,0,sizeof(Schedule));
+    hexdump("fb64_session_key",fbp->krbdes_key,8);
+
+    rc = des_key_sched(fbp->krbdes_key, fbp->krbdes_sched);
+    if ( rc == -1 ) {
+        printf("?Invalid DES key specified for encryption\n");
+        debug(F110,"fb64_session_key",
+               "invalid DES Key specified for encryption",0);
+    } else if ( rc == -2 ) {
+        printf("?Weak DES key specified for encryption\n");
+        debug(F110,"fb64_session_key",
+               "weak DES Key specified for encryption",0);
+    } else if ( rc != 0 ) {
+        printf("?Key Schedule not created by encryption\n");
+        debug(F110,"fb64_session_key",
+               "Key Schedule not created by encryption",0);
+    }
+
+    hexdump("fb64_session_key schedule",fbp->krbdes_sched,8*16);
+#endif /* MIT_CURRENT */
+    /*
+    * 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);
+    }
+    return(0);
+}
+
+/*
+ * We only accept a keyid of 0.  If we get a keyid of
+ * 0, then mark the state as SUCCESS.
+ */
+int
+cfb64_keyid(dir, kp, lenp)
+    int dir, *lenp;
+    unsigned char *kp;
+{
+    return(fb64_keyid(dir, kp, lenp, &des_fb[CFB]));
+}
+
+int
+ofb64_keyid(dir, kp, lenp)
+    int dir, *lenp;
+    unsigned char *kp;
+{
+    return(fb64_keyid(dir, kp, lenp, &des_fb[OFB]));
+}
+
+int
+fb64_keyid(dir, kp, lenp, fbp)
+    int dir, *lenp;
+    unsigned char *kp;
+    struct des_fb *fbp;
+{
+    register int state = fbp->state[dir-1];
+
+    if (*lenp != 1 || (*kp != '\0')) {
+        *lenp = 0;
+        return(state);
+    }
+
+    if (state == xFAILED)
+        state = IN_PROGRESS;
+
+    state &= ~NO_KEYID;
+
+    return(fbp->state[dir-1] = state);
+}
+
+#if 0
+void
+fb64_printsub(data, cnt, buf, buflen, type)
+    unsigned char *data, *buf, *type;
+    int cnt, buflen;
+{
+    char lbuf[64];
+    register 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;
+
+    case FB64_CHALLENGE:
+        sprintf(lbuf, "%s_CHALLENGE", type);
+        cp = lbuf;
+        goto common;
+
+    case FB64_RESPONSE:
+        sprintf(lbuf, "%s_RESPONSE", 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(data, cnt, buf, buflen)
+    unsigned char *data, *buf;
+    int cnt, buflen;
+{
+    fb64_printsub(data, cnt, buf, buflen, "CFB64");
+}
+
+void
+ofb64_printsub(data, cnt, buf, buflen)
+    unsigned char *data, *buf;
+    int cnt, buflen;
+{
+    fb64_printsub(data, cnt, buf, buflen, "OFB64");
+}
+#endif
+
+void
+fb64_stream_iv(seed, stp)
+    Block seed;
+    register struct des_stinfo *stp;
+{
+    int rc=0;
+
+    memcpy(stp->str_iv,     seed, sizeof(Block));
+    memcpy(stp->str_output, seed, sizeof(Block));
+
+    memset(stp->str_sched,0,sizeof(Schedule));
+
+    hexdump("fb64_stream_iv",stp->str_ikey,8);
+
+#ifndef MIT_CURRENT
+    rc = des_key_sched(stp->str_ikey, stp->str_sched);
+    if ( rc == -1 ) {
+        printf("?Invalid DES key specified for encryption\r\n");
+        debug(F110,"fb64_stream_iv",
+               "invalid DES Key specified for encryption",0);
+    } else if ( rc == -2 ) {
+        printf("?Weak DES key specified for encryption\r\n");
+        debug(F110,"fb64_stream_iv",
+               "weak DES Key specified for encryption",0);
+    } else if ( rc != 0 ) {
+        printf("?Key Schedule not created by encryption\r\n");
+        debug(F110,"fb64_stream_iv",
+               "Key Schedule not created by encryption",0);
+    }
+    hexdump("fb64_stream_iv schedule",stp->str_sched,8*16);
+#endif /* MIT_CURRENT */
+
+    stp->str_index = sizeof(Block);
+}
+
+void
+fb64_stream_key(key, stp)
+    Block key;
+    register struct des_stinfo *stp;
+{
+    int rc = 0;
+
+#ifdef MIT_CURRENT
+    memcpy(stp->str_keybytes, key, sizeof(Block));
+    stp->str_key.length = 8;
+    stp->str_key.contents = stp->str_keybytes;
+    /* the original version of this code uses des ecb mode, but
+    it only ever does one block at a time.  cbc with a zero iv
+    is identical */
+    stp->str_key.enctype = ENCTYPE_DES_CBC_RAW;
+#else /* MIT_CURRENT */
+    memcpy(stp->str_ikey, key, sizeof(Block));
+
+    memset(stp->str_sched,0,sizeof(Schedule));
+
+    hexdump("fb64_stream_key",key,8);
+
+    rc = des_key_sched(key, stp->str_sched);
+    if ( rc == -1 ) {
+        printf("?Invalid DES key specified for encryption\r\n");
+        debug(F110,"fb64_stream_key",
+               "invalid DES Key specified for encryption",0);
+    } else if ( rc == -2 ) {
+        printf("?Weak DES key specified for encryption\r\n");
+        debug(F110,"fb64_stream_key",
+               "weak DES Key specified for encryption",0);
+    } else if ( rc != 0 ) {
+        printf("?Key Schedule not created by encryption\r\n");
+        debug(F110,"fb64_stream_key",
+               "Key Schedule not created by encryption",0);
+    }
+    hexdump("fb64_stream_key schedule",stp->str_sched,8*16);
+#endif /* MIT_CURRENT */
+
+    memcpy(stp->str_output, 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(s, c)
+    register unsigned char *s;
+    int c;
+{
+    register struct des_stinfo *stp = &des_fb[CFB].streams[DIR_ENCRYPT-1];
+    register int index;
+
+    index = stp->str_index;
+    while (c-- > 0) {
+        if (index == sizeof(Block)) {
+            Block b;
+#ifdef MIT_CURRENT
+            ecb_encrypt(stp, stp->str_output, b);
+#else /* MIT_CURRENT */
+            des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
+#endif /* MIT_CURRENT */
+            memcpy(stp->str_feed,b,sizeof(Block));
+            index = 0;
+        }
+
+        /* On encryption, we store (feed ^ data) which is cypher */
+        *s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
+        s++;
+        index++;
+    }
+    stp->str_index = index;
+}
+
+int
+cfb64_decrypt(data)
+    int data;
+{
+    register struct des_stinfo *stp = &des_fb[CFB].streams[DIR_DECRYPT-1];
+    int index;
+
+    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);
+    }
+
+    index = stp->str_index++;
+    if (index == sizeof(Block)) {
+        Block b;
+#ifdef MIT_CURRENT
+        ecb_encrypt(stp, stp->str_output, b);
+#else /* MIT_CURRENT */
+        des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
+#endif /* MIT_CURRENT */
+        memcpy(stp->str_feed, b, sizeof(Block));
+        stp->str_index = 1;     /* Next time will be 1 */
+        index = 0;              /* But now use 0 */
+    }
+
+    /* On decryption we store (data) which is cypher. */
+    stp->str_output[index] = data;
+    return(data ^ stp->str_feed[index]);
+}
+
+/*
+ * 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(s, c)
+    register unsigned char *s;
+    int c;
+{
+    register struct des_stinfo *stp = &des_fb[OFB].streams[DIR_ENCRYPT-1];
+    register int index;
+
+    index = stp->str_index;
+    while (c-- > 0) {
+        if (index == sizeof(Block)) {
+            Block b;
+#ifdef MIT_CURRENT
+            ecb_encrypt(stp, stp->str_feed, b);
+#else /* MIT_CURRENT */
+            des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
+#endif /* MIT_CURRENT */
+            memcpy(stp->str_feed,b,sizeof(Block));
+            index = 0;
+        }
+        *s++ ^= stp->str_feed[index];
+        index++;
+    }
+    stp->str_index = index;
+}
+
+int
+ofb64_decrypt(data)
+    int data;
+{
+    register struct des_stinfo *stp = &des_fb[OFB].streams[DIR_DECRYPT-1];
+    int index;
+
+    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);
+    }
+
+    index = stp->str_index++;
+    if (index == sizeof(Block)) {
+        Block b;
+#ifdef MIT_CURRENT
+        ecb_encrypt(stp, stp->str_feed, b);
+#else /* MIT_CURRENT */
+        des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
+#endif /* MIT_CURRENT */
+        memcpy(stp->str_feed, b, sizeof(Block));
+        stp->str_index = 1;     /* Next time will be 1 */
+        index = 0;              /* But now use 0 */
+    }
+
+    return(data ^ stp->str_feed[index]);
+}
+
+
+void des3_fb64_stream_iv P((Block, struct des3_stinfo *));
+void des3_fb64_init P((struct des3_fb *));
+static int des3_fb64_start P((struct des3_fb *, int, int));
+int des3_fb64_is P((unsigned char *, int, struct des3_fb *));
+int des3_fb64_reply P((unsigned char *, int, struct des3_fb *));
+static int des3_fb64_session P((Session_Key *, int, struct des3_fb *));
+void des3_fb64_stream_key P((Block *, struct des3_stinfo *));
+int des3_fb64_keyid P((int, unsigned char *, int *, struct des3_fb *));
+
+void
+des3_cfb64_init(server)
+    int server;
+{
+    des3_fb64_init(&des3_fb[CFB]);
+    des3_fb[CFB].fb_feed[4] = ENCTYPE_DES3_CFB64;
+    des3_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
+    des3_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
+}
+
+void
+des3_ofb64_init(server)
+    int server;
+{
+    des3_fb64_init(&des3_fb[OFB]);
+    des3_fb[OFB].fb_feed[4] = ENCTYPE_DES3_OFB64;
+    des3_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
+    des3_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
+}
+
+void
+des3_fb64_init(fbp)
+    register struct des3_fb *fbp;
+{
+    memset((void *)fbp, 0, sizeof(*fbp));
+    fbp->state[0] = fbp->state[1] = xFAILED;
+    fbp->fb_feed[0] = IAC;
+    fbp->fb_feed[1] = SB;
+    fbp->fb_feed[2] = TELOPT_ENCRYPTION;
+    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
+des3_cfb64_start(dir, server)
+    int dir;
+    int server;
+{
+    return(des3_fb64_start(&des3_fb[CFB], dir, server));
+}
+int
+des3_ofb64_start(dir, server)
+    int dir;
+    int server;
+{
+    return(des3_fb64_start(&des3_fb[OFB], dir, server));
+}
+
+static int
+des3_fb64_start(fbp, dir, server)
+    struct des3_fb *fbp;
+    int dir;
+    int server;
+{
+    int x;
+    unsigned char *p;
+    register 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 == xFAILED)
+            state = IN_PROGRESS;
+        break;
+
+    case DIR_ENCRYPT:
+        state = fbp->state[dir-1];
+        if (state == xFAILED)
+            state = IN_PROGRESS;
+        else if ((state & NO_SEND_IV) == 0)
+            break;
+
+        if (!VALIDKEY(fbp->krbdes_key[0]) ||
+            !VALIDKEY(fbp->krbdes_key[1]) ||
+            !VALIDKEY(fbp->krbdes_key[2]) ) {
+            fbp->need_start = 1;
+            break;
+        }
+        state &= ~NO_SEND_IV;
+        state |= NO_RECV_IV;
+        /*
+        * Create a random feed and send it over.
+        */
+        des_new_random_key(fbp->temp_feed);
+#ifdef LIBDES
+        des_ecb3_encrypt(fbp->temp_feed, fbp->temp_feed,
+                         fbp->krbdes_sched[0],
+                         fbp->krbdes_sched[1],
+                         fbp->krbdes_sched[2],
+                         1);
+#else /* LIBDES */
+        des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+                         fbp->krbdes_sched[0], 1);
+        des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+                         fbp->krbdes_sched[1], 0);
+        des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+                         fbp->krbdes_sched[2], 1);
+#endif /* LIBDES */
+
+        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;
+
+        if (deblog || tn_deb || debses) {
+            int i;
+            sprintf(tn_msg,
+                     "TELNET SENT SB %s IS %s FB64_IV ",
+                     TELOPT(fbp->fb_feed[2]),
+                     enctype_names[fbp->fb_feed[4]]);           /* safe */
+            tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6);
+            ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+            debug(F100,tn_msg,"",0);
+            if (tn_deb || debses) tn_debug(tn_msg);
+        }
+#ifdef OS2
+        RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+        ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+        break;
+    default:
+        return(xFAILED);
+    }
+    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
+des3_cfb64_is(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(des3_fb64_is(data, cnt, &des3_fb[CFB]));
+}
+
+int
+des3_ofb64_is(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(des3_fb64_is(data, cnt, &des3_fb[OFB]));
+}
+
+int
+des3_fb64_is(data, cnt, fbp)
+    unsigned char *data;
+    int cnt;
+    struct des3_fb *fbp;
+{
+    unsigned char *p;
+    register int state = fbp->state[DIR_DECRYPT-1];
+
+    if (cnt-- < 1)
+        goto failure;
+
+#ifdef CK_SSL
+    if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+#endif /* CK_SSL */
+    switch (*data++) {
+    case FB64_IV:
+        if (cnt != sizeof(Block)) {
+#ifdef DEBUG
+            if (encrypt_debug_mode)
+                printf("DES3_FB64: initial vector failed on size\r\n");
+#endif
+            state = xFAILED;
+            goto failure;
+        }
+
+#ifdef DEBUG
+        if (encrypt_debug_mode) {
+            printf("DES3_FB64: initial vector received\r\n");
+            printf("Initializing Decrypt stream\r\n");
+        }
+#endif
+        des3_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;
+
+        if (deblog || tn_deb || debses) {
+            int i;
+            sprintf(tn_msg,
+                     "TELNET SENT SB %s REPLY %s FB64_IV_OK ",
+                     TELOPT(fbp->fb_feed[2]),
+                     enctype_names[fbp->fb_feed[4]]);           /* safe */
+            tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6);
+            ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+            debug(F100,tn_msg,"",0);
+            if (tn_deb || debses) tn_debug(tn_msg);
+        }
+#ifdef OS2
+        RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+        ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+        state = IN_PROGRESS;
+        break;
+
+    default:
+#if 0
+        if (encrypt_debug_mode) {
+            printf("Unknown option type: %d\r\n", *(data-1));
+            printf("\r\n");
+        }
+#endif
+        /* 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;
+
+        if (deblog || tn_deb || debses) {
+            int i;
+            sprintf(tn_msg,
+                     "TELNET SENT SB %s REPLY %s FB64_IV_BAD ",
+                     TELOPT(fbp->fb_feed[2]),
+                     enctype_names[fbp->fb_feed[4]]);           /* safe */
+            tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6);
+            ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+            debug(F100,tn_msg,"",0);
+            if (tn_deb || debses) tn_debug(tn_msg);
+        }
+#ifdef OS2
+        RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+        ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+        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
+des3_cfb64_reply(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(des3_fb64_reply(data, cnt, &des3_fb[CFB]));
+}
+int
+des3_ofb64_reply(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(des3_fb64_reply(data, cnt, &des3_fb[OFB]));
+}
+
+
+int
+des3_fb64_reply(data, cnt, fbp)
+    unsigned char *data;
+    int cnt;
+    struct des3_fb *fbp;
+{
+    register int state = fbp->state[DIR_ENCRYPT-1];
+
+    if (cnt-- < 1)
+        goto failure;
+
+    switch (*data++) {
+    case FB64_IV_OK:
+        des3_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+        if (state == xFAILED)
+            state = IN_PROGRESS;
+        state &= ~NO_RECV_IV;
+        encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
+        break;
+
+    case FB64_IV_BAD:
+        memset(fbp->temp_feed, 0, sizeof(Block));
+        des3_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+        state = xFAILED;
+        break;
+
+    default:
+#if 0
+        if (encrypt_debug_mode) {
+            printf("Unknown option type: %d\r\n", data[-1]);
+            printf("\r\n");
+        }
+#endif
+        /* FALL THROUGH */
+      failure:
+        state = xFAILED;
+        break;
+    }
+    return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+int
+des3_cfb64_session(key, server)
+    Session_Key *key;
+    int server;
+{
+    return(des3_fb64_session(key, server, &des3_fb[CFB]));
+}
+
+int
+des3_ofb64_session(key, server)
+    Session_Key *key;
+    int server;
+{
+    return(des3_fb64_session(key, server, &des3_fb[OFB]));
+}
+
+static int
+des3_fb64_session(key, server, fbp)
+    Session_Key *key;
+    int server;
+    struct des3_fb *fbp;
+{
+    int rc=0,i=0;
+    int keys2use=0;
+    struct des3_stinfo * s_stream;
+    struct des3_stinfo * c_stream;
+
+    if(server) {
+        s_stream = &fbp->streams[DIR_ENCRYPT-1];
+        c_stream = &fbp->streams[DIR_DECRYPT-1];
+    }
+    else {
+        s_stream = &fbp->streams[DIR_DECRYPT-1];
+        c_stream = &fbp->streams[DIR_ENCRYPT-1];
+    }
+
+    keys2use = key->length / sizeof(Block);
+    if (!key || (key->type == SK_DES) || (keys2use < 2)) {
+        CHAR buf[80];
+        sprintf(buf,"Can't set 3DES session key (%d < %d)",
+                key ? key->length : 0, 2 * sizeof(Block));      /* safe */
+#ifdef DEBUG
+        if (encrypt_debug_mode)
+            printf("%s\r\n",buf);
+#endif
+        debug(F110,"des3_fb64_session",buf,0);
+        return(-1);
+    }
+
+    debug(F111,"des3_fb64_session","keys2use",keys2use);
+    /* Compute the first set of keys / key order */
+    switch ( keys2use ) {
+    case 2:
+        memcpy((void *)fbp->krbdes_key[0], (void *)key->data, sizeof(Block));
+        memcpy((void *) fbp->krbdes_key[1],(void *)(key->data + sizeof(Block)),
+                 sizeof(Block));
+        memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block));
+        break;
+    case 3:
+    default:
+        memcpy((void *)fbp->krbdes_key[0], (void *)key->data, sizeof(Block));
+        memcpy((void *) fbp->krbdes_key[1],(void *)(key->data + sizeof(Block)),
+                 sizeof(Block));
+        memcpy((void *) fbp->krbdes_key[2],
+                 (void *) (key->data + 2*sizeof(Block)), sizeof(Block));
+        break;
+    }
+    hexdump("des3_session_key key->data",key->data,sizeof(Block));
+    hexdump("des3_session_key fbp->krbdes_key[0]",
+            fbp->krbdes_key[0],
+            sizeof(Block)
+            );
+    if (fbp->once == 0) {
+        des_set_random_generator_seed(fbp->krbdes_key[0]);
+        fbp->once = 1;
+    }
+
+    for ( i=0;i<3;i++ )
+        des_fixup_key_parity(fbp->krbdes_key[i]);
+    des3_fb64_stream_key(fbp->krbdes_key, s_stream);
+
+
+    /* Compute the second set of keys / key order */
+    switch ( keys2use ) {
+    case 2:
+        memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)),
+                 sizeof(Block));
+        memcpy((void *)fbp->krbdes_key[1], (void *)key->data, sizeof(Block));
+        memcpy((void *) fbp->krbdes_key[2],(void *)(key->data + sizeof(Block)),
+                 sizeof(Block));
+        break;
+    case 3:
+        memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)),
+                 sizeof(Block));
+        memcpy((void *) fbp->krbdes_key[1],
+                 (void *) (key->data + 2*sizeof(Block)), sizeof(Block));
+        memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block));
+        break;
+    case 4:
+        memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)),
+                 sizeof(Block));
+        memcpy((void *) fbp->krbdes_key[1],
+                 (void *) (key->data + 3*sizeof(Block)), sizeof(Block));
+        memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block));
+        break;
+    case 5:
+        memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)),
+                 sizeof(Block));
+        memcpy((void *) fbp->krbdes_key[1],
+                 (void *) (key->data + 3*sizeof(Block)), sizeof(Block));
+        memcpy((void *)fbp->krbdes_key[2],
+                 (void *)(key->data + 4*sizeof(Block)), sizeof(Block));
+        break;
+    case 6:
+        memcpy((void *) fbp->krbdes_key[0],
+                 (void *) (key->data + 3*sizeof(Block)), sizeof(Block));
+        memcpy((void *)fbp->krbdes_key[1],
+                 (void *)(key->data + 4*sizeof(Block)), sizeof(Block));
+        memcpy((void *) fbp->krbdes_key[2],
+                 (void *) (key->data + 5 *sizeof(Block)),  sizeof(Block));
+        break;
+    }
+
+    for ( i=0;i<3;i++ )
+        des_fixup_key_parity(fbp->krbdes_key[i]);
+    des3_fb64_stream_key(fbp->krbdes_key, c_stream);
+
+    /* now use the second set of keys to build the default Key Schedule */
+    /* which is used for generating the IV.                             */
+    for ( i=0;i<3;i++ ) {
+        memset(fbp->krbdes_sched[i],0,sizeof(Schedule));
+
+        rc = des_key_sched(fbp->krbdes_key[i], fbp->krbdes_sched[i]);
+        if ( rc == -1 ) {
+            printf("?Invalid DES key specified for encryption [DES3,%s]\r\n",
+                    server?"server":"client");
+            debug(F110,"des3_fb64_stream_iv",
+                   "invalid DES Key specified for encryption",0);
+        } else if ( rc == -2 ) {
+            printf("?Weak DES key specified for encryption\r\n");
+            debug(F110,"des3_fb64_stream_iv",
+                   "weak DES Key specified for encryption",0);
+        } else if ( rc != 0 ) {
+            printf("?Key Schedule not created by encryption\r\n");
+            debug(F110,"des3_fb64_stream_iv",
+                   "Key Schedule not created by encryption",0);
+        }
+        hexdump("des3_fb64_session_key schedule",fbp->krbdes_sched[i],8*16);
+    }
+    /*
+    * 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;
+        des3_fb64_start(fbp, DIR_ENCRYPT, server);
+    }
+    return(0);
+}
+
+/*
+ * We only accept a keyid of 0.  If we get a keyid of
+ * 0, then mark the state as SUCCESS.
+ */
+int
+des3_cfb64_keyid(dir, kp, lenp)
+    int dir, *lenp;
+    unsigned char *kp;
+{
+    return(des3_fb64_keyid(dir, kp, lenp, &des3_fb[CFB]));
+}
+
+int
+des3_ofb64_keyid(dir, kp, lenp)
+    int dir, *lenp;
+    unsigned char *kp;
+{
+    return(des3_fb64_keyid(dir, kp, lenp, &des3_fb[OFB]));
+}
+
+int
+des3_fb64_keyid(dir, kp, lenp, fbp)
+    int dir, *lenp;
+    unsigned char *kp;
+    struct des3_fb *fbp;
+{
+    register int state = fbp->state[dir-1];
+
+    if (*lenp != 1 || (*kp != '\0')) {
+        *lenp = 0;
+        return(state);
+    }
+
+    if (state == xFAILED)
+        state = IN_PROGRESS;
+
+    state &= ~NO_KEYID;
+
+    return(fbp->state[dir-1] = state);
+}
+
+#if 0
+void
+des3_fb64_printsub(data, cnt, buf, buflen, type)
+    unsigned char *data, *buf, *type;
+    int cnt, buflen;
+{
+    char lbuf[64];
+    register 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;
+
+    case FB64_CHALLENGE:
+        sprintf(lbuf, "%s_CHALLENGE", type);
+        cp = lbuf;
+        goto common;
+
+    case FB64_RESPONSE:
+        sprintf(lbuf, "%s_RESPONSE", 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
+des3_cfb64_printsub(data, cnt, buf, buflen)
+    unsigned char *data, *buf;
+    int cnt, buflen;
+{
+    des3_fb64_printsub(data, cnt, buf, buflen, "CFB64");
+}
+
+void
+des3_ofb64_printsub(data, cnt, buf, buflen)
+    unsigned char *data, *buf;
+    int cnt, buflen;
+{
+    des3_fb64_printsub(data, cnt, buf, buflen, "OFB64");
+}
+#endif
+
+void
+des3_fb64_stream_iv(seed, stp)
+    Block seed;
+    register struct des3_stinfo *stp;
+{
+    int rc=0, i = 0;;
+
+    memcpy(stp->str_iv,     seed, sizeof(Block));
+    memcpy(stp->str_output, seed, sizeof(Block));
+    for ( i=0;i<3;i++ ) {
+        memset(stp->str_sched[i],0,sizeof(Schedule));
+
+        hexdump("des3_fb64_stream_iv",stp->str_ikey[i],8);
+
+        rc = des_key_sched(stp->str_ikey[i], stp->str_sched[i]);
+        if ( rc == -1 ) {
+            printf("?Invalid DES key specified for encryption [DES3 iv]\r\n");
+            debug(F110,"des3_fb64_stream_iv",
+                   "invalid DES Key specified for encryption",0);
+        } else if ( rc == -2 ) {
+            printf("?Weak DES key specified for encryption\r\n");
+            debug(F110,"des3_fb64_stream_iv",
+                   "weak DES Key specified for encryption",0);
+        } else if ( rc != 0 ) {
+            printf("?Key Schedule not created by encryption\r\n");
+            debug(F110,"des3_fb64_stream_iv",
+                   "Key Schedule not created by encryption",0);
+        }
+        hexdump("des3_fb64_stream_iv schedule",stp->str_sched[i],8*16);
+    }
+    stp->str_index = sizeof(Block);
+}
+
+void
+des3_fb64_stream_key(key, stp)
+    Block * key;
+    register struct des3_stinfo *stp;
+{
+    int rc = 0, i = 0;
+
+    for ( i=0;i<3;i++ ) {
+        memcpy(stp->str_ikey[i], key[i], sizeof(Block));
+
+        memset(stp->str_sched[i],0,sizeof(Schedule));
+
+        hexdump("des3_fb64_stream_key",key[i],8);
+
+        rc = des_key_sched(key[i], stp->str_sched[i]);
+        if ( rc == -1 ) {
+            printf("?Invalid DES key specified for encryption [DES3 key]\r\n");
+            debug(F110,"des3_fb64_stream_key",
+                   "invalid DES Key specified for encryption",0);
+        } else if ( rc == -2 ) {
+            printf("?Weak DES key specified for encryption\r\n");
+            debug(F110,"des3_fb64_stream_key",
+                   "weak DES Key specified for encryption",0);
+        } else if ( rc != 0 ) {
+            printf("?Key Schedule not created by encryption\r\n");
+            debug(F110,"des3_fb64_stream_key",
+                   "Key Schedule not created by encryption",0);
+        }
+        hexdump("des3_fb64_stream_key schedule",stp->str_sched[i],8*16);
+    }
+
+    memcpy(stp->str_output, stp->str_iv, sizeof(Block));
+    stp->str_index = sizeof(Block);
+}
+
+/*
+ * DES3 64 bit Cipher Feedback
+ *
+ *                key1       key2       key3
+ *                 |          |          |
+ *                 v          v          v
+ *             +-------+  +-------+  +-------+
+ *          +->| DES-e |->| DES-d |->| DES-e |-- +
+ *          |  +-------+  +-------+  +-------+   |
+ *          |                                    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-e(DES-d(DES-e(iV, key1),key2),key3)
+ *      On = Dn ^ Vn
+ *      V(n+1) = DES-e(DES-d(DES-e(On, key1),key2),key3)
+ */
+
+void
+des3_cfb64_encrypt(s, c)
+    register unsigned char *s;
+    int c;
+{
+    register struct des3_stinfo *stp = &des3_fb[CFB].streams[DIR_ENCRYPT-1];
+    register int index;
+
+    index = stp->str_index;
+    while (c-- > 0) {
+        if (index == sizeof(Block)) {
+            Block b;
+#ifdef LIBDES
+            des_ecb3_encrypt(stp->str_output, b, stp->str_sched[0],
+                              stp->str_sched[1], stp->str_sched[2], 1);
+#else /* LIBDES */
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[0], 1);
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[1], 0);
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[2], 1);
+#endif /* LIBDES */
+            memcpy(stp->str_feed,b,sizeof(Block));
+            index = 0;
+        }
+
+        /* On encryption, we store (feed ^ data) which is cypher */
+        *s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
+        s++;
+        index++;
+    }
+    stp->str_index = index;
+}
+
+int
+des3_cfb64_decrypt(data)
+    int data;
+{
+    register struct des3_stinfo *stp = &des3_fb[CFB].streams[DIR_DECRYPT-1];
+    int index;
+
+    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);
+    }
+
+    index = stp->str_index++;
+    if (index == sizeof(Block)) {
+        Block b;
+#ifdef LIBDES
+        des_ecb3_encrypt(stp->str_output, b, stp->str_sched[0],
+                          stp->str_sched[1], stp->str_sched[2], 1);
+#else /* LIBDES */
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[0], 1);
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[1], 0);
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[2], 1);
+#endif /* LIBDES */
+        memcpy(stp->str_feed, b, sizeof(Block));
+        stp->str_index = 1;     /* Next time will be 1 */
+        index = 0;              /* But now use 0 */
+    }
+
+    /* On decryption we store (data) which is cypher. */
+    stp->str_output[index] = data;
+    return(data ^ stp->str_feed[index]);
+}
+
+/*
+ * DES3 64 bit Output Feedback
+ *
+ *
+ *                key1       key2       key3
+ *                 |          |          |
+ *                 v          v          v
+ *             +-------+  +-------+  +-------+
+ *          +->| DES-e |->| DES-d |->| DES-e |-- +
+ *          |  +-------+  +-------+  +-------+   |
+ *          +------------------------------------+
+ *                                               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-e(DES-d(DES-e(iV, key1),key2),key3)
+ *      V(n+1) = DES-e(DES-d(DES-e(Vn, key1),key2),key3)
+ *      On = Dn ^ Vn
+ */
+void
+des3_ofb64_encrypt(s, c)
+    register unsigned char *s;
+    int c;
+{
+    register struct des3_stinfo *stp = &des3_fb[OFB].streams[DIR_ENCRYPT-1];
+    register int index;
+
+    index = stp->str_index;
+    while (c-- > 0) {
+        if (index == sizeof(Block)) {
+            Block b;
+#ifdef LIBDES
+            des_ecb3_encrypt(stp->str_feed, b, stp->str_sched[0],
+                             stp->str_sched[1], stp->str_sched[2], 1);
+#else /* LIBDES */
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[0], 1);
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[1], 0);
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[2], 1);
+#endif /* LIBDES */
+            memcpy(stp->str_feed,b,sizeof(Block));
+            index = 0;
+        }
+        *s++ ^= stp->str_feed[index];
+        index++;
+    }
+    stp->str_index = index;
+}
+
+int
+des3_ofb64_decrypt(data)
+    int data;
+{
+    register struct des3_stinfo *stp = &des3_fb[OFB].streams[DIR_DECRYPT-1];
+    int index;
+
+    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);
+    }
+
+    index = stp->str_index++;
+    if (index == sizeof(Block)) {
+        Block b;
+#ifdef LIBDES
+        des_ecb3_encrypt(stp->str_feed, b, stp->str_sched[0],
+                          stp->str_sched[1], stp->str_sched[2], 1);
+#else /* LIBDES */
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[0], 1);
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[1], 0);
+            des_ecb_encrypt(stp->str_output, b,
+                             stp->str_sched[2], 1);
+#endif /* LIBDES */
+        memcpy(stp->str_feed, b, sizeof(Block));
+        stp->str_index = 1;     /* Next time will be 1 */
+        index = 0;              /* But now use 0 */
+    }
+
+    return(data ^ stp->str_feed[index]);
+}
+#endif /* CK_DES */
+
+#ifdef CK_CAST
+/*-
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1997 Stanford University
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#ifdef  __STDC__
+#include <stdlib.h>
+#endif
+
+/*
+ * cast.h
+ * Author: Tom Wu
+ *
+ * Type and function declarations for CAST.
+ */
+
+#ifndef _CAST_H_
+#define _CAST_H_
+
+#ifndef P
+#ifdef __STDC__
+#define P(x) x
+#else
+#define P(x) ()
+#endif /* __STDC__ */
+#endif /* P */
+
+#ifndef LITTLE_ENDIAN
+#ifndef BIG_ENDIAN
+#ifndef WORDS_BIGENDIAN
+#define LITTLE_ENDIAN 1
+#endif /* WORDS_BIGENDIAN */
+#endif /* BIG_ENDIAN */
+#endif /* LITTLE_ENDIAN */
+
+typedef unsigned int uint32;    /* Must be 32 bits */
+typedef uint32 * uint32p;
+typedef unsigned char uint8;
+typedef uint8 * uint8p;
+
+typedef struct {
+  struct CastSubkeyPair {
+    uint32 Km;
+    uint32 Kr;
+  } K[16];
+  int ksize;
+} CastKeySched;
+
+/*
+ * cast*_key_sched(schedule, key)
+ *
+ * Initializes the CAST key schedule "schedule" according to the given key.
+ * The different setup routines accept different length keys:
+ *
+ *   ck_cast5_40_key_sched: 40-bit/5-byte (12 round) keys
+ *   ck_cast5_64_key_sched: 64-bit/8-byte (12 round) keys
+ *   ck_cast5_80_key_sched: 80-bit/10-byte (12 round) keys
+ *   ck_cast128_key_sched: 128-bit/16-byte (16 round) keys
+ */
+
+extern void ck_cast5_40_key_sched P((CastKeySched *, uint8 *));
+extern void ck_cast5_64_key_sched P((CastKeySched *, uint8 *));
+extern void ck_cast5_80_key_sched P((CastKeySched *, uint8 *));
+extern void  ck_cast128_key_sched P((CastKeySched *, uint8 *));
+
+/*
+ * ck_cast_ecb_encrypt(output, input, schedule, mode)
+ * ck_cast_ecb_crypt(data, schedule, mode)
+ *
+ * Encrypts the 64-bit "input" according to the CAST key schedule
+ * "schedule" and places the result in "output".  If "mode" is 0,
+ * ck_cast_ecb_encrypt will encrypt, otherwise it will decrypt.
+ * "Output" and "input" can point to the same memory, in which case
+ * en/decryption will be performed in place.
+ *
+ * ck_cast_ecb_crypt accepts input in the form of an array of two
+ * 32-bit words and performs encryption/decryption in place.
+ */
+
+extern void ck_cast_ecb_encrypt P((uint8 *, uint8 *, CastKeySched *, int));
+extern void ck_cast_ecb_crypt P((uint32 *, CastKeySched *, int));
+
+#endif /* CAST_H */
+
+extern encrypt_debug_mode;
+
+#define CFB_40  0
+#define OFB_40  1
+#ifdef CAST_EXPORT_ENCRYPTION
+#define FB_CNT  2
+#else
+#define CFB_128 2
+#define OFB_128 3
+#define FB_CNT  4
+#endif
+
+#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 cFAILED         -1
+
+
+struct cast_fb {
+        Block temp_feed;
+        unsigned char fb_feed[64];
+        int key_isset;
+        int need_start;
+        int state[2];
+        struct cast_stinfo {
+                Block           str_output;
+                Block           str_feed;
+                Block           str_iv;
+                CastKeySched    str_sched;
+                int             str_index;
+        } streams[2];
+};
+
+static struct cast_fb cast_fb[FB_CNT];
+
+#define FB64_IV         1
+#define FB64_IV_OK      2
+#define FB64_IV_BAD     3
+
+
+static void cast_fb64_stream_iv P((Block, struct cast_stinfo *));
+static void cast_fb64_init P((struct cast_fb *));
+static int cast_fb64_start P((struct cast_fb *, int, int));
+static int cast_fb64_is P((unsigned char *, int, struct cast_fb *));
+static int cast_fb64_reply P((unsigned char *, int, struct cast_fb *));
+static int cast_fb64_session P((Session_Key *, int, struct cast_fb *, int));
+static void cast_fb64_stream_key P((Block, struct cast_stinfo *, int));
+static int cast_fb64_keyid P((int, unsigned char *, int *, struct cast_fb *));
+static void _cast_cfb64_encrypt P((unsigned char *,int, struct cast_stinfo *));
+static int _cast_cfb64_decrypt P((int, struct cast_stinfo *));
+static void _cast_ofb64_encrypt P((unsigned char *,int, struct cast_stinfo *));
+static int _cast_ofb64_decrypt P((int, struct cast_stinfo *));
+
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+cast_cfb64_init(server)
+        int server;
+{
+        cast_fb64_init(&cast_fb[CFB_128]);
+        cast_fb[CFB_128].fb_feed[4] = ENCTYPE_CAST128_CFB64;
+}
+
+void
+cast_ofb64_init(server)
+        int server;
+{
+        cast_fb64_init(&cast_fb[OFB_128]);
+        cast_fb[OFB_128].fb_feed[4] = ENCTYPE_CAST128_OFB64;
+}
+#endif
+
+void
+castexp_cfb64_init(server)
+        int server;
+{
+        cast_fb64_init(&cast_fb[CFB_40]);
+        cast_fb[CFB_40].fb_feed[4] = ENCTYPE_CAST5_40_CFB64;
+}
+
+void
+castexp_ofb64_init(server)
+        int server;
+{
+        cast_fb64_init(&cast_fb[OFB_40]);
+        cast_fb[OFB_40].fb_feed[4] = ENCTYPE_CAST5_40_OFB64;
+}
+
+static void
+cast_fb64_init(fbp)
+    register struct cast_fb *fbp;
+{
+    memset((void *)fbp, 0, sizeof(*fbp));
+    fbp->key_isset = 0;
+    fbp->state[0] = fbp->state[1] = cFAILED;
+    fbp->fb_feed[0] = IAC;
+    fbp->fb_feed[1] = SB;
+    fbp->fb_feed[2] = TELOPT_ENCRYPTION;
+    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.
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_start(dir, server)
+    int dir;
+    int server;
+{
+    return(cast_fb64_start(&cast_fb[CFB_128], dir, server));
+}
+
+int
+cast_ofb64_start(dir, server)
+    int dir;
+    int server;
+{
+    return(cast_fb64_start(&cast_fb[OFB_128], dir, server));
+}
+#endif
+
+int
+castexp_cfb64_start(dir, server)
+    int dir;
+    int server;
+{
+    return(cast_fb64_start(&cast_fb[CFB_40], dir, server));
+}
+
+int
+castexp_ofb64_start(dir, server)
+    int dir;
+    int server;
+{
+    return(cast_fb64_start(&cast_fb[OFB_40], dir, server));
+}
+
+static int
+cast_fb64_start(fbp, dir, server)
+    struct cast_fb *fbp;
+    int dir;
+    int server;
+{
+    Block b;
+    int x;
+    unsigned char *p;
+    register 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 == cFAILED)
+            state = IN_PROGRESS;
+        break;
+
+    case DIR_ENCRYPT:
+        state = fbp->state[dir-1];
+        if (state == cFAILED)
+            state = IN_PROGRESS;
+        else if ((state & NO_SEND_IV) == 0)
+            break;
+
+        if (!fbp->key_isset) {
+            fbp->need_start = 1;
+            break;
+        }
+        state &= ~NO_SEND_IV;
+        state |= NO_RECV_IV;
+#ifdef DEBUG
+        if (encrypt_debug_mode)
+            printf("Creating new feed\r\n");
+#endif
+        /*
+         * Create a random feed and send it over.
+         */
+        ck_cast_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+                          &fbp->streams[dir-1].str_sched, 0);
+
+        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;
+
+        ttol(fbp->fb_feed, p - fbp->fb_feed);
+        break;
+    default:
+        return(cFAILED);
+    }
+    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.
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_is(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(cast_fb64_is(data, cnt, &cast_fb[CFB_128]));
+}
+
+int
+cast_ofb64_is(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(cast_fb64_is(data, cnt, &cast_fb[OFB_128]));
+}
+#endif
+
+int
+castexp_cfb64_is(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(cast_fb64_is(data, cnt, &cast_fb[CFB_40]));
+}
+
+int
+castexp_ofb64_is(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(cast_fb64_is(data, cnt, &cast_fb[OFB_40]));
+}
+
+static int
+cast_fb64_is(data, cnt, fbp)
+    unsigned char *data;
+    int cnt;
+    struct cast_fb *fbp;
+{
+    int x;
+    unsigned char *p;
+    Block b;
+    register int state = fbp->state[DIR_DECRYPT-1];
+
+    if (cnt-- < 1)
+        goto failure;
+
+#ifdef CK_SSL
+    if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+#endif /* CK_SSL */
+    switch (*data++) {
+    case FB64_IV:
+        if (cnt != sizeof(Block)) {
+#ifdef DEBUG
+            if (encrypt_debug_mode)
+                printf("FB64: initial vector failed on size\r\n");
+#endif
+            state = cFAILED;
+            goto failure;
+        }
+#ifdef DEBUG
+        if (encrypt_debug_mode)
+            printf("FB64: initial vector received\r\n");
+
+        if (encrypt_debug_mode)
+            printf("Initializing Decrypt stream\r\n");
+#endif
+        cast_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;
+
+        ttol(fbp->fb_feed, p - fbp->fb_feed);
+        state = IN_PROGRESS;
+        break;
+
+    default:
+        /* unknown option type */
+        /* 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;
+
+        ttol(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.
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_reply(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(cast_fb64_reply(data, cnt, &cast_fb[CFB_128]));
+}
+
+int
+cast_ofb64_reply(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(cast_fb64_reply(data, cnt, &cast_fb[OFB_128]));
+}
+#endif
+
+int
+castexp_cfb64_reply(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(cast_fb64_reply(data, cnt, &cast_fb[CFB_40]));
+}
+
+int
+castexp_ofb64_reply(data, cnt)
+    unsigned char *data;
+    int cnt;
+{
+    return(cast_fb64_reply(data, cnt, &cast_fb[OFB_40]));
+}
+
+static int
+cast_fb64_reply(data, cnt, fbp)
+    unsigned char *data;
+    int cnt;
+    struct cast_fb *fbp;
+{
+    int x;
+    unsigned char *p;
+    Block b;
+    register int state = fbp->state[DIR_ENCRYPT-1];
+
+    if (cnt-- < 1)
+        goto failure;
+
+    switch (*data++) {
+    case FB64_IV_OK:
+        cast_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+        if (state == cFAILED)
+            state = IN_PROGRESS;
+        state &= ~NO_RECV_IV;
+        encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
+        break;
+
+    case FB64_IV_BAD:
+        memset(fbp->temp_feed, 0, sizeof(Block));
+        cast_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+        state = cFAILED;
+        break;
+
+    default:
+#if 0
+        if (encrypt_debug_mode) {
+            printf("Unknown option type: %d\r\n", data[-1]);
+            printd(data, cnt);
+            printf("\r\n");
+        }
+#endif
+        /* FALL THROUGH */
+      failure:
+        state = cFAILED;
+        break;
+    }
+    return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_session(key, server)
+    Session_Key *key;
+    int server;
+{
+    return(cast_fb64_session(key, server, &cast_fb[CFB_128], 1));
+}
+
+int
+cast_ofb64_session(key, server)
+    Session_Key *key;
+    int server;
+{
+    return(cast_fb64_session(key, server, &cast_fb[OFB_128], 1));
+}
+#endif
+
+int
+castexp_cfb64_session(key, server)
+    Session_Key *key;
+    int server;
+{
+    return(cast_fb64_session(key, server, &cast_fb[CFB_40], 0));
+}
+
+int
+castexp_ofb64_session(key, server)
+    Session_Key *key;
+    int server;
+{
+    return(cast_fb64_session(key, server, &cast_fb[OFB_40], 0));
+}
+
+#define CAST128_KEYLEN  16      /* 128 bits */
+#define CAST5_40_KEYLEN  5      /*  40 bits */
+
+static int
+cast_fb64_session(key, server, fbp, fs)
+    Session_Key *key;
+    int server;
+    struct cast_fb *fbp;
+    int fs;
+{
+    int klen;
+    unsigned char * kptr;
+
+    if(fs)
+        klen = CAST128_KEYLEN;
+    else
+        klen = CAST5_40_KEYLEN;
+
+    if (!key || key->length < klen) {
+        CHAR buf[80];
+        sprintf(buf,"Can't set CAST session key (%d < %d)",
+                key ? key->length : 0, klen);                   /* safe */
+#ifdef DEBUG
+        if (encrypt_debug_mode)
+            printf("%s\r\n",buf);
+#endif
+        debug(F110,"cast_fb64_session",buf,0);
+        return(cFAILED);
+    }
+    if(key->length < 2 * klen)
+        kptr = key->data;
+    else
+        kptr = key->data + klen;
+
+    if(server) {
+        cast_fb64_stream_key(kptr, &fbp->streams[DIR_ENCRYPT-1], fs);
+        cast_fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1], fs);
+    }
+    else {
+        cast_fb64_stream_key(kptr, &fbp->streams[DIR_DECRYPT-1], fs);
+        cast_fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1], fs);
+    }
+
+    /* Stuff leftovers into the feed */
+    if(key->length >= 2 * klen + sizeof(Block))
+        memcpy(fbp->temp_feed, key->data + 2 * klen, sizeof(Block));
+    else {
+#ifdef COMMENT
+        /* This is a better way of erasing the password */
+        /* but we do not want to link in libsrp         */
+        t_random(fbp->temp_feed, sizeof(Block));
+#else
+        memset(fbp->temp_feed, 0, sizeof(Block));
+#endif
+    }
+
+    fbp->key_isset = 1;
+    /*
+    * Now look to see if cast_fb64_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;
+        cast_fb64_start(fbp, DIR_ENCRYPT, server);
+    }
+    return(0);
+}
+
+/*
+ * We only accept a keyid of 0.  If we get a keyid of
+ * 0, then mark the state as SUCCESS.
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_keyid(dir, kp, lenp)
+    int dir, *lenp;
+    unsigned char *kp;
+{
+    return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[CFB_128]));
+}
+
+int
+cast_ofb64_keyid(dir, kp, lenp)
+    int dir, *lenp;
+    unsigned char *kp;
+{
+    return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[OFB_128]));
+}
+#endif
+
+int
+castexp_cfb64_keyid(dir, kp, lenp)
+    int dir, *lenp;
+    unsigned char *kp;
+{
+    return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[CFB_40]));
+}
+
+int
+castexp_ofb64_keyid(dir, kp, lenp)
+    int dir, *lenp;
+    unsigned char *kp;
+{
+    return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[OFB_40]));
+}
+
+static int
+cast_fb64_keyid(dir, kp, lenp, fbp)
+    int dir, *lenp;
+    unsigned char *kp;
+    struct cast_fb *fbp;
+{
+    register int state = fbp->state[dir-1];
+
+    if (*lenp != 1 || (*kp != '\0')) {
+        *lenp = 0;
+        return(state);
+    }
+
+    if (state == cFAILED)
+        state = IN_PROGRESS;
+
+    state &= ~NO_KEYID;
+
+    return(fbp->state[dir-1] = state);
+}
+
+static void
+cast_fb64_printsub(data, cnt, buf, buflen, type)
+    unsigned char *data, *buf, *type;
+    int cnt, buflen;
+{
+    char lbuf[64];
+    register 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
+cast_cfb64_printsub(data, cnt, buf, buflen)
+    unsigned char *data, *buf;
+    int cnt, buflen;
+{
+    cast_fb64_printsub(data, cnt, buf, buflen, "CFB64");
+}
+
+void
+cast_ofb64_printsub(data, cnt, buf, buflen)
+    unsigned char *data, *buf;
+    int cnt, buflen;
+{
+    cast_fb64_printsub(data, cnt, buf, buflen, "OFB64");
+}
+
+static void
+cast_fb64_stream_iv(seed, stp)
+    Block seed;
+    register struct cast_stinfo *stp;
+{
+    memcpy((void *)stp->str_iv, (void *)seed, sizeof(Block));
+    memcpy((void *)stp->str_output, (void *)seed, sizeof(Block));
+
+    stp->str_index = sizeof(Block);
+}
+
+static void
+cast_fb64_stream_key(key, stp, fs)
+    unsigned char * key;
+    register struct cast_stinfo *stp;
+    int fs;
+{
+#ifndef CAST_EXPORT_ENCRYPTION
+    if(fs)
+        ck_cast128_key_sched(&stp->str_sched, key);
+    else
+#endif
+        ck_cast5_40_key_sched(&stp->str_sched, key);
+
+    memcpy((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
+
+    stp->str_index = sizeof(Block);
+}
+
+/*
+ * CAST 64 bit Cipher Feedback
+ *
+ *     key --->+------+
+ *          +->| CAST |--+
+ *          |  +------+  |
+ *          |            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 = CAST(iV, key)
+ *      On = Dn ^ Vn
+ *      V(n+1) = CAST(On, key)
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+cast_cfb64_encrypt(s, c)
+        register unsigned char *s;
+        int c;
+{
+    _cast_cfb64_encrypt(s, c, &cast_fb[CFB_128].streams[DIR_ENCRYPT-1]);
+}
+#endif
+
+void
+castexp_cfb64_encrypt(s, c)
+    register unsigned char *s;
+    int c;
+{
+    _cast_cfb64_encrypt(s, c, &cast_fb[CFB_40].streams[DIR_ENCRYPT-1]);
+}
+
+static void
+_cast_cfb64_encrypt(s, c, stp)
+    register unsigned char *s;
+    int c;
+    register struct cast_stinfo *stp;
+{
+    register int index;
+
+    index = stp->str_index;
+    while (c-- > 0) {
+        if (index == sizeof(Block)) {
+            Block b;
+            ck_cast_ecb_encrypt(b, stp->str_output, &stp->str_sched, 0);
+            memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+            index = 0;
+        }
+
+        /* On encryption, we store (feed ^ data) which is cypher */
+        *s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
+        s++;
+        index++;
+    }
+    stp->str_index = index;
+}
+
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_decrypt(data)
+    int data;
+{
+    return _cast_cfb64_decrypt(data, &cast_fb[CFB_128].streams[DIR_DECRYPT-1]);
+}
+#endif
+
+int
+castexp_cfb64_decrypt(data)
+    int data;
+{
+    return _cast_cfb64_decrypt(data, &cast_fb[CFB_40].streams[DIR_DECRYPT-1]);
+}
+
+static int
+_cast_cfb64_decrypt(data, stp)
+    int data;
+    register struct cast_stinfo *stp;
+{
+    int index;
+
+    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);
+    }
+
+    index = stp->str_index++;
+    if (index == sizeof(Block)) {
+        Block b;
+        ck_cast_ecb_encrypt(b, stp->str_output, &stp->str_sched, 0);
+        memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+        stp->str_index = 1;     /* Next time will be 1 */
+        index = 0;              /* But now use 0 */
+    }
+
+    /* On decryption we store (data) which is cypher. */
+    stp->str_output[index] = data;
+    return(data ^ stp->str_feed[index]);
+}
+
+/*
+ * CAST 64 bit Output Feedback
+ *
+ * key --->+------+
+ *      +->| CAST |--+
+ *      |  +------+  |
+ *      +------------+
+ *                   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 = CAST(iV, key)
+ *      V(n+1) = CAST(Vn, key)
+ *      On = Dn ^ Vn
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+cast_ofb64_encrypt(s, c)
+    register unsigned char *s;
+    int c;
+{
+    _cast_ofb64_encrypt(s, c, &cast_fb[OFB_128].streams[DIR_ENCRYPT-1]);
+}
+#endif
+
+void
+castexp_ofb64_encrypt(s, c)
+    register unsigned char *s;
+    int c;
+{
+  _cast_ofb64_encrypt(s, c, &cast_fb[OFB_40].streams[DIR_ENCRYPT-1]);
+}
+
+static void
+_cast_ofb64_encrypt(s, c, stp)
+    register unsigned char *s;
+    int c;
+    register struct cast_stinfo *stp;
+{
+    register int index;
+
+    index = stp->str_index;
+    while (c-- > 0) {
+        if (index == sizeof(Block)) {
+            Block b;
+            ck_cast_ecb_encrypt(b, stp->str_feed, &stp->str_sched, 0);
+            memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+            index = 0;
+        }
+        *s++ ^= stp->str_feed[index];
+        index++;
+    }
+    stp->str_index = index;
+}
+
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_ofb64_decrypt(data)
+    int data;
+{
+    return _cast_ofb64_decrypt(data, &cast_fb[OFB_128].streams[DIR_DECRYPT-1]);
+}
+#endif
+
+int
+castexp_ofb64_decrypt(data)
+    int data;
+{
+    return _cast_ofb64_decrypt(data, &cast_fb[OFB_40].streams[DIR_DECRYPT-1]);
+}
+
+static int
+_cast_ofb64_decrypt(data, stp)
+    int data;
+    register struct cast_stinfo *stp;
+{
+    int index;
+
+    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);
+    }
+
+    index = stp->str_index++;
+    if (index == sizeof(Block)) {
+        Block b;
+        ck_cast_ecb_encrypt(b, stp->str_feed, &stp->str_sched, 0);
+        memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+        stp->str_index = 1;     /* Next time will be 1 */
+        index = 0;              /* But now use 0 */
+    }
+
+    return(data ^ stp->str_feed[index]);
+}
+
+/*
+ * Copyright (c) 1997 Stanford University
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * cast.c
+ * Author: Tom Wu
+ *
+ * An implementation of the CAST-128 encryption algorithm, as
+ * specified in RFC 2144.
+ */
+
+/* The first four S-boxes are for encryption/decryption */
+
+static uint32 S1[] = {
+  0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3,
+  0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675,
+  0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059,
+  0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+  0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b,
+  0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de,
+  0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159,
+  0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+  0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f,
+  0xb48ee411, 0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165,
+  0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, 0x882240f2, 0x0c6e4f38,
+  0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+  0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493,
+  0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a,
+  0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb,
+  0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+  0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14,
+  0xa0bebc3c, 0x54623779, 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6,
+  0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, 0x81383f05, 0x6963c5c8,
+  0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+  0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495,
+  0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e,
+  0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426,
+  0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+  0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98,
+  0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f,
+  0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,0x7b5a41f0, 0xd37cfbad,
+  0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+  0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464,
+  0x5ad328d8, 0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a,
+  0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,0x3f04442f, 0x6188b153,
+  0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+  0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274,
+  0xdd24cb9e, 0x7e1c54bd, 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755,
+  0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,0x580304f0, 0xca042cf1,
+  0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+  0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1,
+  0xd5ea50f1, 0x85a92872, 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79,
+  0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,0x474d6ad7, 0x7c0c5e5c,
+  0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+  0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff,
+  0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d,
+  0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
+};
+
+static uint32 S2[] = {
+  0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a,
+  0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba,
+  0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605,
+  0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+  0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b,
+  0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4,
+  0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083,
+  0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+  0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f,
+  0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d,
+  0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e,
+  0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+  0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366,
+  0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4,
+  0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064,
+  0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+  0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6,
+  0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709,
+  0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364,
+  0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+  0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b,
+  0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9,
+  0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c,
+  0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+  0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741,
+  0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab,
+  0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b,
+  0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+  0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa,
+  0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8,
+  0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028,
+  0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+  0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6,
+  0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b,
+  0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1,
+  0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+  0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb,
+  0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea,
+  0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d,
+  0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+  0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e,
+  0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef,
+  0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
+};
+
+static uint32 S3[] = {
+  0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b,
+  0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae,
+  0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9,
+  0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+  0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd,
+  0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e,
+  0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, 0xa8c01db7, 0x579fc264,
+  0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+  0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e,
+  0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f,
+  0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e,
+  0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+  0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790,
+  0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504,
+  0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e,
+  0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+  0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8,
+  0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d,
+  0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240,
+  0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+  0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c,
+  0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15,
+  0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788,
+  0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+  0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa,
+  0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392,
+  0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f,
+  0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+  0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae,
+  0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67,
+  0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9,
+  0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+  0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888,
+  0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d,
+  0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2,
+  0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+  0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2,
+  0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce,
+  0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d,
+  0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+  0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00,
+  0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5,
+  0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
+};
+
+static uint32 S4[] = {
+  0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57,
+  0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120,
+  0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd,
+  0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+  0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe,
+  0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701,
+  0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801,
+  0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+  0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1,
+  0x72500e03, 0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746,
+  0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3,
+  0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+  0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c,
+  0x18f8931e, 0x281658e6, 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c,
+  0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16,
+  0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+  0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7,
+  0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327,
+  0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002,
+  0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+  0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7,
+  0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031,
+  0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff,
+  0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+  0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035,
+  0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69,
+  0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec,
+  0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+  0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e,
+  0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3,
+  0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532, 0x58fd7eb6,
+  0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+  0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f,
+  0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091,
+  0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6,
+  0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+  0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2,
+  0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367,
+  0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda,
+  0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+  0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6,
+  0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e,
+  0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
+};
+
+/* Encrypt/decrypt one 64-bit block of data */
+
+void
+ck_cast_ecb_encrypt(out, in, sched, mode)
+    uint8p out;
+    uint8p in;
+    CastKeySched * sched;
+    int mode;           /* zero means encrypt */
+{
+    uint32 t[2];
+
+#ifdef LITTLE_ENDIAN
+    t[0] = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
+    t[1] = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | in[7];
+#else
+    t[0] = *(uint32p) in;
+    t[1] = *(uint32p) (in + 4);
+#endif
+
+    ck_cast_ecb_crypt(t, sched, mode);
+
+#ifdef LITTLE_ENDIAN
+    out[0] = (t[0] >> 24) & 0xff;
+    out[1] = (t[0] >> 16) & 0xff;
+    out[2] = (t[0] >> 8) & 0xff;
+    out[3] = t[0] & 0xff;
+    out[4] = (t[1] >> 24) & 0xff;
+    out[5] = (t[1] >> 16) & 0xff;
+    out[6] = (t[1] >> 8) & 0xff;
+    out[7] = t[1] & 0xff;
+#else
+    *(uint32p) out = t[0];
+    *(uint32p) (out + 4) = t[1];
+#endif
+}
+
+void
+ck_cast_ecb_crypt(data, sched, mode)
+    uint32p data;
+    CastKeySched * sched;
+    int mode;
+{
+    register uint32 L, R, temp;
+    register struct CastSubkeyPair * kp;
+    register uint8p Ia, Ib, Ic, Id;
+    uint32 I;
+
+#ifdef LITTLE_ENDIAN
+    Id = (uint8p) &I;
+    Ic = Id + 1;
+    Ib = Ic + 1;
+    Ia = Ib + 1;
+#else
+    Ia = (uint8p) &I;
+    Ib = Ia + 1;
+    Ic = Ib + 1;
+    Id = Ic + 1;
+#endif
+
+    L = data[0];
+    R = data[1];
+
+#define type0(left,right)       \
+      temp = kp->Km + right;\
+      I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\
+      left ^= ((S1[*Ia] ^ S2[*Ib]) - S3[*Ic]) + S4[*Id];
+
+#define type1(left,right)       \
+      temp = kp->Km ^ right;\
+      I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\
+      left ^= ((S1[*Ia] - S2[*Ib]) + S3[*Ic]) ^ S4[*Id];
+
+#define type2(left,right)       \
+      temp = kp->Km - right;\
+      I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\
+      left ^= ((S1[*Ia] + S2[*Ib]) ^ S3[*Ic]) - S4[*Id];
+
+    if(mode) {
+#ifndef CAST_EXPORT_ENCRYPTION
+        if(sched->ksize > 10) {
+            kp = &sched->K[15];
+            type0(L, R); --kp;
+            type2(R, L); --kp;
+            type1(L, R); --kp;
+            type0(R, L); --kp;
+        }
+        else
+#endif
+        kp = &sched->K[11];
+        type2(L, R); --kp;
+        type1(R, L); --kp;
+        type0(L, R); --kp;
+        type2(R, L); --kp;
+        type1(L, R); --kp;
+        type0(R, L); --kp;
+        type2(L, R); --kp;
+        type1(R, L); --kp;
+        type0(L, R); --kp;
+        type2(R, L); --kp;
+        type1(L, R); --kp;
+        type0(R, L);
+    }
+    else {
+        kp = &sched->K[0];
+        type0(L, R); ++kp;
+        type1(R, L); ++kp;
+        type2(L, R); ++kp;
+        type0(R, L); ++kp;
+        type1(L, R); ++kp;
+        type2(R, L); ++kp;
+        type0(L, R); ++kp;
+        type1(R, L); ++kp;
+        type2(L, R); ++kp;
+        type0(R, L); ++kp;
+        type1(L, R); ++kp;
+        type2(R, L); ++kp;
+#ifndef CAST_EXPORT_ENCRYPTION
+        if(sched->ksize > 10) {
+            type0(L, R); ++kp;
+            type1(R, L); ++kp;
+            type2(L, R); ++kp;
+            type0(R, L);
+        }
+#endif
+    }
+
+    data[0] = R;
+    data[1] = L;
+}
+
+/* The last four S-boxes are for key schedule setup */
+
+static uint32 S5[] = {
+  0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5,
+  0x44dd9d44, 0x1731167f, 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00,
+  0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, 0xe6a2e77f, 0xf0c720cd,
+  0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+  0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb,
+  0x8dba1cfe, 0x41a99b02, 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725,
+  0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, 0xf2f3f763, 0x68af8040,
+  0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+  0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2,
+  0x2261be02, 0xd642a0c9, 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec,
+  0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, 0x5c1ff900, 0xfe38d399,
+  0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+  0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966,
+  0xdfdd55bc, 0x29de0655, 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468,
+  0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, 0xbcf3f0aa, 0x87ac36e9,
+  0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+  0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616,
+  0xf24766e3, 0x8eca36c1, 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4,
+  0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, 0x26e46695, 0xb7566419,
+  0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+  0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9,
+  0x68cb3e47, 0x086c010f, 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6,
+  0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, 0x0ab378d5, 0xd951fb0c,
+  0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+  0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715,
+  0x646c6bd7, 0x44904db3, 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6,
+  0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, 0x76f0ae02, 0x083be84d,
+  0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+  0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba,
+  0x9cad9010, 0xaf462ba2, 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487,
+  0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, 0x445f7382, 0x175683f4,
+  0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+  0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c,
+  0x1ad2fff3, 0x8c25404e, 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78,
+  0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, 0x44094f85, 0x3f481d87,
+  0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+  0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110,
+  0x1b5ad7a8, 0xf61ed5ad, 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58,
+  0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, 0x5ce96c28, 0xe176eda3,
+  0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+  0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d,
+  0x34010718, 0xbb30cab8, 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55,
+  0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
+};
+
+static uint32 S6[] = {
+  0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4,
+  0xeced5cbc, 0x325553ac, 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9,
+  0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, 0x33f14961, 0xc01937bd,
+  0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+  0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f,
+  0xa888614a, 0x2900af98, 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c,
+  0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, 0xfd41197e, 0x9305a6b0,
+  0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+  0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941,
+  0x2c0e636a, 0xba7dd9cd, 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d,
+  0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, 0x284caf89, 0xaa928223,
+  0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+  0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6,
+  0x9a69a02f, 0x68818a54, 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a,
+  0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, 0x53bddb65, 0xe76ffbe7,
+  0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+  0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89,
+  0xfd339fed, 0xb87834bf, 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be,
+  0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, 0x4ec75b95, 0x24f2c3c0,
+  0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+  0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4,
+  0xe9a9d848, 0xf3160289, 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853,
+  0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, 0x36f73523, 0x4cfb6e87,
+  0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+  0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585,
+  0xdc049441, 0xc8098f9b, 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751,
+  0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, 0xbf32679d, 0xd45b5b75,
+  0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+  0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283,
+  0x3cc2acfb, 0x3fc06976, 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459,
+  0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, 0x3007cd3e, 0x74719eef,
+  0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+  0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0,
+  0xbc60b42a, 0x953498da, 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb,
+  0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, 0xe8816f4a, 0x3814f200,
+  0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+  0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf,
+  0x3a479c3a, 0x5302da25, 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b,
+  0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, 0xb81a928a, 0x60ed5869,
+  0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+  0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb,
+  0xb0e93524, 0xbebb8fbd, 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454,
+  0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
+};
+
+static uint32 S7[] = {
+  0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912,
+  0xde6008a1, 0x2028da1f, 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82,
+  0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, 0xa05fbcf6, 0xcd4181e9,
+  0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+  0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4,
+  0x1286becf, 0xb6eacb19, 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9,
+  0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, 0x107789be, 0xb3b2e9ce,
+  0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+  0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7,
+  0xd0d854c0, 0xcb3a6c88, 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e,
+  0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, 0x0a961288, 0xe1a5c06e,
+  0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+  0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9,
+  0xc6e6fa14, 0xbae8584a, 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b,
+  0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, 0x92544a8b, 0x009b4fc3,
+  0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+  0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c,
+  0x16746233, 0x3c034c28, 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802,
+  0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, 0x0c4fb99a, 0xbb325778,
+  0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+  0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be,
+  0xbe8b9d2d, 0x7979fb06, 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858,
+  0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, 0xf28ebfb0, 0xf5b9c310,
+  0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+  0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476,
+  0x488dcf25, 0x36c9d566, 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df,
+  0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, 0xf22b017d, 0xa4173f70,
+  0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+  0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a,
+  0x058745b9, 0x3453dc1e, 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07,
+  0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, 0x66626c1c, 0x7154c24c,
+  0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+  0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e,
+  0xe4f2dfa6, 0x693ed285, 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378,
+  0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, 0xc79f022f, 0x3c997e7e,
+  0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+  0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301,
+  0xcfd2a87f, 0x60aeb767, 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2,
+  0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, 0x97fd61a9, 0xea7759f4,
+  0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+  0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021,
+  0xc3c0bdae, 0x4958c24c, 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada,
+  0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
+};
+
+static uint32 S8[] = {
+  0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b,
+  0x0e241600, 0x052ce8b5, 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174,
+  0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, 0xde9adeb1, 0x0a0cc32c,
+  0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+  0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7,
+  0x72df191b, 0x7580330d, 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164,
+  0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, 0x12a8ddec, 0xfdaa335d,
+  0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+  0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8,
+  0x57e8726e, 0x647a78fc, 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6,
+  0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, 0xbbd35049, 0x2998df04,
+  0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+  0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38,
+  0x424f7618, 0x35856039, 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8,
+  0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, 0x7170c608, 0x2d5e3354,
+  0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+  0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160,
+  0x7895cda5, 0x859c15a5, 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab,
+  0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, 0x835ffcb8, 0x6df4c1f2,
+  0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+  0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98,
+  0x7cd16efc, 0x1436876c, 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441,
+  0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, 0xa842eedf, 0xfdba60b4,
+  0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+  0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5,
+  0xbae7dfdc, 0x42cbda70, 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c,
+  0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, 0x77853b53, 0x37effcb5,
+  0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+  0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b,
+  0xc4248289, 0xacf3ebc3, 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4,
+  0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, 0xe87b40e4, 0xe98ea084,
+  0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+  0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a,
+  0xe0779695, 0xf9c17a8f, 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf,
+  0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, 0x11403092, 0x00da6d77,
+  0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+  0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f,
+  0xdf09822b, 0xbd691a6c, 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819,
+  0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, 0x5938fa0f, 0x42399ef3,
+  0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+  0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1,
+  0xa466bb1e, 0xf8da0a82, 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d,
+  0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e
+};
+
+/* Initialize a key schedule from a 128-bit key */
+
+static void
+cast_key_sched(sched, key)
+     CastKeySched * sched;
+     uint8p key;
+{
+    uint8p x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xA, xB, xC, xD, xE, xF;
+    uint8p z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, zA, zB, zC, zD, zE, zF;
+    uint32 X03, X47, X8B, XCF, Z03, Z47, Z8B, ZCF;
+
+#ifdef LITTLE_ENDIAN
+    x3 = (uint8p) &X03;  x2 = x3 + 1;  x1 = x2 + 1;  x0 = x1 + 1;
+    x7 = (uint8p) &X47;  x6 = x7 + 1;  x5 = x6 + 1;  x4 = x5 + 1;
+    xB = (uint8p) &X8B;  xA = xB + 1;  x9 = xA + 1;  x8 = x9 + 1;
+    xF = (uint8p) &XCF;  xE = xF + 1;  xD = xE + 1;  xC = xD + 1;
+    z3 = (uint8p) &Z03;  z2 = z3 + 1;  z1 = z2 + 1;  z0 = z1 + 1;
+    z7 = (uint8p) &Z47;  z6 = z7 + 1;  z5 = z6 + 1;  z4 = z5 + 1;
+    zB = (uint8p) &Z8B;  zA = zB + 1;  z9 = zA + 1;  z8 = z9 + 1;
+    zF = (uint8p) &ZCF;  zE = zF + 1;  zD = zE + 1;  zC = zD + 1;
+#else
+    x0 = (uint8p) &X03;  x1 = x0 + 1;  x2 = x1 + 1;  x3 = x2 + 1;
+    x4 = (uint8p) &X47;  x5 = x4 + 1;  x6 = x5 + 1;  x7 = x6 + 1;
+    x8 = (uint8p) &X8B;  x9 = x8 + 1;  xA = x9 + 1;  xB = xA + 1;
+    xC = (uint8p) &XCF;  xD = xC + 1;  xE = xD + 1;  xF = xE + 1;
+    z0 = (uint8p) &Z03;  z1 = z0 + 1;  z2 = z1 + 1;  z3 = z2 + 1;
+    z4 = (uint8p) &Z47;  z5 = z4 + 1;  z6 = z5 + 1;  z7 = z6 + 1;
+    z8 = (uint8p) &Z8B;  z9 = z8 + 1;  zA = z9 + 1;  zB = zA + 1;
+    zC = (uint8p) &ZCF;  zD = zC + 1;  zE = zD + 1;  zF = zE + 1;
+#endif
+
+#ifdef LITTLE_ENDIAN
+    *x0 = key[0];
+    *x1 = key[1];
+    *x2 = key[2];
+    *x3 = key[3];
+    *x4 = key[4];
+    *x5 = key[5];
+    *x6 = key[6];
+    *x7 = key[7];
+    *x8 = key[8];
+    *x9 = key[9];
+    *xA = key[10];
+    *xB = key[11];
+    *xC = key[12];
+    *xD = key[13];
+    *xE = key[14];
+    *xF = key[15];
+#else
+    X03 = *(uint32p) key;
+    X47 = *(uint32p) (key + 4);
+    X8B = *(uint32p) (key + 8);
+    XCF = *(uint32p) (key + 12);
+#endif
+
+  /* First half of key schedule */
+
+    Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8];
+    Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA];
+    Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9];
+    ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB];
+
+    sched->K[0].Km = S5[*z8] ^ S6[*z9] ^ S7[*z7] ^ S8[*z6] ^ S5[*z2];
+    sched->K[1].Km = S5[*zA] ^ S6[*zB] ^ S7[*z5] ^ S8[*z4] ^ S6[*z6];
+    sched->K[2].Km = S5[*zC] ^ S6[*zD] ^ S7[*z3] ^ S8[*z2] ^ S7[*z9];
+    sched->K[3].Km = S5[*zE] ^ S6[*zF] ^ S7[*z1] ^ S8[*z0] ^ S8[*zC];
+
+    X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0];
+    X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2];
+    X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1];
+    XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3];
+
+    sched->K[4].Km = S5[*x3] ^ S6[*x2] ^ S7[*xC] ^ S8[*xD] ^ S5[*x8];
+    sched->K[5].Km = S5[*x1] ^ S6[*x0] ^ S7[*xE] ^ S8[*xF] ^ S6[*xD];
+    sched->K[6].Km = S5[*x7] ^ S6[*x6] ^ S7[*x8] ^ S8[*x9] ^ S7[*x3];
+    sched->K[7].Km = S5[*x5] ^ S6[*x4] ^ S7[*xA] ^ S8[*xB] ^ S8[*x7];
+
+    Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8];
+    Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA];
+    Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9];
+    ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB];
+
+    sched->K[8].Km = S5[*z3] ^ S6[*z2] ^ S7[*zC] ^ S8[*zD] ^ S5[*z9];
+    sched->K[9].Km = S5[*z1] ^ S6[*z0] ^ S7[*zE] ^ S8[*zF] ^ S6[*zC];
+    sched->K[10].Km = S5[*z7] ^ S6[*z6] ^ S7[*z8] ^ S8[*z9] ^ S7[*z2];
+    sched->K[11].Km = S5[*z5] ^ S6[*z4] ^ S7[*zA] ^ S8[*zB] ^ S8[*z6];
+
+    X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0];
+    X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2];
+    X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1];
+    XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3];
+
+    sched->K[12].Km = S5[*x8] ^ S6[*x9] ^ S7[*x7] ^ S8[*x6] ^ S5[*x3];
+    sched->K[13].Km = S5[*xA] ^ S6[*xB] ^ S7[*x5] ^ S8[*x4] ^ S6[*x7];
+    sched->K[14].Km = S5[*xC] ^ S6[*xD] ^ S7[*x3] ^ S8[*x2] ^ S7[*x8];
+    sched->K[15].Km = S5[*xE] ^ S6[*xF] ^ S7[*x1] ^ S8[*x0] ^ S8[*xD];
+
+  /* Second half of key schedule - just like first half */
+
+    Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8];
+    Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA];
+    Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9];
+    ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB];
+
+    sched->K[0].Kr = (S5[*z8] ^ S6[*z9] ^ S7[*z7] ^ S8[*z6] ^ S5[*z2]) & 0x1f;
+    sched->K[1].Kr = (S5[*zA] ^ S6[*zB] ^ S7[*z5] ^ S8[*z4] ^ S6[*z6]) & 0x1f;
+    sched->K[2].Kr = (S5[*zC] ^ S6[*zD] ^ S7[*z3] ^ S8[*z2] ^ S7[*z9]) & 0x1f;
+    sched->K[3].Kr = (S5[*zE] ^ S6[*zF] ^ S7[*z1] ^ S8[*z0] ^ S8[*zC]) & 0x1f;
+
+    X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0];
+    X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2];
+    X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1];
+    XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3];
+
+    sched->K[4].Kr = (S5[*x3] ^ S6[*x2] ^ S7[*xC] ^ S8[*xD] ^ S5[*x8]) & 0x1f;
+    sched->K[5].Kr = (S5[*x1] ^ S6[*x0] ^ S7[*xE] ^ S8[*xF] ^ S6[*xD]) & 0x1f;
+    sched->K[6].Kr = (S5[*x7] ^ S6[*x6] ^ S7[*x8] ^ S8[*x9] ^ S7[*x3]) & 0x1f;
+    sched->K[7].Kr = (S5[*x5] ^ S6[*x4] ^ S7[*xA] ^ S8[*xB] ^ S8[*x7]) & 0x1f;
+
+    Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8];
+    Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA];
+    Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9];
+    ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB];
+
+    sched->K[8].Kr = (S5[*z3] ^ S6[*z2] ^ S7[*zC] ^ S8[*zD] ^ S5[*z9]) & 0x1f;
+    sched->K[9].Kr = (S5[*z1] ^ S6[*z0] ^ S7[*zE] ^ S8[*zF] ^ S6[*zC]) & 0x1f;
+    sched->K[10].Kr = (S5[*z7] ^ S6[*z6] ^ S7[*z8] ^ S8[*z9] ^ S7[*z2]) & 0x1f;
+    sched->K[11].Kr = (S5[*z5] ^ S6[*z4] ^ S7[*zA] ^ S8[*zB] ^ S8[*z6]) & 0x1f;
+
+    X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0];
+    X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2];
+    X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1];
+    XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3];
+
+    sched->K[12].Kr = (S5[*x8] ^ S6[*x9] ^ S7[*x7] ^ S8[*x6] ^ S5[*x3]) & 0x1f;
+    sched->K[13].Kr = (S5[*xA] ^ S6[*xB] ^ S7[*x5] ^ S8[*x4] ^ S6[*x7]) & 0x1f;
+    sched->K[14].Kr = (S5[*xC] ^ S6[*xD] ^ S7[*x3] ^ S8[*x2] ^ S7[*x8]) & 0x1f;
+    sched->K[15].Kr = (S5[*xE] ^ S6[*xF] ^ S7[*x1] ^ S8[*x0] ^ S8[*xD]) & 0x1f;
+}
+
+/* Initialize with a full-strength 128-bit key */
+
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+ck_cast128_key_sched(sched, key)
+    CastKeySched * sched;
+    uint8 * key;
+{
+    sched->ksize = 16;
+    cast_key_sched(sched, key);
+}
+#endif
+
+/* Handle reduced-keysize variants */
+
+static void
+cast5_key_sched(sched, key, sz)
+    CastKeySched * sched;
+    uint8 * key;
+    int sz;
+{
+    uint8 buf[16];
+
+    sched->ksize = sz;
+    memset(buf, 0, sizeof(buf));
+    memcpy(buf, key, sz);
+    cast_key_sched(sched, buf);
+}
+
+/* 40, 64, and 80-bit keys - all use 12 rounds */
+
+void
+ck_cast5_40_key_sched(sched, key)
+    CastKeySched * sched;
+    uint8 * key;
+{
+    cast5_key_sched(sched, key, 5);
+}
+
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+ck_cast5_64_key_sched(sched, key)
+     CastKeySched * sched;
+     uint8 * key;
+{
+    cast5_key_sched(sched, key, 8);
+}
+
+void
+ck_cast5_80_key_sched(sched, key)
+     CastKeySched * sched;
+     uint8 * key;
+{
+    cast5_key_sched(sched, key, 10);
+}
+#endif /* CAST_EXPORT_ENCRYPTION */
+#endif /* CK_CAST */
+
+#ifdef CRYPT_DLL
+static char *
+ck_crypt_dll_version()
+{
+    return(ckcrpv);
+}
+
+int
+crypt_dll_init( struct _crypt_dll_init * init )
+{
+#ifdef LIBDES
+    extern int des_check_key;
+    extern void libdes_dll_init(struct _crypt_dll_init *);
+    des_check_key = 1;
+#endif /* LIBDES */
+
+    if ( init->version >= 1 ) {
+        p_ttol = init->p_ttol;
+        p_dodebug = init->p_dodebug;
+        p_dohexdump = init->p_dohexdump;
+        p_tn_debug = init->p_tn_debug;
+        p_vscrnprintf = init->p_vscrnprintf;
+        if ( init->version == 1 )
+            return(1);
+    }
+    if ( init->version >= 2 ) {
+        /* This is a k5_context but we don't want to include krb5.h */
+        p_k5_context = (void *) init->p_k5_context;
+        if ( init->version == 2 )
+            return(1);
+    }
+    if ( init->version >= 3 ) {
+        init->p_install_funcs("encrypt_parse",encrypt_parse);
+        init->p_install_funcs("encrypt_init",encrypt_init);
+        init->p_install_funcs("encrypt_session_key",encrypt_session_key);
+        init->p_install_funcs("encrypt_send_request_start",
+                              encrypt_send_request_start
+                              );
+        init->p_install_funcs("encrypt_request_start",encrypt_request_start);
+        init->p_install_funcs("encrypt_send_request_end",
+                              encrypt_send_request_end
+                              );
+        init->p_install_funcs("encrypt_request_end",encrypt_request_end);
+        init->p_install_funcs("encrypt_send_end",encrypt_send_end);
+        init->p_install_funcs("encrypt_send_support",encrypt_send_support);
+        init->p_install_funcs("encrypt_is_encrypting",encrypt_is_encrypting);
+        init->p_install_funcs("encrypt_is_decrypting",encrypt_is_decrypting);
+        init->p_install_funcs("get_crypt_table",get_crypt_table);
+        init->p_install_funcs("des_is_weak_key",ck_des_is_weak_key);
+        libdes_dll_init(init);
+        if (init->version == 3)
+          return(1);
+    }
+    if ( init->version >= 4 ) {
+        init->p_install_funcs("crypt_dll_version",ck_crypt_dll_version);
+        if (init->version == 4)
+          return(1);
+    }
+
+    if ( init->version >= 5 ) {
+        p_reqtelmutex = init->p_reqtelmutex;
+        p_reltelmutex = init->p_reltelmutex;
+        if (init->version == 5)
+          return(1);
+    }
+
+    if ( init->version >= 6 ) {
+        init->p_install_funcs("encrypt_dont_support",encrypt_dont_support);
+        if ( init->version == 6 )
+            return(1);
+        /* when adding new versions; migrate the next two lines */
+        init->version = 6;
+        return(1);
+    }
+    return(0);
+}
+
+#undef malloc
+#undef realloc
+#undef free
+#undef strdup
+
+static void
+fatal(char *msg) {
+    if (!msg) msg = "";
+
+    printf(msg);
+    exit(1);        /* Exit indicating failure */
+}
+
+void *
+kmalloc(size_t size)
+{
+    void *ptr;
+
+    if (size == 0) {
+        fatal("kmalloc: zero size");
+    }
+    ptr = malloc(size);
+    if (ptr == NULL) {
+        fatal("kmalloc: out of memory");
+    }
+    return ptr;
+}
+
+void *
+krealloc(void *ptr, size_t new_size)
+{
+    void *new_ptr;
+
+    if (new_size == 0) {
+        fatal("krealloc: zero size");
+    }
+    if (ptr == NULL)
+        new_ptr = malloc(new_size);
+    else
+        new_ptr = realloc(ptr, new_size);
+    if (new_ptr == NULL) {
+        fatal("krealloc: out of memory");
+    }
+    return new_ptr;
+}
+
+void
+kfree(void *ptr)
+{
+    if (ptr == NULL) {
+        printf("kfree: NULL pointer given as argument");
+        return;
+    }
+    free(ptr);
+}
+
+char *
+kstrdup(const char *str)
+{
+    size_t len;
+    char *cp;
+
+    if (str == NULL) {
+        fatal("kstrdup: NULL pointer given as argument");
+    }
+    len = strlen(str) + 1;
+    cp = kmalloc(len);
+    if (cp)
+        memcpy(cp, str, len);
+    return cp;
+}
+#endif /* CRYPT_DLL */
+#endif /* CK_ENCRYPTION */
diff --git a/ckermit-8.0.211/ck_des.c b/ckermit-8.0.211/ck_des.c
new file mode 100644
index 0000000..c534652
--- /dev/null
+++ b/ckermit-8.0.211/ck_des.c
@@ -0,0 +1,98 @@
+/*
+  C K _ D E S . C  -  libDES interface for Kermit 95"
+
+  Copyright (C) 1998, 2001, Trustees of Columbia University in the City of New
+  York.  The C-Kermit software may not be, in whole or in part, licensed or
+  sold for profit as a software product itself, nor may it be included in or
+  distributed with commercial products or otherwise distributed by commercial
+  concerns to their clients or customers without written permission of the
+  Office of Kermit Development and Distribution, Columbia University.  This
+  copyright notice must not be removed, altered, or obscured.
+
+  Author:
+  Jeffrey E Altman (jaltman@secure-endpoints.com)
+*/
+
+/*
+   This file contains wrappers so that the following functions will be imported
+   into the k95crypt.dll/k2crypt.dll files in such a form that they can be
+   re-exported to k95.exe/k2.exe.  This subset of the DES library is needed to
+   provide DES based Kerberos authentication.
+*/
+
+
+#ifdef LIBDES
+/* The following is specific to my installation, but since I'm the only one */
+/* that uses this file ...                                                  */
+#include "ckcdeb.h"
+#include "ckuath.h"
+#define CK_DES_C
+#include "ckuat2.h"
+#ifdef NT
+#ifdef _M_ALPHA
+#include <c:\srp\des\des.h>
+#else
+#include <c:\src\srp\des\des.h>
+#endif
+#else
+#include <c:\srp\des\des.h>
+#endif
+
+int
+libdes_random_key(des_cblock B)
+{
+    des_random_key(B);
+    return(0);
+}
+
+void
+libdes_random_seed(des_cblock B)
+{
+    des_random_seed(B);
+}
+
+void
+libdes_key_sched(des_cblock * B, des_key_schedule S)
+{
+    des_key_sched(B,S);
+}
+
+void
+libdes_ecb_encrypt(des_cblock * B1, des_cblock * B2, des_key_schedule S, int n)
+{
+    des_ecb_encrypt(B1,B2,S,n);
+}
+
+int
+libdes_string_to_key(char * s, des_cblock * B)
+{
+    des_string_to_key(s,B);
+    return(0);
+}
+
+void
+libdes_fixup_key_parity(des_cblock * B)
+{
+    des_set_odd_parity(B);
+}
+
+void
+libdes_pcbc_encrypt(des_cblock *input, des_cblock *output, long length,
+                     des_key_schedule schedule, des_cblock *ivec, int enc)
+{
+    des_pcbc_encrypt(input,output,length,schedule,ivec,enc);
+}
+
+void
+libdes_dll_init(struct _crypt_dll_init * init)
+{
+    init->p_install_funcs("libdes_random_key",libdes_random_key);
+    init->p_install_funcs("libdes_random_seed",libdes_random_seed);
+    init->p_install_funcs("libdes_key_sched",libdes_key_sched);
+    init->p_install_funcs("libdes_ecb_encrypt",libdes_ecb_encrypt);
+    init->p_install_funcs("libdes_string_to_key",libdes_string_to_key);
+    init->p_install_funcs("libdes_fixup_key_parity",libdes_fixup_key_parity);
+    init->p_install_funcs("libdes_pcbc_encrypt",libdes_pcbc_encrypt);
+
+}
+#endif /* LIBDES */
diff --git a/ckermit-8.0.211/ck_ssl.c b/ckermit-8.0.211/ck_ssl.c
new file mode 100644
index 0000000..7b53770
--- /dev/null
+++ b/ckermit-8.0.211/ck_ssl.c
@@ -0,0 +1,4242 @@
+char *cksslv = "SSL/TLS support, 8.0.221, 26 Feb 2004";
+/*
+  C K _ S S L . C --  OpenSSL Interface for C-Kermit
+
+  Copyright (C) 1985, 2004,
+    Trustees of Columbia University in the City of New York.
+    All rights reserved.  See the C-Kermit COPYING.TXT file or the
+    copyright text in the ckcmai.c module for disclaimer and permissions.
+
+    Author:  Jeffrey E Altman (jaltman@secure-endpoints.com)
+               Secure Endpoints Inc., New York City
+
+  Provides:
+
+  . Telnet Auth SSL option compatible with Tim Hudson's hack.
+  . Telnet START_TLS option
+  . Configuration of certificate and key files
+  . Certificate verification and revocation list checks
+  . Client certificate to user id routine
+
+  Note: This code is written to be compatible with OpenSSL 0.9.6[abcdefgh]
+  and 0.9.7 beta 5.
+  It will also compile with version 0.9.5 although that is discouraged
+  due to security weaknesses in that release.
+*/
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+
+#ifdef CK_SSL
+#include "ckcnet.h"
+#include "ckuath.h"
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef UNIX
+#include <netinet/in.h>
+#ifndef FREEBSD4
+#include <arpa/inet.h>
+#endif /* FREEBSD4 */
+#endif /* UNIX */
+
+#ifdef DEC_TCPIP
+#include <time.h>
+#include <inet.h>
+#endif /* DEC_TCPIP */
+
+#ifdef OS2
+extern char exedir[];
+#ifdef NT
+char * GetAppData(int);
+#endif
+#endif /* OS2 */
+
+static int ssl_installed = 1;
+#endif /* CK_SSL */
+int
+ck_ssh_is_installed()
+{
+#ifdef SSHBUILTIN
+#ifdef SSLDLL
+#ifdef NT
+    extern HINSTANCE hCRYPTO;
+#else /* NT */
+    extern HMODULE hCRYPTO;
+#endif /* NT */
+    debug(F111,"ck_ssh_is_installed","hCRYPTO",hCRYPTO);
+    return(ssl_installed && (hCRYPTO != NULL));
+#else /* SSLDLL */
+    return(ssl_installed);
+#endif /* SSLDLL */
+#else
+    return 0;
+#endif
+}
+
+int
+#ifdef CK_ANSIC
+ck_ssleay_is_installed(void)
+#else
+ck_ssleay_is_installed()
+#endif
+{
+#ifdef CK_SSL
+#ifdef SSLDLL
+#ifdef NT
+    extern HINSTANCE hSSL, hCRYPTO;
+#else /* NT */
+    extern HMODULE hSSL, hCRYPTO;
+#endif /* NT */
+    debug(F111,"ck_ssleay_is_installed","hSSL",hSSL);
+    debug(F111,"ck_ssleay_is_installed","hCRYPTO",hCRYPTO);
+    return(ssl_installed && (hSSL != NULL) && (hCRYPTO != NULL));
+#else /* SSLDLL */
+    return(ssl_installed);
+#endif /* SSLDLL */
+#else /* CK_SSL */
+    return(0);
+#endif /* CK_SSL */
+}
+
+#ifdef CK_SSL
+#include "ckcker.h"
+#include "ckucmd.h"                             /* For struct keytab */
+#include "ckctel.h"
+#include "ck_ssl.h"
+#ifdef UNIX
+#include <pwd.h>                    /* Password file for home directory */
+#endif /* UNIX */
+#ifdef OS2
+#include <process.h>
+#endif /* OS2 */
+#ifdef OS2ONLY
+#include "ckotcp.h"
+#endif /* OS2ONLY */
+
+#ifdef SSLDLL
+int ssl_finished_messages = 0;
+#else /* SSLDLL */
+#ifdef OPENSSL_VERSION_NUMBER
+int ssl_finished_messages = (OPENSSL_VERSION_NUMBER >= 0x0090581fL);
+#else
+!ERROR This module requires OpenSSL 0.9.5a or higher
+#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* SSLDLL */
+
+static int auth_ssl_valid = 0;
+static char *auth_ssl_name = 0;    /* this holds the oneline name */
+char ssl_err[SSL_ERR_BFSZ]="";
+
+BIO *bio_err=NULL;
+X509_STORE *crl_store = NULL;
+
+#ifndef NOFTP
+#ifndef SYSFTP
+SSL *ssl_ftp_con             = NULL;
+SSL_CTX *ssl_ftp_ctx         = NULL;
+SSL *ssl_ftp_data_con        = NULL;
+int ssl_ftp_active_flag      = 0;
+int ssl_ftp_data_active_flag = 0;
+#endif /* SYSFTP */
+#endif /* NOFTP */
+
+#ifndef NOHTTP
+SSL *tls_http_con            = NULL;
+SSL_CTX *tls_http_ctx        = NULL;
+int tls_http_active_flag     = 0;
+int ssl_http_initialized = 0;
+#endif /* NOHTTP */
+
+SSL_CTX *ssl_ctx = NULL;
+SSL *ssl_con = NULL;
+int ssl_debug_flag = 0;
+int ssl_verbose_flag = 0;
+int ssl_only_flag = 0;
+int ssl_active_flag = 0;
+int ssl_verify_flag = SSL_VERIFY_PEER;
+int ssl_certsok_flag = 0;
+char *ssl_rsa_cert_file = NULL;
+char *ssl_rsa_cert_chain_file = NULL;
+char *ssl_rsa_key_file = NULL;
+char *ssl_dsa_cert_file = NULL;
+char *ssl_dsa_cert_chain_file = NULL;
+char *ssl_dh_key_file = NULL;
+char *ssl_crl_file = NULL;
+char *ssl_crl_dir = NULL;
+char *ssl_verify_file = NULL;
+char *ssl_verify_dir = NULL;
+char *ssl_dh_param_file = NULL;
+char *ssl_cipher_list = NULL;
+char *ssl_rnd_file = NULL;
+
+SSL_CTX *tls_ctx = NULL;
+SSL *tls_con = NULL;
+int tls_only_flag = 0;
+int tls_active_flag = 0;
+
+int ssl_initialized = 0;
+int ssl_verify_depth = -1; /* used to track depth in verify routines */
+
+/* compile this set to 1 to negotiate SSL/TLS but not actually start it */
+int ssl_dummy_flag=0;
+
+extern int inserver;
+extern int debses;
+extern int accept_complete;
+extern char szHostName[], szUserNameRequested[], szUserNameAuthenticated[];
+
+_PROTOTYP(int X509_to_user,(X509 *, char *, int));
+
+int
+#ifdef CK_ANSIC
+ssl_server_verify_callback(int ok, X509_STORE_CTX * ctx)
+#else /* CK_ANSIC */
+ssl_server_verify_callback(ok, ctx)
+int ok;
+X509_STORE_CTX *ctx;
+#endif /* CK_ANSIC */
+{
+    static char *saved_subject=NULL;
+    char *subject=NULL, *issuer=NULL;
+    int depth,error;
+    X509 *xs = NULL;
+
+    if ( ssl_certsok_flag )
+        return(1);
+
+    error=X509_STORE_CTX_get_error(ctx);
+    depth=X509_STORE_CTX_get_error_depth(ctx);
+    xs=X509_STORE_CTX_get_current_cert(ctx);
+
+    if (depth==0) {
+        /* clear things */
+        if (saved_subject!=NULL) {
+            free(saved_subject);
+            saved_subject=NULL;
+        }
+        if (auth_ssl_name!=NULL) {
+            free(auth_ssl_name);
+            auth_ssl_name=NULL;
+        }
+    }
+
+
+    if (ssl_debug_flag && !inserver) {
+        printf("ssl:server_verify_callback:depth=%d ok=%d err=%d-%s\r\n",
+            depth,ok,error,X509_verify_cert_error_string(error));
+    }
+
+    /* first thing is to have a meaningful name for the current
+     * certificate that is being verified ... and if we cannot
+     * determine that then something is seriously wrong!
+     */
+    makestr(&subject,
+            (char *)X509_NAME_oneline(X509_get_subject_name(xs),NULL,0));
+    makestr(&issuer,
+            (char *)X509_NAME_oneline(X509_get_issuer_name(xs),NULL,0));
+    if (!subject || !subject[0] || !issuer || !issuer[0]) {
+        ok = 0;
+        goto return_time;
+    }
+
+    if (ssl_verbose_flag && !inserver && depth != ssl_verify_depth) {
+        printf("[%d] Certificate Subject:\r\n%s\r\n",depth,subject);
+        printf("[%d] Certificate Issuer:\r\n%s\r\n",depth,issuer);
+        ssl_verify_depth = depth;
+    }
+
+    /* make sure that the certificate that has been presented */
+    /* has not been revoked (if we have been given a CRL.     */
+    ok =  ssl_verify_crl(ok, ctx);
+
+    /* if we have any form of error in secure mode we reject the connection */
+    if (error!=X509_V_OK) {
+        if (inserver) {
+#ifdef CKSYSLOG
+            if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+                cksyslog(SYSLG_LI, 0,
+                          "X.509 Certificate verify failure",
+                          (char *) subject,
+                          (char *)X509_verify_cert_error_string(error)
+                          );
+            }
+#endif /* CKSYSLOG */
+
+        } else {
+            if ( ssl_verify_flag &
+                 (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+                printf("Error: ");
+            else
+                printf("Warning: ");
+            switch (error) {
+            case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+                printf("Certificate is self signed.\r\n");
+                break;
+            case X509_V_ERR_CERT_HAS_EXPIRED:
+                printf("Certificate has expired.\r\n");
+                break;
+            case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+                printf(
+  "Certificate issuer's certificate isn't available locally.\r\n");
+                break;
+            case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+                printf("Unable to verify leaf signature.\r\n");
+                break;
+            case X509_V_ERR_CERT_REVOKED:
+                printf("Certificate revoked.\r\n");
+                break;
+            default:
+                printf("Error %d while verifying certificate.\r\n",
+                       ctx->error);
+                break;
+            }
+        }
+        ok = !(ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+    } else {
+        /* if we got all the way to the top of the tree then
+         * we *can* use this certificate for a username to
+         * match ... in all other cases we must not!
+         */
+        auth_ssl_name = saved_subject;
+        saved_subject = NULL;
+    }
+
+  return_time:
+
+    /* save the name if at least the first level is okay */
+    if (depth == 0 && ok)
+        makestr(&saved_subject,subject);
+
+    /* clean up things */
+    if (subject!=NULL)
+        free(subject);
+    if (issuer!=NULL)
+        free(issuer);
+
+    return ok;
+}
+
+int
+#ifdef CK_ANSIC
+ssl_client_verify_callback(int ok, X509_STORE_CTX * ctx)
+#else
+ssl_client_verify_callback(ok, ctx)
+int ok;
+X509_STORE_CTX *ctx;
+#endif
+{
+    char subject[256]="", issuer[256]="";
+    int depth, error, len;
+    X509 *xs;
+
+    xs=X509_STORE_CTX_get_current_cert(ctx);
+    error=X509_STORE_CTX_get_error(ctx);
+    depth=X509_STORE_CTX_get_error_depth(ctx);
+
+    if ( ssl_debug_flag )
+        printf("ssl:client_verify_callback:depth=%d ok=%d err=%d-%s\r\n",
+                depth,ok,error,X509_verify_cert_error_string(error));
+
+    if ( ssl_certsok_flag ) {
+        ok = 1;
+    }
+
+    /* first thing is to have a meaningful name for the current
+     * certificate that is being verified ... and if we cannot
+     * determine that then something is seriously wrong!
+     */
+#ifdef XN_FLAG_SEP_MULTILINE
+    X509_NAME_print_ex(bio_err,X509_get_subject_name(xs),4,
+                        XN_FLAG_SEP_MULTILINE);
+    len = BIO_read(bio_err,subject,256);
+    subject[len < 256 ? len : 255] = '\0';
+    if (!subject[0]) {
+        ERR_print_errors(bio_err);
+        len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+        ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+        uq_ok("X.509 Subject Name unavailable", ssl_err, 1, NULL, 0);
+        ok=0;
+        goto return_time;
+    }
+
+    X509_NAME_print_ex(bio_err,X509_get_issuer_name(xs),4,
+                        XN_FLAG_SEP_MULTILINE);
+    len = BIO_read(bio_err,issuer,256);
+    issuer[len < 256 ? len : 255] = '\0';
+    if (!issuer[0]) {
+        ERR_print_errors(bio_err);
+        len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+        ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+        uq_ok("X.509 Issuer Name unavailable", ssl_err, 1, NULL, 0);
+        ok=0;
+        goto return_time;
+    }
+#else /* XN_FLAG_SEP_MULTILINE */
+    X509_NAME_oneline(X509_get_subject_name(xs),subject,256);
+    if (!subject[0]) {
+        int len;
+        ERR_print_errors(bio_err);
+        len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+        ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+        uq_ok("X.509 Subject Name unavailable", ssl_err, 1, NULL, 0);
+        ok=0;
+        goto return_time;
+    }
+
+    X509_NAME_oneline(X509_get_issuer_name(xs),issuer,256);
+    if (!issuer[0]) {
+        int len;
+        ERR_print_errors(bio_err);
+        len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+        ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+        uq_ok("X.509 Issuer Name unavailable", ssl_err, 1, NULL, 0);
+        ok=0;
+        goto return_time;
+    }
+#endif /* XN_FLAG_SEP_MULTILINE */
+
+    if (ssl_verbose_flag && depth != ssl_verify_depth) {
+        printf("[%d] Certificate Subject:\r\n%s\r\n",depth,subject);
+        printf("[%d] Certificate Issuer:\r\n%s\r\n",depth,issuer);
+        ssl_verify_depth = depth;
+    }
+
+    ok = ssl_verify_crl(ok, ctx);
+
+    if ( !ok ) {
+        char prefix[1024];
+        /* if the server is using a self signed certificate then
+         * we need to decide if that is good enough for us to
+         * accept ...
+         */
+
+        switch ( error ) {
+        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: {
+            if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                /* make 100% sure that in secure more we drop the
+                 * connection if the server does not have a
+                 * real certificate!
+                 */
+                ckmakxmsg(prefix,1024,
+                           "Error: Server has a self-signed certificate\n",
+                           "[",ckitoa(depth),"] Certificate Subject=\n",subject,
+                           "\n[",ckitoa(depth),"] Certificate Issuer=\n",issuer,
+                           NULL,NULL,NULL);
+
+                uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+
+                /* sometimes it is really handy to be able to debug things
+                * and still get a connection!
+                */
+                if (ssl_debug_flag) {
+                    printf("SSL: debug -> ignoring cert required!\r\n");
+                    ok=1;
+                } else {
+                    ok=0;
+                }
+                goto return_time;
+            } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+                ckmakxmsg(prefix,1024,
+                           "Warning: Server has a self-signed certificate\n",
+                           "[",ckitoa(depth),"] Certificate Subject=\n",subject,
+                           "\n[",ckitoa(depth),"] Certificate Issuer=\n",issuer,
+                           NULL,NULL,NULL);
+
+                ok = uq_ok(prefix,
+                           "Continue? (Y/N) ",
+                           3, NULL, 0);
+                if ( ok < 0 )
+                    ok = 0;
+                goto return_time;
+            }
+        }
+        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+            if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                /* make 100% sure that in secure more we drop the
+                 * connection if the server does not have a
+                 * real certificate!
+                 */
+                ckmakxmsg(prefix,1024,
+                           "Error: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Issuer=\n",issuer,
+                           NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+                uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+
+                /* sometimes it is really handy to be able to debug things
+                * and still get a connection!
+                */
+                if (ssl_debug_flag) {
+                    printf("SSL: debug -> ignoring cert required!\r\n");
+                    ok=1;
+                } else {
+                    ok=0;
+                }
+                goto return_time;
+            } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+                ckmakxmsg(prefix,1024,
+                           "Warning: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Issuer=\n",issuer,
+                           NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+                ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+                goto return_time;
+            }
+            break;
+        case X509_V_ERR_CERT_NOT_YET_VALID:
+        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+            if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                int len;
+                /* make 100% sure that in secure more we drop the
+                 * connection if the server does not have a
+                 * real certificate!
+                 */
+                ASN1_TIME_print(bio_err,X509_get_notBefore(xs));
+                len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+                ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+                ckmakxmsg(prefix,1024,
+                           "Error: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Subject=\n",subject,
+                           "\nnotBefore=",ssl_err,
+                           NULL,NULL,NULL,NULL,NULL,NULL);
+                uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+                /* sometimes it is really handy to be able to debug things
+                * and still get a connection!
+                */
+                if (ssl_debug_flag) {
+                    printf("SSL: debug -> ignoring cert required!\r\n");
+                    ok=1;
+                } else {
+                    ok=0;
+                }
+                goto return_time;
+            } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+                int len;
+                ASN1_TIME_print(bio_err,X509_get_notBefore(xs));
+                len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+                ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+                ckmakxmsg(prefix,1024,
+                           "Warning: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Subject=\n",subject,
+                           "\n    notBefore=",ssl_err,
+                           NULL,NULL,NULL,NULL,NULL,NULL);
+                ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+            }
+            break;
+        case X509_V_ERR_CERT_HAS_EXPIRED:
+        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+            if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                int len;
+                /* make 100% sure that in secure more we drop the
+                 * connection if the server does not have a
+                 * real certificate!
+                 */
+                ASN1_TIME_print(bio_err,X509_get_notAfter(xs));
+                len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+                ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+
+                ckmakxmsg(prefix,1024,
+                           "Error: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Subject=\n",subject,
+                           "\n    notAfter=",ssl_err,
+                           NULL,NULL,NULL,NULL,NULL,NULL);
+                uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+   
+                /* sometimes it is really handy to be able to debug things
+                * and still get a connection!
+                */
+                if (ssl_debug_flag) {
+                    printf("SSL: debug -> ignoring cert required!\r\n");
+                    ok=1;
+                } else {
+                    ok=0;
+                }
+                goto return_time;
+            } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+                int len;
+                ASN1_TIME_print(bio_err,X509_get_notAfter(xs));
+                len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+                ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+                ckmakxmsg(prefix,1024,
+                           "Warning: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Subject=\n",subject,
+                           "\n    notAfter=",ssl_err,
+                           NULL,NULL,NULL,NULL,NULL,NULL);
+                ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+            }
+            break;
+        case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+            /*
+             * When an SSL server sends its certificates to the client there
+             * are two" conventions": one is to send the complete certificate
+             * chain and the other is to send the whole chain apart from the
+             * root.
+             *
+             * You don't usually need the root because the root is normally
+             * stored and trusted locally.
+             *
+             * So if you get the whole chain it will complain about the self
+             * signed certificate whereas if the root is missing it says it
+             * can't find the issuer certificate.
+             */
+            if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                /* make 100% sure that in secure more we drop the
+                 * connection if the server does not have a
+                 * real certificate!
+                 */
+                ckmakxmsg(prefix,1024,
+                           "Error: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Issuer=\n",issuer,
+                           NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+                uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+                /* sometimes it is really handy to be able to debug things
+                * and still get a connection!
+                */
+                if (ssl_debug_flag) {
+                    printf("SSL: debug -> ignoring cert required!\r\n");
+                    ok=1;
+                } else {
+                    ok=0;
+                }
+                goto return_time;
+            } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+                ckmakxmsg(prefix,1024,
+                           "Warning: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Issuer=\n",issuer,
+                           NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+                ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+#ifdef NT
+                if (ok) {
+                    /* if the user decides to accept the certificate
+                     * offer to store it for future connections in 
+                     * the user's private store
+                     */
+                    ok = uq_ok(
+  "Do you wish to store the certificate to verify future connections?",
+                               "Continue (Y/N)", 3, NULL, 0);
+                    if (ok)
+                        ck_X509_save_cert_to_user_store(xs);
+                }
+#endif /* NT */
+            }
+            break;
+        case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+        case X509_V_ERR_UNABLE_TO_GET_CRL:
+        case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+        case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+        case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+        case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+        case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+        case X509_V_ERR_CRL_NOT_YET_VALID:
+        case X509_V_ERR_CRL_HAS_EXPIRED:
+        case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+        case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+        case X509_V_ERR_OUT_OF_MEM:
+        case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+        case X509_V_ERR_CERT_REVOKED:
+        case X509_V_ERR_APPLICATION_VERIFICATION:
+        default:
+            if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                /* make 100% sure that in secure mode we drop the
+                 * connection if the server does not have a
+                 * real certificate!
+                 */
+                ckmakxmsg(prefix,1024,
+                           "Error: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Subject=\n",subject,
+                           NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+                uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+
+                /* sometimes it is really handy to be able to debug things
+                * and still get a connection!
+                */
+                if (ssl_debug_flag) {
+                    printf("SSL: debug -> ignoring cert required!\r\n");
+                    ok=1;
+                } else {
+                    ok=0;
+                }
+                goto return_time;
+            } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+                ckmakxmsg(prefix,1024,
+                           "Warning: ",
+                           (char *)X509_verify_cert_error_string(error),
+                           "\nCertificate Subject=\n",subject,
+                           NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+                ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+            }
+            break;
+        }
+    }
+
+  return_time:
+    if ( ssl_debug_flag )
+        printf("ssl:client_verify_callback => ok: %d\r\n",ok);
+    return ok;
+}
+
+VOID
+#ifdef CK_ANSIC
+ssl_client_info_callback(const SSL *s, int where, int ret)
+#else
+ssl_client_info_callback(s,where,ret)
+const SSL *s;
+int where;
+int ret;
+#endif /* CK_ANSIC */
+{
+    if (inserver || !ssl_debug_flag)
+        return;
+
+    switch ( where ) {
+    case SSL_CB_CONNECT_LOOP:
+        printf("SSL_connect:%s %s\r\n",
+                SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+        break;
+    case SSL_CB_CONNECT_EXIT:
+        if (ret == 0) {
+            printf("SSL_connect:failed in %s %s\r\n",
+                    SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+        } else if (ret < 0) {
+            printf("SSL_connect:error in %s %s\r\n",
+                    SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+        }
+        break;
+    case SSL_CB_ACCEPT_LOOP:
+        printf("SSL_accept:%s %s\r\n",
+                SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+        break;
+    case SSL_CB_ACCEPT_EXIT:
+        if (ret == 0) {
+            printf("SSL_accept:failed in %s %s\r\n",
+                    SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+        } else if (ret < 0) {
+            printf("SSL_accept:error in %s %s\r\n",
+                    SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+        }
+        break;
+    case SSL_CB_READ_ALERT:
+        printf("SSL_read_alert\r\n");
+        break;
+    case SSL_CB_WRITE_ALERT:
+        printf("SSL_write_alert\r\n");
+        break;
+    case SSL_CB_HANDSHAKE_START:
+        printf("SSL_handshake:%s %s\r\n",
+                SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+        break;
+    case SSL_CB_HANDSHAKE_DONE:
+        printf("SSL_handshake:%s %s\r\n",
+                SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+        break;
+    }
+}
+
+#ifdef USE_CERT_CB
+/* Return 1, client cert is available */
+/* Return 0, no client cert is available */
+/* Return -1, callback must be called again. SSL_want_x509_lookup() == 1 */
+int
+#ifdef CK_ANSIC
+ssl_client_cert_callback(SSL * s, X509 ** x509, EVP_PKEY ** pkey)
+#else /* CK_ANSIC */
+ssl_client_cert_callback(s, x509, pkey)
+    SSL * s;
+    X509 ** x509;
+    EVP_PKEY ** pkey;
+#endif /* CK_ANSIC */
+{
+    if ( ssl_debug_flag ) {
+        const char * cipher_list=SSL_get_cipher(s);
+        printf("ssl_client_cert_callback called (%s)\r\n",
+                cipher_list?cipher_list:"UNKNOWN");
+    }
+#ifdef COMMENT
+    if ( s == tls_con ) {
+        if (tls_load_certs(tls_cts,tls_con,0)) {
+            *x509 = SSL_get_certificate(s);
+            *pkey = SSL_get_privatekey(s);
+            return(1);
+        }
+    } else if ( s == ssl_con ) {
+        if (tls_load_certs(ssl_ctx,ssl_con,0)) {
+            *x509 = SSL_get_certificate(s);
+            *pkey = SSL_get_privatekey(s);
+            return(1);
+        }
+    }
+    return(0);
+#else /* COMMENT */
+    return(0);
+#endif /* COMMENT */
+}
+#endif /* USE_CERT_CB */
+
+#ifndef MS_CALLBACK
+#define MS_CALLBACK
+#endif /* MS_CALLBACK */
+
+static RSA MS_CALLBACK *
+#ifdef CK_ANSIC
+tmp_rsa_cb(SSL * s, int export, int keylength)
+#else /* CK_ANSIC */
+tmp_rsa_cb(s,export,keylength)
+SSL *s;
+int export;
+int keylength;
+#endif /* CK_ANSIC */
+{
+    static RSA *rsa_tmp=NULL;
+    extern int quiet;
+
+#ifndef NO_RSA
+    if (rsa_tmp == NULL)
+    {
+        if (ssl_debug_flag)
+            printf("Generating temporary (%d bit) RSA key...\r\n",keylength);
+
+        rsa_tmp=RSA_generate_key(keylength,RSA_F4,NULL,NULL);
+
+        if (ssl_debug_flag)
+            printf("\r\n");
+    }
+#else /* NO_RSA */
+    if (ssl_debug_flag)
+        printf("Unable to generate temporary RSA key...\r\n");
+#endif
+    return(rsa_tmp);
+}
+
+
+#ifndef NO_DH
+static unsigned char dh512_p[]={
+    0xE9,0x4E,0x3A,0x64,0xFA,0x65,0x5F,0xA6,0x44,0xC7,0xFC,0xF1,
+    0x16,0x8B,0x11,0x11,0x7A,0xF0,0xB2,0x49,0x80,0x56,0xA3,0xF8,
+    0x0F,0x7D,0x01,0x68,0x5D,0xF6,0x8A,0xEA,0x8C,0xDD,0x01,0xDC,
+    0x43,0x18,0xE0,0xC4,0x89,0x80,0xE6,0x2D,0x44,0x77,0x45,0xFD,
+    0xBA,0xFC,0x43,0x35,0x12,0xC0,0xED,0x32,0xD3,0x16,0xEF,0x51,
+    0x09,0x44,0xA2,0xDB,
+};
+static unsigned char dh512_g[]={
+    0x05,
+};
+
+static unsigned char dh768_p[]={
+    0x8B,0x2A,0x8C,0x6C,0x0F,0x87,0xC7,0x34,0xEE,0x2E,0xFB,0x60,
+    0x94,0xB3,0xBF,0x95,0xBA,0x84,0x74,0x86,0xEA,0xE0,0xA4,0x33,
+    0xE0,0x8F,0x7C,0x79,0x5C,0x62,0xE2,0x91,0xC5,0x6D,0x68,0xB9,
+    0x6C,0x5E,0x4E,0x94,0x0C,0x8E,0x56,0x8E,0xEB,0x98,0x7C,0x6E,
+    0x0E,0xF2,0xD5,0xAA,0x22,0x27,0x3F,0x0F,0xAF,0x10,0xB5,0x0B,
+    0x16,0xCC,0x05,0x27,0xBB,0x58,0x6D,0x61,0x4B,0x2B,0xAB,0xDC,
+    0x6A,0x15,0xBC,0x36,0x75,0x4D,0xEC,0xAB,0xFA,0xB6,0xE1,0xB1,
+    0x13,0x70,0xD8,0x77,0xCD,0x5E,0x51,0x77,0x81,0x0D,0x77,0x43,
+};
+static unsigned char dh768_g[]={
+    0x05,
+};
+
+static unsigned char dh1024_p[]={
+    0xA4,0x75,0xCF,0x35,0x00,0xAF,0x3C,0x17,0xCE,0xB0,0xD0,0x52,
+    0x43,0xA0,0x0E,0xFA,0xA2,0xC9,0xBE,0x0B,0x76,0x7A,0xD9,0x2E,
+    0xF4,0x97,0xAC,0x02,0x24,0x69,0xF6,0x36,0x4F,0xAB,0xCC,0x43,
+    0xC1,0x74,0xFF,0xA3,0xD4,0x04,0x0F,0x11,0x2B,0x6D,0x8C,0x47,
+    0xC9,0xCF,0x40,0x93,0x9B,0x7D,0x1E,0x52,0x85,0xB2,0x17,0x55,
+    0x9C,0xF2,0x41,0x02,0x2A,0x9D,0x5F,0x24,0x22,0xC6,0x04,0xC4,
+    0xAB,0x92,0x6D,0xC7,0xC8,0xF3,0x41,0x58,0x6C,0x86,0xFD,0xB8,
+    0x0F,0x2D,0xDD,0xBF,0xA8,0x40,0x0C,0x58,0xC8,0xF2,0x3F,0x18,
+    0xEF,0xF1,0x93,0x3E,0xBA,0x16,0x41,0xBE,0x32,0x6C,0xC5,0x63,
+    0xFF,0x8A,0x02,0x3D,0xAC,0xD5,0x5A,0x49,0x64,0x34,0x14,0x2E,
+    0xFB,0x2E,0xE7,0x39,0x1A,0x0F,0x3C,0x33,
+};
+static unsigned char dh1024_g[]={
+    0x05,
+};
+
+static unsigned char dh1536_p[]={
+    0xA3,0x2B,0x75,0x0E,0x7B,0x31,0x82,0xCA,0xF2,0xFC,0xF3,0x3D,
+    0xCE,0x5F,0xCD,0x5B,0x95,0xF6,0x2F,0xA4,0x5D,0x08,0x26,0xD2,
+    0x5F,0xC0,0x3F,0xC5,0xD8,0xA2,0xFE,0x83,0x26,0xBC,0xEB,0x7D,
+    0xF0,0x4E,0xD2,0xA6,0xBB,0x3C,0x88,0x63,0xCE,0x98,0xDE,0x08,
+    0xE2,0xE1,0xAF,0xE2,0x38,0xA8,0xFA,0x68,0x76,0x8D,0xBF,0xDF,
+    0xBB,0x30,0x15,0xFE,0xBD,0x22,0xCC,0x03,0x4E,0x5E,0x33,0xA3,
+    0x6D,0xD6,0x68,0x12,0x97,0x17,0x4B,0xB5,0x84,0x5F,0x5F,0xA3,
+    0x5C,0x2F,0xA4,0x10,0xC1,0xAD,0xBF,0xAC,0x30,0xCA,0x47,0x64,
+    0x63,0xFE,0xEE,0xEE,0xA1,0x64,0x73,0x70,0xAA,0xF9,0xFE,0xC6,
+    0xAD,0x5E,0xF6,0xF3,0x9C,0xDF,0x34,0x53,0x34,0x72,0xA6,0xA4,
+    0xBB,0x81,0x5A,0x43,0x41,0xFD,0x41,0x05,0x5B,0x77,0x7B,0x84,
+    0x03,0xFA,0x8A,0xFA,0xF7,0x8E,0x0F,0xCB,0x51,0xA2,0xB8,0x45,
+    0xFF,0x59,0x42,0xEF,0xCF,0xF6,0x25,0x37,0xE2,0x6D,0xFF,0x69,
+    0x11,0xF5,0x77,0x59,0x79,0x1C,0x5F,0x05,0xFC,0x7A,0x65,0x81,
+    0x03,0x4A,0x78,0xC6,0xE9,0x48,0x73,0xF6,0x10,0xBC,0x99,0x1C,
+    0xEE,0x44,0x2F,0x8B,0x70,0xCA,0xA8,0xB6,0x02,0x83,0x3E,0x0B,
+};
+static unsigned char dh1536_g[]={
+    0x05,
+};
+
+static unsigned char dh2048_p[]={
+    0xFA,0x4E,0xE4,0x3B,0xFA,0xC1,0x87,0xDD,0xE7,0xC6,0x8B,0xE6,
+    0x13,0x85,0xBC,0x9B,0x2B,0x8B,0x5B,0x46,0xBB,0x8B,0x86,0x6D,
+    0xD7,0xB6,0xD5,0x49,0xC5,0x54,0xF2,0x3E,0xD2,0x39,0x64,0x9B,
+    0x0E,0x33,0x39,0x8F,0xFA,0xFA,0xD9,0x78,0xED,0x34,0x82,0x29,
+    0x37,0x58,0x4D,0x5D,0x40,0xCB,0x69,0xE3,0x8A,0x9F,0x17,0x0C,
+    0x01,0x23,0x6B,0x05,0x01,0xAF,0x33,0xDE,0xDF,0x1A,0xBB,0x7B,
+    0x6A,0x9F,0xD8,0xED,0x8D,0x5E,0x44,0x19,0x5B,0xE0,0xB6,0x23,
+    0xF9,0x7A,0x96,0x6E,0x94,0x33,0x31,0x49,0xBA,0x84,0xD5,0x12,
+    0xD7,0x6D,0xDC,0x35,0x54,0x64,0xA3,0xD8,0x04,0x26,0xC5,0xAF,
+    0x7F,0xE3,0xFE,0x6F,0xBE,0xD5,0x17,0x72,0x4B,0xA6,0xD0,0xA7,
+    0x5F,0x18,0xF5,0xF0,0x2D,0x11,0x9A,0xF6,0xD5,0x3B,0x6C,0x61,
+    0x3C,0x6F,0x8E,0x09,0x4F,0x2C,0xE1,0x26,0x06,0x51,0xB3,0x19,
+    0x85,0x85,0x13,0xF9,0xC2,0x6E,0x80,0x28,0x9E,0x8A,0xA0,0x01,
+    0x46,0xD1,0x85,0x44,0x8C,0xE6,0xEE,0x7E,0x1E,0x17,0x3D,0xBA,
+    0x54,0xFF,0xE8,0x0E,0xDD,0x51,0xF3,0x74,0x7F,0x0D,0x0B,0xAB,
+    0xCA,0x84,0x8D,0x24,0x5D,0x56,0xD4,0x47,0x02,0xFC,0x93,0x9F,
+    0xAE,0x9B,0x5C,0xDB,0x63,0xEB,0x65,0x01,0x38,0xC2,0x7B,0x30,
+    0x1E,0x17,0x1C,0x75,0xF5,0x16,0x3B,0x4F,0x5F,0x41,0x32,0xB5,
+    0xFF,0x9E,0x61,0xFD,0xD2,0x62,0x6E,0xFD,0x8A,0x28,0x93,0x59,
+    0x2D,0x70,0x14,0x4D,0xE1,0x86,0xD5,0x90,0xB4,0xDF,0x72,0x71,
+    0xE0,0xB4,0xD0,0xD6,0x82,0x3A,0x4A,0x04,0x58,0x32,0x0B,0xD3,
+    0x51,0x13,0x32,0x63,
+};
+static unsigned char dh2048_g[]={
+    0x02,
+};
+
+static DH *
+get_dh512()
+{
+    DH *dh=NULL;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+    dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+    if ((dh->p == NULL) || (dh->g == NULL))
+        return(NULL);
+    return(dh);
+}
+
+static DH *
+get_dh768()
+{
+    DH *dh=NULL;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    dh->p=BN_bin2bn(dh768_p,sizeof(dh768_p),NULL);
+    dh->g=BN_bin2bn(dh768_g,sizeof(dh768_g),NULL);
+    if ((dh->p == NULL) || (dh->g == NULL))
+        return(NULL);
+    return(dh);
+}
+
+static DH *
+get_dh1024()
+{
+    DH *dh=NULL;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
+    dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
+    if ((dh->p == NULL) || (dh->g == NULL))
+        return(NULL);
+    return(dh);
+}
+
+static DH *
+get_dh1536()
+{
+    DH *dh=NULL;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    dh->p=BN_bin2bn(dh1536_p,sizeof(dh1536_p),NULL);
+    dh->g=BN_bin2bn(dh1536_g,sizeof(dh1536_g),NULL);
+    if ((dh->p == NULL) || (dh->g == NULL))
+        return(NULL);
+    return(dh);
+}
+
+static DH *
+get_dh2048()
+{
+    DH *dh=NULL;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
+    dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
+    if ((dh->p == NULL) || (dh->g == NULL))
+        return(NULL);
+    return(dh);
+}
+#endif /* NO_DH */
+
+static DH MS_CALLBACK *
+#ifdef CK_ANSIC
+tmp_dh_cb(SSL * s, int export, int keylength)
+#else /* CK_ANSIC */
+tmp_dh_cb(s,export,keylength)
+SSL *s;
+int export;
+int keylength;
+#endif /* CK_ANSIC */
+{
+    static DH *dh_tmp=NULL;
+    BIO *bio=NULL;
+    extern int quiet;
+
+#ifndef NO_DH
+    if (dh_tmp == NULL)
+    {
+        if (ssl_dh_param_file  &&
+             (bio=BIO_new_file(ssl_dh_param_file,"r")) != NULL)
+            dh_tmp=PEM_read_bio_DHparams(bio,NULL,NULL,NULL);
+        if (bio != NULL)
+            BIO_free(bio);
+
+        if ( dh_tmp == NULL ) {
+            if ( keylength < 768 )
+                dh_tmp = get_dh512();
+            else if ( keylength < 1024 )
+                dh_tmp = get_dh768();
+            else if ( keylength < 1536 )
+                dh_tmp = get_dh1024();
+            else if ( keylength < 2048 )
+                dh_tmp = get_dh1536();
+            else
+                dh_tmp = get_dh2048();
+        }
+    }
+#else /* NO_DH */
+    if (ssl_debug_flag)
+        printf("DH not supported...\r\n");
+#endif /* NO_DH */
+    return(dh_tmp);
+}
+
+static void
+ssl_display_comp(SSL * ssl)
+{
+    if ( !ck_ssleay_is_installed() )
+        return;
+
+    if (ssl == NULL)
+        return;
+
+    if (ssl->expand == NULL || ssl->expand->meth == NULL)
+        printf("Compression: None\r\n");
+    else {
+        printf("Compression: %s\r\n",ssl->expand->meth->name);
+    }
+}
+
+int
+#ifdef CK_ANSIC
+ssl_display_connect_details(SSL * ssl_con, int server, int verbose)
+#else /* CK_ANSIC */
+ssl_display_connect_details(ssl_con,server,verbose)
+SSL *ssl_con;
+int server;
+int verbose;
+#endif /* CK_ANSIC */
+{
+    X509 *peer;
+    SSL_CIPHER * cipher;
+    const char *cipher_list;
+    char buf[512]="";
+
+    if ( !ck_ssleay_is_installed() )
+        return(0);
+
+    if ( inserver && !tn_deb )
+        return(0);
+
+    /* the cipher list *can* be NULL ... useless but it happens! */
+    cipher = SSL_get_current_cipher(ssl_con);
+    cipher_list = SSL_CIPHER_get_name(cipher);
+    SSL_CIPHER_description(cipher,buf,sizeof(buf));
+    if (cipher_list==NULL)
+        cipher_list="<NULL>";
+    printf("[TLS - %s",buf);
+    ssl_display_comp(ssl_con);
+
+    if ( server ) {
+        cipher_list=SSL_get_shared_ciphers(ssl_con,buf,512);
+        if (cipher_list==NULL)
+            cipher_list="<NULL>";
+        printf("[TLS - shared ciphers=%s]\r\n",
+                cipher_list);
+        }       
+    if ( server || tn_deb ) {
+        peer=SSL_get_peer_certificate(ssl_con);
+        if (peer != NULL) {
+            X509_NAME_oneline(X509_get_subject_name(peer),buf,512);
+            printf("[TLS - subject=%s]\r\n",buf);
+            X509_NAME_oneline(X509_get_issuer_name(peer),buf,512);
+            printf("[TLS - issuer=%s]\r\n",buf);
+            /* X509_free(peer); */
+        } else if (!tls_is_krb5(0)) {
+            if ( !sstelnet && !tcp_incoming ) {
+                printf("[TLS - No certificate provided.]\r\n");
+                printf(
+     "[TLS - The identity of the host could not be verified.]\r\n");
+            }
+        }
+    }
+    return(0);
+}
+
+/*
+ * Use SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *, void * userdata)
+ * to set the value of the userdata.  We are going to use it to store the
+ * prompt.
+ */
+
+int
+#ifdef CK_ANSIC
+ssl_passwd_callback(char *buf, int len, int rwflag, VOID * userdata)
+#else /* CK_ANSIC */
+ssl_passwd_callback(buf,len,rwflag,userdata)
+    char * buf; int len; int rwflag; VOID *userdata;
+#endif /* CK_ANSIC */
+{
+    extern char pwbuf[];
+    extern int  pwflg, pwcrypt;
+    int   ok;
+    char *prompt=NULL;
+
+    if ( pwbuf[0] && pwflg ) {
+        int n;
+        n = ckstrncpy(buf,pwbuf,len);
+#ifdef OS2
+        if ( pwcrypt )
+            ck_encrypt((char *)buf);
+#endif /* OS2 */
+        return(n);
+    }
+
+    if ( userdata == NULL )
+        prompt="Enter certificate passphrase: ";
+    else
+        prompt=(char*)userdata;
+    ok = uq_txt(NULL,prompt,2,NULL,buf,len,NULL,DEFAULT_UQ_TIMEOUT);
+    return(ok > 0 ? strlen(buf) : 0);
+}
+
+
+/* Attempts to load certificate data into the TLS context structures */
+/* Returns 1 on success; 0 on failure */
+int
+tls_load_certs(SSL_CTX * ctx, SSL * con, int server)
+{
+    int rc = 1;
+    extern int quiet;
+
+    if ( !ck_ssleay_is_installed() )
+        return(0);
+
+    debug(F111,"tls_load_certs","SSL_CTX",ctx);
+    debug(F111,"tls_load_certs","SSL",con);
+    debug(F111,"tls_load_certs","server",server);
+
+    if ( con ) {
+        if (ssl_rsa_cert_file) {
+            if ( ssl_debug_flag )
+                printf("Loading RSA certificate into SSL\r\n");
+
+            rc = SSL_use_certificate_file(con, ssl_rsa_cert_file,
+                                               X509_FILETYPE_PEM);
+            if (!rc)
+            {
+                if ( !quiet || ssl_debug_flag )
+                    printf("Error loading certificate from %s\r\n",
+                            ssl_rsa_cert_file);
+            } else {
+                if (!ssl_rsa_key_file || !ssl_rsa_key_file[0])
+                    makestr(&ssl_rsa_key_file,ssl_rsa_cert_file);
+
+                rc = SSL_use_PrivateKey_file(con, ssl_rsa_key_file,
+                                                  X509_FILETYPE_PEM);
+                if (!rc)
+                    rc = SSL_use_PrivateKey_file(con, ssl_rsa_cert_file,
+                                                      X509_FILETYPE_PEM);
+                if (!rc)
+                {
+                    if ( !quiet || ssl_debug_flag )
+                        printf("Error loading key from %s\r\n",
+                                ssl_rsa_key_file);
+                } else {
+                    rc = SSL_check_private_key(con);
+                    if (!rc)
+                    {
+                        if ( ssl_debug_flag )
+                            printf(
+                "Private key does not match the certificate public key\r\n");
+                    }
+                }
+            }
+        }
+
+        if (ssl_dsa_cert_file) {
+            if ( ssl_debug_flag )
+                printf("Loading DSA certificate into SSL\r\n");
+
+            rc = SSL_use_certificate_file(con, ssl_dsa_cert_file,
+                                               X509_FILETYPE_PEM);
+            if (!rc)
+            {
+                if ( ssl_debug_flag ) {
+                    printf("Error loading certificate from %s\r\n",
+                            ssl_dsa_cert_file);
+                }
+            } else {
+                if (!ssl_dh_key_file || !ssl_dh_key_file[0])
+                    makestr(&ssl_dh_key_file,ssl_dsa_cert_file);
+                rc = SSL_use_PrivateKey_file(con, ssl_dh_key_file,
+                                                  X509_FILETYPE_PEM);
+                if (!rc)
+                    rc = SSL_use_PrivateKey_file(con, ssl_dsa_cert_file,
+                                                      X509_FILETYPE_PEM);
+                if (!rc)
+                {
+                    if ( !quiet || ssl_debug_flag ) {
+                        printf("Error loading key from %s\r\n",
+                                ssl_dh_key_file);
+                    }
+                } else {
+                    rc = SSL_check_private_key(con);
+                    if (!rc)
+                    {
+                        if ( ssl_debug_flag )
+                            printf(
+                   "Private key does not match the certificate public key\n");
+                    }
+                }
+            }
+        }
+    } else {
+        if (ssl_rsa_cert_file) {
+            if ( ssl_debug_flag )
+                printf("Loading RSA certificate into SSL\r\n");
+
+            rc = SSL_CTX_use_certificate_file(ctx, ssl_rsa_cert_file,
+                                       X509_FILETYPE_PEM);
+            if (!rc)
+            {
+                if ( !quiet || ssl_debug_flag )
+                    printf("Error loading certificate from %s\r\n",
+                            ssl_rsa_cert_file);
+            } else {
+                if (!ssl_rsa_key_file || !ssl_rsa_key_file[0])
+                    makestr(&ssl_rsa_key_file,ssl_rsa_cert_file);
+
+                rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_rsa_key_file,
+                                                  X509_FILETYPE_PEM);
+                if (!rc)
+                  rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_rsa_cert_file,
+                                                   X509_FILETYPE_PEM);
+                if (!rc) {
+                    if ( ssl_debug_flag )
+                      printf("Error loading key from %s\r\n",ssl_rsa_key_file);
+                } else {
+                    rc = SSL_CTX_check_private_key(ctx);
+                    if (!rc) {
+                        if ( ssl_debug_flag )
+                          printf(
+                "Private key does not match the certificate public key\r\n");
+                    }
+                }
+            }
+        }
+        if (ssl_dsa_cert_file) {
+            if ( ssl_debug_flag )
+              printf("Loading DSA certificate into SSL\r\n");
+
+            rc = SSL_CTX_use_certificate_file(ctx, ssl_dsa_cert_file,
+                                              X509_FILETYPE_PEM);
+            if (!rc) {
+                if ( ssl_debug_flag ) {
+                    printf("Error loading certificate from %s\r\n",
+                           ssl_dsa_cert_file);
+                }
+            } else {
+                if (!ssl_dh_key_file || !ssl_dh_key_file[0])
+                    makestr(&ssl_dh_key_file,ssl_dsa_cert_file);
+                rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_dh_key_file,
+                                                  X509_FILETYPE_PEM);
+                if (!rc)
+                  rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_dsa_cert_file,
+                                                      X509_FILETYPE_PEM);
+                if (!rc) {
+                    if ( ssl_debug_flag )
+                      printf("Error loading key from %s\r\n",ssl_dh_key_file);
+                } else {
+                    rc = SSL_CTX_check_private_key(ctx);
+                    if (!rc) {
+                        if ( ssl_debug_flag )
+                          printf(
+                   "Private key does not match the certificate public key\n");
+                    }
+                }
+            }
+        }
+    }
+
+    if (ssl_rsa_cert_chain_file && server) {
+        int skip1st = 0;
+        if (ssl_debug_flag)
+            printf("Loading RSA Certificate Chain into SSL\r\n");
+        if (!ckstrcmp(ssl_rsa_cert_chain_file,ssl_rsa_cert_file,-1,
+#ifdef OS2
+                       0
+#else
+                       1
+#endif /* OS2 */
+                       ))
+            skip1st = 1;
+        rc = SSL_CTX_use_certificate_chain_file(ctx,ssl_rsa_cert_chain_file);
+        if (!rc && ssl_debug_flag)
+                printf("Error loading RSA Certificate Chain into SSL\r\n");
+    }
+    if (ssl_dsa_cert_chain_file && server) {
+        int skip1st = 0;
+        if (ssl_debug_flag)
+            printf("Loading DSA Certificate Chain into SSL\r\n");
+        if (!ckstrcmp(ssl_dsa_cert_chain_file,ssl_dsa_cert_file,-1,
+#ifdef OS2
+                       0
+#else
+                       1
+#endif /* OS2 */
+                       ))
+            skip1st = 1;
+        rc = SSL_CTX_use_certificate_chain_file(ctx,ssl_dsa_cert_chain_file);
+        if (!rc && ssl_debug_flag)
+                printf("Error loading DSA Certificate Chain into SSL\r\n");
+    }
+    return(rc);
+}
+
+VOID
+#ifdef CK_ANSIC
+ssl_once_init(void)
+#else
+ssl_once_init()
+#endif /* CK_ANSIC */
+{
+    COMP_METHOD * cm;
+
+    if ( !ck_ssleay_is_installed() )
+        return;
+
+    debug(F111,"Kermit built for OpenSSL",OPENSSL_VERSION_TEXT,SSLEAY_VERSION_NUMBER);
+#ifndef OS2ONLY
+    debug(F111,"OpenSSL Library",SSLeay_version(SSLEAY_VERSION),
+           SSLeay());
+    debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_BUILT_ON),0);
+    debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_CFLAGS),0);
+    debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_PLATFORM),0);
+
+    /* The following test is suggested by Richard Levitte */
+    if (((OPENSSL_VERSION_NUMBER ^ SSLeay()) & 0xffffff0f) 
+#ifdef OS2
+         || ckstrcmp(OPENSSL_VERSION_TEXT,(char *)SSLeay_version(SSLEAY_VERSION),-1,1)
+#endif /* OS2 */
+         ) {
+        ssl_installed = 0;
+        debug(F111,"OpenSSL Version does not match.  Built with",
+               SSLeay_version(SSLEAY_VERSION),SSLEAY_VERSION_NUMBER);
+        printf("?OpenSSL libraries do not match required version.");
+        printf("  SSL\\TLS support disabled\r\n\r\n");
+        bleep(BP_FAIL);
+#ifdef SSLDLL
+        ck_ssl_unloaddll();
+        ck_crypto_unloaddll();
+#endif /* SSLDLL */
+        return;
+    }
+#endif /* OS2ONLY */
+
+    /* init things so we will get meaningful error messages
+    * rather than numbers
+    */
+    SSL_load_error_strings();
+
+#ifdef SSHBUILTIN
+    OPENSSL_add_all_algorithms_noconf();
+#else
+    /* SSL_library_init() only loads those ciphers needs for SSL  */
+    /* These happen to be a similar set to those required for SSH */
+    /* but they are not a complete set of ciphers provided by the */
+    /* crypto library.                                            */
+    SSL_library_init();
+#endif /* SSHBUILTIN */
+
+#ifdef ZLIB
+    cm = COMP_zlib();
+    if (cm != NULL && cm->type != NID_undef) {
+        SSL_COMP_add_compression_method(0xe0, cm); /* EAY's ZLIB ID */
+    }
+#endif /* ZLIB */
+    cm = COMP_rle();
+    if (cm != NULL && cm->type != NID_undef)
+        SSL_COMP_add_compression_method(0xe1, cm); /* EAY's RLE ID */
+
+    /* Ensure the Random number generator has enough entropy */
+    if ( !RAND_status() ) {
+        char buffer[256]="";
+        char randombytes[256];
+        int rc1 = -1, rc2 = 1;  /* assume failure and success */
+
+        debug(F110,"ssl_once_init","!RAND_status()",0);
+
+        if ( ssl_rnd_file == NULL ) {
+            debug(F110,"ssl_rnd_file","ssl_rnd_file is NULL",0);
+            RAND_file_name(buffer,256);
+            if ( buffer[0] )
+                makestr(&ssl_rnd_file, buffer);
+            else
+                makestr(&ssl_rnd_file,".rnd");
+        }
+        debug(F110,"ssl_rnd_file",ssl_rnd_file,0);
+
+        rc1 = RAND_egd(ssl_rnd_file);
+        debug(F111,"ssl_once_init","RAND_egd()",rc1);
+        if ( rc1 <= 0 ) {
+            rc2 = RAND_load_file(ssl_rnd_file, -1);
+            debug(F111,"ssl_once_init","RAND_load_file()",rc1);
+        }
+
+        if ( rc1 <= 0 && !rc2 )
+        {
+            time_t t = time(NULL);
+            int tlen = sizeof(time_t);
+            int pid = getpid();
+            int plen = sizeof(int);
+            int n;
+#ifndef RAND_MAX
+#define RAND_MAX 0x7FFF
+#endif
+            debug(F110,"ssl_once_init","calling RAND_seed()",0);
+
+            RAND_seed((unsigned char *)&t, tlen);
+            RAND_seed((unsigned char *)&pid, plen);
+
+            srand((unsigned int)t);
+            sprintf(buffer, "%.0f", (((double)(rand()%RAND_MAX)/RAND_MAX)*
+                                      (sizeof(randombytes)-128-1)));
+            n = (atoi(buffer)+1)%(sizeof(randombytes)-128-1);
+            RAND_seed(randombytes, 128);
+        }
+
+        if ( !RAND_status() ) {
+            debug(F110,"ssl_once_init","Unable to initialize PRNG",0);
+            printf(" Unable to load 'random state'\n");
+            printf(" SSL and TLS are unavailble.\n");
+            printf(" Use SET AUTH SSL RANDOM-FILE <file> command to provide random data.\n");
+            printf(" Specified file will be overwritten with new random data after use.\n");
+            return;
+        }
+
+        if ( ssl_rnd_file ) {
+            int rc = RAND_write_file(ssl_rnd_file);
+            debug(F111,"ssl_once_init","RAND_write_file()",rc);
+        }
+    }
+
+#ifdef NT
+    // Initialize additional OID types for use when saving certs to a file
+    OBJ_create("2.99999.3","SET.ex3","SET x509v3 extension 3");
+#endif /* NT */
+
+    /* make sure we have somewhere we can log errors to */
+    bio_err=BIO_new(BIO_s_mem());
+
+    debug(F100,"ssl_once_init() complete","",0);
+}
+
+int
+#ifdef CK_ANSIC
+ssl_tn_init(int mode)
+#else
+ssl_tn_init(mode) int mode;
+#endif /* CK_ANSIC */
+{
+#ifdef KRB5
+    extern char * k5_keytab;
+    extern char * krb5_d_srv;
+#endif /* KRB5 */
+    static int last_ssl_mode = -1;
+    SSL * ssl_conx=NULL, * tls_conx=NULL;
+
+    ssl_initialized = 0;
+
+    if ( !ck_ssleay_is_installed() )
+        return(0);
+
+    debug(F111,"ssl_tn_init","mode",mode);
+
+    if (ssl_debug_flag)
+        printf("SSL_DEBUG_FLAG on\r\n");
+
+    if (last_ssl_mode != mode) {
+        if (ssl_ctx) {
+            SSL_CTX_free(ssl_ctx);
+            ssl_ctx = NULL;
+        }
+        if (tls_ctx) {
+            SSL_CTX_free(tls_ctx);
+            tls_ctx = NULL;
+        }
+    }
+
+    if ( (last_ssl_mode != mode) || !ssl_ctx || !tls_ctx ) {
+        if ( mode == SSL_CLIENT ) {
+            ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
+            /* This can fail because we do not have RSA available */
+            if ( !ssl_ctx ) {
+                debug(F110,"ssl_tn_init","SSLv23_client_method failed",0);
+                ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
+            }
+            if ( !ssl_ctx ) {
+                debug(F110,"ssl_tn_init","SSLv3_client_method failed",0);
+                last_ssl_mode = -1;
+                return(0);
+            }
+#ifndef COMMENT
+            tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method());
+#else /* COMMENT */
+            tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
+            /* This can fail because we do not have RSA available */
+            if ( !tls_ctx ) {
+                debug(F110,"ssl_tn_init","SSLv23_client_method failed",0);
+                tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
+            }
+#endif /* COMMENT */
+            if ( !tls_ctx ) {
+                debug(F110,"ssl_tn_init","TLSv1_client_method failed",0);
+                last_ssl_mode = -1;
+                return(0);
+            }
+#ifdef USE_CERT_CB
+            SSL_CTX_set_client_cert_cb(ssl_ctx,ssl_client_cert_callback);
+            SSL_CTX_set_client_cert_cb(tls_ctx,ssl_client_cert_callback);
+#endif /* USE_CERT_CB */
+        } else if (mode == SSL_SERVER) {
+            /* We are a server */
+            ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_server_method());
+            /* This can fail because we do not have RSA available */
+            if ( !ssl_ctx ) {
+                debug(F110,"ssl_tn_init","SSLv23_server_method failed",0);
+                ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_server_method());
+            }
+            if ( !ssl_ctx ) {
+                debug(F110,"ssl_tn_init","SSLv3_server_method failed",0);
+                last_ssl_mode = -1;
+                return(0);
+            }
+#ifdef COMMENT
+            tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_server_method());
+#else /* COMMENT */
+            tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_server_method());
+            /* This can fail because we do not have RSA available */
+            if ( !tls_ctx ) {
+                debug(F110,"ssl_tn_init","SSLv23_server_method failed",0);
+                tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_server_method());
+            }
+#endif /* COMMENT */
+            if ( !tls_ctx ) {
+                debug(F110,"ssl_tn_init","TLSv1_server_method failed",0);
+                last_ssl_mode = -1;
+                return(0);
+            }
+        } else /* Unknown mode */
+            return(0);
+
+        if ( !inserver ) {
+            SSL_CTX_set_default_passwd_cb(ssl_ctx,
+                                   (pem_password_cb *)ssl_passwd_callback);
+            SSL_CTX_set_default_passwd_cb(tls_ctx,
+                                   (pem_password_cb *)ssl_passwd_callback);
+        }
+
+        /* for SSL switch on all the interoperability and bug
+         * workarounds so that we will communicate with people
+         * that cannot read poorly written specs :-)
+         * for TLS be sure to prevent use of SSLv2
+         */
+        SSL_CTX_set_options(ssl_ctx,SSL_OP_ALL|SSL_OP_NO_SSLv2);
+        SSL_CTX_set_options(tls_ctx,
+                 SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA);
+
+        SSL_CTX_set_info_callback(ssl_ctx,ssl_client_info_callback);
+        SSL_CTX_set_info_callback(tls_ctx,ssl_client_info_callback);
+
+#ifndef COMMENT
+        /* Set the proper caching mode */
+        if ( mode == SSL_SERVER ) {
+            SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_SERVER);
+            SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_SERVER);
+        } else {
+            SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_CLIENT);
+            SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_CLIENT);
+        }
+        SSL_CTX_set_session_id_context(ssl_ctx,(CHAR *)"1",1);
+        SSL_CTX_set_session_id_context(tls_ctx,(CHAR *)"2",1);
+#else /* COMMENT */
+        SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_OFF);
+        SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_OFF);
+#endif /* COMMENT */
+    }
+
+    /* The server uses defaults for the certificate files. */
+    /* The client does not.                                */
+    if (mode == SSL_SERVER) {
+        char cert_filepath[1024];
+        const char * defdir = NULL;
+        DH * dh = NULL;
+
+        defdir = getenv("SSL_CERT_DIR");
+        if ( !defdir ) {
+#ifdef OS2
+            defdir = exedir;
+#else /* OS2 */
+            defdir = X509_get_default_cert_dir();
+#endif /* OS2 */
+            debug(F110,"ssl_tn_init - setting default directory to",defdir,0);
+        }
+        if ( !defdir )
+            defdir = "";
+
+        if (!ssl_rsa_cert_file) {
+            /* we need to know the fullpath to the location of the
+            * certificate that we will be running with as we cannot
+            * be sure of the cwd when we are launched
+            */
+            sprintf(cert_filepath,"%s/%s",defdir,"telnetd-rsa.pem");
+            if (zchki(cert_filepath) > 0)
+                makestr(&ssl_rsa_cert_file,cert_filepath);
+        }
+        if (ssl_rsa_cert_file && !ssl_rsa_key_file) {
+            /* we need to know the fullpath to the location of the
+            * certificate that we will be running with as we cannot
+            * be sure of the cwd when we are launched
+            */
+            sprintf(cert_filepath,"%s/%s",defdir,"telnetd-rsa-key.pem");
+            if (zchki(cert_filepath) > 0)
+                makestr(&ssl_rsa_key_file,cert_filepath);
+        }
+        if (!ssl_dsa_cert_file) {
+            /* we need to know the fullpath to the location of the
+            * certificate that we will be running with as we cannot
+            * be sure of the cwd when we are launched
+            */
+            sprintf(cert_filepath,"%s/%s",defdir,"telnetd-dsa.pem");
+            if (zchki(cert_filepath) > 0)
+                makestr(&ssl_dsa_cert_file,cert_filepath);
+        }
+        if (ssl_dsa_cert_file && !ssl_dh_key_file) {
+            /* we need to know the fullpath to the location of the
+            * certificate that we will be running with as we cannot
+            * be sure of the cwd when we are launched
+            */
+            sprintf(cert_filepath,"%s/%s",defdir,"telnetd-dsa-key.pem");
+            if (zchki(cert_filepath) > 0)
+                makestr(&ssl_dh_key_file,cert_filepath);
+        }
+        if (!ssl_crl_dir) {
+            /* we need to know the fullpath to the location of the
+            * certificate that we will be running with as we cannot
+            * be sure of the cwd when we are launched
+            */
+            sprintf(cert_filepath,"%s/crl",defdir);
+            if (zchki(cert_filepath) > 0)
+                makestr(&ssl_crl_dir,cert_filepath);
+        }
+
+        if (ssl_only_flag && !tls_load_certs(ssl_ctx,ssl_con,1)) {
+            debug(F110,"ssl_tn_init","Unable to load SSL certs",0);
+            last_ssl_mode = -1;
+            return(0);
+        }
+        if (tls_only_flag && !tls_load_certs(tls_ctx,tls_con,1)) {
+            debug(F110,"ssl_tn_init","Unable to load TLS certs",0);
+            last_ssl_mode = -1;
+            return(0);
+        }
+
+        if ( (last_ssl_mode != mode) || !ssl_ctx || !tls_ctx ) {
+            /* we may require a temp 512 bit RSA key because of the
+             * wonderful way export things work ... if so we generate
+             * one now!
+             */
+
+            SSL_CTX_set_tmp_rsa_callback(ssl_ctx, tmp_rsa_cb);
+            SSL_CTX_set_tmp_dh_callback( ssl_ctx, tmp_dh_cb);
+            SSL_CTX_set_tmp_rsa_callback(tls_ctx, tmp_rsa_cb);
+            SSL_CTX_set_tmp_dh_callback( tls_ctx, tmp_dh_cb);
+
+            dh = tmp_dh_cb(NULL,0,512);
+            SSL_CTX_set_tmp_dh(ssl_ctx,dh);
+            SSL_CTX_set_tmp_dh(tls_ctx,dh);
+
+            /* The following code is only called if we are using a
+             * certificate with an RSA public key and where the
+             * certificate has a key length less than 512 bits or is
+             * marked for signing only.  This is so we can support
+             * the greatest legal privacy level with exportable clients.
+             */
+
+            if (SSL_CTX_need_tmp_RSA(ssl_ctx) ||
+                 SSL_CTX_need_tmp_RSA(tls_ctx))
+            {
+                RSA *rsa;
+
+                if ( ssl_debug_flag )
+                    printf("Generating temp (512 bit) RSA key ...\r\n");
+                rsa=RSA_generate_key(512,RSA_F4,NULL,NULL);
+                if ( ssl_debug_flag )
+                    printf("Generation of temp (512 bit) RSA key done\r\n");
+
+                if (SSL_CTX_need_tmp_RSA(ssl_ctx)) {
+                    if (!SSL_CTX_set_tmp_rsa(ssl_ctx,rsa)) {
+                        if ( ssl_debug_flag )
+                            printf(
+  "Failed to assign generated temp RSA key to SSL!\r\n");
+                    }
+                }
+                if (SSL_CTX_need_tmp_RSA(tls_ctx)) {
+                    if (!SSL_CTX_set_tmp_rsa(tls_ctx,rsa)) {
+                        if ( ssl_debug_flag )
+                            printf(
+  "Failed to assign generated temp RSA key to TLS!\r\n");
+                    }
+                }
+                RSA_free(rsa);
+                if ( ssl_debug_flag )
+                    printf("Assigned temp (512 bit) RSA key\r\n");
+            }
+        }
+    }
+
+    /* make sure we will find certificates in the standard
+     * location ... otherwise we don't look anywhere for
+     * these things which is going to make client certificate
+     * exchange rather useless :-)
+     * In OS2, default values for ssl_verify_file and ssl_verify_path.
+     */
+
+#ifdef OS2
+#ifdef NT
+    {
+        /* The defaults in the SSL crypto library are not appropriate for OS/2 */
+        char path[CKMAXPATH];
+
+        ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
+        if (isdir(path) && 
+            SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1)  {
+            debug(F110,"ssl_tn_init certificate verify dir",path,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification Directory: %s\r\n",path);
+            SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
+        }
+        ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/certs",NULL,NULL);
+        if (isdir(path) &&
+            SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1)  {
+            debug(F110,"ssl_tn_init certificate verify dir",path,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification Directory: %s\r\n",path);
+            SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
+        }
+        ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs",NULL,NULL);
+        if (isdir(path) &&
+            SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1)  {
+            debug(F110,"ssl_tn_init certificate verify dir",path,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification Directory: %s\r\n",path);
+            SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
+        }
+        ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
+        if (zchki(path) > 0 && 
+            SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
+            debug(F110,"ssl_tn_init certificate verify file",path,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification File: %s\r\n",path);
+            SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
+        }
+        ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_certs.pem",NULL,NULL);
+        if (zchki(path) > 0 && 
+            SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
+            debug(F110,"ssl_tn_init certificate verify file",path,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification File: %s\r\n",path);
+            SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
+        }
+        ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_certs.pem",NULL,NULL);
+        if (zchki(path) > 0 && 
+            SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
+            debug(F110,"ssl_tn_init certificate verify file",path,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification File: %s\r\n",path);
+            SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
+        }
+    }
+#else /* NT */
+    {
+        /* The defaults in the SSL crypto library are not appropriate for OS/2 */
+        char path[CKMAXPATH];
+
+        ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
+        if (isdir(path) && 
+            SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1)  {
+            debug(F110,"ssl_tn_init certificate verify dir",path,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification Directory: %s\r\n",path);
+            SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
+        }
+        ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
+        if (zchki(path) > 0 && 
+            SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
+            debug(F110,"ssl_tn_init certificate verify file",path,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification File: %s\r\n",path);
+            SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
+        }
+    }
+#endif /* NT */
+#else /* OS2 */
+    SSL_CTX_set_default_verify_paths(ssl_ctx);
+    SSL_CTX_set_default_verify_paths(tls_ctx);
+#endif /* OS2 */
+
+    if (ssl_verify_file) {
+        if (zchki(ssl_verify_file) > 0 && 
+            SSL_CTX_load_verify_locations(tls_ctx,ssl_verify_file,NULL) == 1) {
+            debug(F110,"ssl_tn_init certificate verify file",ssl_verify_file,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification File: %s\r\n",ssl_verify_file);
+            SSL_CTX_load_verify_locations(ssl_ctx,ssl_verify_file,NULL);
+        }
+    }
+    if (ssl_verify_dir && isdir(ssl_verify_dir)) {
+        if (SSL_CTX_load_verify_locations(tls_ctx,NULL,ssl_verify_dir) == 1)  {
+            debug(F110,"ssl_tn_init certificate verify dir",ssl_verify_dir,0);
+            if (ssl_debug_flag)
+                printf("  Certificate Verification Directory: %s\r\n",ssl_verify_dir);
+            SSL_CTX_load_verify_locations(ssl_ctx,NULL,ssl_verify_dir);
+        }
+    }
+    if (mode == SSL_SERVER) {
+        SSL_CTX_set_verify(ssl_ctx,
+                     ssl_verify_flag?ssl_verify_flag|SSL_VERIFY_CLIENT_ONCE:0,
+                           ssl_server_verify_callback);
+        SSL_CTX_set_verify(tls_ctx,
+                     ssl_verify_flag?ssl_verify_flag|SSL_VERIFY_CLIENT_ONCE:0,
+                           ssl_server_verify_callback);
+    } else {
+        SSL_CTX_set_verify(ssl_ctx,ssl_verify_flag,
+                           ssl_client_verify_callback);
+        SSL_CTX_set_verify(tls_ctx,ssl_verify_flag,
+                           ssl_client_verify_callback);
+    }
+
+    /* Free the existing CRL Store */
+    if (crl_store) {
+        X509_STORE_free(crl_store);
+        crl_store = NULL;
+    }
+
+    /* set up the new CRL Store */
+    crl_store = X509_STORE_new();
+    if (crl_store) {
+#ifdef OS2
+        char path[CKMAXPATH];
+
+        ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
+        if (isdir(path) &&
+            X509_STORE_load_locations(crl_store,NULL,path) == 1) {
+            debug(F110,"ssl_tn_init crl dir",path,0);
+            if (ssl_debug_flag)
+                printf("  CRL Directory: %s\r\n",path);
+        }
+#ifdef NT
+        ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/crls",NULL,NULL);
+        if (isdir(path) && 
+            X509_STORE_load_locations(crl_store,NULL,path) == 1) {
+            debug(F110,"ssl_tn_init crl dir",path,0);
+            if (ssl_debug_flag)
+                printf("  CRL Directory: %s\r\n",path);
+        }
+        ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/crls",NULL,NULL);
+        if (isdir(path) && 
+            X509_STORE_load_locations(crl_store,NULL,path) == 1) {
+            debug(F110,"ssl_tn_init crl dir",path,0);
+            if (ssl_debug_flag)
+                printf("  CRL Directory: %s\r\n",path);
+        }
+#endif /* NT */
+        
+        ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
+        if (zchki(path) > 0 && 
+            X509_STORE_load_locations(crl_store,path,NULL) == 1) {
+            debug(F110,"ssl_tn_init crl file",path,0);
+            if (ssl_debug_flag)
+                printf("  CRL File: %s\r\n",path);
+        }
+#ifdef NT
+        ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_crls.pem",NULL,NULL);
+        if (zchki(path) > 0 && 
+            X509_STORE_load_locations(crl_store,path,NULL) == 1) {
+            debug(F110,"ssl_tn_init crl file",path,0);
+            if (ssl_debug_flag)
+                printf("  CRL File: %s\r\n",path);
+        }
+        ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_crls.pem",NULL,NULL);
+        if (zchki(path) > 0 && 
+            X509_STORE_load_locations(crl_store,path,NULL) == 1) {
+            debug(F110,"ssl_tn_init crl file",path,0);
+            if (ssl_debug_flag)
+                printf("  CRL File: %s\r\n",path);
+        }
+#endif /* NT */
+#endif /* OS2 */
+
+        if (ssl_crl_file || ssl_crl_dir) {
+            if (ssl_crl_file && zchki(ssl_crl_file) > 0 && 
+                X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 1) {
+                debug(F110,"ssl_tn_init crl file",ssl_crl_file,0);
+                if (ssl_debug_flag)
+                    printf("  CRL File: %s\r\n",ssl_crl_file);
+            }
+            if (ssl_crl_dir && isdir(ssl_crl_dir) &&
+                X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 1) {
+                debug(F110,"ssl_tn_init crl dir",ssl_crl_dir,0);
+                if (ssl_debug_flag)
+                    printf("  CRL Directory: %s\r\n",ssl_crl_dir);
+            }
+        } 
+#ifndef OS2
+        else {
+            X509_STORE_set_default_paths(crl_store);
+        }
+#endif /* OS2 */
+    }
+
+#ifndef COMMENT
+    ssl_conx = ssl_con;
+    ssl_con=(SSL *)SSL_new(ssl_ctx);
+    if ( !ssl_con ) {
+        debug(F110,"ssl_tn_init","SSL_new(ssl_con) failed",0);
+        last_ssl_mode = -1;
+        ssl_con = ssl_conx;
+        return(0);
+    }
+    if (ssl_conx) {
+        if ( mode == SSL_CLIENT ) {
+            SSL_set_session(ssl_con, SSL_get_session(ssl_conx));
+        }
+#ifdef SSL_KRB5
+		if (ssl_conx->kssl_ctx) {
+			kssl_ctx_free(ssl_conx->kssl_ctx);
+			ssl_conx->kssl_ctx = NULL;
+		}
+#endif /* SSL_KRB5 */
+        SSL_free(ssl_conx);
+        ssl_conx = NULL;
+    }
+    tls_conx = tls_con;
+    tls_con=(SSL *)SSL_new(tls_ctx);
+    if ( !tls_con ) {
+        debug(F110,"ssl_tn_init","SSL_new(tls_con) failed",0);
+        last_ssl_mode = -1;
+        tls_con = tls_conx;
+        return(0);
+    }
+    if (tls_conx) {
+        if ( mode == SSL_CLIENT )
+            SSL_set_session(tls_con, SSL_get_session(tls_conx));
+#ifdef SSL_KRB5
+		if (tls_conx->kssl_ctx) {
+			kssl_ctx_free(tls_conx->kssl_ctx);
+			tls_conx->kssl_ctx = NULL;
+		}
+#endif /* SSL_KRB5 */
+        SSL_free(tls_conx);
+        tls_conx = NULL;
+    }
+#else /* COMMENT */
+    /* I don't know why this does not work to reuse the connection. */
+    if ( ssl_con ) {
+        SSL_clear(ssl_con);
+        SSL_set_session(ssl_con,NULL);
+        SSL_set_accept_state(ssl_con) ;
+    } else {
+        ssl_con=(SSL *)SSL_new(ssl_ctx);
+        if (!ssl_con) {
+            debug(F110,"ssl_tn_init","SSL_new(ssl_ctx) failed",0);
+            last_ssl_mode = -1;
+            ssl_con = ssl_conx;
+            return(0);
+        }
+    }
+
+    if ( tls_con ) {
+        SSL_clear(tls_con);
+        SSL_set_session(tls_con,NULL);
+        SSL_set_accept_state(tls_con) ;
+    } else {
+        tls_con=(SSL *)SSL_new(tls_ctx);
+        if ( !tls_con ) {
+            debug(F110,"ssl_tn_init","SSL_new(tls_ctx) failed",0);
+            last_ssl_mode = -1;
+            tls_con = tls_conx;
+            return(0);
+        }
+    }
+#endif /* COMMENT */
+
+#ifdef SSL_KRB5
+#ifndef KRB5_SERVICE_NAME
+#define KRB5_SERVICE_NAME    "host"
+#endif
+
+    if (ssl_con->kssl_ctx == NULL)
+        ssl_con->kssl_ctx = kssl_ctx_new();
+    if (tls_con->kssl_ctx == NULL)
+    tls_con->kssl_ctx = kssl_ctx_new();
+    if (mode == SSL_SERVER) {
+        if (ssl_con->kssl_ctx != NULL)
+            kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_KEYTAB, k5_keytab);
+        if (tls_con->kssl_ctx != NULL)
+            kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_KEYTAB, k5_keytab);
+    } else {
+        if (ssl_con->kssl_ctx != NULL)
+            kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_SERVER, szHostName);
+        if (tls_con->kssl_ctx != NULL)
+            kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_SERVER, szHostName);
+    }
+    kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_SERVICE,
+                        krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME);
+    kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_SERVICE,
+                        krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME);
+#endif /* SSL_KRB5 */
+
+    if (ssl_cipher_list) {
+        SSL_set_cipher_list(ssl_con,ssl_cipher_list);
+        SSL_set_cipher_list(tls_con,ssl_cipher_list);
+    } else {
+        char * p;
+        if (p = getenv("SSL_CIPHER")) {
+            SSL_set_cipher_list(ssl_con,p);
+            SSL_set_cipher_list(tls_con,p);
+        } else {
+            SSL_set_cipher_list(ssl_con,DEFAULT_CIPHER_LIST);
+            SSL_set_cipher_list(tls_con,DEFAULT_CIPHER_LIST);
+        }
+    }
+
+    ssl_verify_depth = -1;
+
+    if ( ssl_debug_flag )
+        printf("SSL/TLS init done!\r\n");
+
+    ssl_initialized = 1;
+    last_ssl_mode = mode;
+    debug(F110,"ssl_tn_init","done",0);
+    return(1);
+}
+
+#ifndef NOHTTP
+int
+#ifdef CK_ANSIC
+ssl_http_init(char * hostname)
+#else
+ssl_http_init(hostname) char * hostname;
+#endif /* CK_ANSIC */
+{
+#ifdef KRB5
+    extern char * k5_keytab;
+    extern char * krb5_d_srv;
+#endif /* KRB5 */
+    SSL * tls_conx=NULL;
+
+    ssl_http_initialized = 0;
+
+    if ( !ck_ssleay_is_installed() )
+        return(0);
+    debug(F110,"ssl_http_init",hostname,0);
+
+    if (ssl_debug_flag)
+        printf("SSL_DEBUG_FLAG on\r\n");
+
+    if (!tls_http_ctx ) {
+#ifdef COMMENT
+        /* too many web servers still do not support TLSv1 */
+        tls_http_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method());
+#else /* COMMENT */
+        tls_http_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
+        /* This can fail because we do not have RSA available */
+        if ( !tls_http_ctx ) {
+            debug(F110,"ssl_http_init","SSLv23_client_method failed",0);
+            tls_http_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
+        }
+#endif /* COMMENT */
+        if ( !tls_http_ctx ) {
+            debug(F110,"ssl_http_init","TLSv1_client_method failed",0);
+            return(0);
+        }
+#ifdef USE_CERT_CB
+        SSL_CTX_set_client_cert_cb(tls_http_ctx,ssl_client_cert_callback);
+#endif /* USE_CERT_CB */
+    }
+
+    SSL_CTX_set_default_passwd_cb(tls_http_ctx,
+                                  (pem_password_cb *)ssl_passwd_callback);
+
+    /* for SSL switch on all the interoperability and bug
+     * workarounds so that we will communicate with people
+     * that cannot read poorly written specs :-)
+     * for TLS be sure to prevent use of SSLv2
+     */
+    SSL_CTX_set_options(tls_http_ctx,
+            SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA);
+
+    SSL_CTX_set_info_callback(tls_http_ctx,ssl_client_info_callback);
+
+#ifndef COMMENT
+    SSL_CTX_set_session_cache_mode(tls_http_ctx,SSL_SESS_CACHE_CLIENT);
+    SSL_CTX_set_session_id_context(tls_http_ctx,(CHAR *)"3",1);
+#else /* COMMENT */
+    SSL_CTX_set_session_cache_mode(tls_http_ctx,SSL_SESS_CACHE_OFF);
+#endif /* COMMENT */
+
+    /* make sure we will find certificates in the standard
+     * location ... otherwise we don't look anywhere for
+     * these things which is going to make client certificate
+     * exchange rather useless :-)
+     */
+
+#ifdef OS2
+#ifdef NT
+    {
+        /* The defaults in the SSL crypto library are not appropriate for OS/2 */
+        char path[CKMAXPATH];
+
+        ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
+        if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0)  {
+            debug(F110,"ssl_http_init unable to load path",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load verify-dir: %s\r\n",path);
+        }
+
+        ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/certs",NULL,NULL);
+        if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0)  {
+            debug(F110,"ssl_http_init unable to load path",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load verify-dir: %s\r\n",path);
+        }
+
+        ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs",NULL,NULL);
+        if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0)  {
+            debug(F110,"ssl_http_init unable to load path",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load verify-dir: %s\r\n",path);
+        }
+
+        ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
+        if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
+            debug(F110,"ssl_http_init unable to load path",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load verify-file: %s\r\n",path);
+        }
+
+        ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_certs.pem",NULL,NULL);
+        if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
+            debug(F110,"ssl_http_init unable to load path",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load verify-file: %s\r\n",path);
+        }
+
+        ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_certs.pem",NULL,NULL);
+        if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
+            debug(F110,"ssl_http_init unable to load path",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load verify-file: %s\r\n",path);
+        }
+    }
+#else /* NT */
+    {
+        /* The defaults in the SSL crypto library are not appropriate for OS/2 */
+        char path[CKMAXPATH];
+
+        ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
+        if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0)  {
+            debug(F110,"ssl_http_init unable to load path",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load verify-dir: %s\r\n",path);
+        }
+        ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
+        if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
+            debug(F110,"ssl_http_init unable to load path",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load verify-file: %s\r\n",path);
+        }
+    }
+#endif /* NT */
+#else /* OS2 */
+    SSL_CTX_set_default_verify_paths(tls_http_ctx);
+#endif /* OS2 */
+
+    if (ssl_verify_file &&
+        SSL_CTX_load_verify_locations(tls_http_ctx,ssl_verify_file,NULL) == 0)  {
+        debug(F110,"ssl_http_init unable to load ssl_verify_file",ssl_verify_file,0);
+        if (ssl_debug_flag)
+            printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
+    }
+    if (ssl_verify_dir &&
+        SSL_CTX_load_verify_locations(tls_http_ctx,NULL,ssl_verify_dir) == 0)  {
+        debug(F110,"ssl_http_init unable to load ssl_verify_dir",ssl_verify_dir,0);
+        if (ssl_debug_flag)
+            printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
+    }
+
+    SSL_CTX_set_verify(tls_http_ctx,ssl_verify_flag,
+                           ssl_client_verify_callback);
+
+    /* Free the existing CRL Store */
+    if (crl_store) {
+        X509_STORE_free(crl_store);
+        crl_store = NULL;
+    }
+
+    /* set up the new CRL Store */
+    crl_store = X509_STORE_new();
+    if (crl_store) {
+#ifdef OS2
+        char path[CKMAXPATH];
+
+        ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
+        if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
+            debug(F110,"ssl_http_init unable to load dir",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load crl-dir: %s\r\n",path);
+        }
+#ifdef NT
+        ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/crls",NULL,NULL);
+        if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
+            debug(F110,"ssl_http_init unable to load dir",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load crl-dir: %s\r\n",path);
+        }
+        ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/crls",NULL,NULL);
+        if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
+            debug(F110,"ssl_http_init unable to load dir",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load crl-dir: %s\r\n",path);
+        }
+#endif /* NT */
+        
+        ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
+        if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
+            debug(F110,"ssl_http_init unable to load file",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load crl-file: %s\r\n",path);
+        }
+#ifdef NT
+        ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_crls.pem",NULL,NULL);
+        if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
+            debug(F110,"ssl_http_init unable to load file",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load crl-file: %s\r\n",path);
+        }
+        ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_crls.pem",NULL,NULL);
+        if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
+            debug(F110,"ssl_http_init unable to load file",path,0);
+            if (ssl_debug_flag)
+                printf("?Unable to load crl-file: %s\r\n",path);
+        }
+#endif /* NT */
+#endif /* OS2 */
+
+        if (ssl_crl_file || ssl_crl_dir) {
+            if (ssl_crl_file &&
+                X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
+                debug(F110,"ssl_http_init unable to load ssl_crl_file",ssl_crl_file,0);
+                if (ssl_debug_flag)
+                    printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
+            }
+            if (ssl_crl_dir &&
+                X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
+                debug(F110,"ssl_http_init unable to load ssl_crl_dir",ssl_crl_dir,0);
+                if (ssl_debug_flag)
+                    printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
+            }
+        } else {
+            X509_STORE_set_default_paths(crl_store);
+        }
+    }
+
+#ifndef COMMENT
+    tls_conx = tls_http_con;
+    tls_http_con=(SSL *)SSL_new(tls_http_ctx);
+    if ( !tls_http_con ) {
+        debug(F110,"ssl_http_init","SSL_new(tls_http_con) failed",0);
+        tls_http_con = tls_conx;
+        return(0);
+    }
+    if (tls_conx) {
+        SSL_set_session(tls_http_con, SSL_get_session(tls_conx));
+#ifdef SSL_KRB5
+		if (tls_conx->kssl_ctx) {
+			kssl_ctx_free(tls_conx->kssl_ctx);
+			tls_conx->kssl_ctx = NULL;
+		}
+#endif /* SSL_KRB5 */
+        SSL_free(tls_conx);
+        tls_conx = NULL;
+    }
+#else /* COMMENT */
+    /* I don't know why this does not work to reuse the connection. */
+    if ( tls_http_con ) {
+        SSL_clear(tls_http_con);
+        SSL_set_session(tls_http_con,NULL);
+        SSL_set_accept_state(tls_http_con) ;
+    } else {
+        tls_http_con=(SSL *)SSL_new(tls_http_ctx);
+        if ( !tls_http_con ) {
+            debug(F110,"ssl_http_init","SSL_new(tls_http_ctx) failed",0);
+            tls_http_con = tls_conx;
+            return(0);
+        }
+    }
+#endif /* COMMENT */
+
+#ifdef SSL_KRB5
+#ifndef KRB5_SERVICE_NAME
+#define KRB5_SERVICE_NAME    "host"
+#endif
+
+    if (tls_http_con->kssl_ctx == NULL)
+    tls_http_con->kssl_ctx = kssl_ctx_new();
+    if (tls_http_con->kssl_ctx != NULL)
+        kssl_ctx_setstring(tls_http_con->kssl_ctx, KSSL_SERVER, hostname);
+
+    kssl_ctx_setstring(tls_http_con->kssl_ctx, KSSL_SERVICE,
+                        krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME);
+#endif /* SSL_KRB5 */
+
+    if (ssl_cipher_list)
+        SSL_set_cipher_list(tls_http_con,ssl_cipher_list);
+    else {
+        char * p;
+        if (p = getenv("SSL_CIPHER")) {
+            SSL_set_cipher_list(tls_http_con,p);
+        } else {
+            SSL_set_cipher_list(tls_http_con,DEFAULT_CIPHER_LIST);
+        }
+    }
+
+    ssl_verify_depth = -1;
+
+    if ( ssl_debug_flag )
+        printf("SSL/TLS init done!\r\n");
+
+    ssl_http_initialized = 1;
+    return(1);
+}
+#endif /* NOHTTP */
+
+char *
+ssl_get_dNSName(ssl) SSL * ssl;
+{
+    static char *dns = NULL;
+    X509 *server_cert = NULL;
+    int i;
+    X509_EXTENSION *ext = NULL;
+    STACK_OF(GENERAL_NAME) *ialt = NULL;
+    GENERAL_NAME *gen = NULL;
+
+    if ( dns ) {
+        free(dns);
+        dns = NULL;
+    }
+
+    if (server_cert = SSL_get_peer_certificate(ssl)) {
+        if ((i = X509_get_ext_by_NID(server_cert, NID_subject_alt_name, -1))<0)
+            return NULL;
+        if (!(ext = X509_get_ext(server_cert, i)))
+            return NULL;
+        X509V3_add_standard_extensions();
+        if (!(ialt = X509V3_EXT_d2i(ext)))
+            return NULL;
+        for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) {
+            gen = sk_GENERAL_NAME_value(ialt, i);
+            if (gen->type == GEN_DNS) {
+                if(!gen->d.ia5 || !gen->d.ia5->length)
+                    break;
+                dns = malloc(gen->d.ia5->length + 1);
+                if (dns) {
+                    memcpy(dns, gen->d.ia5->data, gen->d.ia5->length);
+                    dns[gen->d.ia5->length] = 0;
+                }
+                break;
+            }
+        }
+        X509V3_EXT_cleanup();
+    }
+cleanup:
+    if (ialt)           sk_GENERAL_NAME_free(ialt);
+    if (server_cert)    X509_free(server_cert);
+    return dns;
+}
+
+char *
+ssl_get_commonName(ssl) SSL * ssl;
+{
+    static char name[256];
+    int err;
+    X509 *server_cert;
+
+    if (server_cert = SSL_get_peer_certificate(ssl)) {
+        err = X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert),
+                NID_commonName, name, sizeof(name));
+        X509_free(server_cert);
+    }
+    if (err > 0)
+        return name;
+    else
+        return NULL;
+}
+
+char *
+ssl_get_issuer_name(ssl) SSL * ssl;
+{
+    static char name[256];
+    X509 *server_cert;
+
+    name[0] = '\0';
+    if (server_cert = SSL_get_peer_certificate(ssl)) {
+        X509_NAME_oneline(X509_get_issuer_name(server_cert),name,sizeof(name));
+        X509_free(server_cert);
+        return name;
+    }
+    else {
+#ifdef COMMENT
+      fprintf(stderr, "Warning: No certificate from server!\r\n");
+#endif /* COMMENT */
+        return NULL;
+    }
+}
+
+char *
+ssl_get_subject_name(ssl) SSL * ssl;
+{
+    static char name[256];
+    X509 *server_cert;
+
+    name[0] = '\0';
+    if (server_cert = SSL_get_peer_certificate(ssl)) {
+       X509_NAME_oneline(X509_get_subject_name(server_cert),name,sizeof(name));
+       X509_free(server_cert);
+       return name;
+    }
+    else
+        return NULL;
+}
+
+#ifdef COMMENT
+#ifdef CK_SSL
+            && !(ck_ssleay_is_installed() &&
+               (tls_active_flag || ssl_active_flag) &&
+               ssl_anonymous_cipher(tls_active_flag?tls_con:ssl_con))
+#endif /* CK_SSL */
+
+int
+ssl_anonymous_cipher(ssl) SSL * ssl;
+{
+    X509 * cert;
+
+    if (sstelnet)
+        cert = SSL_get_certificate(ssl);
+    else
+        cert = SSL_get_peer_certificate(ssl);
+
+    if ( cert ) {
+        X509_free(cert);
+        return 0;
+    }
+    return 1;
+}
+#endif /* COMMENT */
+
+/*
+  This one is (very much!) based on work by
+  Ralf S. Engelschall <rse@engelschall.com>.
+  Comments by Ralf.
+*/
+int
+ssl_verify_crl(int ok, X509_STORE_CTX *ctx)
+{
+    X509_OBJECT obj;
+    X509_NAME *subject = NULL;
+    X509_NAME *issuer = NULL;
+    X509 *xs = NULL;
+    X509_CRL *crl = NULL;
+    X509_REVOKED *revoked = NULL;
+    X509_STORE_CTX * store_ctx = NULL;
+    long serial;
+    BIO *bio = NULL;
+    int i, n, rc;
+    char *cp;
+    char *cp2;
+
+    /*
+     * Unless a revocation store for CRLs was created we
+     * cannot do any CRL-based verification, of course.
+     */
+    if (!crl_store)
+        return ok;
+
+    store_ctx = X509_STORE_CTX_new();
+    if ( !store_ctx )
+        return(ok);
+
+    /*
+     * Determine certificate ingredients in advance
+     */
+    xs      = X509_STORE_CTX_get_current_cert(ctx);
+    subject = X509_get_subject_name(xs);
+    issuer  = X509_get_issuer_name(xs);
+
+    /*
+     * OpenSSL provides the general mechanism to deal with CRLs but does not
+     * use them automatically when verifying certificates, so we do it
+     * explicitly here. We will check the CRL for the currently checked
+     * certificate, if there is such a CRL in the store.
+     *
+     * We come through this procedure for each certificate in the certificate
+     * chain, starting with the root-CA's certificate. At each step we've to
+     * both verify the signature on the CRL (to make sure it's a valid CRL)
+     * and it's revocation list (to make sure the current certificate isn't
+     * revoked).  But because to check the signature on the CRL we need the
+     * public key of the issuing CA certificate (which was already processed
+     * one round before), we've a little problem. But we can both solve it and
+     * at the same time optimize the processing by using the following
+     * verification scheme (idea and code snippets borrowed from the GLOBUS
+     * project):
+     *
+     * 1. We'll check the signature of a CRL in each step when we find a CRL
+     *    through the _subject_ name of the current certificate. This CRL
+     *    itself will be needed the first time in the next round, of course.
+     *    But we do the signature processing one round before this where the
+     *    public key of the CA is available.
+     *
+     * 2. We'll check the revocation list of a CRL in each step when
+     *    we find a CRL through the _issuer_ name of the current certificate.
+     *    This CRLs signature was then already verified one round before.
+     *
+     * This verification scheme allows a CA to revoke its own certificate as
+     * well, of course.
+     */
+
+    /*
+     * Try to retrieve a CRL corresponding to the _subject_ of
+     * the current certificate in order to verify it's integrity.
+     */
+    memset((char *)&obj, 0, sizeof(obj));
+    X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL);
+    rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, subject, &obj);
+    X509_STORE_CTX_cleanup(store_ctx);
+    crl = obj.data.crl;
+    if (rc > 0 && crl != NULL) {
+        /*
+         * Verify the signature on this CRL
+         */
+        if (X509_CRL_verify(crl, X509_get_pubkey(xs)) <= 0) {
+            fprintf(stderr, "Invalid signature on CRL!\n");
+            X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
+            X509_OBJECT_free_contents(&obj);
+            X509_STORE_CTX_free(store_ctx);
+            return 0;
+        }
+
+        /*
+         * Check date of CRL to make sure it's not expired
+         */
+        i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
+        if (i == 0) {
+            fprintf(stderr, "Found CRL has invalid nextUpdate field.\n");
+            X509_STORE_CTX_set_error(ctx,
+                                    X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+            X509_OBJECT_free_contents(&obj);
+            X509_STORE_CTX_free(store_ctx);
+            return 0;
+        }
+        if (i < 0) {
+            fprintf(stderr,
+"Found CRL is expired - revoking all certificates until you get updated CRL.\n"
+                    );
+            X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED);
+            X509_OBJECT_free_contents(&obj);
+            X509_STORE_CTX_free(store_ctx);
+            return 0;
+        }
+        X509_OBJECT_free_contents(&obj);
+    }
+
+    /*
+     * Try to retrieve a CRL corresponding to the _issuer_ of
+     * the current certificate in order to check for revocation.
+     */
+    memset((char *)&obj, 0, sizeof(obj));
+    X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL);
+    rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, issuer, &obj);
+    X509_STORE_CTX_free(store_ctx);		/* calls X509_STORE_CTX_cleanup() */
+    crl = obj.data.crl;
+    if (rc > 0 && crl != NULL) {
+        /*
+         * Check if the current certificate is revoked by this CRL
+         */
+        n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
+        for (i = 0; i < n; i++) {
+            revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
+            if (ASN1_INTEGER_cmp(revoked->serialNumber,
+                                 X509_get_serialNumber(xs)) == 0) {
+
+                serial = ASN1_INTEGER_get(revoked->serialNumber);
+                cp = X509_NAME_oneline(issuer, NULL, 0);
+                free(cp);
+
+                X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
+                X509_OBJECT_free_contents(&obj);
+                return 0;
+            }
+        }
+        X509_OBJECT_free_contents(&obj);
+    }
+    return ok;
+}
+
+char *
+tls_userid_from_client_cert(ssl) SSL * ssl;
+{
+    static char cn[256];
+    static char *r = cn;
+    int err;
+    X509 *client_cert;
+
+    if (client_cert = SSL_get_peer_certificate(ssl)) {
+        /* call the custom function */
+        err = X509_to_user(client_cert, cn, sizeof(cn));
+        X509_free(client_cert);
+        if (err)
+            return r = NULL;
+        else
+            return r;
+    }
+    else
+        return r = NULL;
+}
+
+unsigned char **
+tls_get_SAN_objs(SSL * ssl, int type)
+/* returns NULL or an array of malloc'ed objects of type `type' from the server's
+ * subjectAltName, remember to free() them all!
+ */
+{
+#define NUM_SAN_OBJS 64
+    static unsigned char *objs[NUM_SAN_OBJS];
+    unsigned char **rv = NULL;
+    X509 *server_cert = NULL;
+    int i, j;
+    X509_EXTENSION *ext = NULL;
+    STACK_OF(GENERAL_NAME) *ialt = NULL;
+    GENERAL_NAME *gen = NULL;
+
+    memset(objs, 0, sizeof(objs));
+    if (server_cert = SSL_get_peer_certificate(ssl)) {
+        if ((i = X509_get_ext_by_NID(server_cert, NID_subject_alt_name, -1)) < 0)
+            goto eject;
+        if (!(ext = X509_get_ext(server_cert, i)))
+            goto eject;
+        X509V3_add_standard_extensions();
+        if (!(ialt = X509V3_EXT_d2i(ext)))
+            goto eject;
+        rv = objs;
+        for (i = 0, j = 0; i < sk_GENERAL_NAME_num(ialt) && j < NUM_SAN_OBJS - 2; i++) {
+            gen = sk_GENERAL_NAME_value(ialt, i);
+            /* The use of V_ASN1_CONTEXT_SPECIFIC is because OpenSSL 0.9.6 defined its
+             * types | V_ASN1_CONTEXT_SPECIFIC.  0.9.7 does not.  In case, we are built
+             * with one and linked to the other we use this hack.
+             */
+            if ((gen->type | V_ASN1_CONTEXT_SPECIFIC) == (type | V_ASN1_CONTEXT_SPECIFIC)) {
+                if(!gen->d.ia5 || !gen->d.ia5->length)
+                    break;
+                objs[j] = malloc(gen->d.ia5->length + 1);
+                if (objs[j]) {
+                    memcpy(objs[j], gen->d.ia5->data, gen->d.ia5->length);
+                    objs[j][gen->d.ia5->length] = 0;
+                    j++;
+                }
+            }
+        }
+        X509V3_EXT_cleanup();
+    }
+eject:
+    if (ialt)           sk_GENERAL_NAME_free(ialt);
+    if (server_cert)    X509_free(server_cert);
+    return rv;
+}
+
+
+static int
+dNSName_cmp(const char *host, const char *dNSName)
+{
+    int c1 = 0, c2 = 0, num_comp, rv = -1;
+    char *p, *p1, *p2, *host_copy=NULL, *dNSName_copy=NULL;
+
+    /* first we count the number of domain name components in both parameters.
+     * they should be equal many, or it's not a match
+     */
+    p = (char *) host;
+    while (p = strstr(p, ".")) {
+        c1++;
+        p++;
+    }
+    p = (char *) dNSName;
+    while (p = strstr(p, ".")) {
+        c2++;
+        p++;
+    }
+    if (c1 != c2)
+        return -1;
+    num_comp = c1;
+
+    makestr(&host_copy,host);
+    makestr(&dNSName_copy,dNSName);
+    if (host_copy == NULL || dNSName_copy == NULL)
+        goto eject;
+    /* make substrings by replacing '.' with '\0' */
+    p = dNSName_copy;
+    while (p = strstr(p, ".")) {
+        *p = '\0';
+        p++;
+    }
+    p = host_copy;
+    while (p = strstr(p, ".")) {
+        *p = '\0';
+        p++;
+    }
+
+    /* compare each component */
+    p1 = host_copy;
+    p2 = dNSName_copy;
+    for (; num_comp; num_comp--) {
+        if (!ckmatch(p2, p1,0,1))
+            /* failed match */
+            goto eject;
+        p1 += strlen(p1) + 1;
+        p2 += strlen(p2) + 1;
+    }
+    /* match ok */
+    rv = 0;
+
+  eject:
+    if (dNSName_copy)   free(dNSName_copy);
+    if (host_copy)      free(host_copy);
+    return rv;
+}
+
+
+
+static int
+show_hostname_warning(char *s1, char *s2)
+{
+    char prefix[1024];
+    int ok = 1;
+    ckmakxmsg(prefix,1024,
+              "Warning: Hostname (\"", s1, 
+              "\") does not match server's certificate (\"", s2, "\")",
+              NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+    if (ssl_verify_flag)
+        ok = uq_ok(prefix,
+                    "Continue? (Y/N) ",
+                    3, NULL, 0);
+    else if (ssl_verbose_flag)
+        printf(prefix);
+    return(ok);
+}
+
+#ifndef HPUX10
+#ifndef HPUX1100
+#ifndef SCO_OSR505
+#ifndef OpenBSD
+#ifndef FREEBSD4
+#ifndef LINUX
+#ifndef AIX41
+#ifndef UW7
+#ifndef SOLARIS9
+#ifndef SOLARIS8
+#ifndef SOLARIS7
+#ifdef DEC_TCPIP
+#define inet_aton INET_ATON
+#endif /* DEC_TCPIP */
+static int
+inet_aton(char * ipaddress, struct in_addr * ia) {
+    struct stringarray * q;
+    union {
+        unsigned long l;
+        unsigned char b[4];
+    } dummy;
+
+    q = cksplit(1,0,ipaddress,".","0123456789abcdefACDEF",8,0,0);
+    if (q->a_size == 4) {
+        dummy.b[0] = atoi(q->a_head[1]);
+        dummy.b[1] = atoi(q->a_head[2]);
+        dummy.b[2] = atoi(q->a_head[3]);
+        dummy.b[3] = atoi(q->a_head[4]);
+        ia->s_addr = dummy.l;
+        return(ia->s_addr != 0);
+    }
+    return(0);
+}
+#endif /* SOLARIS7 */
+#endif /* SOLARIS8 */
+#endif /* SOLARIS9 */
+#endif /* UW7 */
+#endif /* AIX41 */
+#endif /* LINUX */
+#endif /* FREEBSD4 */
+#endif /* OpenBSD */
+#endif /* SCO_OSR505 */
+#endif /* HPUX1100 */
+#endif /* HPUX10 */
+
+int
+ssl_check_server_name(SSL * ssl, char * hostname)
+/* returns 0 if hostname and server's cert matches, else -1 */
+{
+    char * commonName;
+    unsigned char ** dNSName;
+    unsigned char ** ipAddress;
+    struct in_addr ia;
+    int rv;
+
+    if (ssl_verbose_flag && !inserver) {
+        if (dNSName = tls_get_SAN_objs(ssl,GEN_DNS)) {
+            int i = 0;
+            for (i = 0; dNSName[i]; i++) {
+                printf("Certificate[0] altSubjectName DNS=%s\r\n",dNSName[i]);
+                free(dNSName[i]);
+            }
+        }
+        if (ipAddress = tls_get_SAN_objs(ssl,GEN_IPADD)) {
+            int i = 0;
+            char *server_ip;
+            struct in_addr ia;
+
+            for (i = 0; ipAddress[i]; i++) {
+                if (ipAddress[i]) {
+                    ia.s_addr = *(unsigned long *)ipAddress[i];
+                    server_ip = inet_ntoa(ia);
+                    printf("Certificate[0] altSubjectName IPAddr=%s\r\n",server_ip);
+                }
+                free(ipAddress[i]);
+            }
+            /* ipAddress points to a static - don't free */
+        }
+        if (dNSName = tls_get_SAN_objs(ssl,GEN_EMAIL)) {
+            int i = 0;
+            for (i = 0; dNSName[i]; i++) {
+                printf("Certificate[0] altSubjectName Email=%s\r\n",dNSName[i]);
+                free(dNSName[i]);
+            }
+        }
+        if (dNSName = tls_get_SAN_objs(ssl,GEN_URI)) {
+            int i = 0;
+            for (i = 0; dNSName[i]; i++) {
+                printf("Certificate[0] altSubjectName URI=%s\r\n",dNSName[i]);
+                free(dNSName[i]);
+            }
+        }
+        if (dNSName = tls_get_SAN_objs(ssl,GEN_OTHERNAME)) {
+            int i = 0;
+            for (i = 0; dNSName[i]; i++) {
+                printf("Certificate[0] altSubjectName Other=%s\r\n",dNSName[i]);
+                free(dNSName[i]);
+            }
+        }
+    }
+
+    /* first we check if `hostname' is in fact an ip address */
+    if (inet_aton(hostname, &ia)) {
+        ipAddress = tls_get_SAN_objs(ssl,GEN_IPADD);
+        if (ipAddress) {
+            int i = 0;
+            char *server_ip = "UNKNOWN";
+
+            for (i = 0; ipAddress[i]; i++)
+                if (*(unsigned long *)ipAddress[i] == ia.s_addr)
+                    return 0;
+
+            if (ipAddress[i - 1]) {
+                ia.s_addr = *(unsigned long *)ipAddress[i - 1];
+                server_ip = inet_ntoa(ia);
+            }
+            rv = show_hostname_warning(hostname, server_ip) ? 0 : -1;
+            for (i = 0; ipAddress[i]; i++)
+                free(ipAddress[i]);
+        } else {
+            rv = show_hostname_warning(hostname, "NO IP IN CERT") ? 0 : -1;
+        }
+        return(rv);
+    }
+
+    /* look for dNSName(s) in subjectAltName in the server's certificate */
+    dNSName = tls_get_SAN_objs(ssl,GEN_DNS);
+    if (dNSName) {
+        int i = 0;
+        for (i = 0; dNSName[i]; i++) {
+            if (!dNSName_cmp(hostname,(char *)dNSName[i]))
+                return 0;
+        }
+        rv = show_hostname_warning(hostname,
+				   (char *)((dNSName[i - 1] == NULL) ? 
+			           (char *)"UNKNOWN" : (char *)dNSName[i - 1]))
+	     ? 0 : -1;
+        for (i = 0; dNSName[i]; i++)
+            free(dNSName[i]);
+        return rv;
+    } else if ((commonName = ssl_get_commonName(ssl))) {
+       /* so the server didn't have any dNSName's, check the commonName */
+       if (!dNSName_cmp(hostname, commonName))
+           return 0;
+       else
+           return (show_hostname_warning(hostname, commonName) ? 0 : -1);
+    }
+    return -1;
+}
+
+/* Is 'user' authorized to access the system without a login */
+int
+tls_is_user_valid(SSL * ssl, const char *user)
+{
+    X509 *client_cert;
+    int r = 0;
+
+    if ( !ssl || !user || !user[0] )
+        return(0);
+
+    if (!(client_cert = SSL_get_peer_certificate(ssl)))
+        return 0;
+
+    /* Use user supplied function */
+    r = X509_userok(client_cert,user);
+
+    X509_free(client_cert);
+    return r;
+}
+
+int
+tls_is_anon(int x)
+{
+    char buf[128];
+    SSL_CIPHER * cipher;
+    SSL * ssl = NULL;
+
+    switch ( x ) {
+#ifndef NOFTP
+#ifndef SYSFTP
+    case 1:     /* ftp command */
+        if ( ssl_ftp_active_flag )
+            ssl = ssl_ftp_con;
+        else
+            return(0);
+        break;
+    case 2:     /* ftp data */
+        if ( ssl_ftp_data_active_flag )
+            ssl = ssl_ftp_data_con;
+        else
+            return(0);
+        break;
+#endif /* SYSFTP */
+#endif /* NOFTP */
+    default:
+        if (tls_active_flag)
+            ssl = tls_con;
+        else if (ssl_active_flag)
+            ssl = ssl_con;
+        else
+            return(0);
+    }
+
+    cipher = SSL_get_current_cipher(ssl);
+    if (SSL_CIPHER_description(cipher,buf,sizeof(buf))) {
+        if (ckindex("Au=None",buf,0,0,0) != 0)
+            return(1);                  /* anonymous */
+        return(0);                  /* known */
+    } else {
+        /* could not get cipher description.  Assume anonymous */
+        return(1);
+    }
+}
+
+int
+tls_is_krb5(int x)
+{
+    char buf[128];
+    SSL_CIPHER * cipher;
+    SSL * ssl = NULL;
+
+    switch ( x ) {
+#ifndef NOFTP
+#ifndef SYSFTP
+    case 1:     /* ftp command */
+        if ( ssl_ftp_active_flag )
+            ssl = ssl_ftp_con;
+        else
+            return(0);
+        break;
+    case 2:     /* ftp data */
+        if ( ssl_ftp_data_active_flag )
+            ssl = ssl_ftp_data_con;
+        else
+            return(0);
+        break;
+#endif /* SYSFTP */
+#endif /* NOFTP */
+#ifndef NOHTTP
+    case 3:
+        if ( tls_http_active_flag )
+            ssl = tls_http_con;
+        break;
+#endif /* NOHTTP */
+    default:
+        if (tls_active_flag)
+            ssl = tls_con;
+        else if (ssl_active_flag)
+            ssl = ssl_con;
+        else
+            return(0);
+    }
+
+    cipher = SSL_get_current_cipher(ssl);
+    if (cipher && SSL_CIPHER_description(cipher,buf,sizeof(buf))) {
+        if (ckindex("Au=KRB5",buf,0,0,0) != 0)
+            return(1);                  /* krb5 */
+    }
+    return(0);                          /* not */
+}
+
+int
+ssl_get_client_finished(char *buf, int count)
+{
+#ifdef NO_GET_FINISHED
+    return(0);
+#else
+    if (sstelnet || tcp_incoming) {
+        return(SSL_get_peer_finished(ssl_active_flag?ssl_con:tls_con,
+                                      buf,count));
+    } else {
+        return(SSL_get_finished(ssl_active_flag?ssl_con:tls_con,
+                                      buf,count));
+    }
+#endif /* NO_GET_FINISHED */
+}
+
+int
+ssl_get_server_finished(char *buf, int count)
+{
+#ifdef NO_GET_FINISHED
+    return(0);
+#else
+    if (sstelnet || tcp_incoming) {
+        return(SSL_get_finished(ssl_active_flag?ssl_con:tls_con,
+                                      buf,count));
+    } else {
+        return(SSL_get_peer_finished(ssl_active_flag?ssl_con:tls_con,
+                                      buf,count));
+    }
+#endif /* NO_GET_FINISHED */
+}
+
+
+#ifdef CK_AUTHENTICATION
+int
+#ifdef CK_ANSIC
+ssl_reply(int how, unsigned char *data, int cnt)
+#else
+ssl_reply(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+    char * str=NULL;
+
+    data += 4;                          /* Point to status byte */
+    cnt  -= 4;
+
+    if(cnt-- < 1) {
+        auth_finished(AUTH_REJECT);
+        return AUTH_FAILURE;
+    }
+
+    switch(*data++) {
+    case SSL_ACCEPT:
+        if (tn_deb || debses)
+            tn_debug("[SSL - handshake starting]");
+        else if ( ssl_verbose_flag )
+            printf("[SSL - handshake starting]\r\n");
+        debug(F110,"ssl_reply","[SSL - handshake starting]",0);
+
+        /* right ... now we drop into the SSL library */
+        if (!ssl_only_flag) {
+            if (ssl_dummy_flag) {
+                if (tn_deb || debses)
+                    tn_debug("[SSL - Dummy Connected]");
+                else if ( ssl_verbose_flag ) {
+                    printf("[SSL - Dummy Connected]\r\n");
+                }
+                debug(F110,"ssl_reply","[SSL - Dummy Connected]",0);
+                auth_finished(AUTH_UNKNOWN);
+                accept_complete = 1;
+                return AUTH_SUCCESS;
+            }
+
+            if (SSL_connect(ssl_con) <= 0) {
+                int len;
+                if (tn_deb || debses) {
+                    tn_debug("[SSL - FAILED]");
+                    ERR_print_errors(bio_err);
+                    len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+                    ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+                    printf(ssl_err);
+                } else if ( ssl_verbose_flag ) {
+                    printf("[SSL - FAILED]\r\n");
+                    ERR_print_errors(bio_err);
+                    len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+                    ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+                    printf(ssl_err);
+                }
+                debug(F110,"ssl_reply","[SSL - FAILED]",0);
+                auth_finished(AUTH_REJECT);
+                ttclos(0);
+                return AUTH_FAILURE;
+            } else {
+                if (tn_deb || debses)
+                    tn_debug("[SSL - OK]");
+                else if ( ssl_verbose_flag ) {
+                    printf("[SSL - OK]\r\n");
+                }
+                debug(F110,"ssl_reply","[SSL - OK]",0);
+
+                ssl_active_flag = 1;
+                ssl_display_connect_details(ssl_con,0,ssl_verbose_flag);
+            }
+        }
+        auth_finished(AUTH_UNKNOWN);
+        accept_complete = 1;
+        break;
+
+    case SSL_REJECT:
+        if (tn_deb || debses) {
+            tn_debug(
+                 "[SSL - failed to switch on SSL - trying plaintext login]");
+        } else if ( ssl_verbose_flag ) {
+            printf("[SSL - failed to switch on SSL]\r\n");
+            printf("Trying plaintext login:\r\n");
+        }
+        debug(F110,"ssl_reply","[SSL - failed to switch on SSL]",0);
+        auth_finished(AUTH_REJECT);
+        return AUTH_FAILURE;
+
+    default:
+        return AUTH_FAILURE;
+    }
+    return AUTH_SUCCESS;
+}
+
+int
+#ifdef CK_ANSIC
+ssl_is(unsigned char *data, int cnt)
+#else
+ssl_is(data,cnt) unsigned char *data; int cnt;
+#endif
+{
+    if ((cnt -= 4) < 1)
+        return AUTH_FAILURE;
+
+    data += 4;
+    switch(*data++) {
+    case SSL_START:
+        /* server starts the SSL stuff now ... */
+        if (!ssl_only_flag) {
+            if ( !tls_load_certs(ssl_ctx,ssl_con,1) ) {
+                auth_finished(AUTH_REJECT);
+                return AUTH_FAILURE;
+            }
+
+            if (tn_deb || debses)
+                tn_debug("[SSL - handshake starting]");
+            else if ( ssl_verbose_flag )
+                printf("[SSL - handshake starting]\r\n");
+            debug(F110,"ssl_is","[SSL - handshake starting]",0);
+
+            SendSSLAuthSB(SSL_ACCEPT, (void *)0, 0);
+
+            auth_ssl_valid = 1;
+
+            if (ssl_dummy_flag) {
+                if (tn_deb || debses)
+                    tn_debug("[SSL - Dummy Connected]");
+                else if ( ssl_verbose_flag ) {
+                    printf("[SSL - Dummy Connected]\r\n");
+                }
+                debug(F110,"ssl_is","[SSL - Dummy Connected]",0);
+                accept_complete = 1;
+                auth_finished(AUTH_UNKNOWN);
+                return AUTH_SUCCESS;
+            }
+
+            if (SSL_accept(ssl_con) <= 0) {
+                char errbuf[1024];
+
+                sprintf(errbuf,"[SSL - SSL_accept error: %s",
+                         ERR_error_string(ERR_get_error(),NULL));
+
+                if (tn_deb || debses)
+                    tn_debug(errbuf);
+                else if ( ssl_debug_flag )
+                    printf("%s\r\n",errbuf);
+                else if ( ssl_verbose_flag )
+                    printf("[SSL - SSL_accept error]\r\n");
+
+                debug(F110,"ssl_is",errbuf,0);
+
+                auth_finished(AUTH_REJECT);
+                ttclos(0);
+                return AUTH_FAILURE;
+            }
+
+            if (tn_deb || debses)
+                tn_debug("[SSL - OK]");
+            else if ( ssl_verbose_flag ) {
+                printf("[SSL - OK]\r\n");
+            }
+            debug(F110,"ssl_is","[SSL - OK]",0);
+            ssl_active_flag = 1;
+            ssl_display_connect_details(ssl_con,1,ssl_verbose_flag);
+
+            /* now check to see that we got exactly what we
+            * wanted from the caller ... if a certificate is
+            * required then we make 100% sure that we were
+            * given one during the handshake (as it is an optional
+            * part of SSL)
+            */
+
+#ifdef SSL_KRB5
+            if ( tls_is_krb5(0) ) {
+                if (ssl_con->kssl_ctx->client_princ)
+                    debug(F110,"ssl_is KRB5",ssl_con->kssl_ctx->client_princ,0);
+            } else
+#endif /* SSL_KRB5 */
+            if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                X509 * peer = SSL_get_peer_certificate(ssl_con);
+                if (peer == NULL) {
+                    if (tn_deb || debses)
+                        tn_debug("[SSL - peer check failed]");
+                    else if (ssl_debug_flag)
+                        printf("[SSL - peer check failed]\r\n");
+                    debug(F110,"ssl_is","[SSL - peer check failed]",0);
+
+                    /* LOGGING REQUIRED HERE! */
+                    auth_finished(AUTH_REJECT);
+                    return AUTH_FAILURE;
+                }
+            }
+            auth_finished(AUTH_UNKNOWN);
+            accept_complete = 1;
+        }
+        break;
+
+    default:
+        SendSSLAuthSB(SSL_REJECT, (void *) "Unknown option received", -1);
+        if (tn_deb || debses)
+            tn_debug("[SSL - Unknown option received]");
+        else
+            printf("Unknown SSL option %d\r\n", data[-1]);
+        debug(F111,"ssl_is","[SSL - Unknown option received]",data[-1]);
+        auth_ssl_valid = 0;
+        auth_finished(AUTH_REJECT);
+        return(AUTH_FAILURE);
+    }
+    return AUTH_SUCCESS;
+}
+
+#endif /* CK_AUTHENTICATION */
+
+int
+ck_tn_tls_negotiate(VOID)
+{
+    X509 * peer = NULL;
+    char str[256], *uid=NULL;
+    extern int sstelnet;
+
+    if ( !ck_ssleay_is_installed() )
+        return(-1);
+
+    if (sstelnet) {
+        /* server starts the TLS stuff now ... */
+        if (!tls_only_flag) {
+            if ( !tls_load_certs(tls_ctx,tls_con,1) ) {
+                auth_finished(AUTH_REJECT);
+                return -1;
+            }
+
+            if (tn_deb || debses)
+                tn_debug("[TLS - handshake starting]");
+            else if ( ssl_verbose_flag )
+                printf("[TLS - handshake starting]\r\n");
+            debug(F110,"ck_tn_tls_negotiate","[TLS - handshake starting]",0);
+
+            if (ssl_dummy_flag) {
+                if (tn_deb || debses)
+                    tn_debug("[TLS - Dummy Connected]");
+                else if ( ssl_verbose_flag ) {
+                    printf("[TLS - Dummy Connected]\r\n");
+                }
+                debug(F110,"ck_tn_tls_negotiate","[TLS - Dummy Connected]",0);
+                accept_complete = 1;
+                auth_finished(AUTH_REJECT);
+                return 0;
+            }
+
+            if (SSL_accept(tls_con) <= 0) {
+                char errbuf[1024];
+
+                sprintf(errbuf,"[TLS - SSL_accept error: %s",
+                         ERR_error_string(ERR_get_error(),NULL));
+
+                if (tn_deb || debses)
+                    tn_debug(errbuf);
+                else if ( ssl_debug_flag )
+                    printf("%s\r\n",errbuf);
+                else if ( ssl_verbose_flag )
+                    printf("[TLS - SSL_accept error]\r\n");
+
+                debug(F110,"ck_tn_tls_negotiate",errbuf,0);
+                auth_finished(AUTH_REJECT);
+                return -1;
+            }
+
+            if (tn_deb || debses)
+                tn_debug("[TLS - OK]");
+            else if ( ssl_verbose_flag ) {
+                printf("[TLS - OK]\r\n");
+            }
+
+            debug(F110,"ck_tn_tls_negotiate","[TLS - OK]",0);
+            tls_active_flag = 1;
+            ssl_display_connect_details(tls_con,1,ssl_verbose_flag);
+
+
+#ifdef SSL_KRB5
+            if ( tls_is_krb5(0) ) {
+                if (tls_con->kssl_ctx->client_princ) {
+                    char *p;
+                    ckstrncpy(szUserNameAuthenticated,
+                               tls_con->kssl_ctx->client_princ,
+                               UIDBUFLEN);
+                    ckstrncpy(szUserNameRequested,
+                               tls_con->kssl_ctx->client_princ,
+                               UIDBUFLEN);
+                    for ( p = szUserNameRequested; *p ; p++ ) {
+                        if ( *p == '@' || *p == '/' ) {
+                            *p = '\0';
+                            break;
+                        }
+                    }
+                } else {
+                    szUserNameRequested[0] = '\0';
+                    szUserNameAuthenticated[0] = '\0';
+                }
+#ifdef CK_LOGIN
+                if (zvuser(szUserNameRequested))
+                    auth_finished(AUTH_VALID);
+                else
+#endif /* CK_LOGIN */
+                    auth_finished(AUTH_USER);
+            } else
+#endif /* SSL_KRB5 */
+            {
+            /* now check to see that we got exactly what we
+            * wanted from the caller ... if a certificate is
+            * required then we make 100% sure that we were
+            * given one during the handshake (as it is an optional
+            * part of TLS)
+            */
+            peer=SSL_get_peer_certificate(tls_con);
+            if (peer == NULL) {
+                debug(F100,"SSL_get_peer_certificate() == NULL","",0);
+                auth_finished(AUTH_REJECT);
+                if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                    if (tn_deb || debses)
+                        tn_debug("[TLS - peer check failed]");
+                    else if (ssl_debug_flag) {
+                        printf("[TLS - peer check failed]\r\n");
+                    }
+                    debug(F110,
+                           "ck_tn_tls_negotiate",
+                           "[TLS - peer check failed]",
+                           0
+                           );
+                    /* LOGGING REQUIRED HERE! */
+                    return -1;
+                }
+            } else {
+                debug(F100,"SSL_get_peer_certificate() != NULL","",0);
+                X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
+                                           NID_commonName,str,
+                                           256
+                                           );
+                if ( ssl_verbose_flag )
+                    printf("[TLS - commonName=%s]\r\n",str);
+
+                X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
+#ifndef NID_x500UniqueIdentifier
+                                           NID_uniqueIdentifier,
+#else
+                                           NID_x500UniqueIdentifier,
+#endif
+                                           str,
+                                           256
+                                           );
+                if ( ssl_verbose_flag )
+                    printf("[TLS - uniqueIdentifier=%s]\r\n",str);
+
+                /* Try to determine user name */
+                uid = tls_userid_from_client_cert(tls_con);
+                if ( uid ) {
+                    /* This code is very questionable.
+                     * How should it behave?
+                     * The client has presented a certificate that
+                     * contains a username.  We have validated the
+                     * certificate but we do not automatically
+                     * log the user in unless there is a .tlslogin
+                     * file.
+                     */
+
+                    ckstrncpy(szUserNameRequested,uid,UIDBUFLEN);
+#ifdef CK_LOGIN
+                    if (zvuser(uid))
+                        auth_finished(AUTH_VALID);
+                    else
+#endif /* CK_LOGIN */
+                        auth_finished(AUTH_USER);
+                }
+                else {
+                    szUserNameRequested[0] = '\0';
+                    auth_finished(AUTH_REJECT);
+                }
+            }
+            }
+        }
+    } else {
+        char * str=NULL;
+
+        if (tn_deb || debses)
+            tn_debug("[TLS - handshake starting]");
+        else if ( ssl_verbose_flag )
+            printf("[TLS - handshake starting]\r\n");
+        debug(F110,"ck_tn_tls_negotiate","[TLS - handshake starting]",0);
+
+        /* right ... now we drop into the SSL library */
+        if (!tls_only_flag) {
+            char *subject=NULL, *issuer=NULL, *commonName=NULL, *dNSName=NULL;
+
+            if (ssl_dummy_flag) {
+                if (tn_deb || debses)
+                    tn_debug("[TLS - Dummy Connected]");
+                else if ( ssl_verbose_flag ) {
+                    printf("[TLS - Dummy Connected]\r\n");
+                }
+                debug(F110,"ck_tn_tls_negotiate","[TLS - Dummy Connected]",0);
+                auth_finished(AUTH_REJECT);
+                accept_complete = 1;
+                return 0;
+            }
+
+#ifndef USE_CERT_CB
+            if (!tls_load_certs(tls_ctx,tls_con,0))
+                return(-1);
+#endif /* USE_CERT_CB */
+            if (SSL_connect(tls_con) <= 0) {
+                int len;
+                if (tn_deb || debses) {
+                    tn_debug("[TLS - FAILED]");
+                    ERR_print_errors(bio_err);
+                    len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+                    ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+                    printf(ssl_err);
+                } else if ( ssl_verbose_flag ) {
+                    printf("[TLS - FAILED]\r\n");
+                    ERR_print_errors(bio_err);
+                    len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+                    ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+                    printf(ssl_err);
+                }
+                debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                auth_finished(AUTH_REJECT);
+                return -1;
+            }
+
+            tls_active_flag = 1;
+            if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER)
+                 && !tls_is_krb5(0)) {
+                char prmpt[1024];
+                subject = ssl_get_subject_name(tls_con);
+
+                if (!subject) {
+                    if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+                    {
+                        if (tn_deb || debses)
+                            tn_debug("[TLS - FAILED]");
+                        else if ( ssl_verbose_flag )
+                            printf("[TLS - FAILED]\r\n");
+                        debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                        auth_finished(AUTH_REJECT);
+                        return -1;
+                    } else {
+                        int ok;
+                        ok = uq_ok("Warning: Server didn't provide a certificate",
+                                   "Continue? (Y/N)", 3, NULL, 0);
+                        if (!ok) {
+                            if (tn_deb || debses)
+                                tn_debug("[TLS - FAILED]");
+                            else if ( ssl_verbose_flag )
+                                printf("[TLS - FAILED]\r\n");
+                            debug(F110,
+                                   "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                            auth_finished(AUTH_REJECT);
+                            return -1;
+                        }
+                    }
+                } else if (ssl_check_server_name(tls_con, szHostName)) {
+                    if (tn_deb || debses)
+                        tn_debug("[TLS - FAILED]");
+                    else if ( ssl_verbose_flag )
+                        printf("[TLS - FAILED]\r\n");
+                    debug(F110,
+                           "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                    auth_finished(AUTH_REJECT);
+                    return -1;
+                }
+            }
+
+            if ( ssl_debug_flag && ssl_finished_messages) {
+                char msg[32];
+                int i, len=32;
+                extern char tn_msg[], hexbuf[];
+
+                tn_msg[0] = '\0';
+                len = ssl_get_client_finished(msg,len);
+                if ( len > 0 ) {
+                    for ( i=0;i<len;i++ ) {
+                        sprintf(hexbuf,"%02X ",msg[i]);
+                        ckstrncat(tn_msg,hexbuf,TN_MSG_LEN);
+                    }
+                    printf("TLS client finished: %s\r\n",tn_msg);
+                }
+                tn_msg[0] = '\0';
+                len = ssl_get_server_finished(msg,len);
+                if ( len > 0 ) {
+                    for ( i=0;i<len;i++ ) {
+                        sprintf(hexbuf,"%02X ",msg[i]);
+                        ckstrncat(tn_msg,hexbuf,TN_MSG_LEN);
+                    }
+                    printf("TLS server finished: %s\r\n",tn_msg);
+                }
+            }
+
+            if (tn_deb || debses)
+                tn_debug("[TLS - OK]");
+            else if ( ssl_verbose_flag )
+                printf("[TLS - OK]\r\n");
+            debug(F110,"ck_tn_tls_negotiate","[TLS - OK]",0);
+
+            ssl_display_connect_details(tls_con,0,ssl_verbose_flag);
+        }
+        auth_finished(AUTH_REJECT);
+    }
+    accept_complete = 1;
+    auth_ssl_valid = 1;
+    return(0);
+}
+
+int
+ck_ssl_incoming(fd) int fd;
+{
+    /* if we are not running in debug then any error
+    * stuff from SSL debug *must* not go down
+    * the socket (which 0,1,2 are all pointing to by
+    * default)
+    */
+
+    int timo = 2000;
+
+    if ( !ck_ssleay_is_installed() )
+        return(-1);
+
+    /* do the SSL stuff now ... before we play with pty's */
+    SSL_set_fd(ssl_con,fd);
+    SSL_set_fd(tls_con,fd);
+
+    if (tls_only_flag) {
+        if (tn_deb || debses)
+            tn_debug("[TLS - handshake starting]");
+        else if ( ssl_verbose_flag )
+            printf("[TLS - handshake starting]\r\n");
+        debug(F110,"ck_ssl_incoming","[TLS - handshake starting]",0);
+
+        /* hmm ... only when running talking to things like
+        * https servers should we hit this code and then
+        * we really don't care *who* we talk to :-)
+        */
+        if (SSL_accept(tls_con) <= 0) {
+            char errbuf[1024];
+
+            sprintf(errbuf,"[TLS - SSL_accept error: %s",
+                     ERR_error_string(ERR_get_error(),NULL));
+
+            if (tn_deb || debses)
+                tn_debug(errbuf);
+            else if ( ssl_debug_flag )
+                printf("%s\r\n",errbuf);
+            else if ( ssl_verbose_flag )
+                printf("[TLS - SSL_accept error]\r\n");
+
+            debug(F110,"ck_ssl_incoming",errbuf,0);
+            return(-1);
+        } else {
+            if (tn_deb || debses)
+                tn_debug("[TLS - OK]");
+            else if ( ssl_verbose_flag )
+                printf("[TLS - OK]\r\n");
+            debug(F110,"ck_ssl_incoming","[TLS - OK]",0);
+            tls_active_flag = 1;
+        }
+    } else if (ssl_only_flag) {
+        if (tn_deb || debses)
+            tn_debug("[SSL - handshake starting]");
+        else if ( ssl_verbose_flag )
+            printf("[SSL - handshake starting]\r\n");
+        debug(F110,"ck_ssl_incoming","[SSL - handshake starting]",0);
+
+        /* hmm ... only when running talking to things like
+         * https servers should we hit this code and then
+         * we really don't care *who* we talk to :-)
+         */
+        if (SSL_accept(ssl_con) <= 0) {
+            char errbuf[1024];
+
+            sprintf(errbuf,"[SSL - SSL_accept error: %s",
+                     ERR_error_string(ERR_get_error(),NULL));
+
+            if (tn_deb || debses)
+                tn_debug(errbuf);
+            else if ( ssl_debug_flag )
+                printf("%s\r\n",errbuf);
+            else if ( ssl_verbose_flag )
+                printf("[SSL - SSL_accept error]\r\n");
+
+            debug(F110,"ck_ssl_incoming",errbuf,0);
+            return(-1);
+        } else {
+            if (tn_deb || debses)
+                tn_debug("[SSL - OK]");
+            else if ( ssl_verbose_flag )
+            printf("[SSL - OK]\r\n");
+            debug(F110,"ssl_is","[SSL - OK]",0);
+            ssl_active_flag = 1;
+        }
+    }
+    if (ssl_active_flag || tls_active_flag) {
+        X509 *peer;
+        char str[256], *uid=NULL;
+
+        /* now check to see that we got exactly what we
+         * wanted from the caller ... if a certificate is
+         * required then we make 100% sure that we were
+         * given on during the handshake (as it is an optional
+         * part of SSL and TLS)
+         */
+
+        if ( tls_active_flag ) {
+            peer=SSL_get_peer_certificate(tls_con);
+        } else if ( ssl_active_flag ) {
+            peer=SSL_get_peer_certificate(ssl_con);
+        }
+
+        if (peer == NULL) {
+            debug(F100,"SSL_get_peer_certificate() == NULL","",0);
+            auth_finished(AUTH_REJECT);
+
+            if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                if (tn_deb || debses)
+                    tn_debug("[SSL/TLS - peer check failed]");
+                else if (ssl_debug_flag) {
+                    printf("[SSL/TLS - peer check failed]\r\n");
+                }
+                debug(F110,
+                       "ck_tn_tls_negotiate",
+                       "[SSL/TLS - peer check failed]",
+                       0
+                       );
+                /* LOGGING REQUIRED HERE! */
+                return -1;
+            }
+
+        } else {
+            debug(F100,"SSL_get_peer_certificate() != NULL","",0);
+            X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
+                                       NID_commonName,str,
+                                       256
+                                       );
+            printf("[TLS - commonName=%s]\r\n",str);
+
+            X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
+#ifndef NID_x500UniqueIdentifier
+                                       NID_uniqueIdentifier,
+#else   
+                                       NID_x500UniqueIdentifier,
+#endif
+                                       str,256
+                                       );
+            printf("[TLS - uniqueIdentifier=%s]\r\n",str);
+
+            /* Try to determine user name */
+            uid = tls_userid_from_client_cert(tls_con);
+            if ( uid ) {
+                /* This code is very questionable.
+                * How should it behave?
+                * The client has presented a certificate that
+                * contains a username.  We have validated the
+                * certificate but we do not automatically
+                * log the user in unless there is a .tlslogin
+                * file.
+                */
+
+                ckstrncpy(szUserNameRequested,uid,UIDBUFLEN);
+#ifdef CK_LOGIN
+                if (zvuser(uid))
+                    auth_finished(AUTH_VALID);
+                else
+#endif /* CK_LOGIN */
+                    auth_finished(AUTH_USER);
+            }
+            else {
+                szUserNameRequested[0] = '\0';
+                auth_finished(AUTH_REJECT);
+            }
+        }
+    }
+    return(0);  /* success */
+}
+
+int
+ck_ssl_outgoing(fd) int fd;
+{
+    int timo = 2000;
+
+    if ( !ck_ssleay_is_installed() )
+        return(-1);
+
+    /* bind in the network descriptor */
+    SSL_set_fd(ssl_con,fd);
+    SSL_set_fd(tls_con,fd);
+
+    /* If we are doing raw TLS then start it now ... */
+    if (tls_only_flag) {
+#ifndef USE_CERT_CB
+        if (!tls_load_certs(tls_ctx,tls_con,0)) {
+            debug(F110,"ck_ssl_outgoing","tls_load_certs() failed",0);
+            return(-1);
+        }
+#endif /* USE_CERT_CB */
+        if (tn_deb || debses)
+            tn_debug("[TLS - handshake starting]");
+        else if (ssl_verbose_flag)
+            printf("[TLS - handshake starting]\r\n");
+        debug(F110,"ck_ssl_outgoing","[TLS - handshake starting]",0);
+        if (SSL_connect(tls_con) <= 0) {
+            char errbuf[1024];
+
+            sprintf(errbuf,"[TLS - SSL_connect error: %s",
+                     ERR_error_string(ERR_get_error(),NULL));
+
+            if (tn_deb || debses)
+                tn_debug(errbuf);
+            else if ( ssl_debug_flag )
+                printf("%s\r\n",errbuf);
+
+            if (tn_deb || debses)
+                tn_debug("[TLS - FAILED]");
+            else if ( ssl_verbose_flag )
+                printf("[TLS - FAILED]\r\n");
+            debug(F110,"ck_ssl_outgoing","[TLS - FAILED]",0);
+            netclos();
+            return(-1);
+        } else {
+            tls_active_flag = 1;
+            if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) && 
+                 !tls_is_krb5(0) ) {
+                char *subject = ssl_get_subject_name(tls_con);
+
+                if (!subject) {
+                    if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+                    {
+                        if (tn_deb || debses)
+                            tn_debug("[TLS - FAILED]");
+                        else if ( ssl_verbose_flag )
+                            printf("[TLS - FAILED]\r\n");
+                        debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+
+                        auth_finished(AUTH_REJECT);
+                        return -1;
+                    } else {
+                        char prmpt[1024];
+                        int ok;
+                        ok = uq_ok("Warning: Server didn't provide a certificate",
+                                   "Continue? (Y/N)", 3, NULL, 0);
+                        if (!ok) {
+                            if (tn_deb || debses)
+                                tn_debug("[TLS - FAILED]");
+                            else if ( ssl_verbose_flag )
+                                printf("[TLS - FAILED]\r\n");
+                            debug(F110,
+                                   "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                            auth_finished(AUTH_REJECT);
+                            return -1;
+                        }
+                    }
+                } else if (ssl_check_server_name(tls_con, szHostName)) {
+                    if (tn_deb || debses)
+                        tn_debug("[TLS - FAILED]");
+                    else if ( ssl_verbose_flag )
+                        printf("[TLS - FAILED]\r\n");
+                    debug(F110,
+                           "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                    auth_finished(AUTH_REJECT);
+                    return -1;
+                }
+            }
+
+            printf("[TLS - OK]\r\n");
+            if (tn_deb || debses)
+                tn_debug("[TLS - OK]");
+            debug(F110,"ck_ssl_outgoing","[TLS - OK]",0);
+            ssl_display_connect_details(tls_con,0,ssl_verbose_flag);
+        }
+    }
+    /* if we are doing raw SSL then start it now ... */
+    else if (ssl_only_flag) {
+#ifndef USE_CERT_CB
+        if (!tls_load_certs(ssl_ctx,ssl_con,0))
+            return(-1);
+#endif /* USE_CERT_CB */
+        if (tn_deb || debses)
+            tn_debug("[SSL - handshake starting]");
+        else if ( ssl_verbose_flag )
+            printf("[SSL - handshake starting]\r\n");
+        debug(F110,"ck_ssl_outgoing","[SSL - handshake starting]",0);
+        if (SSL_connect(ssl_con) <= 0) {
+            if ( ssl_debug_flag ) {
+                char errbuf[1024];
+
+                sprintf(errbuf,"[SSL - SSL_connect error: %s",
+                         ERR_error_string(ERR_get_error(),NULL));
+                printf("%s\r\n",errbuf);
+            }
+            if (tn_deb || debses)
+                tn_debug("[SSL - FAILED]");
+            else if ( ssl_verbose_flag )
+                printf("[SSL - FAILED]\r\n");
+            debug(F110,"ck_ssl_outgoing","[SSL - FAILED]",0);
+            return(-1);
+        } else {
+            ssl_active_flag = 1;
+
+            if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) &&
+                 !tls_is_krb5(0)) {
+                char *subject = ssl_get_subject_name(ssl_con);
+
+                if (!subject) {
+                    if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+                    {
+                        if (tn_deb || debses)
+                            tn_debug("[SSL - FAILED]");
+                        else if ( ssl_verbose_flag )
+                            printf("[SSL - FAILED]\r\n");
+                        debug(F110,"ck_tn_tls_negotiate","[SSL - FAILED]",0);
+
+                        auth_finished(AUTH_REJECT);
+                        return -1;
+                    } else {
+                        char prmpt[1024];
+                        int ok;
+                        ok = uq_ok("Warning: Server didn't provide a certificate",
+                                   "Continue? (Y/N)", 3, NULL, 0);
+                        if (!ok) {
+                            if (tn_deb || debses)
+                                tn_debug("[SSL - FAILED]");
+                            else if ( ssl_verbose_flag )
+                                printf("[SSL - FAILED]\r\n");
+                            debug(F110,
+                                   "ck_tn_tls_negotiate","[SSL - FAILED]",0);
+                            auth_finished(AUTH_REJECT);
+                            return -1;
+                        }
+                    }
+                } else if (ssl_check_server_name(ssl_con, szHostName)) {
+                    if (tn_deb || debses)
+                        tn_debug("[SSL - FAILED]");
+                    else if ( ssl_verbose_flag )
+                        printf("[SSL - FAILED]\r\n");
+                    debug(F110, "ck_tn_tls_negotiate","[SSL - FAILED]",0);
+                    auth_finished(AUTH_REJECT);
+                    return -1;
+                }
+            }
+
+            printf("[SSL - OK]\r\n");
+            if (tn_deb || debses)
+                tn_debug("[SSL - OK]");
+            debug(F110,"ck_ssl_outgoing","[SSL - OK]",0);
+            ssl_display_connect_details(ssl_con,0,ssl_verbose_flag);
+        }
+    }
+    return(0);  /* success */
+}
+
+#ifndef NOHTTP
+int
+ck_ssl_http_client(fd, hostname) int fd; char * hostname;
+{
+    int timo = 2000;
+
+    if ( !ck_ssleay_is_installed() )
+        return(-1);
+
+    /* bind in the network descriptor */
+    SSL_set_fd(tls_http_con,fd);
+
+    /* If we are doing raw TLS then start it now ... */
+    if (1) {
+#ifndef USE_CERT_CB
+        if (!tls_load_certs(tls_http_ctx,tls_http_con,0)) {
+            debug(F110,"ck_ssl_http_client","tls_load_certs() failed",0);
+            return(-1);
+        }
+#endif /* USE_CERT_CB */
+        if (tn_deb || debses)
+            tn_debug("[TLS - handshake starting]");
+        else if (ssl_verbose_flag)
+            printf("[TLS - handshake starting]\r\n");
+        debug(F110,"ck_ssl_outgoing","[TLS - handshake starting]",0);
+        if (SSL_connect(tls_http_con) <= 0) {
+            char errbuf[1024];
+
+            sprintf(errbuf,"[TLS - SSL_connect error: %s",
+                     ERR_error_string(ERR_get_error(),NULL));
+
+            if (tn_deb || debses)
+                tn_debug(errbuf);
+            else if ( ssl_debug_flag )
+                printf("%s\r\n",errbuf);
+
+            if (tn_deb || debses)
+                tn_debug("[TLS - FAILED]");
+            else if ( ssl_verbose_flag )
+                printf("[TLS - FAILED]\r\n");
+            debug(F110,"ck_ssl_http_client","[TLS - FAILED]",0);
+            http_close();
+            return(-1);
+        } else {
+            tls_http_active_flag = 1;
+            if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) &&
+                 !tls_is_krb5(3) ) {
+                char *subject = ssl_get_subject_name(tls_http_con);
+
+                if (!subject) {
+                    if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+                    {
+                        if (tn_deb || debses)
+                            tn_debug("[TLS - FAILED]");
+                        else if ( ssl_verbose_flag )
+                            printf("[TLS - FAILED]\r\n");
+                        debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                        return -1;
+                    } else {
+                        char prmpt[1024];
+                        int ok;
+                        ok = uq_ok("Warning: Server didn't provide a certificate",
+                                   "Continue? (Y/N)", 3, NULL, 0);
+                        if (!ok) {
+                            if (tn_deb || debses)
+                                tn_debug("[TLS - FAILED]");
+                            else if ( ssl_verbose_flag )
+                                printf("[TLS - FAILED]\r\n");
+                            debug(F110,
+                                   "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                            return -1;
+                        }
+                    }
+                } else if (ssl_check_server_name(tls_http_con, hostname)) {
+                    if (tn_deb || debses)
+                        tn_debug("[TLS - FAILED]");
+                    else if ( ssl_verbose_flag )
+                        printf("[TLS - FAILED]\r\n");
+                    debug(F110,
+                           "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                    return -1;
+                }
+            }
+
+            printf("[TLS - OK]\r\n");
+            if (tn_deb || debses)
+                tn_debug("[TLS - OK]");
+            debug(F110,"ck_ssl_outgoing","[TLS - OK]",0);
+            ssl_display_connect_details(tls_http_con,0,ssl_verbose_flag);
+        }
+    }
+    return(0);  /* success */
+}
+#endif /* NOHTTP */
+int
+ck_ssl_renegotiate_ciphers()
+{
+
+    if ( !ck_ssleay_is_installed() )
+        return(0);
+
+    if ( !sstelnet )
+        return(0);
+
+    if ( ssl_active_flag )
+        return SSL_renegotiate(ssl_con);
+    else if ( tls_active_flag )
+        return SSL_renegotiate(tls_con);
+    return(0);
+}
+
+#ifdef NT
+int 
+ck_X509_save_cert_to_user_store(X509 *cert)
+{
+#ifdef X509V3_EXT_DUMP_UNKNOWN
+    char path[CKMAXPATH];
+    char hash[16];
+    char * GetAppData(int);
+    BIO * out=NULL;
+
+    if ( cert == NULL )
+        return(0);
+
+    sprintf(hash,"%08lx",X509_subject_name_hash(cert));
+    ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs/",
+             hash,".0");
+
+    
+    out=BIO_new(BIO_s_file());
+    if (out == NULL)
+    {
+        ERR_print_errors(bio_err);
+        return(0);
+    }
+    if (BIO_write_filename(out,path) <= 0) {
+        perror(path);
+        return(0);
+    }
+
+    X509_print_ex(out, cert, XN_FLAG_SEP_MULTILINE, X509V3_EXT_DUMP_UNKNOWN);
+    if (!PEM_write_bio_X509(out,cert)) {
+        BIO_printf(bio_err,"unable to write certificate\n");
+        ERR_print_errors(bio_err);
+        BIO_free_all(out);
+        return(0);
+    }
+    BIO_free_all(out);
+    return(1);
+#else /* X509V3_EXT_DUMP_UNKNOWN */
+    return(0);
+#endif /* X509V3_EXT_DUMP_UNKNOWN */
+}
+#endif /* NT */
+
+#ifndef OS2
+/* The following function should be replaced by institution specific */
+/* code that will convert an X509 cert structure to a userid for the */
+/* purposes of client to host login.  The example code included      */
+/* simply returns the UID field of the Subject if it exists.         */
+
+/* X509_to_user() returns 0 if valid userid in 'userid', else -1 */
+int
+X509_to_user(X509 *peer_cert, char *userid, int len)
+{
+#ifdef X509_UID_TO_USER
+    /* BEGIN EXAMPLE */
+    int err;
+
+    if (!(peer_cert && userid) || len <= 0)
+        return -1;
+
+    userid[0] = '\0';
+    debug(F110,"X509_to_user() subject",
+           X509_NAME_oneline(X509_get_subject_name(peer_cert),NULL,0),0);
+
+    /* userid is in cert subject /UID */
+    err = X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
+#ifndef NID_x500UniqueIdentifier
+                                     NID_uniqueIdentifier,
+#else
+                                     NID_x500UniqueIdentifier,
+#endif
+                                     userid, len);
+
+    debug(F111,"X509_to_user() userid",userid,err);
+    if (err > 0)
+        return 0;
+
+    /* END EXAMPLE */
+#else /* X509_UID_TO_USER */
+#ifdef X509_SUBJECT_ALT_NAME_TO_USER
+    /* BEGIN EXAMPLE */
+    int i;
+    X509_EXTENSION *ext = NULL;
+    STACK_OF(GENERAL_NAME) *ialt = NULL;
+    GENERAL_NAME *gen = NULL;
+    char email[256];
+
+    if (!(peer_cert && userid) || len <= 0)
+        return -1;
+
+    userid[0] = '\0';
+    email[0] = '\0';
+    debug(F110,"X509_to_user() subject",
+           X509_NAME_oneline(X509_get_subject_name(peer_cert),NULL,0),0);
+
+    if ((i = X509_get_ext_by_NID(peer_cert, NID_subject_alt_name, -1))<0)
+        return -1;
+    if (!(ext = X509_get_ext(peer_cert, i)))
+        return -1;
+    X509V3_add_standard_extensions();
+    if (!(ialt = X509V3_EXT_d2i(ext)))
+        return -1;
+    for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) {
+        gen = sk_GENERAL_NAME_value(ialt, i);
+        if (gen->type == GEN_DNS) {
+            if(!gen->d.ia5 || !gen->d.ia5->length)
+                break;
+            if ( gen->d.ia5->length + 1 > sizeof(email) ) {
+                goto cleanup;
+            }
+            memcpy(email, gen->d.ia5->data, gen->d.ia5->length);
+            email[gen->d.ia5->length] = 0;
+            break;
+        }
+    }
+  cleanup:
+    X509V3_EXT_cleanup();
+    if (ialt)
+        sk_GENERAL_NAME_free(ialt);
+
+    debug(F110,"X509_to_user() email",email,0);
+
+    if ( email[0] ) {
+        char * domain = NULL;
+
+        /* Find domain */
+        for ( i=0 ; email[i] ; i++ ) {
+            if ( email[i] == '@' ) {
+                email[i] = '\0';
+                domain = &email[i+1];
+                break;
+            }
+        }
+
+        if ( domain ) {
+            /* XXX - Put code to Verify domain here */
+
+            if ( /* domain is okay */ 1 )
+                ckstrncpy(userid,email,len);
+        }
+    }
+
+    return(userid[0] ? 0 : -1);
+    /* END EXAMPLE */
+#endif /* X509_SUBJECT_ALT_NAME_TO_USER */
+#endif /* X509_UID_TO_USER */
+    return -1;
+}
+
+/* The following function should be replaced by institution specific */
+/* code that will determine whether or not the combination of the    */
+/* provided X509 certificate and username is valid for automatic     */
+/* login.   Whereas X509_to_user() is used to provide authentication */
+/* of the user, the X509_userok() function is used to provide        */
+/* authorization.  The certificate passed into X509_userok() does    */
+/* need to map to a userid; nor would the userid it would map to     */
+/* need to match the userid provided to the function.  There are     */
+/* numerous circumstances in which it is beneficial to have the ability */
+/* for multiple users to gain access to a common account such as     */
+/* 'root' on Unix; or a class account on a web server.  In Unix we   */
+/* implement this capability with the ~userid/.tlslogin file which   */
+/* a list of X509 certificates which may be used to access the       */
+/* account 'userid'.                                                 */
+
+/* X509_to_user() returns 0 if access is denied; 1 is access is permitted */
+int
+X509_userok(X509 * peer_cert, const char * userid)
+{
+#ifndef VMS
+    /* check if clients cert is in "user"'s ~/.tlslogin file */
+    char buf[512];
+    int r = 0;
+    FILE *fp;
+    struct passwd *pwd;
+    X509 *file_cert;
+
+    if ( peer_cert == NULL )
+        return(0);
+
+    if (!(pwd = getpwnam(userid)))
+       return 0;
+    if (strlen(pwd->pw_dir) > 500)
+       return(0);
+    sprintf(buf, "%s/.tlslogin", pwd->pw_dir);
+
+    if (!(fp = fopen(buf, "r")))
+        return 0;
+    while (!r && (file_cert = PEM_read_X509(fp, NULL, NULL, NULL))) {
+        if (!ASN1_STRING_cmp(peer_cert->signature, file_cert->signature))
+            r = 1;
+        X509_free(file_cert);
+    }
+    fclose(fp);
+    return(r);
+#else /* VMS */
+    /* Need to implement an appropriate function for VMS */
+    return(0);
+#endif /* VMS */
+}
+#endif /* OS2 */
+#endif /* CK_SSL */
diff --git a/ckermit-8.0.211/ck_ssl.h b/ckermit-8.0.211/ck_ssl.h
new file mode 100644
index 0000000..b4dd8a3
--- /dev/null
+++ b/ckermit-8.0.211/ck_ssl.h
@@ -0,0 +1,147 @@
+/*
+  C K _ S S L . H --  OpenSSL Interface Header for C-Kermit
+
+  Copyright (C) 1985, 2004,
+    Trustees of Columbia University in the City of New York.
+    All rights reserved.  See the C-Kermit COPYING.TXT file or the
+    copyright text in the ckcmai.c module for disclaimer and permissions.
+
+    Author:  Jeffrey E Altman (jaltman@secure-endpoints.com)
+               Secure Endpoints Inc., New York City
+*/
+
+#ifdef CK_SSL
+#ifndef CK_ANSIC
+#define NOPROTO
+#endif /* CK_ANSIC */
+
+#ifdef COMMENT                          /* Not for C-Kermit 7.1 */
+#ifdef KRB5
+#ifndef NOSSLK5
+#ifndef SSL_KRB5
+#define SSL_KRB5
+#endif /* SSL_KRB5 */
+#endif /* NOSSLK5 */
+#endif /* KRB5 */
+#endif /* COMMENT */
+
+#ifdef OS2
+#ifndef ZLIB
+#define ZLIB
+#endif /* ZLIB */
+#endif /* OS2 */
+
+#ifdef ZLIB
+#include <openssl/comp.h>
+#endif /* ZLIB */
+/* We place the following to avoid loading openssl/mdc2.h since it 
+ * relies on the OpenSSL des.h.  Since we do not need the MDC2 
+ * definitions there is no reason to have it included by openssl/evp.h
+ */
+#define OPENSSL_NO_MDC2
+#include <openssl/des.h>
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/bn.h>
+#include <openssl/blowfish.h>
+#include <openssl/dh.h>
+#include <openssl/rc4.h>
+#include <openssl/cast.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#ifdef SSL_KRB5
+#include <openssl/kssl.h>
+#endif /* SSL_KRB5 */
+
+extern BIO *bio_err;
+extern SSL *ssl_con;
+extern SSL_CTX *ssl_ctx;
+extern int ssl_debug_flag;
+extern int ssl_only_flag;
+extern int ssl_active_flag;
+extern int ssl_verify_flag;
+extern int ssl_verbose_flag;
+extern int ssl_certsok_flag;
+extern int ssl_dummy_flag;
+extern int ssl_verify_depth;
+
+extern char *ssl_rsa_cert_file;
+extern char *ssl_rsa_cert_chain_file;
+extern char *ssl_rsa_key_file;
+extern char *ssl_dsa_cert_file;
+extern char *ssl_dsa_cert_chain_file;
+extern char *ssl_dh_key_file;
+extern char *ssl_cipher_list;
+extern char *ssl_crl_file;
+extern char *ssl_crl_dir;
+extern char *ssl_verify_file;
+extern char *ssl_verify_dir;
+extern char *ssl_dh_param_file;
+extern char *ssl_rnd_file;
+
+extern SSL_CTX *tls_ctx;
+extern SSL *tls_con;
+extern int tls_only_flag;
+extern int tls_active_flag;
+extern int x509_cert_valid;
+extern X509_STORE *crl_store;
+
+#ifndef NOHTTP
+extern SSL_CTX *tls_http_ctx;
+extern SSL *tls_http_con;
+extern int tls_http_active_flag;
+#endif /* NOHTTP */
+
+extern int ssl_initialized;
+
+_PROTOTYP(VOID ssl_once_init,(void));
+_PROTOTYP(int ssl_tn_init,(int));
+_PROTOTYP(int ssl_http_init,(char *));
+_PROTOTYP(int ck_ssl_http_client,(int,char *));
+_PROTOTYP(int ssl_display_connect_details,(SSL *,int,int));
+_PROTOTYP(int ssl_server_verify_callback,(int, X509_STORE_CTX *));
+_PROTOTYP(int ssl_client_verify_callback,(int, X509_STORE_CTX *));
+_PROTOTYP(int ssl_reply,(int, unsigned char *, int));
+_PROTOTYP(int ssl_is,(unsigned char *, int));
+_PROTOTYP(int ck_ssl_incoming,(int));
+_PROTOTYP(int ck_ssl_outgoing,(int));
+_PROTOTYP(int tls_is_user_valid,(SSL *, const char *));
+_PROTOTYP(char * ssl_get_dnsName,(SSL *));
+_PROTOTYP(char * ssl_get_commonName,(SSL *));
+_PROTOTYP(char * ssl_get_issuer_name,(SSL *));
+_PROTOTYP(char * ssl_get_subject_name,(SSL *));
+_PROTOTYP(int ssl_get_client_finished,(char *, int));
+_PROTOTYP(int ssl_get_server_finished,(char *, int));
+_PROTOTYP(int ssl_passwd_callback,(char *, int, int, VOID *));
+_PROTOTYP(VOID ssl_client_info_callback,(const SSL *,int, int));
+_PROTOTYP(int ssl_anonymous_cipher,(SSL * ssl));
+_PROTOTYP(int tls_load_certs,(SSL_CTX * ctx, SSL * con, int server));
+_PROTOTYP(int ssl_verify_crl,(int, X509_STORE_CTX *));
+_PROTOTYP(int tls_is_krb5,(int));
+_PROTOTYP(int X509_userok,(X509 *,const char *));
+_PROTOTYP(int ck_X509_save_cert_to_user_store,(X509 *));
+#ifdef OS2
+#include "ckosslc.h"
+#include "ckossl.h"
+#endif /* OS2 */
+
+#define SSL_CLIENT 0
+#define SSL_SERVER 1
+#define SSL_HTTP   2
+
+#define SSL_ERR_BFSZ 4096
+
+#ifdef SSL_KRB5
+#define DEFAULT_CIPHER_LIST "HIGH:MEDIUM:LOW:+KRB5:+ADH:+EXP"
+#else
+#define DEFAULT_CIPHER_LIST "HIGH:MEDIUM:LOW:+ADH:+EXP"
+#endif /* SSL_KRB5 */
+#endif /* CK_SSL */
diff --git a/ckermit-8.0.211/ckaaaa.txt b/ckermit-8.0.211/ckaaaa.txt
new file mode 100644
index 0000000..efa83a5
--- /dev/null
+++ b/ckermit-8.0.211/ckaaaa.txt
@@ -0,0 +1,385 @@
+ckaaaa.txt                                                        10 Apr 2004
+
+			   C-KERMIT VERSION 8.0.211
+			      OVERVIEW OF FILES
+
+	       Communications software for UNIX and (Open)VMS.
+
+		       And in former versions also for:
+			  Stratus VOS, AOS/VS, QNX,
+	     Plan 9, OS-9, Apollo Aegis, and the Commodore Amiga.
+		      The Apple Macintosh, the Atari ST.
+
+		  The Kermit Project - Columbia University
+
+	    http://www.columbia.edu/kermit/ - kermit@columbia.edu
+
+
+  Copyright (C) 1985, 2004,
+    Trustees of Columbia University in the City of New York.
+    All rights reserved.  See the C-Kermit COPYING.TXT file or the
+    copyright text in the ckcmai.c module for disclaimer and permissions.
+
+
+DOCUMENTATION
+
+  C-Kermit is documented in the book "Using C-Kermit", Second Edition, by
+  Frank da Cruz and Christine M. Gianone, Digital Press, ISBN 1-55558-164-1,
+  supplementated by Web-based updates for C-Kermit 7.0 and 8.0.
+
+PLATFORMS
+                   Security
+   Name            Included   Last Updated
+
+   Unix               Yes     8.0.211  10 Apr 2004
+   (Open)VMS          No      8.0.208  10 Apr 2004
+   Windows (K95)      Yes     8.0.208  14 Mar 2003  (K95 2.1)
+   OS/2 (K95)         Yes     8.0.208  14 Mar 2003  (K95 2.1)
+   DG AOS/VS          No      7.0.196   1 Jan 2000
+   Stratus VOS        No      7.0.196   1 Jan 2000
+   Bell Plan 9        No      7.0.196   1 Jan 2000
+   Microware OS-9     No      7.0.196   1 Jan 2000
+   Commodore Amiga    No      7.0.196   1 Jan 2000
+   Macintosh          No      5A(190)  16 Aug 1994  (Mac Kermit 0.991)
+   Atari ST           No      5A(189)  30 Jun 1993
+
+QUICK START FOR FTP USERS
+
+  If you have a Web browser, go to:
+
+    http://www.columbia.edu/kermit/ckermit.html
+
+  And take it from there.  Otherwise...
+
+  The definitive FTP source for Kermit software is kermit.columbia.edu.
+  Kermit software obtained from other FTP sites is not necessarily complete
+  or up to date, and may have been modified.
+
+C-Kermit for UNIX computers that have a C compiler and 'make' program:
+
+  Directory kermit/archives, binary mode, file cku211.tar.Z or cku211.tar.gz
+
+  This is a compressed tar archive of UNIX C-Kermit source code, makefile, and
+  other files.  It unpacks into its current directory, so download it into a
+  fresh directory.  Transfer in binary mode, uncompress (or gunzip), untar (tar
+  xvf cku211.tar), and then give the appropriate "make" command to build for
+  your UNIX system; read the comments in the makefile and ckuins.txt for
+  further info.
+
+C-Kermit for VMS:
+
+  If you have VMS UNZIP, get the file kermit/archives/ckv211.zip in binary
+  mode, unzip, and build with CKVKER.COM.
+
+Others:  In the kermit/f or kermit/test directories under the appropriate
+prefixes, explained below.
+
+
+INSTALLATION
+
+Installation procedures depend on the system.  Please read the CK?INS.TXT,
+if any, file for your system (?=U for UNIX, V for VMS, etc).  Please note
+the naming and placement for the initialization files:
+
+  CKERMIT.INI
+    The standard initialization file.  Please leave it as is unless you
+    know what you are doing and (if you are changing it or replacing it
+    for others to use) you are prepared to support it.  Rename this file
+    to .kermrc in UNIX, OS-9, BeBox, or Plan 9.  In Stratus VOS, rename
+    it ckermit.ini (lowercase).  On multiuser systems, it goes either in the
+    (or EACH) user's home (login) directory, or else in a common shared
+    place if C-Kermit has been configured to look in that place (see
+    ckccfg.txt for details).
+
+  CKERMOD.INI
+    A *sample* customization file.  On multiuser OS's, a copy of this file
+    goes in each user's home directory, and then each user edits it to suit
+    her needs and preferences; e.g. by defining macros for their common
+    connections.
+
+  DIALING DIRECTORIES
+    Dialing directory files can be system-wide, per-group, or per-user, or
+    any combination.  For example, there can be a corporate wide directory
+    shared by all users, a supplemental directory for each division or
+    department, and a personal directory for each user.  Simply be sure the
+    dialing directory files are identified a SET DIAL DIRECTORY command in
+    the user's (or the system-wide) C-Kermit initialization file, or in the
+    environment variable (logical name, symbol) K_DIAL_DIRECTORY.  (The
+    standard initialization file looks by default in the user's home or login
+    directory.)  When installing C-Kermit on multiuser platforms from which
+    users will dial out, you can also set environment variables for area
+    code, country code, and the various dialing prefixes as described on page
+    478 of "Using C-Kermit" (second edition), so users don't have to worry
+    about defining these items themselves.   Network directories and service
+    directories can also be set up in a similar manner.
+
+  DOCUMENTATION
+    In UNIX, the general C-Kermit man page (or one of the versions tailored
+    for a specific platform, like HP-UX or Solaris) should be installed in
+    the appropriate place.  In VMS, the VMS help topic (CKVKER.HLP) should
+    be installed as described in CKVINS.TXT.  Plain-text documentation such
+    as CKERMIT2.TXT should be put in whatever place people are accustomed
+    to looking.
+
+FILES AND FILE NAMING CONVENTIONS
+
+C-Kermit is a family of Kermit programs for many different computer systems.
+The program shares a common set of system-independent file transfer protocol
+modules, written in the C language.  System-dependent operations are collected
+into system-specific modules for each system.
+
+C-Kermit file names all start with the letters "CK", followed by a single
+letter indicating the subgroup.  When referring to these files in the UNIX,
+AOS/VS, or VOS environments, use lowercase letters, rather than the uppercase
+letters shown here.  Subgroups:
+
+  _: Security/Authentication/Encryption code, possibly regulated by law
+  a: General descriptive material and documentation
+  b: BOO file encoders and decoders (obsolete)
+  c: All platforms with C compilers
+  d: Data General AOS/VS
+  e: Reserved for "ckermit" files, like CKERMIT.INI, CKERMIT80.TXT
+  f: (reserved)
+  g: (reserved)
+  h: (reserved)
+  i: Commodore Amiga (Intuition)
+  j: (unused)
+  k: (unused)
+  l: Stratus VOS
+  m: Macintosh with Mac OS
+  n: Microsoft Windows NT
+  o: OS/2 and/or Microsoft Windows 95/98/ME/NT/2000/XP/...
+  p: Bell Labs Plan 9
+  q: (reserved)
+  r: DEC PDP-11 with RSTS/E (reserved)
+  s: Atari ST GEMDOS (last supported in version 5A(189))
+  t: DEC PDP-11 with RT-11 (reserved)
+  u: UNIX or environments with UNIX-like C libraries
+  v: VMS and OpenVMS
+  w: Wart (Lex-like preprocessor, used with all systems)
+  x: (reserved)
+  y: (reserved)
+  z: (reserved)
+  0-3: (reserved)
+  4: IBM AS/400 (reserved)
+  5-8: (reserved)
+  9: Microware OS-9
+
+Examples:
+
+  ckaaaa.txt - This file
+  ckufio.c   - File i/o for UNIX
+  ckstio.c   - Communications i/o for the Atari ST
+  makefile   - makefile for building UNIX C-Kermit
+  ckpker.mk  - makefile for building Plan 9 C-Kermit
+  ckvker.com - build procedure for VMS C-Kermit
+
+IMPORTANT FILES (use lowercase names on UNIX, VOS, or AOS/VS):
+
+  ckaaaa.txt  - This file (overview of the C-Kermit files).
+                For system-specific distributions, this will normally
+                be replaced by a system-specific READ.ME file.
+
+  ckermit70.txt - Updates: Supplement to "Using C-Kermit", 2nd Ed, for 7.0.
+  ckermit80.txt - Updates: Supplement to "Using C-Kermit", 2nd Ed, for 8.0.
+  ckututor.txt  - C-Kermit Tutorial for Unix (plain text)
+  ckcbwr.txt  - "Beware file" (limitations, known bugs, hints), general.
+  ckermit.ini - Standard initialization file (rename to .kermrc in UNIX, OS-9)
+  ckermod.ini - Sample customization file (rename to .mykermrc in UNIX, OS-9)
+
+The following can be found at the Kermit FTP site:
+
+  ckermit.kdd - Sample dialing directory file (rename to .kdd in UNIX, OS-9)
+  ckermit.knd - Sample dialing directory file (rename to .knd in UNIX, OS-9)
+  ckermit.ksd - Sample services directory file (rename to .ksd in UNIX, OS-9)
+  ckedemo.ksc - Demonstration macros from "Using C-Kermit"
+  ckepage.ksc - Ditto
+  ckevt.ksc   - Ditto
+
+UNIX-specific files:
+
+  ckuins.txt - UNIX-specific installation instructions.
+  ckubwr.txt - UNIX-specific beware file.
+  ckuker.nr  - "man page" for UNIX.
+
+VMS-specific files:
+
+  ckvins.txt - VMS-specific installation instructions.
+  ckvbwr.txt - VMS-specific beware file
+  ckvker.hlp - VMS C-Kermit HELP topic (needs updating).
+
+DG AOS/VS-specific files:
+
+  ckdins.txt - Data General AOS/VS C-Kermit installation instructions
+  ckdbwr.txt - AOS/VS "beware" file
+  ckd*.cli   - Procedures for building AOS/VS C-Kermit
+
+The following files are of interest mainly to programmers and historians
+(find them at the Kermit ftp site):
+
+  ckcker.ann - Release announcements.
+  ckccfg.txt - Configuration information (feature selection), general.
+  ckcplm.txt - Program logic manual (for programmers).
+  ckc211.txt - Program update history for edit 201-211.
+  ckc200.txt - Program update history for edit 198-200 (big)
+  ckc197.txt - Program update history for edit 195-197 (big)
+  ckc190.txt - Program update history for edits 189-190 (big).
+  ckc188.txt - Program update history, edits 179-188 (big).
+  ckc178.txt - Program edit history, 5A edits through 178 (very big).
+  ckcv4f.txt - Program edit history, version 4F.
+  ckcv4e.txt - Program edit history, version 4E.
+
+BINARIES
+
+If you have FTP access to kermit.columbia.edu (also known as
+kermit.cc.columbia.edu, ftp.cc.columbia.edu), you can also retrieve various
+C-Kermit binaries from the directory kermit/bin/ck*.*, or more conventiently
+from the web page:
+
+  http://www.columbia.edu/kermit/ck80binaries.html
+
+Test versions would be in kermit/test/bin/ck*.*.  Be sure to transfer these
+files in binary mode.  The READ.ME file in that directory explains what's
+what.
+
+SOURCE FILES
+
+The source files for the UNIX version (all UNIX versions) are available in
+kermit/archives/ckuNNN.tar.Z, approximately 1MB in size.  Transfer this file
+in binary mode.  This is a compressed tar archive.  There is also a gzip'd
+version, cku211.tar.gz.  To get the binary tar archive:
+
+  mkdir kermit                   (at shell prompt, make a Kermit directory)
+  cd kermit                      (make it your current directory)
+
+  ftp kermit.columbia.edu        (make an ftp connection)
+  user: anonymous                (log in as user "anonymous", lower case!)
+  password:                      (use your email id as a password)
+  cd kermit/archives             (go to the archives directory)
+  type binary                    (specify binary file transfer)
+  get cku211.tar.Z               (get the tar archive) (or get cku192.tar.gz)
+  bye                            (disconnect and exit from ftp)
+
+  uncompress cku211.tar.Z        (at the shell prompt, uncompress the archive)
+  tar xvf cku211.tar             (extract the files from the tar archive)
+  make xxx                       (build C-Kermit for your system)
+
+(where "xxx" is the makefile entry appropriate for your system.)
+
+All C-Kermit source and other text files are also kept separately in the
+kermit/f directory.  The files necessary to build a particular implementation
+of C-Kermit are listed in the appropriate makefile or equivalent:
+
+       UNIX: makefile (or rename ckuker.mak to makefile)
+   2.11 BSD: ckubs2.mak (rename to makefile), ckustr.sed
+     Plan 9: ckpker.mk  (rename to mkfile)
+  Macintosh: ckmker.mak (rename to kermit.make, use MPW C 3.2)
+        VMS: CKVKER.COM (DCL) (and optionally also CKVKER.MMS)
+             or CKVOLD.COM (for VMS 4.x)
+      Amiga: CKIKER.MAK (Aztec C) or CKISAS.MAK (SAS C)
+   Atari ST: CKSKER.MAK
+       OS-9: ck9ker.mak or ck9ker.gcc
+     AOS/VS: ckdmak.cli, ckdcc.cli, ckdlnk.cli
+Stratus VOS: cklmak.cm
+
+Minimal source files for building selected versions (these patterns get all
+the files you need, and in some cases maybe a few extra):
+
+   UNIX:   ck[cuw]*.[cwh]  (including QNX, Plan 9, and BeBox)
+   UNIX:   ck[cuw_]*.[cwh] (Unix with security modules)
+   VMS:    ck[cuwv]*.[cwh]
+   Mac:    ck[cuwm]*.[cwhr]
+   AOS/VS: ck[cuwd]*.[cwh]
+   VOS:    ck[cwhl]*.[cwh]
+   Amiga:  ck[cuwi]*.[cwh]
+   Atari:  ck[cuws]*.[cwh]
+   OS-9:   ck[cuw9]*.[cwha]
+
+For a detailed, specific source file list for this C-Kermit release, see the
+file ckcxxx.txt, where xxx is the current C-Kermit edit number, such as 211.
+
+Finally, here is a more detailed description of the C-Kermit file naming
+conventions.  A C-Kermit filename has the form:
+
+  CK<system><what>.<type>
+
+where:
+
+<system> is described earlier in this file;
+
+<type> is the file type (use lowercase on UNIX, VOS, or AOS/VS):
+
+  c:   C language source
+  h:   Header file for C language source
+  w:   Wart preprocessor source, converted by Wart (or Lex) to a C program
+  r:   Macintosh resource file (8-bit text)
+  a:   Assembler source
+
+  txt: Plain text.
+  nr:  Nroff/Troff text formatter source for UNIX "man page"
+  mss: Scribe text formatter source
+  ps:  Typeset material to be printed on a PostScript printer
+  hlp: A VMS Help topic
+
+  ini: Initialization file
+  ksc: A Kermit Script to be executed by the TAKE command
+  kdd: A Kermit Dialing Directory
+  knd: A Kermit Network Directory
+  ksd: A Kermit Services Directory
+
+  mak: A Makefile or other build procedure (often needs renaming)
+  com: (VMS only) a DCL command procedure
+  cli: (AOS/VS only) a command procedure
+  cmd: (OS/2 only) a Rexx command procedure
+
+  boo: "boo"-encoded executable program, decode with CKBUNB program.
+  hex: "hex"-encoded executable program, decode with CKVDEH program (VMS only).
+  hqx: BinHex'd Macintosh Kermit program, decode with BinHex version 4.0.
+  uue: A uuencoded binary file, decode with uudecode or (DG only) CKDECO.
+
+  def: An OS/2 linker definitions file.
+  sh:  A UNIX shell script.
+  sed: A UNIX sed (editor) script.
+  str: A file of character strings extracted from C-Kermit (BSD 2.1x only).
+
+<what> is mnemonic (up to 3 characters) for what's in the file:
+
+NOTE: After C-Kermit 6.0, text filetypes such as .DOC and .HLP were changed
+to .TXT to avoid confusion in Windows-based Web browsers, which would
+otherwise mistake them for Microsoft Word or Windows Help documents.
+
+  aaa: A "read-me" file, like this one
+  ins: Installation instructions or procedures
+  bwr: "Beware" file -- things to watch out for, hints and tips
+  plm: Program Logic Manual
+  ker: General C-Kermit definitions, information, documentation
+
+  nnn: Digits: C-Kermit edit number (e.g. cku211.tar.gz)
+  cmd: Command parsing
+  con: CONNECT command
+  cns: CONNECT command (UNIX only - version that uses select(), not fork())
+  deb: Debug/Transaction Log formats, Typedefs
+  dia: Modem/Dialer control
+  fio: System-depdendent File I/O
+  fns: Protocol support functions
+  fn2: More protocol support functions (and FN3, ...)
+  lib: Common library routines module
+  mai: Main program
+  net: Network i/o module
+  pro: Protocol
+  scr: SCRIPT command
+  tel: Telnet protocol module
+  tio: System-dependent communications i/o & control and interrupt handing
+  sig: Signal handling module
+  usr: Interactive/script user interface
+  us2: More user interface (mainly help text)
+  us3: Still more user interface (and USR4, USR5, USR6, USR7)
+  usx: Common user interface functions
+  usy: Command-line parsing
+  xla: Character set translation module
+  uni: Unicode support
+  pty: Pseudoterminal support
+  mdb: Malloc-debugging module (not included in real builds)
+  str: Strings module (only for 2.xBSD)
+
+(End of ckaaaa.txt)
diff --git a/ckermit-8.0.211/ckc211.txt b/ckermit-8.0.211/ckc211.txt
new file mode 100644
index 0000000..1886725
--- /dev/null
+++ b/ckermit-8.0.211/ckc211.txt
@@ -0,0 +1,3595 @@
+C-KERMIT CHANGE LOG (Changes since 8.0.200 of 12 Dec 2001)
+
+Chronological order: Go to the bottom to find the newest edits.
+
+---8.0.200---
+
+Known bugs (+ = fixed after release):
+
+ + 1. tilde_expand() can call getcwd() with NULL arg.
+ + 2. getexedir() called too early (fatal in combination with (1)).
+ + 3. Kermit "get blah" where blah is a symlink; server refuses to send it.
+      Should not do this if GET not recursive.
+ ? 4. Dave Sneddon's report about VMS fore/background confusion.
+ + 5. FTP GET path/file doesn't work - path not stripped - but MGET works.
+ + 6. IRIX 5.3 compilation problems (have patches from Marcus Herbert)
+ X 7. Filename completion bug (see below) (deferred).
+ + 8. QNX6 herald and other problems.
+
+-------------
+
+Merged Jeff's changes, 20 Dec 2001:
+
+ . Changed all occurrences of "ttnproto == NP_TELNET" to "IS_TELNET()" to
+   account for the difference between SSH and Telnet.  ckuscr.c,
+   ckuus[3457].c, ckcnet.h, ckcfns.c, ckudia.c, ckutio.c, ckucon.c, ckucns.c.
+
+ . Moved SSH pty failure warnings.  ckuusr.c.
+
+ . Security adjustments to FTP module, plus fix an error message.  ckcftp.c.
+
+ . Adjustment of some security-related #ifdefs. ckcdeb.h, ckuus2.c, ckctel.c.
+
+ . Guard against calling getpwnam() with a NULL arg in tilde_expand() ckufio.c.
+ 
+ . Moved getexedir() call to later, where it's safe.  ckcmai.c.
+
+Added SSH ADD and many SSH SET commands from Jeff's spec.  Fixed SHOW SSH
+to not dump core if variables weren't set.  ckcker.h, ckuus[r3].c, 20 Dec 2001.
+
+C-Kermit in server mode, client says "get foo" where foo is a symlink.
+Server says "no files meet selection criteria" instead of sending the file.
+It should only refuse to follow symlinks if it's a recursive get.  Fixed
+in sgetinit(): ckcpro.w, 21 Dec 2001.
+
+More work on SSH and SET/SHOW SSH commands.  ckuus[r3].c, 21 Dec 2001.
+
+Undid Jeff's replacement of the SSH pseudoterminal allocation failure
+message, because now it comes out any time an SSH command has to be
+reparsed (in the non-SSHBUILTIN case).  ckuusr.c, 21 Dec 2001.
+
+More SSH and SET SSH command work back & forth with Jeff, plus Jeff added
+SET HOST /NET:SSH.  ckcmai.c, ckuus[r37].c, ckcdeb.h, ckuusr.h, 22 Dec 2001.
+
+Added SSH OPEN switches.  ckuusr.c, 22 Dec 2001.
+
+Added SSH CLEAR, HELP SSH, and HELP SET SSH.  ckuus[r2].c, 23 Dec 2001.
+
+From Jeff:
+ . SET TCP commands now apply to SSH
+ . SSH V2 REKEY and FORWRD-{LOCAL,REMOTE}-PORT  commands now implemented
+ . Missing DLLs automatically disable appropriate authentication mechanisms.
+ckuusr.c ckcnet.c ckuus3.c ckcmai.c ckcnet.h ckuus4.c, 26 Dec 2001.
+
+From Jeff:
+ . Remove SET SSH KEEPALIVES.
+ . Add help text for SSH AGENT { ADD, DELETE, LIST }.
+ckuus[23].c, 28 Dec 2001.
+
+Added parsing for SSH AGENT { ADD, DELETE, LIST }.  ckuusr.c, 28 Dec 2001.
+
+From Jeff:
+ . Fixed a crash that can happen when making an SSH connection.
+ . Filled in SSH AGENT actions.
+ . Changed default for strict host key check (to ASK) and help text.
+ . uploaded new binaries include ~kermit/os2test/beta/ssh-agent.exe
+ . Read man ssh-agent on ftp.kermit.columbia.edu for details on what it does.
+ckuus[r23].c, 28 Dec 2001.
+
+"ftp get path/filename" didn't work; the FTP client did not strip the path
+from the local copy of the filename when doing a GET, even though it did
+for MGET.  Diagnosis: in doftpget(), the "if (!getone && !skipthis)" statement
+lacked an "else" part for the getone case.  ckcftp.c, 28 Dec 2001.
+
+A while back Jeff reported that in FTP MGET, if you cancel a file with 'x',
+all the rest of the files arrive truncated to 0 bytes.  I tried this on both
+Unix and Windows and couldn't reproduce it.
+
+In the last-minute flurry to release C-Kermit 8.0, I thought I noticed the FTP
+client failing to update the fullscreen file-transfer display.  But it seems
+to work right, at least in Unix.  When downloading a big file with FTP, all
+the display fields are updated as expected.  But smaller files might go by too
+fast for the display to do anything.  HOWEVER, in K95 the file transfer
+display does not update itself until the end of the file, even if the file
+takes a long time to transfer.  This happens in both the Console and GUI
+versions.  A thread thing?  (Jeff says no.)  Yet the same display works fine
+on Telnet connections.
+
+In IRIX 5.3, the select()-based CONNECT module had to include <sys/time.h>
+or else it blew up with "struct timeval" unknown.  Since there already was
+a SYSTIMEH CFLAG, I added the #include within #ifdef SYSTIMEH..#endif and
+rebuilt with KFLAGS=-DSYSTIMEH, only to discover that the irix5* targets
+didn't bother to propogate KFLAGS.  Fixed in ckucns.c, makefile, 30 Dec 2001.
+
+Increased IRIX5x Olimit from 2400 to 3000 because of ckuus[34].c.  Added
+-ansi, since (Marcus Herbert reported) we were not actually getting ANSI-C
+compilation even though CK_ANSIC was defined.  But now that we are, we get
+warnings in <netinet/tcp.h>, which is included by ckcnet.h:
+
+  bit-field 'th_off' type required to be int, unsigned int, or signed int.
+  (3.5.2.1(30))
+	  u_char  th_off:4,
+	  ------  ^
+Tough.  makefile, 30 Dec 2001.
+
+But adding -ansi to the IRIX 5x targets also make compilation bomb whenever we
+referenced fdopen() or popen(), which evidently don't have prototypes in any
+of the header files.  Luckily we already have CFLAGS for this occasion too:
+DCLFDOPEN and DCLPOPEN.  Added these to the irix51 target.  Also had to copy
+the fdopen()-popen() prototype section to ckuusx.c, which has a new reference
+to fdopen() in a workaround for the curses console buffering bug.  makefile,
+ckuusx.c, 30 Dec 2001.
+
+The QNX6 version did not receive a proper herald (it announced itself as
+"unknown version".  Reshuffled #ifdefs in ckuver.h, added display of QNX6
+and NEUTRINO symbols to ckuus5.c, 30 Dec 2001.
+
+Lucas Hart sent in a patch for the VMS problem.  Apparently it was even worse
+than Dave Sneddon had reported: 8.0 couldn't run at all under Batch.  ckvtio.c,
+31 Dec 2001.
+
+A major obstacle to the usability of the FTP client is that certain commands
+don't behave as FTP users expect: CD, DIR, DELETE, MKDIR, etc, which are local
+rather remote, and there are no LCD (etc), USER, or ACCOUNT commands.  We
+could fix this by adding an FTP command-language personality, but file
+management commands can also be remote or local on connections to Kermit
+servers too.  So:
+
+SET LOCUS { LOCAL, REMOTE, AUTO }
+  Sets the locus for unprefixed file management commands.
+  When LOCAL, a REMOTE (or R) prefix is required for
+  to send file management commands to a remote server (e.g. RCD, RDIR).
+  When REMOTE, an L prefix is required to issue local file management
+  commands (e.g. LCD, LDIR).  The word LOCAL can't be used as a prefix
+  since it is used for declaring local variables.
+
+This applies to all types of connections, and thus is orthogonal to SET
+GET-PUT-REMOTE, which selects between Kermit and FTP for remote file-transfer
+and management commands.
+
+The default LOCUS is AUTO, which means we switch to REMOTE whenever an FTP
+connection is made, and to LOCAL whenever a non-FTP connection is made,
+and switch back accordingly whenever a connnection is closed.
+
+Implementation (31 Dec 2001):
+ . None of this is compiled if LOCUS is not defined.
+ . Added XYLOCUS (SET LOCUS) and LOCUS definitions: ckuusr.h.
+ . Override by defining NOLOCUS (which inhibits definition of LOCUS).
+ . Added LOCUS to SET keyword table: ckuusr.c.
+ . Added locus & autolocus variables: ckuusr.c.
+ . Added SET LOCUS parsing and variable setting: ckuus3.c.
+ . Added display of LOCUS setting to SHOW COMMAND: ckuus5.c.
+ . Added automatic locus setting to setlin(): ckuus7.c.
+ . Added automatic locus setting to ftpopen() and ftpclose(): ckcftp.c.
+
+How to catch all the places where a Kermit connection is closed?  Turns out
+we've done this before, when we added the connection log.  So I made
+dologend() take care of locus switching.  But dologend() was not compiled in
+if certain symbols were defined, such as NOLOCAL, or not defined, such as
+CKLOGDIAL.  So I (a) rearranged the #ifdefs so that even if these would
+otherwise have obliviated dologend(), now they leave a piece of it for
+locus-setting; (b) moved the prototype out of #ifdefs; and (c) took all calls
+to it out of #ifdefs.  ckcker.h, ckcfn2.c, ckcmai.c, ckucns.c, ckucon.c,
+ckuus[r347x].c, 31 Dec 2001.
+
+Added locus checking to the following commands: DIRECTORY, CD/CWD, CDUP,
+DELETE, PWD, MKDIR, RMDIR, RENAME.  ckuusr.c, 31 Dec 2001.
+
+Added LDIRECTORY, LCD/LCWD, LCDUP, LDELETE, LPWD, LMKDIR, LRMDIR,
+LRENAME.  ckuusr.[ch], 31 Dec 2001.
+
+Added USER and ACCOUNT commands, which are the same as FTP USER and FTP
+ACCOUNT.  ckuusr.[ch], ckcftp.c, 31 Dec 2001.
+
+Since automatic locus switching could be a big surprise for most people, I
+printed message any time it changed.  ckcftp.c, ckuus[37].c, 31 Dec 2001.
+
+Added help text for the new L commands and filled in missing HELP text for
+SET GET-PUT-REMOTE, CDUP, MKDIR, and RMDIR.  ckuus2.c, 31 Dec 2001.
+
+Changed help text of CD, DIR, etc, for LOCUS.  Changed the help text for
+RCD, RPWD, RDEL, RDIR, etc, to mention that they also work with FTP servers.
+Updated HELP REMOTE for this too.  ckuus2.c, 31 Dec 2001.
+
+Made sure code builds with NOLOCAL, NOLOGDIAL, and NOLOCUS (it does).
+
+The IKSD command, when given with a /USER: switch, sends the user ID to the
+IKSD.  But the SET HOST /USER: command does not, when making a connection to a
+Kermit service.  This makes it impossible to script IKSD interactions using
+only client commands.  Furthermore, even if you include a /PASSWORD switch
+with the IKSD command, it does not send the password.  I added code near the
+bottom of setlin() to do this.  If we have a connection to a Kermit service
+and a /USER: switch was given, then we attempt a REMOTE LOGIN.  If a
+/PASSWORD: switch was not given then if the username is "ftp" or "anonymous",
+we automatically supply a password of user@host; otherwise we prompt for a
+password.  If a /USER: switch was not given, it acts like before.  It all
+works, but it might not be the best way (or place) to do it.  setlin():
+ckuus7.c, 31 Dec 2001.
+
+  NOTE: The above change doesn't help with IKSD /USER:anonymous,
+  the server prompts for password anyway, not sure why.
+
+  NOTE 2: What about secure authentication?  We have to test to see
+  if user was already authenticated before sending the login packet.
+
+Added /opt/kermit and /opt/kermit/doc to info_dir[] list (for Solaris).
+ckuus5.c, 31 Dec 2001.
+
+From Jeff: new Help text for SET TERM FONT (K95 GUI).  ckuus2.c, 1 Jan 2002.
+
+More work on help text for file management commands -- e.g. we can't lump
+the L-commands together with the unprefixed ones; they need separate entries.
+Also: added missing HELP REMOTE PWD, improved the default case (in which
+help text had been omitted for a valid command).  ckuus2.c, 1 Jan 2002.
+
+It seems VMS C-Kermit was pretty much ignoring the -B (force background) and
+-z (force foreground) command-line options.  Fixed in congm(): ckvtio.c,
+1 Jan 2002.
+
+Tested the SET LOCUS business with VMS C-Kermit, which does not have a
+built-in FTP client.  Of course in this case there is no automatic locus
+switching, but SET LOCUS REMOTE works nicely on IKSD connections.
+
+From Jeff:
+ . #ifdef adjustments for LOCUS changes.
+ . SSH KEY CREATE /TYPE:SRP.
+ . Fix \v(serial) to not be 8N2 by default if speed is 0.
+ . Don't let doexit() run if sysinit() hasn't been called first.
+ckuus[r247x].c, 2 Jan 2002.
+
+Made SET BACKGROUND { ON, OFF } do exactly the same as -B and -z options.
+ckuus3.c, 2 Jan 2002.
+
+Updated user-visible copyright dates to 2002 (but still need to do all the
+source-module comments).  ckcmai.c, ckuus[25].c, 2 Jan 2002.
+
+Rearranged #include <sys/time.h> in ckucns.c that was done for IRIX 5.3,
+to avoid conflicts in SV/68 R3v6.  3 Jan 2002.
+
+From Dave Sneddon: Code changes in VMS sysinit() and congm() to work around
+problems in batch, SPAWN'd, etc, and change CTTNAM from TT: to SYS$INPUT:.
+ckcdeb.h, ckvtio.c, 3 Jan 2002.
+
+From Jeff:
+ . Fixed typo in definition of CTTNAM for VMS.  ckcdeb.h
+ . Moved macro definitions for SSHBUILTIN from ckuus3.c to ckuusr.h
+   so they can be referenced in ckuus7.c
+ . Added SSH functionality to SET HOST:
+     SET HOST /NET:SSH /CONNECT hostname [port] /switches
+ . Fixed SET NET TYPE so it won't reject SSH if SSH is installed.
+ . Changes to allow IKSD to continue functioning.  Somehow this minor change
+   to ckcmai.c got lost in one of the back and forth exchanges.
+ . HELP TEXT for UCS2 kverb
+ . Fix a problem in K95 where multiple threads could be attempting to
+   send a telnet negotiation simultaneously.
+ckcmai.c ckcdeb.h ckuus2.c ckuus3.c ckuusr.c ckuusr.h ckuus7.c ckctel.c
+ck_crp.c ckuat2.h ckuath.c, 4 Jan 2002.
+
+From Jeff:
+
+  Peter Runestig complaining that the Telnet Forward X code was corrupting
+  data.  This resulted in a very thorough examination of the telnet module
+  code and a discovery of some rather significant problems.  The root of the
+  problems is the lack of thread safety.  To correct this problem the
+  following was done.
+
+  All code (regardless of module) which outputs telnet commands is placed
+  into a mutex region to ensure that competing output threads do not result
+  in interleaving their output.  This could happen for instance when the
+  forward-x thread is forwarding data and the user changes the window size
+  or sends an AYT or BREAK.  Next the buffer used for input and output
+  processing were identical.  This means that output data could be treated
+  as input or vice versa.  Ugh....
+
+  I also spent some more time cleaning up setlin().  Mostly reorganizing the
+  code into single if (...) blocks so that breaking it up will be easier.
+
+ckctel.c ckuus7.c, 4 Jan 2002.
+
+Updated internal copyright notices.  All modules, 5 Jan 2002.
+
+From Jeff:
+  More of same, plus new makefile target and changes from Spike Gronim
+  for freebsd44+srp+openssl.
+ckcdeb.h ckcnet.c ckctel.c ckuus7.c ck_ssl.c makefile, 5 Jan 2002.
+
+Some minor updates and fixes to SSH and SET SSH help text.
+ckuus2.c, 6 Jan 2002.
+
+Added SET RGB-COLORS for GUI.  ckuusr.[ch], ckuus3.c, 6 Jan 2002.
+
+From Jeff: More Telnet changes, Debug semaphores for K95, etc: ckcdeb.h,
+ckuusr.h, ckuus[r35x].c, ckctel.[ch], ckuath.c, 7 Jan 2002.
+
+Added --xpos:n --ypos:n, SET GUI WINDOW POSITION x y, and changed SET
+RGB-COLORS to SET GUI RGBCOLOR.  Action needs to be filled in (in setguiwin()
+in ckuus3.c), and gui_xpos and gui_ypos need to be defined in cko???.c.
+ckuusr.h, ckuus[r3y].c, 7 Jan 2002.
+
+Added --fontname:name --fontsize:name (and facename as synonym for fontname).
+ckuusr.h, ckuus[7y].c, 7 Jan 2002.
+
+Moved GUI (not OS/2) SET TERM FONT code in ckuus7.c to its own routine,
+setguifont(), in ckuus3.c, and made GUI SET TERM FONT call this routine,
+and also made SET GUI FONT call the same routine.  ckuus[37].c, 7 Jan 2002.
+
+Added --termtype:, --height:, --width:, --user:.  Also added symbols for
+--telnet:, --ssh:, --ftp:, --[remote-]charset, and --password:, but didn't
+fill them in.  --password: is probably not a good idea (but we allow it for
+FTP); the others involve a lot of code-shuffling and reconciliation, which
+I'll try to do when I get a chance (especially the connection ones, which
+can be done as part of the setlin() restructuring).  ckuusr.h, ckuusy.c,
+8 Jan 2002.
+
+Also I tried commenting out the #ifndef KUI..#endif's around SET TERMINAL
+CHARACTER-SET (easier said than done because a crucial #endif was mislabeled).
+Let's see if it compiles & works...  ckuus7.c, 8 Jan 2002
+
+Added FTP [ OPEN ] /NOINIT, meaning don't send REST, STRU, and MODE commands
+upon making an FTP connection.  This allows connection to servers that close
+the connection (or worse) when given these commands (e.g. Linux 2.4 TUX 2.0
+FTP server).  ckcftp.c, 8 Jan 2002.
+
+Looked at adding caller ID support for the ANSWER command:
+
+ . SET ANSWER CALLER-ID { ON, OFF }
+ . SET ANSWER RINGS <number>
+ . \v(callid_xxx) xxx = { date, time, name, nmbr, mesg }
+ . CKD_CID modem capability
+ . Set CKD_CID for modems that have it.
+ . A quick survey shows:
+   - USR V.90:      No (but Jeff says some USRs have it).
+   - V.250:         No
+   - Lucent Venus:  No
+   - USR:           #CID=1 (the ones that have it -- X2?)
+   - Diamond Supra: #CID=1
+   - Rockwell 56K:  #CID=1
+   - PCTEL:         #CID=1
+   - Zoltrix:       +VCID=1
+   - Conexant:      +VCID=1
+ . Since there are different commands to enable caller ID reporting,
+   we need a new field in struct MDMINF.
+ . SHOW MODEM and SHOW DIAL would need updating.
+ . etc etc...
+
+This is all way too much for now so I just did the setting of the \v(callid_*)
+variables.  These are reset at the beginning of an ANSWER command, and then
+set by the ANSWER command if they come in; thus they persist from the time
+they are collected until another ANSWER command is given.  To take advantage
+of autoanswer, the user has to enable it in the modem (all the modems I found
+that support it have it disabled by default), and also has to set the number
+of rings to at least 2.  This can be done with (depending on the modem):
+
+  set modem command autoanswer on ATS0=2#CID=1\{13}
+  set modem command autoanswer on ATS0=2+VCID=1\{13}
+
+and undone with:
+
+  set modem command autoanswer on ATS0=1#CID=0\{13}
+  set modem command autoanswer on ATS0=1+VCID=0\{13}
+
+The variables can be accessed only after the call is answered.  Therefore the
+only way to refuse a call is to answer it, inspect the variables, and then
+hang it up if desired.  Future Kermit releases can do this more nicely (as
+sketched out above.)  Also while I was in the dialing code, I added result
+code VCON (= VOICE), used by several of the newer modems.  These changes are
+untested.  The SET ANSWER command is written but commented out.  ckuusr.h,
+ckcker.h, ckuus[r3].c, ckudia.c, 8 Jan 2002.
+
+From Jeff: fixes to --termtype:, --height:, --width:, --user:, and filling in
+of --rcharset:, which required extracting code from settrm() into a separate
+parse-method-independent remote character-set setting routine.  ckuus[7y].c,
+8 Jan 2002.
+
+From Jeff: More work on TERMINAL CHARACTER-SET code reorganization, and
+reinstatement of SET TERMINAL CHARACTER-SET in K95G.  Also, fix char/CHAR
+warnings in Telnet module.  ckuus7.c, ckctel.c, 9 Jan 2002.
+
+Made SET TERM CHARACTER-SET visible for all builds, including K95G, and filled
+in HELP text for it.  ckuus[27].c, 9 Jan 2002.
+
+Added help text for new extended options.  ckuusy.c, 9 Jan 2002.
+
+Commented out the return(-2) statement at the end of xgnbyte() to make the
+"Statement not reached" errors go away, after checking to make sure that there
+was no path that could fall through to the end.  I'm 99.99% sure there isn't,
+but that doesn't mean that some compilers might not still complain.  ckcfns.c,
+9 Jan 2002.
+
+From Jeff: fix typo in the K95 extended-option help text; add more
+semaphores to network i/o.  ckuusy.c, ckcnet.c, 10 Jan 2002.
+
+Undid ansiisms in set{lcl,rem}charset() declarations.  ckuus7.c, 10 Jan 2002.
+
+Removed a duplicated clause from the install target.  makefile, 10 Jan 2002.
+
+From Jeff: more semaphores.  ckcnet.c, 11 Jan 2002.
+
+Moved references to tmpusrid and tmpstring out of NOSPL #ifdefs -- they can
+be used with NOSPL.  setlin(): ckuus7.c, 13 Jan 2002.
+
+Made a dummy dologend() routine outside of #ifndef NOICP, so we don't have
+to enclose every reference to dologend in #ifdefs.  (I had added a bunch of
+calls to dologend() throughout the code to handle automatic LOCUS switching.)
+ckuus3.c, 13 Jan 2002.
+
+Moved "extern int nettype" outside of NOICP #ifdefs in ckuus4.c for NOICP
+builds.  13 Jan 2002.
+
+Moved a misplaced #ifdef in the VERSION command.  ckuusr.c, 13 Jan 2002.
+
+Did 81 different feature-selection builds on Linux (RH 7.0), all OK after the
+changes listed above for today.  13 Jan 2002.
+
+Added prototypes for set{rem,lcl}charset().  ckcxla.h, 13 Jan 2002.
+
+Added ckcxla.h to dependencies for ckuusy.c.  ckvker.com, 13 Jan 2002.
+
+Made a correction to the HELP SET LOCUS text and supplied a missing comma
+for HELP REMOTE.  ckuus2.c, 13 Jan 2002.
+
+Built OK on HP-UX 11.11 (K&R and ANSI), Solaris 8 (cc), Solaris 2.5.1 (gcc),
+SunOS 4.1.3 (cc and gcc), VMS 7.1 (DEC C, net and nonet), Unixware 7.1.1,
+Tru64 4.0G, HP-UX 10.20 (K&R), AIX 4.3.3, FreeBSD 2.2.8, Slackware 8.0, IRIX
+6.5.13f, IRIX 5.3 (??? Can't tell -- the computer ran out of swap space -- but
+it was OK a few days ago), VMS 5.5-2 (VAX C, UCX + nonet)...  HP-UX 9.05, ...
+
+Some corrections to comments in HP targets from PeterE.  makefile, 14 Jan 2002.
+
+Corrections to prototypes for set{rem,lcl}charset() (VOID, not void) from Jeff.
+ckcxla.h, 14 Jan 2002.
+
+Builds, cont'd...  SINIX 5.42, Red Hat Linux 5.2 on i386, SuSE 7.0 on S/390, 
+Red Hat 7.1 on IA64, QNX 4.25, HP-UX 5.21/WinTCP, ..., 
+
+Dell Coleman <dell@aleph.tum.com> noticed that in AIX, the COPY command always
+says "Source and destination are the same file" when the destination file
+doesn't exist.  This is because in AIX, realpath() fails with ENOENT (errno
+2).  The zfnqfp() code already accounts for this, but evidently not well
+enough.  So I did what I should have done long ago.  zfnqfp() was originally
+accomplished with do-it-yourself code.  Later I added support for realpath(),
+and partitioned the routine into mutually exclusive compile-time sections:
+#ifdef CKREALPATH realpath()... #else do-it-yourself... #endif.  But if
+realpath() failed, there was no recourse to the do-it-yourself code.  Today I
+replaced the #else with the #endif, so the do-it-yourself part is always
+included and is executed if the realpath() call fails.  Built and tested on
+AIX 4.3.3 and Solaris 2.5.1, as well as on Linux with and without the
+realpath() code included.  zfnqfp(): ckufio.c, 16 Jan 2002.
+
+Separated K95 and C-Kermit test version numbers, so C-Kermit can be RC.02
+while K95 is Beta.01.  ckcmai.c, 16 Jan 2002.
+
+Inhibited 0-length writes by conol() and conoll(), since they cause big
+trouble with the AIX 4.3.3 pty driver, e.g. when you have an SSH connection
+into AIX and run C-Kermit there.  ckutio.c, 16 Jan 2002.
+
+Suppressed "Switching LOCUS..." messages from FTP client when it was invoked
+from the command line.  ckcfns.c, 17 Jan 2002.
+
+Dave Sneddon noticed that FOPEN /APPEND gets "?Write access denied" in VMS
+if the file exists.  This is apparently because VMS zchko() does the wrong
+thing.  Commenting out the call zchko() in the VMS case gets past this but
+then the appended part of the file has different attributes than the orignal
+part, e.g.:
+
+  abc  <- original line (horizontal, normal)
+  d    <- appended line (vertical)
+  e
+  f
+
+VMS fopen() takes an optional 4th argument: a series of RMS keyword=value
+pairs.  Kermit doesn't give any.  Experimentation shows that appending to
+a Stream_LF works fine.  That'll be a restriction for now, until somebody
+sends in code to get the RMS attributes of the original file and feed them
+to fopen().  Also need code to fix VMS zhcko() to say whether it's OK to
+append to a file.  ckuus7.c, 17 Jan 2002.
+
+Somebody suggested I could get a working Kermit for Neutrino 2+ by doing the
+QNX6 build on Neutrino itself.  I verified that this can't be done -- at least
+not by me -- since Netutrino 2+ doesn't have a compiler, and we already know
+the version cross-built for it on QNX4 doesn't work.  17 Jan 2002.
+
+From Jeff: SET SSH GSSAPI KEY-EXCHANGE { ON, OFF } parsing, SHOW SSH.
+ckuus3.c, 18 Jan 2002.
+
+PeterE suggested that SET ESCAPE allow 8-bit escape characters because of the
+difficulty in entering Ctrl-\ on European keyboards and the hardship (e.g. to
+EMACS and VI users) of sacrificing another C0 control character.  Like
+everything these days, this turns out to be rather a bigger deal than it would
+seem.  The SET ESCAPE parser calls setcc(), which accepts control characters
+in various formats (literal, ^X notation, or numbers), and gives an error
+return if the value is not 0-31 or 127.  This is changed easily enough to also
+allow numbers between 128 and 255.  But who else calls setcc()?  The commands
+for setting Kermit packet start and end characters.  No big deal, this gives
+people a bit more flexibility in case they need it, but it won't be
+documented.  setcc(): ckuus7.c, 18 Jan 2002.
+
+Since code to display the escape character is scattered all over the place,
+and some of it indexes into an array based on the character value (which would
+now dump core if the escape character was > 128), I put the code in one place,
+a new shoesc() routine in ckuusx.c (which needs to be outside #ifndef NOICP,
+since the CONNECT modules use it even in command-line only builds).  Also
+discovered that this code was indexing into the nm[] array with tt_escape to
+get "enabled" or "disabled", which is no longer appropriate, so fixed this
+too.  ckuusr.h, ckuus[5x].c, 18 Jan 2002.
+
+Made SHOW ESCAPE, SHOW TERM, and the various CONNECT modules call shoesc(),
+and updated HELP SET ESC.  ckuus[25].c, ckucns.c, ck[cuvd9]con.c, 18 Jan 2002.
+
+After all that, it occurred to me that this is a really bad idea for K95,
+with all the confusion about Console code pages, OEM code pages, Windows
+code pages, and Unicode.  But I tried "echo \161" at the K95 prompt and got
+the expected 8-bit character in both the Console version and the GUI, so
+maybe it's OK after all.
+
+Removed the automatic IKSD login code from setlin() since it complicates
+interactive anonymous login.  ckuus7.c, 20 Jan 2002.
+
+An #ifdef clause from Matthew Clarke to avoid "redeclaration of free" error
+when building a curses version of C-Kermit for AIX 2.2.1 on RT PC.  ckuusx.c,
+22 Jan 2002.
+
+Took care of one detail I omitted when adding the 8-bit escape character:
+not stripping the 8th bit before comparing the keyboard char with the escape
+char.  ck[uv]con.c, ckucns.c, 24 Jan 2002.
+
+Started to go through Jeff's changes of the last week but he had run trim -t
+on them, which untabifies, so the diffs were huge.  Retabifying Jeff's files
+only makes matters worse.  So instead of comparing each old and new source
+file in EMACS windows with M-X Compare-Windows like I usually do (which can't
+be told to ignore whitespace), I had to work from the diff -c -b listings.
+In ascending order of size of diffs:
+
+ckcker.h: Add I_AM_SSHSUB definition.
+ckuusr.h: XXLINK and VN_PERSONAL, etc, definitions.
+ckuusy.c: Support for "I Am SSHSUB" invocation.
+ckuus5.c: Support for new K95 directory structure.
+ckcmai.c: Init endianness earlier (K95 TYPE was broken), "I Am SSHSUB" support.
+ckuus7.c: Security #ifdefs, SSH OPEN /PASSWORD, SSHSUB support
+ckcftp.c: <-- SAVE TIL LAST
+ckuus6.c: Add LINK command for K95 on NT.
+ckuus4.c: Support for new K95 directory structure; SSHSUB support
+ckuus3.c: Support for new K95 directory structure; some SSH changes
+ckuus2.c: Changes to SSH related help text, add HELP LINK text
+ckuusr.c: LINK command, SSH OPEN /PASSWORD: /SUBSYSTEM: switches,
+  Pattern-management fixes.
+ckctel.c, ck_ssl.c, ckuath.c, ckcnet.c:
+ Took Jeff's without looking.
+ckuusx.c, ckucns.c, ckucon.c, ckwart.c:
+  My changes from weeks ago that were never picked up.
+
+Built OK on Solaris with gcc and on SunOS with (K&R non-ANSI) cc.
+31 Jan 2002.
+
+Meanwhile, Jeff had made various changes in response to Jaya Natarajan at IBM,
+whose basic complaint was that numerous failure conditions were not being
+detected if the fullscreen file-transfer display was active.  Jeff found that
+this was because big blocks of code were skipped in that case and changed the
+code not to do that, which fixed the reported problems.  But later Jaya said
+that "ftp mget file1 file2" acted like "ftp mget *", so it seemed that Jeff's
+fixes broke file selection.  After taking Jeff's fixes for ckcftp.c, however,
+I still could not reproduce the problem.  ckcftp.c, 31 Jan 2002.  <-- Later,
+it turned out the problem was with IBM's custom FTP server.
+
+Fixed updates that I missed yesterday in ckcftp.c, ckuusr.c.  Moved misplaced
+#ifdef in ckuusy.c breaking nonet builds.  Added #ifdefs to sysinit() for
+nonet builds in ckutio.c.  Ran through build-in-many-configurations script
+in Linux, all builds OK.  1 Feb 2002.
+
+Moved shoesc() definition outside of NOXFER to fix NOXFER builds.
+ckuusx.c, 1 Feb 2002.
+
+Added MYCUSTOM definition alongside KERMRC and changed KERMCL to be the
+same as CKMAXPATH, instead of some random hardwired number.  ckuusr.h,
+1 Feb 2002.
+
+Changed ckcdeb.h to define DIRSEP and ISDIRSEP(), and put #ifndef
+[IS]DIRSEP..#endif around all [IS]DIRSEP definitions in ck[udso]fio.c, so we
+can finally put away the many repeated #ifdef chains when we get around to it.
+1 Feb 2002.
+
+Make VMS zkermini() return 1 on success, 0 on failure, rather than 0 always.
+ckvfio.c, 1 Feb 2002.
+
+Added code to doinit(), just before it goes to execute the init file.  If the
+init file name we are about to open is empty or fails zchki(), substitute the
+customization filename.  For now this code is in #ifdef USE_CUSTOM..#endif,
+which is not defined by default.  It does the trick in Unix and VMS.  Also
+included code from Jeff for K95, but this needs verification and testing.
+Also used DIRSEP and ISDIRSEP() throughout doinit() instead of the long #ifdef
+chains.  ckuus5.c, 1 Feb 2002.
+
+Moved shoesc() prototype from ckuusr.h to ckcker.h so modules that need it
+don't have to include ckuusr.h just for this one thing (example: ckvcon.c).
+1 Feb 2002.
+
+Defined USE_CUSTOM by default, except if NOCUSTOM is defined.  ckuusr.h,
+1 Feb 2002.
+
+Fixed kermit-sshsub code to really enter server mode, and to print
+"KERMIT READY TO SERVE..." so scripts can wait for it.  Also bumped the
+C-Kermit test ID to RC.03 and the K95 one to Beta.02.  ckcpro.w, ckcmai.c,
+2 Feb 2002.
+
+I was thinking about adding SET COMMAND BUFFER-SIZE to let people allocate
+as big a buffer as they wanted at runtime, mainly for defining huge macros.
+Moved the SCMD_blah definitions from ckuusr.h to ckuus3.c, since they aren't
+used anywhere else.  But stopped there since the rest turns out to be a rather
+big deal.  ckuusr.h, ckuus3.c, 2 Feb 2002.
+
+From Jeff, 3 Feb 2002:
+ . Fix an out-of-order modem name in the SET MODEM TYPE table: ckudia.c.
+ . Use SET LOGIN USER and PASSWORD if present. ckcftp.c.
+
+Cody Gould noticed that array declarations had become case sensitive, and
+upper case didn't work.  Diagnosis: misplaced case conversion in xarray().
+Fixed in ckuus5.c, 4 Feb 2002.
+
+SHOW VAR dumps core on \v(sexpression) or \v(svalue) -- failure to check for
+NULL pointer.  I wonder why this didn't happen before (answer: because I was
+doing it on SunOS; now I'm doing it on Solaris).  ckuus4.c, 6 Feb 2002.
+
+I've had several requests for "show var name name name...".  I added this to
+doshow(), such that SHOW VAR works exactly as it did before (if you don't give
+it an arg, it lists all variables; if you give it an arg, it appends "*" to it
+and lists all matching variables) but now you can also give more than one arg
+and it works the same way with each one as it did before if you gave it a
+single item (i.e., "*" is appended, so "show var os cmd" shows all variables
+whose names begin with "os" or "cmd".  You can also freely use pattern
+notation, including anchors.  Hmmm, no, actually it's different in that now
+each includes an implied * before AND after, so "show var version" shows all
+variables whose name contain "version" rather than all variables whose names
+start with it.  ckuus5.c, 6 Feb 2002.
+
+Cody Gould reported that WRITE FILE blah blah \fexec(anything) ... got a
+spurious "File or Log not open" error.  This turns out to be a rather
+pervasive problem -- whenever you use \fexec() it calls the parser recursively
+and this can run roughshod over global variables, such as our innocent little
+x, y, and s.  The fix in this case was to put x and y on the stack.  The same
+thing probably needs doing in about 10,000 other places.  Too bad C isn't
+Algol.  ckuusr.c, 6 Feb 2002.
+
+Minor fix to SHO VAR -- the "^" anchor wasn't working (e.g. "show var ^os").
+ckuus5.c, 6 Feb 2002.
+
+Fixes from Jeff for FTP file-transfer character-set translation in K95 and
+in WIKSD, plus updated K95 SSH help text.  ckcftp.c, ckcfns.c, ckuus2.c,
+7 Feb 2002.
+
+Server has its date set in the past.  Client says "remote dir".  Server sends
+A packet containing old date.  If client has FILE COLLISION UPDATE, it
+rejects the directory listing.  Changed gattr() to only reject real files
+(introduced by F packet), not X-packet material like directory listings.
+ckcfn3.c, 7 Feb 2002.
+
+Up-down arrow keys for command recall.  People have been asking for it for
+years but now it's actually important because of PDAs that don't have Ctrl
+keys.  Would have been trivial except that we use getchar() rather than
+coninc() for reading from the keyboard in Unix so conchk() doesn't help.  In
+fact there are lots of other places where conchk() is used this way and works
+only by accident.  The only reason we never noticed a problem before is that
+characters don't usually arrive from the keyboard that fast.  But when an
+arrow key sends "ESC [ A" all once, the stdin buffer gets some extra stuff in
+it, which getchar() will return next time, but which coninc()/conchk() will
+never see.  So I added a new cmdconchk() routine which, if the keyboard is
+being read with getchar() rather than coninc(), looks at the stdin buffer.
+Unfortunately, however, there is no API for this, nor is there any standard
+way to access the stdin buffer directly.  So first I did it for Solaris.  Then
+to make it portable requires a survey of the headers for every platform.  I
+found four major variations:
+
+  stdin->_r:
+    {Free,Open,Net}BSD, BSDI
+  stdin->_cnt:
+    SunOS, Solaris, HP-UX 5-6, AIX, VMS, SINIX, IRIX 5.3-6.5, DGUX
+    4.2BSD, 4.3BSD, OSF/1..Tru64, QNX4, Unixware 1.0-2.1.0
+  stdin->__cnt:
+    HP-UX 7-11, SCO: OSR5.0.6a, Unixware 2.1.3-7.x, OU8, UNIX 3.2v4.x
+  Subtract read from end pointer (_IO_file_flags defined):
+    Linux (tested on RH 5.2 thru 7.1)
+
+The Linux method is new and different to account for multibyte characters.
+All the others assume character == byte.
+
+For docs: ANSI only, 7-bit only; both application and cursor modes are
+accepted.  Only up and down arrow are handled; left and right arrows cause
+a beep.  ckucmd.c, 8 Feb 2002.
+
+Build-all: Discovered that changing CTTNAM from TT: to SYS$INPUT: in VMS
+(which was done on 3 Jan 2002 to work around problems starting Kermit in
+batch, spawn'd, etc) breaks Kermit on VMS 5.5/VAX (concb() fails with "lacks
+sufficient privilege"; if you enable all privs Kermit starts but then spews
+out a constant stream of BEL characters).  If you put dftty back to "TT:",
+everything is fine -- I have no idea why, so I used #ifdef VMSV70 to decide,
+which is totally crude.  Next I had to find where the boundary really is: VAX
+vs Alpha?  VAX C vs DEC C?  Or between VMS releases?  Built on:
+ . VMS 6.2 Alpha (DEC C) - OK with TT:
+ . VMS 6.2 Alpha (DEC C) - OK with SYS$INPUT: <-- keep this one
+ . VMS 7.1 VAX   (DEC C)
+So the final condition is #ifdef VMSV60.  ckvker.com, ckvtio.c, ckuus5.c.
+
+QNX 6 needed some attention too:
+ . Whoever did the makefile target made the default port "/dev/ser1".
+ . Arrow keys...
+But I gave up on getting arrow keys to work -- it should be just like *BSD,
+but for some reason gcc complains that struct FILE has no _r member, even
+though it does (getchar uses it).
+
+Checked stdio.h on Mac OS X and it looks like the *BSDs.
+
+--- C-Kermit 8.0.201 ---
+
+Removed -g from solaris2xg+krb5+krb4+openssl+shadow makefile target -- it
+was producing a 15MB binary!  makefile, 14 Feb 2002.
+
+Fixed a couple thinkos in "make install": $(DESTDIR) should not have been
+included in the tests for whether INFODIR or SRCDIR were desired.  makefile,
+14 Feb 2002.
+
+(tarball refreshed 16 Feb 2002)
+
+--- C-Kermit 8.0.201 ---
+
+From Jeff: Better seeding of \frandom(): ckcmai.c, ckuus4.c, 18 Feb 2002.
+
+From Jeff: Make arrow keys work in WIKSD, but now also unconditionally
+compile arrow-key code in all versions.  ckucmd.c, 18 Feb 2002.
+
+From Jeff: ckuath.c, ck_ssl.c, ckcnet.c (didn't look).  18 Feb 2002.
+
+Added ORIENTATION command, that lists the various important directories, and
+\flongpathname() and \fshortpathname(), which do path format conversions in
+Windows, and are just synonynyms for \fpathname() elsewhere.  The new functions
+need building and testing in Windows.  ckuusr.h, ckuus[r24].c, 18 Feb 2002.
+
+Changed PWD for Windows only to show both short and long paths (but only if
+they are different; otherwise it behaves as before).  ckuusr.c, 18 Feb 2002.
+
+Changed default Windows prompt to show long pathname. ckuus5.c, 18 Feb 2002.
+
+Updated INTRO command to mention FTP, HTTP, and SSH.  ckuus2.c, 18 Feb 2002.
+
+From Jeff: fixes for typos in GetLongPathName() code: ckuus[r4].c, 22 Feb 2002.
+
+From Jeff: net/auth updates: ckcnet.c, ckuath.c, 22 Feb 2002.
+
+Added -DUSE_FILE__CNT to NCR MPRAS targets, George Gilmer: makefile,
+24 Feb 2002.
+
+From Jeff: Add support for GetLongPathName() in Win95 and NT: ckcdeb.h,
+ckuus[r4].c, 24 Feb 2002.
+
+From Jeff: More fixes for FTP SIGINT, plus fix [M]PUT /MOVE.  ckcftp.c,
+24 Feb 2002.
+
+Fixed an unguarded reference to inserver, gtword(): ckucmd.c, 24 Feb 2002.
+
+Adapted RETRIEVE for use with FTP connections; this one was missed when
+adapting GET, REGET, MOVE, etc.  ckuus6.c, ckcftp.c, 24 Feb 2002.
+
+Added special COPYRIGHT command text for the free version of WIKSD.
+ckcmai.c, ckuusr.c, 24 Feb 2002.
+
+C-Kermit, when in CONNECT mode and given the <Esc-Char>U sequence, would
+unconditionally close the connection if it was a network connection.  This
+is bad when Telnetting to a modem server.  I added to code to prevent this
+in the RFC2117 TELNET COMPORT case but I'm not sure how to exend this to the
+general case (or whether it would be a good idea).  ckucns.c, 24 Feb 2002.
+
+During file transfer, chktimo() calls ttgspd() for every packet, which clearly
+doesn't make sense on network connections, especially since on Telnet COMPORT
+connections it results in a network speed query for every packet.  Rearranged
+the code so this happens only on true serial-port connections.  ckcfn2.c,
+24 Feb 2002.
+
+From Jeff: Fix reversed ANSI/non-ANSI function declarations clauses in
+ckcftp.c, 26 Feb 2002.
+
+Changed Unix CONNECT module to call kstart() only when it has a chance of
+doing anything (i.e. a Kermit packet has been partially detected, or the
+packet start character just came in), rather than unconditionally on every
+incoming character.  ckucns.c, 8 Mar 2002.
+
+FTP PUT /SERVER-RENAME:, /RENAME-TO:, /MOVE-TO: were sticky.  Patch: In
+ckcftp.c, near the top of doftpput(), add the lines marked with "+":
+
+    makestr(&filefile,NULL);            /* No filename list file yet. */
++   makestr(&srv_renam,NULL);		/* Clear /SERVER-RENAME: */
++   makestr(&snd_rename,NULL);		/*  PUT /RENAME */
++   makestr(&snd_move,NULL);		/*  PUT /MOVE */
+    putpath[0] = NUL;                   /* Initialize for syncdir(). */
+
+ckcftp.c, 26 Mar 2002.
+
+\fday() and \fnday() were broken for dates prior to 17 Nov 1858.  Fixed in
+fneval(): ckuus4.c, 28 Mar 2002.
+
+From Jeff:
+ . New calling convenion for demoscrn(): ckucmd.c, ckuusx.c
+ . Fix for host-initiated 80/132 col screen mode change.  ckuus7.c.
+ . New \v(desktop) variable: K95 user desktop directory, ckuusr.h, ckuus4.c
+ . New \v(rfc2717_signature) var: Telnet Com Port, ckuusr.h, ckuus4.c
+ . Uncomment "not-reached" return(-2) in xgnbyte(): ckcfns.c
+ . New dates: ckcmai.c.
+ . Telnet Com Port fixes: ckutio.c
+ . SET PRINTER fixes for K95: ckuus3.c
+ . Session limit adjustments: ckuus3.c
+ . New directory layout for K95 (TAKE, ORIENT): ckuusr.c
+ . Fixes for Telnet Com Port, recycling SSH connections: ckuusr.c
+
+From me, not picked up by Jeff previously:
+ . kstart() speedup: ckucns.c.
+
+1 Apr 2002.
+
+---K95 1.1.21---
+
+From Jeff, 4 Apr 2002:
+ . More fixes for Telnet Com Port: ckuus4.c, ckudia.c, ckutio.c, ckcnet.c:
+   . network connections will check for carrier detect if SET
+     CARRIER-WATCH is ON.   This could have a potential conflict if
+     the option is negotiated and the carrier is off, but the site
+     requires login.
+   . modem hangup message generated since the dial module did not
+     believe that network modems could be reset with a DTR drop.
+ . Version number adjustments: 8.0.203, 1.1.99: ckcmai.c.
+ . Security: ck_ssl.[ch], ckuath.c.
+
+---C-Kermit 8.0.203---
+
+From Jeff, 6 Apr 2002:
+ . Fix typo in HELP REMOTE HOST: ckuus2.c.
+ . More Telnet Com Port fixes: ckctel.c, ckcnet.c, ckudia.c, ckutio.c
+
+From Jeff, 9 Apr 2002:
+ . Fix autodownload problem: ckcfn[2s].c.
+
+Chiaki Ishikawa reported that in Linux (two different kinds), if you choose
+hardware parity, CONNECT, then escape back, the speed can change.  I tracked
+this down to the following statement in ttvt():
+
+	tttvt.c_cflag &= ~(IGNPAR);	/* Don't discard incoming bytes */
+
+Somehow execution of this statement corrupted the speed words of the termios
+struct, which are entirely separate words that are nowhere near the c_cflag
+member.  Anyway, the statement is wrong; it should be:
+
+	tttvt.c_cflag |= IGNPAR;	/* Don't discard incoming bytes */
+
+Fixing it cured the problem; don't ask me why.  ckutio.c, 9 Apr 2002.
+
+From Jeff:
+  fixes the problem reported by robi@hastdeer.com.au.  The request to
+  enter server mode was received while we were entering server mode.
+  But the server was waiting for the response to REQ_STOP sent to the
+  client.  Therefore, we weren't quite in server mode yet and the
+  request to enter server mode was rejected.  A check for the sstate
+  value solves the problem.  ckctel.c, 10 Apr 2002.
+
+Chiaki Ishikawa (CI) discovered the real cause for the speed changing problem.
+I was setting the IGNPAR bit in the wrong flag word: it should have been
+c_iflag instead of c_oflag, silly me.  Fixed in ttvt() and ttpkt(): ckutio.c.
+I also did a thorough census of all the termio[s] flags to ensure each was
+applied to the right flag word -- they were, IGNPAR in the HWPARITY case was
+the only mistake.  CI also discovered that the speed words in the Linux
+termios struct are not used at all -- the speeds are encoded in an
+undocumented field of c_cflag, which explains the problem.  10 Apr 2002.
+
+Any use of \{nnn} character notation in a macro definition, loop, or other
+braced block caused an "unbalanced braces" parse error.  The backslash in this
+case is not quoting the open brace; it's introducing a balanced braced
+quantity.  Special-cased in getncm(): ckuus5.c, 12 Apr 2002.
+
+The semantics of "if defined \v(xxx)" were changed in 8.0 to avoid obnoxious
+error messages when xxx was not a built-in variable (see notes of 19 Nov
+2000), such that "if defined \v(xxx)" would always succeed if there were such
+a variable, even if it had no value.  The behavior that is documented in the
+book (and also in ckermit70.html) and that we had in versions 6 and 7, was
+that IF DEFINED \v(xxx) would fail if \v(xxx) was defined but had an empty
+value OR if it was not defined, and would succeed only if it was defined and
+had a value.  Fixed in boolexp(): ckuus6.c, 12 Apr 2002.
+
+What about \function()s?  IF DEF \fblah() presently succeeds if the function
+exists; you don't even have to give arguments.  I think this behavior is more
+useful than if I required valid arguments and then evaluated the function --
+you can do that anyway with 'if not eq "\fxxx(a,b)" "" ...'  Of course this
+argument applies to "if def \v(xxx)" too, except that the current behavior is
+consistent with the 7.0 behavior, so there is no need for a change.
+
+Kent Martin discovered that if a macro contains a LOCAL statement for a
+variable whose name is the same as, or a unique left substring of, the macro's
+name, then undefining the local variable makes the macro disappear:
+
+  define DateDiff {
+    echo {DateDiff(\%1) executing...}
+  }
+  define Kent {
+    do DateDiff {2}
+    local date
+    assign date {}
+    do DateDiff {3}  <-- This fails (A)
+  }
+  do DateDiff {1}
+  do Kent
+  do DateDiff {4}    <-- So does this (B)
+
+The first part of the problem is that "assign date {}" called delmac with
+exact=0, so delmac evidently deleted first macro whose name started with
+"date" -- and since the only one was DateDiff, that's the one that was
+deleted.  Fixing this (change "delmac(vnp,0)" to "delmac(vnp,1)" in dodef())
+got us past A.  The second part was making the same fix to the delmac()
+call in popclvl().  ckuus[56].c, 13 Apr 2002.
+
+The INPUT command ignored the parity setting, thus SET PARITY EVEN,
+INPUT 10 "login:" didn't work.  Fixed in doinput(): ckuus4.c.  Also fixed a
+bogus #ifdef COMMENT section that messed up the block structure of the module
+and therefore EMACS's indenting.  18 Apr 2002.
+
+Added sco32v500net+ssl and Added sco32v505net+ssl targets, from Scott Rochford
+at Dell (not sure yet if they work).  Makefile, 19 Apr 2002.
+
+From Jeff, 22 Apr 2002:
+ . Added "darkgray" color and made "dgray" an invisible synonym: ckuus3.c.
+ . Fix carrier sense on Telnet Com Port immediately after dial: ckudia.c.
+ . Change krb5_des_blah() arg list: ckutio.c.
+ . Fix ttgmdm() for Telnet Com Port: ckutio.c.
+ . Fix tthang() return code: ckutio.c.
+ . Add aix43gcc+openssl target: makefile.
+
+From Jeff, 25 Apr 2002:
+ . Fix SET GUI keyword table: ckuus[37].c.
+ . A final fix to Telnet Com Port: ckctel.c, ckcnet.c.
+
+From Jeff, 26 Apr 2002:
+ . Another final fix to Telnet Com Port: ckctel.c, ckudia.c.
+
+From Jeff, 27 Apr 2002:
+ . separate the wait mechanism for TELNET SB COMPORT synchronous messages
+   from the asynchronous TELNET SB COMPORT MODEMSTATUS messages: ckctel.[ch]
+ . fix debug messages in Certificate verify functions: ck_ssl.c, ckcftp.c.a
+
+Frank, 27 Apr 2002:
+ . Fixed VMS zgetfs() to fail when file doesn't exist: ckvfio.c.
+ . Fixed UNIX zgetfs() to check for null or empty arg: ckufio.c.
+ . Added #include <time.h> for time() call: ckcmai.c.
+ . Add casts to args in tn_wait() calls: ckctel.c.
+
+SINIX-P 5.42 (Pyramid architecture) makefile target from Igor Sobrado.
+makefile (no source-code changes), 1 May 2002.
+
+From Jeff, 5 May 2002,
+ . Fix some "unknown host" messages: ckcftp.c.
+ . Add more casts to tnc_wait() calls: ckudia.c.
+ . Improvements to SHOW SSH, SHOW GUI: ckuus3.c.
+ . Fixes to SET COMMAND { WIDTH, HEIGHT }: ckuus3.c.
+ . Updates to ck_ssl.[ch], ckctel.c, ckcnet.c.
+
+Fixed the erroneous setting of ssh_cas during switch parsing rather than
+after cmcfm() in setlin(): ckuus7.c, 5 May 2002.
+
+setlin() decomposition (2300 lines), Part One: 
+
+ . Copied a big chunk from the end of setlin(), beginning with net directory
+   lookup, but only the network-specific and common parts, to a new routine,
+   cx_net(), 900 lines.
+
+ . Extracted many repetitious lines of error-message code from cx_net()
+   to a new routine, cx_fail().  Error messages are stored in slmsg, and
+   also printed but only if we were not called from a GUI dialog (and
+   QUIET wasn't set, etc etc).  Any adjutments in this policy can now be
+   made in one place.
+
+ . I put a call to cx_net() in setlin() just before all the code it replaced.
+   It works for TELNET and SET HOST /TELNET.
+
+ . Built with mkwatsol-k5k4ssl; after a couple fixes it builds OK and makes
+   Kerberized connections OK.
+
+ . Copied the serial-port and common parts of the setlin() post-cmcfm()
+   code to another new routine, cx_serial(), about 275 lines.  Fixed
+   messages not to come out when called from GUI dialog, etc.  Inserted
+   a call to cx_serial() at the appropriate spot in setlin().  Tested
+   serial connections on watsun with "set line /dev/ttyh6", works OK.
+
+ . Removed all the code from setlin() that was copied to cx_*().  This slims
+   setlin() down to 1120 lines.  Tested regular Telnet, Kerberized Telnet, and
+   serial connections again, all OK.  The Unix version of the SSH command is
+   OK too.
+
+setlin() deconstruction, Part Two:
+
+Now that we have the common network and serial connection pieces moved out of
+setlin(), we still need to move out the little code snippets for each network
+type that take place between command confirmation and the common code we just
+replaced.   As far as I can tell, this needs doing only for SSH.  The code
+labeled "Stash everything" copied to cx_ssh() but I didn't remove the original
+code since I can't test this.  I think I'm done -- maybe I'm overlooking
+something but I don't know what...  First we need to test the heck out of it
+in all command-line versions (K95 and C-Kermit).  Then to use this from
+the GUI, see the calling sequences for cx_serial(), cx_net(), and cx_ssh():
+
+ . For serial or TAPI connections, the GUI should call cx_serial().
+ . For SSH connections, it should call cx_ssh() and then cx_net().
+ . For all other network connections, just calls cx_net().
+
+ckuus7.c, Cinco de Mayo de 2002.
+
+New ckuus7.c from Jeff, 8 May 2002.  Merge cx_ssh() into cx_net().  Also: I
+had made line[] an automatic variable, since the global line[] buffer is used
+by almost every parsing routine in C-Kermit to hold string fields between
+parsing and execution but Jeff says he found that some code somewhere depended
+on line[] containing the hostname after setlin() was finished.
+
+From Jeff, 10 May 2002:
+ . Fix SET SSH STRICT-HOST-CHECKING parse: ckuus3.c.
+ . Add prototypes for cx_net() and cx_serial(): ckuusr.h.
+ . Add ANSI versions of cx_net() and cx_serial() declarations and supply a
+   missing parameter in the cx_serial() invocation, change SSHCMD cx_net()
+   invocation to new form.
+
+From Jeff, 16 May 2002:
+ . ANSI strictness changes: ck_ssl.[ch]
+ . New DIALER command: ckuusr.[ch]
+ . Correction to how -0 turns off autodownload: ckuusy.c
+ . Prototypes for GUI menu action functions: ckuusr.h.
+ . Replace setting of GUI-action variables by function calls: ckuus[3457x].c
+ . Fix FTP -z switch parsing: ckcftp.c.
+ . Fix SET HOST testing of setlin() return code: ckuus3.c
+
+From Jeff, 18 May 2002:
+ . Allow half-size GUI fonts: ckuus[35y].c.
+
+Fixed setguifont() to parse fractional font sizes and round to nearest half
+point.  ckuus3.c, 18 May 2002.
+
+For GUI, wrote front ends for getyesno(), readtext(), and readpass():
+
+ . uq_ok() prints text and gets Yes/No, OK/Cancel, or just OK response.
+   This replaces getyesno() and can also be used for alert or help boxes.
+
+ . uq_txt() prints text and gets a single text response.  Replaces
+   readtext() and readpass().
+
+ . uq_mtxt() is like uq_txt() but allows multiple text fields.  Replaces
+   any combination of readtext() and readpass().
+
+Obviously the #ifdef KUI portions of the uq_blah() routines need filling in.
+ckuusr.h, ckuus3.c, 18 May 2002.
+
+Converted selected getyesno() calls to uq_ok(): ckcftp.c, ckuus3.c, ckuus6.c.
+Some were not converted because it was inappropriate, e.g. DELETE /ASK; others
+because they're in Jeff's code.  The most interesting conversions are in the
+DIAL command when DIAL CONFIRMATION is ON.  Here there is a dialog for each
+phone number asking if it's OK (ug_ok()) and if not, asking for a replacement
+(uq_txt()); seems to work fine in C-Kermit.  All the candidates for uq_mtxt()
+are in Jeff's code.  18 May 2002.
+
+From Jeff: Convert remaining getyesno/readtext/readpass calls to uq_blah()
+so they can be GUI dialogs.  ckuus[37].c, ckcftp.c, ckuath.c, ck_ssl.c,
+21 May 2002.
+
+Added KCD command = CD to symbolic directory name (EXEDIR, COMMON, APPDATA,
+TMPDIR, etc etc).  ckuusr.h, ckuus[r25].c, 21 May 2002.
+
+From Jeff, 28 May 2002:
+ . --title: commandline option: ckuusr.h, ckuusy.c
+ . Fix some #includes, move some declarations: ckcfns.c
+ . Change K95 version from Dev.00 to Beta.01
+ . ASK[Q] /GUI: ckuus6.c.
+ . Various GUI screen updates and #ifdefs: ckuus7.c
+ . Add missing cx_net() calls to new setlin() for file SuperLAT..: ckuus7.c
+ . Updated uq_*() routines for GUI dialogs: ckuus3.c.
+
+Added GETOK switches (/TIMEOUT for all; /POPUP and /GUI for K95G):
+ckuus6.c, 29 May 2002.
+
+Added HELP SET GUI text.  ckuus2.c, 29 May 2002.
+
+From Jeff:
+ . Another K95-specific #include for ckcfns.c.
+ . More items for K95G Actions menu.
+ . Change K95G Locus switching to call setlocus() rather than set variable.
+ . Ditto for several other variables now settable from Actions menu.
+ . Fix SET HOST /NET:SSH status code so IF SUCCESS works.
+ . Fix SHOW SSH port-forwarding.
+ckcfns.c, ckuus[r367].c, ckcftp.c, ckcmai.c, 30 May 2002.
+
+Changed SET LOCUS to have a new value, ASK, corresponding to new autolocus
+value of 2, K95G only.  Changed setlocus() to not do anything if the new and
+old loci are the same, otherwise to invoke a GUI dialog in K95G if autolocus
+is 2, and also to handle any text messages.  Changed SHOW COMMAND to show ASK
+value for SET LOCUS.  Rewrote HELP SET LOCUS.  ckuusr.[ch], ckuus[23].c,
+ckcftp.c, 30 May 2002.
+
+Add a missing space to Locus popup, and fix Jeff's version of the code to
+compile in C-Kermit.  ckuusr.c, 31 May 2002.
+
+From Jeff, for K95 GUI, 6 June 2002:
+ . Force some GUI popups to be in foreground: ckuus3.c.
+ . Fix SHOW TERM font display: ckuus5.c.
+ . Update K95 version numbers and date (4 June 2002): ckcmai.c.
+ . Add note about encrypted private keys vs scripts to HELP SET AUTH: ckuus2.c.
+ . Fix SET HOST for DECnet: ckuus7.c.
+
+--- K95 2.0 ---
+
+From Jeff, 7 June 2002:
+ . Fix some #ifdefs for Unix builds (locus, dial, etc): ckuus7.c
+ . Add gui_resize_scale_font() prototype: ckuus3.c
+ . Add some missing SET GUI commands: ckuus3.c
+ . Update version numbers: ckcmai.c
+
+--- K95 2.0.1 ---
+
+From Jeff, 11 June 2002:
+ . Conditionalize Locus-switching popup text for GUI/Console: ckuusr.c.
+ . Fix the SRP_installed_as_server() function.  The new API returns TRUE even
+   if the SRP config and password files cannot be found.  Went back to the old
+   API.  This bug affects C-Kermit 8 when built with SRP as well as 1.1.21
+   through 2.0.1.  Since iksdnt.exe has not been shipped yet I fixed it and
+   uploaded a new non-beta build of it.  ckuath.c.
+
+From Jeff, 12 June 2002:
+ . Fix SSH AGENT ADD: ckuusr.c.
+ . Fix --facename: option to not fail if name unknown: ckuusy.c.
+ . Fixes for OpenSSL 0.9.7 and OpenBSD 3.1: ck_ssl.c.
+ . Fix SET AUTH TLS VERIFY NO to prevent a dialog but still a warning if
+   SET AUTH TLS VERBOSE ON is set: ck_ssl.c.
+ . Fix FTP code to verify the hostname as specified by the user and not
+   the hostname discovered by the reverse DNS lookup.  For example,
+     FTP OPEN kermit.columbia.edu
+   should produce a dialog because that name is not in the certificate
+   even though ftp.kermit.columbia.edu (the reverse DNS name) is:  ckcftp.c.
+
+Add support for Solaris 9 and NetBSD 1.6.  makefile, ckuver.h, ckcdeb.h,
+13 Jun 2002.
+
+Discovered that Solaris 9 wants to hide the members of struct FILE, and
+enforces this for 64-bit builds.  They offer some functions like __fbufsize()
+to get the info, but not the info we need for reading escape sequences (the
+_cnt member).  Let's hear it for political correctness.  Created new solaris9g
+(32-bit) and solaris9g64 (64-bit) targets.  Sorry, no arrow keys in 64-bit
+mode.  Also no more direct access to sys_errlist[]; must use strerror().
+makefile, ckucmd.c, 13 Jun 2002.
+
+Added solaris9g+openssl+zlib+pam+shadow, which in turn required adding
+solaris2xg32+openssl+zlib+pam+shadow, needed for gcc 3.1 in which you have
+to specify 32-bit.  Fails for some mysterious reason in link step
+(can't find libssl.so.0.9.6 even though it's there).  makefile, 13 Jun 2002.
+
+Solaris 8 empty socket problems again -- tthang() times out, subsequent
+tcsetattr() calls do horrible things.  Added a bandaid to ttclos(): don't
+call tcsetattr() any more if hangup timed out.  ckutio.c, 14 June 2002.
+
+Gerry B reported the bandaid got us bit farther but Kermit still disappears.
+Added code to reassert the alarm signal handler, since it is likely that
+Solaris has become stricter about this since last time I looked.  (Later
+Gerry reported back that this did the trick -- C-Kermit now exits normally
+and releases the lockfile).  ttclos(): ckutio.c, 17 Jun 2002.
+
+If you use Kermit to copy a file to a destination file that already exists and
+is longer than the source file, the destination file is not truncated.  I had
+mistakenly assumed that setting O_CREAT in the open() call in zcopy() would
+create a new copy of the file.  Fixed by also setting O_TRUNC.  ckufio.c,
+17 Jun 2002.
+
+Updated HELP INPUT and MINPUT text to explain 0 and -1 timeout values, and
+HELP DIAL to explain about entering CONNECT mode automatically.  ckuus2.c,
+17 Jun 2002.
+
+Got rid of client-side "Press the X or E key to cancel" message when giving
+a REMOTE command if QUIET is set or if XFER DISPLAY is NONE.  ckuus7.c,
+17 Jun 2002.
+
+From Jeff 25 Jun 2002:
+ . Add SUN terminal type: ckuusr.h, ckuus[57].c.
+ . Add GUI file transfer display: ckcker.h, ckuus[47x].c.
+ . Changes to allow C-Kermit to build with OpenSSL 0.9.7.  Current
+   C-Kermit code is designed to compile with 0.9.6 and earlier.  To
+   compile with 0.9.7 you must specify -DOPENSSL_097.  This avoids
+   missing symbols in the DES library.  The functions in OpenSSL were
+   renamed in 0.9.7 to avoid link time conflicts with Kerberos 4.
+   ckufio.c ck_crp.c ckuath.c ck_ssl.h ck_ssl.c, makefile.
+
+From Jeff 26 Jun 2002:
+ . apparently the SSL Passphrase Callback function was not converted
+   from readpass() to uq_txt()
+ . FTP Authentication failure errors were not being reported to the
+   user.  So a failure would appear to be a successful completion
+   unless FTP DEBUG was ON.  Now the message is reported unless
+   the QUIET flag is set.
+ck_ssl.c, ckcftp.c.
+
+SET TRANSFER MODE MANUAL didn't work for FTP; fixed in putfile() and getfile():
+ckcftp.c, 1 Jul 2002.
+
+Changed debug log for FTP to log "FTP SENT" and "FTP RECD" for protocol
+messages, just like we do for Telnet, to make it easy to grep them out of
+the log.  ckcftp.c, 1 Jul 2002.
+
+In FTP MGET /UPDATE, equal times spuriously caused download.  doftpget() was
+misinterpreting chkmodtime()'s return code.  ckcftp.c, 3 Jul 2002.
+
+In FTP MGET /RECOVER, recovery is skipped if the local file is newer than
+the remote.  This would seem to make sense, but when a download is
+interrupted, the partial file never gets the date of the remote file, so
+the partial file is always newer, and recovery never works.  Fixed in
+recvrequest() by commenting out the date check.  ckcftp.c, 3 Jul 2002.
+
+A better way to fix the previous problem is to always set the file date from
+the server and then only allow /RECOVER to work when the dates are equal.
+But that's not possible because MDTM is not implemented universally, and it
+conflicts with how Kermit currently works, namely that FTP DATES are OFF by
+default.  Also, checking dates prevents [M]GET /RECOVER from working with
+files that were incompletely downloaded by some other FTP client.
+
+In FTP MGET /RECOVER <wildcard> <wildcard> ..., the first file in each group
+is always downloaded.  Diagnosis: Kermit sends "TYPE A" prior to NLST (as it
+must).  Then when it sends its first SIZE command, it's still in ASCII mode,
+so the server sends the "ASCII size" rather than the binary size, which does
+not agree with the size of the local file (which was downloaded in binary
+mode), so recovery is always attempted even when the files are identical.  The
+TYPE A command is sent by initconn().  After the remote_files() call, we have
+to change the type back to the prevailing type before sending the first SIZE
+command.  Fixed in cmdlinget() and doftpget(): ckcftp.c, 3 Jul 2002.
+
+In FTP MGET /EXCEPT:<pattern> used with SET XFER DISPLAY brief, files that
+are skipped just say ERROR instead of saying why they were skipped.  Fixed
+in doftpget(): ckcftp.c, 3 Jul 2002.
+
+Added EXIT to top-level HELP text.  ckuus2.c, 13 Jul 2002.
+
+Strip braces in REINPUT n {string}.  ckuusr.c, 13 Jul 2002.
+
+Added /QUIET switch to ASK-class commands.  This means not to print any error
+messages when an ASK-class command times out waiting for a response.  Made
+sure that when a timeout occurs, the command fails.  Also made sure the
+c-Kermit prompt doesn't write over the ASK prompt if ASK times out.  Also
+fixed ASK, when it times out, not to return -9, which it did in one case,
+which causes a command-stack dump.  ckuus[267].c, ckucmd.c, 13 Jul 2002.
+
+Fixed SET FILE INCOMPLETE help text, which said that both KEEP and AUTO were
+the default.  ckuus2.c, 13 Jul 2002.
+
+If you SET FTP DEB ON and then turn it OFF, the MGET temp file is still kept.
+Fixed by getting rid of ftp_knf variable and using ftp_deb to control whether
+temp file is deleted (ftp_knf was being set from ftp_deb anyway, but then
+wasn't being reset by SET FTP DEB OFF).  ckcftp.c, 13 Jul 2002.
+
+If an FTP transfer was in progress but the FTP connection drops and automatic
+locus switching is enabled, the locus does not change; thus (for example) a
+subsequent DELETE command makes Kermit send a REMOTE DELETE packet on stdout.
+Fixed in lostpeer(): ckcftp.c, 13 Jul 2002.
+
+For docs: FTP CD with no arg might not be accepted by the server; e.g. the
+Kermit FTP server says "501 Invalid number of arguments".
+
+The FTP module never handled SET INCOMPLETE.  Fixed in doftprecv2().  ckcftp.c,
+13 Jul 2002.
+
+When FTP DATES is ON, we set an incoming file's date only if the file was
+received successfully.  Changed the code to set the file's date even if it was
+received only partially (assuming we can get the date from server).  ckcftp.c,
+13 Jul 2002.
+
+Suppose we were doing FTP MGET /UPDATE from a server directory of 100,000
+files.  Kermit would send a SIZE command for every file unconditionally.  On
+some connections, e.g. to the Red Hat Rawhide server, each one could take up
+to 30 seconds.  That would be 3 million seconds = 34 days.  Don't send a SIZE
+command during the selection phase unless a /SMALLER or /LARGER selector was
+given.  Once the file is selected, send a SIZE command only if one hadn't been
+sent for that file already.  ckcftp.c, 13 Jul 2002.
+
+Made [M]GET and [M]PUT /UPDATE switch imply FTP DATES ON, since they didn't
+work unless it was.  ckcftp.c, 13 Jul 2002.
+
+Added FTP [M]GET /DATES-DIFFER, which is like /UPDATE except it selects files
+that are newer or older, rather than only newer.  This allows updates from
+sources where files might be rolled back to earlier versions.  It's a bit
+dangerous if you use it without knowing what it's for, since it allows older
+files to overwrite newer ones.  (Code is also in place for [M]PUT
+/DATES-DIFFER, and it works, but I commented it out because it's either
+useless or dangerous since when uploading, you can't set the the file dates
+when they are arrive on the server.)  ckcftp.c, 13 Jul 2002.
+
+Changed chkmodtime() to remember if MDTM fails on a particular connection
+because it's an unknown command (500, 502, or 202), and if so, not to ask
+again.  ckcftp.c, 13 Jul 2002.
+
+With this last change, I think it's safe to change the default for FTP DATES
+from OFF to ON.  ckcftp.c, 13 Jul 2002. 
+
+Increased max number of /EXCEPT: patterns from 8 to 64 for file transfer (not
+necessarily for other things).  This is now a compile-time symbol NSNDEXCEPT.
+ckcker.h, ckcmai.c, ckclib.c, ckcfns.c, ckcftp.c, ckuus[rx].c.  13 Jul 2002.
+
+Fixed FTP MGET to not send SIZE command when there is a name collision and
+FILE COLLISION is DISCARD, even if /SMALLER or /LARGER were also specified.
+ckcftp.c, 15 Jul 2002.
+
+MGET fails if no files were transferred, even if the reason is that no files
+met the selection critieria: /COLLISION:DISCARD, /UPDATE, /SMALLER, etc.
+Changed MGET to succeed in that case.  domget(): ckcftp.c, 16 Jul 2002.
+
+Big problems with canceling MGET; Ctrl-C cancels the current file, but we
+don't break out of the file loop, we just go on to the next file.  Worse, if
+we're executing a command file that has a series of MGETs, Ctrl-C doesn't
+break us out of the command file.  Fixed by making failftprecv() and
+failftprecv2() "chain" to the main SIGINT handler, trap().  This is fine in
+Unix, but I'd be really surprised if it works in K95 so I put it in #ifndef
+OS2.  Ditto for MPUT: Added the same treatment to failftpsend() and
+failftpsend2().  Ditto for cmdcancel().  To adapt to K95, search for "TEST ME
+IN K95" (5 places).  ckcftp.c, 16 Jul 2002.
+ 
+Fixed previous fix to account for the fact that failftpblah() can be called
+not only upon Ctrl-C, but also if transfer interrupted with X or Z.
+ckcftp.c, 16 Jul 2002.
+
+Yesterday's fixes revealed another problem: Interrupt MGET with Ctrl-C, start
+another MGET, and the file list is total garbage.  Diagnosis: secure_getc()
+and secure_getbyte() use internal static buffer pointers.  The only way they
+ever get reset is when the data connection is closed by the server, so if you
+interrupt a GET, the pointers are not reset and the next network read (e.g. of
+an NLST response) returns whatever junk was lying around in the old buffer.
+ckcftp.c, 17 Jul 2002.
+
+FTP MGET temp file is kept only if FTP DEBUG is ON.  Changed FTP module to
+also keep it if the regular debug log is active.  ckcftp.c, 17 Jul 2002.
+
+Fixed version test in ckermit.ini: should be 6 digits, not 5.  17 Jul 2002.
+
+Changed C-Kermit version number to 8.0.205 so scripts can test for the
+recent changes.  ckcmai.c, 18 Jul 2002.
+
+---8.0.205---
+
+SET FILE COLLISION UPDATE would unset FTP DATES due to a typo in the recent
+changes.  ckcftp.c, 21 Jul 2002.
+
+FTP [M]GET /DATES-DIFFER really should have been a collision option.  Added
+this option (implemented for FTP only) to both SET FTP COLLISION and the
+FTP [M]GET /COLLISION: table, so this way if you have lots of [M]GETs, you
+don't have to put /DATES-DIFFER on each one.  ckcker.h, ckcftp.c, 21 Jul 2002.
+
+"FTP MGET a* b* c*" would fail to get any c*'s if no b*'s existed.
+ckcftp.c, 21 Jul 2002.
+
+From Jeff, 22 Jul 2002:
+ . Beginnings of Ann Arbor Ambassador terminal emulation for K95;
+   ckuus[57].c, ckuusr.h.
+ . Bump K95 version number to 2.0.2: ckcmai.c
+
+Added -DCK_PAM -DCK_SHADOW to all Solaris targets, 2.6 and above.  makefile,
+23 Jul 2002.
+
+Discovered that CK_SCRIPTS path search for TAKE files was #ifdef'd out
+except for K95.  Fixed in ckuusr.c, 25 Jul 2002.
+
+From Jeff: changes to support K95 italics: ckuus[57].c,  25 Jul 2002.
+
+Fixed path search for TAKE to not search the CK_SCRIPTS path if the filespec
+contains any directory or path parts.  Added a new function to check for
+this:  int hasnopath(filespec) in ckucmd.c: 26 Jul 2002.
+
+Update HP-UX build instructions from PeterE: makefile, 26 Jul 2002.
+
+Commented out "const" from struct pam_message declarations because it
+causes "initialization type mismatch" warnings.  ckufio.c, 26 Jul 2002.
+
+Suppose you have a network directory containing a listing for host "foo":
+
+  foo tcp/ip foo.bar.com
+
+Then in K95 you give a command "set host /network-type:ssh foo".  This
+results in the directory lookup replacing the "ssh" network type with TCP/IP,
+and making a Telnet connection.  Fix attempted at about line 8625 of ckuus7.c
+in cx_net(); needs testing in K95.  26 Jul 2002.
+
+FTP Password: prompt in Unix was not allowing editing.  The code looked right;
+I put in some debugging and suddenly it worked.  Took out the debugging and
+it still worked.  Maybe I dreamed it.  Anyway, I fixed the "FTP SENT" debug
+log entry to not record the password, and removed a redundant section above
+to log the same thing, but prior to any charset conversion.  ckcftp.c,
+27 Jul 2002.
+
+From Jeff, 28 Jul 2002:
+ . Fix typo in initxlist(): ckcmai.c.
+ . Fix typo in Friday's set-host fix: ckuus7.c.
+ . Move parsing of --height/width command-line args after prescan(): ckuusy.c.
+
+Added invisible top-level SITE and PASSIVE commands for FTP as a convenience
+for habituated FTP client users.  ckuusr.[ch], ckcftp.c, 28 Jul 2002.
+
+A while back a user asked if it was possible to MGET a bunch of files from
+an FTP server and have them all appended to each other upon arrival.  The
+obvious way to do this would have been:
+
+  mget /collision:append /as-name:bigfile *.*
+
+But to make this work, I had to get rid of the "as-name must contain
+variables" check in the MGET parser.  doftpget(): ckcftp.c, 28 Jul 2002.  
+
+Verified that it was possible to do the same thing (GET a bunch of files
+and append them all into one result file) with Kermit protocol.  It works
+fine but in this case there is no /COLLISION switch; you have to SET FILE
+COLLISION APPEND first.  30 Jul 2002.
+
+Changed COPY /APPEND to allow wild source to single destination file, e.g.
+"copy /append *.* bigfile".  ckuus6.c, 30 Jul 2002.
+
+From Mark Berryman: a replacement for zchkpath(), the VMS routine that checks
+whether a file is in the current directory; the old one (that I wrote) was
+a hack that only worked sometimes.  Martin Vorlaender verified Mark's code in
+the situation where mine was breaking (server running in captive account).
+ckvfio.c, 30 Jul 2002.
+
+PeterE reported a problem with SWITCH case labels that start with '#':
+The problem is that the SWITCH variable contents in this case happens to be
+a comment, e.g.:
+
+  CMD(M)[_forward # Stand: 24.07.2002<CR>]
+
+so the GOTO target is null.  The solution would be for SWITCH to put the GOTO
+(_FORWARD) target in quotes.  But GOTO does not strip quotes or braces from
+around its target.  Fixed in ckuusr.c, 30 Jul 2002.
+
+Fixed the SWITCH macro definition to put the _FORWARD target in quotes.
+ckuus5.c, 30 Jul 2002.
+
+PeterE also reported that an empty SWITCH case label did not work.  There's no
+particular reason why it should, but after a brief look, it wasn't that hard
+so I did it.  It required commenting out the check for empty labels and fixing
+the comparison in dogoto().  Now it's possible to read lines from a file and
+use each line as a SWITCH variable, with patterns as case labels, including an
+empty label to match empty lines, #* labels to match comment lines, etc.
+ckuus[r6].c, 30 Jul 2002.
+
+PeterE also reported the value of \%* acquiring a trailing blank when
+referenced inside a SWITCH statment.  This happens because \%* is formed using
+\fjoin() on the \&_[] array based on its dimension, and at some point the
+dimension is spuriously increased by one.  As a workaround, I made \fjoin()
+ignore trailing empty \&_[] array elements and oddly enough this also fixed
+the growing dimensions problem.  The many script torture tests reveal no ill
+effects, so it seems like a keeper.  ckuus4.c, 30 Jul 2002.
+
+Some of Peter's sample scripts made C-Kermit 8.0.201 dump core, but no more.
+
+Fixed "delete xxx" to print an error message and fail if if xxx does not exist.
+Ditto for when xxx is a directory.  ckuus6.c, 30 Jul 2002.
+
+Patches to SSL modules from Jeff based on yesterday's advisory.  ck_ssl.[ch],
+31 Jul 2002.
+
+Fixed some typos affecting the filename collision action during command-line
+FTP [M]GET.  ckcftp.c, 31 Jul 2002.
+
+Fixed SHOW FTP to handle FTP COLLISION DATES-DIFFER.  ckcftp.c, 31 Jul 2002.
+
+A while back someone pointed out that SET CONTROL UNPREFIX ALL and SET
+PREFIXING NONE gave different results.  Fixed them to use the same code.
+Also made "set prefixing none" visible.  ckuus3.c, 4 Aug 2002.
+
+Added SET CD HOME <path>, to let the user specify which directory is intended
+when "CD" or "KCD" is given by itself.  This is because in Windows, some
+applications set up their own HOME environment variable that isn't necessarily
+where the user wants "cd" to go, but redefining HOME can interfere with the
+application (example: Windows EMACS).  SET CD HOME was done by adding a myhome
+variable, initially a NULL pointer, and then changing homepath() to use it if
+it is set.  zhome() is not affected.  Also the homepath() prototype had been
+missing from header files.  ckcmai.c, ckuusr.h, ckuus[2345].c, 4 Aug 2002.
+
+PeterE got another core dump with his SWITCH statement.  Found a place where
+an out-of-bounds array reference could occur if the switch variable was
+empty.  ckuus6.c, 5 Aug 2002.
+
+PeterE noticed that if the switch variable contained a comma, spurious matches
+could occur with the label pattern.  The real problem turns out to be what
+happens when the SWITCH variable doesn't match any of the case labels and
+there is no DEFAULT label.  Fixed by having dogoto() in the SWITCH (_FORWARD)
+case pop the command stack before returning failure, i.e. by moving the
+"if (stopflg) return(0);" statement down a few lines.  ckuus6.c, 5 Aug 2002.
+
+PeterE noticed that a SWITCH case label of :* did not match an empty SWITCH
+variable.  Fixed in doswitch(): ckuus6.c, 6 Aug 2002.
+
+In testing the previous fix, I found it only worked sometimes.  Inspection
+of the debug log showed that a statement like:
+
+  if (y == -3) s = "{}";
+
+was assigning "{" rather than "{}" to s.  Replacing the string constant by a
+buffer containing the same string fixed it.  The reason (guessed correctly by
+PeterE) was the following sequence:
+
+  y = cmfld("Variable name","",&s,xxstring);
+  if (y == -3) s = "{}";
+  len = ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
+
+brstrip() (by design and as documented) affects the string in place.  But in
+this case the string is a constant, not data in a buffer, so all further uses
+of "{}" get the wrong string (at least in optimized builds).  The only real
+cure is to change brstrip() to make a copy of its argument if it has to do
+anything to it.  This will slow down some scripts, but it's too risky to
+leave it as it was.  ckclib.c, 6 Aug 2002.
+
+The previous change required an audit of the C-Kermit code to make sure that
+no references to brstrip() depended the result buffer being persistent, or the
+result pointer indicating a position in the source buffer.  Oops, it turns out
+that thousands of places rely on brstrip() working in place.  Therefore the
+change had to be undone.  There's no good way to write a dummy-proof brstrip();
+programmers either have be sure they're not calling it with a pointer to a
+string constant, or else they have to copy the result back to the right place
+each time.  Better to leave it as it was and audit the code to fix any calls
+that refer to string constants (turns out there were only two).  Restored the
+original fix to doswitch() (replacing the string constant by a buffer holding
+the same string), plus minor fixes to ckcftp.c, ckuus[r36].c, 6 Aug 2002.
+
+We need file dialogs in several situations in the K95 GUI.  I added a "user
+query" routine for this, uq_file(), in ckuus3.c, filling it in only for Unix.
+Then I added code to call it from rcvfil() when (a) it's an autodownload, and
+(b) SET TERM AUTODOWNLOAD is ASK (I just added this option; it needs to be set
+to see it in action -- maybe it should be the default for KUI, in which case
+initialize "int autodl = ?" to TAD_ASK in ckcmai.c).  Works fine, except of
+course it interferes with the file-transfer display, but that won't be a
+problem in K95G.  ckuusr.h, ckuus[37].c, ckcfns.c, ckucns.c, 6 Aug 2002.
+
+Another place we need a file dialog is when Kermit is a URL interpreter.  The
+problem is: how can we let the user decide whether Kermit should ask?  There
+really isn't any way.  Either it always asks or it never does.  In this case I
+think it makes sense to always ask if it's KUI, otherwise never.  I added the
+code for ftp: URLs to to doftprecv2(), which I tested successfully in Unix
+before putting it into #ifdef KUI..#endif.  Also added code for http[s] to
+ckuusy.c in #ifdef KUI..#endif, not tested.
+
+Still need this added for K95G Actions->Capture.  The clearest example is the
+FTP one.  Just search for KUI in the FTP module.
+
+Some minor adjustments to yesterday's work, mainly just comments, plus
+generate the full pathname for the default file.  ckuus3.c, ckcftp.c,
+7 Aug 2002.
+
+Note: for some reason cmofi() is not supplying the default value if user
+enters an empty name... (but that won't affect the Windows version).
+
+Added /USER: and /PASSWORD: switches to SET TCP { HTTP-PROXY, SOCKS-SERVER }.
+ckuus3.c, 7 Aug 2002.
+
+New 'uninstall' target from PeterE, works by having the 'install' target
+write an UNINSTALL shell script.  makefile, 8 Aug 2002.
+
+Added some debugging statements to the VMS communications i/o module to try
+to track down a problem that occurs when the controlling terminal is a LAT
+device.  ckvtio.c, 10 Aug 2002.
+
+Fixed the non-K95 uq_file() to respect the given default name, but still show
+the fully qualified absolute pathname for the default in the dialog.  The
+reason to not use the fully qualifed name as the default in the cmxxx() calls
+is that this can easily result in a whole directory tree being created due to
+directory aliases, symlinks, etc.  So when you get a file by referring to its
+URL (e.g. ftp://kermit.columbia.edu/kermit/READ.ME), uq_file() converts the
+READ.ME part to (e.g.) /home/fdc/tmp/READ.ME but gives just "READ.ME" as the
+default when parsing the name.  This way the user knows where it will go and
+gets an opportunity to change it, and if the default is accepted, it goes into
+the current directory.  uq_file(): ckuus3.c, 10 Aug 2002.
+
+Found the spot for calling uq_file() for kermit:// URL downloads.  Added
+prefatory text to filename prompts for Kermit and FTP downloads.  ckcfns.c,
+ckcftp.c, 10 Aug 2002.
+
+Now with kermit:// or ftp:// URL downloads there's no way to disable the
+prompting.  I could easily make SET TERMINAL AUTODOWNLOAD ASK cover these
+cases too (even though "terminal" has nothing to do with FTP or URL
+downloads).  OK, I did this, but now prompting is disabled by default.
+ckcftp.c, ckcfns.c.  10 Aug 2002.
+
+Enabled file prompting (adl_ask) by default in K95G, disabled it by default
+everywhere else.  So now FTP and Kermit URL downloads as well as terminal-mode
+Kermit (but not Zmodem) downloads are prompted for if TERMINAL AUTODOWNLOAD is
+ASK, which is it by default only in K95G.  But this will happen only if
+uq_file() is filled in for K95G; otherwise everything should work as before.
+ckcmai.c, 10 Aug 2002.
+
+Notes:
+ . Need a better command to control this.
+ . FTP URL downloads are almost instantaneous, whereas Kermit URL downloads
+   take a really long time to set up (logging in takes at least 10 seconds).
+
+From Jeff, 13 Aug 2002:
+ . Increase K95 version to 2.1.0: ckcmai.c.
+ . SET TCP { HTTP-PROXY, SOCKS-SERVER } /USER: /PASSWORD: actions: ckuus3.c.
+
+From PeterE: a new install target that's only about half as a big as the
+previous one, yet still generates an UNINSTALL script.  makefile, 13 Aug 2002.
+
+Vace wanted to be able to give the FTP client an offset for the server time,
+in case the server's time (or timezone) is set incorrectly.  I added this by
+building on all the date/time parsing/arithmetic code -- notably delta times
+-- that was done for C-Kermit 8.0.  The new command is SET FTP
+SERVER-TIME-OFFSET delta-time; shows up in SHOW FTP and HELP SET FTP.
+ckcftp.c, 13 Aug 2002.
+
+Fixed HELP ASK and HELP GETOK text.  ckuus2.c, 14 Aug 2002.
+
+Fixed GETOK to accept /GUI switch even in K95.EXE and C-Kermit, just like ASK
+does (in which case, it just ignores it).  ckuus6.c, 14 Aug 2002.
+
+SET XFER CHAR TRANSPARENT no longer disables character-set translation because
+file-scanning turns it back on.  The "new way" to disable character-set
+translation is SET XFER TRANSLATION OFF.  This needlessly confuses users who
+expect the old way to still work.  So I fixed SET XFER CHAR TRANSPARENT to set
+XFER TRANSLATION OFF, and SET XFER CHAR anything-else to set it back ON.
+ckuus3.c, 15 Aug 2002.
+
+Fixed SET TERM AUTODOWNLOAD { ON, OFF } to turn off the ASK flag (adl_ask).
+ckuus7.c, 16 Aug 2002.
+
+Added FEAT query to FTP client from draft-ietf-ftpext-mlst-13.txt.  FEAT is
+sent along with REST 0, MODE S, and STRU F if /NOINIT is not included in the
+FTP OPEN command.  Parsing the FEAT result is handled by turning the "auth"
+argument to getreply() into a function code: GRF_AUTH to parse AUTH reply;
+GRF_FEAT to parse FEAT reply.  For GRF_FEAT, getreply() fills in a flag array,
+sfttab[] (server feature table); sfttab[0] > 0 means server responded to the
+FEAT query, in which case individual elements are set > 0 for each supported
+feature.  ckcftp.c, 18 Aug 2002.
+
+If server sends a feature list, display it if FTP DEBUG is on, then set mdtmok
+and sizeok (the flags that say whether it's OK to send MDTM and SIZE commands)
+accordingly.  If user gives an [M]PUT /RECOVER command and server has
+announced it doesn't support REST, print a warning but try anyway (maybe
+change this later).  Responses about other features that we use such as AUTH
+and PBSZ are ignored for now -- i.e. we try them anyway.  And of course
+responses for features we don't care about (LANG, TVFS, PROT) are ignored.
+ckcftp.c, 18 Aug 2002.
+
+If the server says it supports MLST, use MLSD instead of NLST to get the file
+list.  This is done in remote_files() with some simple string-twiddling.  Then
+replace the relevant (but not all) SIZE commands with code to first check if
+we already got the size from the MLSD response and use that instead rather
+than asking again.  Same deal for MDTM.  ckcftp.c, 18 Aug 2002.
+
+Checked that this works when giving pathnames in the MGET filespec.  Checked
+to make sure everything works as before with servers that don't support FEAT
+or MLSD.  Checked to make sure FTP OPEN blah /NOINIT worked with servers that
+do support FEAT and MLSD.  Checked that FTP CHECK works.  It's all OK.
+
+Tested only with Ipswitch server; need to find and test with others.
+
+The stack of temp files needed for MGET /RECURSIVE is annoying because what
+if we run out of file descriptors...  But the spec doesn't provide a way to
+request a recursive listing.
+
+Supplied a missing comma in HELP SET CD text.  ckuus2.c, 19 Aug 2002.
+
+Generalized parsing of MLST/MLSD file facts and values.  Got file type from
+server and had MGET skip non-regular files.  ckcftp.c, 19 Aug 2002.
+
+Kirk Turner-Rustin <ktrustin@owu.edu> reported that if Unix C-Kermit has a SET
+HOST PTY connection (e.g. SSH) open, local window size changes are not
+propogated through the connection to the host.  I imagine that must be because
+the SIGWINCH signal is caught by Kermit and its children don't see it; maybe
+if I pass it along to the child fork, all will be OK.  Began by exporting
+"slavepid" from the pty module and changing its name to pty_fork_pid.  Moved
+the SIGWINCH handler, winchh(), from ckctel.c to ckutio.c.  Armed it from Unix
+sysinit() so it's always armed.  This way window changes affect Unix C-Kermit
+no matter what mode it's in: tt_rows, tt_cols, cmd_rows, and cmd_cols are all
+kept in sync.  Then if we're not in remote mode (i.e. we have a ttyfd), we
+call tn_snaws() and rlog_snaws() (which should be ok since they return right
+away if the appropriate kind of connection is not open) and then if
+(pty_fork_pid > -1), a SIGWINCH signal is sent to it.  ckupty.c, ckctel.c,
+ckutio.c, 20 Aug 2002.
+
+All this works fine except the PTY part; in other words, the original problem
+is not fixed.  The "kill(pty_fork_pid,SIGWINCH)" call executes without error
+but has no effect because the size of the PTY never changed.  To make this
+work I had to add an ioctl() to change the size of the PTY before sending it
+the SIGWINCH.  Compiles and works ok on Linux and Solaris; Kirk also confirmed
+it for AIX 4.3.3.  ckutio.c, 20 Aug 2002.
+
+Fixed xlookup() to work for uppercase keywords.  ckucmd.c, 20 Aug 2002.
+
+Fixed FTP parsefeat() and parsefacts() to use xlookup() instead of lookup(),
+since abbreviated keywords are not allowed.  ckcftp.c, 20 Aug 2002.
+
+Adjusted some lines from yesterday's window-size code for platforms I hadn't
+tried yet.  ckutio.c, 21 Aug 2002.
+
+EXIT from K95 when it has an FTP connection open and it pops up the
+Locus dialog.  Made it not do this if it knows it's in the act of EXITing.
+ckuus[rx].c, 22 Aug 2002.
+
+In K95, FTP GET in ASCII mode results in a file with Unix line terminators
+even though the protocol is correct:
+
+  RETR smjulie.txt
+  150 Opening ASCII mode data connection for smjulie.txt (1878 bytes).
+
+The source file is a regular Unix text file with LF at the end of each line.
+It's incredible that nobody noticed this before.  It only came to light when
+somebody tried to open a downloaded text file with Notepad, which doesn't
+handle Unix-format files (Wordpad and Emacs have no problems with them).  The
+problem was in doftprecv2() in the FTT_ASC section.  There was no conditional
+code for Unix vs Windows.  In all cases, the code discarded incoming CR's in
+ASCII mode.  I put the CR-discarding code in #ifdef UNIX..#endif.  ckcftp.c,
+22 Aug 2002.
+
+Removed super-verbose debugging from gtword(): ckucmd.c, 23 Aug 2002.
+
+Gregory Bond reported a problem with "if defined \$(BLAH) ..." inside of a
+SWITCH statement.  It wasn't really the SWITCH that was doing it, it was the
+fact that he had enclosed the SWITCH case in braces, which made it an
+"immediate macro" (XXMACRO).  The XXMACRO code parsed the macro definition
+(the part inside the braces) with cmtxt(...,xxstring), which should have been
+cmtxt(...,NULL) to defer the evaluation of the interior of the macro until it
+was executed.  This is better illustrated with the following example:
+
+  { echo START, for \%i 1 3 1 { echo \%i }, echo STOP }
+
+which totally fell on its face prior to the fix.  Also fixed ?-help for
+immediate macros, which was broken too.  ckuusr.c, 23 Aug 2002.
+
+RFC959 says STOU does not take an argument.  But every FTP server I've
+encountered but one accepts the arg and constructs the unique name from it,
+which is better than making up a totally random name for the file, which is
+what RFC959 calls for.  Especially because there is no way for the client to
+find out the name chosen by the server (because RFC 959 and 1123 are
+contradictory, plus no servers follow either one of them for this anyway).  So
+we try STOU with the argument first, which works with most servers, and if it
+fails, we retry it without the arg, for the benefit of the one picky server
+that is not "liberal in what it accepts" UNLESS the first STOU got a 502 code
+("not implemented") which means STOU is not accepted, period (which happens
+with ProFTPD).  ckcftp.c, 25 Aug 2002.
+
+Added SET FTP ANONYMOUS-PASSWORD (plus help text and show value).  ckcftp.c,
+25 Aug 2002.
+
+Made FTP command "not available" if NOFTP is defined.  ckuusr.c, 25 Aug 2002.
+
+Forced client to send a TYPE command upon initial connection, since given
+the variable quality of FTP servers, it's not safe to assume the server is
+in ASCII or any other particular mode.  ckcftp.c, 25 Aug 2002.
+
+SET FTP CHARACTER-SET-TRANSLATION ON is completely broken in K95, although it
+works fine in C-Kermit.  Furthermore it is broken in both the GUI and Console
+versions, so it's not a Unicode vs OEM console-character-set issue.
+
+Added Concurrent PowerMAX OS target from Tom Horsley.  makefile, ckuver.h,
+27 Aug 2002.
+
+Minor fixes to FTP module from Jeff.  ckcftp.c, 27 Aug 2002.
+
+New Makefile target for Mac OS X 10.2, needs -DNDSYSERRLIST added, from
+William Bader.  2 Sep 2002.
+
+SET OPT DIR /DOTFILES didn't work for server listings.  A few years ago when
+I front-ended zxpand() with nzxpand(), I missed a couple places where
+traverse() needed to refer to xmatchdot (nzxpand's argument flag) rather than
+global matchdot.  Fixed in traverse(): ckufio.c, 2 Sep 2002.
+
+From Jeff, 4 Sep 2002:
+ . setautodl(x) -> setautodl(x,y): ckuusr.h, ckuus[7y].c
+ . Add another parameter to popup_readblah(): ckuus6.c
+ . Sort out some confusion in scanfile() where a parameter was also used as a
+   local flag.  ckuusx.c.
+ . Protect restoring of saved terminal idle parameters with a flag that says
+   they were actually saved.  ckuusr.c.
+ . Rework uq_text() and uq_mtxt().  ckuus3.c.
+ . Fix FTP charset translation for little-endian hardware: ckcftp.c.
+
+The latter still doesn't work in Linux:
+
+  (/home/fdc/kermit/) C-Kermit>set ftp server-character-set latin1-iso
+  (/home/fdc/kermit/) C-Kermit>set file character-set utf8
+  (/home/fdc/kermit/) C-Kermit>get latin1.txt
+
+Results in "????????: file not found".  But it works fine on the Sun.
+
+Jeff's patch removed a little-endian byte-swap (LEBS) from doftpsend2().  But
+the real problem was that LEBS was not being done consistently throughout the
+module.  There were similar xgnbyte()/xpnbyte() loops elsewhere in the code,
+and all of them needed to work the same way.  Undoing Jeff's fix and then
+adding the LEBS to the loop in getreply() makes downloads work right, but the
+messages are still messed up (they come out in Chinese :-)  Begin by moving all
+byte-swapping operations that occur in ckcftp.c itself into a new function,
+bytswap().  It's either right to do it all the time, or to do it never; this
+way we can turn it on and off in one place.
+
+xp/gnbyte() include behavior that depends on what Kermit is doing: W_SEND,
+etc.  xpnbyte() tests W_KERMIT, which is a combination of W_SEND, W_RECV, etc.
+Defined a new symbol W_XFER, which is like W_KERMIT but includes W_FTP.  These
+are all the "whats" in which character sets might need to be converted.
+Changed the W_KERMIT reference in xpnbyte() to W_XFER.  Fixed the inderminate
+"what" state after an FTP command by moving "what = W_COMMAND;" from before
+the main parse loop to inside it (this didn't matter before the addition of
+FTP but now it does).  ckcker.h, ckcftp.c, ckuus5.c, 6 Sep 2002.
+
+Finally I changed xlatec() to be consistent with all the other xgnbyte() /
+xpnbyte() usage throughout the FTP module and, poof, everything worked in
+Linux (and still works on the Sun).  We still need some work in Windows (where
+the file character-set is not necessarily the console character set for
+messages) but we can tackle that next.  ckcftp.c, 6 Sep 2002.
+
+Checking yesterday's work:
+
+Kermit file transfers with charset translation work fine in both directions.
+
+FTP GET with charset translation works fine on both BE and LE
+
+Fixed a typo in yesterday's changes that made FTP PUT with charset translation
+always upload 0-length files.  ckcftp.c, 7 Sep 2002.
+
+FTP PUT (after the typo was fixed) with charset translation works fine on BE,
+but on LE the message comes out in Chinese and the resulting file gets ? or
+nothing for all for the accented letters:
+
+      FTP...  Kermit 
+      Up  Dn  Up  Dn  Term
+  BE  OK  OK  OK  OK   xx
+  LE  no  OK  OK  OK   xx
+
+xx = C-Kermit CONNECT mode with translation doesn't seem to do anything, not
+only in today's code, but also in the 8.0 release version: "set term char
+latin1 utf8" -- SHOW CHAR shows the right stuff, but no translation is done.
+Ditto for the 7.0 release.  That can't be right...
+
+But one problem at a time -- what's wrong with LE FTP uploads?  Note that
+XLATE works on the same machine, so it's obviously confusion in xgnbyte()
+about "what".  Suppose we make xgnbyte() ALWAYS return bytes in BE order.
+This makes sense because xgnbyte() is almost always used to feed xpnbyte(),
+and xpnbyte() requires its bytes to come in BE order.  This means that all
+code that uses xgnbyte()/xpnbyte() loops can be simplifed, which I did for
+the FTP module.  ckcfns.c, ckcftp.c, 7 Sep 2002.
+
+Of course Kermit protocol uses xgnbyte() too, but only for filling
+packets, and packets never contain UCS2 and even if they did, it would have
+to be big-endian, so no changes needed for getpkt().  Now we have:
+
+      FTP...  Kermit 
+      Up  Dn  Up  Dn
+  BE  OK  OK  OK  OK
+  LE  OK  OK  OK  OK
+
+Now let's look at the remaining xgnbyte() calls in the rest of the code:
+
+ckuus4.c:
+  xlate() uses it of course.  I simplified the general-case loop.
+  Works OK on both Sun and Linux.
+
+ckuus6.c:
+  typegetline() uses it.  I commented out the byte swap.  Seems OK.
+
+Built and tested on Linux, Solaris, and SunOS.  I'm sure I must have broken
+something, but the main things are better than they were.  Kermit and FTP
+transfers need testing in K95, as well as the TYPE command (there's a bunch of
+special K95 code in there).  C-Kermit charset translation during CONNECT is
+still broken, or else I forgot how to use it, but that's a separate issue
+since xgnbyte()/xpnbyte() are not involved.  And we still need to do something
+in FTP getreply() for K95 to convert messages to the console character set for
+display, rather than the file character set (should be trivial).  Also there's
+still a lot of extra debugging and commented-out junk in ckcftp.c to be
+cleaned up after more testing.
+
+During yesterday's testing, I noticed that REMOTE SET { FILE, XFER }
+CHARACTER-SET didn't work.  The server accepted these commands but they didn't
+seem to do anything.  In fact, they did work, but they were undone later by
+code in sfile() that restored the global settings in case they had been
+temporarily overridden by autoswitching or whatever.  The solution is to
+"unsave" the saved values whenever a global setting is performed explicitly.
+Tested successfully against Sun and Linux servers.  Also the server end of
+REMOTE SET needed updating for Unicode.  ckcfn[s3].c, ckuus3.c, 8 Sep 2002.
+
+Cleaned commented-out cruft and extra debugging from ckcftp.c.  8 Sep 2002.
+
+Kermit autodownload with ASK file dialog: if user supplied an absolute
+pathname, it was treated like a relative one.  Fixed the invocation of
+uq_file() in rcvfil() to temporarily override the RECEIVE PATHNAMES setting.
+ckcfns.c, 10 Sep 2002.
+
+Added SET TERMINAL ROLL KEYSTROKES { SEND, RESTORE-AND-SEND, IGNORE }, parse
+only.  Needs implementation (search for tt_rkeys and rollkeytab in ckuus7.c).
+ckuusr.h, ckuus[27].c, 10 Sep 2002.
+
+If FILE INCOMPLETE is DISCARD and a file is being received by IKSD but IKSD
+gets a Telnet LOGOUT command, the partial file is not deleted.  In fact this
+happens any time doexit() is called for any reason during file reception,
+e.g. because of SIGHUP.  Added code to doclean() to check if a download
+output file was open, and if so, to delete it after closing it if keep==0.
+ckuusx.c, 10 Sep 2002.
+
+Added a brief one-line message after remote-mode file transfer saying
+what (or how many) file(s) were transferred, where they went, and whether
+the transfer was successful -- kind of an automatic WHERE command, useful
+with autodownloads so you know what happened.  ckcpro.w, 11 Sep 2002.
+
+The Unix and VMS C-Kermit CONNECT modules have botched remote-charset to
+local-UTF8 translation ever since the Unicode was first added in v7.0.  Fixed
+in ckucns.c, ckucon.c, ckvcon.c, 11 Sep 2002.
+
+On to pattern-matching...  The matchdot business should apply only for (Unix)
+filename matching, not for general string matching.  Fixed in ckmatch():
+ckclib.c, 11 Sep 2002.
+
+A bigger problem occurs in filename matching.  Somehow the dirsep == fence
+business interferes with matching {foo,bar,baz} segments.  For example, I have
+a filename "foo" and I want to match it with the pattern "{foo,bar}".  Somehow
+the segment pattern becomes "*/foo" and doesn't match the string.  Where does
+the '/' get tacked on?  I don't even know how to explain this, but the short
+story was that ckmatch(), under certain circumstances, would back up to before
+the beginning of the filename string, which just happened to contain a "/"
+(and before that a ".") because of who was calling it.  Obviously this is not
+how to write a pattern matching function...  Ensuring that it never backs up
+beyond the beginning of a string fixed the immediate problem and does not seem
+to have broken any other matching scenarios (I have 150 of them in my test
+script).  ckclib.c, 11 Sep 2002.
+
+There's still a problem though.  Suppose the a client sends "dir {{.*,*}}" to
+a server.  This asks for a directory listing of all files that begin with
+dot as well as all files.  Still doesn't work because we don't normally show
+dot-files, but in this case it SHOULD work because ".*" was explicitly
+requested.  Staring at the ckmatch() code revealed how to fix this, and I did,
+but that was only half the problem.  The other half was that the list of
+files being fed to ckmatch() did not include the dotfiles in the first place.
+The cure here is to change nzxpand() to prescan the pattern to see if it
+includes a leading dot, and if so to set the "xmatchdot" flag itself, even
+if it wasn't set by the caller.  ckclib.c, ckufio.c, 11 Sep 2002.
+
+Now that {foo,bar,...} patterns work better, I added a quick hack to the
+DIRECTORY command to allow multiple filespecs to be given, in which case we
+combine them into a {file1,file2,...} pattern before calling nzxpand().  Works
+fine but it's a hack because you don't get file lists upon "?" in the second
+and subsequent filespec fields, but I doubt anyone will notice.  So now,
+finally, people can do "dir .* *" like they do in Unix (except with ls) to get
+a listing of all files in a directory without having to know about or use the
+/DOTFILES switch.  This was NOT done for the server end of RDIR because of
+ambiguity of spaces as separators versus filename characters.)  domydir():
+ckuus6.c, ckuus[r2].c, 11 Sep 2002.
+
+Added a CONTINUE command.  In a script, this does whatever CONTINUE did before
+(e.g. in a FOR or WHILE loop).  At the prompt, it calls popclvl(), which gives
+a more natural way to continue a script that has "shelled out" to the prompt.
+ckuusr.[ch], 11 Sep 2002.
+
+Added help text for CONTINUE.  ckuus2.c, 12 Sep 2002.
+
+From Jeff, 16 Sep 2002:
+ . SET TERM ROLL KEYSTROKES for K95: ckuusr.h, ckuus7.c
+ . Remove the doexit() call from the Telnet TELOPT_LOGOUT handler: ckctel.c
+
+Fixed an FTP debug message to be consistent with Kermit ones.
+ckcftp.c, 16 Sep 2002.
+
+Added SET/SHOW TRANSFER REPORT to turn the post-transfer report off and on.
+ckuusr.h, ckuus[234].c, 16 Sep 2002.
+
+Fixed Solaris (and maybe some other SVORPOSIX builds) to find out their full
+hostname rather than just short form (e.g. watsol.cc.columbia.edu rather than
+just watsol).  ckhost(): ckuusx.c, 16 Sep 2002.
+
+"cat somefile | kermit -Ts -" is supposed to send stdin in text mode, but
+K95's file transfer display reports BINARY.  Looked at C-Kermit code; it seems
+fine.  Looked at packet and debug logs; C-Kermit was indeed sending in text
+mode and announcing it correctly.  K95 gattr() is doing the right thing:
+
+  gattr file type[AMJ]=3
+  gattr attribute A=text=0
+  gattr sets tcharset TC_TRANSP[A]
+
+Same thing happens when C-Kermit is receiving.  Yet when I send an actual
+file, rather than stdin, it's received in text mode.  The only difference is
+that stdin does not have a Length attribute in its A-packet, so in this case
+the receiver skips any calls to screen() that show the length or percent done.
+Aha, so maybe it's just a display problem -- scrft() is not being called to
+repaint the file type if the size was not known.  Fixed in opena() by
+removing the IF clause from "if (fsize > -1L) xxscreen(SCR_FS,0,fsize,"");".
+ckcfn3.c, 18 Sep 2002.
+
+K95 user has a listfile containing some regular filenames and then some
+filenames that include paths and has all kinds of problems with MGET /LISTFILE
+(pieces of different names concatenated to each other, etc).  Setting up the
+same scenario here, I don't see the same problems but I do see "Refused: Name"
+when we go to get a path/name file.  This happens because (a) we had already
+got a top-level file with a certain name, (b) a file in a subdirectory has the
+same name, (c) we are stripping the path before calling zchki(), and (d)
+FTP COLLISION is set to DISCARD.  How do we make FTP not strip the path?
+
+This is an interesting question...  The answer depends on where the user
+wants the file to go.  Normally if you tell an FTP client to "get foo/bar",
+you want the file "bar" to be downloaded to the current directory.
+
+Anyway, it turns out the FTP module uses paths locally during MGET only if
+/RECURSIVE was specified.  So:
+
+  mget /listfile:blah /recursive
+
+should have made this work, but it didn't because in the /LISTFILE case,
+we have effectively turned an MGET into a series of GETs, where the code to
+check whether to strip the path didn't check the recursive flag because how
+could a GET (as opposed to an MGET) be recursive?  Adding this exception to
+the if-condition got us a bit farther but now when we try to open the output
+file in doftprecv2(), zopeno() fails because the name contains a dirsep.
+We have to call zmkdir() first but that wasn't happening because some other
+flag wasn't set right in this case.  Finally zmkdir was called, but with
+the wrong string.  After fixing that, it works.  Now we should be able
+to use /RECURSIVE to force the pathname to be used on the local end.
+ckcftp.c, 19 Sep 2002.
+
+Checked FTP filename conversion issues.  FTP FILENAMES AUTO is supposed to
+mean LITERAL if "wearealike" OR server is UNIX or Windows, otherwise
+CONVERTED, but there were places where this rule was not applied consistently,
+fixed now.  ckcftp.c, 21 Sep 2002.
+
+Added SET FTP DISPLAY, which is like SET TRANSFER DISPLAY but applies only to
+FTP, mainly because I tended to type it all the time.  Now if you have dual
+sessions, each session can have its own transfer display style.  ckcftp.c,
+ckuusr.h, ckuus[347].c, 21 Sep 2002.
+
+Back to FTP MLSD.  We're supposed to match the pattern locally, not rely on
+the server to filter its list according to the client's pattern.  Thus we must
+also allow an empty argument to MGET and must not send a filespec with MLSD.
+Actually this is tricky -- how is the client supposed to know whether to send
+a filespec.  For example, if the user's command is "mget foo*bar", and the
+server supports MLSD, then what should the client do?  The client does not
+know the wildcard syntax on the server, so for all the client knows, this
+might be a valid directory name, in which case it should be sent.  On the
+other hand, the user might intend it as a wildcard, in which case it should
+NOT be sent.  But the FTP client can't read the user's mind.  This is another
+serious flaw in the Elz/Hethmon draft.  Anyway, I got the local matching
+business working for MLSD as long as the user's MGET arg is really a pattern
+and not a directory name.  To be continued...  ckcftp.c, 21 Sep 2002.
+
+Added FTP { ENABLE, DISABLE } { FEAT, MLST }.  If we always send FEAT, we
+usually get a complaint.  If we send FEAT and MLST is negotiated, there is a
+good chance it is misimplemented or will have undesirable side effects, such
+as sending huge file lists.  NOTE: /NOINIT on the FTP OPEN command also
+disables both of these.  ckcftp.c, 22 Sep 2002.
+
+Fixed mkstemp() code in FTP remote_files().  mktemp() does not open the file,
+mkstemp() does open it; previously we had been opening it again and never
+closing the first instance so every MGET would create another open file
+descriptor.  ckcftp.c, 22 Sep 2002.
+
+Added debug messages for temp-file creation and lines read from the temp file.
+ckcftp.c, 22 Sep 2002.
+
+Eliminated sending of some extraneous TYPE commands, but there's still room
+for improvement.  ckcftp.c, 22 Sep 2002.
+
+Moved definition of build date to top of ckcmai.c.  22 Sep 2002.
+
+Added recursion to MGET with MLSD...  It's all done in remote_files().
+Temp-file pointers are on a stack (max size 128).  When parsing MLSD lines
+from the temp file and we see "type=dir", we create the local directory by
+calling zmkdir(), change to the remote by sending CWD, increment the depth,
+and call ourselves.  When reading from a temp file, upon EOF we close and
+dispose of the temp file, return -3 if currently at top level, otherwise we
+free the tmpfile name, decrement the depth, send CDUP to the server, "cd .."
+locally, and go back and read the next line from the previous but now current
+temp file.  Conceptually simple but needed hours of debugging -- what must
+be static, what must be on the stack...  Seems OK now but still needs some
+heavy testing.  ckcftp.c, 22 Sep 2002.
+
+Added FTP { ENABLE, DISABLE } { SIZE, MDTM } and add help text for FTP
+ENABLE and DISABLE.  ckcftp.c, 23 Sep 2002.
+
+Don't allow restart if SIZE disabled.  ckcftp.c, 23 Sep 2002.
+
+Make sure all implicit SIZE commands are surpressed if SIZE disabled.
+ckcftp.c, 23 Sep 2002.
+
+If an explicit FTP MODTIME command is sent when MDTM is DISABLED, and it
+succeeds, re-ENABLE MDTM.  Ditto for SIZE.  ckcftp.c, 23 Sep 2002.
+
+If an explicit FTP FEATURES command is sent during an FTP session, redo the
+features database from it.  ckcftp.c, 23 Sep 2002.
+
+After further discussion with Robert Elz, I realized I had to expose the
+underlying MGET mechanisms to the user; the draft isn't going to change, and
+the new spec will result in undesirable effects if the client tries to "do the
+right thing" by magic in all situations; thus the user must have some new
+controls:
+
+  MGET [ /MLST, /NLST, /MATCH:xxx ] [ filespec [ filespec [ ... ] ] ]
+
+These switches let the user force the use of MLSD or NLST when there's a
+choice, and to force local use of a pattern rather than sending it to the
+server, and even to send a directory name to the server at the same time as
+specifying a pattern for local matching, and of course by default we try to do
+the right thing in all scenarios.  Symbols only; not coded yet.  ckuusr.h,
+23 Sep 2002.
+
+Added the three new switches to MGET, plus /MLST is an invisible synonym for
+/MLSD.  If /NLST or /MLSD is given it, it forces the corresponding FTP protocol
+directive.  ckcftp.c, 25 Sep 2002.
+
+Now for the tricky part: now we have two separate concepts for what to send to
+the server: a filename or wildcard to be interpreted by the server (NLST only)
+or a directory from which to get a list of all the files (NLST or MLSD),
+possibly together with a pattern to be used by the client to match filenames
+returned by the server.  This required giving remote_files() an additional
+argument.  Now it uses "pattern" (if any) strictly for local pattern matching
+(because now it is the /MATCH: switch argument, not the MGET filespec), and
+"arg" (the MGET filespec) is what it sends to the server, maybe (see the
+comments in the code for the actual details); either or both these can be
+null.  ckcftp.c, 25 Sep 2002.
+
+Discovered that "mget foo", where foo is a directory name, never worked.
+Fixed in remote_files(): ckcftp.c, 25 Sep 2002.
+
+Going through every combination of NLST, MLSD, /MATCH:, and MGET arg and
+debugging each case until OK...  Then also with the panix.com NetBSD server
+(lukemftpd 1.0) which also supports MLSD....  11 test cases all debugged and
+tested OK.  ckcftp.c, 26 Sep 2002.
+
+Added /NODOTFILES switch to FTP MGET, to control what happens with dot-files
+if the server includes their names in the list (as lukemftpd does).  There's
+no point in adding a /DOTFILES switch because what could it possibly do?
+ckcftp.c, 26 Sep 2002.
+
+Changed a bunch of "skipthis++" to "continue" in doftpget(), to avoid
+error messages when skipping files that user said she wanted to skip.
+ckcftp.c, 26 Sep 2002.
+
+Added help text for the new MGET switches.  ckcftp.c, 26 Sep 2002.
+
+Don't switch LOCUS when making an FTP connection until logged in.
+ckcftp.c, 26 Sep 2002.
+
+Fixed LDIR to run Kermit's built-in DIRECTORY code rather than the external
+directory program.  ckuusr.c, 26 Sep 2002.
+
+Protect iswild() against NULL args.  ckufio.c, 26 Sep 2002.
+
+From Jeff: SET GUI WINDOW RUN-MODE { MAXIMIZE, MINIMIZE, RESTORE },
+plus variables for GUI Window X position, GUI Window Y position, GUI
+Window X resolution, GUI Window Y resolution, GUI Window Run mode.
+ckuusr.h, ckuus[24].c, 27 Sep 2002.
+
+From Ronan Flood: updated FreeBSD 1.0 makefile entry, plus an #ifdef to protect
+sysconf() calls.  makefile, ckutio.c, 28 Sep 2002.
+
+Change ftp_auth() to return(0) if an AUTH command gets a 500 response, so it
+doesn't keep sending other kinds of AUTH commands.  ckcftp.c, 29 Sep 2002.
+
+Changes from Jeff to yesterday's changes.  ckcftp.c, 30 Sep 2002.
+
+From Jeff: SSH command-line personality.  Uses same command line as the Telnet
+personality.  ckcker.h, ckcmai.c, ckuus[4y].c, 3 Oct 2002.
+
+From Jeff, 7 Oct 2002:
+ . SET PRINTER CHARACTER-SET.  ckuxla.c, ckuusr.h, ckuus[25].c
+ . Promotion of K95 to Beta.01.  ckcmai.c
+ . Promotion of SET GUI { MENUBAR, TOOLBAR } to visible.  ckuus3.c
+
+Changed the URL parser as follows: if the username and/or password fields are
+present but empty, as in:
+
+           ftp://@ftp.xyzcorp.com/somepath
+  or:      ftp://:@ftp.xyzcorp.com/somepath
+  but not: ftp://:ftp.xyzcorp.com/somepath
+
+the pointer for these items becomes a pointer to an empty string, rather than
+a NULL pointer.  Then when we go to open the connection, if the username
+string pointer points to an empty string, we prompt for the username (and/or
+password).  ckuusy.c 9 Oct 2002.
+
+Jason Heskett reported an interesting bug involving a core dump when an
+ON_EXIT macro is defined that executes another macro.  Sometimes.  He was able
+to send a short command file that always crashed.  Diagnosis: ON_EXIT, when it
+is called, pokes itself out of the macro table by setting its own entry in the
+macro name list to an empty string.  But this interferes with any macro
+lookups that are done while executing ON_EXIT's body and also evidently some
+code is not happy with empty macro names...  To fix: replace "on_exit" with
+"on_exxx", so the replacement keyword is (a) nonempty, and (b) doesn't wreck
+the alphabetical sorting of the table.  ckuusx.c, 9 Oct 2002.
+
+Added makefile targets for FreeBSD 4.6 and 5.0.  Built and tested on 4.6;
+don't know about 5.0.  ckuver.h, makefile, 9 Oct 2002.
+
+Added targets for AIX 5.2 and 5.3; totally untested.  ckuver.h, makefile,
+9 Oct 2002.
+
+Built current source on Unixware 7.1.3 (make uw7); it's fine.  9 Oct 2002.
+
+Promoted C-Kermit to 8.0.206 Beta.01 in hopes of a simultaneous release
+with K95 2.1.  ckcmai.c, 9 Oct 2002.
+
+From Jeff: Change KERMITFONT definitions to use the new (Unicode 3.1) code
+points for the terminal graphics characters (such as VT100 horizontal scan
+lines), rather than private-use codes.  ckcuni.c, 10 Oct 2002.
+
+Jason Heskett also complained that REMOTE CD would print the name of the new
+directory returned by the server even if he SET QUIET ON.  This is a tricky
+one.  Which server replies should the QUIET settings apply to?  If I give a
+REMOTE DIRECTORY command, it means I want to see the directory listing,
+period.  But if I give a REMOTE CD command, I get an "unsolicited" response
+message that SET QUIET ON should suppress.  Adding message suppression to 
+rcv_shortreply() is close, but not totally right; for example, it also
+suppresses the response to REMOTE PWD, which is not helpful.  The only right
+way to do this is to suppress for REMOTE CD only, which can be done only by
+setting a (new) global flag, rcdactive.  ckuus[r57].c, ckcpro.w, 10 Oct 2002.
+
+Ditto for REMOTE LOGIN response message ("Logged in").  ckuus7.c, 11 Oct 2002.
+
+From Jeff: SET GUI WINDOW FONT { NAME, SIZE }. ckuusr.h, ckuus4.c, 11 Oct 2002.
+
+Quick preliminary 8.0.206 build-all:
+
+ OK SunOS 4.1.3
+ OK Solaris 2.5.1
+ OK Solaris 9
+ OK AIX 4.3.3
+ OK HP-UX 10.20
+ OK VMS 7.1 Alpha + TCP/IP
+ OK VMS 7.1 Alpha nonet
+ OK VMS 5.5 VAX + TCP/IP
+ OK VMS 5.5 VAX nonet
+ OK Unixware 7.1.3
+ OK FreeBSD 3.1
+ OK FreeBSD 4.6
+ OK NetBSD 1.5.2 MVME (Gerry B)
+ OK Sinix 5.42
+
+Sinix build got stuck on ckuusr.c even though we're not optimizing on Sinix
+any more.  Rebooting the machine fixed it.
+
+Fixed some #ifdefs for VMS in new incomplete-file deletion code in doclean().
+ckuusx.c, 11 Oct 2002.
+
+Moved uq_blah() prototypes from ckuusr.h to ckcker.h because these routines
+are called in modules that don't (and shouldn't have to) include ckuusr.h.
+11 Oct 2002.
+
+Jeff verified secure builds on Linux and Solaris.
+
+Custom-build workout: 80 different feature-selection combinations:
+ . Fixed yesterday's change for NOSPL: ckcfns.c.
+ . Fixed conflict between NORECALL and USE_ARROWKEYS: ckucmd.c.
+ . Moved setseslog() from ckuus5.c to ckuusx.c to avoid link-time foulups.
+ . Fixed an unguarded reference to zmkdir() in ckcftp.c.
+ . Protected rmsg() by #ifndef NOXFER: ckuus7.c.
+ . Protected initxlist() by #ifndef NOXFER: ckcmai.c.
+ . Fixed unguarded references to g_url struct in xx_ftp(): ckuusy.c.
+ . Fixed unguarded references to tt_snaws() in winchh(): ckutio.c.
+
+--- 8.0.206 Beta.01 11 Oct 2002 ---
+
+From Jeff, 16 Oct 2002:
+ . Fix K95 RMDIR: ckcfn3.c.
+ . Makefile targets for Red Hat 7.2, 7.3, 8.0: ckuver.h, makefile.
+ . Added \v(log_xxx) for each kind of log for PeterE: ckuusr.h, ckuus4.c.
+ . Added SET TERM ATTRIBUTE DIM { ON, OFF }: ckuus[27].c.
+ . Change "const" to "CONST" in some PAM declarations.  ckufio.c.
+
+Added SET MATCH { DOTFILE, FIFO } { ON, OFF }.  A FIFO special file is a named
+pipe, used for interprocess communication.  It must be opened at both ends, so
+it's silly to match them by default; opening a FIFO and attempting to read
+will block forever unless somebody is writing into the other end.  Made the
+MATCH FIFO default OFF in all cases.  The dotfile default is the same as
+always (OFF for UNIX, ON elsewhere); SET MATCH DOTFILE is simply a more
+untuitive and findable command than SET WILD KERMIT /MATCH-DOT-FILES.  Note
+that SET MATCH DOTFILE undoes SET OPTIONS DIRECTORY /[NO]DOTFILES, and vice
+versa.  ckcmai.c, ckuusr.h, ckuus[23].c, ckufio.c. 17 Oct 2002.
+
+Added client and server end of REMOTE SET MATCH { DOTFILE, FIFO } { ON, OFF }.
+The new protocol codes are 330 and 331, respectively.  ckuus[367].c, ckcfns.c,
+17 Oct 2002.
+
+Adjusted the "match dot if pattern starts with dot" heuristic in nzxpand()
+to not kick in if the filespec is "./foo".  This probably needs more work.
+ckufio.c, 17 Oct 2002.
+
+Fixed typo in transcribing Jeff's ckcfn3.c code from yesterday.  18 Oct 2002.
+
+Moved some help text out of #ifdef ANYSSH that had nothing to do with SSH.
+(Idea for a new EMACS feature: M-X list-ifdef-environment.)
+ckuus2.c, 18 Oct 2002.
+
+Removed "set file { permission, protection }" keywords, which led nowhere.
+ckuus7.c, 18 Oct 2002.
+
+Added -DSV68 to all SV/68 targets.  Make ckgetfqhostname() just return its
+argument in SV/68; it dumps core otherwise.  In case this happens anywhere
+else, add -DNOCKGETFQHOST to CFLAGS.  makefile, ckcnet.c, 18 Oct 2002.
+
+For PeterE, added SET { SEND, RECEIVE } PERMISSIONS { ON, OFF } so incoming and
+outbound permission attributes can be set separately. ckuus[27].c, 18 Oct 2002.
+
+Changed SHOW ATTRIBUTES to show In and Out permissions separately.
+ckuus5.c, 18 Oct 2002.
+
+Fixed REDO to display the command it's redoing and to add it to the bottom
+of the recall buffer.  ckuusr.c, 18 Oct 2002.
+
+Discovered that DATE SATURDAY dumps core...  Apparently it always did; this
+case was not included in the date-time torture test script.  The crash happens
+because the DATE parsing code doesn't check for a NULL date-converion
+error-message pointer.  Fixed in ckuusr.c, 18 Oct 2002.
+
+The reason DATE SATURDAY got a date-conversion error was that this path thru
+the code left a result pointer unset.  Fixed in cmcvtdate(): ckucmd.c,
+19 Oct 2002.
+
+DATE SUNDAY +1DAY returned incorrect results (for any day-of-week name, any
+delta time), even though DATE TODAY +1DAY worked fine.  Fixed in cmcvtdate():
+ckucmd.c, 19 Oct 2002.
+
+SET TAKE ECHO ON counted each line twice when GOTO was active.  Fixed in
+dogoto(): ckuus6.c, 19 Oct 2002.
+
+Jeff noticed:
+"KERMIT READY TO GET...
+ RCVD: (2 files) Last: [/amd/prost/p/kd/jaltman/.src/ckonet.c] (OK)
+the last file attempted may have been ckonet.c but it certainly was
+not the last file received" (similarly for sending).  Fixed by having two
+pointers for each name; a preliminary pointer, which is set for each file at
+the beginning of the transfer (when we have all the needed info), and a final
+one that is set from the preliminary one only after the file was transferred
+successfully.  This corrects not only the automatic "wheremessage" at the end
+of a remote-mode transfer, but also the WHERE and SHOW FILE command results.
+ckuusx.c, ckcfn[s3].c, ckcpro.w, 19 Oct 2002.
+
+From Jeff: Improve ORIENTATION message for K95 to say which directories are
+for which INI files.  ckuusr.c, 23 Oct 2002.
+
+Removed Beta designation from herald.  ckcmai.c, 23 Oct 2002.
+
+Put final dates and ID strings in Unix and VMS build procedures.
+Makefile, ckvker.com, 23 Oct 2002.
+
+Build-all...  #ifdef adjustments: ckcfns.c...  83 different feature-set
+combinations build OK on Linux.  23 Oct 2002.
+
+From Jeff: SET WIN95 HORIZONTAL-SCAN-LINE-SUBSTITUTIONS.  ckuusr.h, ckuus7.c,
+24 Oct 2002.
+
+Fixed Heath-19 graphic character-set table to use new Unicode 3.1 values
+if WIN95 HORIZ OFF.  ckcuni.c, 24 Oct 2002.
+
+Changed tx_usub() to return Unicode 3.1 values if WIN95 HORIZ OFF.
+ckcuni.c, 24 Oct 2002. <-- No backed off on this.
+
+Some problems during build-all:
+
+ . VMS 7.1 TGV 4.2: If I make a Telnet connection with it, then try to send
+   a file (itself. wermit.exe) over the connection, the connection drops
+   after about 20%, the thermometer zooms out to 100% and SUCCESS is reported.
+   This doesn't happen with UCX.
+
+ . VMS 7.3 TGV 4.3: ckcmai.c won't compile because of a complaint about the
+   declaration of select() (which ckcmai.c doesn't use) in
+   SYS$COMMON:[SYSLIB]DECC$RTLDEF.TLB.  Ditto in VMS 7.2 TGV 4.3.
+   Adding NOSELECT to CFLAGS doesn't help.  I don't think the VMS version
+   even uses select().  But the TGV 4.3 builds were OK in 8.0.201, so what
+   changed?  I don't see anything in ckcnet.h that would have done it.
+
+It builds OK with VMS 7.1 / TGV 4.2 but sending files on Telnet connections
+fails in a strange way: the connection drops, but the thermomoter goes to 100%
+and success is reported.  I don't know why the connection is dropping (s_errno
+is 32 == "broken pipe"), but the spurious success indication is because of
+a double failure in sdata(): (1) The packet-sending loop index could go
+negative without breaking the loop when streaming; (2) if spack() fails,
+sdata() should return -2, not -1 (which means EOF).  Also if any ttchk() in
+sdata() returns < 0, sdata should return -2.  I fixed this code (which has
+been this way for YEARS) and now VMS C-Kermit properly fails when it gets
+the spack() error, but ttchk() in this case still doesn't think the connection
+is lost, but that must be our new problem with MultiNet.  ckcfns.c,
+27 Oct 2002.
+
+The compilation failure in ckcmai.c is a clue...  The problem was that I added
+#ifdef VMS / #include <time.h> / #endif to shut up complaints about the time()
+call.  Evidently something in VMS <time.h> gives MultiNet a bad case of
+indigestion; removing it fixes the compilation and the result works fine.  The
+transmission failures in the other case seem to be a coincidence -- something
+to do with the U of Arizona (probably some obscure VMS quota on my IDs there,
+or some kind of network connection throttling), since it doesn't happen
+anywhere else.  ckcmai.c, 27 Oct 2002.
+
+Changed four occurrences of "void" to "VOID" in ckcftp.c, 27 Oct 2002.
+
+Defined NOCKFQHOSTNAME for HPUXPRE65.  Might also need this for HP-UX 7
+and maybe 8.  ckcnet.c, 27 Oct 2002.
+
+From Jeff: PAM_CONST definition to clear up warnings caused by different
+vendors' definitions of PAM structs.  ckufio.c, 28 Oct 2002.
+
+Unixware 2.1.0 build bombs immediately with "UX:make: ERROR: line too long"
+(which line?)  Not worth chopping up the makefile to fix but in a pinch it
+could be done.  2.1.3 builds OK.
+
+Did another 20-some platform builds, bringing the total to 83, plus a final
+runthrough of the build-with-84-different-feature-set-combinations script on
+Linux.  Should be good to go!
+
+--- 8.0.206 24 Oct 2002 ---
+
+Finally got access to Linux on IA64 again.  Builds OK but dumps core
+immediately on startup.  Adding -DNOCKGETFQHOST was necessary but not
+sufficient.  In this case, the very call to ckgetfqhostname() from ckhost()
+(which is in ckuusx.c) was dumping core; thus I had to move the definition of
+NOCKGETFQHOST from ckcnet.c to ckcdeb.h, add an #ifdef __ia64__ clause to it,
+and protect the call to ckgetfqhostname() with it.  Obviously there has to be
+a better fix but this will have to for now.  ckcnet.c, ckuusx.c, ckcdeb.h,
+31 Oct 2002.
+
+Link step fails in Mandrake 9.0 with undefined references to res_search,
+dn_expand, and crypt.  Turns out the linux makefile target tests for the
+existence of libcrypt.a and libresolv.a, but in Mandrake 9.0 they exist
+only as *.so.  Changed linux target to look for both.  makefile, 1 Nov 2002.
+
+Vace reported that "ftp mget a b c" would get ALL files from the server's
+directory if c did not exist.  Diagnosis: off-by-one error in counting MGET
+args processed.  Naturally fixing this bug revealed another (this time
+cosmetic) one, which resulted in spurious error messages when hitting MGET
+args that have no match on the server.  Fixed in ckcftp.c, 1 Nov 2002.
+
+Rebuilt about 60 of the most important Unix binaries to pick up the fixes
+31 Oct - 1 Nov 2002, and refreshed the FTP site with new sources, tarballs,
+ZIP files, etc.  Sat Nov  2 19:11:30 2002
+
+From Martin Vorlaender and Jeff, SSL/TLS support for VMS:
+ckuusr.h, ckuath.h, ckcnet.c, ckctel.c, ckuath.c, 10 Nov 2002.
+
+Added PASV as invisible synonym for PASSIVE.  ckcftp.c, 10 Nov 2002.
+
+--- 8.0.206 24 Oct 2002 #2 ---
+
+More work on SSL in VMS: Jeff + Martin Vorlaender: ck_ssl.c ckcmai.c ckcnet.c
+ckctel.c ckuath.h ckvcon.c ckvtio.c ckvker.com 10-15 Nov 2002.
+
+Discovered that ckvfio.c would not compile on VMS 6.1 with UCX 4.1 because 
+<conv$routines.h> was missing, which is explicitly included.  Enclosed the
+#include in #ifdef NOCONVROUTINES..#endif and rebuilt with
+@[users.fdc.src]ckvker.com "" "" "NOCONVROUTINES".  16 Nov 2002.
+
+Fixed the "ftp mget */data/*" problem with two small changes to doftpget():
+ckcftp.c, 16 Nov 2002.  Placed a copy of ckcftp.patch in ~kermit/f.
+
+From Lucas Hart: Fixes for VAX C 2.x and CMU TCP/IP.  "Can't guarantee that
+the revised CKVOLD will work for all combinations of more recent
+VMS/compiler/TCPIP releases, but I've tested it for compatibility on our AXP
+VMS 6.2, UCX 4.0, DECC 5.6, your AXP VMS 7.1, DEC TCPIP 5.1, DECC 6.0 as well
+as with VAX VMS 5.4, VAX C 3.2, CMU12 and VAX VMS 4.7, VAX C 2.4."  ckvfio.c,
+ckvtio.c, ckuus5.c, ckvker.com, ckvold.com, 17 Nov 2002.
+
+From Jeff: More work on VMS SSL.  Now it actually works, even in CONNECT mode,
+except it hangs when it gets an error alert or the remote closes the
+connection.  ckcnet.c. ckvtio.c, 17 Nov 2002.
+
+NOTE: Lucas's changes should go into the 8.0.206 source code but it's too
+late since ckvtio.c (upon which he based his changes) is already full of
+SSL code.
+
+MGET in K95 in totally broken FOR SOME PEOPLE (mainly me) if the TMP (or TEMP)
+value is too long.  It works fine if you set these to C:\TMP.  Diagnosis: (1)
+we were malloc'ing only 16 bytes for the temp file name (I think this was my
+fault -- I was only looking at the "ckXXXXXX" part and forgetting that this
+was appended to the TMP path); (2) the Windows version of mktemp() wants you
+to use the value pointed to by the pointer it returns, rather than assuming
+the mktemp() arg will be modified in place.  The code was changed to malloc a
+longer string and to use the return value from mktemp() (if any) rather than
+assuming that mktemp() modified its argument string (in K95 only -- not sure
+about Unix platforms; the man pages differ on this, but at least this way if
+some mktemp() version does NOT alter its argument, we still have a usable
+filename (like /tmp/ckXXXXXX)).  Of course this won't be good for recursive
+MLSD downloads, but we can always issue patches for the Unix version later if
+needed.  The Linux and BSD versions use mkstemp() anyway.  There is, however,
+a danger of a memory leak in the Unix version if the user has defined a TMPDIR
+or CK_TMP environment variable whose value is longer than 9 bytes.  All this
+is highly unlikely so we should be OK.  ckcftp.c, 17 Nov 2002.
+
+--- K95 2.1.1 and updated ck[uv]206.{tar,zip} but not C-Kermit binaries ---
+
+From Jeff: Fixes for Telnet Com Port Control, update to a newer release of
+OpenSSL: ck_ssl.c ck_ssl.h ckcdeb.h ckcftp.c ckcmai.c ckcnet.c ckctel.c
+ckuath.c ckuath.h ckucns.c ckuus4.c ckuus5.c ckuusr.c ckuusr.h ckvcon.c
+ckvfio.c ckvker.com ckvtio.c ckvvms.h, 25 Nov 2002.
+
+--- K95 2.1.2 and C-Kermit 8.0 CDROM ---
+
+From Jeff, 28 Nov 2002:
+ . Updated SSL modules: ck_ssl.[ch].
+ . Fixed cipher-list display in SHOW AUTH & FTP ssl_auth(): ckuus7.c. ckcftp.c
+ . Some minor tn_wait() fixes: ckctel.c.
+ . Preliminary SSL support for VMS CONNECT: ckvcon.c.
+
+Bumped C-Kermit edit number to 207.
+
+From Jeff, 29 Nov 2002: "[C-Kermit was dumping core on SCO OSR5 Telnet Com Port
+connections because] the SCO compiler treats all characters as signed.  This
+was causing 'sprintf(buf,"02x ",ch);' to produce strings such as "ffffffc2"
+instead of "c2" for values between 128 and 255.  This wrote beyond the end of
+a buffer and blew away the stack.  Having fixed this I also noticed that
+conect() did not properly check for carrier when TN CPC was negotiated.  This
+has now been fixed as well."  ckucns.c, ckucon.c, ckctel.c, 29 Nov 2002.
+
+From Jeff, 30 Nov 2002: Fix SSL for VMS and also carry forward the CPC fixes
+to VMS.  ckcnet.c, ckvtio.c, ckvcon.c, 30 Nov 2002.
+
+Changed copyright dates that are displayed (but not yet all the internal
+ones) from 2002 to 2003.  ckcmai.c, 3 Jan 2003.
+
+Fixed the FTP module's brief-format transaction log, which had the status
+inverted: OK for FAILED and v.v.  ckcftp.c 3 Jan 2003.
+
+From Jeff, 4 Jan 2003:
+ . Make /MOVE-TO:xxx convert xxx to full pathname: ckuus[r67].c,
+ . Make SHOW OPTIONS ALL show both kinds of options: ckuus2.c.
+ . More command-line personalities: ckcmai.c, ckuusy.c.
+ . New NOSCROLL command for K95: ckuusr.[ch], ckuus2.c.
+ . New lockdown and other command-line options: ckuusr.h, ckuusy.c.
+ . SSL interface updated to OpenSSL 0.9.7: ck_ssl.c.
+ . SET TERM LINE-SPACING and CURSOR xxx NOBLINK: ckuus[27]c.
+ . Expanded SHOW GUI command: ckuus3.c
+ . New SHOW TABS code: ckuus5.c.
+
+Updated SUPPORT (BUG), NEWS, and INTRO texts.  ckuus[26].c. 5 Jan 2003.
+
+Fixed FTP module to suppress "'FEAT': Command not understood" message
+unless FTP DEBUG is ON.  ckcftp.c, 6 Jan 2003.
+
+Got a report that C-Kermit dumps core on Solaris when executing a certain
+script.  Seems to be related to changing vnambuf[] in zzstring() from an
+automatic array to a malloc'd buffer (see notes from 29 Jun 2000).  Changed
+it to an automatic buffer except for K95.  ckuus4.c, 6 Jan 2003.
+
+Nope, that's not it.  It evidently happens only after FTP PUT has been used.
+Fixed solaris9g makefile target to include -funsigned-char and built a new
+binary.  Determined that building with gcc and -funsigned-char makes no
+difference.  makefile, 7 Jan 2003.
+
+I did a preliminary audit, looking at the items in the left column: if used in
+a given routine, are there any obvious mistakes:
+
+                       1        2          3           4              5
+                   doftpput->putfile->sendrequest->doftpsend2->secure_write
+malloc                OK       OK         OK          OK             OK
+makestr               OK       OK     	  OK          OK    	     OK
+automatic arrays      OK       OK     	  OK          OK    	     OK
+[ck]str[n]cpy         OK       OK     	  OK          OK    	     OK
+[ck]str[n]cat         OK       OK     	  OK          OK    	     OK
+sprintf               OK       OK     	  OK          OK    	     OK
+nzltor                OK       OK     	  OK          OK    	     OK
+zfnqfp                OK       OK     	  OK          OK    	     OK
+memcpy                OK       OK     	  OK          OK    	     OK
+bcopy                 OK       OK     	  OK          OK    	     OK
+
+secure_write sends the data directly on clear-text connections.  On secure
+connections, it calls secure_putbuf(), which calls secure_putbyte(), but we
+aren't using those, so secure_write() is the end of the call chain for FTP
+PUT.  doftpsend2 has buf[] as an automatic array, which it reads file data
+into using zxin (binary mode only), but this looks OK.  Still, I changed it
+read 1 less than the buffer size (fread) just in case.  Also there was one
+debug() statement that referred to an automatic array (fullname[]) before it
+was initialized (but not used in this case), which I fixed.  ckcftp.c,
+7 Jan 2003.
+
+FTP GET /RECURSIVE somepath/somefile still didn't work, despite what the
+notes of 19 Sep 2001 say.  There are so many paths through the code,
+depending on switch values, GET vs MGET, etc, that a crucial spot was missed.
+Fixed in doftpget(): ckcftp.c, 7 Jan 2003.
+
+Back to the core dump...  after two days of full-time debugging, I found the
+culprit: the buffer-full test in the zzout() macro should have been ">="
+rather than just ">", thus Kermit wrote 1 byte past the end of the malloc'd
+FTP PUT output buffer, ucbuf.  Why did it never happen in K95?  Because, since
+it's a secure build, FUDGE_FACTOR is defined there.  But it's not defined in
+Solaris or other clear-text builds.  Although the crash wouldn't happen in
+secure builds, the 1-byte leak might have caused errors in the data transfer.
+In non-Solaris clear-text builds, like Linux, I suspect that malloc() tends
+add something for safety (especially given the man page statement that it
+allocates "at least" what you asked for).  Another reason the problem escaped
+notice is that zzout() is used only for text-mode PUTs (and then only when
+there is no character-set translation), but most transfers these days are
+binary and/or downloads.  Anyway, in the course of debugging, a lot of small
+cleanups were done: sizeof(blah) for all arrays was replaced by the same
+symbolic size that was used to allocate the array, numeric array sizes were
+replaced with symbolic ones, etc.  The real fix is one character long.
+ckcftp.c, 9 Jan 2003.
+
+Got a report that "mget /recursive */somedir/*" downloaded the files into
+the current directory, rather than re-creating the remote directory structure.
+Fixed in doftpget(): ckcftp.c, 10 Jan 2003.
+
+Unix C-Kermit did not allow file transfer if started under inetd and accessed
+via Internet raw socket (or whatever).  Diagnosis: isatty() and friends would
+fail causing ttopen() to fail.  Fixed by adding escape clauses for "-l 0"
+situations (i.e. Kermit invoked with an already-open file descriptor) at the
+appropriate places.  ckcmai.c, ckutio.c, 14 Jan 2003.
+
+From Jeff for K95 2.1.3
+ . Add test for startflags & 128 to trap() for ignoring BREAK.
+ . Fix for SHOW TRANSMIT.
+
+--- K95 2.1.3 ---
+
+FTP USER, FTP ACCOUNT, plus the various prompts and switches for FTP username,
+password, and account all neglected to strip quotes, and in most cases quotes
+are necessary to specify a username that contains spaces.  ckcftp.c,
+15 Jan 2003.
+
+FTP MPUT f1 f2 f3... gets a parse error if any of the fn's do not match an
+existing file.  This is bad for scripts.  In doftpput(), cmfdb() looks for
+keywords (switches) or CMIFI.  When it hits CMIFI, it exits from the initial
+parse loop and then does additional cmifi()s in a loop until done.  The most
+obvious fix is to parse each field with cmfdb(CMIFI,CMFLD), i.e. fall back to
+CMFLD if CMIFI doesn't match anything.  Then if CMFLD was used, we don't add
+the filespec to the list.  This is a rather big change but it seems to work.
+No error messages or failures happen for non-matching fields, but an error
+message is printed (and the MPUT command fails) if none of the fields match
+any files.  This fix got in too late for 2.1.3; workaround: use C-Shell
+like wildcard list (ftp mput "{*.abc,foo.*}").  ckcftp.c, 16 Jan 2003.
+
+GREP did not pass its pattern through the expander, thus variables could
+not be used for patterns.  This must have been an oversight -- I can't find
+anything in my notes about it.  Fixed in dogrep(): ckuus6.c, 24 Jan 2003.
+
+New makefile target for HP-UX 11.xx with OpenSSL from Tapani Tarvainen.
+makefile, 31 Jan 2003.
+
+From Jeff:
+ . Avoid core dump when dereferencing tnc_get_signature(): ckuus4.c.
+ . Bump version numbers to 8.0.208, 2.1.4: ckcmai.c.
+
+Added /NOLOGIN to FTP [OPEN].  ckcftp.c, 10 Feb 2003.
+
+Don't dump core if FTP DEBUG is ON and FTP OPEN does not include a service.
+openftp(): ckcftp.c, 10 Feb 2003.
+
+HELP PATTERN text incorrectly identified commands and functions with
+floating and anchored patterns.  The corrected lists are:
+Floating: GREP, TYPE /MATCH:, /EXCEPT: patterns, \farraylook(),
+Anchored: IF MATCH, file-matching wildcards, \fsearch(), \frsearch()
+ckuus2.c, 10 Feb 2003.     
+
+INPUT n \fpattern(xxx) did not work for case-independent comparisons.
+Fixed in doinput(): ckuus4.c, 10 Feb 2003.
+
+It seems \fpattern() didn't work with MINPUT at all.  There was no code to
+handle \fpattern() in the MINPUT parse loop, so it never worked.  The code
+had to be totally rewritten to use cmfld() in a loop, rather than cmtxt()
+and then cksplit().  Furthermore, whenever any of the fields was an
+\fjoin(), this had to be split.  ckuusr.c, 10 Feb 2003.
+
+Macro replacement via \m() and \fdefinition() does not work as advertised
+(i.e. case sensitively) for associative array elements; e.g. \m(xxx<abc>) is
+treated the same as \m(xxx<ABC>), contrary to section 7.10.10 of the C-Kermit
+7.0 update notes, and to the fact that the two really do exist separately.
+Fixed by adding a static function isaarray(s) which succeeds if s is an
+associative array reference and fails otherwise, and then having \m()
+and \fdef() call mxxlook() (case-sensitive lookup) if isaarray(), otherwise
+(as before) mxlook()).  ckuus4.c, 11 Feb 2003.
+
+Fixed FTP OPEN to allow the /USER switch to override SET FTP AUTOLOGIN OFF,
+just as /NOLOGIN overrides SET FTP AUTOLOGIN ON.  ckcftp.c, 11 Feb 2003.
+
+In K95, "set key \1234 \27H" (any SET KEY command in which the first char of
+the definition was backslash, and the ONLY character after the backslash
+quantity was an uppercase letter, that letter would be lowercased).  Diagnosis:
+xlookup() poking its argument (see notes from July 2000).  Jeff sent a fix.
+ckucmd.c, 15 Feb 2003.
+
+Ran my S-Expression torture test to make sure Sexps still worked.  They do,
+except the bitwise & and | operators were broken, e.g. (& 7 2) and (| 1 2 4)
+get "Invalid operand" errors.  Jeff's code had added an early failure return
+from the lookup loop when when a single-byte keyword matched a keyword that
+started with the same byte but was more than one byte long.  So "&" would hit
+"&&" and fail instead of continuing its search (xlookup tables aren't sorted
+so there can be no early return).  Fixed in xlookup(): ckucmd.c, 16 Feb 2003.
+
+Got rid of "krbmit" target from makefile.  It's still there, but we don't
+use it any more.  All secure targets now use "xermit", and produce a binary
+called wermit, just like the regular ones do (except the old ckucon.c ones).
+Non-secure targets, since they don't define any of the security symbols,
+wind up compiling and linking to (mostly) empty security modules.  makefile,
+15 Feb 2003.
+
+Added \fcvtdate(xxx,3) to format its result in MDTM format (yyyymmddhhmmss,
+all numeric, no spaces or punctuation).  Of course these numeric strings
+are too big to be 32-bit numbers and are useless for arithmetic, but they're
+useful for lexical comparison, etc.  ckuus[24].c, 16 Feb 2003.
+
+The following FTP commands did not set FAILURE when they failed: RMDIR,
+CD, CDUP, Fixed in the corresponding doftpblah() routines.  ckcftp.c,
+16 Feb 2003.
+
+RENAME would sometimes not print an error message when it failed, e.g. in K95
+when the destination file already existed.  ckuus6.c, 17 Feb 2003.
+
+Fixed COPY error messages, which did not come out in standard format when
+/LIST was not included.  ckuus6.c, 17 Feb 2003.
+
+Fixed #ifdefs in ck_crp.c to allow nonsecure builds on old platforms like
+System V/68 R3.  19 Feb 2003.
+
+Similar treatment for ck_ssl.c.  20 Feb 2003.
+
+From Jeff, 21 Feb 2003:
+ . AIX53 and AIX52 symbols for ckcdeb.h, makefile.
+ . New gcc targets for various AIX 4.x/5.x versions: makefile.
+ . Copyright date updates: ck_crp.c, ck_ssl.c.
+ . ENABLE/DISABLE QUERY broken because keyword table out of order: ckuusr.c.
+ . Fixed the use of HTTP proxies for HTTP [RE]OPEN for Unix: ckcnet.c.
+
+Also for K95 only: Allow file transfer when K95 is invoked on the remote end
+of a connection to a Pragma Systems Terminal Server connection; automatically
+SET EXIT HANGUP OFF when invoked with open port handle ("k95 -l nnnn").
+
+"cd a*" failed even when "a*" matched only one directory.  Fixed in cmifi():
+ckucmd.c, 21 Feb 2003.
+
+In the Unix version, replace "extern int errno;" with "#include <errno.h>"
+if __GLIBC__ is defined, since glibc now defines a thread-specific errno.
+ckcdeb.h, 26 Feb 2003.
+
+Added #ifdefs to skip compilation of ckuath.c in nonsecure builds.  Tested
+by building both secure and regular versions in Linux.  ckuath.c, 26 Feb 2003.
+
+Ran the build-in-84-different-configurations script on Linux to make sure it
+still builds with all different combinations of feature selection options.
+All OK.  26 Feb 2003.
+
+Built on VMS.  Needed to add a prototype for mxxlook*() to ckuusr.h; built
+OK otherwise.  26 Feb 2003.
+
+From Jeff: More #ifdef shuffling for nonsecure builds: ckuath.c, ck_ssl.c,
+27 Feb 2003.
+
+Added code to ensure \v(download) ends in a directory separator in Unix,
+Windows, and OS/2.  ckuus7.c, 27 Feb 2003.
+
+Added code to K95 zfnqfp() to tack on directory separator when returning
+a directory name.  ckofio.c, 27 Feb 2003.
+
+Somehow an old copy of ckuath.c popped to replace the new one.  Put the new
+one back.  28 Feb 2003.
+
+From Jeff: Fix typo in my K95 zfnqfp() code from yesterday; fixes for handling
+UNCs uniformly, no matter which way their slashes are leaning.  ckofio.c,
+28 Feb 2003.
+
+At Jeff Mezei's suggestion, separate text and binary mode open sequences
+for VMS session log.  ckvfio.c, 28 Feb 2003.
+
+Added freebsd48 target for FreeBSD 4.8.  makefile, 1 Mar 2003.
+
+Changed Mac OS X entries to include -DUSE_STRERROR.  makefile, 2 Mar 2003.
+
+Fixed GETOK /GUI to evaluate its text argument.  ckuus6.c, 3 Mar 2003.
+
+Jeff fixed the K95 Dialer QUICK dialog to (a) allow templates, and (b) have
+a Save-As option.  3 Mar 2003.
+
+Jeff fixed a problem with the Xmodem-CRC checksum being crunched whenever
+there was a retransmission.  7 Mar 2003.
+
+Added target/banner for Tru64 5.1B.  makefile, ckuver.h, 5 Mar 2003.
+
+In Unix, the zcopy() routine (used by the COPY command) reset the user's umask
+to 0 for the remainder of the Kermit process lifetime.  The bug was in
+ckufio.c 8.0.194, 24 Oct 2002, and is fixed in ckufio.c 8.0.195, 6 Mar 2003.
+Of course this happened after building 155 C-Kermit 8.0.208 binaries.  (But
+before officially releasing 8.0.208.)
+
+In the VMS version, changed:
+
+        while ((n--) && xx_inc(2) > -1) ;
+to:
+        while ((n--) && xx_inc(2) >= 0) ;
+
+to suppress the "...is being compared with a relational operator to a constant
+whose value is not greater than zero" warning.  ckvtio.c, 7 Mar 2002.
+
+Added a debug call to dologend in hopes of catching overzealous Locus
+switching, which seems to happen only in K95.  ckuus3.c, 7 Mar 2002.
+
+Rebuilt binaries for some of the more current Unix releases: AIX 4.3.3-5.1,
+Solaris 7-9 , Red Hat 7.0-8.0, Slackware 8.1, Freebsd 4.7-4.8, NetBSD 1.6,
+OpenBSD 3.2, Unixware 7.1.3, Open Unix 8, OSR5.0.6a, etc.  A Unix binary with
+COPY umask fix shows a 6 Mar 2003 date for "UNIX File support" in SHOW
+VERSIONS; a binary without the fix shows 24 Oct 2002.
+
+C-Kermit 8.0.208 dated 14 March 2003 released on 10 March 2003.
+
+---8.0.208---
+
+From Jeff 13 Mar 2003:
+ . Updated SSL module allows importation of tickets from host.
+ . freebsd50+openssl target: makefile.
+ . FTP PUT /PERMISSIONS error message for K95: ckcftp.c.
+ 
+Fixed MINPUT to strip quotes or braces from around targets (this was broken
+on Feb 10th).  Thanks to Jason Heskett for discovering and reporting this
+(killer) bug.  ckuusr.c, 14 Mar 2003.
+
+Changed version number to 209 Dev.00.  ckcmai.c, 14 Mar 2003.
+
+While debugging the alphapage script, I found that the command "minput 8 \6\13
+\21\13 \13\27\4\13 \30\13" gets "?Not confirmed" in 8.0.208 and 8.0.209, but
+not in 206 and earlier.  This problem too was introduced on Feb 10th by
+changing MINPUT parsing from cmtxt() followed by cksplit() to cmfld() in a
+loop.  cmfld() uses setatm() to return its result and of course setatm()
+breaks on \13.  Changing setatm() not to do this would break everything else.
+But cmfld() has no arguments that let us tell it to do anything different in
+this case.  Changing the API would be a disaster.  The only solution is to add
+an "MINPUT ACTIVE" (minputactive) global variable that tells cmfld() to tell
+setatm() not to break on CR.  Now MINPUT with braced targets containing CR
+and/or LF works in 209, 206, and 201 (but not 208).  ckucmd.c, ckuusr.c,
+ckuus5.c, 15 Mar 2003.
+
+MINPUT n \fjoin(&a) works OK if all the members of \&a[] are text strings, but
+if they are strings of control chars (as above), they don't get separated by
+the spaces.  For example in:
+
+  dcl \&a[] = "\4\5" "\6\7" xxx
+  minput 10 \fjoin(&a)
+
+MINPUT gets two targets: "aaa" and "\4\5 \6\7 xxx".  The bug was in the
+cksplit() call in the \fjoin() case of MINPUT: it needed to specify an
+include set consisting of all the control characters except NUL.  ckuusr.c,
+16 Mar 2003.
+
+But there's still a problem:
+
+  dcl \&a[] = "\4\5\13\10" "\6\7" "xxx"
+
+creates an array whose first member is "^D^E (one doublequote included).  But
+if braces are used instead, there's no problem.  Same deal as MINPUT: cmfld()
+breaks on CR or LF, thus the end quote is lost.  If I set minputactive for
+DECLARE initializers too, that fixes it.  Is there any reason not to do this?
+Can't think of any (famous last words)...  ckuusr.c, 16 Mar 2003.
+
+Since it has multiple applications, changed the flag's name from minputactive
+to keepallchars.  ckucmd.c, ckuus[r5].c, 16 Mar 2003.
+
+\v(exedir) wasn't being set correctly (it included the program name as well
+as the directory).  Fixed in getexedir(): ckuus4.c, 16 Mar 2003.
+
+SET CARRIER-WATCH <Esc> "auto matic" (spurious space in supplied keyword).
+Cosmetic only; it still worked.  Fixed in setdcd(): ckuus3.c, 16 Mar 2003.
+
+"directory a b c" listed too many files -- all files whose names END WITH a,
+b, or c, rather than the files whose names WERE a, b, or c.  Diagnosis: The
+filespec is changed into a pattern: {a,b,c}, which is the correct form.  It is
+passed to nzxpand(), which goes through the directory getting filenames and
+sending each one to ckmatch() with the given pattern.  ckmatch() receives the
+correct pattern but then prepends a "*" -- that's not right.  It's not just
+in filename matching either.  The following succeeds when it shouldn't:
+
+  if match xxxxc {{a,b,c}} <command>
+
+Changing ckmatch() to not prepend the "*" to each segment fixes the command
+above but breaks lots of others.  Running through the "match" torture-test
+script shows the problem occurs only when the {a,b,c} list is the entire
+pattern, and not embedded within a larger pattern.  Testing for this case
+fixed the problem.  ckmatch(): ckclib.c, 16 Mar 2003.
+
+Fixed FTP MODTIME to not print anything if QUIET ON.  ckcftp.c, 16 Mar 2003.
+
+Picked up a new ckuath.c from Jeff, not sure what the changes are. 16 Mar 2003.
+
+Did a few regular and secure builds to make sure I didn't wreck anything.
+
+Changed version number to 209 (final).  ckcmai.c, 16 Mar 2003.
+
+Jason Heskett found another bug: if you define a macro FOO inside the
+definition of another macro BAR, and FOO's definition includes an odd number
+of doublequotes (such as 1), FOO's definition absorbs the rest of BAR's
+definition.  Example:
+
+  def TEST {
+    .foo = {X"}
+    sho mac foo
+  }
+  do test
+  sho mac foo
+
+Results in:
+
+  foo = {X"}, sho mac foo
+
+Diagnosis: the TEST definition becomes:
+
+  def TEST .foo = {X"}, sho mac foo
+
+and the macro reader is erroneously treating the doublequote as an open
+quote, and then automatically closes the quote at the end of the definition.
+The error is that a doublequote should be significant only at the beginning of
+a field.  But the macro reader isn't a command parser; it doesn't know what
+a field is -- it's just looking for commas and skipping over quoted ones.
+First we have to fix an oversight: SET COMMAND DOUBLEQUOTING OFF should have
+worked here, but it wasn't tested in this case.  Fixed in getncm(): ckuus5.c,
+17 Mar 2003.
+
+There are only certain cases where it makes sense to treat doublequotes as
+signicant:
+
+ . An open quote must be at the beginning or preceded by a space.
+ . A close quote is only at the end or else followed by a space.
+
+This too was fixed in getncm(): ckuus5.c, 17 Mar 2003.
+
+A fix from Jeff SSL/TLS FTP data decoding.  ckcftp.c, 18 Mar 2003.
+
+Tried building C-Kermit on a Cray Y-MP with UNICOS 9.0.  "int suspend",
+declared in ckcmai.c and used in many modules, conflicts with:
+
+  unistd.h:extern int suspend __((int _Category, int _Id));
+
+The "=Dsuspend=xsuspend" trick doesn't work for this; there is no way around
+the conflict other than to rename the variable: ckcmai.c, ckutio.c,
+ckuus[35xy].c.  26 Mar 2003.  VMS and K95 not affected.
+
+OK that gets us past ckcmai.c...  Then in ckutio.c I had to add a new #ifdef
+around the LFDEVNO setting, because the Cray didn't have mkdev.h.  Could not
+find a Cray-specific manifest symbol, so I made a new makefile target (cray9)
+that sets this symbol.  Having done this I have no idea what kind of lockfile
+would be created, but I also doubt if anybody dials out from a Cray.  The
+binary should run a C90, J90, or Y-MP.  makefile, 26 Mar 2003.
+
+Added a target for SCO OSR5.0.7.  makefile, ckuver.h, 30 Mar 2003.
+
+Changed since 208:
+makefile ckuver.h ckcmai.c ckclib.c ckcftp.c ckucmd.c ckuus*.c ckutio.c.
+
+---8.0.209---
+
+From Mark Sapiro, a fix for the March 17th doubleqote fix, getncm(): ckuus5.c,
+4 Apr 2003.
+
+From Jeff, 29 Apr 2003:
+ . Corrected target for HP-UX 11.00 + OpenSSL: makefile, 
+ . Do not allow WILL AUTH before WONT START_TLS: ckctel.h ckctel.c
+ . Add hooks for SFTP and SET/SHOW SFTP: ckcdeb.h ckuusr.h ckuusr.c ckuus3.c
+ . Add SKERMIT ckuusr.h ckuusr.c
+ . Add ADM-5 terminal emulation: ckuus7.c, ckuus5.c
+ . Uncomment and update HELP SET SSH V2 AUTO-REKEY: ckuus2.c
+ . Enable IF TERMINAL-MACRO and IF STARTED-FROM-DIALER for C-Kermit: ckuus6.c
+ . Fix conflicting NOSCROLL keyword definition: ckuusr.h
+ . Set ttname when I_AM_SSH: ckuusy.c
+ . Add extended arg parsing for SSH, Rlogin, Telnet: ckuusy.c, ckuus4.c
+ . Security updates: ckuath.c, ck_ssl.c
+ . Change K95 version number to 2.2.0: ckcmai.c
+ . Save K95 term i/o state before executing keyboard macro: ckuus4.c
+ . Add tests for SSH Subsystem active during INPUT/OUTPUT/CONNECT: ckuus[45].c
+ . Enable K95 SET SSH V2 AUTO-REKEY: ckuus3.c
+
+SFTP and SET SFTP subcommands are implemented up to the case statements.
+
+Files of mine that Jeff hadn't picked up:
+  ckuver.h ckcftp.c ckutio.c ckuusx.c (just minor changes for last build-all)
+
+On 4 Jan 2003, SET RECEIVE MOVE-TO was changed to convert is argument to an
+absolute path, which made it impossible to specify a relative path, then
+move to different directories and have it apply relatively to each directory.
+Changed this as follows:
+
+ . Parser uses cmtxt() rather than cmdir() so it won't fail at parse time.
+ . If path is absolute, we fail at parse time if directory doesn't exist.
+ . In reof() we run the the path through xxstring (again, in case deferred
+   evaluation of variables is desired) and then, if not null, use it.
+ . If the directory doesn't exist, rename() fails and reof() returns -4,
+   resulting in a protocol error (this is not a change).  We do NOT create
+   the directory on the fly. 
+
+I also fixed SET SEND/RECEIVE RENAME-TO to parse with cmtxt() rather than
+cmdir(), since it's parsing a text template, not a directory name, e.g.
+"set receive rename-to file-\v(time)-v(date)-\v(pid)".  This was totally
+broken, since when I don't know.  We don't call xxstring() in this parse, so
+evaluation is always deferred -- I'd better not change this.  ckuus7.c,
+ckcfns.c, 1 May 2003.
+
+From Jeff, Sat May  3 14:15:23 2003:
+ . Pick up the right isascii definition for K95: ckctel.c
+ . malloc...  ckuath.c (new safe malloc routines for K95)
+ . Add author listing: ckuus5.c
+ . SSH Heartbeat support (K95 only): ckuus[23].c
+ . Prescan --height and --width to avoid window resizing at startup: ckuusy.c
+ . Add checks for fatal() or doexit() called from sysinit(): ckuusx.c
+ . Move some K95-specific definitions to ckoker.h: ckcdeb.h
+ . Add support for ON_CD macro in zchdir(): ckufio.c
+ . Add a command to let FTP client authenticate with SSLv2: ckcftp.c
+ . Fix parsing of FTP file facts like "UNIX.mode": ckcftp.c
+
+ON_CD will need some explaining (to be done).  It's implemented for Unix,
+VMS, WIndows, and OS/2.
+
+The FTP file facts fix came from first exposure to the new OpenBSD FTP
+server: ftp://ftp7.usa.openbsd.org/pub/os/OpenBSD/3.3/i386/
+The period in "UNIX.mode" caused an erroneous word break, adding junk to
+the filename.
+
+About the malloc changes, Jeff says "K95 is not behaving well in low memory
+environments.  I'm not sure that C-Kermit does much better.  The program does
+not crash but it certainly does not behave the way the user expects it to.
+I'm beginning to think that any malloc() error should be treated as fatal."
+
+Not visible in these changes because it's in K95-specific modules: Jeff made
+SET ATTRIBUTES OFF and SET ATTRIBUTES DATE OFF apply to XYZMODEM transfers.
+
+From Jeff, 11 May 2003:
+ . Add support for SSH Keepalive to relevant SET command (K95): ckuus3.c
+ . Reduce max overlapped i/o requests from 30 to 7 (K95): ckuus7.c
+ . Don't call sysinit() in fatal(): ckuusx.c.
+ . Some new conditionalizations for SSL module: ck_ssl.c
+
+The doublequote-parsing fixes from March and April broke the SWITCH statement,
+which is implemented by internally defining, then executing, a macro.  If I
+drop back to the old dumb handling of doublequotes, everything is fixed except
+the problem of March 17th.  But can we really expect getncm() to pre-guess
+what the parser is going to do?  getncm()'s only job is to find command
+boundaries, which are represented by commas.  Commas, however, is needed IN
+commands too.  We take a comma literally if it is quoted with \, or is inside
+a matched pair of braces, parens, or doublequotes.  It is not unreasonable to
+require a doublequote in a macro definition to be prefixed by \ when it is to
+be taken literally.  The proper response to Jason Heskett's complaint of March
+17th should have been to leave the code alone and recommand an appropriate
+form of quoting:
+
+  def TEST {
+      .foo = {X\"}
+      sho mac foo
+  }
+
+And this is what I have done.  Another reason for sticking with the old method
+is that it's explainable.  The "improved" method, even if it worked, would be
+be impossible to explain.  Btw, in testing this I noticed that the switch-test
+script made 8.0.201 dump core.  Today's version is fine.  The problem with
+quoted strings inside of IF {...} clauses and FOR and WHILE loops is fixed
+too.  Perhaps "unbroken" would be a better word.  ckuus5.c, 11 May 2003.
+
+Vace discovered that FTP MGET /EXCEPT:{... (with an unterminated /EXCEPT list)
+could crash Kermit.  Fixed in ckcftp.c, 11 May 2003.
+
+CONTINUE should not affect SUCCESS/FAILURE status.  ckuusr.c, 11 May 2003.
+
+Fixed an oversight that goes back 15 years.  While \{123} is allowed for
+decimal codes, \x{12} and \o{123} were never handled.  ckucmd.c, 11 May 2003.
+
+Added support for Red Hat <baudboy.h> and /usr/sbin/lockdev.  Supposedly this
+allows Kermit to be installed without setuid or setgid bits and still be able
+to lock and use the serial device.  Compiles and starts, but not tested.
+ckcdeb.h, makefile, ckutio.c, ckuus5.c, 16 May 2003.
+
+From Jeff: FTP ASCII send data to host when FTP /SSL was in use was broken.
+ftp_dpl is set to Clear when FTP /SSL is in use.  This was causing the data to
+be written to the socket with send() instead of the OpenSSL routines.
+ckcftp.c, ckuath.c, 21 May 2003.
+
+From Jeff: Stuff for Kerberos 524: ckcdeb.h.  Fixes for FTP; "FTP ASCII send
+data did not properly compute the end of line translations.  On Unix (and
+similar platforms) the end of line was correct for no character sets but
+incorrect when character sets were specified.  On Windows/OS2, the end of line
+was correct when character sets were specified and incorrect when they were
+not.  On MAC, both were broken.  Also, FTP Send Byte counts were incorrect
+when character sets were specified."  ckcftp.c.  17 Jun 2003.
+
+From Jeff: fixes to HTTP /AGENT: and /USER: switch action: ckcnet.c ckuus3.c
+ck_crp.c ckcftp.c ckuus2.c ckuusy.c ckuusr.c ckcnet.h, 21 Jun 2003.
+
+From Jeff: Fix SET DIALER BACKSPACE so it can override a previous SET KEY
+(e.g. from INI file): ckuus7.c.  Some SSL/TLS updates: ck_ssl.c.  HTTP support
+for VMS and other VMS improvements (e.g. a way to not have to hardwire the
+C-Kerit version number into the build script) from Martin Vorlaender:
+ckcnet.h, ckuus[r3].c, ckcdeb.h, ckvtio.c, ckcnet.c, ckvker.com.  Built on
+Solaris (gcc/ansi) and SunOS (cc/k&r).  The new VMS script tests the VMS
+version and includes HTTP support only for VMS 6.2 or later.  2 Jul 2003.
+
+Tried to build on our last VMS system but it seems to be dead.  Looks like a
+head crash (makes really loud noises, boot says DKA0 not recognized) (fooey, I
+just paid good money to renew the VMS license).  Tried building at another
+site with:
+
+  Process Software MultiNet V4.3 Rev A-X,
+  Compaq AlphaServer ES40, OpenVMS AXP V7.3
+  Compaq C V6.4-008 on OpenVMS Alpha V7.3
+
+Had to make a few corrections to ckvker.com.  But still, compilation of
+ckcnet.c bombs, indicating that the SELECT definition somehow got lost
+somewhere since the 209 release (i.e. no SELECT type is defined so it falls
+thru to "SELECT is required for this code").  But I don't see anything in
+ckcdeb.h or ckcnet.[ch] that would explain this.  Not ckvker.com either
+(putting the old one back gives the same result).  OK, I give up, maybe it's
+just that I haven't tried building it on MultiNet recently.  What about UCX?
+Aha, builds fine there except for warnings about mlook, dodo, and parser in
+ckvfio.c (because of ON_CD) -- I suppose I have #include <ckucmd.h>... (done)
+Anyhow it builds OK and the HTTP code is active and almost works (HTTP OPEN
+works; HTTP GET seems to succeed but creates an empty file every time).  Tried
+building under MultiNet at another installation; same bad result.
+
+OK so why won't it build for MultiNet?  Comparing ckcnet.c with the 209
+version, not a single #ifdef or #include is changed.  Tried building with
+p3="NOHTTP" -- builds OK, aha.  Where's the problem?  Not ckcnet.h...
+Not ckcdeb.h...  OK I give up, will revisit this next time I get time to
+do anything with the code.
+
+Later Jeff said "Martin did not implement VMS networking for the HTTP code.
+All he did was activate the #define HTTP which happens to work because his
+connections are using SSL/TLS connections.  http_inc(), http_tol(), etc have
+no support for VMS networking regardless of whether it is UCX or MULTINET.
+The vast majority of HTTP connections are not secured by SSL/TLS.  It makes no
+sense to support HTTP on VMS until someone is willing to either do the work or
+pay have the work done to implement VMS networking in that code base."  So the
+fix is to not enable HTTP for VMS after all.  Removed the CKHTTP definition
+for VMS from ckcdeb.h, 6 Jul 2003.
+
+Fixed ckvfio.c to #include <ckuusr.h> (instead of <ckucmd.h>) to pick up 
+missing prototypes.  6 Jul 2003.
+
+From Arthur Marsh: solaris2xg+openssl+zlib+srp+pam+shadow and the corresponding
+Solaris 7 target.  makefile, 6 Jul 2003.
+
+Remove duplicate #includes for <sys/stat.h>, <errno.h>, and <ctype.h> from
+ckcftp.c.  6 Jul 2003.
+
+Add -DUSE_MEMCPY to Motorola SV/68 targets because of shuffled #includes in 
+ckcftp.c.  8 Jul 2003.
+
+From Jeff: Fix problems mixing SSL and SRP without Kerberos.  Plus a few minor
+#define comment changes and a reshuffling of #defines in ckcdeb.h to allow me
+to build on X86 Windows without Kerberos.  ckcdeb.h, ck_crp.c, ckuath.c,
+10 Jul 2003.
+
+From Jeff: updated ckuat2.h and ckuath.c, 29 Jul 2003.
+
+Mats Peterson noticed that a very small Latin-1 file would be incorrectly
+identified as UCS-2 by scanfile().  Fixed in ckuusx.c, 29 Jul 2003.
+
+Fixed ACCESS macro definition to account for the fact that FIND is now a
+built-in command.  ckermit.ini, 30 Jul 2003.
+
+From Jeff: Fix for typo in urlparse() (svc/hos): ckuusy.c, 18 Aug 2003.
+
+From Jeff: Redhat9 makefile targets (needed for for OpenSSL 0.9.7):
+makefile, 19 Aug 2003.
+
+GREP /NOLIST and /COUNT did too much magic, with some undesirable fallout:
+"GREP /NOLIST /COUNT:x args" printed "file:count" for each file.  "GREP
+/COUNT:x /NOLIST args" did not print "file:count", but neither did it set the
+count variable.  Removed the magic.  Also one of the GREP switches,
+/LINENUMBERS, was out of order.  Fixed in ckuus6.c, 20 Aug 2003.
+
+From Jeff: "Reorganizing code to enable building with different subsets of
+options; a few typos corrected as well."  ckcdeb.h, ckuver.h (for RH9),
+ckcnet.c, ckuus7.c, ckuus3.c: 24 Aug 2003.
+
+Scanfile misidentified a big PDF file as text because the first 800K of it
+*was* text (most other PDF files were correctly tagged as binary).  Fixed
+by adding a check for the PDF signature at the beginning of the file.
+scanfile(): ckuusx.c, 25 Aug 2003.
+
+Ditto for PostScript files, but conservatively.  Signature at beginning of
+file must begin with "%!PS-Ado".  If it's just "%!" (or something nonstandard
+like "%%Creator: Windows PSCRIPT") we do a regular scan.  Also added "*.ps"
+to all binary filename patterns.  ckuusx.c, 4 Sep 2003.
+
+Ditto (but within #ifndef NOPCLSCAN) for PCL (<ESC>E) and PJL (<ESC>%) files,
+but no binpatterns (note: ".PCL" is the extension for TOPS-20 EXEC scripts).
+ckuusx.c, 4 Sep 2003.
+
+Added comments about OpenSSL 0.9.7 to all linux+openssl targets.
+makefile, 4 Sep 2003.
+
+From Jeff: Added - #define ALLOW_KRB_3DES_ENCRYPT.  When this symbol is defined
+at compilation Kermit will allow non-DES session keys to be used during Telnet
+Auth.  These session keys can then be used for Telnet Encrypt.  The reason
+this is not compiled on by default is that the MIT Kerberos Telnet does not
+follow the RFC for constructing keys for ENCRYPT DES when the keys are longer
+than 8 bytes in length.  ckuath.c, ckuus5.c, 4 Sep 2003.
+
+"ftp mget a b c" succeeded if one or more of the files did not exist, even
+with "set ftp error-action proceed".  This is because the server's NLST file
+list does not include any files that don't exist, so the client never even
+tries to get them.  Fortunately, the way the code is structured, this one was
+easy to fix.  ckcftp.c, 14 Sep 2003.
+
+From Jeff: Corrected code in ckcnet.c to ensure that Reverse DNS Lookups are
+not performed if tcp_rdns is OFF.  Fixed ck_krb5_getrealm() to actually return
+the realm of the credentials cache and not the default realm specified in the
+krb5.conf file.  Previously krb5_cc_get_principal() was not being called.
+Fixed ck_krb5_is_tgt_valid() to test the TGT in the current ccache and not the
+TGT constructed from the default realm.  ckcnet.c, ckuath.c, 14 Sep 2003.
+
+Marco Bernardi noticed that IF DIRECTORY could produce a false positive if
+the argument directory had previously been referenced but then removed.  This
+is because of the clever isdir() cache that was added to speed up recursion
+through big directory trees.  Changed IF DIRECTORY to make a second check
+(definitive but more expensive) if isdir() succeeds, and changed the
+directory-deleting routine, ckmkdir(), to flush the directory cache (UNIX
+only -- this also should be done in K95 but it's not critical).  This was
+done by adding a routine, clrdircache() to ckufio.c, which sets prevstat
+to -1 and prevpath[0] to NUL.  ckcfn3.c, ckuus6.c, ckufio.c, 18 Sep 2003.
+
+Marco reported the second fix still didn't work for him (even though it did
+for me).  Rather than try to figure out why, I concluded that the directory
+cache is just not safe: a directory found a second ago might have been deleted
+or renamed not only by Kermit but by some other process.  Why did I add this
+in the first place?  The log says:
+
+  Some debug logs showed that isdir() is often called twice in a row on the
+  same file.  Rather than try to sort out clients, I added a 1-element cache
+  to Unix isdir().  ckufio.c, 24 Apr 2000.
+
+Experimentation with DIR and DIR /RECURSIVE does not show this happening at
+all.  So I #ifdef'd out the directory cache (see #ifdef ISDIRCACHE in ckufio.c;
+ISDIRCACHE is not defined) and backed off the previous changes: ckufio.c,
+ckcfn3.c, ckuus6.c, 28 Sep 2003.
+
+From Jeff: Replace the compile time ALLOW_KRB_3DES_ENCRYPT with a run-time
+command SET TELNET BUG AUTH-KRB5-DES which defaults to ON: ckctel.[ch],
+ckuus[234].c, ck_crp.c, ckuath.c.  4 Oct 2003.
+
+Allow DIAL RETRIES to be any positive number, and catch negative ones.
+Also added code to check for atoi() errors (e.g. truncation).  At least on
+some platforms (e.g. Solaris) atoi() is supposed to set errno, but it
+doesn't.  ckuus3.c, ckucmd.c, 4 Oct 2003.
+
+Added /DEFAULT: to ASK-class commands (ASK, ASKQ, GETOK):
+
+ . For popups: no way to send defaults to popup_readtext() or popup_readpass().
+ . For GUI ASK[Q], pass default to gui_txt_dialog().
+ . For GUI GETOK, convert "yes" "ok" or "no" default to number for uq_ok().
+ . For Text GETOK, add default to cmkey().
+ . For Text ASK[Q], add default to cmtxt().
+ . For GETC, GETKEY, and READ: no changes.
+
+GETOK, ASK, and ASKQ with /TIMEOUT: no longer fail when the timer goes off
+if a /DEFAULT was supplied.  The GUI functions (uq_blah) don't seem to
+support timeouts.  Only the text version has been tested.  ckuus[26].c,
+4 Oct 2003.
+
+From Jeff: add /DEFAULT: for popups.  ckuus6.c. 6 Oct 2003.
+
+Change SET DIAL INTERVAL to be like SET DIAL RETRIES.  ckuus[34].c, 6 Oct 2003.
+
+Added target for HP-UX 10/11 + OpenSSL built with gcc, from Chris Cheney.
+Makefile, 12 Oct 2003.
+
+From Jeff, 6 Nov 2003:
+ . #ifdef adjustments: ckcftp.c, ckcdeb.h
+ . Fix spurious consumption of first byte(s) on Telnet connection: ckctel.c
+ . Another HP PJL test for scanfile: ckuusx.c.
+ . K95: Recognize DG4xx protected fields in DG2xx emulation: ckuus7.c.
+ . Add SSLeay version display to SHOW AUTH command: ckuus7.c
+ . Improved SET MOUSE CLEAR help text: ckuus2.c.
+ . Improved Kverbs help text: ckuus2.c (+ new IBM-3151 Kverbs).
+ . Some changes to ck_ssl.c, ckuath.c.
+
+From PeterE, 10 Nov 2003:
+ . Improved HP-UX 10/11 makefile targets for OpenSSL.
+ . #ifdef fix for OpenSSL on HP-UX: ck_ssl.c.
+
+Another new makefile from PeterE with improved and integrated HP-UX targets.
+12 Nov 2003.
+
+A couple fixes to the solaris9g+krb5+krb4+openssl+shadow+pam+zlib target
+from Jeff.  Added a solaris9g+openssl+shadow+pam+zlib target.  makefile,
+21 Nov 2003.
+
+From Jeff, 30 Nov 2003:
+ . Fix SEND /MOVE-TO: ckuusr.c.
+ . Fix K95 SET TITLE to allow quotes/braces around text: ckuus7.c.
+ . Improved "set term autodownload ?" response: ckuus5.c.
+ . Fix SHOW FEATURES to specify the protocol for encryption: ckuus5.c
+ . Make {SEND, RECEIVE} {MOVE-TO, RENAME-TO} work for XYZMODEM (K95 only).
+
+From Jeff: 7 Jan 2004:
+ . At one point Frank started to add a timer parameter to the
+   uq_txt() function but he only did it for the non-ANSI
+   compilers.  I added it for the ANSI compilers, fixed the
+   prototypes and provided a default value easily changed
+   DEFAULT_UQ_TIMEOUT: ckcker.h, ckuus[36].c, ck_ssl.c, ckcftp.c, ckuath.c.
+ . Fixed SET TERMINAL DEBUG ON (typo in variable name): ckuus7.c.
+ . Fixed BEEP INFORMATION; previously it made no sound, now uses
+   MB_ICONQUESTION.  ckuusx.c.
+
+From Ian Beckwith <ian@nessie.mcc.ac.uk> (Debianization), 7 Jan 2004:
+ . Search dir/ckermit for docs, as well as dir/kermit in cmdini(): ckuus5.c.
+ . New linux+krb5+krb4+openssl+shadow+pam target (kitchen sink minus SRP,
+   which Debian does not distribute): makefile.
+ ? Mangles the DESTDIR support in makefile to install into a staging area:
+   makefile (I didn't take this one yet).
+
+Updated copyright notices for 2004, all modules.  7 Jan 2004.
+
+Added INPUT /NOMATCH, allowing INPUT to be used for a fixed amount of time
+without attempting to match any text or patterns, so it's no longer
+necessary to "input 600 STRING_THAT_WILL_NEVER_COME".  If /NOMATCH is
+included, INPUT succeeds if the timeout expires, with \v(instatus) = 1
+(meaning "timed out"); fails upon interruption or i/o error.  ckuusr.h,
+ckuus[r24].c, 7 Jan 2004.
+
+Added SET INPUT SCALE-FACTOR <float>.  This scales all INPUT timeouts by the
+given factor, allowing time-sensitive scripts to be adjusted to changing
+conditions such as congested networks or different-speed modems without
+having to change each INPUT-class command.  This affects only those timeouts
+that are given in seconds, not as wall-clock times.  Although the scale
+factor can have a fractional part, the INPUT timeout is still an integer.
+Added this to SHOW INPUT, and added a \v(inscale) variable for it.
+ckuusr.h, ckuus[r257].c, 7 Jan 2004.
+
+undef \%a, \fverify(abc,\%a) returns 0, which makes it look as if \%a is a
+string composed of a's, b's, and/or c's, when in fact it contains nothing.
+Changed \fverify() to return -1 in this case.  ckuus4.c, 12 Jan 2004.
+
+\fcode(xxx) returned an empty string if its argument string was empty.  This
+makes it unsafe to use in arithmetic or boolean expressions.  Changed it to
+return 0 if its argument was missing, null, or empty.  ckuus4.c, 12 Jan 2004.
+
+Updated \verify() and \fcode() help text.  ckuus2.c, 12 Jan 2004.
+
+While setting up IKSD, Ian Beckwith noticed that including the --initfile:
+option caused Kermit to start parsing its own Copyright string as if it were
+the command line, and eventually crash.  I couldn't reproduce on Solaris /
+Sparc but I could in Linux / i386 (what Ian is using) -- a change from Jeff
+on 28 Apr 2003 set the command-line arg pointer to a literal empty string in
+prescan() about line 1740 of of ckuus4.c; the pointer is incremented next
+time thru the loop, resulting in random memory being referenced.  Fixed by
+setting the pointer to NULL instead of "".  ckuus4.c, 12 Jan 2004.
+
+declare \&a[999999999999999] would dump core on some platforms.  atoi()
+or whatever would truncate the dimension to maxint.  When we add 1 to the
+result, we get a negative number, which is used as an index, loop test, etc.
+Fixed both dodcl() and dclarray() to check for (n+1 < 0).  ckuus[r5].c,
+12 Jan 2004.
+
+Unix zchki() would fail on /dev/tty, which is unreasonable.  This prevented
+FOPEN /READ from reading from the terminal.  zchki() already allowed for
+/dev/null, so I added /dev/tty to the list of specials.  Ditto for FOPEN
+/WRITE and zchko().  ckufio.c 13 Jan 2004.
+
+Added untabify() routine to ckclib.[ch], 13 Jan 2004.
+Added FREAD /TRIM and /UNTABIFY.  ckuus[27].c, 13 Jan 2004.
+Added \funtabify().  ckuusr.h, ckuus[24].c, 13 Jan 2004.
+
+Dat Nguyen noticed that (setq u 'p') followed by (u) dumped core.  This was
+caused by an over-clever optimization that skipped mallocs for short
+literals, but then went on later to try to free one that hadn't been
+malloc'd.  Fixed in dosexp(): ckuus3.c, 14 Jan 2004.
+
+Catch another copyright date.  ckuus5.c, 14 Jan 2004.
+
+Fixed SWITCH to work even when SET COMMAND DOUBLEQUOTE OFF (from Mark
+Sapiro).  ckuus5.c, 15 Jan 2004.
+
+Changed version to 8.0.211 so scripts can test for recently added features.
+ckcmai.c, 15 Jan 2004.
+
+Fixed a glitch in K95 "help set port".  ckuus2.c, 20 Jan 2004.
+
+Fix from Jeff: Connections to a TLS-aware protocol which require a reconnect
+upon certificate verification failure could not reconnect if the connection
+was initiated from the command line or via a URL.  ckctel.c ckcmai.c
+ckuusr.c ckuus7.c ckuusy.c, 20 Jan 2004.
+
+From Alex Lewin: makefile target and #ifdef for Mac OS X 10.3 (Panther):
+makefile, ckcnet.c, 7 Feb 2004.
+
+Added KFLAGS to sco32v507 targets to make PTY and SSH commands work.  The
+same flags could probably also be added to earlier OSR5 targets but they
+have not been tested there.  makefile, 7 Feb 2004.
+
+Checked a complaint that "LOCAL &a" did not make array \&a[] local.  Indeed
+it did not, and can not.  You have to use the full syntax in the LOCAL
+command, "LOCAL \&a[]", or else it doesn't know it's not a macro named &a.
+7 Feb 2004.
+
+Fixed some confusion in creating IKSD database file and temp-file names.
+I was calling zfnqfp() without remembering that the path member of the
+returned struct included the filename, so to get just the directory name,
+I needed to strip the filename from the right.  ckuusy.c, 2 Mar 2004.
+
+New ckuath.c, ck_ssl.c from Jeff.  2 Mar 2004.
+
+Updated Jeff's affiliation in VERSION command text.  ckuusr.c, 2 Mar 2004.
+
+Designation changed from Dev.00 to Beta.01.  ckcmai.c, 2 Mar 2004.
+
+Fixed zrename() syslogging -- it had success and failure reversed.
+Beta.02: ckufio.c, 4 Mar 2004.
+
+Problem: when accessing IKSD via a kermit:// or iksd:// URL, and a user ID
+is given but no password, doxarg() set the password to "" instead of leaving
+it NULL, but all the tests in dourl() are for NULL.  Fixed in doxarg():
+ckuusy.c, 5 Mar 2004.
+
+The logic in dourl() about which macro to construct (login and connect,
+login and get directory listing, or login and fetch a file) was a bit off,
+so all three cases were not handled.  ckcmai.c, 5 Mar 2004.
+
+Trial Beta builds:
+ . HP-UX B.11.11 PA-RISC
+ . HP-UX B.11.23 IA64
+ . Tru64 4.0G Alpha
+ . Tru64 5.1B Alpha
+ . Debian 3.0 i386
+ . Red Hat ES 2.1 i386
+ . Slackware 9.1 i386
+ . VMS 7.3-1 Alpha + UCX 5.3
+ . VMS 7.3-1 Alpha no TCP/IP
+ . VMS 7.3 Alpha MultiNet 4.3 A-X
+ . SCO UnixWare 7.1.4 i386
+ . SCO OSR5.0.7 i386
+ . Solaris 9 Sparc
+
+Fixed compiler warning in doxarg() caused by typo (NULL instead of NUL) in
+the 5 March doxarg() edit.  ckuusy.c, 9 Mar 2004.
+
+IKSD (kermit://) command-line URLs did not work right if the client had
+already preauthenticated with Kerberos or somesuch because they tried to log
+in again with REMOTE LOGIN.  The macros constructed in doxarg() needed to
+check \v(authstate) before attempting REMOTE LOGIN.  ckcmai.c, 10 Mar 2004.
+
+Added ckuker.nr to x.sh (ckdaily upload) and updated ckuker.nr with current
+version number and dates.  10 Mar 2004.
+
+Replaced hardwired references to /usr/local in makefile with $(prefix)
+(which defaults to /usr/local, but can be overridden on the command line),
+suggested by Nelson Beebe for use with Configure.  10 Mar 2004.
+
+From Nelson Beebe: In the Kermit makefile in the install target commands,
+line 981 reads:
+
+        cp $(BINARY) $(DESTDIR)$(BINDIR)/kermit || exit 1;\
+
+Could you please add this line before it:
+
+        rm -f $(DESTDIR)$(BINDIR)/kermit;\
+
+Some sites (mine included) keep multiple versions of software around,
+with hard links between $(prefix)/progname and $(prefix)/progname-x.y.z.
+Failure to remove the $(prefix)/progname at "make install" time then
+replaces the old $(prefix)/progname-x.y.z with the new one, destroying
+an old version that the site wanted to be preserved.  makefile, 10 Mar 2004.
+
+Minor syntax and typo fixes (mostly prototypes): ckcdeb.h, ckcfns.c,
+ckclib.c, ckufio.c, ckuusr.h, ckuusx.c, 10 Mar 2004.  (I still have a few
+more to do.)
+
+Added CC=$(CC) CC2=$(CC2) to many (but not all) makefile targets that
+reference other makefile targets.  On some platforms (notably AIX, Solaris,
+SunOS) there are specific targets for different compilers, so I skipped
+those.  makefile, 10 Mar 2004.
+
+Added error checking to kermit:// URL macros, so they don't plow ahead
+after the connection is closed.  ckcmai.c, 11 Mar 2004.
+
+Added FreeBSD 4.9 and 5.1 targets (only the herald is affected).
+makefile, ckuver.h, 11 Mar 2004.
+
+Added "LIBS=-lcrypt" to bsd44 targets since nowadays crypt is almost always
+unbundled from libc.  Also added explanatory notes.  makefile, 11 Mar 2004.
+
+Changed MANDIR to default to $(manroot)/man/man1, and manroot to default
+to $(prefix).  More adding of CC=$(CC) clauses: {Free,Net,Open}BSD, 4.4BSD.
+makefile, 11 Mar 2004.
+
+Miscellaneous cleanups: ckuusx.c, ckcnet.c, ckufio.c, 11 Mar 2004.
+
+Corrected the check in the linux target to see if /usr/include/crypt.h
+exists, and if so to define HAVE_CRYPT_H, which is used in ckcdeb.h to
+#include <crypt.h> to get the prototype for crypt() and prevent bogus
+conversions on its return type on 64-bit platforms (the previous test wasn't
+quite right and the resulting symbol wasn't spelled right).  makefile,
+12 Mar 2004.
+
+From Jeff, 14 Mar 2004:
+ . Initialize localuidbuf[] in tn_snenv(): ckctel.c.
+ . Remove remote-mode checks in hupok() for K95G only (why?): ckuus3.c.
+ . Add help text for new K95-only TYPE /GUI switches: ckuus2.c.
+ . TYPE /GUI parsing, ...: ckuusr.c.
+ . TYPE /GUI action, dotype(): ckuus6.c
+ . Change Jeff's affiliation: most modules.
+
+20 Mar 2004: Looked into adding long file support, i.e. handling files more
+than 2GB (or 4GB) long.  Discovered very quickly this would be a major
+project.  Each platform has a different API, or environment, or transition
+plan, or whatever -- a nightmare to handle in portable code.  At the very
+least we'll need to convert a lot of Kermit variables from long or unsigned
+long to some new Kermit type, which in turn is #defined or typedef'd
+appropriately for each platform (to off_t or size_t or whatever).  Then we
+have to worry about the details of open() vs fopen(); printf() formats (%lld
+vs %Ld vs %"PRId64"...), platforms like HP-UX where you might have to use
+different APIs for different file systems on the same computer, etc.  We'll
+need to confront this soon, but let's get a good stable 8.0.211 release out
+first!  Meanwhile, for future reference, here are a few articles:
+
+General: http://freshmeat.net/articles/view/709/
+Linux:   http://www.ece.utexas.edu/~luo/linux_lfs.html
+HP-UX:   http://devrsrc1.external.hp.com/STK/partner/lg_files.pdf
+Solaris: http://wwws.sun.com/software/whitepapers/wp-largefiles/largefiles.pdf
+
+Looked into FTP timeouts.  It appears I can just call empty() (which is
+nothing more than a front end for select()) with the desired timeout before
+any kind of network read.  If it returns <= 0, we have a timeout.  This is
+not quite the same as using alarm() / signal() around a recv() (which could
+get stuck) but alarm() / signal() are not not used in the FTP module and are
+not naturally portable to Windows, but select() is already in use in the FTP
+module for both Unix and Windows.  This form of timeout could be used
+portably for both command response and data reads.  What about writes to the
+command or data socket?  They can get stuck for hours and hours without
+returning too, but the select() approach won't help here -- we need the
+actual send() or recv() to time out, or be wrapped in an alarm()/signal()
+kind of mechanism.  But if we can do that for sends, we can also do it for
+receives.  Better check with Jeff before I start programming anything.
+20 Mar 2004.
+
+Later: Decided to postpone the above two projects (ditto IPv6) until after
+8.0.211 is released because both will have major impacts on portability.
+Grumble: all i/o APIs should have been designed from the beginning with a
+timeout parameter.  To this day, hardly any have this feature.
+
+3-4 Apr 2004: More 8.0.211 Beta.02+ test builds:
+
+ . FreeBSD 3.3
+ . FreeBSD 4.4
+ . Linux Debian 2.1
+ . Linux RH 6.1
+ . Linux RH 7.1
+ . Linux RH 7.2
+ . Linux RH 9 (with 84 different combinations of feature selection)
+ . Linux SuSE 6.4
+ . Linux SuSE 7.0
+ . NetBSD 1.4.1
+ . NetBSD 1.5.2
+ . OpenBSD 2.5
+ . OpenBSD 3.0
+ . QNX 4.25
+ . SCO UnixWare 2.1.3
+ . SCO UnixWare 7.1.4
+ . SCO OpenServer 5.0.7
+ . SCO XENIX 2.3.4 (no TCP)
+
+Changes needed: None.
+
+Problem: SCO XENIX 2.3.4 network build failed in the FTP module with
+header-file syntax and conflicting-definitions trouble.  I'm not going to
+try to fix it; 8.0.209 built OK with FTP, so we'll just keep that one
+available.
+
+Got access to VMS 8.1 on IA64.  Building the nonet version of C-Kermit
+required minor modifications to ckvvms.h, ckv[ft]io.c, and ckvcon.c, to
+account for a third architecture.  Also to SHOW FEATURES in ckuus5.c.  Once
+that was done, the UCX 5.5 version built OK too.  Starts OK, makes Telnet
+connection OK, sends files.  Has some obvious glitches though -- "stat"
+after a file transfer reports 0 elapsed time (in fact it was 00:09:48) and
+1219174400 cps (when in fact it was 10364).  This doesn't happen on the
+Alpha.  Btw, the IA64 binary is twice as big as the Alpha one.  Changed
+to Beta.03.  5 Apr 2004.
+
+Fixed the ckdaily script to include the makefile and man page in the Zip
+file (they were not included because the Zip file was intended mainly for
+VMS users, but some Unix users prefer Zip to tar.gz).  6 Apr 2004.
+
+Traced problems in VMS/IA64 statistics report to rftimer()/gftimer() in
+ckvtio.c, which use sys$ and lib$ calls to figure elapsed time.  These work
+on VAX and Alpha but not IA64.  Sent a report to the chief engineer of the
+IA64 VMS port; he says it's probably a bug in VMS 8.1 (which is not a real
+release); he'll make sure it's fixed in 8.2.  As an experiment, tried
+swapping in the Unix versions of these routines (which call gettimeofday()
+etc).  They seem work just fine (it hung a couple times but I think that's
+because the underlying system hung too; trying it later on a new connection,
+it was fine; however I noticed a BIG discrepancy in throughput between
+sending and receiving).  Moved definitions for VMS64BIT and VMSI64 to
+ckcdeb.h so all modules can use them and added them to the SHOW FEATURES
+display.  Added VMSV80 definition to build procedure.  Beta.03+.  ckcdeb.h,
+ckcuus5.c, ckcvvms.h, ckvtio.c, ckvker.com, 6 Apr 2004.
+
+While doing the build-all, I noticed the VMS version did not build with
+Multinet or older UCX versions, always with the same errors -- undeclared
+variables, undefined symbols, all TCP/IP related.  This didn't happen a
+couple weeks ago...  Somehow the order of #includes was messed up --
+ckuusr.h depended on symbols that are defined in ckcnet.h, but ckcnet.h
+was being included after ckuusr.h...  this was compounded by two missing
+commas in ckvker.com.  11 Apr 2004.
+
+Removed Beta designation, released as 8.0.211, 10 Apr 2004.
+
+---8.0.211---
+
+I had somehow lost the edit to ckutio.c that changed the UUCP lockfile for
+Mac OS X from /var/spool/uucp to /var/spool/lock.  So I slipped it in and
+re-uploaded version 8.0.211.  You can tell the difference because SHOW
+VERSIONS has a 17 Apr 2004 for the Communications I/O module.  Also the 10.3
+executable now has a designer banner: "Mac OS X 10.3".  makefile, ckuver.h,
+ckutio.c, ckuus[45].c, 17 Apr 2004.
+
+***********************
diff --git a/ckermit-8.0.211/ckcasc.h b/ckermit-8.0.211/ckcasc.h
new file mode 100644
index 0000000..c7c32cc
--- /dev/null
+++ b/ckermit-8.0.211/ckcasc.h
@@ -0,0 +1,69 @@
+/*
+  File CKCASC.H
+  Mnemonics for ASCII control characters (and Space) for use with C-Kermit.
+*/
+/*
+  Author: Frank da Cruz (fdc@columbia.edu).
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    Trustees of Columbia University in the City of New York.
+    All rights reserved.  See the C-Kermit COPYING.TXT file or the
+    copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#ifndef CKCASC_H
+#define CKCASC_H
+
+#define NUL  '\0'       /* Null Ctrl-@*/
+#define SOH    1        /* Start of header Ctrl-A */
+#define STX    2        /* Ctrl-B */
+#define ETX    3        /* Ctrl-C */
+#define EOT    4        /* Ctrl-D */
+#define ENQ    5        /* ENQ Ctrl-E */
+#define ACK    6        /* Ctrl-F */
+#define BEL    7        /* Bell (Beep) Ctrl-G */
+#define BS     8        /* Backspace Ctrl-H */
+#define HT     9        /* Horizontal Tab Ctrl-I */
+#define LF    10        /* Linefeed Ctrl-J */
+#define VT    11        /* Vertical Tab Ctrl-K */
+#define NL   '\n'       /* Newline */
+#define FF    12        /* Formfeed Ctrl-L */
+#define CR    13        /* Carriage Return Ctrl-M */
+#define SO    14        /* Shift Out Ctrl-N */
+#define SI    15        /* Shift In Ctrl-O */
+#define DLE   16        /* Datalink Escape Ctrl-P */
+#define XON   17        /* XON Ctrl-Q */
+#define DC1   17
+#define DC2   18        /* Ctrl-R */
+#define XOFF  19        /* XOFF Ctrl-S */
+#define DC3   19
+#define DC4   20        /* Ctrl-T */
+#define NAK   21        /* Ctrl-U */
+#define SYN   22        /* SYN, Ctrl-V */
+#define ETB   23        /* Ctrl-W */
+#define CAN   24        /* CAN, Ctrl-X */
+#define EM    25        /* Ctrl-Y */
+#define SUB   26        /* SUB Ctrl-Z */
+#define ESC   27        /* Escape Ctrl-[ */
+#define XFS   28        /* Field Separator,  Ctrl-Backslash */
+#define XGS   29        /* Group Separator,  Ctrl-Rightbracket */
+#define XRS   30        /* Record Separator, Ctrl-Circumflex */
+#define US    31        /* Unit Separator,   Ctrl-Underscore */
+#define SP    32        /* Space */
+#define DEL  127        /* Delete (Rubout) */
+#define RUB  127        /* Delete (Rubout) */
+
+#ifdef OS2
+/*
+  These are needed in OS/2, so let's not cause any unnecessary conflicts.
+*/
+#define _CSI  0233      /* 8-bit Control Sequence Introducer */
+#define _SS2  0216      /* 8-bit Single Shift 2 */
+#define _SS3  0217      /* 8-bit Single Shift 3 */
+#define _DCS  0220      /* 8-bit Device Control String Introducer */
+#define _ST8  0234      /* 8-bit String Terminator */
+#define _OSC  0235      /* 8-bit Operating System Command */
+#define _PM8  0236      /* 8-bit Privacy Message */
+#define _APC  0237      /* 8-bit Application Program Command */
+#endif /* OS2 */
+#endif /* CKCASC_H */
diff --git a/ckermit-8.0.211/ckcbwr.txt b/ckermit-8.0.211/ckcbwr.txt
new file mode 100644
index 0000000..5e70e65
--- /dev/null
+++ b/ckermit-8.0.211/ckcbwr.txt
@@ -0,0 +1,1467 @@
+
+                      C-Kermit 8.0 General Hints and Tips
+
+     Frank da Cruz
+     [1]The Kermit Project, [2]Columbia University
+
+   As of: C-Kermit 8.0.211, 17 March 2003
+   This page last updated: Sat Apr 10 16:37:37 2004 (New York USA Time)
+
+     IF YOU ARE READING A PLAIN-TEXT version of this document, it is a
+     plain-text dump of a Web page. You can visit the original (and
+     possibly more up-to-date) Web page here:
+
+  [3]http://www.columbia.edu/kermit/ckcbwr.html
+
+   This document contains platform-independent C-Kermit hints and tips.
+   Also see the platform-specific C-Kermit hints and tips document for
+   your platform, for example:
+
+  [4]http://www.columbia.edu/kermit/ckubwr.html
+
+   for Unix. This document also applies to [5]Kermit 95 for Windows,
+   which is based on C-Kermit.
+
+   [ [6]C-Kermit ] [ [7]TUTORIAL ]
+    ________________________________________________________________________
+
+  CONTENTS
+
+   0. [8]PATCHES
+   1. [9]INCOMPATIBLE CHANGES
+   2. [10]THE C-KERMIT COMMAND PARSER
+   3. [11]MULTIPLE SESSIONS
+   4. [12]NETWORK CONNECTIONS
+   5. [13]MODEMS AND DIALING
+   6. [14]DIALING HINTS AND TIPS
+   7. [15]TERMINAL SERVERS
+   8. [16]TERMINAL EMULATION
+   9. [17]KEY MAPPING
+  10. [18]FILE TRANSFER
+  11. [19]SCRIPT PROGRAMMING
+    ________________________________________________________________________
+
+  0. PATCHES
+
+   [ [20]Top ] [ [21]Contents ] [ [22]Next ]
+
+   Source-level patches for C-Kermit 8.0.211:
+
+     (None)
+    ________________________________________________________________________
+
+  1. INCOMPATIBLE CHANGES
+
+   [ [23]Top ] [ [24]Contents ] [ [25]Next ]
+
+   These are not necessarily exhaustive lists.
+
+  1.1. C-Kermit 6.0
+
+   C-Kermit 6.0 was released 6 September 1996 and is completely
+   documented in [26]Using C-Kermit, 2nd Edition. The following
+   incompatible changes were made in C-Kermit 6.0:
+
+     * Unless you tell C-Kermit otherwise, if a serial or network
+       connection seems to be open, and you attempt to EXIT or to open a
+       new connection, C-Kermit warns you that an active connection
+       appears to be open and asks you if you really want to close it. If
+       you do not want these warnings, add SET EXIT WARNING OFF to your
+       customization file or script, or give this command at the prompt.
+     * The default for SET { SEND, RECEIVE } PATHNAMES was changed from
+       ON to OFF, to prevent unexpected creation of directories and
+       depositing of incoming files in places you might not know to look.
+     * The default for SET FILE INCOMPLETE was changed from DISCARD to
+       KEEP to allow for file transfer recovery.
+     * The default file-transfer block-check is now 3, rather than 1. If
+       the other Kermit does not support this, the two will drop back to
+       type 1 automatically unless the other Kermit fails to follow the
+       protocol specification.
+     * The default flow-control is now "auto" ("do the right thing for
+       each type of connection"), not Xon/Xoff.
+     * Backslash (\) is no longer a command continuation character. Only
+       - (hyphen, dash) may be used for this in C-Kermit 6.0 and later.
+     * Negative INPUT timeout now results in infinite wait, rather than 1
+       second.
+
+  1.2. C-Kermit 7.0
+
+   C-Kermit 7.0 was released 1 January 2000. Its new features are
+   documented in the C-Kermit 7.0 Supplement,
+   [27]http://www.columbia.edu/kermit/ckermit2.html. The following
+   incompatible changes were made in C-Kermit 7.0:
+     * The "multiline GET" command is gone. Now use either of the
+       following forms instead:
+  get remote-name local-name
+  get /as-name:local-name remote-name
+       If either name contains spaces, enclose it in braces (or, in
+       C-Kermit 8.0, doublequotes).
+     * To include multiple file specifications in a GET command, you must
+       now use MGET rather than GET:
+  mget file1 file2 file3 ...
+     * C-Kermit 7.0 and later use FAST Kermit protocol settings by
+       default. This includes "unprefixing" of certain control
+       characters. Because of this, file transfers that worked with
+       previous releases might not work in the new release especially
+       against a non-Kermit-Project Kermit protocol implementation (but
+       it is more likely that they will work, and much faster). If a
+       transfer fails, you'll get a context-sensitive hint suggesting
+       possible causes and cures. Usually SET PREFIXING ALL does the
+       trick.
+     * By default C-Kermit 7.0 and later send files in text or binary
+       mode by looking at each file to see which is the appropriate mode.
+       To restore the previous behavior, put SET TRANSFER MODE MANUAL and
+       the desired SET FILE TYPE (TEXT or BINARY) in your C-Kermit
+       initialization file.
+     * The RESEND and REGET commands automatically switch to binary mode;
+       previously if RESEND or REGET were attempted when FILE TYPE was
+       TEXT, these commands would fail immediately, with a message
+       telling you they work only when the FILE TYPE is BINARY. Now they
+       simply do this for you.
+     * SET PREFIXING CAUTIOUS and MINIMAL now both prefix linefeed (10
+       and 138) in case rlogin, ssh, or cu are "in the middle", since
+       otherwise <LF>~ might appear in Kermit packets, and this would
+       cause rlogin, ssh, or cu to disconnect, suspend,escape back, or
+       otherwise wreck the file transfer. Xon and Xoff are now always
+       prefixed too, even when Xon/Xoff flow control is not in effect,
+       since unprefixing them has proven dangerous on TCP/IP connections.
+     * In UNIX, VMS, Windows, and OS/2, the DIRECTORY command is built
+       into C-Kermit itself rather than implemented by running an
+       external command or program. The built-in command might not behave
+       the way the platform-specific external one did, but many options
+       are available for customization. Of course the underlying
+       platform-specific command can still be accessed with "!", "@", or
+       "RUN" wherever the installation does not forbid. In UNIX, the "ls"
+       command can be accessed directly as "ls" in C-Kermit.
+     * SEND ? prints a list of switches rather than a list of filenames.
+       If you want to see a list of filenames, use a (system-dependent)
+       construction such as SEND ./? (for UNIX, Windows, or OS/2), SEND
+       []? (VMS), etc.
+     * In UNIX, OS-9, and Kermit 95, the wildcard characters in previous
+       versions were * and ?. In C-Kermit 7.0 they are *, ?, [, ], {, and
+       }, with dash used inside []'s to denote ranges and comma used
+       inside {} to separate list elements. If you need to include any of
+       these characters literally in a filename, precede each one with
+       backslash (\).
+     * SET QUIET { ON, OFF } is now on the command stack, just like SET
+       INPUT CASE, SET COUNT, SET MACRO ERROR, etc, as described on p.458
+       of [28]Using C-Kermit, 2nd Edition. This allows any macro or
+       command file to SET QUIET ON or OFF without worrying about saving
+       and restoring the global QUIET value. For example, this lets you
+       write a script that tries SET LINE on lots of devices until it
+       finds one free without spewing out loads of error messages, and
+       also without disturbing the global QUIET setting, whatever it was.
+     * Because of the new "." operator (which introduces assignments),
+       macros whose names begin with "." can not be invoked "by name".
+       However, they still can be invoked with DO or \fexecute().
+     * The syntax of the EVALUATE command has changed. To restore the
+       previous syntax, use SET EVALUATE OLD.
+     * The \v(directory) variable now includes the trailing directory
+       separator; in previous releases it did not. This is to allow
+       constructions such as:
+  cd \v(dir)data.tmp
+       to work across platforms that might have different directory
+       notation, such as UNIX, Windows, and V