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