From:	SMTP%"mab@research.att.com"

Enclosed is release 1.3.0 of CFS, the Cryptographic File System, which
also includes version 1.0 of ESM, the Encrypting Session Manager.

To unpack this distribution, create a directory for the cfs sources, cd
there and copy every thing after the "cut here" line to a file called
"cfs.shar".  Then type 
	/bin/sh cfs.shar
at your shell prompt.

For installation instructions, see the files "README.install",
"notes.ms" and "README.esm".

There is a mailing list, cfs-users, for discussion of topics of interest to
CFS users and developers.  It is a fairly quiet list, and it's where bug
fixes and new ports are announced, so I encourage you to join.  To subscribe:
	echo subscribe cfs-users | mail cfs-users-request@research.att.com
You will automatically receive a "welcome" message confirming that you
have been added to the list.

User-contributed ports to other platforms are available in the list archive.
   echo help | mail cfs-users-request@research.att.com
and
   echo get cfs-users README.archive | mail cfs-users-request@research.att.com
for details.

-matt

=================cut here=========
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#  10689 -rw-r--r-- Makefile
#   3593 -rw-r--r-- admproto.x
#   4310 -rw-r--r-- mount.x
#   7684 -rw-r--r-- nfsproto.x
#   7232 -rw-r--r-- cfs.c
#   4908 -rw-r--r-- cfs_adm.c
#  24472 -rw-r--r-- cfs_nfs.c
#   6303 -rw-r--r-- cfs.h
#  25370 -rw-r--r-- cfs_fh.c
#  36708 -rw-r--r-- cfs_des.c
#   3298 -rw-r--r-- cfs_cipher.c
#   5720 -rw-r--r-- mcg.c
#   8536 -rw-r--r-- mcgsbox.c
#   1917 -rw-r--r-- mcg.h
#   7310 -rw-r--r-- shs.c
#    300 -rw-r--r-- shs.h
#   5756 -rw-r--r-- cattach.c
#   7590 -rw-r--r-- getpass.c
#   1826 -rw-r--r-- cdetach.c
#   3909 -rw-r--r-- cmkdir.c
#   1785 -rw-r--r-- adm.c
#   2726 -rw-r--r-- cname.c
#   3335 -rw-r--r-- ccat.c
#   4569 -rw-r--r-- cpasswd.c
#   2017 -rw-r--r-- truerand.c
#     70 -rw-r--r-- ver.c
#     45 -rwxr-xr-x i
#     24 -rwxr-xr-x o
#    305 -rwxr-xr-x ssh
#  17727 -rw-r--r-- esm.c
#   6542 -rw-r--r-- esm_cipher.c
#   2331 -rw-r--r-- esm_gen.c
#   3870 -rw-r--r-- dhparams.c
#   1232 -rw-r--r-- esm.h
#   4169 -rw-r--r-- cattach.1
#    672 -rw-r--r-- cdetach.1
#   2047 -rw-r--r-- cmkdir.1
#   1279 -rw-r--r-- ssh.1
#   1523 -rw-r--r-- cfsd.8
#   1322 -rw-r--r-- cname.8
#   1037 -rw-r--r-- ccat.8
#    922 -rw-r--r-- cpasswd.1
#    646 -rw-r--r-- README
#   3622 -rw-r--r-- README.install
#   1158 -rw-r--r-- README.history
#  22239 -rw-r--r-- notes.ms
#   2336 -rw-r--r-- README.linux
#   4464 -rw-r--r-- README.esm
#   3682 -rw-r--r-- esm.1
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  echo 'WARNING: not restoring timestamps.  Consider getting and'
  echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
# ============= Makefile ==============
if test -f 'Makefile' && test X"$1" != X"-c"; then
  echo 'x - skipping Makefile (file already exists)'
else
  echo 'x - extracting Makefile (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
# Makefile for cfs 1.3.x, ESM 1.0
#*
#* The author of this software is Matt Blaze.
#*              Copyright (c) 1992, 1993, 1994 by AT&T.
#* Permission to use, copy, and modify this software without fee
#* is hereby granted, provided that this entire notice is included in
#* all copies of any software which is or includes a copy or
#* modification of this software and in all copies of the supporting
#* documentation for such software.
#*
#* This software is subject to United States export controls.  You may
#* not export it, in whole or in part, or cause or allow such export,
#* through act or omission, without prior authorization from the United
#* States government and written permission from AT&T.  In particular,
#* you may not make any part of this software available for general or
#* unrestricted distribution to others, nor may you disclose this software
#* to persons other than citizens and permanent residents of the United
#* States and Canada. 
#*
#* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
#* WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
#* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
#* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
#*
X
#==========================================================================
# See the README* and the CFS release notes (notes.ms) for instructions.
#==========================================================================
X
#==========================================================================
# Edit the three "CONFIGURE:" sections below to customize for your platform.
# Note that I've tested only the SunOS and BSDI configurations.
# Good luck if you're using something weird like Solaris...
#==========================================================================
X
# ESM NOTE: You need RSAREF 2.0 (not included in the distribution) to
# compile ESM.  You can get RSAREF by ftp from rsa.com .
# To compille, edit the configuration section for your platform below.
# You'll probably need to change the RSALIB and CFLAGS to point tothe
# right places for your local copy of RSAREF
X
# WARNING:  ESM RUNS ON FEWER PLATFORMS THAN CFS.  COMPILE ESM AT
# YOUR OWN RISK IF YOU AREN'T USING BSDI OR SUNOS 4.x.
# ESM does NOT run under Solaris.
X
#CFS PORTS:
# HP/UX, Irix, Linux and AIX ported by Mark Henderson (markh@wimsey.com)
# Ultrix 4.2 ported by Ed Gould (ed@left.wing.org)
# Solaris 2.3 ported by Mark Stein (Mark.Stein@Eng.Sun.COM)
# More Solaris/Linux help by Christopher Oliver (oliver@fritz.co.traverse.com) 
X
X
#==========================================================================
# (1/3) CONFIGURE: local customization
#==========================================================================
#
# configuration options for all platforms
#
# pathnames, compiler, etc:
CC=cc
COPT=-O
BINDIR=/usr/local/bin
ETCDIR=/usr/local/etc
PRINTCMD=enscript -Gr2
# you only need RSAREF for ESM
RSALIB=/usr/mab/rsaref/install/rsaref.a
RINCLUDES=/usr/mab/rsaref/source
X
# if you're a paranoid facist, you might want to configure
# default timeouts on the attach command.  If you do,
# just add definitions for TIMEOUT and IDLE with the default number
# of minutes you want to the CFLAGS line.
# So the CFLAGS line for the SUNOS configuration with a timeout
# of 12 hours and an idle timer of 2 hours would look like:
# CFLAGS=-O -DTIMEOUT=720 -DIDLE=120
# If you leave them out the default timeouts are infinite.  You
# can override them, of course, on the cattach command line.
X
X
#=======================================================================
# (2/3) CONFIGURE: platform selection
#=======================================================================
# Uncomment the options for the your local platform.
# You'll need to figure out how to install man pages yourself.
X
## use these for vanilla SUNOS 4.x
#CFLAGS=$(COPT) -I$(RINCLUDES) -DPROTOTYPES=0 -DSUN
#LIBS=
#COMPAT=
X
## use these for Linux (Slackware 1.1.2)
#CFLAGS=$(COPT) -I$(RINCLUDES)
#LIBS=
#COMPAT=
X
## Irix 4.0 -- markh@wimsey.bc.ca
#CFLAGS=-cckr $(COPT) -Dirix
#LIBS=-lrpcsvc -lsun -I$(RINCLUDES) -DPROTOTYPES=0
#COMPAT=
X
## hpux 8.0 -- markh@wimsey.bc.ca
# also thanks to Charles Henrich (henrich@crh.cl.msu.edu)
# and Eric Ross (ericr@hpvclq.vcd.hp.com)
#CFLAGS=$(COPT) -Dhpux -DNORLIMITS -I$(RINCLUDES) -DPROTOTYPES=0
#LIBS=-lBSD
#COMPAT=
X
## use these for AIX 3.2.0 -- markh@wimsey.bc.ca
#CFLAGS=$(COPT) -D_BSD -D_SUN -DAIX320EUIDBUG -I$(RINCLUDES) -DPROTOTYPES=0
#LIBS=
#COMPAT=
X
## use these for 4.4/BSD386 systems with CFS on its own port
#CFLAGS=$(COPT) -DBSD44 -DANYPORT -I$(RINCLUDES)
#LIBS=-lrpc
#COMPAT=-lcompat
X
## Ultrix 4.2a
#CFLAGS=$(COPT) -DANYPORT -I$(RINCLUDES)
#LIBS=
#COMPAT=
X
## use these for 4.4/BSD386 systems with CFS on the NFS port because of no
# support for the port options in the mount syscall
# BSDI support by mab
# Also works under freeBSD, though you may want to use -static on the
#  linker (dean@deanstoy.wa.com (Dean M. Phillips))
#CFLAGS=$(COPT) -DBSD44 -DANYPORT -DCFS_PORT=2049 -I$(RINCLUDES)
#LIBS=-lrpc
#COMPAT=-lcompat
X
##use these for NetBSD i386 1.0 (John Kohl)
# for mounting, you need to use a command like:
#	mount -o -P,-c localhost:/null /crypt
# use -DSHORTLINKS to support the BSD 4.4 symbolic links (Dave Carrel)
#CFLAGS=$(COPT) -DBSD44 -DANYPORT -DCFS_PORT=2049 -DSHORTLINKS -I$(RINCLUDES)
#LIBS=
#COMPAT=-lcompat
X
## use these flags on Solaris 2.3 / SUNOS 5.x
#CFLAGS=$(COPT) -DSOLARIS2X -DPORTMAP -I$(RINCLUDES) -DPROTOTYPES=0
#LIBS=-lsocket -lnsl
#COMPAT=
X
## not sure what to do for NeXT.  I think this works:
#CFLAGS=$(COPT) -posix -D_BSD -DANYPORT -I$(RINCLUDES)
X
X
#==========================================================================
# (3/3) CONFIGURE: one last thing
#==========================================================================
# finally, comment out the next line:
X	HEY! Edit the Makefile for your local configuration
X
# now you're done with local configuration.
X
X
#==========================================================================
# CONFIGURE: you shouldn't touch anything below here
#==========================================================================
X
SRCS=Makefile admproto.x mount.x nfsproto.x cfs.c cfs_adm.c cfs_nfs.c cfs.h \
X  cfs_fh.c cfs_des.c cfs_cipher.c mcg.c mcgsbox.c mcg.h shs.c shs.h cattach.c \
X  getpass.c cdetach.c cmkdir.c adm.c cname.c ccat.c cpasswd.c truerand.c \
X  ver.c i o ssh
ESRCS=esm.c esm_cipher.c esm_gen.c dhparams.c esm.h
MANS=cattach.1 cdetach.1 cmkdir.1 ssh.1 cfsd.8 cname.8 ccat.8 cpasswd.1 \
X  README README.install README.history notes.ms README.linux README.esm esm.1
OBJS= cfs.o nfsproto_xdr.o nfsproto_svr.o admproto_xdr.o admproto_svr.o \
X  cfs_adm.o cfs_nfs.o cfs_fh.o cfs_des.o cfs_cipher.o adm.o ver.o mcgsbox.o \
X  mcg.o
EOBJS=dhparams.o truerand.o esm_gen.o esm.o esm_cipher.o
COBJS=admproto_clnt.o cfs_des.o cfs_cipher.o cattach.o getpass.o cmkdir.o \
X  cdetach.o ver.o cname.o ccat.o mcgsbox.o mcgsbox.o mcg.o shs.o cpasswd.o \
X  truerand.o
OTHERS = nfsproto.h nfsproto_svr.c nfsproto_xdr.c admproto.h admproto_svr.c \
X  admproto_xdr.c admproto_clnt.c
X
default:
X	@echo make "cfs", "esm", "install_cfs" or "install_esm"
X
cfs: cfsd cattach cmkdir cdetach cname ccat cpasswd
X	@echo
X
cfsd: $(OBJS)
X	$(CC) $(OBJS) $(LIBS) -o cfsd
X
cattach: cattach.o admproto_clnt.o admproto_xdr.o getpass.o cfs_des.o \
X  cfs_cipher.o adm.o ver.o mcg.o mcgsbox.o shs.o
X	$(CC) cattach.o admproto_clnt.o admproto_xdr.o cfs_des.o \
X	   cfs_cipher.o getpass.o adm.o ver.o mcg.o mcgsbox.o \
X	   shs.o $(COMPAT) $(LIBS) -o cattach
X
cdetach: cdetach.o admproto_clnt.o admproto_xdr.o adm.o ver.o
X	$(CC) cdetach.o adm.o admproto_clnt.o admproto_xdr.o \
X	   ver.o $(LIBS) -o cdetach
X
cmkdir: getpass.o cfs_des.o cfs_cipher.o cmkdir.o ver.o mcg.o \
X   mcgsbox.o shs.o truerand.o
X	$(CC) cmkdir.o cfs_des.o cfs_cipher.o getpass.o adm.o ver.o mcg.o \
X	   mcgsbox.o shs.o truerand.o  $(COMPAT) -o cmkdir
X
cpasswd: getpass.o cfs_des.o cfs_cipher.o cpasswd.o ver.o mcg.o \
X   mcgsbox.o shs.o truerand.o
X	$(CC) cpasswd.o cfs_des.o cfs_cipher.o getpass.o ver.o mcg.o \
X	   mcgsbox.o shs.o truerand.o  $(COMPAT) -o cpasswd
X
cname: cname.o getpass.o cfs_des.o cfs_cipher.o cfs_adm.o cfs_fh.o \
X   cfs_nfs.o ver.o mcg.o mcgsbox.o shs.o
X	$(CC) cname.o getpass.o cfs_des.o cfs_cipher.o cfs_adm.o cfs_fh.o \
X	   cfs_nfs.o ver.o mcg.o mcgsbox.o shs.o $(LIBS) $(COMPAT) -o cname
X
ccat: ccat.o getpass.o cfs_des.o cfs_cipher.o cfs_adm.o cfs_fh.o cfs_nfs.o \
X   ver.o mcg.o mcgsbox.o shs.o
X	$(CC) ccat.o getpass.o cfs_des.o cfs_cipher.o cfs_adm.o cfs_fh.o \
X	   cfs_nfs.o ver.o mcg.o mcgsbox.o shs.o $(LIBS) $(COMPAT) -o ccat
X
$(OBJS): nfsproto.h admproto.h cfs.h mcg.h shs.h
X
$(COBJS): nfsproto.h admproto.h cfs.h mcg.h shs.h
X
nfsproto_xdr.c: nfsproto.x
X	rpcgen -c -o nfsproto_xdr.c nfsproto.x 
X
nfsproto_svr.c: nfsproto.x
X	rpcgen -m -o nfsproto_svr.c nfsproto.x 
X
nfsproto.h: nfsproto.x
X	rpcgen -h -o nfsproto.h nfsproto.x
X
admproto_xdr.c: admproto.x
X	rpcgen -c -o admproto_xdr.c admproto.x 
X
admproto_svr.c: admproto.x
X	rpcgen -m -o admproto_svr.c admproto.x 
X
admproto.h: admproto.x
X	rpcgen -h -o admproto.h admproto.x
X
admproto_clnt.c: admproto.x
X	rpcgen -l -o admproto_clnt.c admproto.x 
X
clean:
X	rm -f $(OBJS) $(COBJS) $(OTHERS) cfsd cmkdir cattach cdetach cname ccat
X	rm -f $(EOBJS) esm
X
cfs.shar: $(SRCS) $(ESRCS) $(MANS)
X	shar $(SRCS) $(ESRCS) $(MANS)  > cfs.shar
X
printout: $(SRCS) cfs.h mcg.h admproto.h nfsproto.h
X	$(PRINTCMD) $(SRCS) cfs.h mcg.h admproto.h nfsproto.h
X
labprint: $(SRCS) cfs.h mcg.h admproto.h nfsproto.h
X	pr $(SRCS) cfs.h mcg.h admproto.h nfsproto.h | ipr -Pip7 -O -2 #-F
X	stroff -man $(MANS)
X
install_cfs: cfsd cattach cdetach cmkdir
X	install -m 0755 -c -o root cfsd $(ETCDIR)
X	install -m 0755 -c -o root cattach cdetach cmkdir cpasswd ssh cname ccat $(BINDIR)
#	install -m 0755 i o $(BINDIR)
X	@echo "Kill any running cfsd prior to restarting."
X	@echo "See the README file for more information."
X	@echo "Don't forget to install the man pages (*.[18])."
X
X
$(EOBJS): esm.h
X
esm: esm.o cfs_des.o esm_cipher.o dhparams.o truerand.o
X	$(CC) -o esm esm.o cfs_des.o esm_cipher.o dhparams.o truerand.o $(RSALIB)
X
# to generate your own dhparams, remove the existing dhparams.c and
# remake esm.  You shouldn't do this if you want to remain interoperable.
# esm_gen takes a long time.
esm_gen: esm_gen.o esm_cipher.o cfs_des.o truerand.o
X	$(CC) -o esm_gen esm_gen.o esm_cipher.o cfs_des.o truerand.o $(RSALIB)
X
dhparams.c:
X	make esm_gen
X	esm_gen > dhparams.c
X
install_esm: esm
X	install esm $(BINDIR)
X
esm.shar: 
X	shar README.esm Makefile esm.c *.x cfs_des.c esm_cipher.c esm_gen.c \
X	dhparams.c truerand.c esm.h esm.1> esm.shar
SHAR_EOF
  $shar_touch -am 0728032195 'Makefile' &&
  chmod 0644 'Makefile' ||
  echo 'restore of Makefile failed'
  shar_count="`wc -c < 'Makefile'`"
  test 10689 -eq "$shar_count" ||
    echo "Makefile: original size 10689, current size $shar_count"
fi
# ============= admproto.x ==============
if test -f 'admproto.x' && test X"$1" != X"-c"; then
  echo 'x - skipping admproto.x (file already exists)'
else
  echo 'x - extracting admproto.x (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'admproto.x' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * cfs admin protocol RPC spec
X *  1.3 version, supporting multiple crypt modes & new ciphers
X */
X
/* error conditions */
enum cfsstat {
X	CFS_OK=0,		/* ok */
X	CFSERR_PERM=1,		/* permission denied */
X	CFSERR_IFULL=2,		/* instance table full; */
X	CFSERR_NOINS=3,		/* no such instance */
X	CFSERR_EXIST=4,		/* name already in use */
X	CFSERR_NODIR=5,		/* no such directory */
X	CFSERR_BADKEY=6,	/* invalid key */
X	CFSERR_BADNAME=7	/* badly formed name */
};
X
enum ciphers {
X	CFS_STD_DES=0,		/* 2 key hybrid single DES */
X	CFS_THREE_DES=1,	/* 2 key hybrid 3DES */
X	CFS_IDEA=2,		/* 2 key hybrid IDEA (n/a) */
X	CFS_BLOWFISH=3,		/* 2 key hybrid BLOWFISH */
X	CFS_SKIPJACK=4,		/* 2 key hybrid SKIPJACK, (PCMCIA) (n/a) */
X	CFS_MACGUFFIN=5		/* 2 key hybrid MacGuffin */
};
X
const CFS_MAXCOMP=255;
const CFS_MAXNAME=1024;
X
X
X
struct cfs_adm_deskey {
X	long pl;	/* for the align police */
X	u_char primary[8];
X	u_char secondary[8];
};
X
struct cfs_adm_3deskey {
X	long pl;	/* for the align police */
X	u_char primary1[8];
X	u_char primary2[8];
X	u_char secondary1[8];	/* same as primaries */
X	u_char secondary2[8];
};
X
struct cfs_adm_blowkey {
X	long pl;		/* for 32 bit police */
X	u_char primary[16];
X	u_char secondary[16];	/* same as primary */
};
X
struct cfs_adm_mcgkey {
X	long pl;		/* for 32 bit align police */
X	u_char primary[16];
X	u_char secondary[16];	/* same as primary */
};
X
union cfs_admkey switch (ciphers cipher) {
X    case CFS_STD_DES:
X	cfs_adm_deskey deskey;
X    case CFS_THREE_DES:
X	cfs_adm_3deskey des3key;
X    case CFS_BLOWFISH:
X	cfs_adm_blowkey blowkey;
X    case CFS_MACGUFFIN:
X	cfs_adm_mcgkey mcgkey;
X    default:
X	void;
};
X
struct cfs_attachargs {
X	string dirname<CFS_MAXNAME>;	/* directory to attach to */
X	string name<CFS_MAXCOMP>;	/* instance name */
X	cfs_admkey key;			/* key to use */
X	int uid;			/* uid to apply - need not be
X					   same as in rpc */
X	int highsec;			/* nonzero for highsec mode */
X	bool anon;			/* anonymousness */
X	/* for timeouts, zero indicates infinite */
X	int expire;			/* number of minutes to live */
X	int idle;			/* idle timeout */
};
X
struct cfs_detachargs {
X	string name<CFS_MAXCOMP>;	/* instance name */
X	int uid;			/* just has to match */
};
X
X
program ADM_PROGRAM {
X	version ADM_VERSION {
X		void ADMPROC_NULL(void) = 0;
X		cfsstat ADMPROC_ATTACH(cfs_attachargs) = 1;
X		cfsstat ADMPROC_DETACH(cfs_detachargs) = 2;
X	} = 2;
} = 0x21234567;
X
X
X
SHAR_EOF
  $shar_touch -am 0722232895 'admproto.x' &&
  chmod 0644 'admproto.x' ||
  echo 'restore of admproto.x failed'
  shar_count="`wc -c < 'admproto.x'`"
  test 3593 -eq "$shar_count" ||
    echo "admproto.x: original size 3593, current size $shar_count"
fi
# ============= mount.x ==============
if test -f 'mount.x' && test X"$1" != X"-c"; then
  echo 'x - skipping mount.x (file already exists)'
else
  echo 'x - extracting mount.x (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'mount.x' &&
/* @(#)mount.x	1.2 87/11/12 3.9 RPCSRC */
/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */
X
/*
X * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
X * unrestricted use provided that this legend is included on all tape
X * media and as a part of the software program in whole or part.  Users
X * may copy or modify Sun RPC without charge, but are not authorized
X * to license or distribute it to anyone else except as part of a product or
X * program developed by the user.
X * 
X * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
X * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
X * 
X * Sun RPC is provided with no support and without any obligation on the
X * part of Sun Microsystems, Inc. to assist in its use, correction,
X * modification or enhancement.
X * 
X * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
X * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
X * OR ANY PART THEREOF.
X * 
X * In no event will Sun Microsystems, Inc. be liable for any lost revenue
X * or profits or other special, indirect and consequential damages, even if
X * Sun has been advised of the possibility of such damages.
X * 
X * Sun Microsystems, Inc.
X * 2550 Garcia Avenue
X * Mountain View, California  94043
X */
X
/*
X * Protocol description for the mount program
X */
X
X
const MNTPATHLEN = 1024;	/* maximum bytes in a pathname argument */
const MNTNAMLEN = 255;		/* maximum bytes in a name argument */
const FHSIZE = 32;		/* size in bytes of a file handle */
X
/*
X * The fhandle is the file handle that the server passes to the client.
X * All file operations are done using the file handles to refer to a file
X * or a directory. The file handle can contain whatever information the
X * server needs to distinguish an individual file.
X */
struct fhandle {
X	opaque data[FHSIZE];	
};
X
/*
X * If a status of zero is returned, the call completed successfully, and 
X * a file handle for the directory follows. A non-zero status indicates
X * some sort of error. The status corresponds with UNIX error numbers.
X */
union fhstatus switch (unsigned fhs_status) {
case 0:
X	struct fhandle fhs_fhandle;
default:
X	void;
};
X
/*
X * The type dirpath is the pathname of a directory
X */
typedef string dirpath<MNTPATHLEN>;
X
/*
X * The type name is used for arbitrary names (hostnames, groupnames)
X */
typedef string name<MNTNAMLEN>;
X
/*
X * A list of who has what mounted
X */
struct mountlist {
X	name ml_hostname;
X	dirpath ml_directory;
X	mountlist *ml_next;
};
X
/*
X * A list of netgroups
X */
typedef struct groupnode *groups;
struct groupnode {
X	name gr_name;
X	groups *gr_next;
};
X
/*
X * A list of what is exported and to whom
X */
struct exports {
X	dirpath ex_dir;
X	groups ex_groups;
X	exports *ex_next;
};
X
program MOUNTPROG {
X	/*
X	 * Version one of the mount protocol communicates with version two
X	 * of the NFS protocol. The only connecting point is the fhandle 
X	 * structure, which is the same for both protocols.
X	 */
X	version MOUNTVERS {
X		/*
X		 * Does no work. It is made available in all RPC services
X		 * to allow server reponse testing and timing
X		 */
X		void
X		MOUNTPROC_NULL(void) = 0;
X
X		/*	
X		 * If fhs_status is 0, then fhs_fhandle contains the
X	 	 * file handle for the directory. This file handle may
X		 * be used in the NFS protocol. This procedure also adds
X		 * a new entry to the mount list for this client mounting
X		 * the directory.
X		 * Unix authentication required.
X		 */
X		fhstatus 
X		MOUNTPROC_MNT(dirpath) = 1;
X
X		/*
X		 * Returns the list of remotely mounted filesystems. The 
X		 * mountlist contains one entry for each hostname and 
X		 * directory pair.
X		 */
X		mountlist
X		MOUNTPROC_DUMP(void) = 2;
X
X		/*
X		 * Removes the mount list entry for the directory
X		 * Unix authentication required.
X		 */
X		void
X		MOUNTPROC_UMNT(dirpath) = 3;
X
X		/*
X		 * Removes all of the mount list entries for this client
X		 * Unix authentication required.
X		 */
X		void
X		MOUNTPROC_UMNTALL(void) = 4;
X
X		/*
X		 * Returns a list of all the exported filesystems, and which
X		 * machines are allowed to import it.
X		 */
X		exports
X		MOUNTPROC_EXPORT(void)  = 5;
X	
X		/*
X		 * Identical to MOUNTPROC_EXPORT above
X		 */
X		exports
X		MOUNTPROC_EXPORTALL(void) = 6;
X	} = 1;
} = 100005;
SHAR_EOF
  $shar_touch -am 1201164292 'mount.x' &&
  chmod 0644 'mount.x' ||
  echo 'restore of mount.x failed'
  shar_count="`wc -c < 'mount.x'`"
  test 4310 -eq "$shar_count" ||
    echo "mount.x: original size 4310, current size $shar_count"
fi
# ============= nfsproto.x ==============
if test -f 'nfsproto.x' && test X"$1" != X"-c"; then
  echo 'x - skipping nfsproto.x (file already exists)'
else
  echo 'x - extracting nfsproto.x (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'nfsproto.x' &&
/* @(#)nfs_prot.x	1.2 87/11/12 3.9 RPCSRC */
X
/*
X * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
X * unrestricted use provided that this legend is included on all tape
X * media and as a part of the software program in whole or part.  Users
X * may copy or modify Sun RPC without charge, but are not authorized
X * to license or distribute it to anyone else except as part of a product or
X * program developed by the user.
X * 
X * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
X * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
X * 
X * Sun RPC is provided with no support and without any obligation on the
X * part of Sun Microsystems, Inc. to assist in its use, correction,
X * modification or enhancement.
X * 
X * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
X * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
X * OR ANY PART THEREOF.
X * 
X * In no event will Sun Microsystems, Inc. be liable for any lost revenue
X * or profits or other special, indirect and consequential damages, even if
X * Sun has been advised of the possibility of such damages.
X * 
X * Sun Microsystems, Inc.
X * 2550 Garcia Avenue
X * Mountain View, California  94043
X */
X
/*
X * nfs_prot.x 1.2 87/10/12
X * Copyright 1987 Sun Microsystems, Inc.
X */
const NFS_PORT          = 2049;
const NFS_MAXDATA       = 8192;
const NFS_MAXPATHLEN    = 1024;
const NFS_MAXNAMLEN	= 255;
const NFS_FHSIZE	= 32;
const NFS_COOKIESIZE	= 4;
const NFS_FIFO_DEV	= -1;	/* size kludge for named pipes */
X
/*
X * File types
X */
const NFSMODE_FMT  = 0170000;	/* type of file */
const NFSMODE_DIR  = 0040000;	/* directory */
const NFSMODE_CHR  = 0020000;	/* character special */
const NFSMODE_BLK  = 0060000;	/* block special */
const NFSMODE_REG  = 0100000;	/* regular */
const NFSMODE_LNK  = 0120000;	/* symbolic link */
const NFSMODE_SOCK = 0140000;	/* socket */
const NFSMODE_FIFO = 0010000;	/* fifo */
X
/*
X * Error status
X */
enum nfsstat {
X	NFS_OK= 0,		/* no error */
X	NFSERR_PERM=1,		/* Not owner */
X	NFSERR_NOENT=2,		/* No such file or directory */
X	NFSERR_IO=5,		/* I/O error */
X	NFSERR_NXIO=6,		/* No such device or address */
X	NFSERR_ACCES=13,	/* Permission denied */
X	NFSERR_EXIST=17,	/* File exists */
X	NFSERR_NODEV=19,	/* No such device */
X	NFSERR_NOTDIR=20,	/* Not a directory*/
X	NFSERR_ISDIR=21,	/* Is a directory */
X	NFSERR_FBIG=27,		/* File too large */
X	NFSERR_NOSPC=28,	/* No space left on device */
X	NFSERR_ROFS=30,		/* Read-only file system */
X	NFSERR_NAMETOOLONG=63,	/* File name too long */
X	NFSERR_NOTEMPTY=66,	/* Directory not empty */
X	NFSERR_DQUOT=69,	/* Disc quota exceeded */
X	NFSERR_STALE=70,	/* Stale NFS file handle */
X	NFSERR_WFLUSH=99	/* write cache flushed */
};
X
/*
X * File types
X */
enum ftype {
X	NFNON = 0,	/* non-file */
X	NFREG = 1,	/* regular file */
X	NFDIR = 2,	/* directory */
X	NFBLK = 3,	/* block special */
X	NFCHR = 4,	/* character special */
X	NFLNK = 5,	/* symbolic link */
X	NFSOCK = 6,	/* unix domain sockets */
X	NFBAD = 7,	/* unused */
X	NFFIFO = 8 	/* named pipe */
};
X
/*
X * File access handle
X */
struct nfs_fh {
X	opaque data[NFS_FHSIZE];
};
X
/* 
X * Timeval
X */
struct nfstime {
X	unsigned seconds;
X	unsigned useconds;
};
X
X
/*
X * File attributes
X */
struct fattr {
X	ftype type;		/* file type */
X	unsigned mode;		/* protection mode bits */
X	unsigned nlink;		/* # hard links */
X	unsigned uid;		/* owner user id */
X	unsigned gid;		/* owner group id */
X	unsigned size;		/* file size in bytes */
X	unsigned blocksize;	/* prefered block size */
X	unsigned rdev;		/* special device # */
X	unsigned blocks;	/* Kb of disk used by file */
X	unsigned fsid;		/* device # */
X	unsigned fileid;	/* inode # */
X	nfstime	atime;		/* time of last access */
X	nfstime	mtime;		/* time of last modification */
X	nfstime	ctime;		/* time of last change */
};
X
/*
X * File attributes which can be set
X */
struct sattr {
X	unsigned mode;	/* protection mode bits */
X	unsigned uid;	/* owner user id */
X	unsigned gid;	/* owner group id */
X	unsigned size;	/* file size in bytes */
X	nfstime	atime;	/* time of last access */
X	nfstime	mtime;	/* time of last modification */
};
X
X
typedef string filename<NFS_MAXNAMLEN>; 
typedef string nfspath<NFS_MAXPATHLEN>;
X
/*
X * Reply status with file attributes
X */
union attrstat switch (nfsstat status) {
case NFS_OK:
X	fattr attributes;
default:
X	void;
};
X
struct sattrargs {
X	nfs_fh file;
X	sattr attributes;
};
X
/*
X * Arguments for directory operations
X */
struct diropargs {
X	nfs_fh	dir;	/* directory file handle */
X	filename name;		/* name (up to NFS_MAXNAMLEN bytes) */
};
X
struct diropokres {
X	nfs_fh file;
X	fattr attributes;
};
X
/*
X * Results from directory operation
X */
union diropres switch (nfsstat status) {
case NFS_OK:
X	diropokres diropres;
default:
X	void;
};
X
union readlinkres switch (nfsstat status) {
case NFS_OK:
X	nfspath data;
default:
X	void;
};
X
/*
X * Arguments to remote read
X */
struct readargs {
X	nfs_fh file;		/* handle for file */
X	unsigned offset;	/* byte offset in file */
X	unsigned count;		/* immediate read count */
X	unsigned totalcount;	/* total read count (from this offset)*/
};
X
/*
X * Status OK portion of remote read reply
X */
struct readokres {
X	fattr	attributes;	/* attributes, need for pagin*/
X	opaque data<NFS_MAXDATA>;
};
X
union readres switch (nfsstat status) {
case NFS_OK:
X	readokres reply;
default:
X	void;
};
X
/*
X * Arguments to remote write 
X */
struct writeargs {
X	nfs_fh	file;		/* handle for file */
X	unsigned beginoffset;	/* beginning byte offset in file */
X	unsigned offset;	/* current byte offset in file */
X	unsigned totalcount;	/* total write count (to this offset)*/
X	opaque data<NFS_MAXDATA>;
};
X
struct createargs {
X	diropargs where;
X	sattr attributes;
};
X
struct renameargs {
X	diropargs from;
X	diropargs to;
};
X
struct linkargs {
X	nfs_fh from;
X	diropargs to;
};
X
struct symlinkargs {
X	diropargs from;
X	nfspath to;
X	sattr attributes;
};
X
X
typedef opaque nfscookie[NFS_COOKIESIZE];
X
/*
X * Arguments to readdir
X */
struct readdirargs {
X	nfs_fh dir;		/* directory handle */
X	nfscookie cookie;
X	unsigned count;		/* number of directory bytes to read */
};
X
struct entry {
X	unsigned fileid;
X	filename name;
X	nfscookie cookie;
X	entry *nextentry;
};
X
struct dirlist {
X	entry *entries;
X	bool eof;
};
X
union readdirres switch (nfsstat status) {
case NFS_OK:
X	dirlist reply;
default:
X	void;
};
X
struct statfsokres {
X	unsigned tsize;	/* preferred transfer size in bytes */
X	unsigned bsize;	/* fundamental file system block size */
X	unsigned blocks;	/* total blocks in file system */
X	unsigned bfree;	/* free blocks in fs */
X	unsigned bavail;	/* free blocks avail to non-superuser */
};
X
union statfsres switch (nfsstat status) {
case NFS_OK:
X	statfsokres reply;
default:
X	void;
};
X
/*
X * Remote file service routines
X */
program NFS_PROGRAM {
X	version NFS_VERSION {
X		void 
X		NFSPROC_NULL(void) = 0;
X
X		attrstat 
X		NFSPROC_GETATTR(nfs_fh) =	1;
X
X		attrstat 
X		NFSPROC_SETATTR(sattrargs) = 2;
X
X		void 
X		NFSPROC_ROOT(void) = 3;
X
X		diropres 
X		NFSPROC_LOOKUP(diropargs) = 4;
X
X		readlinkres 
X		NFSPROC_READLINK(nfs_fh) = 5;
X
X		readres 
X		NFSPROC_READ(readargs) = 6;
X
X		void 
X		NFSPROC_WRITECACHE(void) = 7;
X
X		attrstat
X		NFSPROC_WRITE(writeargs) = 8;
X
X		diropres
X		NFSPROC_CREATE(createargs) = 9;
X
X		nfsstat
X		NFSPROC_REMOVE(diropargs) = 10;
X
X		nfsstat
X		NFSPROC_RENAME(renameargs) = 11;
X
X		nfsstat
X		NFSPROC_LINK(linkargs) = 12;
X
X		nfsstat
X		NFSPROC_SYMLINK(symlinkargs) = 13;
X
X		diropres
X		NFSPROC_MKDIR(createargs) = 14;
X
X		nfsstat
X		NFSPROC_RMDIR(diropargs) = 15;
X
X		readdirres
X		NFSPROC_READDIR(readdirargs) = 16;
X
X		statfsres
X		NFSPROC_STATFS(nfs_fh) = 17;
X	} = 2;
} = 100003;
X
SHAR_EOF
  $shar_touch -am 1130153592 'nfsproto.x' &&
  chmod 0644 'nfsproto.x' ||
  echo 'restore of nfsproto.x failed'
  shar_count="`wc -c < 'nfsproto.x'`"
  test 7684 -eq "$shar_count" ||
    echo "nfsproto.x: original size 7684, current size $shar_count"
fi
# ============= cfs.c ==============
if test -f 'cfs.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cfs.c (file already exists)'
else
  echo 'x - extracting cfs.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cfs.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * Crypto file system
X *  main 1.3
X * mab - 11/30/92
X * mab - 01/11/94
X * mab - 11/10/94
X */
X
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
/* #include <netinet/in.h> */
/* #include <arpa/inet.h> */
#include <netdb.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#ifndef NORLIMITS
#include <sys/resource.h>
#endif
#include <signal.h>
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
X
struct in_addr validhost;
X
#if defined(SOLARIS2X) || defined(__NetBSD__)
void nfs_program_2();
void adm_program_2();
#include <string.h>
#else
int nfs_program_2();
int adm_program_2();
#endif
X
void grimreap();
X
char zerovect[]={0,0,0,0,0,0,0,0,0};
int cursecs;
X
main(argc,argv)
X     int argc;
X     char **argv;
{
X	int port=CFS_PORT;
X
X	struct timeval tv;
X	struct hostent *hp;
X	struct sockaddr_in sin;
X	int svrsock;
X	SVCXPRT *tp;
X	int pid;
#ifdef SOLARIS2X
X	struct netconfig *nc;
X	struct t_bind tbind, *tres;
X	struct t_info tinfo;
#endif
X
X	/* create the right kind of socket */
X	if (argc > 2) {
X		fprintf(stderr,"Usage: cfsd [port]\n");
X		exit(1);
X	}
X	if (argc==2) {
X		if ((port=atoi(argv[1]))<=0) {
X			fprintf(stderr,"Usage: cfsd [port]\n");
X			exit(1);
X		}
X	}
X	if ((hp=gethostbyname("localhost"))==NULL) {
X		fprintf(stderr,"Can't deal with localhost\n");
X		exit(1);
X	}
X	bzero((char *)&sin,sizeof(sin));
X	sin.sin_family=AF_INET;
X	bcopy((char *)hp->h_addr,(char *)&sin.sin_addr,hp->h_length);
X	/* sin.sin_addr = inet_makeaddr(INADDR_ANY,np);*/
X	validhost.s_addr=sin.sin_addr.s_addr;
X	sin.sin_port = htons(port);
X
#ifdef SOLARIS2X
X	if ((nc = getnetconfigent("udp")) == NULL) {
X		nc_perror("udp");
X		exit(1);
X	}
X
X	if ((svrsock = t_open(nc->nc_device, O_RDWR, &tinfo)) < 0) {
X		t_error("Can't t_open UDP device");
X		exit(1);
X	}
X
X	if ((tres = (struct t_bind *)t_alloc(svrsock, T_BIND, T_ADDR)) == NULL){
X		t_error("Can't t_alloc buffer");
X		exit(1);
X	}
X
X	tbind.qlen = 0;
X	tbind.addr.buf = (char *)&sin;
X	tbind.addr.len = tbind.addr.maxlen = tinfo.addr;
X
X	if (t_bind(svrsock, &tbind, tres) != 0) {
X		t_error("t_bind");
X		exit(1);
X	}
X
X	if (tbind.addr.len != tres->addr.len ||
X	    memcmp(tbind.addr.buf, tres->addr.buf, tres->addr.len) != 0) {
X		/* bound address does not match requested one */
X		fprintf(stderr,
"t_bind did not bind to requested address (is another cfsd running?)\n");
X		exit(1);
X	}
X
X	if ((tp = svc_dg_create(svrsock, 0, 0)) == NULL) {
X		fprintf(stderr,"Can't create UDP RPC Service\n");
X		exit(1);
X	}
X
X	/* Assign the local bind address and type of service */
X	tp->xp_ltaddr = tres->addr;
X	tp->xp_type = tinfo.servtype;
X	tp->xp_rtaddr.len = 0;
X	tp->xp_rtaddr.maxlen = tres->addr.maxlen;
X	tp->xp_netid = strdup(nc->nc_netid);
X	tp->xp_tp = strdup(nc->nc_device);
X
X	if ((tp->xp_rtaddr.buf = malloc(tp->xp_rtaddr.maxlen)) == NULL) {
X		fprintf(stderr, "Can't malloc buffer space\n");
X		exit(1);
X	}
X
X	/* now register w/ the local dispatcher */
X	/*  don't register nfs w/ portmaper, tho */
X	if (!svc_reg(tp, NFS_PROGRAM, NFS_VERSION, nfs_program_2,
X			(port==2049? nc : NULL))) {
X		fprintf(stderr,"Can't register CFS NFS\n");
X		exit(1);
X	}
X	if (!rpcb_unset(ADM_PROGRAM, ADM_VERSION, nc)) {
X		fprintf(stderr, "Can't init CFS ADM rpcbind mapping\n");
X		exit(1);
X	}
X	if (!svc_reg(tp, ADM_PROGRAM, ADM_VERSION, adm_program_2, nc)) {
X		fprintf(stderr,"Can't register CFS ADM\n");
X		exit(1);
X	}
#else
X	if ((svrsock=socket(AF_INET,SOCK_DGRAM,0)) < 0) {
X		perror("socket");
X		exit(1);
X	}
X
X	if (bind(svrsock,(struct sockaddr *)&sin,sizeof(sin)) != 0) {
X		perror("bind");
X		exit(1);
X	}
X
X	if ((tp = svcudp_create(svrsock)) == NULL) {
X		fprintf(stderr,"Can't create UDP RPC Service\n");
X		exit(1);
X	}
X	
X	/* now register w/ the local dispatcher */
X	/*  don't register nfs w/ portmaper, tho */
X	if (!svc_register(tp,NFS_PROGRAM,NFS_VERSION,nfs_program_2,
X			(port==2049?IPPROTO_UDP:0))) {
X		fprintf(stderr,"Can't register CFS NFS\n");
X		exit(1);
X	}
X	pmap_unset(ADM_PROGRAM,ADM_VERSION);
X	if (!svc_register(tp,ADM_PROGRAM,ADM_VERSION,adm_program_2,
X			  IPPROTO_UDP)) {
X		fprintf(stderr,"Can't register CFS ADM\n");
X		exit(1);
X	}
#endif
X
#ifndef	DEBUG
X	if ((pid=fork())!=0) {
X		if (pid<0) {
X			perror("cfsd: fork\n");
X			exit(1);
X		}
X		printf("cfs ready [%d]\n",pid);
X		exit(0);
X	}
#else
X	printf("cfs running DEBUG (%d)\n", getpid());
#endif
X	initstuff();
X	/* and lauch the timeout handler (which we have to do in child) */
X	gettimeofday(&tv,NULL);
X	cursecs=tv.tv_sec;
X	signal(SIGALRM,grimreap);
X	alarm(60); /* every 60 secs */
X
X	svc_run(); /* do it */
X	fprintf(stderr,"Huh??  Where the hell am I?\n");
X	exit(1);
}
X
initstuff()
{
X	int i;
X	static instance ina,inb;
#ifndef NORLIMITS
X	struct rlimit rl;
#endif
X	
X	/* first set uid to 0, if we can */
X	/* now we can go back and forth easily */
X 	setuid(0);
X	umask(0);
X
#if defined(__NetBSD__)
#ifndef DEBUG
X	/* detach from terminal */
X	daemon(0,0);
#endif /* DEBUG */
#endif /* __NetBSD__ */
X
#ifndef NORLIMITS
X	/* make sure we don't spill a corefile */
X	rl.rlim_cur=0;
X	rl.rlim_max=0;
X	setrlimit(RLIMIT_CORE,&rl);
#else	
X	/* set signal handlers */
X	/* for things that can dump core */
X	signal(SIGQUIT,SIG_IGN);
X	signal(SIGILL,SIG_IGN);
X	signal(SIGTRAP,SIG_IGN);
X	signal(SIGABRT,SIG_IGN);
X	signal(SIGEMT,SIG_IGN);
X	signal(SIGFPE,SIG_IGN);
X	signal(SIGBUS,SIG_IGN);
X	signal(SIGSEGV,SIG_IGN);
X	signal(SIGSYS,SIG_IGN);
#ifdef SIGLOST
X	signal(SIGLOST,SIG_IGN);
#endif
#endif
X	/* clear out the instances table */
X	for (i=0; i<NINSTANCES; i++)
X		instances[i]=NULL;
}
X
/* look for instances to kill */
void grimreap()
{
X	struct timeval tv;
X	int i;
X
X	gettimeofday(&tv,NULL);
X	cursecs=tv.tv_sec;
#ifdef DEBUG
X	fprintf(stderr,"grimly reaping\n");
#endif
X	for (i=0; i<NINSTANCES; i++)
X		if (instances[i] != NULL) {
X			if (instances[i]->dead > 4)
X				freeinstance(i);
X			else if ((instances[i]->timeout)
X			    && (instances[i]->timeout < cursecs))
X					instances[i]->dead++;
X			else if ((instances[i]->idle)
X			    && ((instances[i]->access + instances[i]->idle)
X				< cursecs))
X					instances[i]->dead++;
X		}
X	signal(SIGALRM,grimreap);
X	alarm(60);
}
SHAR_EOF
  $shar_touch -am 0724160295 'cfs.c' &&
  chmod 0644 'cfs.c' ||
  echo 'restore of cfs.c failed'
  shar_count="`wc -c < 'cfs.c'`"
  test 7232 -eq "$shar_count" ||
    echo "cfs.c: original size 7232, current size $shar_count"
fi
# ============= cfs_adm.c ==============
if test -f 'cfs_adm.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cfs_adm.c (file already exists)'
else
  echo 'x - extracting cfs_adm.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cfs_adm.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * server adm rpc handlers - ver 1.2
X */
#include <sys/types.h>
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#include <string.h>
#include "admproto.h"
#include "nfsproto.h"
#include "cfs.h"
X
typedef struct svc_req *SR;
X
int topinstance = 0;
X
cfs_adm()
{
}
X
void *
admproc_null_2()
{
}
X
cfsstat *
admproc_attach_2(ap,rp)
X     cfs_attachargs *ap;
X     SR *rp;
{
X	static cfsstat ret;
X	int i;
X	cfskey tk;
X	instance *ins;
X
#ifdef DEBUG
X	printf("attach: %s %s %d\n",ap->dirname, ap->name, ap->anon);
#endif
X	if (*ap->dirname != '/') {
X		ret = CFSERR_BADNAME;
X		return &ret;
X	}
X	if (index(ap->name,'/') != NULL) {
X		ret = CFSERR_BADNAME;
X		return &ret;
X	}
X	if (already(ap->name)) {
X		ret=CFSERR_EXIST;
X		return &ret;
X	}
X	become(rp);
X	copykey(&ap->key,&tk);
X	if ((ret=verify(ap->dirname,&tk)) != CFS_OK) {
X		become(NULL);
X		return &ret;
X	}
X	become(NULL);
X	for (i=topinstance+1; i<NINSTANCES; i++)
X		if (instances[i] == NULL)
X			break;
X	if (i==NINSTANCES) for (i=1; i<topinstance; i++)
X		if (instances[i] == NULL)
X			break;
X	if (i==topinstance) {
X		ret=CFSERR_IFULL;
X		return &ret;
X	}
X	if ((ins=(instance*)malloc(sizeof(instance)))==NULL) {
X		ret=CFSERR_IFULL;
X		return &ret;
X	}
X	topinstance=i;
X	instances[i]=ins;
X	ins->id=i;
X	for (i=0; i<HSIZE; i++)
X		ins->file[i]=NULL;
X	ins->anon=ap->anon;
X	sprintf(ins->path,"%s/.",ap->dirname);
X	strcpy(ins->name,ap->name);
X	copykey(&ap->key,&ins->key);
X	genmasks(&ins->key);
X	ins->uid=ap->uid;
X	ins->highsec=ap->highsec;
X	gettimeofday((struct timeval *)&roottime,NULL);
X	if (ap->expire !=0)
X		ins->timeout = roottime.seconds + (ap->expire*60);
X	else
X		ins->timeout = 0;
X	ins->access=roottime.seconds;
X	ins->idle=ap->idle * 60;
X	ins->dead=0;
X	bzero((char *)ins->check,8);
X	bcopy((char *)&roottime,(char *)ins->check,sizeof(roottime));
X	cipher(&ins->key,ins->check,0);
X	ret=CFS_OK;
X	return &ret;
}
X
already(s)
X     char *s;
{
X	int i;
X
X	for (i=1; i<NINSTANCES; i++)
X		if ((instances[i]!=NULL) && !strcmp(instances[i]->name,s))
X			return 1;
X	return 0;
}
X
genmasks(k)
X     cfskey *k;
{
X	unsigned int i;
X	char start[9];
X	FILE *fp;
X
X	for (i=0; i<SMSIZE; i+=CFSBLOCK) {
X		sprintf(start,"0%07x",i/CFSBLOCK);
X		bcopy(start,&k->primask[i],CFSBLOCK);
X		mask_cipher(k,&k->primask[i],0);
X		sprintf(start,"1%07x",i/CFSBLOCK);
X		bcopy(start,&k->secmask[i],CFSBLOCK);
X		mask_cipher(k,&k->secmask[i],0);
X	}
}
X
cfsstat *
admproc_detach_2(ap,rp)
X     cfs_detachargs *ap;
X     SR *rp;
{
X	static cfsstat ret;
X	int i;
X
X	if (strncmp(ap->name,".ANON_",6) == 0) {
X		i = atoi(&ap->name[6]);
X		if ((i>0) && (i<NINSTANCES) && (instances[i]!=NULL))
X			goto found;
X	}
X	for (i=1; i<NINSTANCES; i++)
X		if ((instances[i]!=NULL)&&!strcmp(instances[i]->name,ap->name))
X			break;
X	if (i==NINSTANCES) {
X		ret=CFSERR_NOINS;
X		return &ret;
X	}
found:
X	freeinstance(i);
X	ret=CFS_OK;
X	return &ret;
}
X
/* freeinstance is also called by geth if expired */
freeinstance(i)
X    int i;
{
X	int j;
X
X	for (j=0; j<HSIZE; j++) {
X		freelist(instances[i]->file[j]);
X		instances[i]->file[j]=NULL;
X	}
X	bzero((char *)instances[i],sizeof(instance));
X	free(instances[i]);
X	instances[i]=NULL;
X	gettimeofday((struct timeval *)&roottime,NULL);
X	closeall();
}
X
freelist(f)
X    cfs_fileid *f;
{
X	if (f==NULL)
X		return;
X	freelist(f->next);
X	free(f->name);
X	free(f);
}
X
verify(path,k)
X     char *path;
X     cfs_admkey *k;
{
X	FILE *fp;
X	char fn[1024];
X	char buf[9];
X
X	sprintf(fn,"%s/...",path);
X	if ((fp=fopen(fn,"r"))==NULL)
X		return CFSERR_NODIR;
X	if (fread(buf,8,1,fp)!=1) {
X		fclose (fp);
X		return CFSERR_NODIR;
X	}
X	fclose (fp);
X	cipher(k,buf,1);	/* note order here */
X	mask_cipher(k,buf,0);
X	cipher(k,buf,1);	/* note order here */
X	if (bcmp(buf,"qua!",4)!=0)
X		return CFSERR_BADKEY;
X	return CFS_OK;
}
SHAR_EOF
  $shar_touch -am 0724155895 'cfs_adm.c' &&
  chmod 0644 'cfs_adm.c' ||
  echo 'restore of cfs_adm.c failed'
  shar_count="`wc -c < 'cfs_adm.c'`"
  test 4908 -eq "$shar_count" ||
    echo "cfs_adm.c: original size 4908, current size $shar_count"
fi
# ============= cfs_nfs.c ==============
if test -f 'cfs_nfs.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cfs_nfs.c (file already exists)'
else
  echo 'x - extracting cfs_nfs.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cfs_nfs.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * crypto-nfs server functions
X *  rpc handlers
X *  access control policies
X */
X
#include <stdio.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <rpc/rpc.h>
#include <errno.h>
#ifdef NeXT
#include <sys/dir.h>
#define dirent direct
#else
#include <dirent.h>
#endif
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
X
typedef struct svc_req *SR;
X
#define herr(x) (((x)==H_INVALID)?NFSERR_STALE:NFSERR_PERM)
X
char *
pfh(fh)
X     unsigned char *fh;
{
X	static char ret[NFS_FHSIZE*2+2];
X	unsigned char x[3];
X	int i;
X
X	ret[0]='\0';
X	for (i=0; i<NFS_FHSIZE; i++) {
X		sprintf((char *)x,"%02x",fh[i]);
X		strcat(ret,x);
X	}
X	return ret;
}
X
void *
nfsproc_null_2(ap,rp)
X     void *ap;
X     SR rp;
{
X	static int ret=0;
X	return ((void*) &ret);
}
X
#define as_attr attrstat_u.attributes
X
diropres *rootlookup();
readdirres *rootreaddir();
X
attrstat *
nfsproc_getattr_2(ap,rp)
X     nfs_fh *ap;
X     SR rp;
{
X	static attrstat ret;
X	int uid;
X	int ht;
X	cfs_fileid *h;
X
#ifdef DEBUG
X	printf("getattr:\n");
#endif
X	if ((ht=htype(h=geth(ap)))!=H_REG) {
X		/* this is an ugly hack to deal w/ lookups in root,
X		   but it will do for now */;
X		if (ht==H_ROOT) {
X			ret.status=NFS_OK;
X			rootgetattr(&ret.as_attr);
X			return &ret;
X		}
X		ret.status=NFSERR_STALE;
X		return &ret;
X	}
X	uid=ruid(rp);
X	if (!fhuid(h,uid)) {
X		ret.status = NFSERR_PERM;
X		return &ret;
X	}
X	become(rp);	/* become the user */
X	switch (fhstat(h,&ret.as_attr)) {
X	    case 0:	/* ok */
X		ret.status=NFS_OK;
X		break;
X	    case -1:	/* error from syscall */
X		ret.status=cfsno(errno);
X		break;
X	    default:	/* bad handle, probably */
X		ret.status=cfserrno;
X		break;
X	}
X	closeout(h);	/* if it was open, close it */
X	become(NULL);
X	return &ret;
}
X
attrstat *
nfsproc_setattr_2(ap,rp)
X     sattrargs *ap;
X     SR rp;
{
X	static attrstat ret;
X	int uid;
X	int ht;
X	cfs_fileid *h;
X
X	/* this is non-atomic, and could leave partial results */
X	/* also, we vary from std nfs semantics in that failure does
X	   not always leave the file in its previous state */
X
#ifdef DEBUG
X	printf("setattr: \n");
#endif
X	if ((ht=htype(h=geth(&ap->file)))!=H_REG) {
X		ret.status=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	become(rp);	/* become the user */
X	switch (fhsetattr(h,&ap->attributes)) {
X	    case 0:	/* ok */
X		/* now do a getattr */		
X		switch (fhstat(h,&ret.as_attr)) {
X		    case 0:
X			ret.status=NFS_OK;
X			break;
X		    case -1:
X			ret.status=cfsno(errno);
X			break;
X		    default:
X			ret.status=cfserrno;
X			break;
X		}
X		break;
X	    case -1:	/* error from syscall */
X		/* but some things may be already set.  should fix this */
X		ret.status=cfsno(errno);
X		break;
X	    default:	/* bad handle, probably */
X		ret.status=cfserrno;
X		break;
X	}
X	become(NULL);
X	return &ret;
}
X
void *
nfsproc_root_2(ap,rp)
X     void *ap;
X     SR rp;
{
X	static int ret=0;
X
X	return ((void*)&ret);
}
X
/* fix this to deal w/ fs root (instance root should be ok) */
diropres *
nfsproc_lookup_2(ap,rp)
X     diropargs *ap;
X     SR rp;
{
X	static diropres ret;
X	diropres *retp;
X	nfs_fh *handle;
X	int uid;
X	cfskey *key;
X	char *s;
X	int ht;
X	cfs_fileid *h;
X
X	/* this, mkdir, create, and the mount protocol are the only ways
X	   to create a handle */
#ifdef DEBUG
X	printf("lookup: \n");
#endif
X	/* this is where most of the security has to lie, since lookup
X	   returns handles to files.  so we have to make sure we're coming
X	   from the right place and that it's really a priv port, etc */
X	if (!goodsrc(rp)) {
X		ret.status=NFSERR_PERM;
X		return &ret;
X	}
X	if ((ht=htype(h=geth(&ap->dir)))!=H_REG) {
X		if (ht==H_ROOT) {
X			become(rp);
X			retp=rootlookup(ap->name);
X			become(NULL);
X			return retp;
X		}
X		ret.status=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X 	if (!fhuid(h,uid)) {
X		ret.status = NFSERR_PERM;
X		return &ret;
X	}
X
X	become(rp);	/* become the user */
X	handle = &ret.diropres_u.diropres.file;
X	key=keyof(h);
X	if (key==NULL)
X		ret.status=cfsno(errno);
X	else if ((s=encryptname(key,ap->name))==NULL)
X		ret.status=NFSERR_NOENT;
X	else switch (fhlook(h,s,handle)) {
X	    /* fhlook might update the underlying name associated with the
X	       handle, or delete the handle */
X	    case 0:	/* found it */
X		/* now do a getattr */		
X		switch (fhstat(geth(handle),
X			       &ret.diropres_u.diropres.attributes)) {
X		    case 0:
X			ret.status=NFS_OK;
X			/* stat is already in attributes field */
X			break;
X		    case -1:	/* couldn't open file for some reason */
X			ret.status=cfsno(errno);
X			break;
X		    default:	/* shouldn't happen */
X			ret.status=cfserrno;
X			break;
X		}
X		break;
X	    case -1:	/* some parent dir went away, probably */
X		ret.status=cfsno(errno);
X		break;
X	    default:	/* bad parent handle or notfound, probably */
X		ret.status=cfserrno;
X		break;
X	}
X	become(NULL);
X	return (&ret);
}
X
readlinkres *
nfsproc_readlink_2(ap,rp)
X     nfs_fh *ap;
X     SR rp;
{
X	static readlinkres ret;
X	int uid;
X	char buf[NFS_MAXPATHLEN+1];
X	char *s;
X	cfskey *key;
X	int ht;
X	cfs_fileid *h;
X	int l;
X
#ifdef DEBUG
X	printf("readlink:\n");
#endif
X	if ((ht=htype(h=geth(ap)))!=H_REG) {
X		ret.status=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	become(rp);
X
X	switch (l=fhlinkval(h,buf)) {
X	    case -1:
X		ret.status=cfsno(errno);
X		break;
X	    case -2:
X		ret.status=cfserrno;
X		break;
X	    default:
X		buf[l]='\0';
X		if ((key=keyof(h))==NULL) {
X			ret.status=cfserrno;
X			break;
X		}
X		if ((s=decryptname(key,buf)) == NULL) {
X			ret.status=NFSERR_NOENT; /* close enough */
X			break;
X		}
X		ret.readlinkres_u.data = s;
X		ret.status=NFS_OK;
X		break;
X	}
X
X	become(NULL);
X	return (&ret);
}
X
X
readres *
nfsproc_read_2(ap,rp)
X     readargs *ap;
X     SR rp;
{
X	static readres ret;
X	static char buffer[8192];
X	int fd;
X	int uid;
X	int len;
X	cfskey *key;
X	int ht;
X	cfs_fileid *h;
X	
#ifdef DEBUG
X	printf("read:\n");
#endif
X	if ((ht=htype(h=geth(&ap->file)))!=H_REG) {
X		ret.status=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	if (!fhuid(h,uid)) {
X		ret.status = NFSERR_PERM;
X		return &ret;
X	}
X	become(rp);
X	switch (fd=fhtofd(h,CFS_READ)) {
X	    case -1:	/* syscall error */
X		ret.status = cfsno(errno);
X		break;
X	    case -2:	/* cfs error */
X		ret.status = cfserrno;
X		break;
X	    default:	/* fd should be valid file descriptor */
X		/* do the read */
X		key=keyof(h);
X		if (key==NULL) {
X			ret.status=cfserrno;
X			break;
X		}			
X		if ((len=readblock(buffer,fd,ap->offset,ap->count,
X				   key,vectof(h)))<0){
X			ret.status = cfsno(errno);
X			break;
X		}
X		if (fhstat(h,&ret.readres_u.reply.attributes)!=0) {
X			ret.status = cfsno(errno);
X			break;
X		}
X		ret.readres_u.reply.data.data_len = 
X			(len > (ap->count)) ? ap->count : len;
X		ret.readres_u.reply.data.data_val = buffer;
X		ret.status = NFS_OK;
X		break;
X	}
X	become(NULL);
X	return (&ret);
}
X
X
void *
nfsproc_writecache_2(ap,rp)
X     void *ap;
X     SR rp;
{
X	static int ret;
X
X	return (void *)(&ret);
}
X
X
attrstat *
nfsproc_write_2(ap,rp)
X     writeargs *ap;
X     SR rp;
{
X	static attrstat ret;
X	int fd;
X	int uid;
X	int len;
X	int offset;
X	cfskey *key;
X	char *buf;
X	int ht;
X	cfs_fileid *h;
X
#ifdef DEBUG
X	printf("write:\n");
#endif
X	if ((ht=htype(h=geth(&ap->file)))!=H_REG) {
X		ret.status=herr(ht);
X		return &ret;
X	}
X
X	uid=ruid(rp);
X	if (!fhuid(h,uid)) {
X		ret.status = NFSERR_PERM;
X		return &ret;
X	}
X	become(rp);
X	switch (fd=fhtofd(h,CFS_WRITE)) {
X	    case -1:	/* syscall error */
X		ret.status = cfsno(errno);
X		break;
X	    case -2:	/* cfs error */
X		ret.status = cfserrno;
X		break;
X	    default:	/* fd should be valid file descriptor */
X		len = ap->data.data_len;
X		offset = ap->offset;
X		buf = ap->data.data_val;
X		key=keyof(h);
X		if (key==NULL) {
X			ret.status=cfserrno;
X			break;
X		}
X		if (writeblock(buf,fd,offset,len,key,vectof(h)) < 0) {
X			ret.status = cfsno(errno);
X			break;
X		}
X		if (fhstat(h,&ret.attrstat_u.attributes)!=0) {
X			ret.status = cfsno(errno);
X			break;
X		}
X		ret.status = NFS_OK;
X		break;
X	}
X	become(NULL);
X	return (&ret);
}
X
X
diropres *
nfsproc_create_2(ap,rp)
X     createargs *ap;
X     SR rp;
{
X	static diropres ret;
X	static nfs_fh handle;
X	int uid;
X	int ht;
X	char *s;
X	cfs_fileid *h, *h2;
X
#ifdef DEBUG
X	printf("create:\n");
#endif
X	/* this, lookup, mkdir, and the mount protocol are the only ways
X	   to create a handle */
X	if (!goodsrc(rp)) {
X		ret.status=NFSERR_PERM;
X		return &ret;
X	}
X	if ((ht=htype(h=geth(&ap->where.dir)))!=H_REG) {
X		ret.status=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	if (!fhuid(h,uid)) {
X		ret.status = NFSERR_PERM;
X		return &ret;
X	}
X	become(rp);
X	
X	/* first create the dir entry */
X	/* if one already exist, the underlying handle name field gets
X	   updated to reflect its new name */
X	s=encryptname(keyof(h),ap->where.name);
X	switch (fhmkfileent(h,s,&handle)) {
X	    case 0: /* didnt exist */
X		switch (fhsetattr(h2=geth(&handle),&ap->attributes)) {
X		    case 0:	/* ok */
X			/* now do a getattr */		
X			switch (fhstat(h2,
X				       &ret.diropres_u.diropres.attributes)) {
X			    case 0:
X				bcopy(&handle,&ret.diropres_u.diropres.file,
X				      sizeof(nfs_fh));
X				ret.status=NFS_OK;
X				break;
X			    case -1:
X				ret.status=cfsno(errno);
X				break;
X			    default:
X				ret.status=cfserrno;
X				break;
X			}
X			break;
X		    case -1:	/* error from syscall */
X			ret.status=cfsno(errno);
X			break;
X		    default:	/* bad handle, probably */
X			ret.status=cfserrno;
X			break;
X		}
X		break;
X	    case 1:	/* did exist; no chmod - KLUDGE */
X		switch (fhsetattrprime(h2=geth(&handle),&ap->attributes)) {
X		    case 0:	/* ok */
X			/* now do a getattr */		
X			switch (fhstat(h2,
X				       &ret.diropres_u.diropres.attributes)) {
X			    case 0:
X				bcopy(&handle,&ret.diropres_u.diropres.file,
X				      sizeof(nfs_fh));
X				ret.status=NFS_OK;
X				break;
X			    case -1:
X				ret.status=cfsno(errno);
X				break;
X			    default:
X				ret.status=cfserrno;
X				break;
X			}
X			break;
X		    case -1:	/* error from syscall */
X			ret.status=cfsno(errno);
X			break;
X		    default:	/* bad handle, probably */
X			ret.status=cfserrno;
X			break;
X		}
X		break;
X	    case -1:
X		ret.status=cfsno(errno);
X		break;
X	    default:
X		ret.status=cfserrno;
X		break;
X	}
X	become(NULL);
X	return (&ret);
}
X
X
nfsstat *
nfsproc_remove_2(ap,rp)
X     diropargs *ap;
X     SR rp;
{
X	static nfsstat ret;
X	char *s;
X	cfskey *key;
X	int uid;
X	int ht;
X	cfs_fileid *h;
X
#ifdef DEBUG
X	printf("remove:\n");
#endif
X	if ((ht=htype(h=geth(&ap->dir)))!=H_REG) {
X		ret=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	become(rp);	/* become the user */
X	/* first encrypt the name */
X	key=keyof(h);
X	if (key==NULL) {
X		ret=cfserrno;
X	} else if ((s=encryptname(key,ap->name)) == NULL) {
X		ret=NFSERR_NOENT; /* close enough */
X	} else switch (fhdelete(h,s)) {
X	    case 0:
X		ret=NFS_OK;
X		break;
X	    case -1:
X		ret=cfsno(errno);
X		break;
X	    default:
X		ret=cfserrno;
X	}
X	become(NULL);
X	return (&ret);
}
X
X
nfsstat *
nfsproc_rename_2(ap,rp)
X     renameargs *ap;
X     SR rp;
{
X	static nfsstat ret;
X	int uid;
X	char s1[NFS_MAXPATHLEN+1], s2[NFS_MAXPATHLEN+1];
X	char *s;
X	cfskey *key;
X	int ht;
X	cfs_fileid *fromh, *toh;
X
#ifdef DEBUG
X	printf("rename:\n");
#endif
X	if ((ht=htype(fromh=geth(&ap->from.dir)))!=H_REG) {
X		ret=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	/* just make sure these are the same fs instance
X	   implicitly, this checks for a valid todir */
X	if (iid(fromh) != iid(toh=geth(&ap->to.dir))) {
X		/* what to return? there's no NFSERR_XDEV */
X		ret = NFSERR_EXIST;
X		return &ret;
X	}
X	become(rp);	/* become the user */
X
X	if ((key=keyof(fromh)) == NULL)
X		ret=cfserrno;
X	else if (((s=encryptname(key,ap->from.name)) == NULL) ||
X		 (strcpy(s1,s)==NULL))
X		ret=cfserrno;
X	else if (((s=encryptname(key,ap->to.name)) == NULL) ||
X		 (strcpy(s2,s)==NULL))
X		ret=cfserrno;
X	/* if s1 already has a handle, rename updates its underlying name */
X	else switch (fhrename(fromh,s1,
X			      toh,s2)) {
X	    case -1:
X		ret=cfsno(errno);
X		break;
X	    case -2:
X		ret=cfserrno;
X		break;
X	    default:
X		ret=NFS_OK;
X	}
X
X	become(NULL);
X	return (&ret);
}
X
X
nfsstat *
nfsproc_link_2(ap,rp)
X     linkargs *ap;
X     SR rp;
{
X	static nfsstat ret;
X	int uid;
X	char *s;
X	cfskey *key;
X	int ht;
X	cfs_fileid *fromh, *toh;
X
#ifdef DEBUG
X	printf("link:\n");
#endif
X	if ((ht=htype(fromh=geth(&ap->from)))!=H_REG) {
X		ret=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	/* again, make sure these are the same fs instance
X	   implicitly, this checks for a valid todir, since iip
X	   returns -1 on error */
X	if (iid(fromh) != iid(toh=geth(&ap->to.dir))) {
X		/* what to return? there's no NFSERR_XDEV */
X		ret = NFSERR_EXIST;	/* got a better idea? */
X		return &ret;
X	}
X	if ((key=keyof(toh))==NULL) {
X		ret=cfserrno;
X		return &ret;
X	}
X	become(rp);
X	if ((s=encryptname(key,ap->to.name))==NULL)
X		ret=cfserrno;
X	else switch (fhdohardlink(fromh,toh,s)) {
X	    case -1:
X		ret=cfsno(errno);
X		break;
X	    case -2:
X		ret=cfserrno;
X		break;
X	    default:
X		ret=NFS_OK;
X		break;
X	}
X	become(NULL);
X	return (&ret);
}
X
X
nfsstat *
nfsproc_symlink_2(ap,rp)
X     symlinkargs *ap;
X     SR rp;
{
X	static nfsstat ret;
X	int uid;
X	char *s;
X	char s1[NFS_MAXPATHLEN+1], s2[NFS_MAXPATHLEN+1];
X	cfskey *key;
X	int ht;
X	cfs_fileid *h;
X
#ifdef DEBUG
X	printf("symlink:\n");
#endif
X	if ((ht=htype(h=geth(&ap->from.dir)))!=H_REG) {
X		ret=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	if ((key=keyof(h))==NULL) {
X		ret=cfserrno;
X		return &ret;
X	}
X	become(rp);
X	if ((s=encryptname(key,ap->from.name))==NULL)
X		ret=cfserrno;
X	else {
X		strcpy(s1,s);
X		s=encryptname(key,ap->to); /* can't fail */
X		strcpy(s2,s);
X		/* ignore the attributes stuff */
X		switch (fhdosymlink(h,s1,s2)) {
X		    case -1:
X			ret=cfsno(errno);
X			break;
X		    case -2:
X			ret=cfserrno;
X			break;
X		    default:
X			ret=NFS_OK;
X			break;
X		}
X	}
X	become(NULL);
X	return (&ret);
}
X
diropres *
nfsproc_mkdir_2(ap,rp)
X     createargs *ap;
X     SR rp;
{
X	static diropres ret;
X	nfs_fh handle;
X	char *s;
X	int uid;
X	int ht;
X	cfs_fileid *h, *h2;
X	char *k;
X
#ifdef DEBUG
X	printf("mkdir:\n");
#endif
X	/* this, lookup, create, and the mount protocol are the only ways
X	   to create a handle */
X	if (!goodsrc(rp)) {
X		ret.status=NFSERR_PERM;
X		return &ret;
X	}
X	if ((ht=htype(h=geth(&ap->where.dir)))!=H_REG) {
X		ret.status=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	become(rp);
X	
X	/* first create the dir entry */
X	/* if one already exists, the underlying handle name field gets
X	   updated to reflect its new name */
X
X	s=encryptname(keyof(h),ap->where.name);
X	switch (fhmkdirent(h,s,&handle)) {
X	    case 0:
X		switch (fhsetattr(h2=geth(&handle),&ap->attributes)) {
X		    case 0:	/* ok */
X			/* now do a getattr */		
X			switch (fhstat(h2=geth(&handle),
X				       &ret.diropres_u.diropres.attributes)) {
X			    case 0:
X				bcopy(&handle,&ret.diropres_u.diropres.file,
X				      sizeof(nfs_fh));
X				ret.status=NFS_OK;
X				break;
X			    case -1:
X				ret.status=cfsno(errno);
X				break;
X			    default:
X				ret.status=cfserrno;
X				break;
X			}
X			break;
X		    case -1:	/* error from syscall */
X			ret.status=cfsno(errno);
X			break;
X		    default:	/* bad handle, probably */
X			ret.status=cfserrno;
X			break;
X		}
X		break;
X	    case -1:
X		ret.status=cfsno(errno);
X		break;
X	    default:
X		ret.status=cfserrno;
X		break;
X	}
X	become(NULL);
X	return (&ret);
}
X
X
nfsstat *
nfsproc_rmdir_2(ap,rp)
X     diropargs *ap;
X     SR rp;
{
X	static nfsstat ret;
X	char *s;
X	cfskey *key;
X	int uid;
X	int ht;
X	cfs_fileid *h;
X
#ifdef DEBUG
X	printf("rmdir:\n");
#endif
X	if ((ht=htype(h=geth(&ap->dir)))!=H_REG) {
X		ret=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	become(rp);	/* become the user */
X	/* first encrypt the name */
X	key=keyof(h);
X	if (key==NULL) {
X		ret=cfserrno;
X	} else if ((s=encryptname(key,ap->name)) == NULL) {
X		ret=NFSERR_NOENT; /* close enough */
X	} else switch (fhdeletedir(h,s)) {
X	    case 0:
X		ret=NFS_OK;
X		break;
X	    case -1:
X		ret=cfsno(errno);
X		break;
X	    default:
X		ret=cfserrno;
X	}
X	become(NULL);
X	return (&ret);
}
X
#define MAXENTRIES 128
#define MAXENTSIZE (NFS_MAXNAMLEN + sizeof(entry) + 32)
#define dentsize(s) (strlen(s) + sizeof(entry) + 32)
X
/* #define cfsclosedir(x) fhclosedir(x) */
X
readdirres *
nfsproc_readdir_2(ap,rp)
X     readdirargs *ap;
X     SR rp;
{
X	static readdirres ret;
X	int uid;
X	int ht;
X	static entry entrytab[MAXENTRIES];	/* just deal w/ it staticaly */
X	typedef char str[NFS_MAXNAMLEN+1];
X	static str names[MAXENTRIES];
X	static DIR *dp=NULL;
X	static struct dirent *dent;
X	entry **prev;
X	long loc;
X	char s1[NFS_MAXNAMLEN+1];
X	char *s;
X	cfskey *key;
X	static long curcookie=0;
X	long cookie;
X	int eof;
X	int ne;
X	int bytes;
X	DIR *cfsopendir();
X	cfs_fileid *h;
X	static int fid= -10;
X
#ifdef DEBUG
X	printf("readdir:\n");
#endif
X	if ((ht=htype(h=geth(&ap->dir)))!=H_REG) {
X		/* this is an ugly hack to deal w/ readdir of root, */
X		if (ht==H_ROOT)
X			return (rootreaddir(ap));
X		ret.status=herr(ht);
X		return &ret;
X	}
X	uid=ruid(rp);
X	become(rp);	/* become the user */
X
X	bytes = ap->count - MAXENTSIZE;
X	ne=0;
X	prev= &ret.readdirres_u.reply.entries;
X	*prev=NULL;
X	bcopy(ap->cookie,&cookie,sizeof(cookie));
X	eof=TRUE;
X	
X	key=keyof(h);
X	ret.status=NFS_OK;
X	if (!((h->fileid==fid)&&(cookie==curcookie))) {
X		if (dp!=NULL) {
X			cfsclosedir(dp);
X			dp=NULL;
X		}
X		if ((dp=cfsopendir(h,cookie)) == NULL) {
X			fid = -10;
X			ret.status=cfserrno;
X		} else {
X			fid=h->fileid;
X			curcookie=cookie;
X			dent=readdir(dp);
X		}
X	}
X	if (dp!=NULL) while (dent!=NULL) {
X		s=decryptname(key,dent->d_name);
X		cookie++;
X		if (s==NULL) { /* just skip bogus names */
X			dent=readdir(dp);
X			continue;
X		}
X		eof=FALSE;
X		if (((bytes -= dentsize(s)) < 0) || (ne >= MAXENTRIES))
X			break;
X		eof=TRUE;
X		strcpy(names[ne],s);
X		entrytab[ne].name=names[ne];
X		if (strcmp(s,".")==0)	/* me */
X			entrytab[ne].fileid=fhid(h);
X		else if (strcmp(s,"..")==0)	/* parent */
X			entrytab[ne].fileid=fhpid(h);
X		else entrytab[ne].fileid=dent->d_fileno;
X		bcopy(&cookie,entrytab[ne].cookie,sizeof(long));
X		*prev = &entrytab[ne];
X		prev = &entrytab[ne].nextentry;
X		entrytab[ne].nextentry=NULL;
X		ne++;
X		curcookie++;
X		dent=readdir(dp);
X	}
X	ret.readdirres_u.reply.eof=eof;
X	if (dent==NULL) {
X		fid= -10;
X		cfsclosedir(dp);
X		dp=NULL;
X	}
X	become(NULL);
X	return (&ret);
}
X
DIR *curdir;
int curdirid=0;
long curcookie;
X
DIR *
cfsopendir(dir,cookie)
X     cfs_fileid *dir;
X     long cookie;
{
X	DIR *ret;
X	DIR *fhopendir();
X
X	if ((ret=fhopendir(dir))==NULL)
X		return NULL;	/* fhopendir sets cfserrno */
X	/* this is an ugly hack to deal with braindead systems (afs) that can't
X	   do seekdir properly.  fortunately, we almost always already have
X	   the dir open so we don't have to do this bogosity */
X	while (cookie-- > 0)
X		readdir(ret);
X	return ret;
}
X
cfsclosedir(dp)
X     DIR *dp;
{
X	fhclosedir(dp);
}
X
statfsres *
nfsproc_statfs_2(ap,rp)
X     nfs_fh *ap;
X     SR rp;
{
X	static statfsres ret;
X
#ifdef DEBUG
X	printf("statfs: %s\n",pfh(ap));
#endif
X	setstatfsokres(&ret.statfsres_u.reply);
X	ret.status=NFS_OK;
X	return (&ret);
}
X
rootgetattr(f)
X	struct fattr *f;
{
X	f->type=NFDIR;
X	f->mode=NFSMODE_DIR|0777;
X	f->nlink=4;
X	f->uid=0;
X	f->gid=0;
X	f->size=8192;
X	f->blocksize=8192;
X	f->rdev= -1;
X	f->blocks=1;
X	f->fsid=0;
X	f->fileid=1;
X	bcopy(&roottime,&f->atime,sizeof(nfstime));
X	bcopy(&roottime,&f->mtime,sizeof(nfstime));
X	bcopy(&roottime,&f->ctime,sizeof(nfstime));
X	
}
X
setstatfsokres(s)
X	statfsokres *s;
{
X	s->tsize=8192;
X	s->bsize=8192;
X	s->blocks=0;
X	s->bfree=0;
X	s->bavail=0;
}
X
int fhstat(fh,fa)
X     cfs_fileid *fh;
X     fattr *fa;
{
X	struct stat sb;
X	int r;
X	
X	if (fh==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	if (fh== &rootnode) {
X		rootgetattr(fa);
X		return 0;
X	}
X		
X	if ((r=fhgetstat(fh,&sb)) != 0)
X		return r;
X	fa->type = getftype(sb.st_mode);
X	fa->mode = fhmode(fh,sb.st_mode);
X	fa->nlink = sb.st_nlink;
X	fa->uid = fhowner(fh,sb.st_uid);
X	fa->gid = sb.st_gid;
X	fa->size = sb.st_size; /* already tweeked */
#ifdef irix
X    fa->blocksize = 512;
X    fa->blocks = (sb.st_size + 511)/512;
#else
X	fa->blocksize = sb.st_blksize;
X	fa->blocks = sb.st_blocks;
#endif
X	fa->rdev = sb.st_rdev;
X	fa->fsid = iid(fh); /* we return the instance id */
X	fa->fileid = fhid(fh); /* inode or 0-i for iroots */
X	bcopy(&sb.st_atime,&fa->atime,sizeof(time_t));
X	bcopy(&sb.st_mtime,&fa->mtime,sizeof(time_t));
X	bcopy(&sb.st_ctime,&fa->ctime,sizeof(time_t));
X	return 0;
}
X
/* return uid associated w/ rpc call - unix style only for now */
/* note that this really doesnt belong here */
int
ruid(rp)
X     SR rp;
{
X	struct authunix_parms *cred;
X
X	if (rp->rq_cred.oa_flavor != AUTH_UNIX)
X		return -1;
X	cred=(struct authunix_parms *) rp->rq_clntcred;
X	return cred->aup_uid;
}
X
int
rgid(rp)
X     SR rp;
{
X	struct authunix_parms *cred;
X
X	if (rp->rq_cred.oa_flavor != AUTH_UNIX)
X		return -1;
X	cred=(struct authunix_parms *) rp->rq_clntcred;
X	return cred->aup_gid;
}
X
/* this is ugly, since it duplicates much of the code
X   above in lookup, but it does the job */
diropres *
rootlookup(s)
X     char *s;
{
X	static diropres ret;
X	nfs_fh *handle;
X	
X	handle = &ret.diropres_u.diropres.file;
X	switch (fhrootlook(s,handle)) {
X	    case 0:	/* found it */
X		/* now do a getattr - handle is an instance root, which
X		   is treated normally */
X		switch (fhstat(geth(handle),
X			       &ret.diropres_u.diropres.attributes)) {
X		    case 0:
X			ret.status=NFS_OK;
X			/* stat is already in attributes field */
X			break;
X		    case -1:	/* couldn't open file for some reason */
X			ret.status=cfsno(errno);
X			break;
X		    default:	/* shouldn't happen */
X			ret.status=cfserrno;
X			break;
X		}
X		break;
X	    case -1:	/* some parent dir went away, probably */
X		ret.status=cfsno(errno);
X		break;
X	    default:	/* bad parent handle or notfound, probably */
X		ret.status=cfserrno;
X		break;
X	}
X	return (&ret);
}
X
/* ugly ugly ugly - duplicates fair bit of code from readdir, but at least
X   it works */
readdirres *
rootreaddir(ap)
X    readdirargs *ap;
X
{
X	static readdirres ret;
X	static entry entrytab[MAXENTRIES];	/* just deal w/ it staticaly */
X	typedef char str[NFS_MAXNAMLEN+1];
X	static str names[MAXENTRIES];
X	entry **prev;
X	long cookie;
X	int eof;
X	int ne;
X	int bytes;
X	cfs_fileid *h;
X	struct dirent *dent;
X	struct dirent *rootrd();
X
X	bytes = ap->count - MAXENTSIZE;
X	ne=0;
X	prev= &ret.readdirres_u.reply.entries;
X	*prev=NULL;
X	bcopy(ap->cookie,&cookie,sizeof(long));
X	eof=1;
X	
X	ret.status=NFS_OK;
X	while ((dent=rootrd(cookie))!=NULL) {
X		eof=0;
X		if (((bytes -= dentsize(dent->d_name))<0)||(ne >= MAXENTRIES)){
X			break;
X		}
X		eof=1;
X		strcpy(names[ne],dent->d_name);
X		entrytab[ne].name=names[ne];
X		if (strcmp(dent->d_name,".")==0)	/* me */
X			entrytab[ne].fileid=1;
X		else if (strcmp(dent->d_name,"..")==0) /* parent, also me */
X			entrytab[ne].fileid=1;
X		else entrytab[ne].fileid=dent->d_fileno;
X		cookie=dent->d_reclen;	/* may not work everywhere */
X		*prev = &entrytab[ne];
X		bcopy(&cookie,entrytab[ne].cookie,sizeof(long));
X		prev = &entrytab[ne].nextentry;
X		entrytab[ne].nextentry=NULL;
X		ne++;
X	}
X	ret.readdirres_u.reply.eof=eof;
X	return (&ret);
}
X
extern struct in_addr validhost;
X
goodsrc(rp)
X     SR rp;
{
X	struct in_addr ia;
X	struct in_addr *ip;
X
X	if (svc_getcaller(rp->rq_xprt)->sin_addr.s_addr != validhost.s_addr) {
X		fprintf(stderr,"bad addr! %x !- %x\n",
X		  svc_getcaller(rp->rq_xprt)->sin_addr.s_addr,validhost.s_addr);
X		return 0;
X	}
X	if (rp->rq_cred.oa_flavor != AUTH_UNIX)
X		return 0;	/* bolster defense against portmap bug */
#ifndef ANYPORT
X	if (ntohs(svc_getcaller(rp->rq_xprt)->sin_port) > 1023) {
X		fprintf(stderr,"bad port! %d\n", ntohs(svc_getcaller(rp->rq_xprt)->sin_port));
X		return 0;
X	}
#endif
X	return 1;
}
SHAR_EOF
  $shar_touch -am 1124175594 'cfs_nfs.c' &&
  chmod 0644 'cfs_nfs.c' ||
  echo 'restore of cfs_nfs.c failed'
  shar_count="`wc -c < 'cfs_nfs.c'`"
  test 24472 -eq "$shar_count" ||
    echo "cfs_nfs.c: original size 24472, current size $shar_count"
fi
# ============= cfs.h ==============
if test -f 'cfs.h' && test X"$1" != X"-c"; then
  echo 'x - skipping cfs.h (file already exists)'
else
  echo 'x - extracting cfs.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cfs.h' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/* include files specific to cipher modules go here */
/* (i don't normally like nested includes) */
#include "mcg.h"
X
#define H_REG 0
#define H_ATTACH 0	/* same as regular */
#define H_ROOT 1
#define H_INVALID 9
#ifdef SHORTLINKS
#define H_SLNK 5
#endif
X
#ifndef CFS_PORT
#define CFS_PORT 3049
#endif
X
#ifndef NINSTANCES
#define NINSTANCES 64
#endif
X
#define CFSBLOCK 8	/* granularity of DES encryption */
/* writing is a bit tricky - if not 8 byte boundry, read in prev & next
X   8 byte boundry first, make the change in place, and write back the whole
X   thing */
X
#define STD_DES 0	/* 2 key hybrid single DES */
#define THREE_DES 1	/* 2 key hybrid 3DES */
#define IDEA 2		/* 2 key hybrid IDEA (n/a) */
#define BLOWFISH 3	/* 2 key hybrid BLOWFISH (n/a) */
#define SKIPJACK 4	/* 2 key hybrid SKIPJACK (PCMCIA) (n/a) */
#define MCG 5		/* 2 key hybrid MacGuffin */
X
typedef struct fhdata {
X	u_char magic[8];/* 0x0123456789abcdef */
X	u_short htype;	/* 0=reg, 1=attachpt, 2=root(but notused) */
X	u_short instance;	/* which attach */
X	u_long fileid;	/* inode # */
X	u_char check[8];/* we just encrypt the date and copy it here */
#ifdef SHORTLINKS
X	u_long linkid;	/* To uniquify short links */
X	u_char pad[4];	/* empty */
#else
X	u_char pad[8];	/* empty */
#endif
} fhdata;
X
typedef union fh_u {
X	u_char opaque[NFS_FHSIZE];
X	struct fhdata fh;
} fh_u;
X
typedef struct cfs_fileid {	/* hash table entry */
X	int fileid;	/* inode */
X	int key;	/* key id, for future use */
X	char vect[9];	/* pertubation vector */
X	char vectname[1024];	/* name of symlink w/ pert vect */
X	char *name; /* encrypted path, w/r/t cfs root */
X	/* the name should be changed to a list of names, and we should make
X	   sure we have the right one open.  Lookup (not link) adds names,
X	   remove and rmdir delete names. */
X	struct fdcache *fd; /* fd, if already open, or NULL (reg files only)*/
X	int parent;	/* dir only; -1 for instance root (send back self)*/
#ifdef SHORTLINKS
X	int link_count;	/* dir only; for shortlinks. */
X	int linkid;	/* short links only */
#endif
X	struct cfs_fileid *next;
X	struct instance *ins;	/* this is redundnat, but helps */
} cfs_fileid;
X
typedef struct fdcache {
X	cfs_fileid *file;	/* fh with the file open */
X	int fd;		/* currently open fd */
X	int mode;	/* 0=RO, else RDWR */
X	struct filecache *next;	/* fwd and back ptrs */
X	struct filecache *prev; /* frontmost is mru */
} fdcache;
X
#define HSIZE 1024
#define HMASK 0x3ff	/* change these together, please */
X
#define SMSIZE (32768*CFSBLOCK)
X
typedef struct cfskey {  /* now holds expanded keys for DES also */
X	int cipher;
X	union {	
X		struct { /* DES */
X			u_char primary[128];
X			u_char secondary[128];
X		} des;
X		struct { /* 3DES */
X			u_char primary1[128];
X			u_char primary2[128];
X			u_char secondary1[128];
X			u_char secondary2[128];
X		} des3;
X		struct { /* MacGuffin */
X			mcg_key primary;
X			mcg_key secondary;
X		} mcg;
X	} var;
X	char primask[SMSIZE];
X	char secmask[SMSIZE];
} cfskey;
X
typedef struct instance {
X	cfs_fileid *file[HMASK+1];
X	char path[NFS_MAXPATHLEN+1]; /* path to get to files w/r/t root */
X	char name[NFS_MAXNAMLEN+1];  /* name of the attach point */
X	cfskey key;
X	u_char check[8];/* we just encrypt the date and copy it here */
X	int uid;	/* authorized uid */
X			/* we need a better credential mechanism */
X	int id;		/* same as its position in instances[] */
X	int highsec;	/* use perturbation vectors */
X	int anon;	/* invisability */
X	int timeout;	/* absolute timeout (0 is infinite) */
X	int idle;	/* idle timer (0 is infinite) */
X	int access;	/* last access time (for use by idle timer) */
X	int dead;	/* to be killed */
} instance;
X
extern int cfserrno;
extern int errno;
extern int cursecs;
X
extern char zerovect[];
X
#define CFS_READ O_RDONLY
#define CFS_WRITE (O_RDWR)
X
extern char *admerrs[];
char *admmsg();
X
/* char *keyof(); */
char *encryptname();
char *decryptname();
X
cfs_fileid *geth();
X
extern instance *instances[];
extern nfstime roottime;
extern cfs_fileid rootnode;
X
#ifdef hpux
#define seteuid(x) setresuid(-1,x,-1)
#define setegid(x) setresgid(-1,x,-1)
#endif
X
#ifdef AIX320EUIDBUG
/* AIX 3.2.0 uses ruid for file ownership on creat even though the docs 
X *  say otherwise !!
X * note that we can still switch back to root. 
X * I bet this is fixed in later AIX releases, in which case this whole 
X *  ifdef can be done away with
X */
#include <sys/id.h>
#include <sys/types.h>
#define become(x) ((x)==NULL?(setuidx(ID_EFFECTIVE | ID_REAL,0)||setgidx(ID_EFFECTIVE|ID_REAL,0)) :\
X           (setgidx(ID_EFFECTIVE|ID_REAL,rgid(x)) || setuidx(ID_EFFECTIVE|ID_REAL, ruid(x))))
#else
#define become(x) ((x)==NULL?(seteuid(0)||setegid(0)) :\
X		   (setegid(rgid(x)) || seteuid(ruid(x))))
#endif
#define keyof(f) (&((f)->ins->key))
#define vectof(f) ((f)->vect)
X
#ifdef irix
#define d_fileno d_ino
#endif
X
#ifdef SOLARIS2X
#define d_fileno d_ino
#define bzero(b, l) 		memset(b, 0, l)
#define bcopy(s, d, l)		memcpy(d, s, l)
#define index(s, c)		strchr(s, c)
#define bcmp(s, d, l)		(memcmp(s, d, l)? 1 : 0)
#endif
X
#ifdef BSD44
/*
#define d_off d_reclen
#define d_fileno d_ino
*/
#endif
#include<stdlib.h>
SHAR_EOF
  $shar_touch -am 0722195695 'cfs.h' &&
  chmod 0644 'cfs.h' ||
  echo 'restore of cfs.h failed'
  shar_count="`wc -c < 'cfs.h'`"
  test 6303 -eq "$shar_count" ||
    echo "cfs.h: original size 6303, current size $shar_count"
fi
# ============= cfs_fh.c ==============
if test -f 'cfs_fh.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cfs_fh.c (file already exists)'
else
  echo 'x - extracting cfs_fh.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cfs_fh.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * cfs file handle support - 1.2
X *  local file system interface
X */
X
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/errno.h>
#ifdef NeXT
#include <sys/dir.h>
#define dirent direct
#else
#include <dirent.h>
#endif
#include <rpc/rpc.h>
#include <fcntl.h>
#include <stdio.h>
#ifdef hpux
#define NO_UTIMES
#include <time.h>
#endif
#ifdef	ultrix
#include <time.h>
#endif	/* ultrix */
#ifdef NO_UTIMES
#include <utime.h>
#endif
X
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
X
#ifdef NO_UTIMES
/* simulate utimes with utime */
int utimes(s,tv)
char *s;
struct timeval tv[2];
{
X    struct utimbuf ut;
X    ut.actime = tv[0].tv_sec;
X    ut.modtime = tv[1].tv_sec;
X    return utime(s,&ut);
}
#endif
X
#define hash(x) ((u_long)((x)&HMASK))
int inst = 0;/* starting point */
instance *instances[NINSTANCES];
X
#define MAXFDS 12
fdcache *fds=NULL;
int nfds=0;	/* number of open fd's currently in cache */
X
int cfserrno=NFS_OK;
X
/*
X * get an encrypted block from fd, which damn well better be valid
X */
int
readblock(blk,fd,offset,len,key,vect)
X     char *blk;     /* data */
X     int fd;        /* fd */
X     u_long offset; /* offset from byte zero */
X     u_long len;    /* blk len */
X     cfskey *key;     /* des key */
X     char *vect;  /* perturbation vector */
{
X	u_long begin;
X	u_long fronterr, totlen,datalen;
X	int iolen;
X	int readmore=0;
X	int userbytes;
X	char buf[8208];	/* big enough, may not even need it */
X
X	/* first, normalize to the proper boundries */
X	fronterr = offset&(CFSBLOCK-1);
X	datalen=len+fronterr;
X	begin=offset-fronterr;
X	totlen=vtod(datalen);
X	/* now begin and totlen are what we do the actual i/o on */
X	if (totlen>8208)
X		return -1;	/* shouldn't happen */
X	if (lseek(fd,begin,L_SET)<0)
X		return -1;
X	/* note that we are violating standard unix semantics here - we have
X	   no way to distinguish between zeros in the encrypted file and
X	   holes in the file, which should be returned to the user as
X	   zeros.  This could be fixed by detecting that we're creating
X	   holes at write time and filling w/ encrypted zeros, but that
X	   violates other semantics. */
X	if ((iolen=read(fd,buf,totlen)) < 0)
X		return -1;
X	userbytes=dtov(iolen)-fronterr;
X	if (userbytes < 0) /* empty file */
X		return 0;
X	dodecrypt(key,buf,iolen,begin,vect);
X	/* now copyback to the user's buffer */
X	bcopy((char *)(buf+fronterr),(char *)blk,userbytes);
X	return(userbytes);
}
X
/*
X * write an encrypted block to fd
X */
int
writeblock(blk,fd,offset,len,key,vect)
X     char *blk;     /* data */
X     int fd;        /* fd */
X     u_long offset; /* offset from byte zero */
X     u_long len;    /* blk len */
X     cfskey *key;     /* des key */
X     char *vect;    /* perturb. vector */
{
X	u_long begin, end;
X	u_long fronterr, totlen,datalen;
X	int iolen;
X	int headlen;
X	int writemore=0;
X	struct stat sb;
X	u_long mask = ~0;	/*tells us whether to expand file */
X	char buf[8216];	/* big enough, may not even need it */
X
X	/* first, normalize to the proper boundries */
X	fronterr = offset&(CFSBLOCK-1);
X	datalen=len+fronterr;
X	begin=offset-fronterr;
X	totlen=vtod(datalen);
X	end=begin+datalen+CFSBLOCK; /* lower bound on end of file */
X	if (fstat(fd,&sb)<0)
X		return -1;	/* file's not there */
X	/* now begin and datalen/totlen are what we do the actual i/o on */
X	if (totlen>8208)
X		return -1;	/* shouldn't happen */
X	bzero((char *)buf,totlen);
X	if ((totlen!=len) && (sb.st_size>begin)) {
X			/* read begining and ending slop first */
X			/* we could reduce the size of this read to just
X			   the CFSBLOCKs at the head &/| tail of the file,
X			   but that's probably more trouble than it's worth.*/
X		if (lseek(fd,begin,L_SET)<0)
X			return -1;
X		/* the extra CFSBLOCK ensures that next block is ok */
X		iolen=isbndry(totlen)?totlen:(totlen+CFSBLOCK);
X		if ((read(fd,buf,iolen))<0)
X			return -1;
X		dodecrypt(key,buf,iolen,begin,vect);
X	}
X
X	/* now we can do the actual encrypt and i/o */
X	bcopy((char *)blk,(char *)(buf+fronterr),len);
X	doencrypt(key,buf,totlen,begin,vect);
X	if (lseek(fd,begin,L_SET)<0)
X		return -1;
X	/* again, holes in the file are a delicate problem.  If the CFSBLOCK
X	   bountry is not always on a file boundry, you could even corrupt
X	   valid data.  Fortunately, these both are generally powers of 2,
X	   so it's not an issue. */
X	if ((iolen=write(fd,buf,totlen)) < 0) {
X		perror("write");
X		return -1;
X	}
X	/* iolen may contain CFSBLOCK extra chars */
X	return(dtov(iolen)-fronterr);
}
X
X
#define MAXCLEARNAME ((NFS_MAXPATHLEN-7)/2)
X
X
/*
X * encrypt a path componenet (no /'s) element
X *  leave "." and ".." unmolested
X */
char *
encryptname(key,s)
X     cfskey *key;
X     char *s;
{
X	static char cryptname[NFS_MAXNAMLEN+1];
X	u_char cryptstring[MAXCLEARNAME+CFSBLOCK+1];
X	u_char x[3];
X	u_long l;
X	int i;
X
X	if ((s==NULL) || ((l=strlen(s)+1)>MAXCLEARNAME))
X		return NULL;
X	if (!strcmp(s,".") || !strcmp(s,".."))
X		return s;
X	l=(l+(CFSBLOCK-1)) & (~(CFSBLOCK-1));
X	bzero((char *)cryptstring,l);
X	strcpy(cryptstring,s);
X	chksum(cryptstring,l);
X	doencrypt(key,cryptstring,l,10241,zerovect);
X	cryptname[0]='\0';
X	for (i=0; i<l; i++) {
X		sprintf((char *)x,"%02x",cryptstring[i]);
X		strcat(cryptname,x);
X	}
X	return cryptname;
}
X
/*
X * set high order bits
X */
chksum(s,l)
X     char *s;
X     long l;
{
X	u_long acc;
X	int i;
X	u_char bits[8];
X
X	acc=0;
X	for (i=0; s[i]!='\0'; i++)
X		acc += s[i]*((i%6)+1);
X	for (i++; i<l; i++)	/* fill up the end */
X		s[i] = s[i%8];
X	for (i=0; i<8; i++)
X		bits[i] = (acc<<(i%8))&0x80;
X	for (i=0; i<l; i++)
X		s[i] |= bits[i%8];
}
X
X
/*
X * decrypt path component
X *  leaving "." and ".."
X */
char *
decryptname(key,s)
X     cfskey *key;
X     char *s;
{
X	static char clearstring[MAXCLEARNAME+CFSBLOCK+1];
X	char x[3];
X	int y;
X	char *p, *q;
X	int l;
X	int i;
X
X	if (s==NULL)
X		return NULL;
X	if (!strcmp(s,".") || !strcmp(s,".."))
X		return s;
X	bzero((char *)clearstring,MAXCLEARNAME+CFSBLOCK+1);
X	/* unencode the string */
X	p=s;
X	q=clearstring;
X	x[2]='\0';
X	l=0;
X	while (*p) {
X		x[0] = *p++;
X		if ((x[1] = *p++) == '\0')
X			return NULL;
X		if (sscanf(x,"%x",&y)!=1)
X			return NULL;
X		*q++ = y;
X		l++;
X	}
X	*q='\0';	/* shouldnt need this */
X	if (l%CFSBLOCK)
X		return NULL;
X	dodecrypt(key,clearstring,l,10241,zerovect);
X	for (i=0; (clearstring[i]&0x7f) !='\0'; i++)
X		clearstring[i] &= 0x7f;
X	clearstring[i]='\0';
X	return clearstring;
}
X
doencrypt(k,s,l,salt,vect)
X     cfskey *k;
X     char *s;
X     int l;
X     int salt;
X     char *vect;
{
X	int i,j;
X	
X	for (i=0; i<l; i+=8) {
X		for (j=0; j<8; j++)
X			s[i+j] ^= k->primask[(i+j+salt)%SMSIZE]
X				^ vect[j]
X				^ (((i+j+salt)/SMSIZE)&0377);
X				/* makes big offsets have different masks */
X		cipher(k,&s[i],0);
X		for (j=0; j<8; j++)
X			s[i+j] ^= k->secmask[(i+j+salt)%SMSIZE];
X	}
}
X
dodecrypt(k,s,l,salt,vect)
X     cfskey *k;
X     char *s;
X     int l;
X     int salt;
X     char *vect;
{
X	int i,j;
X	
X	for (i=0; i<l; i+=8) {
X		for (j=0; j<8; j++)
X			s[i+j] ^= k->secmask[(i+j+salt)%SMSIZE];
X		cipher(k,&s[i],1);
X		for (j=0; j<8; j++)
X			s[i+j] ^= k->primask[(i+j+salt)%SMSIZE]
X				^ vect[j]
X				^ (((i+j+salt)/SMSIZE) & 0377);
X	}
X		
}
X
/*
X * convert size of data to size of block to be written
X */
vtod(d)
X     int d;
{
X	return isbndry(d)?d:(d+CFSBLOCK);
}
X
X
/*
X * convert file size into #of valid bits
X */
dtov(d)
X     int d;
{
X	return isbndry(d)?d:(d-CFSBLOCK);
}
X
/*
X * is block size a CFS boundry?
X */
isbndry(d)
X     int d;
{
X	return ((d&(CFSBLOCK-1))==0);
}
X
X
static fh_u roothandle;
cfs_fileid rootnode={1,0,"\0\0\0\0\0\0\0\0","/NOWHERE/null",NULL,NULL,0,NULL,NULL};/* fileid=1; should be unique */
nfstime roottime={0,0};
X
static u_char magictest[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
X
static cfs_fileid *
findh(id,ins
#ifdef SHORTLINKS
X	    ,linkid)
X     int linkid;
#else /* SHORTLINKS */
X     )
#endif /* SHORTLINKS */
X     int id;
X     int ins;
{
X	u_int bucket;
X	cfs_fileid *f;
X	
X	bucket=hash(id);
X	f=instances[ins]->file[bucket];
X	while (f!=NULL) {
X		if (f->fileid == id)	/* note recast */
#ifdef SHORTLINKS
X		    if (f->linkid == linkid)
#endif /* SHORTLINKS */
X			return f;
X		f=f->next;
X	}
X	return NULL;
}
X
X
cfs_fileid *
geth(h)
X     fhdata *h;	/* note recasting here - may give trouble with strict ansi */
{
X	int i;
X	cfs_fileid *r;
X
X	if (h==NULL)
X		return &rootnode;
X	/* check for rootness */
X	for (i=0; i<8; i++)
X		if (h->magic[i] != magictest[i]) {
X			/* update the root handle, so we return the
X			   latest thing it gave out for lookups of /.  */
X			bcopy((char *)h,(char*)&roothandle,sizeof(roothandle));
X			return &rootnode;
X		}
X	if (instances[h->instance] == NULL)
X		return NULL;	/* invalid/stale instance */
X	r=findh(h->fileid,h->instance
#ifdef SHORTLINKS
X				     ,h->linkid
#endif /* SHORTLINKS */
X				     );
X	/* instance may have timed out */
X	if ((r != NULL) && (r->ins->dead != 0)) {
X		/* if so, we GC it first */
X		freeinstance(h->instance);
X		r=NULL;
X	}
X	if ((r==NULL) || (bcmp(r->ins->check,h->check,8)!=0))
X		return NULL;	/* cheater */
X	return r;
}
X
X
htype(f)
X     cfs_fileid *f;
{
X	if (f == &rootnode)
X		return H_ROOT;
X	else if (f == NULL)
X		return H_INVALID;
X	else
X		return H_REG;
}
X
iid(f)
X     cfs_fileid *f;
{
X	if (f == &rootnode)
X		return -1;
X	else if (f == NULL)
X		return -2;
X	else
X		return f->ins->id;
}
X
fhowner(f,uid)
X     cfs_fileid *f;
X     int uid;
{
X	if (f->fileid == 0)	/* an instance root */
X		return (f->ins->uid);	/* return the instance owner */
X	return (uid);	/* normal case */
}
X
fhmode(f,mode)
X     cfs_fileid *f;
X     int mode;
{
X	if (f->fileid == 0)	/* an instance root */
X		return (mode&(~077));	/* set a umask of 0077 */
X	return (mode);
}
X
/* return the inode of me */
fhid(f)
X     cfs_fileid *f;
{
X	if (f==NULL)
X		return 1;
X	if (f->fileid == 0)	/* an instance root */
X		return (0-f->ins->id);	/* should be unique enough */
X	return (f->fileid);
}
X
/* return the inode of .. (directory only) */
fhpid(f)
X     cfs_fileid *f;
{
X	if (f==NULL)	/* this is main root */
X		return 1;
X	if (f->parent<=0) /* child of instance root */
X		if (f->fileid==0)
X			return 1;
X		else
X			return (0-f->ins->id);
X	return f->parent;	/* this is already 2 for main root  */
}
X
/* is uid authorized for this? */
fhuid(f,u)
X     cfs_fileid *f;
X     int u;
{
X	if (f==NULL)
X		return 1;
X	if (f->fileid == 1)	/* special case */
X		return 1;
X	if (f->ins->idle && f->fileid) /* update idle timer */
X		f->ins->access=cursecs;
X	return (f->ins->uid==u);
}
X
cfsno(err)
X     int err;
{
/* 	if (err==ENOENT)
X		return NFSERR_STALE;
X	else */
X		return err;
}
X
X
static cfs_fileid *openfd=NULL;
static int curmode=0700;
static int curfd= -1;
X
/* open file descriptor for handle.  maintains cache of one fd */
int
fhtofd(f,mode)
X     cfs_fileid *f;
X     int mode;
{
X	int fd;
X
#ifdef DEBUG
X	fprintf(stderr,"Translating %s\n",f->name);
#endif
X	if (f==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	if (curfd>=0) { /* it's open already */
X		if ((openfd==f) && (curmode==mode)) /* yay */
X			return curfd;
X		close(curfd);	/* hope it was valid... */
X		openfd=NULL;
X	}
X	if (mode==0) { mode=CFS_WRITE; }
X	if ((fd=open(f->name,mode,0))<0) {
X		cfserrno=cfsno(errno);
X		if ((errno == EACCES) && (mode==CFS_WRITE)) { /* ugly hack */
X			int omode;
X
X			omode=modeof(f->name);
X			if (omode<0)
X				return -2;
X			chmod(f->name,0700);
X			fd=open(f->name,mode,0);
X			chmod(f->name,omode);
X			if (fd<0)
X				return -2;
X		} else return -2;
X	}
X	/* now we have to make sure the vect didn't slide out from under us */
X	/* check for a linkfile */
X	if (readlink(f->vectname,f->vect,9) != 8)
X		bcopy((char *)zerovect,(char *)f->vect,8);
X	curfd=fd;
X	curmode=mode;
X	openfd=f;
X	return fd;
}
X
int
modeof(s)
X     char *s;
{
X	struct stat sb;
X
X	if (lstat(s,&sb)<0)
X		return -1;
X	return((int)sb.st_mode);
}
X
int
fhgetstat(h,sb)
X     cfs_fileid *h;
X     struct stat *sb;
{
X	if (h == NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	/* lstat is correct even for instance roots, since their names
X	   end in /. */
X	if (lstat(h->name,sb)<0)
X		return -1;
X	sb->st_size=dtov(sb->st_size); /* tweek size */
X	return 0;
}
X
closeout(f)
X     cfs_fileid *f;
{
X	if (openfd==f) {
X		if (curfd>=0)
X			close(curfd);
X		openfd=NULL;
X		curfd = -1;
X	}
}
X
closeall()
{
X	if (openfd!=NULL) {
X		if (curfd>=0)
X			close(curfd);
X		openfd=NULL;
X		curfd = -1;
X	}
}
X
fhsetattr(f,a)
X     cfs_fileid *f;
X     sattr *a;
{
X	struct timeval tv[2];
X	struct stat sb;
X	
X	if (f==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	if (f->fileid==0) { /* disallow on instance roots */
X		cfserrno=NFSERR_PERM;
X		return -2;
X	}
X	if (a==NULL) /* i dunno */
X		return 0;
X	if ((a->mode&0177777) != 0177777) {
X		if (chmod(f->name,a->mode&0177777)<0)
X			return -1;
X	}
X	if (((int)a->atime.seconds>=0) || ((int)a->mtime.seconds>=0)) {
X		if ((int)a->atime.seconds<0) {
X			lstat(f->name,&sb);
X			tv[0].tv_sec=sb.st_atime;
X			tv[0].tv_usec=0;
X		} else {
X			tv[0].tv_sec=a->atime.seconds;
X			tv[0].tv_usec=a->atime.useconds;
X		}
X		if ((int)a->mtime.seconds<0) {
X			lstat(f->name,&sb);
X			tv[1].tv_sec=sb.st_mtime;
X			tv[1].tv_usec=0;
X		} else {
X			tv[1].tv_sec=a->mtime.seconds;
X			tv[1].tv_usec=a->mtime.useconds;
X		}
X		if (utimes(f->name,tv)<0)
X			return -1;
X	}
X	if (((int)a->size) >= 0)
X		if (truncate(f->name,vtod(a->size)))
X			if (errno != EISDIR)
X				return 0;
/*	printf("fhsetattr: atime=%x,%x  mtime=%x,%x\n",
X	       a->atime.seconds, a->atime.useconds,
X	       a->mtime.seconds, a->mtime.useconds); */
X	return 0;
}
X
int
fhsetattrprime(f,a)
X     cfs_fileid *f;
X     sattr *a;
{
X	struct timeval tv[2];
X	struct stat sb;
X	
X	if (f==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	if (f->fileid==0) { /* disallow on instance roots */
X		cfserrno=NFSERR_PERM;
X		return -2;
X	}
X	if (a==NULL) /* i dunno */
X		return 0;
X	/* same as above, modulo the chmod */
X	if (((int)a->atime.seconds>=0) || ((int)a->mtime.seconds>=0)) {
X		if ((int)a->atime.seconds<0) {
X			lstat(f->name,&sb);
X			tv[0].tv_sec=sb.st_atime;
X			tv[0].tv_usec=0;
X		} else {
X			tv[0].tv_sec=a->atime.seconds;
X			tv[0].tv_usec=a->atime.useconds;
X		}
X		if ((int)a->mtime.seconds<0) {
X			lstat(f->name,&sb);
X			tv[1].tv_sec=sb.st_mtime;
X			tv[1].tv_usec=0;
X		} else {
X			tv[1].tv_sec=a->mtime.seconds;
X			tv[1].tv_usec=a->mtime.useconds;
X		}
X		if (utimes(f->name,tv)<0)
X			return -1;
X	}
X	if (((int)a->size) >= 0)
X		if (truncate(f->name,vtod(a->size)))
X			if (errno != EISDIR)
X				return 0;
X	return 0;
}
X
fhmkdirent(p,comp,h)
X     cfs_fileid *p;
X     char *comp;
X     fhdata *h;
{
X	char path[NFS_MAXPATHLEN+1];
X	struct stat sb;
X	
X	if (p==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	sprintf(path,"%s/%s",p->name,comp);
X	if (mkdir(path,0)<0)
X		return -1;
X	if (stat(path,&sb)<0)
X		return -1;
X	return (mkhandle(p,path,comp,sb.st_ino,h,zerovect,"/NOWHERE/null"
#ifdef SHORTLINKS
X									 ,FALSE
#endif /* SHORTLINKS */
X									 ));
}
X
int
fhmkfileent(p,comp,h)
X     cfs_fileid *p;
X     char *comp;
X     fhdata *h;
{
X	char path[NFS_MAXPATHLEN+1];
X	int fd;
X	struct stat sb;
X	int rs=0;
X	int m;
X	char vect[9];
X	union{
X		u_char ch[9];
X		u_long i[2];
X	} buf;
X	char linkname[NFS_MAXPATHLEN+1];
X	
X	if (p==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	sprintf(path,"%s/%s",p->name,comp);
X
X	if ((fd=open(path,O_CREAT|O_WRONLY|O_EXCL,0))<0) {
X		if (errno==EEXIST) {
X			if ((fd=open(path,O_WRONLY,0))<0)
X				return -1;
X			else
X				rs=1;
X		} else
X			return -1;
X	}
X	if (fstat(fd,&sb)<0)
X		return -1;
X	close(fd);
X	sprintf(linkname,"%s/.pvect_%s",p->name,comp);
X	if (!rs) {
X	   if (p->ins->highsec) {	/* create new pert file iff highsec */
X		/* note that there's a race condition here until the simlink */
X		/*
X		sprintf((char *)buf,"%08x",(u_long)sb.st_ino+(u_long)sb.st_ctime);
X		*/
X		buf.i[0]=(u_long)sb.st_ino;
X		buf.i[1]=(u_long)sb.st_ctime;
X		q_block_cipher("fixedkey",&buf,1);
X		/* des is just used here as a hash fn to spread the bits */
X		/* since we only use 32 bits of the result, its a nonperfect */
X		/* hash. but this doesn't really matter since collisions */
X		/* are rare.  we could save all 64 bits, but the encoding */
X		/* of the link would get messy and large */
X		sprintf(vect,"%02x%02x%02x%02x",
X			buf.ch[0],buf.ch[1],buf.ch[2],buf.ch[3]);
X		if (symlink(vect,linkname) != 0) {
X			strcpy(linkname,"/NOWHERE/null");
X			bcopy((char *)zerovect,(char *)vect,8);
X		}
X	   } else {
X		unlink(linkname);
X		bcopy((char *)zerovect,(char *)vect,8);
X		strcpy(linkname,"/NOWHERE/null");
X	   }
X	} else {
X		if (readlink(linkname,vect,9) != 8) {
X			bcopy((char *)zerovect,(char *)vect,8);
X			strcpy(linkname,"/NOWHERE/null");
X		}
X		else vect[8]='\0';
X	}
X	m=mkhandle(p,path,comp,sb.st_ino,h,vect,linkname
#ifdef SHORTLINKS
X							,FALSE
#endif /* SHORTLINKS */
X							);
X	if (m!=0)
X		return m;
X	return rs;
}
X
X
int
fhlook(p,comp,h)
X     cfs_fileid *p;
X     char *comp;
X     fhdata *h;
{
X	char path[NFS_MAXPATHLEN+1];
X	char linkname[NFS_MAXPATHLEN+1];
X	char vect[NFS_MAXPATHLEN+1];
X	struct stat sb;
X	
X	if (p==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	if (p->fileid==0) {
X		if (!strcmp(comp,"."))
X			return fhrootlook(p->ins->name,h);
X		if (!strcmp(comp,".."))
X			return fhrootlook(".",h);
X	}
X	if ((p->parent==0) && (!strcmp(comp,"..")))
X		return fhrootlook(p->ins->name,h);
X	sprintf(path,"%s/%s",p->name,comp);
X	if (lstat(path,&sb)<0) {
X		return -1;	/* just need the inode */
X	}
X	/* check for a linkfile */
X	sprintf(linkname,"%s/.pvect_%s",p->name,comp);
X	if (readlink(linkname,vect,9) != 8) {
X		bcopy((char *)zerovect,(char *)vect,8);
X		strcpy(linkname,"/NOWHERE/null");
X	}
X	else vect[8]='\0';
#ifdef SHORTLINKS
X	{
X		struct stat sp;
X		ino_t pino = p->fileid;
X		if (pino == 0) {
X			if (lstat(p->name, &sp) == 0)
X				pino = sp.st_ino;
X		}
X		return (mkhandle(p,path,comp,sb.st_ino,h,vect,linkname,
X				 (S_ISLNK(sb.st_mode)&&(pino == sb.st_ino))));
X	}
#else /* SHORTLINKS */
X	return (mkhandle(p,path,comp,sb.st_ino,h,vect,linkname));
#endif /* SHORTLINKS */
}
X
X
int
mkhandle(p,n,comp,ino,h,vect,vectname
#ifdef SHORTLINKS
X				     ,isl)
X     int isl;	/* is short link */
#else /* SHORTLINKS */
X				     )
#endif /* SHORTLINKS */
X     cfs_fileid *p;
X     char *n;
X     char *comp;
X     int ino;
X     fhdata *h;
X     char *vect;
X     char *vectname;
{
X	cfs_fileid *f;
X
#ifdef SHORTLINKS
X	if (!isl && ((f=findh(ino,p->ins->id,0)) != NULL)) {
#else /* SHORTLINKS */
X	if ((f=findh(ino,p->ins->id)) != NULL) {
#endif /* SHORTLINKS */
X		if (strcmp(comp,".") && strcmp(comp,"..")) {
X			free(f->name);
X			f->name=NULL;
X		}
X	} else {
X		if ((f=(cfs_fileid *)malloc(sizeof(cfs_fileid)))==NULL) {
X			fprintf(stderr,"cfsd: out of memory\n");
X			cfserrno=NFSERR_STALE;	/* bad news */
X			return -2;
X		}
X		f->fileid=ino;
X		f->parent=p->fileid;	/* only need for directory */
#ifdef SHORTLINKS
X		f->link_count = 0;	/* Always start at zero */
X		if (isl)
X			f->linkid = ++p->link_count;
X		else
X			f->linkid = 0;
#endif /* SHORTLINKS */
X		f->ins=p->ins;
X		f->name=NULL;
X		inserth(f);
X	}
X	if (f->name==NULL) {
X		if ((f->name=(char *)malloc(strlen(n)+1)) ==NULL) {
X			fprintf(stderr,"cfsd: out of memory\n");
X			cfserrno=NFSERR_STALE;
X			return -2;
X		}
X		strcpy(f->name,n);
X		strcpy(f->vectname,vectname);
X		bcopy((char *)vect,(char *)f->vect,8);
X		f->vect[8]='\0';
X	}
X	if (h!=NULL) {
X		fillinh(h,p->ins->id,ino,p->ins->check);
#ifdef SHORTLINKS
X		h->linkid = f->linkid;
X		if (isl)
X			h->htype = H_SLNK;
#endif /* SHORTLINKS */
X	}
X	return 0;
}
X
inserth(f)
X     cfs_fileid *f;
{
X	u_int bucket;
X	
X	bucket=hash(f->fileid);
X	f->next=instances[f->ins->id]->file[bucket];
X	instances[f->ins->id]->file[bucket]=f;
}
X
fillinh(h,iid,ino,check)
X     fhdata *h;
X     int iid;
X     int ino;
X     char *check;
{
X	bzero((char *)h,sizeof(fhdata));
X	bcopy((char *)magictest,(char *)h->magic,sizeof(magictest));
X	bcopy((char *)check,(char *)h->check,8);
X	h->htype=H_REG;
X	h->instance=iid;
X	h->fileid=ino;
}
X
int
fhdelete(f,s)
X     cfs_fileid *f;
X     char *s;
{
X	char path[NFS_MAXPATHLEN+1];
X	char linkname[NFS_MAXPATHLEN+1];
X	int ret;
X
X	if (f==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	sprintf(linkname,"%s/.pvect_%s",f->name,s);
X	sprintf(path,"%s/%s",f->name,s);
X	/* note that we don't bother to check and see if there's a
X	   handle allocated for this - just wait for the inode to be
X	   reclaimed */
X	if ((ret=unlink(path)) == 0)
X		unlink(linkname); /* doesn't matter if link isn't there */
X	return (ret);
}
X
int
fhdeletedir(f,s)
X     cfs_fileid *f;
X     char *s;
{
X	char path[NFS_MAXPATHLEN+1];
X
X	if (f==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	sprintf(path,"%s/%s",f->name,s);
X	return (rmdir(path));
}
X
DIR *
fhopendir(d)
X     cfs_fileid *d;
{
X	DIR *dp;
X	
X	if (d==NULL) {
X		cfserrno=NFSERR_STALE;
X		return NULL;
X	}
X	if ((dp=opendir(d->name))==NULL)
X		cfserrno=cfsno(errno);
X	return dp;
}
X
fhclosedir(dp)
X     DIR *dp;
{
X	closedir(dp);
}
X
X
int
fhlinkval(f,buf)
X     cfs_fileid *f;
X     char *buf;
{
X	if (f==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	return(readlink(f->name,buf,NFS_MAXNAMLEN));
}
X
X
int
fhdohardlink(f,t,n)
X     cfs_fileid *f;
X     cfs_fileid *t;
X     char *n;
{
X	char buf[NFS_MAXPATHLEN+1];
X	char linkname[NFS_MAXPATHLEN+1];
X	char vectval[9];
X	int ret;
X	
X	if ((f==NULL)||(t==NULL)) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	sprintf(buf,"%s/%s",t->name,n);
X	if ((ret=link(f->name,buf))!=0)
X			return ret;
X	sprintf(linkname,"%s/.pvect_%s",t->name,n);
X	unlink(linkname);
X	if (readlink(f->vectname,vectval,9) == 8) {
X		vectval[8]='\0';
X		symlink(vectval,linkname);
X	}
X	return ret;
}
X
int
fhdosymlink(f,n,t)
X     cfs_fileid *f;
X     char *n;
X     char *t;
{
X	char buf[NFS_MAXPATHLEN+1];
X	
X	if (f==NULL) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	sprintf(buf,"%s/%s",f->name,n);
X	return (symlink(t,buf));
}
X
int
fhrename(f,fn,t,tn)
X     cfs_fileid *f;
X     char *fn;
X     cfs_fileid *t;
X     char *tn;
{
X	char fb[NFS_MAXPATHLEN+1];
X	char tb[NFS_MAXPATHLEN+1];
X	char fblink[NFS_MAXPATHLEN+1];
X	char tblink[NFS_MAXPATHLEN+1];
X	char vectval[9];
X	
X	if ((f==NULL)||(t==NULL)) {
X		cfserrno=NFSERR_STALE;
X		return -2;
X	}
X	sprintf(fb,"%s/%s",f->name,fn);
X	sprintf(tb,"%s/%s",t->name,tn);
X	sprintf(fblink,"%s/.pvect_%s",f->name,fn);
X	sprintf(tblink,"%s/.pvect_%s",t->name,tn);
X	if (rename(fb,tb)==0) { /* now we have to do a lookup */
X		unlink(tblink);	/* may be a quick race cndtn here */
X		if (readlink(fblink,vectval,9)==8) {
X			vectval[8]='\0';
X			symlink(vectval,tblink);
X		}
X		unlink(fblink);
X		/* rename(fblink,tblink); */
X		fhlook(t,tn,NULL);
X		return 0;
X	}
X	return -1;
}
X
int
getftype(m)
X     int m;
{
X	if ((m&S_IFMT) == S_IFREG)
X		return NFREG;
X	if ((m&S_IFMT) == S_IFDIR)
X		return NFDIR;
X	if ((m&S_IFMT) == S_IFLNK)
X		return NFLNK;
X	if ((m&S_IFMT) == S_IFBLK)
X		return NFBLK;
X	if ((m&S_IFMT) == S_IFCHR)
X		return NFCHR;
X	if ((m&S_IFMT) == S_IFSOCK)
X		return NFSOCK;
X	return NFBAD;
}
X
/* should make . and .. the first entries, but this probably doesn't
X   break anything */
struct dirent *
rootrd(cookie)
X     long cookie;
{
X	static struct dirent d;
X
X	/* note that cookie should never == NINSTANCES */
X	if (cookie == 0) {
X		strcpy(d.d_name,".");
X		d.d_fileno=1;
X	} else if (cookie == 1) {
X		strcpy(d.d_name,"..");
X		d.d_fileno=1;
X	} else while (cookie<(NINSTANCES+2)) {
X		if (instances[cookie-2] != NULL) {
X			if (instances[cookie-2]->anon)
X				sprintf(d.d_name,".ANON_%d",cookie-2);
X			else
X				strcpy(d.d_name,
X				       instances[cookie-2]->name);
X			d.d_fileno=(0-(cookie-2));
X			break;
X		}
X		++cookie;
X	}
X	if (cookie>=(NINSTANCES+2))
X		return NULL;
X	d.d_reclen = ++cookie;
X	return &d;
}
X
X
int
fhrootlook(n,h)
X     char *n;
X     nfs_fh *h;
{
X	int i;
X	cfs_fileid *f;
X	
X	if (!strcmp(n,".") || !strcmp(n,"..")) {	/* self */
X		bcopy((char *)&roothandle,(char *)h,sizeof(roothandle));
X		return 0;
X	}
X	for (i=0; i<NINSTANCES; i++) {
X		if (instances[i]==NULL)
X			continue;
X		if (!strcmp(instances[i]->name,n)) {
X			if ((f=findh(0,i
#ifdef SHORTLINKS
X					,0
#endif /* SHORTLINKS */
X					)) == NULL) {
X				if ((f=(cfs_fileid *)
X				     malloc(sizeof(cfs_fileid)))==NULL) {
X					fprintf(stderr,"cfsd: no memory\n");
X					cfserrno=NFSERR_STALE;	/* bad news */
X					return -2;
X				}
X				f->fileid = 0;
X				f->parent = 0;
X				f->ins=instances[i];
X				inserth(f);
X				if ((f->name=(char *)
X				     malloc(NFS_MAXPATHLEN+1))==NULL) {
X					fprintf(stderr,
X						"cfsd: out of memory\n");
X					cfserrno=NFSERR_STALE;
X					return -2;
X				}
X				strcpy(f->name,instances[i]->path);
X			}
X			fillinh(h,i,0,f->ins->check);
X			return 0;
X		}
X	}
X	cfserrno=NFSERR_NOENT;
X	return -2;
}
SHAR_EOF
  $shar_touch -am 0724161595 'cfs_fh.c' &&
  chmod 0644 'cfs_fh.c' ||
  echo 'restore of cfs_fh.c failed'
  shar_count="`wc -c < 'cfs_fh.c'`"
  test 25370 -eq "$shar_count" ||
    echo "cfs_fh.c: original size 25370, current size $shar_count"
fi
# ============= cfs_des.c ==============
if test -f 'cfs_des.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cfs_des.c (file already exists)'
else
  echo 'x - extracting cfs_des.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cfs_des.c' &&
/*
X * The authors of this software are Don Mitchell, Jack Lacy, and Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X *	Data Encryption Standard
X *	D.P.Mitchell  83/06/08.
X *
X *	block_cipher(key, block, decrypting)
X */
X
#ifdef SOLARIS2X
#define bcopy(s, d, l)		memcpy(d, s, l)
#define bcmp(s, d, l)		(memcmp(s, d, l)? 1 : 0)
#endif
X
static long	ip_low();
static long	ip_high();
static void	fp();
void	des_key_setup();
X
/*
X *	Tables for Combined S and P Boxes
X */
X
static long  s0p[] = {
0x00410100,0x00010000,0x40400000,0x40410100,0x00400000,0x40010100,0x40010000,0x40400000,
0x40010100,0x00410100,0x00410000,0x40000100,0x40400100,0x00400000,0x00000000,0x40010000,
0x00010000,0x40000000,0x00400100,0x00010100,0x40410100,0x00410000,0x40000100,0x00400100,
0x40000000,0x00000100,0x00010100,0x40410000,0x00000100,0x40400100,0x40410000,0x00000000,
0x00000000,0x40410100,0x00400100,0x40010000,0x00410100,0x00010000,0x40000100,0x00400100,
0x40410000,0x00000100,0x00010100,0x40400000,0x40010100,0x40000000,0x40400000,0x00410000,
0x40410100,0x00010100,0x00410000,0x40400100,0x00400000,0x40000100,0x40010000,0x00000000,
0x00010000,0x00400000,0x40400100,0x00410100,0x40000000,0x40410000,0x00000100,0x40010100,
};
X
static long  s1p[] = {
0x08021002,0x00000000,0x00021000,0x08020000,0x08000002,0x00001002,0x08001000,0x00021000,
0x00001000,0x08020002,0x00000002,0x08001000,0x00020002,0x08021000,0x08020000,0x00000002,
0x00020000,0x08001002,0x08020002,0x00001000,0x00021002,0x08000000,0x00000000,0x00020002,
0x08001002,0x00021002,0x08021000,0x08000002,0x08000000,0x00020000,0x00001002,0x08021002,
0x00020002,0x08021000,0x08001000,0x00021002,0x08021002,0x00020002,0x08000002,0x00000000,
0x08000000,0x00001002,0x00020000,0x08020002,0x00001000,0x08000000,0x00021002,0x08001002,
0x08021000,0x00001000,0x00000000,0x08000002,0x00000002,0x08021002,0x00021000,0x08020000,
0x08020002,0x00020000,0x00001002,0x08001000,0x08001002,0x00000002,0x08020000,0x00021000,
};
X
static long  s2p[] = {
0x20800000,0x00808020,0x00000020,0x20800020,0x20008000,0x00800000,0x20800020,0x00008020,
0x00800020,0x00008000,0x00808000,0x20000000,0x20808020,0x20000020,0x20000000,0x20808000,
0x00000000,0x20008000,0x00808020,0x00000020,0x20000020,0x20808020,0x00008000,0x20800000,
0x20808000,0x00800020,0x20008020,0x00808000,0x00008020,0x00000000,0x00800000,0x20008020,
0x00808020,0x00000020,0x20000000,0x00008000,0x20000020,0x20008000,0x00808000,0x20800020,
0x00000000,0x00808020,0x00008020,0x20808000,0x20008000,0x00800000,0x20808020,0x20000000,
0x20008020,0x20800000,0x00800000,0x20808020,0x00008000,0x00800020,0x20800020,0x00008020,
0x00800020,0x00000000,0x20808000,0x20000020,0x20800000,0x20008020,0x00000020,0x00808000,
};
X
static long  s3p[] = {
0x00080201,0x02000200,0x00000001,0x02080201,0x00000000,0x02080000,0x02000201,0x00080001,
0x02080200,0x02000001,0x02000000,0x00000201,0x02000001,0x00080201,0x00080000,0x02000000,
0x02080001,0x00080200,0x00000200,0x00000001,0x00080200,0x02000201,0x02080000,0x00000200,
0x00000201,0x00000000,0x00080001,0x02080200,0x02000200,0x02080001,0x02080201,0x00080000,
0x02080001,0x00000201,0x00080000,0x02000001,0x00080200,0x02000200,0x00000001,0x02080000,
0x02000201,0x00000000,0x00000200,0x00080001,0x00000000,0x02080001,0x02080200,0x00000200,
0x02000000,0x02080201,0x00080201,0x00080000,0x02080201,0x00000001,0x02000200,0x00080201,
0x00080001,0x00080200,0x02080000,0x02000201,0x00000201,0x02000000,0x02000001,0x02080200,
};
X
static long  s4p[] = {
0x01000000,0x00002000,0x00000080,0x01002084,0x01002004,0x01000080,0x00002084,0x01002000,
0x00002000,0x00000004,0x01000004,0x00002080,0x01000084,0x01002004,0x01002080,0x00000000,
0x00002080,0x01000000,0x00002004,0x00000084,0x01000080,0x00002084,0x00000000,0x01000004,
0x00000004,0x01000084,0x01002084,0x00002004,0x01002000,0x00000080,0x00000084,0x01002080,
0x01002080,0x01000084,0x00002004,0x01002000,0x00002000,0x00000004,0x01000004,0x01000080,
0x01000000,0x00002080,0x01002084,0x00000000,0x00002084,0x01000000,0x00000080,0x00002004,
0x01000084,0x00000080,0x00000000,0x01002084,0x01002004,0x01002080,0x00000084,0x00002000,
0x00002080,0x01002004,0x01000080,0x00000084,0x00000004,0x00002084,0x01002000,0x01000004,
};
X
static long  s5p[] = {
0x10000008,0x00040008,0x00000000,0x10040400,0x00040008,0x00000400,0x10000408,0x00040000,
0x00000408,0x10040408,0x00040400,0x10000000,0x10000400,0x10000008,0x10040000,0x00040408,
0x00040000,0x10000408,0x10040008,0x00000000,0x00000400,0x00000008,0x10040400,0x10040008,
0x10040408,0x10040000,0x10000000,0x00000408,0x00000008,0x00040400,0x00040408,0x10000400,
0x00000408,0x10000000,0x10000400,0x00040408,0x10040400,0x00040008,0x00000000,0x10000400,
0x10000000,0x00000400,0x10040008,0x00040000,0x00040008,0x10040408,0x00040400,0x00000008,
0x10040408,0x00040400,0x00040000,0x10000408,0x10000008,0x10040000,0x00040408,0x00000000,
0x00000400,0x10000008,0x10000408,0x10040400,0x10040000,0x00000408,0x00000008,0x10040008,
};
X
static long  s6p[] = {
0x00000800,0x00000040,0x00200040,0x80200000,0x80200840,0x80000800,0x00000840,0x00000000,
0x00200000,0x80200040,0x80000040,0x00200800,0x80000000,0x00200840,0x00200800,0x80000040,
0x80200040,0x00000800,0x80000800,0x80200840,0x00000000,0x00200040,0x80200000,0x00000840,
0x80200800,0x80000840,0x00200840,0x80000000,0x80000840,0x80200800,0x00000040,0x00200000,
0x80000840,0x00200800,0x80200800,0x80000040,0x00000800,0x00000040,0x00200000,0x80200800,
0x80200040,0x80000840,0x00000840,0x00000000,0x00000040,0x80200000,0x80000000,0x00200040,
0x00000000,0x80200040,0x00200040,0x00000840,0x80000040,0x00000800,0x80200840,0x00200000,
0x00200840,0x80000000,0x80000800,0x80200840,0x80200000,0x00200840,0x00200800,0x80000800,
};
X
static long  s7p[] = {
0x04100010,0x04104000,0x00004010,0x00000000,0x04004000,0x00100010,0x04100000,0x04104010,
0x00000010,0x04000000,0x00104000,0x00004010,0x00104010,0x04004010,0x04000010,0x04100000,
0x00004000,0x00104010,0x00100010,0x04004000,0x04104010,0x04000010,0x00000000,0x00104000,
0x04000000,0x00100000,0x04004010,0x04100010,0x00100000,0x00004000,0x04104000,0x00000010,
0x00100000,0x00004000,0x04000010,0x04104010,0x00004010,0x04000000,0x00000000,0x00104000,
0x04100010,0x04004010,0x04004000,0x00100010,0x04104000,0x00000010,0x00100010,0x04004000,
0x04104010,0x00100000,0x04100000,0x04000010,0x00104000,0x00004010,0x04004010,0x04100000,
0x00000010,0x04104000,0x00104010,0x00000000,0x04000000,0x04100010,0x00004000,0x00104010,
};
X
/*
X *	DES electronic codebook encryption of one block
X *	 (quick version)
X */
q_block_cipher(short_key, text, decrypting)
char short_key[8];
char text[8];
int decrypting;
{
X	register char *key;
X	register long temp;
X	register long left, right;
X	register i;
X	register key_offset;
X	int j,k;
X	static int lk= -1;
X	static char lastkey[4][8]={"xxxxxxx","xxxxxxx","xxxxxxx","xxxxxxx"};
X	static char expanded_key[4][128];
X
X	/* now caches 4 session keys.  drops least recently added  */
X	k= -1;
X	for (j=0; j<4; j++) {
X		if (bcmp(short_key,lastkey[j],8)==0) {
X			k=j;
X			break;
X		}
X	}
X	if (k<0) {
X		k= lk = (lk+1)%4;
X		bcopy(short_key,lastkey[k],8);
X		des_key_setup(short_key, expanded_key[k]);
X	}
X	key = expanded_key[k];
X	left = ip_low(text);
X	right = ip_high(text);
X	if (decrypting) {
X		key_offset = 16 - 8;
X		key = key + 128 - 8;
X	} else
X		key_offset = 0 - 8;
X	for (i = 0; i < 16; i++) {
X		temp = (right << 1) | ((right >> 31) & 1);
X		left ^= s0p[(temp         & 0x3f) ^ key[0]]
X		      ^ s1p[((temp >>  4) & 0x3f) ^ key[1]]
X		      ^ s2p[((temp >>  8) & 0x3f) ^ key[2]]
X		      ^ s3p[((temp >> 12) & 0x3f) ^ key[3]]
X		      ^ s4p[((temp >> 16) & 0x3f) ^ key[4]]
X		      ^ s5p[((temp >> 20) & 0x3f) ^ key[5]]
X		      ^ s6p[((temp >> 24) & 0x3f) ^ key[6]];
X		temp = ((right & 1) << 5) | ((right >> 27) & 0x1f);
X		left ^= s7p[temp ^ key[7]];
X		temp = left;
X		left = right;
X		right = temp;
X		key -= key_offset;
X	}
X	temp = left;
X	left = right;
X	right = temp;
X	/*
X	 *	standard final permutation (IPI)
X	 */
X	fp(left, right, text);
}
X
/*
X *	DES electronic codebook encryption of one block
X *	 (expanded key version)
X */
des_block_cipher(expanded_key, text, decrypting)
char expanded_key[8];
char text[8];
int decrypting;
{
X	register char *key;
X	register long temp;
X	register long left, right;
X	register i;
X	register key_offset;
X
X	key = expanded_key;
X	left = ip_low(text);
X	right = ip_high(text);
X	if (decrypting) {
X		key_offset = 16 - 8;
X		key = key + 128 - 8;
X	} else
X		key_offset = 0 - 8;
X	for (i = 0; i < 16; i++) {
X		temp = (right << 1) | ((right >> 31) & 1);
X		left ^= s0p[(temp         & 0x3f) ^ key[0]]
X		      ^ s1p[((temp >>  4) & 0x3f) ^ key[1]]
X		      ^ s2p[((temp >>  8) & 0x3f) ^ key[2]]
X		      ^ s3p[((temp >> 12) & 0x3f) ^ key[3]]
X		      ^ s4p[((temp >> 16) & 0x3f) ^ key[4]]
X		      ^ s5p[((temp >> 20) & 0x3f) ^ key[5]]
X		      ^ s6p[((temp >> 24) & 0x3f) ^ key[6]];
X		temp = ((right & 1) << 5) | ((right >> 27) & 0x1f);
X		left ^= s7p[temp ^ key[7]];
X		temp = left;
X		left = right;
X		right = temp;
X		key -= key_offset;
X	}
X	temp = left;
X	left = right;
X	right = temp;
X	/*
X	 *	standard final permutation (IPI)
X	 */
X	fp(left, right, text);
}
X
/*
X *	Final Permutation
X */
static long	fph0[16] = {
0x00000000,0x40000000,0x00400000,0x40400000,0x00004000,0x40004000,0x00404000,0x40404000,
0x00000040,0x40000040,0x00400040,0x40400040,0x00004040,0x40004040,0x00404040,0x40404040,
};
static long	fpl1[16] = {
0x00000000,0x40000000,0x00400000,0x40400000,0x00004000,0x40004000,0x00404000,0x40404000,
0x00000040,0x40000040,0x00400040,0x40400040,0x00004040,0x40004040,0x00404040,0x40404040,
};
static long	fph2[16] = {
0x00000000,0x10000000,0x00100000,0x10100000,0x00001000,0x10001000,0x00101000,0x10101000,
0x00000010,0x10000010,0x00100010,0x10100010,0x00001010,0x10001010,0x00101010,0x10101010,
};
static long	fpl3[16] = {
0x00000000,0x10000000,0x00100000,0x10100000,0x00001000,0x10001000,0x00101000,0x10101000,
0x00000010,0x10000010,0x00100010,0x10100010,0x00001010,0x10001010,0x00101010,0x10101010,
};
static long	fph4[16] = {
0x00000000,0x04000000,0x00040000,0x04040000,0x00000400,0x04000400,0x00040400,0x04040400,
0x00000004,0x04000004,0x00040004,0x04040004,0x00000404,0x04000404,0x00040404,0x04040404,
};
static long	fpl5[16] = {
0x00000000,0x04000000,0x00040000,0x04040000,0x00000400,0x04000400,0x00040400,0x04040400,
0x00000004,0x04000004,0x00040004,0x04040004,0x00000404,0x04000404,0x00040404,0x04040404,
};
static long	fph6[16] = {
0x00000000,0x01000000,0x00010000,0x01010000,0x00000100,0x01000100,0x00010100,0x01010100,
0x00000001,0x01000001,0x00010001,0x01010001,0x00000101,0x01000101,0x00010101,0x01010101,
};
static long	fpl7[16] = {
0x00000000,0x01000000,0x00010000,0x01010000,0x00000100,0x01000100,0x00010100,0x01010100,
0x00000001,0x01000001,0x00010001,0x01010001,0x00000101,0x01000101,0x00010101,0x01010101,
};
static long	fph8[16] = {
0x00000000,0x80000000,0x00800000,0x80800000,0x00008000,0x80008000,0x00808000,0x80808000,
0x00000080,0x80000080,0x00800080,0x80800080,0x00008080,0x80008080,0x00808080,0x80808080,
};
static long	fpl9[16] = {
0x00000000,0x80000000,0x00800000,0x80800000,0x00008000,0x80008000,0x00808000,0x80808000,
0x00000080,0x80000080,0x00800080,0x80800080,0x00008080,0x80008080,0x00808080,0x80808080,
};
static long	fpha[16] = {
0x00000000,0x20000000,0x00200000,0x20200000,0x00002000,0x20002000,0x00202000,0x20202000,
0x00000020,0x20000020,0x00200020,0x20200020,0x00002020,0x20002020,0x00202020,0x20202020,
};
static long	fplb[16] = {
0x00000000,0x20000000,0x00200000,0x20200000,0x00002000,0x20002000,0x00202000,0x20202000,
0x00000020,0x20000020,0x00200020,0x20200020,0x00002020,0x20002020,0x00202020,0x20202020,
};
static long	fphc[16] = {
0x00000000,0x08000000,0x00080000,0x08080000,0x00000800,0x08000800,0x00080800,0x08080800,
0x00000008,0x08000008,0x00080008,0x08080008,0x00000808,0x08000808,0x00080808,0x08080808,
};
static long	fpld[16] = {
0x00000000,0x08000000,0x00080000,0x08080000,0x00000800,0x08000800,0x00080800,0x08080800,
0x00000008,0x08000008,0x00080008,0x08080008,0x00000808,0x08000808,0x00080808,0x08080808,
};
static long	fphe[16] = {
0x00000000,0x02000000,0x00020000,0x02020000,0x00000200,0x02000200,0x00020200,0x02020200,
0x00000002,0x02000002,0x00020002,0x02020002,0x00000202,0x02000202,0x00020202,0x02020202,
};
static long	fplf[16] = {
0x00000000,0x02000000,0x00020000,0x02020000,0x00000200,0x02000200,0x00020200,0x02020200,
0x00000002,0x02000002,0x00020002,0x02020002,0x00000202,0x02000202,0x00020202,0x02020202,
};
X
static void
fp(left, right, text)
long left, right;
char text[8];
{
X	register unsigned long low, high;
X	register unsigned long temp;
X
X	temp = left;
X	high = fph0[temp & 0xf];
X	temp >>= 4;
X	low  = fpl1[temp & 0xf];
X	temp >>= 4;
X	high |= fph2[temp & 0xf];
X	temp >>= 4;
X	low  |= fpl3[temp & 0xf];
X	temp >>= 4;
X	high |= fph4[temp & 0xf];
X	temp >>= 4;
X	low  |= fpl5[temp & 0xf];
X	temp >>= 4;
X	high |= fph6[temp & 0xf];
X	temp >>= 4;
X	low  |= fpl7[temp & 0xf];
X	temp = right;
X	high |= fph8[temp & 0xf];
X	temp >>= 4;
X	low  |= fpl9[temp & 0xf];
X	temp >>= 4;
X	high |= fpha[temp & 0xf];
X	temp >>= 4;
X	low  |= fplb[temp & 0xf];
X	temp >>= 4;
X	high |= fphc[temp & 0xf];
X	temp >>= 4;
X	low  |= fpld[temp & 0xf];
X	temp >>= 4;
X	high |= fphe[temp & 0xf];
X	temp >>= 4;
X	low  |= fplf[temp & 0xf];
X	text[0] = low;
X	text[1] = low >> 8;
X	text[2] = low >> 16;
X	text[3] = low >> 24;
X	text[4] = high;
X	text[5] = high >> 8;
X	text[6] = high >> 16;
X	text[7] = high >> 24;
}
X
/*
X *	Initial Permutation
X */
static long	ipl0[16] = {
0x00000000,
0x00008000,0x00000000,0x00008000,0x00000080,0x00008080,0x00000080,0x00008080,0x00000000,
0x00008000,0x00000000,0x00008000,0x00000080,0x00008080,0x00000080,0x00008080,};
static long	iph0[16] = {
0x00000000,
0x00000000,0x00008000,0x00008000,0x00000000,0x00000000,0x00008000,0x00008000,0x00000080,
0x00000080,0x00008080,0x00008080,0x00000080,0x00000080,0x00008080,0x00008080,};
static long	ipl1[16] = {
0x00000000,
0x80000000,0x00000000,0x80000000,0x00800000,0x80800000,0x00800000,0x80800000,0x00000000,
0x80000000,0x00000000,0x80000000,0x00800000,0x80800000,0x00800000,0x80800000,};
static long	iph1[16] = {
0x00000000,
0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x80000000,0x80000000,0x00800000,
0x00800000,0x80800000,0x80800000,0x00800000,0x00800000,0x80800000,0x80800000,};
static long	ipl2[16] = {
0x00000000,
0x00004000,0x00000000,0x00004000,0x00000040,0x00004040,0x00000040,0x00004040,0x00000000,
0x00004000,0x00000000,0x00004000,0x00000040,0x00004040,0x00000040,0x00004040,};
static long	iph2[16] = {
0x00000000,
0x00000000,0x00004000,0x00004000,0x00000000,0x00000000,0x00004000,0x00004000,0x00000040,
0x00000040,0x00004040,0x00004040,0x00000040,0x00000040,0x00004040,0x00004040,};
static long	ipl3[16] = {
0x00000000,
0x40000000,0x00000000,0x40000000,0x00400000,0x40400000,0x00400000,0x40400000,0x00000000,
0x40000000,0x00000000,0x40000000,0x00400000,0x40400000,0x00400000,0x40400000,};
static long	iph3[16] = {
0x00000000,
0x00000000,0x40000000,0x40000000,0x00000000,0x00000000,0x40000000,0x40000000,0x00400000,
0x00400000,0x40400000,0x40400000,0x00400000,0x00400000,0x40400000,0x40400000,};
static long	ipl4[16] = {
0x00000000,
0x00002000,0x00000000,0x00002000,0x00000020,0x00002020,0x00000020,0x00002020,0x00000000,
0x00002000,0x00000000,0x00002000,0x00000020,0x00002020,0x00000020,0x00002020,};
static long	iph4[16] = {
0x00000000,
0x00000000,0x00002000,0x00002000,0x00000000,0x00000000,0x00002000,0x00002000,0x00000020,
0x00000020,0x00002020,0x00002020,0x00000020,0x00000020,0x00002020,0x00002020,};
static long	ipl5[16] = {
0x00000000,
0x20000000,0x00000000,0x20000000,0x00200000,0x20200000,0x00200000,0x20200000,0x00000000,
0x20000000,0x00000000,0x20000000,0x00200000,0x20200000,0x00200000,0x20200000,};
static long	iph5[16] = {
0x00000000,
0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x20000000,0x20000000,0x00200000,
0x00200000,0x20200000,0x20200000,0x00200000,0x00200000,0x20200000,0x20200000,};
static long	ipl6[16] = {
0x00000000,
0x00001000,0x00000000,0x00001000,0x00000010,0x00001010,0x00000010,0x00001010,0x00000000,
0x00001000,0x00000000,0x00001000,0x00000010,0x00001010,0x00000010,0x00001010,};
static long	iph6[16] = {
0x00000000,
0x00000000,0x00001000,0x00001000,0x00000000,0x00000000,0x00001000,0x00001000,0x00000010,
0x00000010,0x00001010,0x00001010,0x00000010,0x00000010,0x00001010,0x00001010,};
static long	ipl7[16] = {
0x00000000,
0x10000000,0x00000000,0x10000000,0x00100000,0x10100000,0x00100000,0x10100000,0x00000000,
0x10000000,0x00000000,0x10000000,0x00100000,0x10100000,0x00100000,0x10100000,};
static long	iph7[16] = {
0x00000000,
0x00000000,0x10000000,0x10000000,0x00000000,0x00000000,0x10000000,0x10000000,0x00100000,
0x00100000,0x10100000,0x10100000,0x00100000,0x00100000,0x10100000,0x10100000,};
static long	ipl8[16] = {
0x00000000,
0x00000800,0x00000000,0x00000800,0x00000008,0x00000808,0x00000008,0x00000808,0x00000000,
0x00000800,0x00000000,0x00000800,0x00000008,0x00000808,0x00000008,0x00000808,};
static long	iph8[16] = {
0x00000000,
0x00000000,0x00000800,0x00000800,0x00000000,0x00000000,0x00000800,0x00000800,0x00000008,
0x00000008,0x00000808,0x00000808,0x00000008,0x00000008,0x00000808,0x00000808,};
static long	ipl9[16] = {
0x00000000,
0x08000000,0x00000000,0x08000000,0x00080000,0x08080000,0x00080000,0x08080000,0x00000000,
0x08000000,0x00000000,0x08000000,0x00080000,0x08080000,0x00080000,0x08080000,};
static long	iph9[16] = {
0x00000000,
0x00000000,0x08000000,0x08000000,0x00000000,0x00000000,0x08000000,0x08000000,0x00080000,
0x00080000,0x08080000,0x08080000,0x00080000,0x00080000,0x08080000,0x08080000,};
static long	ipla[16] = {
0x00000000,
0x00000400,0x00000000,0x00000400,0x00000004,0x00000404,0x00000004,0x00000404,0x00000000,
0x00000400,0x00000000,0x00000400,0x00000004,0x00000404,0x00000004,0x00000404,};
static long	ipha[16] = {
0x00000000,
0x00000000,0x00000400,0x00000400,0x00000000,0x00000000,0x00000400,0x00000400,0x00000004,
0x00000004,0x00000404,0x00000404,0x00000004,0x00000004,0x00000404,0x00000404,};
static long	iplb[16] = {
0x00000000,
0x04000000,0x00000000,0x04000000,0x00040000,0x04040000,0x00040000,0x04040000,0x00000000,
0x04000000,0x00000000,0x04000000,0x00040000,0x04040000,0x00040000,0x04040000,};
static long	iphb[16] = {
0x00000000,
0x00000000,0x04000000,0x04000000,0x00000000,0x00000000,0x04000000,0x04000000,0x00040000,
0x00040000,0x04040000,0x04040000,0x00040000,0x00040000,0x04040000,0x04040000,};
static long	iplc[16] = {
0x00000000,
0x00000200,0x00000000,0x00000200,0x00000002,0x00000202,0x00000002,0x00000202,0x00000000,
0x00000200,0x00000000,0x00000200,0x00000002,0x00000202,0x00000002,0x00000202,};
static long	iphc[16] = {
0x00000000,
0x00000000,0x00000200,0x00000200,0x00000000,0x00000000,0x00000200,0x00000200,0x00000002,
0x00000002,0x00000202,0x00000202,0x00000002,0x00000002,0x00000202,0x00000202,};
static long	ipld[16] = {
0x00000000,
0x02000000,0x00000000,0x02000000,0x00020000,0x02020000,0x00020000,0x02020000,0x00000000,
0x02000000,0x00000000,0x02000000,0x00020000,0x02020000,0x00020000,0x02020000,};
static long	iphd[16] = {
0x00000000,
0x00000000,0x02000000,0x02000000,0x00000000,0x00000000,0x02000000,0x02000000,0x00020000,
0x00020000,0x02020000,0x02020000,0x00020000,0x00020000,0x02020000,0x02020000,};
static long	iple[16] = {
0x00000000,
0x00000100,0x00000000,0x00000100,0x00000001,0x00000101,0x00000001,0x00000101,0x00000000,
0x00000100,0x00000000,0x00000100,0x00000001,0x00000101,0x00000001,0x00000101,};
static long	iphe[16] = {
0x00000000,
0x00000000,0x00000100,0x00000100,0x00000000,0x00000000,0x00000100,0x00000100,0x00000001,
0x00000001,0x00000101,0x00000101,0x00000001,0x00000001,0x00000101,0x00000101,};
static long	iplf[16] = {
0x00000000,
0x01000000,0x00000000,0x01000000,0x00010000,0x01010000,0x00010000,0x01010000,0x00000000,
0x01000000,0x00000000,0x01000000,0x00010000,0x01010000,0x00010000,0x01010000,};
static long	iphf[16] = {
0x00000000,
0x00000000,0x01000000,0x01000000,0x00000000,0x00000000,0x01000000,0x01000000,0x00010000,
0x00010000,0x01010000,0x01010000,0x00010000,0x00010000,0x01010000,0x01010000,};
X
static long
ip_low(block)
register char block[8];
{
X	register long l;
X
X	l  = ipl1[block[0] & 0xf];
X	l |= ipl0[(block[0] >> 4) & 0xf];
X	l |= ipl3[block[1] & 0xf];
X	l |= ipl2[(block[1] >> 4) & 0xf];
X	l |= ipl5[block[2] & 0xf];
X	l |= ipl4[(block[2] >> 4) & 0xf];
X	l |= ipl7[block[3] & 0xf];
X	l |= ipl6[(block[3] >> 4) & 0xf];
X	l |= ipl9[block[4] & 0xf];
X	l |= ipl8[(block[4] >> 4) & 0xf];
X	l |= iplb[block[5] & 0xf];
X	l |= ipla[(block[5] >> 4) & 0xf];
X	l |= ipld[block[6] & 0xf];
X	l |= iplc[(block[6] >> 4) & 0xf];
X	l |= iplf[block[7] & 0xf];
X	l |= iple[(block[7] >> 4) & 0xf];
X	return l;
}
X
static long
ip_high(block)
register char block[8];
{
X	register long l;
X
X	l  = iph1[block[0] & 0xf];
X	l |= iph0[(block[0] >> 4) & 0xf];
X	l |= iph3[block[1] & 0xf];
X	l |= iph2[(block[1] >> 4) & 0xf];
X	l |= iph5[block[2] & 0xf];
X	l |= iph4[(block[2] >> 4) & 0xf];
X	l |= iph7[block[3] & 0xf];
X	l |= iph6[(block[3] >> 4) & 0xf];
X	l |= iph9[block[4] & 0xf];
X	l |= iph8[(block[4] >> 4) & 0xf];
X	l |= iphb[block[5] & 0xf];
X	l |= ipha[(block[5] >> 4) & 0xf];
X	l |= iphd[block[6] & 0xf];
X	l |= iphc[(block[6] >> 4) & 0xf];
X	l |= iphf[block[7] & 0xf];
X	l |= iphe[(block[7] >> 4) & 0xf];
X	return l;
}
X
/*
X *	Key set-up
X */
X
void
des_key_setup(key, subkeys)
char key[8];
char *subkeys;
{
X	register octet;
X	register char *kp;
X
X	kp = subkeys;
X	octet = 16;
X	do {
X		*kp++ = 0;	*kp++ = 0;
X		*kp++ = 0;	*kp++ = 0;
X		*kp++ = 0;	*kp++ = 0;
X		*kp++ = 0;	*kp++ = 0;
X	} while (--octet);
X	kp = subkeys;
X	octet = key[0];
X	if (octet & 0x80) {
X		kp[  3] |=  2; kp[  9] |=  8; kp[ 18] |=  8; 
X		kp[ 27] |= 32; kp[ 33] |=  2; kp[ 42] |= 16; 
X		kp[ 48] |=  8; kp[ 65] |= 16; kp[ 74] |=  2; 
X		kp[ 80] |=  2; kp[ 89] |=  4; kp[ 99] |= 16; 
X		kp[104] |=  4; kp[122] |= 32; 
X	}
X	if (octet & 0x40) {
X		kp[  1] |=  4; kp[  8] |=  1; kp[ 18] |=  4; 
X		kp[ 25] |= 32; kp[ 34] |= 32; kp[ 41] |=  8; 
X		kp[ 50] |=  8; kp[ 59] |= 32; kp[ 64] |= 16; 
X		kp[ 75] |=  4; kp[ 90] |=  1; kp[ 97] |= 16; 
X		kp[106] |=  2; kp[112] |=  2; kp[123] |=  1; 
X	}
X	if (octet & 0x20) {
X		kp[  2] |=  1; kp[ 19] |=  8; kp[ 35] |=  1; 
X		kp[ 40] |=  1; kp[ 50] |=  4; kp[ 57] |= 32; 
X		kp[ 75] |=  2; kp[ 80] |= 32; kp[ 89] |=  1; 
X		kp[ 96] |= 16; kp[107] |=  4; kp[120] |=  8; 
X	}
X	if (octet & 0x10) {
X		kp[  4] |= 32; kp[ 20] |=  2; kp[ 31] |=  4; 
X		kp[ 37] |= 32; kp[ 47] |=  1; kp[ 54] |=  1; 
X		kp[ 63] |=  2; kp[ 68] |=  1; kp[ 78] |=  4; 
X		kp[ 84] |=  8; kp[101] |= 16; kp[108] |=  4; 
X		kp[119] |= 16; kp[126] |=  8; 
X	}
X	if (octet & 0x8) {
X		kp[  5] |=  4; kp[ 15] |=  4; kp[ 21] |= 32; 
X		kp[ 31] |=  1; kp[ 38] |=  1; kp[ 47] |=  2; 
X		kp[ 53] |=  2; kp[ 68] |=  8; kp[ 85] |= 16; 
X		kp[ 92] |=  4; kp[103] |= 16; kp[108] |= 32; 
X		kp[118] |= 32; kp[124] |=  2; 
X	}
X	if (octet & 0x4) {
X		kp[ 15] |=  2; kp[ 21] |=  2; kp[ 39] |=  8; 
X		kp[ 46] |= 16; kp[ 55] |= 32; kp[ 61] |=  1; 
X		kp[ 71] |= 16; kp[ 76] |= 32; kp[ 86] |= 32; 
X		kp[ 93] |=  4; kp[102] |=  2; kp[108] |= 16; 
X		kp[117] |=  8; kp[126] |=  1; 
X	}
X	if (octet & 0x2) {
X		kp[ 14] |= 16; kp[ 23] |= 32; kp[ 29] |=  1; 
X		kp[ 38] |=  8; kp[ 52] |=  2; kp[ 63] |=  4; 
X		kp[ 70] |=  2; kp[ 76] |= 16; kp[ 85] |=  8; 
X		kp[100] |=  1; kp[110] |=  4; kp[116] |=  8; 
X		kp[127] |=  8; 
X	}
X	octet = key[1];
X	if (octet & 0x80) {
X		kp[  1] |=  8; kp[  8] |= 32; kp[ 17] |=  1; 
X		kp[ 24] |= 16; kp[ 35] |=  4; kp[ 50] |=  1; 
X		kp[ 57] |= 16; kp[ 67] |=  8; kp[ 83] |=  1; 
X		kp[ 88] |=  1; kp[ 98] |=  4; kp[105] |= 32; 
X		kp[114] |= 32; kp[123] |=  2; 
X	}
X	if (octet & 0x40) {
X		kp[  0] |=  1; kp[ 11] |= 16; kp[ 16] |=  4; 
X		kp[ 35] |=  2; kp[ 40] |= 32; kp[ 49] |=  1; 
X		kp[ 56] |= 16; kp[ 65] |=  2; kp[ 74] |= 16; 
X		kp[ 80] |=  8; kp[ 99] |=  8; kp[115] |=  1; 
X		kp[121] |=  4; 
X	}
X	if (octet & 0x20) {
X		kp[  9] |= 16; kp[ 18] |=  2; kp[ 24] |=  2; 
X		kp[ 33] |=  4; kp[ 43] |= 16; kp[ 48] |=  4; 
X		kp[ 66] |= 32; kp[ 73] |=  8; kp[ 82] |=  8; 
X		kp[ 91] |= 32; kp[ 97] |=  2; kp[106] |= 16; 
X		kp[112] |=  8; kp[122] |=  1; 
X	}
X	if (octet & 0x10) {
X		kp[ 14] |= 32; kp[ 21] |=  4; kp[ 30] |=  2; 
X		kp[ 36] |= 16; kp[ 45] |=  8; kp[ 60] |=  1; 
X		kp[ 69] |=  2; kp[ 87] |=  8; kp[ 94] |= 16; 
X		kp[103] |= 32; kp[109] |=  1; kp[118] |=  8; 
X		kp[124] |= 32; 
X	}
X	if (octet & 0x8) {
X		kp[  7] |=  4; kp[ 14] |=  2; kp[ 20] |= 16; 
X		kp[ 29] |=  8; kp[ 44] |=  1; kp[ 54] |=  4; 
X		kp[ 60] |=  8; kp[ 71] |=  8; kp[ 78] |= 16; 
X		kp[ 87] |= 32; kp[ 93] |=  1; kp[102] |=  8; 
X		kp[116] |=  2; kp[125] |=  4; 
X	}
X	if (octet & 0x4) {
X		kp[  7] |=  2; kp[ 12] |=  1; kp[ 22] |=  4; 
X		kp[ 28] |=  8; kp[ 45] |= 16; kp[ 52] |=  4; 
X		kp[ 63] |= 16; kp[ 70] |=  8; kp[ 84] |=  2; 
X		kp[ 95] |=  4; kp[101] |= 32; kp[111] |=  1; 
X		kp[118] |=  1; 
X	}
X	if (octet & 0x2) {
X		kp[  6] |= 16; kp[ 13] |= 16; kp[ 20] |=  4; 
X		kp[ 31] |= 16; kp[ 36] |= 32; kp[ 46] |= 32; 
X		kp[ 53] |=  4; kp[ 62] |=  2; kp[ 69] |= 32; 
X		kp[ 79] |=  1; kp[ 86] |=  1; kp[ 95] |=  2; 
X		kp[101] |=  2; kp[119] |=  8; 
X	}
X	octet = key[2];
X	if (octet & 0x80) {
X		kp[  0] |= 32; kp[ 10] |=  8; kp[ 19] |= 32; 
X		kp[ 25] |=  2; kp[ 34] |= 16; kp[ 40] |=  8; 
X		kp[ 59] |=  8; kp[ 66] |=  2; kp[ 72] |=  2; 
X		kp[ 81] |=  4; kp[ 91] |= 16; kp[ 96] |=  4; 
X		kp[115] |=  2; kp[121] |=  8; 
X	}
X	if (octet & 0x40) {
X		kp[  3] |= 16; kp[ 10] |=  4; kp[ 17] |= 32; 
X		kp[ 26] |= 32; kp[ 33] |=  8; kp[ 42] |=  8; 
X		kp[ 51] |= 32; kp[ 57] |=  2; kp[ 67] |=  4; 
X		kp[ 82] |=  1; kp[ 89] |= 16; kp[ 98] |=  2; 
X		kp[104] |=  2; kp[113] |=  4; kp[120] |=  1; 
X	}
X	if (octet & 0x20) {
X		kp[  1] |= 16; kp[ 11] |=  8; kp[ 27] |=  1; 
X		kp[ 32] |=  1; kp[ 42] |=  4; kp[ 49] |= 32; 
X		kp[ 58] |= 32; kp[ 67] |=  2; kp[ 72] |= 32; 
X		kp[ 81] |=  1; kp[ 88] |= 16; kp[ 99] |=  4; 
X		kp[114] |=  1; 
X	}
X	if (octet & 0x10) {
X		kp[  6] |= 32; kp[ 12] |=  2; kp[ 23] |=  4; 
X		kp[ 29] |= 32; kp[ 39] |=  1; kp[ 46] |=  1; 
X		kp[ 55] |=  2; kp[ 61] |=  2; kp[ 70] |=  4; 
X		kp[ 76] |=  8; kp[ 93] |= 16; kp[100] |=  4; 
X		kp[111] |= 16; kp[116] |= 32; 
X	}
X	if (octet & 0x8) {
X		kp[  6] |=  2; kp[ 13] |= 32; kp[ 23] |=  1; 
X		kp[ 30] |=  1; kp[ 39] |=  2; kp[ 45] |=  2; 
X		kp[ 63] |=  8; kp[ 77] |= 16; kp[ 84] |=  4; 
X		kp[ 95] |= 16; kp[100] |= 32; kp[110] |= 32; 
X		kp[117] |=  4; kp[127] |=  4; 
X	}
X	if (octet & 0x4) {
X		kp[  4] |=  1; kp[ 13] |=  2; kp[ 31] |=  8; 
X		kp[ 38] |= 16; kp[ 47] |= 32; kp[ 53] |=  1; 
X		kp[ 62] |=  8; kp[ 68] |= 32; kp[ 78] |= 32; 
X		kp[ 85] |=  4; kp[ 94] |=  2; kp[100] |= 16; 
X		kp[109] |=  8; kp[127] |=  2; 
X	}
X	if (octet & 0x2) {
X		kp[  5] |= 16; kp[ 15] |= 32; kp[ 21] |=  1; 
X		kp[ 30] |=  8; kp[ 44] |=  2; kp[ 55] |=  4; 
X		kp[ 61] |= 32; kp[ 68] |= 16; kp[ 77] |=  8; 
X		kp[ 92] |=  1; kp[102] |=  4; kp[108] |=  8; 
X		kp[126] |= 16; 
X	}
X	octet = key[3];
X	if (octet & 0x80) {
X		kp[  2] |=  8; kp[  9] |=  1; kp[ 16] |= 16; 
X		kp[ 27] |=  4; kp[ 42] |=  1; kp[ 49] |= 16; 
X		kp[ 58] |=  2; kp[ 75] |=  1; kp[ 80] |=  1; 
X		kp[ 90] |=  4; kp[ 97] |= 32; kp[106] |= 32; 
X		kp[113] |=  8; kp[120] |= 32; 
X	}
X	if (octet & 0x40) {
X		kp[  2] |=  4; kp[  8] |=  4; kp[ 27] |=  2; 
X		kp[ 32] |= 32; kp[ 41] |=  1; kp[ 48] |= 16; 
X		kp[ 59] |=  4; kp[ 66] |= 16; kp[ 72] |=  8; 
X		kp[ 91] |=  8; kp[107] |=  1; kp[112] |=  1; 
X		kp[123] |= 16; 
X	}
X	if (octet & 0x20) {
X		kp[  3] |=  8; kp[ 10] |=  2; kp[ 16] |=  2; 
X		kp[ 25] |=  4; kp[ 35] |= 16; kp[ 40] |=  4; 
X		kp[ 59] |=  2; kp[ 65] |=  8; kp[ 74] |=  8; 
X		kp[ 83] |= 32; kp[ 89] |=  2; kp[ 98] |= 16; 
X		kp[104] |=  8; kp[121] |= 16; 
X	}
X	if (octet & 0x10) {
X		kp[  4] |=  2; kp[ 13] |=  4; kp[ 22] |=  2; 
X		kp[ 28] |= 16; kp[ 37] |=  8; kp[ 52] |=  1; 
X		kp[ 62] |=  4; kp[ 79] |=  8; kp[ 86] |= 16; 
X		kp[ 95] |= 32; kp[101] |=  1; kp[110] |=  8; 
X		kp[126] |= 32; 
X	}
X	if (octet & 0x8) {
X		kp[  5] |= 32; kp[ 12] |= 16; kp[ 21] |=  8; 
X		kp[ 36] |=  1; kp[ 46] |=  4; kp[ 52] |=  8; 
X		kp[ 70] |= 16; kp[ 79] |= 32; kp[ 85] |=  1; 
X		kp[ 94] |=  8; kp[108] |=  2; kp[119] |=  4; 
X		kp[126] |=  2; 
X	}
X	if (octet & 0x4) {
X		kp[  5] |=  2; kp[ 14] |=  4; kp[ 20] |=  8; 
X		kp[ 37] |= 16; kp[ 44] |=  4; kp[ 55] |= 16; 
X		kp[ 60] |= 32; kp[ 76] |=  2; kp[ 87] |=  4; 
X		kp[ 93] |= 32; kp[103] |=  1; kp[110] |=  1; 
X		kp[119] |=  2; kp[124] |=  1; 
X	}
X	if (octet & 0x2) {
X		kp[  7] |= 32; kp[ 12] |=  4; kp[ 23] |= 16; 
X		kp[ 28] |= 32; kp[ 38] |= 32; kp[ 45] |=  4; 
X		kp[ 54] |=  2; kp[ 60] |= 16; kp[ 71] |=  1; 
X		kp[ 78] |=  1; kp[ 87] |=  2; kp[ 93] |=  2; 
X		kp[111] |=  8; kp[118] |= 16; kp[125] |= 16; 
X	}
X	octet = key[4];
X	if (octet & 0x80) {
X		kp[  1] |=  1; kp[ 11] |= 32; kp[ 17] |=  2; 
X		kp[ 26] |= 16; kp[ 32] |=  8; kp[ 51] |=  8; 
X		kp[ 64] |=  2; kp[ 73] |=  4; kp[ 83] |= 16; 
X		kp[ 88] |=  4; kp[107] |=  2; kp[112] |= 32; 
X		kp[122] |=  8; 
X	}
X	if (octet & 0x40) {
X		kp[  0] |=  4; kp[  9] |= 32; kp[ 18] |= 32; 
X		kp[ 25] |=  8; kp[ 34] |=  8; kp[ 43] |= 32; 
X		kp[ 49] |=  2; kp[ 58] |= 16; kp[ 74] |=  1; 
X		kp[ 81] |= 16; kp[ 90] |=  2; kp[ 96] |=  2; 
X		kp[105] |=  4; kp[115] |= 16; kp[122] |=  4; 
X	}
X	if (octet & 0x20) {
X		kp[  2] |=  2; kp[ 19] |=  1; kp[ 24] |=  1; 
X		kp[ 34] |=  4; kp[ 41] |= 32; kp[ 50] |= 32; 
X		kp[ 57] |=  8; kp[ 64] |= 32; kp[ 73] |=  1; 
X		kp[ 80] |= 16; kp[ 91] |=  4; kp[106] |=  1; 
X		kp[113] |= 16; kp[123] |=  8; 
X	}
X	if (octet & 0x10) {
X		kp[  3] |=  4; kp[ 10] |= 16; kp[ 16] |=  8; 
X		kp[ 35] |=  8; kp[ 51] |=  1; kp[ 56] |=  1; 
X		kp[ 67] |= 16; kp[ 72] |=  4; kp[ 91] |=  2; 
X		kp[ 96] |= 32; kp[105] |=  1; kp[112] |= 16; 
X		kp[121] |=  2; 
X	}
X	if (octet & 0x8) {
X		kp[  4] |= 16; kp[ 15] |=  1; kp[ 22] |=  1; 
X		kp[ 31] |=  2; kp[ 37] |=  2; kp[ 55] |=  8; 
X		kp[ 62] |= 16; kp[ 69] |= 16; kp[ 76] |=  4; 
X		kp[ 87] |= 16; kp[ 92] |= 32; kp[102] |= 32; 
X		kp[109] |=  4; kp[118] |=  2; kp[125] |= 32; 
X	}
X	if (octet & 0x4) {
X		kp[  6] |=  4; kp[ 23] |=  8; kp[ 30] |= 16; 
X		kp[ 39] |= 32; kp[ 45] |=  1; kp[ 54] |=  8; 
X		kp[ 70] |= 32; kp[ 77] |=  4; kp[ 86] |=  2; 
X		kp[ 92] |= 16; kp[101] |=  8; kp[116] |=  1; 
X		kp[125] |=  2; 
X	}
X	if (octet & 0x2) {
X		kp[  4] |=  4; kp[ 13] |=  1; kp[ 22] |=  8; 
X		kp[ 36] |=  2; kp[ 47] |=  4; kp[ 53] |= 32; 
X		kp[ 63] |=  1; kp[ 69] |=  8; kp[ 84] |=  1; 
X		kp[ 94] |=  4; kp[100] |=  8; kp[117] |= 16; 
X		kp[127] |= 32; 
X	}
X	octet = key[5];
X	if (octet & 0x80) {
X		kp[  3] |= 32; kp[  8] |= 16; kp[ 19] |=  4; 
X		kp[ 34] |=  1; kp[ 41] |= 16; kp[ 50] |=  2; 
X		kp[ 56] |=  2; kp[ 67] |=  1; kp[ 72] |=  1; 
X		kp[ 82] |=  4; kp[ 89] |= 32; kp[ 98] |= 32; 
X		kp[105] |=  8; kp[114] |=  8; kp[121] |=  1; 
X	}
X	if (octet & 0x40) {
X		kp[  1] |= 32; kp[ 19] |=  2; kp[ 24] |= 32; 
X		kp[ 33] |=  1; kp[ 40] |= 16; kp[ 51] |=  4; 
X		kp[ 64] |=  8; kp[ 83] |=  8; kp[ 99] |=  1; 
X		kp[104] |=  1; kp[114] |=  4; kp[120] |=  4; 
X	}
X	if (octet & 0x20) {
X		kp[  8] |=  2; kp[ 17] |=  4; kp[ 27] |= 16; 
X		kp[ 32] |=  4; kp[ 51] |=  2; kp[ 56] |= 32; 
X		kp[ 66] |=  8; kp[ 75] |= 32; kp[ 81] |=  2; 
X		kp[ 90] |= 16; kp[ 96] |=  8; kp[115] |=  8; 
X		kp[122] |=  2; 
X	}
X	if (octet & 0x10) {
X		kp[  2] |= 16; kp[ 18] |=  1; kp[ 25] |= 16; 
X		kp[ 34] |=  2; kp[ 40] |=  2; kp[ 49] |=  4; 
X		kp[ 59] |= 16; kp[ 66] |=  4; kp[ 73] |= 32; 
X		kp[ 82] |= 32; kp[ 89] |=  8; kp[ 98] |=  8; 
X		kp[107] |= 32; kp[113] |=  2; kp[123] |=  4; 
X	}
X	if (octet & 0x8) {
X		kp[  7] |=  1; kp[ 13] |=  8; kp[ 28] |=  1; 
X		kp[ 38] |=  4; kp[ 44] |=  8; kp[ 61] |= 16; 
X		kp[ 71] |= 32; kp[ 77] |=  1; kp[ 86] |=  8; 
X		kp[100] |=  2; kp[111] |=  4; kp[117] |= 32; 
X		kp[124] |= 16; 
X	}
X	if (octet & 0x4) {
X		kp[ 12] |=  8; kp[ 29] |= 16; kp[ 36] |=  4; 
X		kp[ 47] |= 16; kp[ 52] |= 32; kp[ 62] |= 32; 
X		kp[ 68] |=  2; kp[ 79] |=  4; kp[ 85] |= 32; 
X		kp[ 95] |=  1; kp[102] |=  1; kp[111] |=  2; 
X		kp[117] |=  2; kp[126] |=  4; 
X	}
X	if (octet & 0x2) {
X		kp[  5] |=  1; kp[ 15] |= 16; kp[ 20] |= 32; 
X		kp[ 30] |= 32; kp[ 37] |=  4; kp[ 46] |=  2; 
X		kp[ 52] |= 16; kp[ 61] |=  8; kp[ 70] |=  1; 
X		kp[ 79] |=  2; kp[ 85] |=  2; kp[103] |=  8; 
X		kp[110] |= 16; kp[119] |= 32; kp[124] |=  4; 
X	}
X	octet = key[6];
X	if (octet & 0x80) {
X		kp[  0] |= 16; kp[  9] |=  2; kp[ 18] |= 16; 
X		kp[ 24] |=  8; kp[ 43] |=  8; kp[ 59] |=  1; 
X		kp[ 65] |=  4; kp[ 75] |= 16; kp[ 80] |=  4; 
X		kp[ 99] |=  2; kp[104] |= 32; kp[113] |=  1; 
X		kp[123] |= 32; 
X	}
X	if (octet & 0x40) {
X		kp[ 10] |= 32; kp[ 17] |=  8; kp[ 26] |=  8; 
X		kp[ 35] |= 32; kp[ 41] |=  2; kp[ 50] |= 16; 
X		kp[ 56] |=  8; kp[ 66] |=  1; kp[ 73] |= 16; 
X		kp[ 82] |=  2; kp[ 88] |=  2; kp[ 97] |=  4; 
X		kp[107] |= 16; kp[112] |=  4; kp[121] |= 32; 
X	}
X	if (octet & 0x20) {
X		kp[  0] |=  2; kp[ 11] |=  1; kp[ 16] |=  1; 
X		kp[ 26] |=  4; kp[ 33] |= 32; kp[ 42] |= 32; 
X		kp[ 49] |=  8; kp[ 58] |=  8; kp[ 65] |=  1; 
X		kp[ 72] |= 16; kp[ 83] |=  4; kp[ 98] |=  1; 
X		kp[105] |= 16; kp[114] |=  2; 
X	}
X	if (octet & 0x10) {
X		kp[  8] |=  8; kp[ 27] |=  8; kp[ 43] |=  1; 
X		kp[ 48] |=  1; kp[ 58] |=  4; kp[ 64] |=  4; 
X		kp[ 83] |=  2; kp[ 88] |= 32; kp[ 97] |=  1; 
X		kp[104] |= 16; kp[115] |=  4; kp[122] |= 16; 
X	}
X	if (octet & 0x8) {
X		kp[  5] |=  8; kp[ 14] |=  1; kp[ 23] |=  2; 
X		kp[ 29] |=  2; kp[ 47] |=  8; kp[ 54] |= 16; 
X		kp[ 63] |= 32; kp[ 68] |=  4; kp[ 79] |= 16; 
X		kp[ 84] |= 32; kp[ 94] |= 32; kp[101] |=  4; 
X		kp[110] |=  2; kp[116] |= 16; kp[127] |=  1; 
X	}
X	if (octet & 0x4) {
X		kp[  4] |=  8; kp[ 15] |=  8; kp[ 22] |= 16; 
X		kp[ 31] |= 32; kp[ 37] |=  1; kp[ 46] |=  8; 
X		kp[ 60] |=  2; kp[ 69] |=  4; kp[ 78] |=  2; 
X		kp[ 84] |= 16; kp[ 93] |=  8; kp[108] |=  1; 
X		kp[118] |=  4; 
X	}
X	if (octet & 0x2) {
X		kp[  7] |= 16; kp[ 14] |=  8; kp[ 28] |=  2; 
X		kp[ 39] |=  4; kp[ 45] |= 32; kp[ 55] |=  1; 
X		kp[ 62] |=  1; kp[ 76] |=  1; kp[ 86] |=  4; 
X		kp[ 92] |=  8; kp[109] |= 16; kp[116] |=  4; 
X		kp[125] |=  1; 
X	}
X	octet = key[7];
X	if (octet & 0x80) {
X		kp[  1] |=  2; kp[ 11] |=  4; kp[ 26] |=  1; 
X		kp[ 33] |= 16; kp[ 42] |=  2; kp[ 48] |=  2; 
X		kp[ 57] |=  4; kp[ 64] |=  1; kp[ 74] |=  4; 
X		kp[ 81] |= 32; kp[ 90] |= 32; kp[ 97] |=  8; 
X		kp[106] |=  8; kp[115] |= 32; kp[120] |= 16; 
X	}
X	if (octet & 0x40) {
X		kp[  2] |= 32; kp[ 11] |=  2; kp[ 16] |= 32; 
X		kp[ 25] |=  1; kp[ 32] |= 16; kp[ 43] |=  4; 
X		kp[ 58] |=  1; kp[ 75] |=  8; kp[ 91] |=  1; 
X		kp[ 96] |=  1; kp[106] |=  4; kp[113] |= 32; 
X	}
X	if (octet & 0x20) {
X		kp[  3] |=  1; kp[  9] |=  4; kp[ 19] |= 16; 
X		kp[ 24] |=  4; kp[ 43] |=  2; kp[ 48] |= 32; 
X		kp[ 57] |=  1; kp[ 67] |= 32; kp[ 73] |=  2; 
X		kp[ 82] |= 16; kp[ 88] |=  8; kp[107] |=  8; 
X		kp[120] |=  2; 
X	}
X	if (octet & 0x10) {
X		kp[  0] |=  8; kp[ 10] |=  1; kp[ 17] |= 16; 
X		kp[ 26] |=  2; kp[ 32] |=  2; kp[ 41] |=  4; 
X		kp[ 51] |= 16; kp[ 56] |=  4; kp[ 65] |= 32; 
X		kp[ 74] |= 32; kp[ 81] |=  8; kp[ 90] |=  8; 
X		kp[ 99] |= 32; kp[105] |=  2; kp[114] |= 16; 
X	}
X	if (octet & 0x8) {
X		kp[  6] |=  1; kp[ 20] |=  1; kp[ 30] |=  4; 
X		kp[ 36] |=  8; kp[ 53] |= 16; kp[ 60] |=  4; 
X		kp[ 69] |=  1; kp[ 78] |=  8; kp[ 92] |=  2; 
X		kp[103] |=  4; kp[109] |= 32; kp[119] |=  1; 
X		kp[125] |=  8; 
X	}
X	if (octet & 0x4) {
X		kp[  7] |=  8; kp[ 21] |= 16; kp[ 28] |=  4; 
X		kp[ 39] |= 16; kp[ 44] |= 32; kp[ 54] |= 32; 
X		kp[ 61] |=  4; kp[ 71] |=  4; kp[ 77] |= 32; 
X		kp[ 87] |=  1; kp[ 94] |=  1; kp[103] |=  2; 
X		kp[109] |=  2; kp[124] |=  8; 
X	}
X	if (octet & 0x2) {
X		kp[  6] |=  8; kp[ 12] |= 32; kp[ 22] |= 32; 
X		kp[ 29] |=  4; kp[ 38] |=  2; kp[ 44] |= 16; 
X		kp[ 53] |=  8; kp[ 71] |=  2; kp[ 77] |=  2; 
X		kp[ 95] |=  8; kp[102] |= 16; kp[111] |= 32; 
X		kp[117] |=  1; kp[127] |= 16; 
X	}
}
X
void
key_crunch(buffer, size, key)
X  char buffer[], key[];
X  int size;
{
X    int i;
X    struct {long fo; char key[9];} s;
X
X    bcopy("encrypt!",s.key,8);
X
X    for (i = 0; i < 8; i++)
X        key[i] = 0;
X    for (i = 0; i < size; i++) {
X        key[(i & 7)] ^= buffer[i];
X        if ((i & 7) == 7)
X            q_block_cipher(s.key, key, 0);
X    }
X    q_block_cipher(s.key, key, 0);
}
X
X
SHAR_EOF
  $shar_touch -am 0722202295 'cfs_des.c' &&
  chmod 0644 'cfs_des.c' ||
  echo 'restore of cfs_des.c failed'
  shar_count="`wc -c < 'cfs_des.c'`"
  test 36708 -eq "$shar_count" ||
    echo "cfs_des.c: original size 36708, current size $shar_count"
fi
# ============= cfs_cipher.c ==============
if test -f 'cfs_cipher.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cfs_cipher.c (file already exists)'
else
  echo 'x - extracting cfs_cipher.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cfs_cipher.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
X
#include <stdio.h>
#include <rpc/rpc.h>
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
X
cipher(k,s,d)
X     cfskey *k;
X     unsigned char *s;
X     int d;
{
X	d=d&1;
X	switch (k->cipher) {
X	    case STD_DES:
X		des_block_cipher(k->var.des.primary,s,d);
X		break;
X	    case THREE_DES:
X		des_block_cipher(k->var.des3.primary1,s,d);
X		des_block_cipher(k->var.des3.primary2,s,1-d);
X		des_block_cipher(k->var.des3.primary1,s,d);
X		break;
X	    case MCG:
X		if (d)
X			mcg_block_decrypt(s,&k->var.mcg.primary);
X		else
X			mcg_block_encrypt(s,&k->var.mcg.primary);
X		break;
X	    default:	/* just does nothing */
X		break;
X	}
}
X
mask_cipher(k,s,d)
X     cfskey *k;
X     unsigned char *s;
X     int d;
{
X	d=d&1;
X	switch (k->cipher) {
X	    case STD_DES:
X		des_block_cipher(k->var.des.secondary,s,d);
X		break;
X	    case THREE_DES:
X		des_block_cipher(k->var.des3.secondary1,s,d);
X		des_block_cipher(k->var.des3.secondary2,s,1-d);
X		des_block_cipher(k->var.des3.secondary1,s,d);
X		break;
X	    case MCG:
X		if (d)
X			mcg_block_decrypt(s,&k->var.mcg.secondary);
X		else
X			mcg_block_encrypt(s,&k->var.mcg.secondary);
X		break;
X	    default:	/* just does nothing */
X		break;
X	}
}
X
X
X
copykey(key,k)
X     cfs_admkey *key;
X     cfskey *k;
{
X	switch (key->cipher) {
X	    case CFS_STD_DES:
X		k->cipher=STD_DES;
X		des_key_setup(key->cfs_admkey_u.deskey.primary,
X		      k->var.des.primary);
X		des_key_setup(key->cfs_admkey_u.deskey.secondary,
X		      k->var.des.secondary);
X		break;
X	    case CFS_THREE_DES:
X		k->cipher=THREE_DES;
X		des_key_setup(key->cfs_admkey_u.des3key.primary1,
X		      k->var.des3.primary1);
X		des_key_setup(key->cfs_admkey_u.des3key.primary2,
X		      k->var.des3.primary2);
X		des_key_setup(key->cfs_admkey_u.des3key.secondary1,
X		      k->var.des3.secondary1);
X		des_key_setup(key->cfs_admkey_u.des3key.secondary2,
X		      k->var.des3.secondary2);
X		break;
X	    case CFS_MACGUFFIN:
X		k->cipher=MCG;
X		mcg_keyset(key->cfs_admkey_u.mcgkey.primary,
X			   &k->var.mcg.primary);
X		mcg_keyset(key->cfs_admkey_u.mcgkey.secondary,
X			   &k->var.mcg.secondary);
X		break;
X	    default:
X		break;
X	}
}
SHAR_EOF
  $shar_touch -am 0722202295 'cfs_cipher.c' &&
  chmod 0644 'cfs_cipher.c' ||
  echo 'restore of cfs_cipher.c failed'
  shar_count="`wc -c < 'cfs_cipher.c'`"
  test 3298 -eq "$shar_count" ||
    echo "cfs_cipher.c: original size 3298, current size $shar_count"
fi
# ============= mcg.c ==============
if test -f 'mcg.c' && test X"$1" != X"-c"; then
  echo 'x - skipping mcg.c (file already exists)'
else
  echo 'x - extracting mcg.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'mcg.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * macguffin block encrypt/decrypt
X * unrolled, constant mask (optimized) version
X * 
X * For a complete description of MacGuffin, see
X * M. Blaze & B. Schneier, "The MacGuffin Block Cipher Algorithm",
X * proc. 2nd Workshop on Cryptographic Algorithms, Leuven, Belgium, 1994.
X *
X * 10/4/94 matt blaze
X */
X
#include "mcg.h"
X
/*
X * codebook encrypt one block with given expanded key
X */
mcg_block_encrypt(blk,key)
X     unsigned char *blk;
X     mcg_key *key;
X
{
X	unsigned short r0, r1, r2, r3, a, b, c;
X	int i;
X	unsigned short *ek;
X
X	r0=blk[0]|(blk[1]<<8);
X	r1=blk[2]|(blk[3]<<8);
X	r2=blk[4]|(blk[5]<<8);
X	r3=blk[6]|(blk[7]<<8);
X	
X	ek = &(key->val[0]);
X	/*
X	 * round loop, unrolled 4x
X	 */
X	for (i=0; i<8; i++) {
X		a = r1 ^ *(ek++);
X		b = r2 ^ *(ek++);
X		c = r3 ^ *(ek++);
X		r0 ^= ((OUT0 & stable[(a & LOOK00) |
X				      (b & LOOK01) |
X				      (c & LOOK02)])
X		       | (OUT1 & stable[(a & LOOK10) |
X					(b & LOOK11) |
X					(c & LOOK12)])
X		       | (OUT2 & stable[(a & LOOK20) |
X					(b & LOOK21) |
X					(c & LOOK22)])
X		       | (OUT3 & stable[(a & LOOK30) |
X					(b & LOOK31) |
X					(c & LOOK32)]));
X		a = r2 ^ *(ek++);
X		b = r3 ^ *(ek++);
X		c = r0 ^ *(ek++);
X		r1 ^= ((OUT0 & stable[(a & LOOK00) |
X				      (b & LOOK01) |
X				      (c & LOOK02)])
X		       | (OUT1 & stable[(a & LOOK10) |
X					(b & LOOK11) |
X					(c & LOOK12)])
X		       | (OUT2 & stable[(a & LOOK20) |
X					(b & LOOK21) |
X					(c & LOOK22)])
X		       | (OUT3 & stable[(a & LOOK30) |
X					(b & LOOK31) |
X					(c & LOOK32)]));
X		a = r3 ^ *(ek++);
X		b = r0 ^ *(ek++);
X		c = r1 ^ *(ek++);
X		r2 ^= ((OUT0 & stable[(a & LOOK00) |
X				      (b & LOOK01) |
X				      (c & LOOK02)])
X		       | (OUT1 & stable[(a & LOOK10) |
X					(b & LOOK11) |
X					(c & LOOK12)])
X		       | (OUT2 & stable[(a & LOOK20) |
X					(b & LOOK21) |
X					(c & LOOK22)])
X		       | (OUT3 & stable[(a & LOOK30) |
X					(b & LOOK31) |
X					(c & LOOK32)]));
X		a = r0 ^ *(ek++);
X		b = r1 ^ *(ek++);
X		c = r2 ^ *(ek++);
X		r3 ^= ((OUT0 & stable[(a & LOOK00) |
X				      (b & LOOK01) |
X				      (c & LOOK02)])
X		       | (OUT1 & stable[(a & LOOK10) |
X					(b & LOOK11) |
X					(c & LOOK12)])
X		       | (OUT2 & stable[(a & LOOK20) |
X					(b & LOOK21) |
X					(c & LOOK22)])
X		       | (OUT3 & stable[(a & LOOK30) |
X					(b & LOOK31) |
X					(c & LOOK32)]));
X	}
X	blk[0] = r0;
X	blk[1] = r0>>8;
X	blk[2] = r1;
X	blk[3] = r1>>8;
X	blk[4] = r2;
X	blk[5] = r2>>8;
X	blk[6] = r3;
X	blk[7] = r3>>8;
}
X
/*
X * codebook decrypt one block with given expanded key
X */
mcg_block_decrypt(blk,key)
X     unsigned char *blk;
X     mcg_key *key;
X
{
X	unsigned short r0, r1, r2, r3, a, b, c;
X	int i;
X	unsigned short *ek;
X
X	r0=blk[0]|(blk[1]<<8);
X	r1=blk[2]|(blk[3]<<8);
X	r2=blk[4]|(blk[5]<<8);
X	r3=blk[6]|(blk[7]<<8);
X
X	ek = &(key->val[KSIZE]);
X	/*
X	 * round loop, unrolled 4x
X	 */
X	for (i=0; i<8; ++i) {
X		c = r2 ^ *(--ek);
X		b = r1 ^ *(--ek);
X		a = r0 ^ *(--ek);
X		r3 ^= ((OUT0 & stable[(a & LOOK00) |
X				      (b & LOOK01) |
X				      (c & LOOK02)])
X		       | (OUT1 & stable[(a & LOOK10) |
X					(b & LOOK11) |
X					(c & LOOK12)])
X		       | (OUT2 & stable[(a & LOOK20) |
X					(b & LOOK21) |
X					(c & LOOK22)])
X		       | (OUT3 & stable[(a & LOOK30) |
X					(b & LOOK31) |
X					(c & LOOK32)]));
X		c = r1 ^ *(--ek);
X		b = r0 ^ *(--ek);
X		a = r3 ^ *(--ek);
X		r2 ^= ((OUT0 & stable[(a & LOOK00) |
X				      (b & LOOK01) |
X				      (c & LOOK02)])
X		       | (OUT1 & stable[(a & LOOK10) |
X					(b & LOOK11) |
X					(c & LOOK12)])
X		       | (OUT2 & stable[(a & LOOK20) |
X					(b & LOOK21) |
X					(c & LOOK22)])
X		       | (OUT3 & stable[(a & LOOK30) |
X					(b & LOOK31) |
X					(c & LOOK32)]));
X		c = r0 ^ *(--ek);
X		b = r3 ^ *(--ek);
X		a = r2 ^ *(--ek);
X		r1 ^= ((OUT0 & stable[(a & LOOK00) |
X				      (b & LOOK01) |
X				      (c & LOOK02)])
X		       | (OUT1 & stable[(a & LOOK10) |
X					(b & LOOK11) |
X					(c & LOOK12)])
X		       | (OUT2 & stable[(a & LOOK20) |
X					(b & LOOK21) |
X					(c & LOOK22)])
X		       | (OUT3 & stable[(a & LOOK30) |
X					(b & LOOK31) |
X					(c & LOOK32)]));
X		c = r3 ^ *(--ek);
X		b = r2 ^ *(--ek);
X		a = r1 ^ *(--ek);
X		r0 ^= ((OUT0 & stable[(a & LOOK00) |
X				      (b & LOOK01) |
X				      (c & LOOK02)])
X		       | (OUT1 & stable[(a & LOOK10) |
X					(b & LOOK11) |
X					(c & LOOK12)])
X		       | (OUT2 & stable[(a & LOOK20) |
X					(b & LOOK21) |
X					(c & LOOK22)])
X		       | (OUT3 & stable[(a & LOOK30) |
X					(b & LOOK31) |
X					(c & LOOK32)]));
X	}
X	blk[0] = r0;
X	blk[1] = r0>>8;
X	blk[2] = r1;
X	blk[3] = r1>>8;
X	blk[4] = r2;
X	blk[5] = r2>>8;
X	blk[6] = r3;
X	blk[7] = r3>>8;
}
SHAR_EOF
  $shar_touch -am 1125133094 'mcg.c' &&
  chmod 0644 'mcg.c' ||
  echo 'restore of mcg.c failed'
  shar_count="`wc -c < 'mcg.c'`"
  test 5720 -eq "$shar_count" ||
    echo "mcg.c: original size 5720, current size $shar_count"
fi
# ============= mcgsbox.c ==============
if test -f 'mcgsbox.c' && test X"$1" != X"-c"; then
  echo 'x - skipping mcgsbox.c (file already exists)'
else
  echo 'x - extracting mcgsbox.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'mcgsbox.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * MacGuffin optimized table initialization and key setup
X *
X * 10/3/94 matt blaze
X */
X
X
#include "mcg.h"
X
/*
X * the 8 s-boxes, expanded to put the output bits in the right
X * places.  note that these are the des s-boxes (in left-right,
X * not cannonical, order), but with only the "outer" two output
X * bits.
X */
unsigned short sboxes[8][64] = {
/* 0 (S1) */
X	{0x0002, 0x0000, 0x0000, 0x0003, 0x0003, 0x0001, 0x0001, 0x0000,
X	 0x0000, 0x0002, 0x0003, 0x0000, 0x0003, 0x0003, 0x0002, 0x0001,
X	 0x0001, 0x0002, 0x0002, 0x0000, 0x0000, 0x0002, 0x0002, 0x0003,
X	 0x0001, 0x0003, 0x0003, 0x0001, 0x0000, 0x0001, 0x0001, 0x0002,
X	 0x0000, 0x0003, 0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0000,
X	 0x0003, 0x0000, 0x0000, 0x0003, 0x0000, 0x0001, 0x0003, 0x0001,
X	 0x0003, 0x0001, 0x0002, 0x0003, 0x0003, 0x0001, 0x0001, 0x0002,
X	 0x0001, 0x0002, 0x0002, 0x0000, 0x0001, 0x0000, 0x0000, 0x0003},
/* 1 (S2) */
X	{0x000c, 0x0004, 0x0004, 0x000c, 0x0008, 0x0000, 0x0008, 0x0004,
X	 0x0000, 0x000c, 0x000c, 0x0000, 0x0004, 0x0008, 0x0000, 0x0008,
X	 0x000c, 0x0008, 0x0004, 0x0000, 0x0000, 0x0004, 0x000c, 0x0008,
X	 0x0008, 0x0000, 0x0000, 0x000c, 0x0004, 0x000c, 0x0008, 0x0004,
X	 0x0000, 0x000c, 0x0008, 0x0008, 0x0004, 0x0008, 0x000c, 0x0004,
X	 0x0008, 0x0004, 0x0000, 0x000c, 0x000c, 0x0000, 0x0004, 0x0000,
X	 0x0004, 0x000c, 0x0008, 0x0000, 0x0008, 0x0004, 0x0000, 0x0008,
X	 0x000c, 0x0000, 0x0004, 0x0004, 0x0000, 0x0008, 0x000c, 0x000c},
/* 2 (S3) */
X	{0x0020, 0x0030, 0x0000, 0x0010, 0x0030, 0x0000, 0x0020, 0x0030,
X	 0x0000, 0x0010, 0x0010, 0x0000, 0x0030, 0x0000, 0x0010, 0x0020,
X	 0x0010, 0x0000, 0x0030, 0x0020, 0x0020, 0x0010, 0x0010, 0x0020,
X	 0x0030, 0x0020, 0x0000, 0x0030, 0x0000, 0x0030, 0x0020, 0x0010,
X	 0x0030, 0x0010, 0x0000, 0x0020, 0x0000, 0x0030, 0x0030, 0x0000,
X	 0x0020, 0x0000, 0x0030, 0x0030, 0x0010, 0x0020, 0x0000, 0x0010,
X	 0x0030, 0x0000, 0x0010, 0x0030, 0x0000, 0x0020, 0x0020, 0x0010,
X	 0x0010, 0x0030, 0x0020, 0x0010, 0x0020, 0x0000, 0x0010, 0x0020},
/* 3 (S4) */
X	{0x0040, 0x00c0, 0x00c0, 0x0080, 0x0080, 0x00c0, 0x0040, 0x0040,
X	 0x0000, 0x0000, 0x0000, 0x00c0, 0x00c0, 0x0000, 0x0080, 0x0040,
X	 0x0040, 0x0000, 0x0000, 0x0040, 0x0080, 0x0000, 0x0040, 0x0080,
X	 0x00c0, 0x0040, 0x0080, 0x0080, 0x0000, 0x0080, 0x00c0, 0x00c0,
X	 0x0080, 0x0040, 0x0000, 0x00c0, 0x00c0, 0x0000, 0x0000, 0x0000,
X	 0x0080, 0x0080, 0x00c0, 0x0040, 0x0040, 0x00c0, 0x00c0, 0x0080,
X	 0x00c0, 0x00c0, 0x0040, 0x0000, 0x0040, 0x0040, 0x0080, 0x00c0,
X	 0x0040, 0x0080, 0x0000, 0x0040, 0x0080, 0x0000, 0x0000, 0x0080},
/* 4 (S5) */
X	{0x0000, 0x0200, 0x0200, 0x0300, 0x0000, 0x0000, 0x0100, 0x0200,
X	 0x0100, 0x0000, 0x0200, 0x0100, 0x0300, 0x0300, 0x0000, 0x0100,
X	 0x0200, 0x0100, 0x0100, 0x0000, 0x0100, 0x0300, 0x0300, 0x0200,
X	 0x0300, 0x0100, 0x0000, 0x0300, 0x0200, 0x0200, 0x0300, 0x0000,
X	 0x0000, 0x0300, 0x0000, 0x0200, 0x0100, 0x0200, 0x0300, 0x0100,
X	 0x0200, 0x0100, 0x0300, 0x0200, 0x0100, 0x0000, 0x0200, 0x0300,
X	 0x0300, 0x0000, 0x0300, 0x0300, 0x0200, 0x0000, 0x0100, 0x0300,
X	 0x0000, 0x0200, 0x0100, 0x0000, 0x0000, 0x0100, 0x0200, 0x0100},
/* 5 (S6) */
X	{0x0800, 0x0800, 0x0400, 0x0c00, 0x0800, 0x0000, 0x0c00, 0x0000,
X	 0x0c00, 0x0400, 0x0000, 0x0800, 0x0000, 0x0c00, 0x0800, 0x0400,
X	 0x0000, 0x0000, 0x0c00, 0x0400, 0x0400, 0x0c00, 0x0000, 0x0800,
X	 0x0800, 0x0000, 0x0400, 0x0c00, 0x0400, 0x0400, 0x0c00, 0x0800,
X	 0x0c00, 0x0000, 0x0800, 0x0400, 0x0c00, 0x0000, 0x0400, 0x0800,
X	 0x0000, 0x0c00, 0x0800, 0x0400, 0x0800, 0x0c00, 0x0400, 0x0800,
X	 0x0400, 0x0c00, 0x0000, 0x0800, 0x0000, 0x0400, 0x0800, 0x0400,
X	 0x0400, 0x0000, 0x0c00, 0x0000, 0x0c00, 0x0800, 0x0000, 0x0c00},
/* 6 (S7) */
X	{0x0000, 0x3000, 0x3000, 0x0000, 0x0000, 0x3000, 0x2000, 0x1000,
X	 0x3000, 0x0000, 0x0000, 0x3000, 0x2000, 0x1000, 0x3000, 0x2000,
X	 0x1000, 0x2000, 0x2000, 0x1000, 0x3000, 0x1000, 0x1000, 0x2000,
X	 0x1000, 0x0000, 0x2000, 0x3000, 0x0000, 0x2000, 0x1000, 0x0000,
X	 0x1000, 0x0000, 0x0000, 0x3000, 0x3000, 0x3000, 0x3000, 0x2000,
X	 0x2000, 0x1000, 0x1000, 0x0000, 0x1000, 0x2000, 0x2000, 0x1000,
X	 0x2000, 0x3000, 0x3000, 0x1000, 0x0000, 0x0000, 0x2000, 0x3000,
X	 0x0000, 0x2000, 0x1000, 0x0000, 0x3000, 0x1000, 0x0000, 0x2000},
/* 7 (S8) */
X	{0xc000, 0x4000, 0x0000, 0xc000, 0x8000, 0xc000, 0x0000, 0x8000,
X	 0x0000, 0x8000, 0xc000, 0x4000, 0xc000, 0x4000, 0x4000, 0x0000,
X	 0x8000, 0x8000, 0xc000, 0x4000, 0x4000, 0x0000, 0x8000, 0xc000,
X	 0x4000, 0x0000, 0x0000, 0x8000, 0x8000, 0xc000, 0x4000, 0x0000,
X	 0x4000, 0x0000, 0xc000, 0x4000, 0x0000, 0x8000, 0x4000, 0x4000,
X	 0xc000, 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0xc000,
X	 0x0000, 0xc000, 0x0000, 0x8000, 0x8000, 0xc000, 0xc000, 0x0000,
X	 0xc000, 0x4000, 0x4000, 0x4000, 0x4000, 0x0000, 0x8000, 0xc000}};
X
/*
X * table s-box outputs, expanded for 16 bit input
X * this one table includes all 8 sboxes - just mask off
X * the output bits not in use
X */
unsigned short stable[SIZE];
X
/*
X * we can exploit two features of the s-box input and output
X * permutations - first, each s-box uses as input two different bits
X * from each of the three registers in the right side, and, second,
X * for each s-box there is another-sbox with no common input bits
X * between them.  therefore we can lookup two s-box outputs in one
X * probe of the table.  just mask off the approprate input bits
X * in the table below for each of the three registers and or
X * together for the table lookup index.
X *
X * These are also available in #defines, for better lookup 
X * speed in unrolled loops.
X */
unsigned short lookupmasks[4][3] = {
X	/* a   ,   b   ,   c    */
X	{0x0036, 0x06c0, 0x6900},	/* s1+s2 */
X	{0x5048, 0x2106, 0x8411},	/* s3+s4 */
X	{0x8601, 0x4828, 0x10c4},	/* s5+s7 */
X	{0x2980, 0x9011, 0x022a}};	/* s6+s8 */
X
/*
X * this table contains the corresponding output masks for the table
X * lookup procedure mentioned above.
X *
X * similarly available in #defines.
X */
unsigned short outputmasks[4] = {
X	0x000f,	 /* s1+s2 */
X	0x00f0,	 /* s3+s4 */
X	0x3300,	 /* s5+s7 */
X	0xcc00}; /* s6+s8 */
X
X
X
/*
X * initialize the macguffin s-box tables.
X * this takes a while, but is only done once.
X */
mcg_init()
{
X	unsigned int i,j,k;
X	int b;
X	/*
X	 * input permutation for the 8 s-boxes.
X	 * each row entry is a bit position from
X	 * one of the three right hand registers,
X	 * as follows:
X	 *   a,a,b,b,c,c
X	 */
X	static int sbits[8][6] = {
X		{2,5,6,9,11,13},
X		{1,4,7,10,8,14},
X		{3,6,8,13,0,15},
X		{12,14,1,2,4,10},
X		{0,10,3,14,6,12},
X		{7,8,12,15,1,5},
X		{9,15,5,11,2,7},
X		{11,13,0,4,3,9}};
X
X	/* fill the table */
X	if ((stable[0]==0xc86e) && (stable[0xffff]==0xedaf))
X		return 0;
X	for (i=0; i<SIZE; i++) {
X		stable[i]=0;
X		for (j=0; j<8; j++)
X			stable[i] |=
X				sboxes[j][((i>>sbits[j][0])&1)
X					  |(((i>>sbits[j][1])&1)<<1)
X					  |(((i>>sbits[j][2])&1)<<2)
X					  |(((i>>sbits[j][3])&1)<<3)
X					  |(((i>>sbits[j][4])&1)<<4)
X					  |(((i>>sbits[j][5])&1)<<5)];
X		
X	}
X	return 1;
}
X
#ifdef SOLARIS2X
#define bcopy(s,d,l) memcpy(d,s,l)
#endif
X
mcg_keyset(key,ek)
X     unsigned char *key;
X     mcg_key *ek;
{
X	int i,j;
X	unsigned char k[2][8];
X
X	mcg_init();
X	bcopy(&key[0],k[0],8);
X	bcopy(&key[8],k[1],8);
X	for (i=0; i<KSIZE; i++)
X		ek->val[i]=0;
X	for (i=0; i<2; i++)
X		for (j=0; j<32; j++) {
X			mcg_block_encrypt(k[i],ek);
X			ek->val[j*3] ^= k[i][0] | (k[i][1]<<8);
X			ek->val[j*3+1] ^= k[i][2] | (k[i][3]<<8);
X			ek->val[j*3+2] ^= k[i][4] | (k[i][5]<<8);
X		}
}	
SHAR_EOF
  $shar_touch -am 1127030094 'mcgsbox.c' &&
  chmod 0644 'mcgsbox.c' ||
  echo 'restore of mcgsbox.c failed'
  shar_count="`wc -c < 'mcgsbox.c'`"
  test 8536 -eq "$shar_count" ||
    echo "mcgsbox.c: original size 8536, current size $shar_count"
fi
# ============= mcg.h ==============
if test -f 'mcg.h' && test X"$1" != X"-c"; then
  echo 'x - skipping mcg.h (file already exists)'
else
  echo 'x - extracting mcg.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'mcg.h' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/* MacGuffin Constants */
X
#define SIZE (1<<16)
extern unsigned short stable[SIZE];
extern unsigned short lookupmasks[4][3];
extern unsigned short outputmasks[4];
X
/*
X * input and output lookup masks
X */
X
/* s1+s2 */
#define LOOK00	0x0036
#define LOOK01	0x06c0
#define LOOK02	0x6900
#define OUT0	0x000f
X
/* s3+s4 */
#define LOOK10	0x5048
#define LOOK11	0x2106
#define LOOK12	0x8411
#define OUT1	0x00f0
X
/* s5+s7 */
#define LOOK20	0x8601
#define LOOK21	0x4828
#define LOOK22	0x10c4
#define OUT2	0x3300
X
/* s6+s8 */
#define LOOK30	0x2980
#define LOOK31	0x9011
#define LOOK32	0x022a
#define OUT3	0xcc00
X
#define ROUNDS 32
#define KSIZE (ROUNDS*3)
typedef struct mcg_key {
X	unsigned short val[KSIZE];
} mcg_key;
X
SHAR_EOF
  $shar_touch -am 1125132994 'mcg.h' &&
  chmod 0644 'mcg.h' ||
  echo 'restore of mcg.h failed'
  shar_count="`wc -c < 'mcg.h'`"
  test 1917 -eq "$shar_count" ||
    echo "mcg.h: original size 1917, current size $shar_count"
fi
# ============= shs.c ==============
if test -f 'shs.c' && test X"$1" != X"-c"; then
  echo 'x - skipping shs.c (file already exists)'
else
  echo 'x - extracting shs.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'shs.c' &&
/*
X * The authors of this software are Jim Reeds and Jack Lacy
X *              Copyright (c) 1992, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * Secure Hash Standard
X * proposed NIST SHS
X * coded for byte strings: number of bits is a multiple of 8
X *
X * Copyright (c) 1992, 1994 AT&T Bell Laboratories
X * Coded by Jim Reeds 5 Feb 1992
X * Enhanced by Jack Lacy 1993
X */
X
/*
X * unsigned long shs(char *s, int n);
X *
X * input:  
X *                s character array to be hashed
X *                n length of s in BYTES
X * output:
X *                return value: address of 5 unsigned longs holding hash
X *
X * machine dependencies:
X *                assumes a char is 8 bits
X */
X
/*
X * passes test on:
X *                gauss (vax)
X *                3k (cray)
X *                slepian (MIPS)
X *                bird (sparcstation II)
X */
X
#include <sys/types.h>
#include <stdio.h>
#include "shs.h"
X
static long nbits;
static unsigned long *h;
static unsigned long *w;
static void shs1();
/*
static void packl (unsigned long);
static void pack (unsigned char, unsigned char, unsigned char, unsigned char);
static void shs1(void);
static void opack(unsigned char);
*/
X
#define MASK        (unsigned long)0xffffffffL        /* in case more than 32 bits per long */
X
/*
X * stick one byte into the current block; process the block when full
X */
static void opack(c)
X  unsigned char c;
{
X	int n32, nd32, shiftbits;
X	register unsigned long x, mask, y;
X	
X	nd32 = (int)(nbits >> 5);  /* nbits/32 */
X	n32 = (int)(nbits & 0x1f); /* nbits%32 */
X	shiftbits = 24-n32;
X	
X	x = (unsigned long)(c<<shiftbits);
X	mask = (unsigned long)(0xff << shiftbits);
X	mask = ~mask;
X	
X	y = w[nd32];
X	y = (y & mask) + x;
X	w[nd32] = y;
X	
X	nbits += 8;
X	if(nbits==512){
X		nbits = 0;
X		shs1();
X	}
}
X
static void pack(c0, c1, c2, c3)
X  unsigned char c0, c1, c2, c3;
{
X	int nd32;
X	
X	nd32 = (int)(nbits >> 5);
X	w[nd32] = (u_long)(((u_long)c0<<24) | ((u_long)c1<<16) | ((u_long)c2<<8) | (u_long)c3);
X	
X	nbits += 32;
X	if(nbits==512){
X		nbits = 0;
X		shs1();
X	}
}
X
/*
X * stick a 4 byte number into the current block
X */
static void
packl(x)
X  unsigned long x;
{
X	pack((unsigned char)(x>>24), (unsigned char)(x>>16),
X	     (unsigned char)(x>>8), (unsigned char)(x>>0));
}
X
/*
X * process one block
X */
static void
shs1()
{
X	unsigned long *wp;
X	unsigned long temp;
X	unsigned long A, B, C, D, E;
X	int t;
X	
#define S(n,x) (u_long)(((x)<<(n))|((MASK&(x))>>(32-(n))))
X	
X	wp = w;
X	t = 8;
X	do {
X		wp[16] = S(1, (u_long)(wp[13]^wp[8]^wp[2]^wp[0]));
X		wp[17] = S(1, (u_long)(wp[14]^wp[9]^wp[3]^wp[1]));
X		wp[18] = S(1, (u_long)(wp[15]^wp[10]^wp[4]^wp[2]));
X		wp[19] = S(1, (u_long)(wp[16]^wp[11]^wp[5]^wp[3]));
X		wp[20] = S(1, (u_long)(wp[17]^wp[12]^wp[6]^wp[4]));
X		wp[21] = S(1, (u_long)(wp[18]^wp[13]^wp[7]^wp[5]));
X		wp[22] = S(1, (u_long)(wp[19]^wp[14]^wp[8]^wp[6]));
X		wp[23] = S(1, (u_long)(wp[20]^wp[15]^wp[9]^wp[7]));
X		wp += 8;
X		t--;
X	} while (t > 0);
X	
X	A = h[0];
X	B = h[1];
X	C = h[2];
X	D = h[3];
X	E = h[4];
X	
X	t = 0;
X	while (t<20) {
X		temp = S(5,A) + E + w[t++];
X		temp += (unsigned long)0x5a827999L + ((B&C)|(D&~B));
X		E = D; D = C; C = S(30,B); B = A; A = temp;
X	}
X	while (t<40) {
X		temp = S(5,A) + E + w[t++];
X		temp += (unsigned long)0x6ed9eba1L + (B^C^D);
X		E = D; D = C; C = S(30,B); B = A; A = temp;
X	}
X	while (t<60) {
X		temp = S(5,A) + E + w[t++];
X		temp += (unsigned long)0x8f1bbcdcL + ((B&C)|(B&D)|(C&D));
X		E = D; D = C; C = S(30,B); B = A; A = temp;
X	}
X	while (t<80) {
X		temp = S(5,A) + E + w[t++];
X		temp += (unsigned long)0xca62c1d6L + (B^C^D);
X		E = D; D = C; C = S(30,B); B = A; A = temp;
X	}
X	h[0] = MASK&(h[0] + A);
X	h[1] = MASK&(h[1] + B);
X	h[2] = MASK&(h[2] + C);
X	h[3] = MASK&(h[3] + D);
X	h[4] = MASK&(h[4] + E);
}
X
#define CHARSTOLONG(wp,s,i) {*wp++ = (u_long)((((u_long)(s[i])&0xff)<<24)|(((u_long)(s[i+1])&0xff)<<16)|(((u_long)(s[i+2])&0xff)<<8)|(u_long)(s[i+3]&0xff));}
X
X
void
shsInit(mdContext)
X  SHS_CTX *mdContext;
{
X	nbits = 0;
X	mdContext->h[0] = (unsigned long)0x67452301L;
X	mdContext->h[1] = (unsigned long)0xefcdab89L;
X	mdContext->h[2] = (unsigned long)0x98badcfeL;
X	mdContext->h[3] = (unsigned long)0x10325476L;
X	mdContext->h[4] = (unsigned long)0xc3d2e1f0L;
X	mdContext->totalLength = 0;
}
X
X
void
shsUpdate(mdContext, s, n)
X  SHS_CTX *mdContext;
X  unsigned char *s;
X  unsigned int n;
{
X	register unsigned long *wp;
X	long nn = n;
X	long i;
X	
X	w = mdContext->w;
X	h = mdContext->h;
X	mdContext->totalLength += n;
X	
X	nbits = 0;
X	n = n/(u_long)64;
X	wp = w;
X	
X	while(n>0){
X		CHARSTOLONG(wp,s,0);
X		CHARSTOLONG(wp,s,4);
X		CHARSTOLONG(wp,s,8);
X		CHARSTOLONG(wp,s,12);
X		CHARSTOLONG(wp,s,16);
X		CHARSTOLONG(wp,s,20);
X		CHARSTOLONG(wp,s,24);
X		CHARSTOLONG(wp,s,28);
X		CHARSTOLONG(wp,s,32);
X		CHARSTOLONG(wp,s,36);
X		CHARSTOLONG(wp,s,40);
X		CHARSTOLONG(wp,s,44);
X		CHARSTOLONG(wp,s,48);
X		CHARSTOLONG(wp,s,52);
X		CHARSTOLONG(wp,s,56);
X		CHARSTOLONG(wp,s,60);
X		n--;
X		wp = w;
X		s = (s + 64);
X		shs1();
X	}
X	i=nn%64;
X	while(i>3) {
X		CHARSTOLONG(wp,s,0);
X		s = (s + 4);
X		nbits += (u_long)32;
X		i -= 4;
X	}
X	while (i) {
X		opack((unsigned char)*s++);
X		i--;
X	}
}
X
void
shsFinal(mdContext)
X  SHS_CTX *mdContext;
{
X	long nn = mdContext->totalLength;
X	w = mdContext->w;
X	h = mdContext->h;
X	
X	opack(128);
X	while(nbits != 448)opack(0);
X	packl((unsigned long)(nn>>29));
X	packl((unsigned long)(nn<<3));
X	
X	/* if(nbits != 0)
X	   handle_exception(CRITICAL,"shsFinal(): nbits != 0\n");*/
}
X
unsigned char *
shs(s, n)
X  unsigned char *s;
X  long n;
{
X        SHS_CTX *mdContext;
X	static SHS_CTX mdC;
X	static unsigned char ret[20];
X	int i;
X	
X	mdContext = &mdC;
X
X	shsInit(mdContext);
X	shsUpdate(mdContext, s, n);
X	shsFinal(mdContext);
X	for (i=0; i<5; i++) {
X		ret[i*4] = (mdContext->h[i]>>24)&0xff;
X		ret[i*4+1] = (mdContext->h[i]>>16)&0xff;
X		ret[i*4+2] = (mdContext->h[i]>>8)&0xff;
X		ret[i*4+3] = (mdContext->h[i])&0xff;
X	}
X        
X	return ret;
}
X
/*int fread(char *, int, int, FILE *);*/
X
unsigned long *
fShsDigest(in)
X  FILE *in;
{
X	SHS_CTX *mdContext;
X	SHS_CTX mdC;
X	unsigned char buffer[1024];
X	long length, total;
X
X	mdContext = &mdC;
X	
X	bzero(buffer, 1024);
X
X	total = 0;
X	shsInit(mdContext);
X	while ((length = fread(buffer, 1, 1024, in)) != 0) {
X		total += length;
X		shsUpdate(mdContext, buffer, length);
X	}
X	shsFinal(mdContext);
X
X	return mdContext->h;
}
X
X
X
SHAR_EOF
  $shar_touch -am 0724161795 'shs.c' &&
  chmod 0644 'shs.c' ||
  echo 'restore of shs.c failed'
  shar_count="`wc -c < 'shs.c'`"
  test 7310 -eq "$shar_count" ||
    echo "shs.c: original size 7310, current size $shar_count"
fi
# ============= shs.h ==============
if test -f 'shs.h' && test X"$1" != X"-c"; then
  echo 'x - skipping shs.h (file already exists)'
else
  echo 'x - extracting shs.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'shs.h' &&
typedef struct {
X    long totalLength;
X    unsigned long h[5];
X    unsigned long w[80];
} SHS_CTX;
X
unsigned char *shs();
#ifdef SOLARIS2X
#define bzero(b, l)             memset(b, 0, l)
#define bcopy(s, d, l)          memcpy(d, s, l)
#define bcmp(s, d, l)           (memcmp(s, d, l)? 1 : 0)
#endif
X
SHAR_EOF
  $shar_touch -am 0724184895 'shs.h' &&
  chmod 0644 'shs.h' ||
  echo 'restore of shs.h failed'
  shar_count="`wc -c < 'shs.h'`"
  test 300 -eq "$shar_count" ||
    echo "shs.h: original size 300, current size $shar_count"
fi
# ============= cattach.c ==============
if test -f 'cattach.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cattach.c (file already exists)'
else
  echo 'x - extracting cattach.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cattach.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994, 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * client side attach - 1.3
X */
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#ifdef irix
#include <sys/statfs.h>
#else
#ifndef BSD44
#ifdef	ultrix
#include <sys/param.h>
#include <sys/mount.h>
#else
#include <sys/vfs.h>
#endif	/* ultrix */
#else
#ifndef MAXHOSTNAMELEN
#include <sys/param.h>
#endif
#include <sys/mount.h>
#endif	/* BSD44 */
#endif
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
X
#ifdef SOLARIS2X
/* NOTE!  delete the #define statfs below if this won't compile on
X  your solaris configuration */
#define statfs		statvfs
#define getwd(b)	getcwd(b, 1024)
#endif
X
#ifndef TIMEOUT		/* default timeout; override in makefile */
#define TIMEOUT 0
#endif
X
#ifndef IDLE		/* default idle timer; override in makefile */
#define IDLE 0
#endif
X
main(argc,argv)
X     int argc;
X     char **argv;
{
X	cfs_attachargs ap;
X	char *pw;
X	int status;
X	cfsstat ret;
X	char *getpassword();
X	char dir[1024]; char buf[1024];
X	char ins[1024];
#ifdef	ultrix
X	struct fs_data sfb;
#define f_blocks  fd_req.btot
#else
X	struct statfs sfb;
#endif
X	char *flg;
X	int ciph;
X	FILE *fp;
X	unsigned char ekey[128];
X	char cname[1024];
X	char kname[1024]; /* indirect key file */
X	int cfmt=0;
X	static struct timeval tout = {60,0};
X	CLIENT *cln;
X	int timeout=TIMEOUT;
X	int idle=IDLE;
X	char *dirarg=NULL;
X	char *namearg=NULL;
X
X	ap.highsec=1;
X	while (--argc) if (**++argv == '-') {
X		for (flg= ++*argv; *flg; ++flg)
X			switch (*flg) {
X			    case 'l':
X				ap.highsec=0;
X				break;
X			    case 't':	/* absolute timeout */
X			    case 'i':	/* idle timer */
X				enq(*flg);
X				break;
X			    default:
X				fprintf(stderr,"usage: cattach [-l] [-t timeout] -i [idle] dir name\n");
X				exit(1);
X			}
X	} else {
X		switch (deq()) {
X		    case -1:
X			if (dirarg==NULL)
X				dirarg = *argv;
X			else if (namearg==NULL)
X				namearg = *argv;
X			else {
X				fprintf(stderr,"usage: cattach [-l] [-t timeout] -i [idle] dir name\n");
X				exit(1);
X			}
X			break;
X		    case 't':
X			timeout = atoi(*argv);
X			break;
X		    case 'i':
X			idle = atoi(*argv);
X			break;
X		    default:	/* should never happen */
X			fprintf(stderr,"cattach: internal error\n");
X			exit(1);
X		}
X	}
X	if ((dirarg==NULL) || (namearg==NULL)) {
X		fprintf(stderr,"usage: cattach [-l] [-t timeout] [-i idle] dir name\n");
X		exit(1);
X	}
X	if (*dirarg!='/') {
X		if (getwd(buf) == NULL) {
X			fprintf(stderr,"Can't stat current directory\n");
X			exit(1);
X		}
X		sprintf(dir,"%s/%s",buf,dirarg);
X	} else
X		strcpy(dir,dirarg);
X	if (chdir(dir)<0) {
X		perror(dirarg);
X		exit(1);
X	}
#ifdef irix
/* or (I hope) more or less any system with the 4 parameter statfs */
X    if ((statfs(".",&sfb,sizeof sfb,0)<0) || (sfb.f_blocks==0)) {
X        fprintf(stderr,"Sorry, can't attach to a crypted directory\n");
X        exit(1);
X    }
#else
X	if ((statfs(".",&sfb)<0) || (sfb.f_blocks==0)) {
X		fprintf(stderr,"Sorry, can't attach to a crypted directory\n");
X		exit(1);
X	}
#endif
X	ap.dirname=dir;
X	strcpy(ins,namearg);
X	*namearg='\0'; /* weak attempt to hide .instance in ps output */
X	ap.name=ins;
X	if ((pw=getpassword("Key:"))==NULL) {
X		fprintf(stderr,"Can't get key\n");
X		exit(1);
X	}
X	sprintf(cname,"%s/..c",dir);
X	sprintf(kname,"%s/..k",dir);
X	if ((fp=fopen(cname,"r")) == NULL) {
X		ciph=CFS_STD_DES;
X	} else {
X		fscanf(fp,"%d",&ciph);
X		fclose(fp);
X	}
X	if ((fp=fopen(kname,"r")) == NULL) {
X		cfmt=0;
X	} else {
X		cfmt=1;
X		if (fread(ekey,32,1,fp) < 0)
X			cfmt=0;
X		fclose(fp);
X	}
X	ap.idle = idle;
X	ap.expire = timeout;
X	ap.key.cipher=ciph;
X	if (cfmt) {
X		if (new_pwcrunch(pw,&ap.key)!=0) {
X			fprintf(stderr,"Invalid key\n");
X			exit(1);
X		}
X		decrypt_key(&ap.key,ekey);
X	}
X	else {
X		if (old_pwcrunch(pw,&ap.key)!=0) {
X			fprintf(stderr,"Invalid key\n");
X			exit(1);
X		}
X	}
X	ap.anon = ap.name[0]=='.';
X	ap.uid=getuid();
X	if ((cln=clnt_create("localhost",ADM_PROGRAM,ADM_VERSION,"udp"))
X	    == NULL) {
X		clnt_pcreateerror("adm");
X		exit(1);
X	}
X	cln->cl_auth = authunix_create_default();
X	if ((status = clnt_call(cln,ADMPROC_ATTACH,xdr_cfs_attachargs,&ap,
X				xdr_cfsstat,&ret,tout)) != RPC_SUCCESS) {
X		clnt_perrno(status);
X		exit(1);
X	}
X	if (ret!=CFS_OK)
X		fprintf(stderr,"cattach: %s\n",admmsg(ret));
X	exit(ret);
}
X
#define QS 5
struct {
X        int data[QS];
X        int head;
X        int tail;
} argq = {{0},0,0};
X
enq(f)
X     char f;
{
X	argq.tail++;
X	argq.tail %= QS;
X	if (argq.head==argq.tail) {
X		fprintf(stderr,"Can't deal with this\n");
X		exit(-2);
X	}
X	argq.data[argq.tail]=f;
}
X
deq()
{
X	if (argq.head==argq.tail)
X		return -1;
X	argq.head++;
X	argq.head %= QS;
X	return(argq.data[argq.head]);
}
SHAR_EOF
  $shar_touch -am 0724170795 'cattach.c' &&
  chmod 0644 'cattach.c' ||
  echo 'restore of cattach.c failed'
  shar_count="`wc -c < 'cattach.c'`"
  test 5756 -eq "$shar_count" ||
    echo "cattach.c: original size 5756, current size $shar_count"
fi
# ============= getpass.c ==============
if test -f 'getpass.c' && test X"$1" != X"-c"; then
  echo 'x - skipping getpass.c (file already exists)'
else
  echo 'x - extracting getpass.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'getpass.c' &&
/* adapted from d. mitchell's code */
/* includes code derived from the ucb getpass */
/*
X * Copyright (c) 1988 The Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *      This product includes software developed by the University of
X *      California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
#include <stdio.h>
#include <signal.h>
#ifndef linux
#include <sgtty.h>
#endif
#include <sys/types.h>
#include <rpc/rpc.h>
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
#include "shs.h"
X
#if defined(irix) || defined(linux)
/* hacks to use POSIX style termios instead of old BSD style sgttyb */
#include <termios.h>
#define sgttyb termios
#define gtty(a,b) tcgetattr((a), (b))
#define stty(a,b) tcsetattr((a), TCSAFLUSH, (b))
#define sg_flags c_lflag
#endif
X
X	
char *
getpassword(prompt)
char *prompt;
{
X	struct sgttyb ttyb;
X	int flags;
X	register char *p;
X	register c;
X	FILE *fi;
X	static char pbuf[128];
#ifdef MACH
X	int (*signal())();
X	int (*sig)();
#else
X	void (*sig)();
#endif
X
X	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
X		fi = stdin;
X	else
X		setbuf(fi, (char *)NULL);
X	sig = signal(SIGINT, SIG_IGN);
X	gtty(fileno(fi), &ttyb);
X	flags = ttyb.sg_flags;
X	ttyb.sg_flags &= ~ECHO;
X	stty(fileno(fi), &ttyb);
X	fprintf(stderr, "%s", prompt); fflush(stderr);
X	for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
X		if (p < &pbuf[127])
X			*p++ = c;
X	}
X	*p = '\0';
X	fprintf(stderr, "\n"); fflush(stderr);
X	ttyb.sg_flags = flags;
X	stty(fileno(fi), &ttyb);
X	signal(SIGINT, sig);
X	if (fi != stdin)
X		fclose(fi);
X	return(pbuf);
}
X
old_pwcrunch(b,k)
X     char *b;
X     cfs_admkey *k;
{
X	int l;
X	u_char k1[8];
X	u_char k2[8];
X
X	if ((l=strlen(b))<3)
X		return -1;
X	/* note that we always use the DES key crunch. */
X	/* that's not a significant weakness, since here DES */
X	/* is just being used as a non-cryptographic hash. */
X	/* note also that k1 and k2 are created from disjoint parts */
X	/* of the passphrase. */
X	key_crunch(&b[l/2],l-l/2,k1);
X	key_crunch(b,l/2,k2);
X	switch (k->cipher) {
X	    case CFS_STD_DES:
X		bcopy(k1,k->cfs_admkey_u.deskey.primary,8);
X		bcopy(k2,k->cfs_admkey_u.deskey.secondary,8);
X		break;
X	    case CFS_THREE_DES:
X		bcopy(k1,k->cfs_admkey_u.des3key.primary1,8);
X		bcopy(k1,k->cfs_admkey_u.des3key.secondary1,8);
X		bcopy(k2,k->cfs_admkey_u.des3key.primary2,8);
X		bcopy(k2,k->cfs_admkey_u.des3key.secondary2,8);
X		break;
X	    case CFS_MACGUFFIN:
X		bcopy(k1,k->cfs_admkey_u.mcgkey.primary,8);
X		bcopy(k2,&(k->cfs_admkey_u.mcgkey.primary[8]),8);
X		bcopy(k1,k->cfs_admkey_u.mcgkey.secondary,8);
X		bcopy(k2,&(k->cfs_admkey_u.mcgkey.secondary[8]),8);
X		break;
X	    default:
X		break;
X	}
X	return 0;
}
new_pwcrunch(b,k)
X     char *b;
X     cfs_admkey *k;
{
X	int l;
X	u_char *k1;
X	u_char *k2;
X	u_char *hash;
X	
X	if ((l=strlen(b))<3)
X		return -1;
X	hash = shs(b,l);
X	k1 = hash;
X	k2 = &(hash[8]);
X	switch (k->cipher) {
X	    case CFS_STD_DES:
X		bcopy(k1,k->cfs_admkey_u.deskey.primary,8);
X		bcopy(k2,k->cfs_admkey_u.deskey.secondary,8);
X		break;
X	    case CFS_THREE_DES:
X		bcopy(k1,k->cfs_admkey_u.des3key.primary1,8);
X		bcopy(k1,k->cfs_admkey_u.des3key.secondary1,8);
X		bcopy(k2,k->cfs_admkey_u.des3key.primary2,8);
X		bcopy(k2,k->cfs_admkey_u.des3key.secondary2,8);
X		break;
X	    case CFS_MACGUFFIN:
X		bcopy(k1,k->cfs_admkey_u.mcgkey.primary,16);
X		bcopy(k1,k->cfs_admkey_u.mcgkey.secondary,16);
X		break;
X	    default:
X		break;
X	}
X	return 0;
}
X
decrypt_key(k,ek)
X     cfs_admkey *k;
X     u_char *ek;
{
X	mcg_key mk;
X	
X	switch (k->cipher) {
X	    case CFS_STD_DES:
X		q_block_cipher(k->cfs_admkey_u.deskey.primary,&(ek[0]),1);
X		q_block_cipher(k->cfs_admkey_u.deskey.secondary,&(ek[0]),0);
X		q_block_cipher(k->cfs_admkey_u.deskey.primary,&(ek[0]),1);
X		q_block_cipher(k->cfs_admkey_u.deskey.primary,&(ek[8]),1);
X		q_block_cipher(k->cfs_admkey_u.deskey.secondary,&(ek[8]),0);
X		q_block_cipher(k->cfs_admkey_u.deskey.primary,&(ek[8]),1);
X		bcopy(&(ek[0]),k->cfs_admkey_u.deskey.primary,8);
X		bcopy(&(ek[8]),k->cfs_admkey_u.deskey.secondary,8);
X		break;
X	    case CFS_THREE_DES:
X		q_block_cipher(k->cfs_admkey_u.des3key.primary1,&(ek[0]),1);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary2,&(ek[0]),0);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary1,&(ek[0]),1);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary1,&(ek[8]),1);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary2,&(ek[8]),0);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary1,&(ek[8]),1);
X		bcopy(&(ek[0]),k->cfs_admkey_u.des3key.primary1,8);
X		bcopy(&(ek[0]),k->cfs_admkey_u.des3key.secondary1,8);
X		bcopy(&(ek[8]),k->cfs_admkey_u.des3key.primary2,8);
X		bcopy(&(ek[8]),k->cfs_admkey_u.des3key.secondary2,8);
X		break;
X	    case CFS_MACGUFFIN:
X		mcg_keyset(k->cfs_admkey_u.mcgkey.primary,&mk);
X		mcg_block_decrypt(&mk,&(ek[0]));
X		mcg_block_decrypt(&mk,&(ek[8]));
X		bcopy(ek,k->cfs_admkey_u.mcgkey.primary,16);
X		bcopy(ek,k->cfs_admkey_u.mcgkey.secondary,16);
X		break;
X	    default:
X		break;
X	}
}
encrypt_key(k,ek)
X     cfs_admkey *k;
X     u_char *ek;
{
X	mcg_key mk;
X		
X	
X	switch (k->cipher) {
X	    case CFS_STD_DES:
X		q_block_cipher(k->cfs_admkey_u.deskey.primary,&(ek[0]),0);
X		q_block_cipher(k->cfs_admkey_u.deskey.secondary,&(ek[0]),1);
X		q_block_cipher(k->cfs_admkey_u.deskey.primary,&(ek[0]),0);
X		q_block_cipher(k->cfs_admkey_u.deskey.primary,&(ek[8]),0);
X		q_block_cipher(k->cfs_admkey_u.deskey.secondary,&(ek[8]),1);
X		q_block_cipher(k->cfs_admkey_u.deskey.primary,&(ek[8]),0);
X		break;
X	    case CFS_THREE_DES:
X		q_block_cipher(k->cfs_admkey_u.des3key.primary1,&(ek[0]),0);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary2,&(ek[0]),1);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary1,&(ek[0]),0);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary1,&(ek[8]),0);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary2,&(ek[8]),1);
X		q_block_cipher(k->cfs_admkey_u.des3key.primary1,&(ek[8]),0);
X		break;
X	    case CFS_MACGUFFIN:
X		mcg_keyset(k->cfs_admkey_u.mcgkey.primary,&mk);
X		mcg_block_encrypt(&mk,&(ek[0]));
X		mcg_block_encrypt(&mk,&(ek[8]));
X		break;
X	    default:
X		break;
X	}
}
X
X
SHAR_EOF
  $shar_touch -am 0723002595 'getpass.c' &&
  chmod 0644 'getpass.c' ||
  echo 'restore of getpass.c failed'
  shar_count="`wc -c < 'getpass.c'`"
  test 7590 -eq "$shar_count" ||
    echo "getpass.c: original size 7590, current size $shar_count"
fi
# ============= cdetach.c ==============
if test -f 'cdetach.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cdetach.c (file already exists)'
else
  echo 'x - extracting cdetach.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cdetach.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * client side detach
X */
#include <stdio.h>
#include <rpc/rpc.h>
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
X
main(argc,argv)
X     int argc;
X     char **argv;
{
X	cfs_detachargs ap;
X	char *pw;
X	int status;
X	cfsstat ret;
X	
X	if (argc!=2) {
X		fprintf(stderr,"Usage: cdetach name\n");
X		exit(1);
X	}
X	ap.name=argv[1];
X	ap.uid=getuid();
X	if ((status = callrpc("localhost",ADM_PROGRAM,ADM_VERSION,
X			    ADMPROC_DETACH,xdr_cfs_detachargs,&ap,
X			    xdr_cfsstat,&ret)) !=0) {
X		clnt_perrno(status);
X		exit(1);
X	}
X	if (ret!=CFS_OK)
X		fprintf(stderr,"cdetach: %s\n",admmsg(ret));
X	exit(ret);
}
SHAR_EOF
  $shar_touch -am 0103114494 'cdetach.c' &&
  chmod 0644 'cdetach.c' ||
  echo 'restore of cdetach.c failed'
  shar_count="`wc -c < 'cdetach.c'`"
  test 1826 -eq "$shar_count" ||
    echo "cdetach.c: original size 1826, current size $shar_count"
fi
# ============= cmkdir.c ==============
if test -f 'cmkdir.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cmkdir.c (file already exists)'
else
  echo 'x - extracting cmkdir.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cmkdir.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994, 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * client cfs mkdir - 1.3
X */
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
#include "shs.h"
X
main(argc,argv)
X     int argc;
X     char **argv;
{
X	char *pw;
X	char pword[256];
X	char *getpassword();
X	cfs_admkey k;
X	cfskey kt;
X	char path[1024];
X	char str[8];
X	FILE *fp;
X	char *flg;
X	struct timeval tv;
X	u_long r;
X	int i;
X	int ciph=CFS_STD_DES;
X	int cfmt=1;
X	unsigned char ekey[128];
X	unsigned char ek1[128];
X	unsigned int l;
X	
X	while (--argc && (**++argv == '-')) {
X		for (flg= ++*argv; *flg; ++flg)
X			switch (*flg) {
X			    case '3':
X				ciph=CFS_THREE_DES;
X				break;
X			    case 'm':
X				ciph=CFS_MACGUFFIN;
X				break;
X			    case 'o':
X				cfmt=0;
X				break;
X			    default:
X				fprintf(stderr,"usage: cmkdir [-3m] dir\n");                               exit(1);
X			}
X	}
X	if (argc!=1) {
X		fprintf(stderr,"Usage: cmkdir [-3m] dir\n");
X		exit(1);
X	}
X	if ((pw=getpassword("Key:"))==NULL) {
X		fprintf(stderr,"Can't get key\n");
X		exit(1);
X	}
X	strcpy(pword,pw);
X	if (strlen(pw)<16) {
X		fprintf(stderr,"Key must be at least 16 chars.\n");
X		exit(1);
X	}
X	if ((pw=getpassword("Again:"))==NULL) {
X		fprintf(stderr,"Can't get key\n");
X		exit(1);
X	}
X	if (strcmp(pword,pw)!=0) {
X		fprintf(stderr,
X			"Keys don't match; drink some coffee and try again\n");
X		exit(1);
X	}
X	k.cipher=ciph;
X	if (cfmt==0) { 
X		if (old_pwcrunch(pw,&k)!=0) {
X			fprintf(stderr,"Invalid key\n");
X			exit(1);
X		}
X	} else {
X		/* this is very ugly and will be replaced but it works */
X		if (new_pwcrunch(pw,&k)!=0) {
X			fprintf(stderr,"Invalid key\n");
X			exit(1);
X		}
X		/* now we xor in some truerand bytes for good measure */
X		bcopy(&k,ekey,32);  /* assumes key material < 32 bytes */
X		for (i=0; i<32; i++) {
X			l=truerand(); 
X			ekey[i] ^= (shs(&l,sizeof(l)))[0];
X		}
X		encrypt_key(&k,ekey);
X		bcopy(ekey,ek1,32);
X		decrypt_key(&k,ek1);
X		/* new &k is our real key */
X	}
X	if (mkdir(argv[0],0777)<0) {
X		perror("cmkdir");
X		exit(1);
X	}
X	sprintf(path,"%s/...",argv[0]);
X	strcpy(str,"qua!");
X	/* now randomize the end of str.. */
X	gettimeofday(&tv,NULL);
X	r=(getpid()<<16)+tv.tv_sec;
X	for (i=0; i<4; i++)
X		str[i+4]=(r<<(i*8))&0377;
X	copykey(&k,&kt);
X	cipher(&kt,str,0);
X	mask_cipher(&kt,str,1);
X	cipher(&kt,str,0);
X	if ((fp=fopen(path,"w")) == NULL) {
X		perror("cmkdir");
X		exit(1);
X	}
X	fwrite(str,8,1,fp);
X	fclose(fp);
X	sprintf(path,"%s/..c",argv[0]);
X	if ((fp=fopen(path,"w")) == NULL) {
X		perror("cmkdir");
X		exit(1);
X	}
X	fprintf(fp,"%d",k.cipher);
X	fclose(fp);
X	if (cfmt) {
X		sprintf(path,"%s/..k",argv[0]);
X		if ((fp=fopen(path,"w")) == NULL) {
X			perror("cmkdir");
X			exit(1);
X		}
X		fwrite(ekey,32,1,fp);
X		fclose(fp);
X	}
X	exit(0);
}
SHAR_EOF
  $shar_touch -am 0722230895 'cmkdir.c' &&
  chmod 0644 'cmkdir.c' ||
  echo 'restore of cmkdir.c failed'
  shar_count="`wc -c < 'cmkdir.c'`"
  test 3909 -eq "$shar_count" ||
    echo "cmkdir.c: original size 3909, current size $shar_count"
fi
# ============= adm.c ==============
if test -f 'adm.c' && test X"$1" != X"-c"; then
  echo 'x - skipping adm.c (file already exists)'
else
  echo 'x - extracting adm.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'adm.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * support for client adm functions
X */
#include <stdio.h>
#include <rpc/rpc.h>
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
X
#define MAXADMERR 7
X
char *admerrs[] = {
X	"no error",			/* 0 */
X	"permission denied",		/* 1 */
X	"too many attached directories",/* 2 */
X	"no such attached name",	/* 3 */
X	"name already attached",	/* 4 */
X	"no such encrypted directory",	/* 5 */
X	"incorrect passphrase",		/* 6 */
X	"badly formed name"		/* 7 */
X	};
X
char *admmsg(e)
X     int e;
{
X	if ((e>MAXADMERR) || (e<0))
X		return "unknown error";
X	return admerrs[e];
}
SHAR_EOF
  $shar_touch -am 0103114394 'adm.c' &&
  chmod 0644 'adm.c' ||
  echo 'restore of adm.c failed'
  shar_count="`wc -c < 'adm.c'`"
  test 1785 -eq "$shar_count" ||
    echo "adm.c: original size 1785, current size $shar_count"
fi
# ============= cname.c ==============
if test -f 'cname.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cname.c (file already exists)'
else
  echo 'x - extracting cname.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cname.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * cfs cname - 1.3
X */
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#include <ctype.h>
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
X
/* following are never used - just so i can re-use the library */
int validhost;
char zerovect[]={0,0,0,0,0,0,0,0,0};
int cursecs=0;
X
char *gets();
X
main(argc,argv)
X     int argc;
X     char **argv;
{
X	char *pw;
X	char pword[256];
X	char *getpassword();
X	cfs_admkey k;
X	cfskey kt;
X	char *flg;
X	char estr[1024];
X	char *cstr;
X	int i;
X	int ciph=CFS_STD_DES;
X	int verb=0;
X	
X	fprintf(stderr,"WARNING: cname works only on old format CFS dirs\n");
X	while (--argc && (**++argv == '-')) {
X		for (flg= ++*argv; *flg; ++flg)
X			switch (*flg) {
X			    case 'v':
X				verb++;
X				break;
X			    case '3':
X				ciph=CFS_THREE_DES;
X				break;
X			    case 'm':
X				ciph=CFS_MACGUFFIN;
X				break;
X			    default:
X				fprintf(stderr,"usage: cname [-3m]\n");
X				exit(1);
X			}
X	}
X	if (argc!=0) {
X		fprintf(stderr,"Usage: cname [-3m]\n");
X		exit(1);
X	}
X	if ((pw=getpassword("Key:"))==NULL) {
X		fprintf(stderr,"Can't get key\n");
X		exit(1);
X	}
X	strcpy(pword,pw);
X	k.cipher=ciph;
X	if (old_pwcrunch(pw,&k)!=0) {
X		fprintf(stderr,"Invalid key\n");
X		exit(1);
X	}
X	copykey(&k,&kt);
X	genmasks(&kt);
X	while (gets(estr) != NULL) {
X		cstr=decryptname(&kt,estr);
X		if (verb)
X			printf("%s -> ",estr);
X		if ((cstr!=NULL) && printable(cstr))
X			puts(cstr);
X		else
X			puts("???");
X	}
X
}
X
int printable(s)
X     char *s;
{
X	while (*s)
X		if (!isprint(*s++))
X			return 0;
X	return 1;
}
X
X
SHAR_EOF
  $shar_touch -am 0722230795 'cname.c' &&
  chmod 0644 'cname.c' ||
  echo 'restore of cname.c failed'
  shar_count="`wc -c < 'cname.c'`"
  test 2726 -eq "$shar_count" ||
    echo "cname.c: original size 2726, current size $shar_count"
fi
# ============= ccat.c ==============
if test -f 'ccat.c' && test X"$1" != X"-c"; then
  echo 'x - skipping ccat.c (file already exists)'
else
  echo 'x - extracting ccat.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'ccat.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1994 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * cfs ccat - 1.3
X */
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/stat.h>
#ifdef SOLARIS2X
#include <string.h>
#define rindex strrchr
#else
#include <strings.h>
#endif
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
X
/* following are never used - just so i can re-use the library */
int validhost;
char zerovect[]={0,0,0,0,0,0,0,0,0};
int cursecs=0;
X
main(argc,argv)
X     int argc;
X     char **argv;
{
X	char *pw;
X	char pword[256];
X	char *getpassword();
X	cfs_admkey k;
X	cfskey kt;
X	char *flg;
X	char *p;
X	char ivfile[1024];
X	char base[1024];
X	char iv[16];
X	int fd;
X	int len;
X	int siz;
X	int offset;
X	int i;
X	char *buf[8192];
X	int ciph=CFS_STD_DES;
X
X	fprintf(stderr,"WARNING: ccat works only on old format CFS files\n");
X	while (--argc && (**++argv == '-')) {
X		for (flg= ++*argv; *flg; ++flg)
X			switch (*flg) {
X			    case '3':
X				ciph=CFS_THREE_DES;
X				break;
X			    case 'm':
X				ciph=CFS_MACGUFFIN;
X				break;
X			    default:
X				fprintf(stderr,"usage: ccat [-3m] file ...\n");
X				exit(1);
X			}
X	}
X	if (argc<1) {
X		fprintf(stderr,"Usage: ccat [-3m] file ...\n");
X		exit(1);
X	}
X	if ((pw=getpassword("Key:"))==NULL) {
X		fprintf(stderr,"Can't get key\n");
X		exit(1);
X	}
X	strcpy(pword,pw);
X	k.cipher=ciph;
X	if (old_pwcrunch(pw,&k)!=0) {
X		fprintf(stderr,"Invalid key\n");
X		exit(1);
X	}
X	copykey(&k,&kt);
X	genmasks(&kt);
X	for (i=0; i<argc; i++) {
X		strcpy(ivfile,argv[i]);
X		if ((p=rindex(ivfile,'/'))==NULL)
X			sprintf(ivfile,".pvect_%s",argv[i]);
X		else {
X			*p='\0';
X			strcpy(base,++p);
X			sprintf(ivfile,"%s/.pvect_%s",ivfile,base);
X		}
X		if (readlink(ivfile,iv,8) != 8)
X			bcopy(zerovect,iv,8);
X		fprintf(stderr,"%s %s\n",ivfile,iv);
X		if ((fd=open(argv[i],O_RDONLY,0))<0) {
X			perror(argv[i]);
X			continue;
X		}
X		len=flen(fd);
X		fprintf(stderr,"%s %d\n",argv[i],len);
X		for (offset=0; offset<len;){
X			siz=len-offset;
X			if (siz>8192)
X				siz=8192;
X			siz=readblock(buf,fd,offset,siz,&kt,iv);
X			write(1,buf,siz);
X			offset+=siz;
X		}
X	}
}
X
flen(fd)
X     int fd;
{
X	struct stat sb;
X
X	if (fstat(fd,&sb)<0)
X		return -1;
X	return dtov(sb.st_size);
}
SHAR_EOF
  $shar_touch -am 0722230695 'ccat.c' &&
  chmod 0644 'ccat.c' ||
  echo 'restore of ccat.c failed'
  shar_count="`wc -c < 'ccat.c'`"
  test 3335 -eq "$shar_count" ||
    echo "ccat.c: original size 3335, current size $shar_count"
fi
# ============= cpasswd.c ==============
if test -f 'cpasswd.c' && test X"$1" != X"-c"; then
  echo 'x - skipping cpasswd.c (file already exists)'
else
  echo 'x - extracting cpasswd.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cpasswd.c' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
/*
X * client cfs cpasswd - 1.3
X */
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#include "nfsproto.h"
#include "admproto.h"
#include "cfs.h"
#include "shs.h"
X
main(argc,argv)
X     int argc;
X     char **argv;
{
X	char *pw;
X	char pword[256];
X	char buf[1024];
X	char *getpassword();
X	cfs_admkey oldkey;
X	cfs_admkey newkey;
X	cfskey kt;
X	char path[1024];
X	char kpath[1024];
X	char opath[1024];
X	char cname[1024];
X	char kname[1024];
X	char dir[1024];
X	FILE *fp;
X	char *flg;
X	int ciph=CFS_STD_DES;
X	int cfmt=1;
X	unsigned char ekey[128];
X	
X	while (--argc && (**++argv == '-')) {
X		for (flg= ++*argv; *flg; ++flg)
X			switch (*flg) {
X			    default:
X				fprintf(stderr,"usage: cpasswd dir\n");
X				exit(1);
X			}
X	}
X	if (argc!=1) {
X		fprintf(stderr,"Usage: cpasswd dir\n");
X		exit(1);
X	}
X	if (*argv[0]!='/') {
X		if (getwd(buf) == NULL) {
X			fprintf(stderr,"Can't stat current directory\n");
X			exit(1);
X		}
X		sprintf(dir,"%s/%s",buf,argv[0]);
X	} else
X		strcpy(dir,argv[0]);
X	if (chdir(dir)<0) {
X		perror(dir);
X		exit(1);
X	}
X
X	sprintf(cname,"%s/..c",dir);
X	sprintf(kname,"%s/..k",dir);
X	if ((fp=fopen(cname,"r")) == NULL) {
X		fprintf(stderr,"Can only change passphrase on new format CFS directories\n");
X		exit(1);
X	} else {
X		fscanf(fp,"%d",&ciph);
X		fclose(fp);
X	}
X	if (((fp=fopen(kname,"r")) == NULL) || (fread(ekey,1,32,fp)<16)) {
X		perror(dir);
X		fprintf(stderr,"Can only change passphrase on new format CFS directories\n");
X		exit(1);
X	}
X	fclose(fp);
X	oldkey.cipher=ciph;
X	if ((pw=getpassword("Old passphrase:"))==NULL) {
X		fprintf(stderr,"Can't get key\n");
X		exit(1);
X	}
X	if (new_pwcrunch(pw,&oldkey)!=0) {
X		fprintf(stderr,"Invalid key\n");
X		exit(1);
X	}
X	decrypt_key(&oldkey,ekey);
X	if (!checkkey(dir,&oldkey)) {
X		fprintf(stderr,"Incorrect passphrase\n");
X		exit(1);
X	}
X
X	if ((pw=getpassword("New passphrase:"))==NULL) {
X		fprintf(stderr,"Can't get key\n");
X		exit(1);
X	}
X	strcpy(pword,pw);
X	if (strlen(pw)<16) {
X		fprintf(stderr,"Key must be at least 16 chars.\n");
X		exit(1);
X	}
X	if ((pw=getpassword("Again:"))==NULL) {
X		fprintf(stderr,"Can't get key\n");
X		exit(1);
X	}
X	if (strcmp(pword,pw)!=0) {
X		fprintf(stderr,
X			"Keys don't match; drink some coffee and try again\n");
X		exit(1);
X	}
X	if (new_pwcrunch(pw,&newkey)!=0) {
X		fprintf(stderr,"Invalid key\n");
X		exit(1);
X	}
X	encrypt_key(&newkey,ekey);
X	sprintf(path,"%s/..n",dir);
X	sprintf(opath,"%s/..o",dir);
X	if ((fp=fopen(path,"w")) == NULL) {
X		perror("cmkdir");
X		exit(1);
X	}
X	if (fwrite(ekey,1,32,fp) != 32) {
X		perror("can't create new key file");
X		exit(1);
X	}
X	fclose(fp);
X	sprintf(kpath,"%s/..k",dir);
X	/* do this in 3 phases, ultra paranoid */
X	if (rename(kpath,opath) < 0) {
X		perror("can't rename old key file");
X		exit(1);
X	}
X	if (rename(path,kpath) < 0) {
X		perror("can't link new key file");
X		exit(1);
X	}
X	if (unlink(opath)<0)
X		perror("warning: old key file not removed");
X	exit(0);
}
X
X
checkkey(path,ak)
X     char *path;
X     cfs_admkey *ak;
{
X	FILE *fp;
X	char fn[1024];
X	char buf[9];
X	cfskey k;
X	
X	copykey(ak,&k);
X	sprintf(fn,"%s/...",path);
X	if ((fp=fopen(fn,"r"))==NULL)
X		return 0;
X	if (fread(buf,8,1,fp)!=1) {
X		fclose (fp);
X		return 0;
X	}
printf("check\n");
X	fclose (fp);
X	cipher(&k,buf,1);        /* note order here */
X	mask_cipher(&k,buf,0);
X	cipher(&k,buf,1);        /* note order here */
printf("check again\n");
X	if (bcmp(buf,"qua!",4)!=0)
X		return 0;
X	return 1;
}
SHAR_EOF
  $shar_touch -am 0728024495 'cpasswd.c' &&
  chmod 0644 'cpasswd.c' ||
  echo 'restore of cpasswd.c failed'
  shar_count="`wc -c < 'cpasswd.c'`"
  test 4569 -eq "$shar_count" ||
    echo "cpasswd.c: original size 4569, current size $shar_count"
fi
# ============= truerand.c ==============
if test -f 'truerand.c' && test X"$1" != X"-c"; then
  echo 'x - skipping truerand.c (file already exists)'
else
  echo 'x - extracting truerand.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'truerand.c' &&
/*
X *	Physically random numbers (very nearly uniform)
X *	D. P. Mitchell 
X * 		hacked by mab
X */
/*
X * The author of this software is Don Mitchell.
X *              Copyright (c) 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
#include <signal.h>
#include <setjmp.h>
#include <sys/time.h>
#include <math.h>
#include <stdio.h>
X
static jmp_buf env;
static unsigned count;
static unsigned ocount;
static unsigned buffer;
X
static
tick()
{
X	struct itimerval it, oit;
X
X	timerclear(&it.it_interval);
X	it.it_value.tv_sec = 0;
X	it.it_value.tv_usec = 16665;
X	if (setitimer(ITIMER_REAL, &it, &oit) < 0)
X		perror("tick");
}
X
static void
interrupt()
{
X	if (count)
X		longjmp(env, 1);
X	(void) signal(SIGALRM, interrupt);
X	tick();
}
X
static unsigned
roulette()
{
X	if (setjmp(env)) {
X		count ^= (count>>3) ^ (count>>6) ^ ocount;
X		count &= 0x7;
X		ocount=count;
X		buffer = (buffer<<3) ^ count;
X		return buffer;
X	}
X	(void) signal(SIGALRM, interrupt);
X	count = 0;
X	tick();
X	for (;;)
X		count++;	/* about 1 MHz on VAX 11/780 */
}
X
unsigned
truerand()
{
X
X	count=0;
X	(void) roulette();
X	(void) roulette();
X	(void) roulette();
X	(void) roulette();
X	(void) roulette();
X	(void) roulette();
X	(void) roulette();
X	(void) roulette();
X	(void) roulette();
X	(void) roulette();
X	return roulette();
}
X
int
n_truerand(n)
int n;
{
X	int slop, v;
X
X	slop = 0x7FFFFFFF % n;
X	do {
X		v = truerand() >> 1;
X	} while (v <= slop);
X	return v % n;
}
X
X
SHAR_EOF
  $shar_touch -am 0723185395 'truerand.c' &&
  chmod 0644 'truerand.c' ||
  echo 'restore of truerand.c failed'
  shar_count="`wc -c < 'truerand.c'`"
  test 2017 -eq "$shar_count" ||
    echo "truerand.c: original size 2017, current size $shar_count"
fi
# ============= ver.c ==============
if test -f 'ver.c' && test X"$1" != X"-c"; then
  echo 'x - skipping ver.c (file already exists)'
else
  echo 'x - extracting ver.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'ver.c' &&
static char version[]="CFS 1.3.0 - cryptlevel: DES=4, 3DES=2, MCG=2";
SHAR_EOF
  $shar_touch -am 0724184395 'ver.c' &&
  chmod 0644 'ver.c' ||
  echo 'restore of ver.c failed'
  shar_count="`wc -c < 'ver.c'`"
  test 70 -eq "$shar_count" ||
    echo "ver.c: original size 70, current size $shar_count"
fi
# ============= i ==============
if test -f 'i' && test X"$1" != X"-c"; then
  echo 'x - skipping i (file already exists)'
else
  echo 'x - extracting i (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'i' &&
#!/bin/sh
cattach -i 45 $HOME/.secrets $USER
SHAR_EOF
  $shar_touch -am 0724183495 'i' &&
  chmod 0755 'i' ||
  echo 'restore of i failed'
  shar_count="`wc -c < 'i'`"
  test 45 -eq "$shar_count" ||
    echo "i: original size 45, current size $shar_count"
fi
# ============= o ==============
if test -f 'o' && test X"$1" != X"-c"; then
  echo 'x - skipping o (file already exists)'
else
  echo 'x - extracting o (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'o' &&
#!/bin/sh
cdetach $USER
SHAR_EOF
  $shar_touch -am 1223085892 'o' &&
  chmod 0755 'o' ||
  echo 'restore of o failed'
  shar_count="`wc -c < 'o'`"
  test 24 -eq "$shar_count" ||
    echo "o: original size 24, current size $shar_count"
fi
# ============= ssh ==============
if test -f 'ssh' && test X"$1" != X"-c"; then
  echo 'x - skipping ssh (file already exists)'
else
  echo 'x - extracting ssh (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'ssh' &&
#!/bin/ksh
X
if [ -z "$1" ]; then
X	echo Usage: ssh directory
X	exit
fi
export PS1="crypto:`basename $1`$ "
D=.$RANDOM.$RANDOM
cattach $1 $D || exit 1
echo "Directory is /crypt/$D"
cd /crypt/$D
D="             "
CWD=`/bin/pwd`
D=`basename $CWD`
PWD=$CWD
export RANDOM=0
exec /bin/sh -c "$SHELL ; cdetach $D"
SHAR_EOF
  $shar_touch -am 0101214594 'ssh' &&
  chmod 0755 'ssh' ||
  echo 'restore of ssh failed'
  shar_count="`wc -c < 'ssh'`"
  test 305 -eq "$shar_count" ||
    echo "ssh: original size 305, current size $shar_count"
fi
# ============= esm.c ==============
if test -f 'esm.c' && test X"$1" != X"-c"; then
  echo 'x - skipping esm.c (file already exists)'
else
  echo 'x - extracting esm.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'esm.c' &&
/*
X * ESM - Encrypted Session Manager
X * v1.0.0
X * matt blaze
X * july 1995
X */
X
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
/*
X * Some of this file was stolen from the BSD "script" program, which
X * is covered under the following notice:
X *
X * Copyright (c) 1980 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
#ifndef lint
char copyright1[] =
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
X All rights reserved.\n";
char copyright2[] =
"@(#) Copyright (c) 1995 AT&T\nAll rights reserved.\n";
#endif /* not lint */
X
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#ifndef SUN
#include <sys/ioctl.h>
#endif
#include <sys/time.h>
#include <sys/file.h>
#include <sys/signal.h>
#include <unistd.h>
#include <stdio.h>
#include "global.h"
#include "rsaref.h"
#include "esm.h"
X
X
char	*shell;
int	master;
int	slave;
int	subchild;
X
int escape=036; /* ^^ */
int ciphstate=0;
int ciphbyte=0;
X
int keyed=0;
X
struct	termios tt;
struct	winsize win;
int	lb;
int	l;
char	line[] = "/dev/ptyXX";
int	aflg;
X
#define REMOTE 0
#define LOCAL 1
#define CALC 2
X
int mode=LOCAL;
int paranoid=0;
X
#define SL_START 0
#define SL_GOT1 1
#define SL_GOT2 2
#define SL_GOT3 3
#define SL_GOT4 4
#define SL_KEYING 5
#define SL_CRYPT 6
int sloutstate=SL_START;
char *cmd=NULL;
X
FILE *fpmaster;
X
#define bwrite(fp,buf,len) (fwrite(buf,len,1,fp))
X
main(argc, argv)
X	int argc;
X	char *argv[];
{
X	extern char *optarg;
X	extern int optind;
X	int ch;
X	void finish();
X	char *getenv();
X	fd_set fds;
X
X	while ((ch = getopt(argc, argv, "e:splrci")) != EOF)
X		switch((char)ch) {
X		    case 'e':
X			cmd=optarg;
X			break;
X		    case 'i':
X		    case 's':
X		    case 'p':
X			paranoid=1;
X		    case 'r':
X			mode=REMOTE;
X			break;
X		    case 'l':
X			mode=LOCAL;
X			break;
X		    case 'c':
X			mode=CALC;
X			break;
X		    case '?':
X		    default:
X			fprintf(stderr,
X			   "usage: esm [-rlc] [-e program\n");
X			exit(1);
X		}
X	argc -= optind;
X	argv += optind;
X
X	if ((shell=getenv("SHELL")) == NULL)
X		shell = "/bin/sh";
X	
X	getmaster();
X
X	(void) signal(SIGCHLD, finish);
X	subchild = fork();
X	if (subchild < 0) {
X		perror("fork");
X		fail();
X	}
X	if (subchild==0)
X		doshell(mode);
X	else {
X		/* main loop */
X		printf("ESM v1.0 - encrypted session manager\n");
X		printf("    by Matt Blaze, AT&T Bell Labs, June 1995\n");
X		randinit();
X		cipherinit();
X		switch (mode) {
X		    case REMOTE:
X			if (paranoid)
X			     printf("remote server ready\n");
X			else
X			     printf("remote server ready; ctl-^ to escape\n");
X			break;
X		    case LOCAL:
X			printf("local layer ready (run 'esm -s' on remote)\n");
X			break;
X		    default:  /* not yet */
X			printf("esm ready\n");
X		}
X		rawtty();
X		fpmaster=fdopen(master,"w");
X		if (fpmaster == NULL)
X			done();
X		if (paranoid)
X			startsession();
X		FD_ZERO(&fds);
X		FD_SET(0,&fds);
X		FD_SET(master,&fds);
X		while (select (FD_SETSIZE,&fds,NULL,NULL,NULL)>0) {
X			if (FD_ISSET(0,&fds))
X				doinput();
X			if (FD_ISSET(master,&fds))
X				dooutput();
X			FD_ZERO(&fds);
X			FD_SET(0,&fds);
X			FD_SET(master,&fds);
X		}
X		done();
X	}
}
X
#define TRANS 0
#define CMDWAIT 1
#define CIPHER 2
#define KEYWAIT 3
X
#define IV0 0
#define IV1 1
#define IV2 2
#define IV3 3
#define C0  4
#define C1  5
X
int state=TRANS;
int cstate=IV0;
X
doinput()
{
X	int cc;
X	int i;
X	static unsigned char ibuf[512];
X	
X	if ((cc = read(0, ibuf, 512)) > 0) {
X		switch (mode) {
X		    case REMOTE:
X			for (i=0; i<cc; i++)
X				domasterin(ibuf[i]);
X			break;
X		    case LOCAL:
X			for (i=0; i<cc; i++)
X				doslavein(ibuf[i]);
X			break;
X		    default:
X			for (i=0; i<cc; i++)
X				bwrite(fpmaster,&ibuf[i],1);
X			break;
X		}
X		fflush(fpmaster);
X		fflush(stdout);
X	} else
X		done();
}
X
doslavein(ibuf)
X     unsigned char ibuf;
{
X	int c;
X	static int count=0;
X	
X	switch (sloutstate) {
X	    case SL_CRYPT:
X		if (ibuf==escape) {
X			bwrite(stdout,">>",2);
X			fflush(stdout);
X			if (slescape()) {
X				printf("q\r\nEntering CLEARTEXT mode\r\n");
X				bwrite(fpmaster,"PPPPPPPPPPPPPPPP",16);
X				sloutstate=SL_START;
X			}
X			break;
X		}			
X		c=cfb8_encrypt(ibuf);
X		if (!(++count % 8))
X			bwrite(fpmaster,"!",1);
X		sendhex(fpmaster,c);
X		break;
X	    default:
X		bwrite(fpmaster,&ibuf,1);
X		break;
X	}
}
X
slescape()
{
X	char buf;
X	int c;
X	int escaped=0;
X	
X	while (read(0,&buf,1)>0) {
X		if (escaped) {
X			escaped=0;
X			bwrite(fpmaster,&buf,1);
X			continue;
X		}
X		if (buf==escape) {
X			c=cfb8_encrypt(buf);
X			sendhex(fpmaster,c);
X			return 0;
X		}
X		bwrite(stdout,&buf,1);
X		fflush(stdout);
X		if (buf=='\\') {
X			escaped=1;
X			continue;
X		}
X		if (buf=='\r')
X			return 0;
X		if (buf=='C') {
X			return 1;
X		}
X		printf("\r\nType one of the following:\r\n");
X		printf("  \\[char] to send char as cleartext\r\n");
X		printf("  ctrl-^ to send escape character\r\n");
X		printf("  'C' to return to CLEARTEXT session\r\n");
X		printf("  <enter> to return to encrypted session\r\n");
X	}
X	return 1; /* should never happen */
}
X
X			       
X
domasterin(ibuf)
X     unsigned char ibuf;
{
X	int c;
X	char ch;
X	static int bad=0;
X	
X	switch (state) {
X	    case TRANS:
X		if (ibuf != escape)
X			bwrite(fpmaster, &ibuf, 1);
X		else {
X			state=CMDWAIT;
X			bwrite(stdout,">>",2);
X			cstate=IV0;
X		}
X		break;
X	    case CMDWAIT:
X		if (ibuf == escape) {
X			bwrite(fpmaster, &ibuf, 1);
X			state=TRANS;
X		} else switch (ibuf) {
X		    case '\r':
X		    case '\n':
X			bwrite(stdout,"\r\n",2);
X			state=TRANS;
X			break;
X		    case 's':
X		    case 'S':
X			startsession(LONG);
X			break;
X		    case 'Q':
X			done();
X			break;
X		    default:
X			printf("Type 's' to start encrypted session\r\n");
X			printf("     'Q' to terminate remote session\r\n");
X			printf("     ctrl-^ to send escape character\r\n");
X			printf("     <enter> to return to session\r\n");
X			break;
X		}
X		break;
X	    case CIPHER:
X		if (strchr("0123456789abcdef!",ibuf)!=NULL) {
X			bad=0;
X			if ((c = cipherout(ibuf)) >= 0) {
X				ch=c;
X				bwrite(fpmaster,&ch,1);
X			}
X		} else if (bad++ > 16) {
X			delkey();
X			bwrite(stdout,"XXXXXXXXXXXXXXXX",16);
X			if (paranoid)
X				done();
X			state=TRANS;
X		} else
X			ciphstate=0;
X		break;
X	    case KEYWAIT:
X		if (strchr("0123456789abcdef:",ibuf)!=NULL) {
X			masterkeyin(ibuf);
X		} else {
X			delkey();
X			bwrite(stdout,"XXXXXXXXXXXXXXXX",16);
X			if (paranoid)
X				done();
X			state=TRANS;
X		}
X		break;
X	}
}
X
int pubstat=0;
int pubpos=0;
unsigned char pubbyte=0;
int pksize = -1;
X
startsession()
{
X	static unsigned char buf[5] = {0177, '~', 0177, '~', 'L'};
X	static unsigned char colon=':';
X	int i;
X
X	pklen=dhparams[LONG].primeLen;
X	printf("Starting remote side of %d bit key exchange.\r\n",pklen*8);
X	printf("  (type any character to abort)");
X	fflush(stdout);
X	bwrite(stdout,buf,5);
X	if (createdh(LONG) < 0)
X		return -1;
X	for (i=0; i<pklen; i++)
X		sendhex(stdout,ourpub[i]);
X	bwrite(stdout,&colon,1);
X	pksize=LONG;
X	pubstat=0;
X	pubpos=0;
X	pubbyte=0;
X	state=KEYWAIT;
X	return 0;
}
X
sltranspub(len)
{
X	static unsigned char colon=':';
X	int i;
X	
X	for (i=0; i<len; i++)
X		sendhex(fpmaster,ourpub[i]);
X	bwrite(fpmaster,&colon,1);
}
X
masterkeyin(c)
X     char c;
{
X	int bits;
X
X	if (c==':') {
X		if (pubpos!=(pklen))
X			goto abort;
X		if (mcalckeys(pksize)<0)
X			goto abort;
X		ciphstate=0;
X		state=CIPHER;
X		/* state = CHECK */
X		/* add code to do check */
X		return;
X	} else if (pubpos<MAXPUBKEY) {
X		bits=atoh(c);
X		if (bits<0)
X			goto abort;
X		if (pubstat) {
X			pubbyte |= bits;
X			otherpub[pubpos]=pubbyte;
X			pubpos++;
X		} else {
X			pubbyte = bits<<4;
X		}
X		pubstat = 1-pubstat;
X		return;
X	}
X    abort:
X	bwrite(stdout,"XXXXXXXXXXXXXXXX",16);
X	if (paranoid)
X		done();
X	state=TRANS;
}
X
int mcalckeys(len)
X     int len;
{
X	int i;
X	static char kh[32];
X	
X	if (dhagree(len,1)<0) /* sets up session keys */
X		return -1;
X	for (i=0; i<8; i++) {
X		ivin[i]=0;
X		ivout[i]=0xff;
X	}
X	/* TODO
X	sprintf(kh,"KEYHASH=%02x%02x%02x%02x",
X		check[0],check[1],check[2],check[3]);
X	putenv(kh);	*/
X	return 0;
}
X
int slcalckeys(len)
X     int len;
{
X	int i;
X	
X	if (dhagree(len,0)<0) /* sets up session keys */
X		return -1;
X	for (i=0; i<8; i++) {
X		ivout[i]=0;
X		ivin[i]=0xff;
X	}
X	printf("\r\n(key hash is %02x%02x%02x%02x)\r\n",
X		check[0],check[1],check[2],check[3]);
X	return 0;
}
X
initslkey(param)
X     int param;
{
X	if ((param<0) || (param>2))
X		return -1;
X	pklen=dhparams[param].primeLen;
X	pksize=param;
X	pubstat=0;
X	pubpos=0;
X	pubbyte=0;
}
X
slkeyin(c)
X     char c;
{
X	int bits;
X
X	if (c==':') {
X		if (pubpos!=pklen)
X			goto abort;
X		printf("\r\nStarting local key exchange...");
X		if (createdh(pksize)<0)
X			goto abort;
X		sltranspub(pklen);
X		printf("calculating DH key...");
X		fflush(stdout);
X		if (slcalckeys(pksize)<0)
X			goto abort;
X		printf("Entering ENCRYPTED mode; type ctrl-^ to escape\r\n");
X		ciphstate=0;
X		sloutstate=SL_CRYPT;
X		/* add code to send two ascci nulls for check */
X		return;
X	} else if (pubpos<MAXPUBKEY){
X		bits=atoh(c);
X		if (bits<0)
X			goto abort;
X		if (pubstat) {
X			pubbyte |= bits;
X			otherpub[pubpos]=pubbyte;
X			pubpos++;
X		} else {
X			pubbyte = bits<<4;
X		}
X		pubstat = 1-pubstat;
X		return;
X	}
X    abort:
X	bwrite(stdout,"X",1);
X	state=SL_START;
X
}
X
X
X
int cipherout(ch)
X     char ch;
{
X	int bits;
X	
X	if (ch=='!') {
X		ciphstate=0;
X		return -1;
X	}
X	bits=atoh(ch);
X	if (ciphstate) {
X		ciphbyte |= bits;
X		ciphstate=0;
X		return(cfb8_decrypt(ciphbyte));
X	} else {
X		ciphbyte = bits<<4;
X		ciphstate=1;
X		return -1;
X	}
}
X
int ciphercalcin(ch)
X     unsigned char ch;
{
X	static unsigned char iv[8];
X	static unsigned int cbuf;
X	int c;
X	int i;
X
X	c = atoh(ch);
X	switch (cstate) {
X	    case IV0:
X		for(i=0; i<8; i++)
X			iv[i]=0;
X		cbuf = (c&0xf)<<4;
X		cstate=IV1;
X		return '.';
X	    case IV1:
X		cbuf = cbuf | (c&0xf);
X		iv[7]=cbuf;
X		cstate=IV2;
X		return '.';
X	    case IV2:
X		cbuf = (c&0xf)<<4;
X		cstate=IV3;
X		return '.';
X	    case IV3:
X		cbuf = cbuf | (c&0xf);
X		iv[6]=cbuf;
X		cstate=C0;
X		return '.';
X	    case C0:
X		cbuf = (c&0xf)<<4;
X		cstate=C1;
X		return '.';
X	    case C1:
X		cbuf = cbuf | c&0xf;
X		c=cfb8_decrypt(cbuf);
X		cstate=C0;
X		if (isprint(c)) {
X			bwrite(fpmaster,&c,1);
X			return '_';
X		} else {
X			return '?';
X		}
X	    default:
X		return '?';
X	}
}
X
#include <sys/wait.h>
X
void
finish()
{
X	union wait status;
X	register int pid;
X	register int die = 0;
X
X	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
X		if (pid == subchild)
X			die = 1;
X
X	if (die)
X		done();
}
X
dooutput()
{
X	register int cc;
X	int i;
X	unsigned char obuf[512];
X	
X	if ((cc = read(master, obuf, 512)) > 0) {
X		switch (mode) {
X		    case REMOTE:
X			for (i=0; i<cc; i++)
X				domasterout(obuf[i]);
X			break;
X		    case LOCAL:
X			for (i=0; i<cc; i++)
X				doslaveout(obuf[i]);
X			break;
X		    default:
X			for (i=0; i<cc; i++)
X				bwrite(stdout, &obuf[i], 1);
X			break;
X		}
X		fflush(fpmaster);
X		fflush(stdout);
X	} else
X		done();
}
X
domasterout(obuf)
X     unsigned char obuf;
{
X	int c;
X	static int count=0;
X	
X	switch (state) {
X	    case CIPHER:
X		c=cfb8_encrypt(obuf);
X		if (!(++count % 8))
X			bwrite(stdout,"!",1);
X		sendhex(stdout,c);
X		break;
X	    case TRANS:
X		bwrite(stdout, &obuf, 1);
X		break;
X	    default:
X		/* throw away since i/o screws up keying */
X		break;
X	}
}
X
X
doslaveout(obuf)
X     unsigned char obuf;
{
X	static int bad=0;
X	int c;
X	char ch;
X	
X	switch (sloutstate) {
X	    case SL_START:
X		bwrite(stdout, &obuf, 1);
X		if (obuf==0177)
X			sloutstate=SL_GOT1;
X		break;
X	    case SL_GOT1:
X		if (obuf=='~')
X			sloutstate=SL_GOT2;
X		else {
X			bwrite(stdout, &obuf, 1);
X       			sloutstate=SL_START;
X		}
X		break;
X	    case SL_GOT2:
X		if (obuf==0177)
X			sloutstate=SL_GOT3;
X		else {
X			bwrite(stdout, &obuf, 1);
X			sloutstate=SL_START;
X		}
X		break;
X	    case SL_GOT3:
X		if (obuf=='~')
X			sloutstate=SL_GOT4;
X		else {
X			bwrite(stdout, &obuf, 1);
X			sloutstate=SL_START;
X		}
X		break;
X	    case SL_GOT4: /* key size indicator */
X		if (obuf=='S') {
X			initslkey(SHORT);
X			sloutstate=SL_KEYING;
X		} else if (obuf=='M') {
X			initslkey(MEDIUM);
X			sloutstate=SL_KEYING;
X		} else if (obuf=='L') {
X			initslkey(LONG);
X			sloutstate=SL_KEYING;
X		} else {
X			sloutstate=SL_START;
X			bwrite(stdout, &obuf, 1);
X		}
X		if (createdh(pksize)<0)
X			sloutstate=SL_START;
X		break;
X	    case SL_KEYING:
X		if (strchr("0123456789abcdef:",obuf) != NULL) {
X			slkeyin(obuf);
X		} else {
X			bwrite(stdout,"U",1);
X			sloutstate=SL_START;
X		}
X		break;
X	    case SL_CRYPT:
X		if (strchr("0123456789abcdef!",obuf) != NULL) {
X			bad=0;
X			if ((c = cipherout(obuf))>=0) {
X				ch=c;
X				bwrite(stdout,&ch,1);
X			}
X		} else if (bad++ > 8) {
X			fprintf(stderr,"\r\nEncrypted session terminated -");
X			fprintf(stderr,"\r\npress enter for CLEARTEXT mode: ");
X			waitenter();
X			delkey();
X			sloutstate=SL_START;
X		} else
X			ciphstate=0;
X		break;
X	    default:
X		bwrite(stdout, &obuf, 1);
X		break;
X	}
}
X
X
X
doshell(mode)
X     int mode;
{
X	int t;
X
X	/***
X	t = open(_PATH_TTY, O_RDWR);
X	if (t >= 0) {
X		(void) ioctl(t, TIOCNOTTY, (char *)0);
X		(void) close(t);
X	}
X	***/
X	/* setprompt(mode); */
X        getslave();
X	(void) close(master);
X	(void) dup2(slave, 0);
X	(void) dup2(slave, 1);
X	(void) dup2(slave, 2);
X	(void) close(slave);
X	if (cmd==NULL)
X		execl(shell, "sh", "-i", 0);
X	else
X		execl("/bin/sh", "sh", "-c", cmd, 0);
X	perror(shell);
X	fail();
}
X
#ifdef NOTDEF
/* make this work more generally */
setprompt(mode)
X     int mode;
{
X	/* TO DO - make this work for csh */
X        char *oldps1;
X	static char newps1[128];
X	char *getenv();
X
X	if ((oldps1=getenv("PS1")) == NULL)
X		oldps1="$ ";
X	switch (mode) {
X	    case LOCAL:
X		sprintf(newps1,"PS1=ESM:%s",oldps1);
X		break;
X	    case REMOTE:
X		sprintf(newps1,"PS1=SECURE:%s",oldps1);
X		break;;
X	    default:
X		sprintf(newps1,"PS1=?esm:%s",oldps1);
X		break;
X	}
X	putenv(newps1);
}
#endif
X
rawtty()
{
X
X	struct termios sbuf;
X
X        sbuf = tt;
X        sbuf.c_iflag &= ~(INLCR|IGNCR|ICRNL|IXON);
X        sbuf.c_oflag &= ~OPOST;
X        sbuf.c_lflag &= ~(ICANON|ISIG|ECHO);
X        sbuf.c_cc[VMIN] = 1;
X        sbuf.c_cc[VTIME] = 0;
X	(void) tcsetattr(0, TCSAFLUSH, &sbuf);
}
X
cookedtty()
{
X	(void) tcsetattr(0, TCSAFLUSH, &tt);
}
X
fail()
{
X
X	(void) kill(0, SIGTERM);
X	done();
}
X
done()
{
X	cookedtty();
X	switch (mode) {
X	    case REMOTE:
X		if (state==CIPHER)
X			printf("XXXXXXXXXXXXXXXX\n");
X		printf("esm remote ");
X		break;
X	    case LOCAL:
X		printf("esm local ");
X		break;
X	}
X	printf("done\n");
X	exit(0);
}
X
getmaster()
{
X	char *pty, *bank, *cp;
X	struct stat stb;
X
X	pty = &line[strlen("/dev/ptyp")];
X	for (bank = "pqrstuvwxyz"; *bank; bank++) {
X		line[strlen("/dev/pty")] = *bank;
X		*pty = '0';
X		if (stat(line, &stb) < 0)
X			break;
X		for (cp = "0123456789abcdef"; *cp; cp++) {
X			*pty = *cp;
X			master = open(line, O_RDWR);
X			if (master >= 0) {
X				char *tp = &line[strlen("/dev/")];
X				int ok;
X
X				/* verify slave side is usable */
X				*tp = 't';
X				ok = access(line, R_OK|W_OK) == 0;
X				*tp = 'p';
X				if (ok) {
X					(void) tcgetattr(0, &tt);
X				    	(void) ioctl(0, TIOCGWINSZ, 
X						(char *)&win);
X					return;
X				}
X				(void) close(master);
X			}
X		}
X	}
X	fprintf(stderr, "Out of pty's\n");
X	fail();
}
X
getslave()
{
X
X	line[strlen("/dev/")] = 't';
X	slave = open(line, O_RDWR);
X	if (slave < 0) {
X		perror(line);
X		fail();
X	}
X	(void) tcsetattr(slave, TCSAFLUSH, &tt);
X	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
X	(void) setsid();
X	(void) ioctl(slave, TIOCSCTTY, 0);
}
X
waitenter()
{
X	unsigned char b;
X	do {
X		read(0,&b,1);
X	} while (b!='\r');
X	printf("\r\n");
}
X
sendhex(fp,c)
X     FILE *fp;
X     unsigned int c;
{
X	static char buf[16];
X
X	sprintf(buf,"%02x",c);
X	bwrite(fp,buf,2);
}
SHAR_EOF
  $shar_touch -am 0725090795 'esm.c' &&
  chmod 0644 'esm.c' ||
  echo 'restore of esm.c failed'
  shar_count="`wc -c < 'esm.c'`"
  test 17727 -eq "$shar_count" ||
    echo "esm.c: original size 17727, current size $shar_count"
fi
# ============= esm_cipher.c ==============
if test -f 'esm_cipher.c' && test X"$1" != X"-c"; then
  echo 'x - skipping esm_cipher.c (file already exists)'
else
  echo 'x - extracting esm_cipher.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'esm_cipher.c' &&
/*
X * ESM crypto interface
X * v0.6
X */
X
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include "global.h"
#include "rsaref.h"
#include "esm.h"
X
unsigned char check[8];
X
unsigned char skey1[8];
unsigned char skey2[8];
unsigned char skey3[8];
unsigned char mkey1[8];
unsigned char mkey2[8];
unsigned char mkey3[8];
unsigned char ivin[8];
unsigned char ivout[8];
X
R_RANDOM_STRUCT rs;
X
R_DH_PARAMS dhparams[3];
X
unsigned char otherpub[MAXPUBKEY+2];
unsigned char ourpub[MAXPUBKEY+2];
unsigned char ourpriv[MAXPUBKEY];
int ourprivlen;
int pklen;
X
keystr inks, outks;
X
cipherinit(master)
X     int master;
{
X	if (master) {
X		des_key_setup(skey1,inks.ek1);
X		des_key_setup(skey2,inks.ek2);
X		des_key_setup(skey3,inks.ek3);
X		des_key_setup(mkey1,outks.ek1);
X		des_key_setup(mkey2,outks.ek2);
X		des_key_setup(mkey3,outks.ek3);
X	} else {
X		des_key_setup(skey1,outks.ek1);
X		des_key_setup(skey2,outks.ek2);
X		des_key_setup(skey3,outks.ek3);
X		des_key_setup(mkey1,inks.ek1);
X		des_key_setup(mkey2,inks.ek2);
X		des_key_setup(mkey3,inks.ek3);
X	}
}
X
/* 8 bit cfb encrypt */
unsigned int cfb8_encrypt(c)
X     unsigned int c;
X     
{
X	int i;
X	char blk[8];
X
X	for (i=0; i<8; i++)
X		blk[i]=ivout[i];
X	des_block_cipher(outks.ek1,blk,0);
X	des_block_cipher(outks.ek2,blk,1);
X	des_block_cipher(outks.ek3,blk,0);
X	for (i=0; i<7; i++)
X		ivout[i]=ivout[i+1];
X	ivout[7] = blk[0] ^ c;
X	return (ivout[7]);
}
X
/*
X * 8 bit cfb decrypt
X */
unsigned int cfb8_decrypt(c)
X     unsigned int c;
{
X	int i;
X	unsigned char blk[8];
X
X	for (i=0; i<8; i++)
X		blk[i]=ivin[i];
X	des_block_cipher(inks.ek1,blk,0);
X	des_block_cipher(inks.ek2,blk,1);
X	des_block_cipher(inks.ek3,blk,0);
X	for (i=0; i<7; i++)
X		ivin[i]=ivin[i+1];
X	ivin[7] = c;
X	return (blk[0] ^ c);
}
X
/*
X * alpha -> hex; used for encoding
X *  (ascii only - bfd)
X */
int atoh(ch)
X     int ch;
{
X	if (isdigit(ch))
X		return ch-'0';
X	if (islower(ch))
X		return 10+ch-'a';
X	if (isupper(ch))
X		return 10+ch-'A';
X	else
X		return -1; /*???*/
}
X
X     
int count=0;
int secs;
unsigned int bits;
void procbit()
{
X	secs--;
X	bits |= ((count ^ (count>>4)) & 0xf)<<(secs*4);
X	if (secs) {
X		alarm(1);
X		signal(SIGALRM,procbit);
X		getuid();	/* do a syscall to slow things a bit */
X	}
}
X
int verbose=1;
/*
X * init the random number generator - seed with
X * truerandbits.
X * Use a combination of OS load and processor clock skew to get
X * enough entropy to generate the secret parameter (we only need a
X * total of 128 or so bits, so we just get more than we need to
X * compensate for any non-randomness).
X * WARNING: use oldrand() (below) on new platforms
X * if you aren't sure about truerand().
X */
randinit()
{
X	unsigned int n;
X	int i=0;
X	struct timeval tv;
X	unsigned long truerand();
X	unsigned long b;
X	
X	R_RandomInit(&rs);
X	if (verbose)
X		fprintf(stderr,"randomizing...");
X	fflush(stderr);
X	while (R_GetRandomBytesNeeded(&n,&rs), (n>0)) {
X		b=truerand();
X		R_RandomUpdate(&rs,(unsigned char *)&b,sizeof(b));
X		if (verbose && ((i++)%10)==0)
X			fprintf(stderr,".");
X	}
X	/* Just for good measure, we throw in a couple other things */
X	b=getpid();
X	R_RandomUpdate(&rs,(unsigned char*)&n,sizeof(n));
X	gettimeofday(&tv,NULL);
X	R_RandomUpdate(&rs,(unsigned char*)&tv,sizeof(tv));
X	if (verbose)
X		fprintf(stderr,"done\n");
}
X
/*
X * OLD CODE HERE.  NOT CALLED.
X * generate 8 random clock skew bits
X * we don't use this anymore.. instead we generate more
X * bits using the mitchell code.
X * modify the code to use this instead if you don't trust
X * the higher-bandwidth mitchell numbers.
X */
int rnd8()
{
X	secs=2;
X	bits=0;
X	signal(SIGALRM,procbit);
X	alarm(1);
X	getpid();
X	while (secs)
X		count++;
X	return bits;
X	
}
X
/*
X * OLD CODE HERE.  NOT CALLED.
X * this is the old, slow but simple truerand routine
X * you should change the code use this on new platforms instead of 
X * the "randinit" above.
X */
oldrandinit()
{
X	unsigned int n;
X	unsigned char b[18];
X	struct timeval tv;
X	
X	R_RandomInit(&rs);
X	R_GetRandomBytesNeeded(&n,&rs); /* but we ignore */
X	/* RSAREF wants 256 bytes, which is an awful lot at 4bps.  we
X	   really only need enough to do justice to the entropy of
X	   the block cipher (3des), so we just generate 18. */
X	   
X	if (verbose)
X		fprintf(stderr,"Randomizing (takes about 45 secs)...");
X	fflush(stderr);
X	for (n=0; n<18; n++) {
X		b[n]=rnd8();
X		if (verbose && (n%4==3)) {
X			fprintf(stderr,".");
X			fflush(stderr);
X		}
X	}
X	while (R_GetRandomBytesNeeded(&n,&rs), (n>0)) {
X		R_RandomUpdate(&rs,b,18);
X		if (verbose)
X			fprintf(stderr,".");
X	}
X	/* Just for good measure, we throw in a couple other things */
X	n=getpid();
X	R_RandomUpdate(&rs,(unsigned char*)&n,sizeof(n));
X	gettimeofday(&tv,NULL);
X	R_RandomUpdate(&rs,(unsigned char*)&tv,sizeof(tv));
X	if (verbose)
X		fprintf(stderr,"done\n");
}
X
#define BLANKLINE 0
#define TERM 1
#define NONE 2
#define SHORTKEY 3
#define MEDKEY 4
#define LONGKEY 5
#define HEX 6
#define FILENAME 7
X
int size[3];
X
int keysize=0;
X	
getpubkey()
{
X	fprintf(stderr,"Calculator not implemented, sorry\n");
X	return;
}
X
createdh(param)
X     int param;
{
X	int e;
X	
X	if ((param<0) || (param>2))
X		return -1;
X	ourprivlen=(dhparams[param].generatorLen)/2; /* from gen'd params */
X	if ((e=R_SetupDHAgreement(ourpub, ourpriv, ourprivlen,
X				  &dhparams[param], &rs))!=0) {
X		return -1;
X	}
X	return 0;
}
X
dhagree(param,master)
X     int param;
X     int master;
{
X	unsigned char buf[MAXPUBKEY];
X	int i;
X	
X	if ((param<0) || (param>2))
X		return -1;
X	if (R_ComputeDHAgreedKey(buf,otherpub,ourpriv,ourprivlen,
X				 &dhparams[param]) != 0)
X		return -1;
X	for (i=0; i<8; i++) {	/* always have enough agreed bits */
X		mkey1[i] = buf[i];
X		mkey2[i] = buf[i+8];
X		mkey3[i] = buf[i+16];
X		skey1[i] = buf[24+i];
X		skey2[i] = buf[24+i+8];
X		skey3[i] = buf[24+i+16];
X		check[i] = buf[32+i];
X	}
X	cipherinit(master);
X	return 0;
}
X	    
X     
delkey()
{
}
X
SHAR_EOF
  $shar_touch -am 0604160195 'esm_cipher.c' &&
  chmod 0644 'esm_cipher.c' ||
  echo 'restore of esm_cipher.c failed'
  shar_count="`wc -c < 'esm_cipher.c'`"
  test 6542 -eq "$shar_count" ||
    echo "esm_cipher.c: original size 6542, current size $shar_count"
fi
# ============= esm_gen.c ==============
if test -f 'esm_gen.c' && test X"$1" != X"-c"; then
  echo 'x - skipping esm_gen.c (file already exists)'
else
  echo 'x - extracting esm_gen.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'esm_gen.c' &&
/*
X * ESM DH parameter generator
X */
X
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
#include <stdio.h>
#include "global.h"
#include "rsaref.h"
#include "esm.h"
X
main()
{
X	R_DH_PARAMS dhparams[3];
X	unsigned char p0[512],p1[512],p2[512],g0[512],g1[512],g2[512];
X	int x;
X	
X	randinit();
X
X	fprintf(stderr,"Generating 512\n");
X	dhparams[0].prime=p0;
X	dhparams[0].generator=g0;
X	if (x=R_GenerateDHParams(&dhparams[0],512,256,&rs))
X		fprintf(stderr,"failed %x\n",x);
X	fprintf(stderr,"Generating 768\n");
X	dhparams[1].prime=p1;
X	dhparams[1].generator=g1;
X	if (x=R_GenerateDHParams(&dhparams[1],768,384,&rs))
X		fprintf(stderr,"failed %x\n",x);
X	fprintf(stderr,"Generating 1024\n");
X	dhparams[2].prime=p2;
X	dhparams[2].generator=g2;
X	if (x=R_GenerateDHParams(&dhparams[2],1024,512,&rs))
X		fprintf(stderr,"failed %x\n",x);
X	fprintf(stderr,"Printing\n");
X	printparams(dhparams);
X	exit(0);
}
X
printparams(dh)
X     R_DH_PARAMS *dh;
{
X	int i,j;
X	
X	printf("#include \"global.h\"\n");
X	printf("#include \"rsaref.h\"\n");
X	for (j=0; j<3; j++) {
X		printf("static unsigned char p%d[] = {\n",j);
X		for (i=0; i < (dh[j].primeLen-1); i++) {
X			printf(" 0x%02x,",dh[j].prime[i]);
X			if (i%6 == 5)
X				printf("\n");
X		}
X		printf(" 0x%02x};\n",dh[j].prime[i]);
X		printf("static unsigned char g%d[] = {\n",j);
X		for (i=0; i < (dh[j].generatorLen-1); i++) {
X			printf(" 0x%02x,",dh[j].generator[i]);
X			if (i%6 == 5)
X				printf("\n");
X		}
X		printf(" 0x%02x};\n",dh[j].generator[i]);
X	}
X	printf("\nR_DH_PARAMS dhparams[3] = {\n");
X	for (j=0; j<3; j++) {
X		printf(" {p%d, %d, g%d, %d}%s\n",j,dh[j].primeLen,
X		       j, dh[j].generatorLen, j==2?"};":",");
X	}
}
X	
SHAR_EOF
  $shar_touch -am 0604160195 'esm_gen.c' &&
  chmod 0644 'esm_gen.c' ||
  echo 'restore of esm_gen.c failed'
  shar_count="`wc -c < 'esm_gen.c'`"
  test 2331 -eq "$shar_count" ||
    echo "esm_gen.c: original size 2331, current size $shar_count"
fi
# ============= dhparams.c ==============
if test -f 'dhparams.c' && test X"$1" != X"-c"; then
  echo 'x - skipping dhparams.c (file already exists)'
else
  echo 'x - extracting dhparams.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'dhparams.c' &&
#include "global.h"
#include "rsaref.h"
static unsigned char p0[] = {
X 0xf1, 0x34, 0xa6, 0x8c, 0xf0, 0xaf,
X 0x4b, 0x5f, 0x9d, 0xaa, 0x13, 0xdc,
X 0x50, 0x2f, 0x80, 0x42, 0xb2, 0x93,
X 0x89, 0x91, 0x47, 0x6e, 0x90, 0x64,
X 0xf5, 0x01, 0x90, 0xed, 0x92, 0x70,
X 0xe5, 0xab, 0xe3, 0x6f, 0x5a, 0x43,
X 0xcf, 0xe2, 0x4f, 0x74, 0x93, 0xcd,
X 0x26, 0x3a, 0x97, 0x0d, 0xaf, 0x74,
X 0x89, 0xb8, 0x9a, 0x8a, 0x26, 0x14,
X 0xd2, 0x22, 0x29, 0x36, 0x0d, 0x91,
X 0x3a, 0x5a, 0xb9, 0xa9};
static unsigned char g0[] = {
X 0x31, 0xc3, 0x07, 0x01, 0xda, 0x60,
X 0x03, 0x71, 0xf6, 0x6a, 0xaf, 0x0f,
X 0x0f, 0x8b, 0x2c, 0xa8, 0x25, 0x5e,
X 0x0f, 0x51, 0x35, 0xc9, 0xb8, 0x83,
X 0xf4, 0xe8, 0x52, 0xf7, 0x4b, 0xe7,
X 0x29, 0x81, 0x4d, 0x76, 0xeb, 0x1d,
X 0xf6, 0x13, 0x79, 0xc6, 0x20, 0x66,
X 0x2b, 0xa8, 0x8a, 0xa1, 0x9a, 0xf5,
X 0xca, 0x51, 0x95, 0x62, 0x31, 0xe4,
X 0x6e, 0x4d, 0xd7, 0x72, 0x41, 0x06,
X 0xe5, 0x13, 0x69, 0xbd};
static unsigned char p1[] = {
X 0xa8, 0x02, 0xf3, 0x46, 0x47, 0xe1,
X 0x42, 0x0a, 0x86, 0xca, 0xe6, 0x4e,
X 0x95, 0xa9, 0xd2, 0xad, 0x90, 0x39,
X 0x53, 0xad, 0x20, 0x88, 0x35, 0x27,
X 0xc1, 0xb9, 0xc1, 0xd2, 0x9a, 0x07,
X 0xde, 0xc8, 0x5d, 0xdd, 0x67, 0x36,
X 0x50, 0xe4, 0xea, 0x2c, 0xb8, 0xf7,
X 0x04, 0xd2, 0xb2, 0x34, 0xc1, 0xdd,
X 0xae, 0x66, 0x20, 0x5f, 0xe3, 0x0b,
X 0xac, 0x3f, 0x7d, 0x47, 0x81, 0xe6,
X 0x57, 0xe8, 0xdf, 0x86, 0x06, 0x8f,
X 0x81, 0xc4, 0x33, 0x71, 0x42, 0x7c,
X 0x9d, 0x87, 0x18, 0x87, 0x7b, 0x81,
X 0x4a, 0xb0, 0x62, 0x19, 0x86, 0xde,
X 0x04, 0xea, 0xa2, 0x1b, 0x25, 0xb3,
X 0xa7, 0x2e, 0x2c, 0xca, 0xe1, 0x3d};
static unsigned char g1[] = {
X 0x80, 0xbb, 0xa6, 0x6e, 0x14, 0x6f,
X 0x8e, 0x34, 0x99, 0x4e, 0x99, 0xde,
X 0xe3, 0xdb, 0x9b, 0x73, 0x02, 0x05,
X 0xcd, 0x37, 0x29, 0x1b, 0xd0, 0x75,
X 0x34, 0x42, 0x93, 0x16, 0x86, 0x21,
X 0x1f, 0x8e, 0x90, 0x77, 0x03, 0xd3,
X 0x1f, 0x06, 0x51, 0x90, 0x01, 0x76,
X 0x48, 0x04, 0x1b, 0xd1, 0x16, 0x68,
X 0x8b, 0x5f, 0x23, 0x4d, 0xe1, 0x41,
X 0x55, 0xa0, 0x03, 0x1c, 0xf7, 0xe4,
X 0x47, 0x8f, 0xea, 0xf1, 0x42, 0x4a,
X 0x04, 0x3b, 0x34, 0x86, 0x08, 0xef,
X 0x55, 0x54, 0x52, 0xa6, 0x91, 0xb3,
X 0x96, 0xcd, 0x09, 0xa8, 0xa2, 0x64,
X 0xd8, 0x14, 0x41, 0x1f, 0xe6, 0x27,
X 0x66, 0x54, 0xf3, 0xfd, 0xd3, 0xe3};
static unsigned char p2[] = {
X 0xfa, 0x18, 0xad, 0x25, 0x10, 0xa2,
X 0x22, 0x5e, 0x00, 0x1e, 0xb7, 0x09,
X 0x80, 0x2c, 0x42, 0x22, 0x74, 0x30,
X 0x5e, 0xbf, 0xfd, 0x11, 0x1b, 0xf9,
X 0xf0, 0x1e, 0x6b, 0x9d, 0x89, 0xfd,
X 0x2c, 0x70, 0x26, 0x96, 0x0a, 0x52,
X 0x11, 0xf1, 0x53, 0x77, 0x37, 0xd1,
X 0xbe, 0x3a, 0x2f, 0x3c, 0xcc, 0x5e,
X 0xc1, 0x89, 0xfd, 0x04, 0x28, 0x5e,
X 0x0f, 0x42, 0xa1, 0x8f, 0x37, 0xa9,
X 0x80, 0xf6, 0x80, 0x7b, 0x59, 0xc5,
X 0x87, 0x3d, 0xf0, 0x80, 0x40, 0x68,
X 0x51, 0x19, 0x74, 0xea, 0x29, 0xe7,
X 0xb6, 0x47, 0x0a, 0x22, 0xaf, 0xc7,
X 0x32, 0xbe, 0x6b, 0x33, 0x64, 0xf2,
X 0x96, 0xd0, 0x00, 0x42, 0xdf, 0x36,
X 0x3b, 0x37, 0x34, 0xac, 0xd3, 0xb9,
X 0x4a, 0x43, 0xde, 0x61, 0x92, 0xd8,
X 0xa7, 0xc4, 0xe2, 0xb2, 0x5a, 0x74,
X 0xc9, 0x89, 0x93, 0xae, 0x84, 0x26,
X 0xb0, 0xd8, 0x8f, 0x1b, 0x74, 0x6d,
X 0x3b, 0x79};
static unsigned char g2[] = {
X 0x62, 0xe0, 0xa7, 0x2a, 0xf4, 0x9e,
X 0x5e, 0xb7, 0x6d, 0xfd, 0x80, 0xd9,
X 0x12, 0x8d, 0xcc, 0x8d, 0xd3, 0xb3,
X 0xf6, 0xf1, 0x2d, 0xb0, 0x38, 0xa3,
X 0x0f, 0xf5, 0x1d, 0x3c, 0x75, 0x24,
X 0xc6, 0x59, 0xc4, 0xb3, 0xe3, 0xbc,
X 0x90, 0x67, 0x83, 0xce, 0xec, 0xa8,
X 0x15, 0x2c, 0x1e, 0x8a, 0x0a, 0x61,
X 0xd2, 0x36, 0x22, 0xa6, 0x2a, 0x43,
X 0xe5, 0x90, 0xac, 0x43, 0x2d, 0xf5,
X 0xbd, 0x96, 0x4e, 0xe6, 0xa4, 0x47,
X 0x4b, 0x2d, 0x8c, 0x4d, 0xd3, 0xd2,
X 0x33, 0x39, 0x1a, 0xf5, 0x4d, 0x11,
X 0xcc, 0xf6, 0x6b, 0xb2, 0x95, 0xaa,
X 0x11, 0x5b, 0xd4, 0x02, 0x60, 0x79,
X 0xbd, 0x68, 0x01, 0x57, 0x5b, 0x98,
X 0x1e, 0x21, 0x04, 0x37, 0x12, 0x5d,
X 0x66, 0x62, 0x07, 0x31, 0x85, 0xc9,
X 0xfa, 0xf1, 0x64, 0xd4, 0x49, 0xfd,
X 0xee, 0xc5, 0x2f, 0x9a, 0x3a, 0x06,
X 0x77, 0x9d, 0x66, 0x69, 0x61, 0xef,
X 0x92, 0x42};
X
R_DH_PARAMS dhparams[3] = {
X {p0, 64, g0, 64},
X {p1, 96, g1, 96},
X {p2, 128, g2, 128}}
;
SHAR_EOF
  $shar_touch -am 0604160195 'dhparams.c' &&
  chmod 0644 'dhparams.c' ||
  echo 'restore of dhparams.c failed'
  shar_count="`wc -c < 'dhparams.c'`"
  test 3870 -eq "$shar_count" ||
    echo "dhparams.c: original size 3870, current size $shar_count"
fi
# ============= esm.h ==============
if test -f 'esm.h' && test X"$1" != X"-c"; then
  echo 'x - skipping esm.h (file already exists)'
else
  echo 'x - extracting esm.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'esm.h' &&
/*
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X */
X
typedef struct {
X	char ek1[128];
X	char ek2[128];
X	char ek3[128];
} keystr;
extern keystr ks;
extern unsigned char check[8];
unsigned int cfb8_encrypt();
unsigned int cfb8_decrypt();
extern R_RANDOM_STRUCT rs;
extern R_DH_PARAMS dhparams[];
extern unsigned char ivin[], ivout[];
extern unsigned char otherpub[];
extern unsigned char ourpub[];
extern unsigned char ourpriv[];
extern int ourprivlen;
extern int pklen;
X
#define SHORT 0
#define MEDIUM 1
#define LONG 2
X
#define MAXPUBKEY 512
SHAR_EOF
  $shar_touch -am 0604160195 'esm.h' &&
  chmod 0644 'esm.h' ||
  echo 'restore of esm.h failed'
  shar_count="`wc -c < 'esm.h'`"
  test 1232 -eq "$shar_count" ||
    echo "esm.h: original size 1232, current size $shar_count"
fi
# ============= cattach.1 ==============
if test -f 'cattach.1' && test X"$1" != X"-c"; then
  echo 'x - skipping cattach.1 (file already exists)'
else
  echo 'x - extracting cattach.1 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cattach.1' &&
X.TH CATTACH 1 ""
X.SH NAME
cattach - attach encrypted directory to CFS
X.SH SYNOPSIS
X.B cattach
[ \-\fBl\fP ]
[ \-\fBt\fP \fIminutes\fP]
[ \-\fBi\fP \fIminutes\fP]
\fIdirectory\fP
\fIname\fP
X.SH DESCRIPTION
\fBcattach\fP associates the encrypted \fIdirectory\fP (previously
created with \fBcmkdir(1)\fP) with the specified \fIname\fP.
\fBcattach\fP prompts for a passphrase, which is used to generate
cryptographic keys sent to the cfs daemon \fBcfsd\fP(8) and used to
transparently encrypt and decrypt the files as needed.  If the correct
passphrase is given (as verified by a known-plaintext hash file in the
encrypted directory), the user may thereafter access the cleartext of
the files in a virtual directory called \fIname\fP under the CFS mount
point (usually /crypt).  Otherwise, no virtual directory is created.
The underlying \fIdirectory\fP may be specified either as an absolute
path or relative to the current directory.
X.LP
The smartcard version of the command is similar in operation, but also
requires a CFS smartcard be present in the smartcard reader.
X.LP
If the \fB-l\fP ("lower security mode") option is given, newly created
identical files will encrypt to identical ciphertexts.  Otherwise, the
creation time plus the inode number of the encrypted file is used to
perturb each file, frustrating certain cryptanalytic attacks.  Under
highly concurrent operation with multiple instances of the same
encrypted directory, however, lower security mode may be required to
avoid some race conditions.  This mode also makes recovery (from
backups) of individual encrypted files a bit simpler.
X.LP
Note that attached virtual directories may be used only by users whose
UID is the same as the issuer of the \fBcattach\fP command.
X.LP
Ordinarily, the names of all currently attached directories can be
obtained by listing the contents of /crypt (e.g., with \fBls\fP(1)).
If the specified \fIname\fP begins with a '.' (dot), however, cfsd
will not include the name in directory listings.  By using a
hard-to-guess \fIname\fP, this mechanism can be used to provide some
protection against attackers who can spoof the UID on the client
machine.  See the \fBssh\fP(1) command for an example of this usage.
X.LP
The \fB-t\fP option causes the attach to automatically go away after
the specified number of minutes.  The \fB-i\fP option deletes the
attach after a specified number of minutes of inactivity.  Note that
these options, if used, should be chosen with some care; too short
timeouts may actually increase the risk of compromise of frequently
re-typed passphrases.
X.LP
Virtual directories should be removed with the \fBcdetach\fP(1)
command when no longer in use.
X.SH EXAMPLES
X.TP
cattach /u/mab/secrets mab
associates encrypted directory "/u/mab/secrets" with the
cleartext name "mab".  Creates virtual directory "/crypt/mab".
X.TP
cattach /u/mab/secrets .123xyzzy
associates encrypted directory "/u/mab/secrets" with the cleartext
name ".123xyzzy".  The cleartext name will not appear in a listing of
/crypt.
X.TP
cattach -l secrets mab
associates the encrypted directory "secrets" in the current directory
with the cleartext name "mab".  Identical files will encrypt to the
same ciphertext.
X.SH FILES
X.TP
/crypt/*
currently attached cleartext instances
X.SH SEE ALSO
cfsd(8), cdetach(1), cmkdir(1), ssh(1)
X.SH BUGS
Really, really slow machines can time out on the RPC before cfsd is
finished processing the attach command, especially when 3-DES is used.
Such machines should probably be considered too slow to be running an
encrypted file system anyway.
X.LP
You can't attach an already encrypted directory, lest the
single-threaded cfsd find itself in a deadlock.
X.LP
There really should be a better security mechanism than the UID to
protect against spoofing currently attached directories.  The .name
hack is an ugly kludge.  In particular, it would be better to limit
access to the process group of the user who issued the cattach
command.  Unfortunately, that information is not passed to cfsd.
X.LP
The timeout isn't perfect, and may occur a minute or two later than
expected.
X.SH AUTHOR
Matt Blaze; for information on cfs, email to cfs@research.att.com.
SHAR_EOF
  $shar_touch -am 1126170394 'cattach.1' &&
  chmod 0644 'cattach.1' ||
  echo 'restore of cattach.1 failed'
  shar_count="`wc -c < 'cattach.1'`"
  test 4169 -eq "$shar_count" ||
    echo "cattach.1: original size 4169, current size $shar_count"
fi
# ============= cdetach.1 ==============
if test -f 'cdetach.1' && test X"$1" != X"-c"; then
  echo 'x - skipping cdetach.1 (file already exists)'
else
  echo 'x - extracting cdetach.1 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cdetach.1' &&
X.TH CDETACH 1 ""
X.SH NAME
cdetach - detach encrypted directory from CFS
X.SH SYNOPSIS
X.B cdetach
\fIname\fP
X.SH DESCRIPTION
\fBcdettach\fP removes the instance called \fIname\fP of an encrypted
directory (created with \fBcattach\fP(1)) from /crypt.  The underlying
encrypted version of the directory remains, of course, and may be
attached again when needed with \fBcattach\fP(1).
X.SH EXAMPLE
X.TP
cdetach mab
deletes /crypt/mab
X.SH SEE ALSO
cfsd(8), cattach(1)
X.SH BUGS
Anyone can cdetach anything, even directories attached by other users.
This can lead to irritating denial-of-service attacks.
X.SH AUTHOR
Matt Blaze; for information on cfs, email to
cfs@research.att.com
SHAR_EOF
  $shar_touch -am 0101143494 'cdetach.1' &&
  chmod 0644 'cdetach.1' ||
  echo 'restore of cdetach.1 failed'
  shar_count="`wc -c < 'cdetach.1'`"
  test 672 -eq "$shar_count" ||
    echo "cdetach.1: original size 672, current size $shar_count"
fi
# ============= cmkdir.1 ==============
if test -f 'cmkdir.1' && test X"$1" != X"-c"; then
  echo 'x - skipping cmkdir.1 (file already exists)'
else
  echo 'x - extracting cmkdir.1 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cmkdir.1' &&
X.TH CMKDIR 1 ""
X.SH NAME
cmkdir - create encrypted directory for CFS
X.SH SYNOPSIS
X.B cmkdir
[ \-\fB3mo\fP ]
\fIdirectory\fP
X.SH DESCRIPTION
\fBcmkdir\fP creates \fIdirectory\fP and assigns to it cryptographic
keys for use by the Cryptographic File System (CFS).  Operation is
similar to the ordinary \fBmkdir\fP(1) command, with the addition that
the user is prompted for a passphrase which is used to generate the
DES keys used by cfsd(8) to transparently encrypt the files.  The
smartcard version of \fBcmkdir\fP initializes a key smartcard and
requires that a blank smartcard be inserted into the smartcard reader.
X.LP
Once created, encrypted directories can be made available for use with
the \fBcattach\fP(1) command.  Users should not ordinarily read and
write directly to directories created with \fBcmkdir\fP, since these
files would not be stored in encrypted form.
X.LP
By default, \fBcmkdir\fP creates directories for 2-key hybrid mode
single DES.  The \-\fB3\fP option specifies 2-key hybrid mode triple
DES; this is more secure, albiet at the expense of performance.  Other
ciphers may also be available, depending on the local configuration.
X.LP
Use the -o option to create directories that can be read by versions
of CFS before 1.3; directories created under this option can be read
by
X.B cname
and
X.B ccat
as well.
X.LP
A new experimental block cipher is included in the default
distribution.  The \-\fBm\fP option specifies Blaze and Schneier's
"MacGuffin" cipher.  It has 32 rounds, a 64 bit codebook size and a
128 bit nominal keyspace.  Use this cipher at your own risk; it may be
much weaker than its keyspace suggests.
X.SH FILES
X.TP
\fIdirectory\fP/...
known-plaintext hash of the assigned keys.
X.TP
\fIdirectory\fP/..c
identifies the cipher algorithm.
X.SH SEE ALSO
cfsd(8), cattach(1)
X.SH BUGS
The MacGuffin cipher isn't nearly as well-studied as DES.  It is
included primarly as an example.  The author's personal files remain
protected with DES.
X.SH AUTHOR
Matt Blaze; for information on cfs, email to cfs@research.att.com.
SHAR_EOF
  $shar_touch -am 0722231295 'cmkdir.1' &&
  chmod 0644 'cmkdir.1' ||
  echo 'restore of cmkdir.1 failed'
  shar_count="`wc -c < 'cmkdir.1'`"
  test 2047 -eq "$shar_count" ||
    echo "cmkdir.1: original size 2047, current size $shar_count"
fi
# ============= ssh.1 ==============
if test -f 'ssh.1' && test X"$1" != X"-c"; then
  echo 'x - skipping ssh.1 (file already exists)'
else
  echo 'x - extracting ssh.1 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'ssh.1' &&
X.TH SSH 1 ""
X.SH NAME
ssh - (somewhat) secure CFS shell
X.SH SYNOPSIS
X.B ssh
\fIdirectory\fP
X.SH DESCRIPTION
\fBssh\fP uses \fBcattach\fP(1) to associate the encrypted
\fIdirectory\fP (previously created with \fBcmkdir\fP(1)) with a
randomly selected name.  Once the correct passphrase is provided,
\fBssh\fP invokes a new shell with the random directory in /crypt as its
working directory.
When the shell exits, the temporary attach name is deleted with
cdetach(1).
Since the generated names are somewhat obscure and are hidden from
view with CFS's "." mechanism, casual attackers cannot easily exploit
the attached cleartext even if they can spoof the UID of the user.
X.LP
This command assumes the Korn Shell is installed as /bin/ksh.
X.SH SEE ALSO
cfsd(8), cattach(1), cdetach(1), cmkdir(1)
X.SH BUGS
The temporary names generated are not random in any cryptographically
strong sense, so this command should really only be viewed as an
example.  A determined attacker could probably guess the generated
name by exploiting the known properties of the way the ksh random
function is seeded.
X.LP
There's no hiding from an attacker who can compromise root on the
client system while an attach is active.
X.SH AUTHOR
Matt Blaze; for information on cfs, email to
cfs@research.att.com.
X
SHAR_EOF
  $shar_touch -am 0101143594 'ssh.1' &&
  chmod 0644 'ssh.1' ||
  echo 'restore of ssh.1 failed'
  shar_count="`wc -c < 'ssh.1'`"
  test 1279 -eq "$shar_count" ||
    echo "ssh.1: original size 1279, current size $shar_count"
fi
# ============= cfsd.8 ==============
if test -f 'cfsd.8' && test X"$1" != X"-c"; then
  echo 'x - skipping cfsd.8 (file already exists)'
else
  echo 'x - extracting cfsd.8 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cfsd.8' &&
X.TH CFSD 8 ""
X.SH NAME
cfsd - cryptographic file system daemon
X.SH SYNOPSIS
X.B cfsd
X.SH DESCRIPTION
\fBcfsd\fP is the user-level daemon for the Cryptographic File System
(CFS).  It is essentially an RPC server for the NFS protocol augmented
with the CFS_ADMIN protocol.  It listens on the CFS port (ordinarily
port 3049) on the \fBlocalhost\fP interface.
X.LP
The main function of \fBcfsd\fP is to manage the keys for currently
attached encrypted directories, presenting them in clear form under
the CFS mount point (typically "/crypt").
X.LP
\fBcfsd\fP should ordinarily be invoked at boot time from /etc/rc
(or /etc/rc.local).  The rc file should also start
\fBmountd\fP(8) daemon with least one file system exported to
localhost; note that cfsd itself does not handle the mount protocol.
Once a mountd is running, the mount(8) command should be invoked to
mount the exported file system from the localhost interface with
port=3049.
X.SH EXAMPLES
X.TP
/usr/local/etc/cfsd
invokes cfs (in /etc/rc)
X.TP
/etc/mount -o port=3049,intr localhost:/ /crypt
mounts cfs on /crypt (in /etc/rc)
X.SH FILES
X.TP
/crypt
cfs mount point
X.TP
/etc/exports
exported file systems
X.SH SEE ALSO
cattach(1), cdetach(1), mountd(8), mount(8)
X.SH BUGS
\fBcfsd\fP is single threaded, which means it doesn't handle lots of
simultanious operations very well.  In particular, it is not possible
to recursively attach encrypted directories, since that would lead to
a deadlock.
X.SH AUTHOR
Matt Blaze; for information on cfs, email to
cfs@research.att.com.
X
SHAR_EOF
  $shar_touch -am 0101143594 'cfsd.8' &&
  chmod 0644 'cfsd.8' ||
  echo 'restore of cfsd.8 failed'
  shar_count="`wc -c < 'cfsd.8'`"
  test 1523 -eq "$shar_count" ||
    echo "cfsd.8: original size 1523, current size $shar_count"
fi
# ============= cname.8 ==============
if test -f 'cname.8' && test X"$1" != X"-c"; then
  echo 'x - skipping cname.8 (file already exists)'
else
  echo 'x - extracting cname.8 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cname.8' &&
X.TH CNAME 8 ""
X.SH NAME
cname
X.SH SYNOPSIS
X.B cname
[ \-\fB3m\fP ]
[ \-\fBv\fP ]
X.SH DESCRIPTION
\fBcname\fP prompts for a passphrase and reads, from standard input, a
list of CFS encrypted file names (e.g., "51051f97e31613b7").  It
produces, on standard output, a corresponding list of cleartext names.
By default, names are decrypted using standard 2-key hybrid mode
single-DES.  The \-\fB3\fP option specifies 2-key hybrid mode triple
DES.  \-\fBm\fP specifies 2-key hybrid MacGuffin. The \-\fBv\fP option
includes the ciphertext names in the output.
X.LP
All names must be specified one per input line, as individual path
components (full path names are not accepted).  If a name cannot be
decrypted to printable characters, "???" is printed in its place.
This is the only way to detect an incorrect passphrase.
X.LP
\fBcname\fP is intended to assist in making sense of CFS directories
when no CFS daemon is available.  It is also useful in locating files
from backups.
X.SH SEE ALSO
ccat(8)
X.SH BUGS
Does not work with new format (1.3 and later) directories.
X.LP
The program is easily confused by slightly wrong input.  It would be
better if it could transparently translate the output from other
programs such as ls(1), tar(1) and dump(8).
X.SH AUTHOR
Matt Blaze; for information on cfs, email to cfs@research.att.com.
X
SHAR_EOF
  $shar_touch -am 0722231395 'cname.8' &&
  chmod 0644 'cname.8' ||
  echo 'restore of cname.8 failed'
  shar_count="`wc -c < 'cname.8'`"
  test 1322 -eq "$shar_count" ||
    echo "cname.8: original size 1322, current size $shar_count"
fi
# ============= ccat.8 ==============
if test -f 'ccat.8' && test X"$1" != X"-c"; then
  echo 'x - skipping ccat.8 (file already exists)'
else
  echo 'x - extracting ccat.8 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'ccat.8' &&
X.TH CCAT 8 ""
X.SH NAME
ccat
X.SH SYNOPSIS
X.B ccat
[ \-\fB3m\fP ]
\fIfile\fP
[ ... ]
X.SH DESCRIPTION
\fBccat\fP prompts for a passphrase and decrypts (onto standard
output) the specified CFS encrypted files.  If a corresponding CFS IV
file (.pvect_*) file exists in the same directory, it is used to
perturb the file accordingly.  By default, files are decrypted using
standard 2-key hybrid mode single-DES.  The \-\fB3\fP option specifies
2-key hybrid mode triple DES.  The \-\fBm\fP option specifies 2-key
hybrid mode MacGuffin.
X.LP
\fBccat\fP is intended to assist in emergency access to CFS
directories when no machine running a CFS daemon is available.  It is
ordinarily used in conjunction with cname(8).
X.SH SEE ALSO
cname(8)
X.SH BUGS
Does not work with new format (1.3 and later) directories.
X.LP
This program is just blindingly slow.  There's no way to tell if an
incorrect passphrase was entered, except that the program will produce
garbage output.
X.SH AUTHOR
Matt Blaze; for information on cfs, email to cfs@research.att.com.
X
SHAR_EOF
  $shar_touch -am 0722231495 'ccat.8' &&
  chmod 0644 'ccat.8' ||
  echo 'restore of ccat.8 failed'
  shar_count="`wc -c < 'ccat.8'`"
  test 1037 -eq "$shar_count" ||
    echo "ccat.8: original size 1037, current size $shar_count"
fi
# ============= cpasswd.1 ==============
if test -f 'cpasswd.1' && test X"$1" != X"-c"; then
  echo 'x - skipping cpasswd.1 (file already exists)'
else
  echo 'x - extracting cpasswd.1 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'cpasswd.1' &&
X.TH CPASSWD 1 ""
X.SH NAME
cpasswd - change passphrase on cfs directory
X.SH SYNOPSIS
X.B cpasswd
\fIdirectory\fP
X.SH DESCRIPTION
\fBcpasswd\fP changes the passphrase associated with a
Cryptographic File System (CFS) directory.  \fBcpasswd\fP prompts for
the old passphrase, and, if it is correct, a new passphrase, which
must be entered twice.  Passphrases must contain at least a minimum
number of characters (currently 16).
X.LP
Only new format (CFS 1.3 or later) directories can have their
passphrases changed.
X.SH FILES
X.TP
\fIdirectory\fP/...
known-plaintext hash of the assigned keys.
X.TP
\fIdirectory\fP/..c
identifies the cipher algorithm.
X.TP
\fIdirectory\fP/..k
encrypted key file
X.SH SEE ALSO
cfsd(8), cattach(1), cmkdir(1)
X.SH BUGS
One passphrase per encrypted directory; there is no provision (yet)
for individual users' passphrases.
X.SH AUTHOR
Matt Blaze; for information on cfs, email to cfs@research.att.com.
SHAR_EOF
  $shar_touch -am 0728024395 'cpasswd.1' &&
  chmod 0644 'cpasswd.1' ||
  echo 'restore of cpasswd.1 failed'
  shar_count="`wc -c < 'cpasswd.1'`"
  test 922 -eq "$shar_count" ||
    echo "cpasswd.1: original size 922, current size $shar_count"
fi
# ============= README ==============
if test -f 'README' && test X"$1" != X"-c"; then
  echo 'x - skipping README (file already exists)'
else
  echo 'x - extracting README (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README' &&
This is version 1.3.0 of CFS, the Cryptographic File System, which
also includes version 1.0 of ESM, the Encrypting Session Manager.
X
There is a mailing list, cfs-users, for discussion of topics of
interest to CFS and ESM users and developers.  To subscribe:
X        echo subscribe cfs-users | mail cfs-users-request@research.att.com
You will automatically receive a "welcome" message confirming that you
have been added to the list.
X
For installation instructions, see the files "README.install",
"notes.ms" and "README.esm".
X
-Matt Blaze
X
THIS SOFTWARE IS SUBJECT TO EXPORT CONTROLS.  See the README.install file
for distribution restrictions.
SHAR_EOF
  $shar_touch -am 0722203095 'README' &&
  chmod 0644 'README' ||
  echo 'restore of README failed'
  shar_count="`wc -c < 'README'`"
  test 646 -eq "$shar_count" ||
    echo "README: original size 646, current size $shar_count"
fi
# ============= README.install ==============
if test -f 'README.install' && test X"$1" != X"-c"; then
  echo 'x - skipping README.install (file already exists)'
else
  echo 'x - extracting README.install (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README.install' &&
This is version 1.2.beta of CFS
X
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1992, 1993, 1994, 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.  You may
X * not export it, in whole or in part, or cause or allow such export,
X * through act or omission, without prior authorization from the United
X * States government and written permission from AT&T.  In particular,
X * you may not make any part of this software available for general or
X * unrestricted distribution to others, nor may you disclose this software
X * to persons other than citizens and permanent residents of the United
X * States and Canada. 
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X
Release notes and general installation instructions are in the 
file "notes.ms".  You can use troff -ms to print it.  READ notes.ms
BEFORE YOU TRY TO INSTALL CFS.
X
Instructions for people who can't stand the idea of reading release notes:
X
To install from scratch:
X
1a) read notes.ms
1b) make sure you're running nfs and sunos or bsd4.4.  good luck if you have
something else.
1c) make sure that you understand that this is completely unsupported software.
we can't help you install it or configure it.  we also can't help you
or be in any way responsible if cfs obliterates your files beyond
recognition.
1d) edit the Makefile for your local configuration
X
2) type "make cfs".
X
3) become root, and type "make install_cfs".
X
4) create the cfs bootstrap mount point:
X	mkdir /null
X	chmod 0 /null
X
5) add this line to /etc/exports:
X
/null localhost
X
6) mkdir /crypt (or whatever you want to call the cfs mount point)
X
7) add this to the end of /etc/rc.local:
X
if [ -x /usr/local/etc/cfsd ]; then
X	/usr/local/etc/cfsd && \
X		/etc/mount -o port=3049,intr localhost:/null /crypt
fi
X
7a) on some platforms (especially BSDI), you may get better CFS
performance with a smaller mount blocksize:
if [ -x /usr/local/etc/cfsd ]; then
X   /usr/local/etc/cfsd && \
X      /etc/mount -o port=3049,intr,rsize=2048,wsize=2048 localhost:/null /crypt
fi
X
X
8) run the commands in step 7 by hand to get it started now.  you may have to
do an "exportfs -a" and/or /etc/rpc.mountd first if you aren't already running
an NFS server, but this will be done automatically at boot time from now on.
X
9) if any of this fails, go back and read notes.ms.
X
Notes:
X
If you already have cfs, this version may not be compatable with the
encryption format used by your old copy.  If you have encrypted directories
created under previous versions of cfs that you want to save, tar them
out to a plaintext file under your existing cfsd prior to installing
the new version.  See the README.history file for details.
X
To install a new version, first cdetach any directories in the cfs mount
point (/crypt/*).  Then (as root) do a make install_cfs, and restart cfsd. 
You need not unmount and remount /crypt, although you may see a few stale
file handle errors in any processes with open references to /crypt.
X
For information on ESM, see README.esm.
X
Problems -> cfs@research.att.com.  But READ THE MANUAL first.
SHAR_EOF
  $shar_touch -am 0723000095 'README.install' &&
  chmod 0644 'README.install' ||
  echo 'restore of README.install failed'
  shar_count="`wc -c < 'README.install'`"
  test 3622 -eq "$shar_count" ||
    echo "README.install: original size 3622, current size $shar_count"
fi
# ============= README.history ==============
if test -f 'README.history' && test X"$1" != X"-c"; then
  echo 'x - skipping README.history (file already exists)'
else
  echo 'x - extracting README.history (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README.history' &&
CFS revision history:
X
1.3.0 - Some minor bug fixes.  Adds SHS-based key hash and indirect
keys.  Includes ESM package.  Much left to do.
X
1.2.1 - Fixes 3DES to make key caching work properly.  Fixed a few
things to make porting easier.  Compatible with 1.2.0.
X
1.2.0 - Fixes various minor bugs.  Adds MacGuffin cipher.  Adds
timeout (-it) options to cattach.  DES ciphers compatible with 1.1.2.
X
1.1.2 - Fixes hanging open on cdetach bug.  Bolsters security against
portmapper bug.  Adds cname and ccat tools.  Compatible with 1.1.1.
X
1.1.1 - Fixes cattach to use low-level client RPC interface for proper
AUTH_UNIX information.  Adds code in cfs_fh.c to fix HPUX "cp" problem.
Compatible with 1.1.0.
X
1.1.0 - Adds 3DES, hooks for other ciphers and merges in various
user-contributed ports and bug fixes.  Compatible with 1.0.4, plus adds
new cipher format.
X
1.0.4 - Fixes Sun append bug.  Compatible with 1.0.3.
X
1.0.3 - Fixes awful key generation bug introduced when removing smartcard
stuff.  Cipher not compatible with previous releases.
X
1.0.2 - Adds user-contributed ports.  Compatible with 1.0.1.
X
1.0.1 - First public release; no smartcard support.
SHAR_EOF
  $shar_touch -am 0724191095 'README.history' &&
  chmod 0644 'README.history' ||
  echo 'restore of README.history failed'
  shar_count="`wc -c < 'README.history'`"
  test 1158 -eq "$shar_count" ||
    echo "README.history: original size 1158, current size $shar_count"
fi
# ============= notes.ms ==============
if test -f 'notes.ms' && test X"$1" != X"-c"; then
  echo 'x - skipping notes.ms (file already exists)'
else
  echo 'x - extracting notes.ms (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'notes.ms' &&
X.TL
CFS Version 1.3
Installation and Operation
X.AU
Matt Blaze
X.AI
AT&T Bell Laboratories
101 Crawfords Corner Road, Room 4G-634
Holmdel, NJ 07733
X
mab@research.att.com
(for cfs questions, use cfs@research.att.com)
X
X.NH
General
X.PP
CFS pushes encryption services into the Unix(tm) file system.  It
supports secure storage at the system level through a standard Unix
file system interface to encrypted files.  Users associate a
cryptographic key with the directories they wish to protect.  Files in
these directories (as well as their pathname components) are
transparently encrypted and decrypted with the specified key without
further user intervention; cleartext is never stored on a disk or sent
to a remote file server.  CFS employs a novel combination of DES
stream and codebook cipher modes to provide high security with good
performance on a modern workstation.  CFS can use any available file
system for its underlying storage without modification, including
remote file servers such as NFS.  System management functions, such as
file backup, work in a normal manner and without knowledge of the key.
X.PP
CFS as distributed runs under SunOS and, with a little coaxing,
several other BSD-derived systems including BSD/386.  It has also
been ported by users to Solaris, Ultrix, Linux, and several other popular
OSs, but is unlikely to work on such systems "out of the box".
"#ifdefs" for most of these systems are included in the distribution;
see the Makefile for compilation details.  User-contributed patches for
porting CFS to platforms not included in the distribution are made available
in the CFS-USERS mailing list archive.  You should check the archive
before undertaking a major porting effort.  (Of course, I encourage you
to share any ports, patches or enhancements you develop.)
X.PP
CFS runs entirely at user level, as a local NFS server running on the
client machine's "loopback" interface.  The system consists of
X.B
cfsd
X.R
(the CFS server daemon), and a small suite of tools
X.B
(cmkdir, cattach, cdetach,
X.R
and
X.B
ssh)
X.R
that create encrypted directories and manage keys as they are used.
CFS, and the motivation and principles behind it, is described in
detail in:
X.IP
Matt Blaze, "A Cryptographic File System for Unix."
X.I
Proc. 1st ACM Conference on Computer and Communications Security,
X.R
Fairfax, VA, November 1993.
X.PP
Another paper describes a key management scheme for CFS that, while
not included in this distribution, may be of interest.
X.IP
Matt Blaze, "Key Management in an Encrypting File System."
X.I
Proc. USENIX Summer 1994 Technical Conference,
X.R
Boston, MA, June 1994.
X.PP
The CFS distribution also includes "ESM", an encrypting session
manager that allows shell-to-shell encrypted sessions across insecure
network links.  It is described in the
X.B "README.esm"
file in the distribution directory and in more detail in the paper
X.IP
Matt Blaze and Steve Bellovin. "Session-layer Encryption."
X.I
Proc. 1995 USENIX Security Workshop,
X.R
Salt Lake City, June 1995.
X.PP
These papers are available for anonymous ftp from research.att.com, in
the files /dist/mab/cfs*.ps and /dist/mab/sesscrypt.ps.  You should
read them before attempting to install and use CFS.  Details on the
usage of each of the CFS commands (cattach, etc.) can be found in the
man pages included in this distribution.  You can print them with
troff -man, and should install them wherever local man pages go on
your system.
X.PP
Basically, CFS provides a mechanism to associate "real" directories
(on other file systems) that contain encrypted data with temporary
"virtual" names through which users can read and write cleartext.
These virtual names appear under the CFS mount point, which is usually
called /crypt (this document assumes that convention).  Users create
encrypted directories on regular file systems (e.g., in their home
directories) using the
X.B cmkdir
command, which creates the directory and assigns to it a cryptographic
"passphrase" which will be used to encrypt its contents.  To actually
use an encrypted directory, it must be "attached" to CFS using the
X.B cattach
command, which asks for the passphrase and installs an association
between the "real" directory and a temporary name under /crypt.
Cleartext is read and written under the virtual directory in /crypt,
but the files are stored in encrypted form (with encrypted names) in
the real directory.  When the directory is not in use, the association
is removed with the
X.B cdetach
command, which deletes the cleartext virtual directory under /crypt
(but not the ciphertext files, of course).  When CFS is run on a
client workstation, the cleartext data (and the cryptographic key
passphrase) are never stored on a disk or sent over a network, even
when the real directory is located on a remote file server.
(Actually, the virtual memory system can theoretically violate this
rule; see the "Internals" section, below.)
X.PP
CFS is implemented as a server, called
X.B cfsd,
for the Sun Network File System (NFS) protocol plus extensions for
associating keys with directories.  cfsd monitors the localhost
virtual network interface for remote procedure call requests from the
local machine.  Once the local machine invokes an NFS "mount" on the
localhost interface for the CFS mount point (/crypt), cfsd handles
file system operations for the mounted file system as if it were a
remote file server.  Initially, /crypt appears completely empty.  The
user interface programs (such as the
X.B cattach
command) send RPCs to cfsd giving the information required to manage
the attached virtual directories that appear under /crypt (e.g., what
name to use, what key to use, the name of the directory on the real
file system, etc.).
X.NH 2
License
X.IP
X.ce 9999
Copyright (c) 1992, 1993, 1994 by AT&T.
X.ce 0
X.IP
Permission to use, copy, and modify this software without fee
is hereby granted, provided that this entire notice is included in
all copies of any software which is or includes a copy or
modification of this software and in all copies of the supporting
documentation for such software.
X.IP
This software is subject to United States export controls.  You may
not export it, in whole or in part, or cause or allow such export,
through act or omission, without prior authorization from the United
States government and written permission from AT&T.  In particular,
you may not make any part of this software available for general or
unrestricted distribution to others, nor may you disclose this software
to persons other than citizens and permanent residents of the United
States and Canada. 
X.IP
THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X.PP
Please abide by the restrictions in the above license agreement.  The
limitations on distribution are there to meet legal requirements that
are taken quite seriously by the government and by AT&T's lawyers.  If
you violate them, you risk creating all sorts of unpleasantness for
yourself and for others (e.g., me).  If the export requirements are
not generally abided by, it will also make it increasingly difficult
to release future such efforts.
X.PP
It would be a good idea to check with me before including CFS as part
of some other software distribution.
X
X.NH
Installation
X.PP
CFS was developed under SunOS 4.1.2 and BSD/386 (BSDI).  I have not
tested it, or even compiled it, on
X.I any
other platforms.  If you are interested in porting it to something
different, such as SYSV or whatever, you should first
get it running under one of the known configurations so that you know
what to expect and are sure you have the complete system.  You should
also read and understand the "Internals" section below.  The rest of
this section assumes you are using one of the known systems.  I'm afraid
we do not have the resources to help you install or port CFS; you're
on your own.
X.PP
The system is designed to be installed on individual single-user
workstations.  You really should not install (or use) it on a shared
file or compute server, even though such a configuration is
technically possible.  There are three main reasons for this.  First,
CFS trades off encryption speed for memory by precomputing large
stream ciphers for each attached directory.  While this is usually
fine for a small number of attaches, more than four or five at a time
can quickly reduce a system to thrashing.  Furthermore, cfsd is
single-threaded, and therefore does not handle many concurrent I/O
operations very well.  Second, any time an attach is active, an
attacker who can log in to the target system and spoof either the UID
of the legitimate user or "root" can potentially compromise the
cleartext or learn the key by examining the address space of the cfsd
process.  Finally, if the connection between the user and the machine
running CFS is compromised (e.g., by watching the Ethernet traffic
between a terminal server and the host), an attacker can potentially
observe the the entire dialog between the user and CFS, including any
passphrases given to cattach and any cleartext written to /crypt.  In
fact, most successful attacks on cryptographically strong systems do
not attack the encryption scheme at all, but instead rely on poorly
managed installation, key management, and usage protocols.  Be sure
your users understand what parts of the system they are trusting
before CFS is used to protect sensitive data.
X.PP
CFS is a user-level NFS server.  It does not, however, include the
X.I mount
protocol, so you'll also need to have /etc/mountd (sometimes called
/usr/etc/rpc.mountd) installed on your system.  You will need the
ability to become "root" on the target machine.
X.PP
To install, first edit the Makefile for your local configuration.
Everything you should have to edit is toward the beginning of the
file.  Make sure BINDIR and ETCDIR are set to the correct directories.
Check the LIBS and COMPAT variables; for SunOS, these should be empty,
but other systems may require -lrpc and -lcompat.  CFLAGS should be
just -O for SunOS.  If you're running a variant of BSD4.4, add
-DBSD44.  To support the BSD4.4 filesystem's short symbolic links (the link
pointer is kept in the directory inode), add -DSHORTLINKS.
If your client system does not put NFS requests on a
privileged port, add -DANYPORT.  (If you set ANYPORT, note that any
logged in user can fairly easily spoof any currently attached user's
files, so this is another reason not to run CFS on a multi-user
machine.)  If your system does not support NFS mounts on ports other
than 2049, add -DCFS_PORT=2049; you will not be able to simultaneously
run the target system as an NFS server under this configuration.
X.PP
Now type "make cfs".  If everything compiles correctly, become root
and do a "make install_cfs".  Now start up /usr/local/etc/cfsd (as
root); you should see "cfs ready" with the PID of the daemon.
X.PP
You'll need a "bootstrap" mount point exported to localhost.  Note
that exporting file systems to localhost is somewhat dangerous; there
is a bug in most versions of the portmapper that can allow remote
access to such file systems.  In order to get CFS running, however,
you need something to provide a file handle for the "root" of the CFS
file system.  To play it safe, I suggest exporting an empty mode 000
directory.  It is used only to get CFS mounted by your local NFS
client code.  If your version of the portmapper doesn't support remote
RPC forwarding, or if you don't have a regular NFS server running on
your machine, or if you already have a file system exported to
localhost for some other purpose, you can use a "real" file system
(such as /) for this purpose.  Note that most versions of mount do not
allow you to export more than one mount point on a given file system.
X.DS
# mkdir /null
# chmod 0 /null
X.DE
X.PP
Now create the real CFS mount point (mkdir /crypt); it should be mode
755.  Edit /etc/exports to export the bootstrap file system to
localhost, e.g.:
X.DS
/null localhost
X.DE
and make sure mountd is running and sees it (you may have to start up
mountd by hand or do a "/etc/exportfs -a").  If you're using a
different file system as the bootstrap mountpoint, use that in place
of /null in the mount command below.
X.PP
Now you should be able to mount CFS just as you would a remote NFS
server:
X.DS
# /etc/mount -o port=3049,intr localhost:/null /crypt
X.DE
(omitting the "port=3049" part if your local system does not support
that option).
X.PP
If all goes well, you should be able to ls /crypt, and you should see
localhost:/ as a mounted NFS server, e.g.:
X.DS
# /etc/mount
\fI[other stuff]\fP
localhost:/null on /crypt type nfs (port=3049,intr,rw)
# 
X.DE
X.PP
Test CFS by cmkdir'ing and cattach'ing a sample directory.  A good
test is to copy the distribution sources into your CFS directory and
make them there; compare the resulting binaries and attempt to run the
user commands (like cmkdir) from there.
X.PP
Now edit /etc/rc.local to automatically start all this up at boot
time after mountd is started up.  I use:
X.DS
if [ -x /usr/local/etc/cfsd ]; then
X   /usr/local/etc/cfsd && \\
X      /etc/mount -o port=3049,intr localhost:/null /crypt
fi
X.DE
Note that if you are using a system that does not allow ports other
than 2049 for NFS, you'll have to make sure the rc file starts up
mountd but
X.I not
any nfsd processes.  The default behavior of the rc files on most NFS
systems checks for the existence of /etc/exports and starts both
mountd and nfsd if it's there; you'll have to edit out any lines that
try to start up nfsd on such systems.
X.PP
On some platforms (especially BSDI), you may find that CFS performance
improves dramatically if you set the NFS mount block size to a smaller
value than the default.  2048 is usually about right:
X.DS
if [ -x /usr/local/etc/cfsd ]; then
X   /usr/local/etc/cfsd && \\
X      /etc/mount -o port=3049,intr,rsize=2048,wsize=2048 localhost:/null /crypt
fi
X.DE
X.PP
If any of this fails, recheck the configuration in the Makefile and
make sure all of the appropriate options are there.  If you get
"permission denied" when you try to ls /crypt, you probably need
-DANYPORT in CFLAGS.
X.PP
A "timeout" feature is available to automatically detach directories,
either after being attached for longer than some period or after a
specified period of inactivity.  The absolute and inactivity timeouts
are specified with the "-t" and "-i" options to cattach, respectively.
X
X.NH
Internals	
X.PP
The public CFS distribution differs a bit from the version described
in the ACM COCCS paper.  First of all, smartcard support is not
included; all keys must be managed via passphrases.  Some of the
interfaces to the various programs are a bit different as well.
X.PP
On the upside, the DES-based encryption scheme has been considerably
strengthened.  At attach time, CFS divides the passphrase into two DES
keys, K1 and K2.  K1 is used to create two DES pseudorandom stream
ciphers, each 128KB long, S1 and S2.  To encrypt a file block, it is
first XORd against a unique bitstream derived from the inode number of
the file.  The result is then XORd against S1 based on its offset
in the file.  This is then DES ECB encrypted with K2, and the result
of that is XORd against the appropriate position in S2.  The resulting
ciphertext is what is stored.  The cipher is reversed in the obvious
manner.  Filenames are similarly encrypted.
X.PP
There does not appear to be a feasible attack that allows an
independent search for the two subkeys K1 and K2; in a known-plaintext
attack, an attacker would have to try all 2**112 key combinations.
Note that the two keys may be vulnerable to independent exhaustive
search under a so-called "linear" attack, but this attack appears to
require a large number of chosen plaintexts encrypted under the same
inode number.  Under most conditions where the attacker cannot
introduce large numbers of chosen plaintexts, I believe CFS encryption
to be very strong in practice.  Note that this is not the same as a
"proof".  In any event, CFS is always at least as secure as 1-DES.  If
you are willing to trade off a great deal of performance, you can use
3-DES directly.
X.PP
A true 3-DES (2 key) mode is now available in this release; this mode
uses the same hybrid stream/codebook scheme as above, but encrypts
both the static stream and the individual cipherblocks three times
(with the two passphrase-derived subkeys).  This mode is more
"standard" and is probably stronger than the default cipher mode, but
at considerable performance expense.  To get true 3-DES, specify "-3"
with \fBcmkdir\fP.  Keep in mind that the limited entropy of most
user-selected key passphrases represents a much greater practical
threat than a direct attack against even single DES.
X.PP
A new experimental block cipher, called "MacGuffin" and designed by
Bruce Schneier and I, is also included in this release.  You can use
it by including the "-m" option to cmkdir.  This cipher is strictly
experimental, and I do not yet suggest its use for protecting
sensitive data.  It is included only to encourage analysis and testing
and to provide a demonstration of how to link in new ciphers to CFS.
It should be assumed to be weaker than DES.  The cipher has a nominal
keyspace of 128 bits, 32 rounds and a standard 64 bit codebook
interface.  It is described in:
X.IP
Matt Blaze and Bruce Schneier, "The MacGuffin Block Cipher Algorithm."
X.I
Proc. 2nd Workshop on Cryptographic Algorithms,
X.R
Leuven, Belgium, December 1994.
X.PP
CFS 1.3 now stores keys in a "keyfile" in the encrypted directory,
using the initial passphrase as seed key material and to encrypt the
keyfile.  This allows you to change the passphrase without re-creating
copying the directory (see cpasswd(1)).  A future release of CFS will
allow multiple users of the same CFS directories to have their own
passphrases.
X.PP
CFS semantics should be roughly the same as those of any other
NFS-mounted file system, with a couple of minor differences.  Because
of the encoding of pathnames as hex strings, path components are
limited to half the normal size and full pathnames can only be about
half as long as the normal maximum.  Also, holes in files (created by
writing beyond the current end of file) are filled in with random
garbage rather than zeros.  This does not appear to break any standard
applications, although some program somewhere might depend on this
property.  CFS does not support special files or named pipes.
X.PP
NFS attribute caching can confuse CFS under certain conditions.  In
particular, if you create a directory, copy something into it and
immediately rename rename the directory, the directory's contents may
not be visible until the client attribute cache times out and the file
handles for the existing files are looked up again.  Cache update
typically takes 30 seconds in the worst case, and seems to be a
problem most often under Linux.  The inconsistencies are only rarely
noticeable under typical workloads and do not lead to any actual
corruption of stored data.  If it bothers you, turn off attribute
caching by adding the "noac" option to the /crypt mount command.  Note
that this option may affect performance.
X.PP
To enhance portability, CFS now stores the IV derived from the inode
in a separate file rather than in the gid of the file.  This is done
using an ugly hack that involves creating a symbolic link that points
to a string containing the IV.  Under highly concurrent operation with
multiple machines creating files in the same encrypted directories,
there may be some undetected race conditions here.  Having separate
IVs for each file can be disabled with the "-l" option to
X.B cattach;
under this option, identical files will encrypt to the same
ciphertext.
X.PP
I think CFS is secure against most non-cryptanalytic attacks,
especially on a single-user machine, but there are a few weak areas of
which you should be mindful.  If your system pages to an untrusted
disk, cfsd could leak cleartext and keys to the paging device.  It is
best to be sure you have sufficient real memory on the client system
to avoid this.  Unfortunately, I know of no portable way to prevent a
user process from paging.  Also, an error in cfsd could cause a
coredump to an untrusted device, leaking keys and cleartext in the
process.
X.PP
cfsd uses lots of memory for each attached directory.  If you must
install CFS on a multiuser system, you should reduce NINSTANCES (in
cfs.h) to a small enough value to avoid thrashing.
X.PP
This release makes it reasonably easy to add other 64 bit codebook
ciphers.  To add a cipher, you'll need to provide a block encrypt/
decrypt function and add hooks for it in the following routines:
\fIcipher(), mask_cipher(), pwcrunch(),\fP and \fIcopykey().\fP  You'll
also need to modify \fIcmkdir.c, admproto.x, and cfs.h\fP to refer to the
new cipher.  If your cipher does not have a 64 bit codebook mode, it
will be more painful to add, since CFS assumes this size in far too many
places.
X.PP
The file ver.c contains a static string with information on the
version of CFS from which it was derived.  In particular,
the cryptlevel number refers to the encryption format; versions
of CFS with the same cryptlevel should be able to share encrypted
directories without any problems.  cryptlevels below 10000 are
reserved for official releases, 10001 and up are for end-user
defined formats.  If you are going to be changing the encryption
scheme in CFS and would like to reserve a cryptlevel number,
let me know at cfs@research.att.com.
X.PP
I maintain a mailing list of developers and users of CFS for
discussion of problems, updates, and other areas of common interest.
To subscribe, send mail to cfs-users-request@research.att.com with the
string "subscribe cfs-users" in the message body.
X.SH
Acknowledgements
X.PP
CFS was ported to HP/UX, Irix, Linux and AIX by Mark Henderson
(markh@wimsey.com).  Ed Gould (ed@left.wing.org) made CFS work under
Ultrix 4.2.  Solaris 2.3 support was added by Mark Stein
(Mark.Stein@Eng.Sun.COM).  Several other users contributed bug
reports, suggestions, and advice.  Thanks!
X.LP
July 22, 1995
X
X
SHAR_EOF
  $shar_touch -am 0728024895 'notes.ms' &&
  chmod 0644 'notes.ms' ||
  echo 'restore of notes.ms failed'
  shar_count="`wc -c < 'notes.ms'`"
  test 22239 -eq "$shar_count" ||
    echo "notes.ms: original size 22239, current size $shar_count"
fi
# ============= README.linux ==============
if test -f 'README.linux' && test X"$1" != X"-c"; then
  echo 'x - skipping README.linux (file already exists)'
else
  echo 'x - extracting README.linux (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README.linux' &&
XFrom owner-cfs-users  Wed Mar  8 18:22:15 1995
Received: by merckx.info.att.com (4.1/4.7)
X        id AA15369; Wed, 8 Mar 95 18:22:15 EST
Posted-Date: Wed, 08 Mar 1995 15:17:01 -0800
Message-Id: <199503082317.PAA02390@gwarn.versant.com>
To: root <root@esprit.topaz.com>
XFrom: strick@techwood.org
Reply-To: strick@techwood.org
Cc: cfs-users@research.att.com
Subject: Re: linux problems 
In-Reply-To: Your message of "Wed, 08 Mar 1995 02:51:09 EST."
X             <199503080751.CAA23174@esprit.topaz.com> 
Date: Wed, 08 Mar 1995 15:17:01 -0800
X
THUS SPAKE owner-cfs-users@research.att.com:
#       I'm still having problems getting CFS to compile under the newest
# version of slackware.  I was told that it worked on previous versions of
X
What I had to do in slackware 2.1.0 (Linux 1.1.59) is delete the _svc suffices 
on the global names in the .c files that are generated from the .x files.
(I'm not enough of a SUNRPC GOD to know why.)
X
Then it would link okay.  (Was linking your problem?)
X
Oh, and you need -Dd_fileno=d_ino  ... see below
X
X                                        strick
X
p.s.   ESM is fantastic, too.
X
X
X
X        make CC="cc -traditional -Dd_fileno=d_ino  \
X        -Dnfsproc_null_2_svc=nfsproc_null_2     \
X        -Dnfsproc_getattr_2_svc=nfsproc_getattr_2       \
X        -Dnfsproc_setattr_2_svc=nfsproc_setattr_2       \
X        -Dnfsproc_root_2_svc=nfsproc_root_2     \
X        -Dnfsproc_lookup_2_svc=nfsproc_lookup_2 \
X        -Dnfsproc_readlink_2_svc=nfsproc_readlink_2     \
X        -Dnfsproc_read_2_svc=nfsproc_read_2     \
X        -Dnfsproc_writecache_2_svc=nfsproc_writecache_2 \
X        -Dnfsproc_write_2_svc=nfsproc_write_2   \
X        -Dnfsproc_create_2_svc=nfsproc_create_2 \
X        -Dnfsproc_remove_2_svc=nfsproc_remove_2 \
X        -Dnfsproc_rename_2_svc=nfsproc_rename_2 \
X        -Dnfsproc_link_2_svc=nfsproc_link_2     \
X        -Dnfsproc_symlink_2_svc=nfsproc_symlink_2       \
X        -Dnfsproc_mkdir_2_svc=nfsproc_mkdir_2   \
X        -Dnfsproc_rmdir_2_svc=nfsproc_rmdir_2   \
X        -Dnfsproc_readdir_2_svc=nfsproc_readdir_2       \
X        -Dnfsproc_statfs_2_svc=nfsproc_statfs_2 \
X        -Dadmproc_null_1_svc=admproc_null_1     \
X        -Dadmproc_attach_1_svc=admproc_attach_1 \
X        -Dadmproc_detach_1_svc=admproc_detach_1 \
X        -Dadmproc_ls_1_svc=admproc_ls_1 \
X                "
X
X
SHAR_EOF
  $shar_touch -am 0413002095 'README.linux' &&
  chmod 0644 'README.linux' ||
  echo 'restore of README.linux failed'
  shar_count="`wc -c < 'README.linux'`"
  test 2336 -eq "$shar_count" ||
    echo "README.linux: original size 2336, current size $shar_count"
fi
# ============= README.esm ==============
if test -f 'README.esm' && test X"$1" != X"-c"; then
  echo 'x - skipping README.esm (file already exists)'
else
  echo 'x - extracting README.esm (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README.esm' &&
This is Version 1.0 (BETA) of ESM, the Encrypted Session Manager.
X
X * The author of this software is Matt Blaze.
X *              Copyright (c) 1995 by AT&T.
X * Permission to use, copy, and modify this software without fee
X * is hereby granted, provided that this entire notice is included in
X * all copies of any software which is or includes a copy or
X * modification of this software and in all copies of the supporting
X * documentation for such software.
X *
X * This software is subject to United States export controls.
X *
X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
X
ESM is an encrypted session layer for managing remote encrypted
sessions.  It does 1024 bit DH key exchange (from RSAREF)
and 3-des in 8bit cfb mode for the traffic encryption.  See the
man page (esm.1 in this distribution).
X
ESM is the first released part of a suite of session encryption tools that
are described in
X
X  Matt Blaze and Steve Bellovin. "Session-layer Encryption."
X  Proc. 1995 USENIX Security Workshop, Salt Lake City, June 1995.
X
PostScript is available from
X    ftp://research.att.com/dist/mab/sesscrypt.ps
or, for those without Internet access:
X    echo get cfs-users sesscrypt.ps | mail cfs-users-request@research.att.com
to get the paper by email from the cfs-users list server.
X
In most applications, an encrypting Telnet is a better choice (and
network-layer encryption better still).  ESM's main purpose is providing
end-to-end encryption across a firewall.  It also requires no "system
support" to install, which is both an advantage and a disadvantage.
X
To compile ESM you'll need the RSAREF 2.0 library, available for free
for non-commercial use in the US and Canada from RSA Laboratories
(anonymous ftp to rsa.com for details).
X
Once you have RSAREF working, this distribution should compile without
problems under SunOS 4.x and BSDI; you're on your own for other platforms.
NOTE: ESM RUNS ON FEWER PLATFORMS THAN CFS.  COMPILE AT YOUR OWN RISK.
X
The best way to explain esm is with an example.  Here's
an encrypted session from alice to bob:
X
X	alice$ esm
X	ESM v0.9 - encrypted session manager
X	    by Matt Blaze, AT&T Bell Labs, April 1995
X	randomizing..........done
X	local layer ready (run 'esm -s' on remote)
X	alice$ rsh bob
X	bob$ ./esm -s                                          
X	ESM v0.9 - encrypted session manager
X	    by Matt Blaze, AT&T Bell Labs, April 1995
X	randomizing..........done
X	remote server ready
X	Starting remote side of 1024 bit key exchange.
X	  (type any character to abort)
X	Starting local key exchange...calculating DH key...
X	(key hash is 8d60f517)
X	Entering ENCRYPTED mode; type ctrl-^ to escape
X	bob$
X	...
X	[encrypted session from alice to bob]
X	...
X	bob$ exit
X	Press <enter> to return CLEARTEXT mode:
X	bob$ exit
X	alice$ exit
X	alice$ 
X
You can also hack ESM to provide an encrypted login session;
create a user "esm" with "esm -s -e 'sleep 3;login'" as the login
shell.  (Getting this to work properly will require some tweaking
on your local system). Run esm -l on the local machine and from
there log in to the esm account on the remote machine.  This is
not completely secure (I haven't audited it for this purpose and
there is the risk of a man-in-the-middle attack), so you
really shouldn't use ESM for this purpose.  But such a
configuration does encrypt the real account name and password over
the network:
X
X	alice$ esm                                  
X	ESM v0.9 - encrypted session manager
X	    by Matt Blaze, AT&T Bell Labs, April 1995
X	randomizing..........done
X	local layer ready (run 'esm -s' on remote)
X	alice$ telnet bob
X	Trying 123.45.67.12...
X	Connected to bob
X	Escape character is '^]'.
X
X	bob login: esm
X	ESM v0.9 - encrypted session manager
X	    by Matt Blaze, AT&T Bell Labs, April 1995
X	randomizing..........done
X	remote server ready
X	Starting remote side of 1024 bit key exchange.
X	  (type any character to abort)
X	Starting local key exchange...calculating DH key...
X	(key hash is 8d60f517)
X	Entering ENCRYPTED mode; type ctrl-^ to escape
X	login: mab
X	Password:
X	bob$
X	...
X
ESM is primitive and slow, but seems to work.  Comments, bug fixes,
ports to new platforms and complaints are welcome.
X
Matt Blaze
mab@research.att.com
(for esm or cfs questions, use cfs@research.att.com).
SHAR_EOF
  $shar_touch -am 0724175995 'README.esm' &&
  chmod 0644 'README.esm' ||
  echo 'restore of README.esm failed'
  shar_count="`wc -c < 'README.esm'`"
  test 4464 -eq "$shar_count" ||
    echo "README.esm: original size 4464, current size $shar_count"
fi
# ============= esm.1 ==============
if test -f 'esm.1' && test X"$1" != X"-c"; then
  echo 'x - skipping esm.1 (file already exists)'
else
  echo 'x - extracting esm.1 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'esm.1' &&
X.TH ESM 1
X.SH NAME
esm - encrypted session manager
X.SH SYNOPSIS
\fBesm\fP [\fB-lrs\fP] [\fB-e\fP \fIcommand\fP]
X.SH DESCRIPTION
X.LP
\fBesm\fP manages a simple encrypted session protocol.  When first
invoked from an interactive shell, it provides a transparent
pseudo-terminal session on the local machine.  When invoked from
within an existing ESM session, however, the two ESM processes can
automatically encrypt all traffic passed between them.  Typically,
the second session is executed on a remote networked machine reached
by using the initial session to invoke, e.g., the \fBtelnet\fP(1)
program.
X.LP
Ordinarily, ESM is run first on the local machine in "local" mode
("\fBesm -l\fP").  The resulting session is used to establish a
connection (over a possibly insecure network) to a remote machine on
which \fBesm\fP is run in "server" mode ("\fBesm -s\fP").  Encrypted
sessions are always initiated by the remote \fBesm\fP process.  Remote
mode can be invoked in two ways.  \fBesm -s\fP will attempt to
initiate an encrypted session immediately after starting.  \fBesm
-r\fP will start the remote session in cleartext mode; a user escape
sequence ("control-^" followed by "s") switches to the encrypted
session mode.  "Control-^ ?"  provides a list of other options.
X.LP
Encrypted sessions use two-key (112 bit) triple DES in 8-bit cipher
feedback mode.  A 1024-bit Diffie-Hellman key exchange protocol is
used to establish the session key; the implementation of this protocol
is based on the RSA Laboratories RSAREF 2.0 library.  All encrypted
traffic is encoded using a simple ASCII hexadecimal representation;
this reduces encrypted terminal bandwidth by a factor of just over two
compared with cleartext mode.
X.SH OPTIONS
X.IP "\fB-l\fP"
Local mode.  This establishes the initial session and provides a
transparent pseudo-terminal interface until an encrypted session is
initiated on the "master" (shell) side by a remote server.  This is
also the default mode if no command line flag is specified.
X.IP "\fB-r\fP"
Remote mode.  Provides a transparent pseudo terminal session on the
remote machine, with the ability to initiate an encrypted session with
the "slave" (terminal) side of the connection.
X.IP "\fB-s\fP"
Remote mode.  Immediately attempts to initiate an encrypted session
with the "slave" (terminal) side of the connection.  This mode is
guaranteed to never operate in cleartext mode.
X.IP "\fB -e\fP \fIcommand\fP"
Executes \fIcommand\fP on the master side of the session.  By default
ESM executes the value of the SHELL environment or, if that is not
set, /bin/sh.
X.SH BUGS
X.LP
ESM is not a replacement for a complete link, network or transport
layer security protocol.  In particular, nothing is authenticated and
traffic is only protected once the session has started (which may
occur after sensitive information like login passwords have already
been sent in the clear).
X.LP
Because nothing is authenticated, the protocol is vulnerable to
several variations of the so-called "man-in-the-middle" active attack.
ESM should be regarded as secure only against passive attacks.
X.LP
ESM is slow.  It takes a long time to generate the high-entropy random
numbers required for the key agreement parameters.  The ASCII encoding
of the encrypted traffic noticeably reduces effective bandwidth and
increases response time.
X.LP
The session keys may not be random on all platforms.  The random
number generator relies on variations in clock rate and other hard to
predict factors.  Test these assumptions carefully before trusting ESM
on a new machine or operating system.
X.SH AUTHOR
Matt Blaze, mab@research.att.com (for ESM and CFS problems, use
cfs@research.att.com).
SHAR_EOF
  $shar_touch -am 0604160195 'esm.1' &&
  chmod 0644 'esm.1' ||
  echo 'restore of esm.1 failed'
  shar_count="`wc -c < 'esm.1'`"
  test 3682 -eq "$shar_count" ||
    echo "esm.1: original size 3682, current size $shar_count"
fi
exit 0
================== RFC 822 Headers ==================
Received: from research.att.com by inet-gw-1.pa.dec.com (5.65/24Feb95)
	id AA10051; Mon, 31 Jul 95 08:42:11 -0700
Received: by research.att.com; Mon Jul 31 11:28 EDT 1995
Received: from tpc.info.att.com.info.att.com by big.info.att.com; id AA10091; Mon, 31 Jul 95 11:27:31 EDT
Posted-Date: Mon, 31 Jul 95 11:27:45 EDT
Received: by tpc.info.att.com.info.att.com (4.1/4.7)
	id AA01398; Mon, 31 Jul 95 11:27:45 EDT
Date: Mon, 31 Jul 95 11:27:45 EDT
From: mab@research.att.com (Matt Blaze)
Message-Id: <9507311527.AA01398@tpc.info.att.com.info.att.com>
To: everhart@star.zko.dec.com
