#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  Makefile conf.h-dist ftpcmd.y glob.c logwtmp.c newvers.sh
#   popen.c strtok.c vers.c
# Wrapped by warren@slug.pws.bull.com on Thu Oct 11 14:54:58 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(2925 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# Copyright (c) 1988 Regents of the University of California.
X# All rights reserved.
X#
X# Redistribution and use in source and binary forms are permitted
X# provided that the above copyright notice and this paragraph are
X# duplicated in all such forms and that any documentation,
X# advertising materials, and other materials related to such
X# distribution and use acknowledge that the software was developed
X# by the University of California, Berkeley.  The name of the
X# University may not be used to endorse or promote products derived
X# from this software without specific prior written permission.
X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X#
X#	@(#)Makefile	5.8 (Berkeley) 9/22/88
X#
XCFLAGS=	-O
XLIBC=	/lib/libc.a
XSRCS=	ftpd.c ftpcmd.c glob.c logwtmp.c popen.c vers.c traceroute.c
XOBJS=	ftpd.o ftpcmd.o glob.o logwtmp.o popen.o vers.o traceroute.o
XMAN=	ftpd.0
X
Xall:  ftpd
X
Xftpd: ${OBJS} ${LIBC} conf.h
X	${CC} -o $@ ${OBJS} -lresolv
X
Xconf.h:
X	@echo "Copy conf.h-dist to conf.h, and EDIT THIS FILE."
X	@echo "then say make again."
X	@exit -1
X
Xvers.o: ftpd.c ftpcmd.y
X	sh newvers.sh
X	${CC} ${CFLAGS} -c vers.c
X
Xclean:
X	rm -f ${OBJS} ftpd core ftpcmd.c
X
Xcleandir: clean
X	rm -f ${MAN} tags .depend
X
Xdepend: ${SRCS}
X	maketd -a ${SRCS}
X
Xinstall:
X	install -s -o bin -g bin -m 755 ftpd ${DESTDIR}/etc/ftpd
X
Xlint: ${SRCS}
X	lint ${CFLAGS} ${SRCS}
X
Xtags: ${SRCS}
X	ctags ${SRCS}
X# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT
XI=/usr/include
XS=/usr/include/sys
X
Xconf.o: conf.h
X
Xftpcmd.o: $I/arpa/ftp.h $I/arpa/telnet.h $I/ctype.h $I/machine/setjmp.h \
X	$I/netinet/in.h $I/pwd.h $I/setjmp.h $I/signal.h $I/stdio.h \
X	$S/signal.h $S/socket.h $S/stdtypes.h $S/sysmacros.h $S/types.h \
X	$Slog.h $I/vm/faultcode.h conf.h ftpcmd.y
X
Xftpd.o: $I/arpa/ftp.h $I/arpa/inet.h $I/arpa/telnet.h $I/ctype.h $I/dirent.h \
X	$I/errno.h $I/machine/param.h $I/machine/setjmp.h $I/netdb.h \
X	$I/netinet/in.h $I/pwd.h $I/setjmp.h $I/signal.h $I/stdio.h \
X	$I/strings.h $S/dirent.h $S/errno.h $S/fcntlcom.h $S/file.h \
X	$S/filio.h $S/ioccom.h $S/ioctl.h $S/param.h $S/signal.h $S/socket.h \
X	$S/sockio.h $S/stat.h $S/stdtypes.h $S/sysmacros.h $S/ttold.h \
X	$S/ttychars.h $S/ttycom.h $S/ttydev.h $S/types.h $S/wait.h $Slog.h \
X	$I/vm/faultcode.h conf.h ftpd.c
X
Xglob.o: $I/errno.h $I/machine/param.h $I/pwd.h $I/stdio.h $S/dir.h $S/errno.h \
X	$S/param.h $S/signal.h $S/stat.h $S/stdtypes.h $S/sysmacros.h \
X	$S/types.h $I/vm/faultcode.h glob.c
X
Xlogwtmp.o: $S/fcntlcom.h $S/file.h $S/stat.h $S/stdtypes.h $S/sysmacros.h \
X	$S/time.h $S/types.h $I/time.h $I/utmp.h logwtmp.c
X
Xpopen.o: $I/stdio.h $S/signal.h $S/stdtypes.h $S/sysmacros.h $S/types.h \
X	$I/vm/faultcode.h popen.c
X
Xstrtok.o: strtok.c
X
Xtraceroute.o: conf.h traceroute.c
X
Xvers.o: vers.c
X
X# *** Do not add anything here - It will go away. ***
END_OF_FILE
if test 2925 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'conf.h-dist' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'conf.h-dist'\"
else
echo shar: Extracting \"'conf.h-dist'\" \(2661 characters\)
sed "s/^X//" >'conf.h-dist' <<'END_OF_FILE'
X#ifndef ___CONF_H
X#define ___CONF_H
X/* 
X * Copyright (c) 1985, 1988 Regents of the University of California.
X * All rights reserved.
X * Modifications (c)1990 Warren J. Lavallee.  <warren@pws.bull.com>
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X/**
X ** Define REGULATE to be a string contained the network number
X ** of the network to be restricted.  If you undefine it, no
X ** restrictions apply.
X ** To restrict a directory, create a ".restrict" file in it.
X **
X ** If you define REGULATE to "129.140", then people comming over
X **  NSFnet can not xfer any file is a directory that has a ".restrict"
X **  file.
X ** 
X ** NSFnet is "129.140"
X **
X ** THIS OPTION WILL PROBALLY ONLY WORK ON SunOS SYSTEMS. 
X **/
X
X#undef REGULATE
X
X/** 
X ** Define MAXANON to be the maximum number of simultaneous ftp's
X **  allowed.  If you undefine it, no limits apply.
X **/
X
X#define MAXANON 6
X
X/**
X ** We need a special directory (under ~ftp) to keep magic files for
X ** the above option.
X **
X **/
X
X#ifdef MAXANON
X#define ANONDIRP "/fs/ftp/conn"	/** relative to / **/
X#define ANONDIR "/conn"		/** relative to ~ftp/  **/
X#endif
X
X/**
X ** Define ALLOW_STRANGERS if you want to allow people to anon-ftp to you
X **  who's ip address can't be mapped to a hostname via bind.
X **
X **/
X
X#undef ALLOW_STRANGERS
X 
X/**
X ** Define STRICT_EMAIL if you want to do some checking on email
X **  addresses received as passwords.  (see ftpd.c for more info)
X **
X **/
X
X#define STRICT_EMAIL
X
X/**
X ** Define BAD_HOSTS to a file that contains hosts that are to
X **  be categorically denied access.  An example entry:
X **	FOO.BAR.FR	You do not obey the rules, you can not use this site.
X **  this site would be denied acces, and the message would be sent
X **  to them.  It would then say if the had any problems with that, they
X ** could send mail to EMAIL_CONTACT
X **
X ** undef this to allow all.
X **/
X
X#define BAD_HOSTS "/etc/ftp.badhosts"
X#ifdef BAD_HOSTS
X#define EMAIL_CONTACT "<foo.bar.baz.com>"
X#endif
X
X#endif
END_OF_FILE
if test 2661 -ne `wc -c <'conf.h-dist'`; then
    echo shar: \"'conf.h-dist'\" unpacked with wrong size!
fi
# end of 'conf.h-dist'
fi
if test -f 'ftpcmd.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ftpcmd.y'\"
else
echo shar: Extracting \"'ftpcmd.y'\" \(17104 characters\)
sed "s/^X//" >'ftpcmd.y' <<'END_OF_FILE'
X/*
X * Copyright (c) 1985 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)ftpcmd.y	5.12 (Berkeley) 10/30/88
X */
X
X/*
X * Grammar for FTP commands.
X * See RFC 765.
X */
X
X%{
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)ftpcmd.y	5.12 (Berkeley) 10/30/88";
X#endif /* not lint */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X
X#include <netinet/in.h>
X
X#include <arpa/ftp.h>
X
X#include <stdio.h>
X#include <signal.h>
X#include <ctype.h>
X#include <pwd.h>
X#include <setjmp.h>
X#include <syslog.h>
X#include "conf.h"
X
Xextern	struct sockaddr_in data_dest;
Xextern	int logged_in;
Xextern	struct passwd *pw;
Xextern	int guest;
Xextern	int logging;
Xextern	int type;
Xextern	int form;
Xextern	int debug;
Xextern	int timeout;
Xextern  int pdata;
Xextern	char hostname[];
Xextern	char *globerr;
Xextern	int usedefault;
Xextern	int unique;
Xextern  int transflag;
Xextern  char tmpline[];
Xchar	**glob();
X
Xstatic	int cmd_type;
Xstatic	int cmd_form;
Xstatic	int cmd_bytesz;
Xchar cbuf[512];
Xchar *fromname;
X
Xchar	*index();
X%}
X
X%token
X	A	B	C	E	F	I
X	L	N	P	R	S	T
X
X	SP	CRLF	COMMA	STRING	NUMBER
X
X	USER	PASS	ACCT	REIN	QUIT	PORT
X	PASV	TYPE	STRU	MODE	RETR	STOR
X	APPE	MLFL	MAIL	MSND	MSOM	MSAM
X	MRSQ	MRCP	ALLO	REST	RNFR	RNTO
X	ABOR	DELE	CWD	LIST	NLST	SITE
X	STAT	HELP	NOOP	XMKD	XRMD	XPWD
X	XCUP	STOU
X
X	LEXERR
X
X%start	cmd_list
X
X%%
X
Xcmd_list:	/* empty */
X	|	cmd_list cmd
X		= {
X			fromname = (char *) 0;
X		}
X	|	cmd_list rcmd
X	;
X
Xcmd:		USER SP username CRLF
X		= {
X			extern struct passwd *sgetpwnam();
X		        int connections;
X
X			logged_in = 0;
X			if (strcmp((char *) $3, "ftp") == 0 ||
X			  strcmp((char *) $3, "anonymous") == 0) {
X				if ((pw = sgetpwnam("ftp")) != NULL) {
X  	                           connections = numcon();
X
X				   if (connections > MAXANON) {
X				      lreply(430,
X"Sorry, there are already MAXANON active anonymous ftp's from this machine.");
X				      reply(430,
X"Only 6 allowed at a time. Try back in 5-10 minutes.");
X				      dologout(0);				
X          			   } else {
X				     guest = 1;
X				     reply(331,
X "Guest login ok, send EMail address as password.");
X
X                                   }
X				}
X				else {
X					reply(530, "User %s unknown.", $3);
X				}
X			} else if (checkuser((char *) $3)) {
X				guest = 0;
X				pw = sgetpwnam((char *) $3);
X				if (pw == NULL) {
X					reply(530, "User %s unknown.", $3);
X				}
X				else {
X				    reply(331, "Password required for %s.", $3);
X				}
X			} else {
X				reply(530, "User %s access denied.", $3);
X			}
X			free((char *) $3);
X		}
X	|	PASS SP password CRLF
X		= {
X			pass((char *) $3);
X			free((char *) $3);
X		}
X	|	PORT SP host_port CRLF
X		= {
X			usedefault = 0;
X			if (pdata > 0) {
X				(void) close(pdata);
X			}
X			pdata = -1;
X			reply(200, "PORT command successful.");
X		}
X	|	PASV CRLF
X		= {
X			passive();
X		}
X	|	TYPE SP type_code CRLF
X		= {
X			switch (cmd_type) {
X
X			case TYPE_A:
X				if (cmd_form == FORM_N) {
X					reply(200, "Type set to A.");
X					type = cmd_type;
X					form = cmd_form;
X				} else
X					reply(504, "Form must be N.");
X				break;
X
X			case TYPE_E:
X				reply(504, "Type E not implemented.");
X				break;
X
X			case TYPE_I:
X				reply(200, "Type set to I.");
X				type = cmd_type;
X				break;
X
X			case TYPE_L:
X				if (cmd_bytesz == 8) {
X					reply(200,
X					    "Type set to L (byte size 8).");
X					type = cmd_type;
X				} else
X					reply(504, "Byte size must be 8.");
X			}
X		}
X	|	STRU SP struct_code CRLF
X		= {
X			switch ($3) {
X
X			case STRU_F:
X				reply(200, "STRU F ok.");
X				break;
X
X			default:
X				reply(504, "Unimplemented STRU type.");
X			}
X		}
X	|	MODE SP mode_code CRLF
X		= {
X			switch ($3) {
X
X			case MODE_S:
X				reply(200, "MODE S ok.");
X				break;
X
X			default:
X				reply(502, "Unimplemented MODE type.");
X			}
X		}
X	|	ALLO SP NUMBER CRLF
X		= {
X			reply(202, "ALLO command ignored.");
X		}
X	|	RETR check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL)
X				retrieve((char *) 0, (char *) $4);
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	STOR check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL)
X				store((char *) $4, "w");
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	APPE check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL)
X				store((char *) $4, "a");
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	NLST check_login CRLF
X		= {
X			if ($2)
X				retrieve("/bin/ls", "");
X		}
X	|	NLST check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL)
X				retrieve("/bin/ls %s", (char *) $4);
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	LIST check_login CRLF
X		= {
X			if ($2)
X				retrieve("/bin/ls -lg", "");
X		}
X	|	LIST check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL)
X				retrieve("/bin/ls -lg %s", (char *) $4);
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	DELE check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL)
X				delete((char *) $4);
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	RNTO SP pathname CRLF
X		= {
X			if (fromname) {
X				renamecmd(fromname, (char *) $3);
X				free(fromname);
X				fromname = (char *) 0;
X			} else {
X				reply(503, "Bad sequence of commands.");
X			}
X			free((char *) $3);
X		}
X	|	ABOR CRLF
X		= {
X			reply(225, "ABOR command successful.");
X		}
X	|	CWD check_login CRLF
X		= {
X			if ($2)
X				cwd(pw->pw_dir);
X		}
X	|	CWD check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL)
X				cwd((char *) $4);
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	HELP CRLF
X		= {
X			help((char *) 0);
X		}
X	|	HELP SP STRING CRLF
X		= {
X			help((char *) $3);
X		}
X	|	NOOP CRLF
X		= {
X			reply(200, "NOOP command successful.");
X		}
X	|	XMKD check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL)
X				makedir((char *) $4);
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	XRMD check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL)
X				removedir((char *) $4);
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	XPWD check_login CRLF
X		= {
X			if ($2)
X				pwd();
X		}
X	|	XCUP check_login CRLF
X		= {
X			if ($2)
X				cwd("..");
X		}
X	|	STOU check_login SP pathname CRLF
X		= {
X			if ($2 && $4 != NULL) {
X				unique++;
X				store((char *) $4, "w");
X				unique = 0;
X			}
X			if ($4 != NULL)
X				free((char *) $4);
X		}
X	|	QUIT CRLF
X		= {
X			reply(221, "Goodbye.");
X			dologout(0);
X		}
X	|	error CRLF
X		= {
X			yyerrok;
X		}
X	;
X
Xrcmd:		RNFR check_login SP pathname CRLF
X		= {
X			char *renamefrom();
X
X			if ($2 && $4) {
X				fromname = renamefrom((char *) $4);
X				if (fromname == (char *) 0 && $4) {
X					free((char *) $4);
X				}
X			}
X		}
X	;
X		
Xusername:	STRING
X	;
X
Xpassword:	STRING
X	;
X
Xbyte_size:	NUMBER
X	;
X
Xhost_port:	NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 
X		NUMBER COMMA NUMBER
X		= {
X			register char *a, *p;
X
X			a = (char *)&data_dest.sin_addr;
X			a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
X			p = (char *)&data_dest.sin_port;
X			p[0] = $9; p[1] = $11;
X			data_dest.sin_family = AF_INET;
X		}
X	;
X
Xform_code:	N
X	= {
X		$$ = FORM_N;
X	}
X	|	T
X	= {
X		$$ = FORM_T;
X	}
X	|	C
X	= {
X		$$ = FORM_C;
X	}
X	;
X
Xtype_code:	A
X	= {
X		cmd_type = TYPE_A;
X		cmd_form = FORM_N;
X	}
X	|	A SP form_code
X	= {
X		cmd_type = TYPE_A;
X		cmd_form = $3;
X	}
X	|	E
X	= {
X		cmd_type = TYPE_E;
X		cmd_form = FORM_N;
X	}
X	|	E SP form_code
X	= {
X		cmd_type = TYPE_E;
X		cmd_form = $3;
X	}
X	|	I
X	= {
X		cmd_type = TYPE_I;
X	}
X	|	L
X	= {
X		cmd_type = TYPE_L;
X		cmd_bytesz = 8;
X	}
X	|	L SP byte_size
X	= {
X		cmd_type = TYPE_L;
X		cmd_bytesz = $3;
X	}
X	/* this is for a bug in the BBN ftp */
X	|	L byte_size
X	= {
X		cmd_type = TYPE_L;
X		cmd_bytesz = $2;
X	}
X	;
X
Xstruct_code:	F
X	= {
X		$$ = STRU_F;
X	}
X	|	R
X	= {
X		$$ = STRU_R;
X	}
X	|	P
X	= {
X		$$ = STRU_P;
X	}
X	;
X
Xmode_code:	S
X	= {
X		$$ = MODE_S;
X	}
X	|	B
X	= {
X		$$ = MODE_B;
X	}
X	|	C
X	= {
X		$$ = MODE_C;
X	}
X	;
X
Xpathname:	pathstring
X	= {
X		/*
X		 * Problem: this production is used for all pathname
X		 * processing, but only gives a 550 error reply.
X		 * This is a valid reply in some cases but not in others.
X		 */
X		if ($1 && strncmp((char *) $1, "~", 1) == 0) {
X			$$ = (int)*glob((char *) $1);
X			if (globerr != NULL) {
X				reply(550, globerr);
X				$$ = NULL;
X			}
X			free((char *) $1);
X		} else
X			$$ = $1;
X	}
X	;
X
Xpathstring:	STRING
X	;
X
Xcheck_login:	/* empty */
X	= {
X		if (logged_in)
X			$$ = 1;
X		else {
X			reply(530, "Please login with USER and PASS.");
X			$$ = 0;
X		}
X	}
X	;
X
X%%
X
Xextern jmp_buf errcatch;
X
X#define	CMD	0	/* beginning of command */
X#define	ARGS	1	/* expect miscellaneous arguments */
X#define	STR1	2	/* expect SP followed by STRING */
X#define	STR2	3	/* expect STRING */
X#define	OSTR	4	/* optional STRING */
X
Xstruct tab {
X	char	*name;
X	short	token;
X	short	state;
X	short	implemented;	/* 1 if command is implemented */
X	char	*help;
X};
X
Xstruct tab cmdtab[] = {		/* In order defined in RFC 765 */
X	{ "USER", USER, STR1, 1,	"<sp> username" },
X	{ "PASS", PASS, STR1, 1,	"<sp> password" },
X	{ "ACCT", ACCT, STR1, 0,	"(specify account)" },
X	{ "REIN", REIN, ARGS, 0,	"(reinitialize server state)" },
X	{ "QUIT", QUIT, ARGS, 1,	"(terminate service)", },
X	{ "PORT", PORT, ARGS, 1,	"<sp> b0, b1, b2, b3, b4" },
X	{ "PASV", PASV, ARGS, 1,	"(set server in passive mode)" },
X	{ "TYPE", TYPE, ARGS, 1,	"<sp> [ A | E | I | L ]" },
X	{ "STRU", STRU, ARGS, 1,	"(specify file structure)" },
X	{ "MODE", MODE, ARGS, 1,	"(specify transfer mode)" },
X	{ "RETR", RETR, STR1, 1,	"<sp> file-name" },
X	{ "STOR", STOR, STR1, 1,	"<sp> file-name" },
X	{ "APPE", APPE, STR1, 1,	"<sp> file-name" },
X	{ "MLFL", MLFL, OSTR, 0,	"(mail file)" },
X	{ "MAIL", MAIL, OSTR, 0,	"(mail to user)" },
X	{ "MSND", MSND, OSTR, 0,	"(mail send to terminal)" },
X	{ "MSOM", MSOM, OSTR, 0,	"(mail send to terminal or mailbox)" },
X	{ "MSAM", MSAM, OSTR, 0,	"(mail send to terminal and mailbox)" },
X	{ "MRSQ", MRSQ, OSTR, 0,	"(mail recipient scheme question)" },
X	{ "MRCP", MRCP, STR1, 0,	"(mail recipient)" },
X	{ "ALLO", ALLO, ARGS, 1,	"allocate storage (vacuously)" },
X	{ "REST", REST, STR1, 0,	"(restart command)" },
X	{ "RNFR", RNFR, STR1, 1,	"<sp> file-name" },
X	{ "RNTO", RNTO, STR1, 1,	"<sp> file-name" },
X	{ "ABOR", ABOR, ARGS, 1,	"(abort operation)" },
X	{ "DELE", DELE, STR1, 1,	"<sp> file-name" },
X	{ "CWD",  CWD,  OSTR, 1,	"[ <sp> directory-name]" },
X	{ "XCWD", CWD,	OSTR, 1,	"[ <sp> directory-name ]" },
X	{ "LIST", LIST, OSTR, 1,	"[ <sp> path-name ]" },
X	{ "NLST", NLST, OSTR, 1,	"[ <sp> path-name ]" },
X	{ "SITE", SITE, STR1, 0,	"(get site parameters)" },
X	{ "STAT", STAT, OSTR, 0,	"(get server status)" },
X	{ "HELP", HELP, OSTR, 1,	"[ <sp> <string> ]" },
X	{ "NOOP", NOOP, ARGS, 1,	"" },
X	{ "MKD",  XMKD, STR1, 1,	"<sp> path-name" },
X	{ "XMKD", XMKD, STR1, 1,	"<sp> path-name" },
X	{ "RMD",  XRMD, STR1, 1,	"<sp> path-name" },
X	{ "XRMD", XRMD, STR1, 1,	"<sp> path-name" },
X	{ "PWD",  XPWD, ARGS, 1,	"(return current directory)" },
X	{ "XPWD", XPWD, ARGS, 1,	"(return current directory)" },
X	{ "CDUP", XCUP, ARGS, 1,	"(change to parent directory)" },
X	{ "XCUP", XCUP, ARGS, 1,	"(change to parent directory)" },
X	{ "STOU", STOU, STR1, 1,	"<sp> file-name" },
X	{ NULL,   0,    0,    0,	0 }
X};
X
Xstruct tab *
Xlookup(cmd)
X	char *cmd;
X{
X	register struct tab *p;
X
X	for (p = cmdtab; p->name != NULL; p++)
X		if (strcmp(cmd, p->name) == 0)
X			return (p);
X	return (0);
X}
X
X#include <arpa/telnet.h>
X
X/*
X * getline - a hacked up version of fgets to ignore TELNET escape codes.
X */
Xchar *
Xgetline(s, n, iop)
X	char *s;
X	register FILE *iop;
X{
X	register c;
X	register char *cs;
X
X	cs = s;
X/* tmpline may contain saved command from urgent mode interruption */
X	for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
X		*cs++ = tmpline[c];
X		if (tmpline[c] == '\n') {
X			*cs++ = '\0';
X			if (debug) {
X				syslog(LOG_DEBUG, "FTPD: command: %s", s);
X			}
X			tmpline[0] = '\0';
X			return(s);
X		}
X		if (c == 0) {
X			tmpline[0] = '\0';
X		}
X	}
X	while (--n > 0 && (c = getc(iop)) != EOF) {
X		c = 0377 & c;
X		while (c == IAC) {
X			switch (c = 0377 & getc(iop)) {
X			case WILL:
X			case WONT:
X				c = 0377 & getc(iop);
X				printf("%c%c%c", IAC, WONT, c);
X				(void) fflush(stdout);
X				break;
X			case DO:
X			case DONT:
X				c = 0377 & getc(iop);
X				printf("%c%c%c", IAC, DONT, c);
X				(void) fflush(stdout);
X				break;
X			default:
X				break;
X			}
X			c = 0377 & getc(iop); /* try next character */
X		}
X		*cs++ = c;
X		if (c=='\n')
X			break;
X	}
X	if (c == EOF && cs == s)
X		return (NULL);
X	*cs++ = '\0';
X	if (debug) {
X		syslog(LOG_DEBUG, "FTPD: command: %s", s);
X	}
X	return (s);
X}
X
Xstatic int
Xtoolong()
X{
X	time_t now;
X	extern char *ctime();
X	extern time_t time();
X
X	reply(421,
X	  "Timeout (%d seconds): closing control connection.", timeout);
X	(void) time(&now);
X	if (logging) {
X		syslog(LOG_INFO,
X			"FTPD: User %s timed out after %d seconds at %s",
X			(pw ? pw -> pw_name : "unknown"), timeout, ctime(&now));
X	}
X	dologout(1);
X}
X
Xyylex()
X{
X	static int cpos, state;
X	register char *cp;
X	register struct tab *p;
X	int n;
X	char c;
X
X	for (;;) {
X		switch (state) {
X
X		case CMD:
X			(void) signal(SIGALRM, toolong);
X			(void) alarm((unsigned) timeout);
X			if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
X				reply(221, "You could at least say goodbye.");
X				dologout(0);
X			}
X			(void) alarm(0);
X			if (index(cbuf, '\r')) {
X				cp = index(cbuf, '\r');
X				cp[0] = '\n'; cp[1] = 0;
X			}
X			if (index(cbuf, ' '))
X				cpos = index(cbuf, ' ') - cbuf;
X			else
X				cpos = index(cbuf, '\n') - cbuf;
X			if (cpos == 0) {
X				cpos = 4;
X			}
X			c = cbuf[cpos];
X			cbuf[cpos] = '\0';
X			upper(cbuf);
X			p = lookup(cbuf);
X			cbuf[cpos] = c;
X			if (p != 0) {
X				if (p->implemented == 0) {
X					nack(p->name);
X					longjmp(errcatch,0);
X					/* NOTREACHED */
X				}
X				state = p->state;
X				yylval = (int) p->name;
X				return (p->token);
X			}
X			break;
X
X		case OSTR:
X			if (cbuf[cpos] == '\n') {
X				state = CMD;
X				return (CRLF);
X			}
X			/* FALL THRU */
X
X		case STR1:
X			if (cbuf[cpos] == ' ') {
X				cpos++;
X				state = STR2;
X				return (SP);
X			}
X			break;
X
X		case STR2:
X			cp = &cbuf[cpos];
X			n = strlen(cp);
X			cpos += n - 1;
X			/*
X			 * Make sure the string is nonempty and \n terminated.
X			 */
X			if (n > 1 && cbuf[cpos] == '\n') {
X				cbuf[cpos] = '\0';
X				yylval = copy(cp);
X				cbuf[cpos] = '\n';
X				state = ARGS;
X				return (STRING);
X			}
X			break;
X
X		case ARGS:
X			if (isdigit(cbuf[cpos])) {
X				cp = &cbuf[cpos];
X				while (isdigit(cbuf[++cpos]))
X					;
X				c = cbuf[cpos];
X				cbuf[cpos] = '\0';
X				yylval = atoi(cp);
X				cbuf[cpos] = c;
X				return (NUMBER);
X			}
X			switch (cbuf[cpos++]) {
X
X			case '\n':
X				state = CMD;
X				return (CRLF);
X
X			case ' ':
X				return (SP);
X
X			case ',':
X				return (COMMA);
X
X			case 'A':
X			case 'a':
X				return (A);
X
X			case 'B':
X			case 'b':
X				return (B);
X
X			case 'C':
X			case 'c':
X				return (C);
X
X			case 'E':
X			case 'e':
X				return (E);
X
X			case 'F':
X			case 'f':
X				return (F);
X
X			case 'I':
X			case 'i':
X				return (I);
X
X			case 'L':
X			case 'l':
X				return (L);
X
X			case 'N':
X			case 'n':
X				return (N);
X
X			case 'P':
X			case 'p':
X				return (P);
X
X			case 'R':
X			case 'r':
X				return (R);
X
X			case 'S':
X			case 's':
X				return (S);
X
X			case 'T':
X			case 't':
X				return (T);
X
X			}
X			break;
X
X		default:
X			fatal("Unknown state in scanner.");
X		}
X		yyerror((char *) 0);
X		state = CMD;
X		longjmp(errcatch,0);
X	}
X}
X
Xupper(s)
X	char *s;
X{
X	while (*s != '\0') {
X		if (islower(*s))
X			*s = toupper(*s);
X		s++;
X	}
X}
X
Xcopy(s)
X	char *s;
X{
X	char *p;
X	extern char *malloc(), *strcpy();
X
X	p = malloc((unsigned) strlen(s) + 1);
X	if (p == NULL)
X		fatal("Ran out of memory.");
X	(void) strcpy(p, s);
X	return ((int)p);
X}
X
Xhelp(s)
X	char *s;
X{
X	register struct tab *c;
X	register int width, NCMDS;
X
X	width = 0, NCMDS = 0;
X	for (c = cmdtab; c->name != NULL; c++) {
X		int len = strlen(c->name) + 1;
X
X		if (len > width)
X			width = len;
X		NCMDS++;
X	}
X	width = (width + 8) &~ 7;
X	if (s == 0) {
X		register int i, j, w;
X		int columns, lines;
X
X		lreply(214,
X	  "The following commands are recognized (* =>'s unimplemented).");
X		columns = 76 / width;
X		if (columns == 0)
X			columns = 1;
X		lines = (NCMDS + columns - 1) / columns;
X		for (i = 0; i < lines; i++) {
X			printf("   ");
X			for (j = 0; j < columns; j++) {
X				c = cmdtab + j * lines + i;
X				printf("%s%c", c->name,
X					c->implemented ? ' ' : '*');
X				if (c + lines >= &cmdtab[NCMDS])
X					break;
X				w = strlen(c->name) + 1;
X				while (w < width) {
X					putchar(' ');
X					w++;
X				}
X			}
X			printf("\r\n");
X		}
X		(void) fflush(stdout);
X		reply(214, "Direct comments to ftp-bugs@%s.", hostname);
X		return;
X	}
X	upper(s);
X	c = lookup(s);
X	if (c == (struct tab *)0) {
X		reply(502, "Unknown command %s.", s);
X		return;
X	}
X	if (c->implemented)
X		reply(214, "Syntax: %s %s", c->name, c->help);
X	else
X		reply(214, "%-*s\t%s; unimplemented.", width, c->name, c->help);
X}
END_OF_FILE
if test 17104 -ne `wc -c <'ftpcmd.y'`; then
    echo shar: \"'ftpcmd.y'\" unpacked with wrong size!
fi
# end of 'ftpcmd.y'
fi
if test -f 'glob.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'glob.c'\"
else
echo shar: Extracting \"'glob.c'\" \(10222 characters\)
sed "s/^X//" >'glob.c' <<'END_OF_FILE'
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 are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)glob.c	5.4 (Berkeley) 6/29/88";
X#endif /* not lint */
X
X/*
X * C-shell glob for random programs.
X */
X
X#include <sys/param.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X
X#include <stdio.h>
X#include <errno.h>
X#include <pwd.h>
X
X#define	QUOTE 0200
X#define	TRIM 0177
X#define	eq(a,b)		(strcmp(a, b)==0)
X#define	GAVSIZ		(NCARGS/6)
X#define	isdir(d)	((d.st_mode & S_IFMT) == S_IFDIR)
X
Xstatic	char **gargv;		/* Pointer to the (stack) arglist */
Xstatic	short gargc;		/* Number args in gargv */
Xstatic	short gnleft;
Xstatic	short gflag;
Xstatic	int tglob();
Xchar	**glob();
Xchar	*globerr;
Xchar	*home;
Xstruct	passwd *getpwnam();
Xextern	int errno;
Xstatic	char *strspl(), *strend();
Xchar	*malloc(), *strcpy(), *strcat();
Xchar	**copyblk();
X
Xstatic	int globcnt;
X
Xchar	*globchars = "`{[*?";
X
Xstatic	char *gpath, *gpathp, *lastgpathp;
Xstatic	int globbed;
Xstatic	char *entp;
Xstatic	char **sortbas;
X
Xchar **
Xglob(v)
X	register char *v;
X{
X	char agpath[BUFSIZ];
X	char *agargv[GAVSIZ];
X	char *vv[2];
X	vv[0] = v;
X	vv[1] = 0;
X	gflag = 0;
X	rscan(vv, tglob);
X	if (gflag == 0)
X		return (copyblk(vv));
X
X	globerr = 0;
X	gpath = agpath; gpathp = gpath; *gpathp = 0;
X	lastgpathp = &gpath[sizeof agpath - 2];
X	ginit(agargv); globcnt = 0;
X	collect(v);
X	if (globcnt == 0 && (gflag&1)) {
X		blkfree(gargv), gargv = 0;
X		return (0);
X	} else
X		return (gargv = copyblk(gargv));
X}
X
Xstatic
Xginit(agargv)
X	char **agargv;
X{
X
X	agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
X	gnleft = NCARGS - 4;
X}
X
Xstatic
Xcollect(as)
X	register char *as;
X{
X	if (eq(as, "{") || eq(as, "{}")) {
X		Gcat(as, "");
X		sort();
X	} else
X		acollect(as);
X}
X
Xstatic
Xacollect(as)
X	register char *as;
X{
X	register int ogargc = gargc;
X
X	gpathp = gpath; *gpathp = 0; globbed = 0;
X	expand(as);
X	if (gargc != ogargc)
X		sort();
X}
X
Xstatic
Xsort()
X{
X	register char **p1, **p2, *c;
X	char **Gvp = &gargv[gargc];
X
X	p1 = sortbas;
X	while (p1 < Gvp-1) {
X		p2 = p1;
X		while (++p2 < Gvp)
X			if (strcmp(*p1, *p2) > 0)
X				c = *p1, *p1 = *p2, *p2 = c;
X		p1++;
X	}
X	sortbas = Gvp;
X}
X
Xstatic
Xexpand(as)
X	char *as;
X{
X	register char *cs;
X	register char *sgpathp, *oldcs;
X	struct stat stb;
X
X	sgpathp = gpathp;
X	cs = as;
X	if (*cs == '~' && gpathp == gpath) {
X		addpath('~');
X		for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
X			addpath(*cs++);
X		if (!*cs || *cs == '/') {
X			if (gpathp != gpath + 1) {
X				*gpathp = 0;
X				if (gethdir(gpath + 1))
X					globerr = "Unknown user name after ~";
X				(void) strcpy(gpath, gpath + 1);
X			} else
X				(void) strcpy(gpath, home);
X			gpathp = strend(gpath);
X		}
X	}
X	while (!any(*cs, globchars)) {
X		if (*cs == 0) {
X			if (!globbed)
X				Gcat(gpath, "");
X			else if (stat(gpath, &stb) >= 0) {
X				Gcat(gpath, "");
X				globcnt++;
X			}
X			goto endit;
X		}
X		addpath(*cs++);
X	}
X	oldcs = cs;
X	while (cs > as && *cs != '/')
X		cs--, gpathp--;
X	if (*cs == '/')
X		cs++, gpathp++;
X	*gpathp = 0;
X	if (*oldcs == '{') {
X		(void) execbrc(cs, ((char *)0));
X		return;
X	}
X	matchdir(cs);
Xendit:
X	gpathp = sgpathp;
X	*gpathp = 0;
X}
X
Xstatic
Xmatchdir(pattern)
X	char *pattern;
X{
X	struct stat stb;
X	register struct direct *dp;
X	DIR *dirp;
X
X	dirp = opendir(gpath);
X	if (dirp == NULL) {
X		if (globbed)
X			return;
X		goto patherr2;
X	}
X	if (fstat(dirp->dd_fd, &stb) < 0)
X		goto patherr1;
X	if (!isdir(stb)) {
X		errno = ENOTDIR;
X		goto patherr1;
X	}
X	while ((dp = readdir(dirp)) != NULL) {
X		if (dp->d_ino == 0)
X			continue;
X		if (match(dp->d_name, pattern)) {
X			Gcat(gpath, dp->d_name);
X			globcnt++;
X		}
X	}
X	closedir(dirp);
X	return;
X
Xpatherr1:
X	closedir(dirp);
Xpatherr2:
X	globerr = "Bad directory components";
X}
X
Xstatic
Xexecbrc(p, s)
X	char *p, *s;
X{
X	char restbuf[BUFSIZ + 2];
X	register char *pe, *pm, *pl;
X	int brclev = 0;
X	char *lm, savec, *sgpathp;
X
X	for (lm = restbuf; *p != '{'; *lm++ = *p++)
X		continue;
X	for (pe = ++p; *pe; pe++)
X	switch (*pe) {
X
X	case '{':
X		brclev++;
X		continue;
X
X	case '}':
X		if (brclev == 0)
X			goto pend;
X		brclev--;
X		continue;
X
X	case '[':
X		for (pe++; *pe && *pe != ']'; pe++)
X			continue;
X		continue;
X	}
Xpend:
X	brclev = 0;
X	for (pl = pm = p; pm <= pe; pm++)
X	switch (*pm & (QUOTE|TRIM)) {
X
X	case '{':
X		brclev++;
X		continue;
X
X	case '}':
X		if (brclev) {
X			brclev--;
X			continue;
X		}
X		goto doit;
X
X	case ','|QUOTE:
X	case ',':
X		if (brclev)
X			continue;
Xdoit:
X		savec = *pm;
X		*pm = 0;
X		(void) strcpy(lm, pl);
X		(void) strcat(restbuf, pe + 1);
X		*pm = savec;
X		if (s == 0) {
X			sgpathp = gpathp;
X			expand(restbuf);
X			gpathp = sgpathp;
X			*gpathp = 0;
X		} else if (amatch(s, restbuf))
X			return (1);
X		sort();
X		pl = pm + 1;
X		if (brclev)
X			return (0);
X		continue;
X
X	case '[':
X		for (pm++; *pm && *pm != ']'; pm++)
X			continue;
X		if (!*pm)
X			pm--;
X		continue;
X	}
X	if (brclev)
X		goto doit;
X	return (0);
X}
X
Xstatic
Xmatch(s, p)
X	char *s, *p;
X{
X	register int c;
X	register char *sentp;
X	char sglobbed = globbed;
X
X	if (*s == '.' && *p != '.')
X		return (0);
X	sentp = entp;
X	entp = s;
X	c = amatch(s, p);
X	entp = sentp;
X	globbed = sglobbed;
X	return (c);
X}
X
Xstatic
Xamatch(s, p)
X	register char *s, *p;
X{
X	register int scc;
X	int ok, lc;
X	char *sgpathp;
X	struct stat stb;
X	int c, cc;
X
X	globbed = 1;
X	for (;;) {
X		scc = *s++ & TRIM;
X		switch (c = *p++) {
X
X		case '{':
X			return (execbrc(p - 1, s - 1));
X
X		case '[':
X			ok = 0;
X			lc = 077777;
X			while (cc = *p++) {
X				if (cc == ']') {
X					if (ok)
X						break;
X					return (0);
X				}
X				if (cc == '-') {
X					if (lc <= scc && scc <= *p++)
X						ok++;
X				} else
X					if (scc == (lc = cc))
X						ok++;
X			}
X			if (cc == 0)
X				if (ok)
X					p--;
X				else
X					return 0;
X			continue;
X
X		case '*':
X			if (!*p)
X				return (1);
X			if (*p == '/') {
X				p++;
X				goto slash;
X			}
X			s--;
X			do {
X				if (amatch(s, p))
X					return (1);
X			} while (*s++);
X			return (0);
X
X		case 0:
X			return (scc == 0);
X
X		default:
X			if (c != scc)
X				return (0);
X			continue;
X
X		case '?':
X			if (scc == 0)
X				return (0);
X			continue;
X
X		case '/':
X			if (scc)
X				return (0);
Xslash:
X			s = entp;
X			sgpathp = gpathp;
X			while (*s)
X				addpath(*s++);
X			addpath('/');
X			if (stat(gpath, &stb) == 0 && isdir(stb))
X				if (*p == 0) {
X					Gcat(gpath, "");
X					globcnt++;
X				} else
X					expand(p);
X			gpathp = sgpathp;
X			*gpathp = 0;
X			return (0);
X		}
X	}
X}
X
Xstatic
XGmatch(s, p)
X	register char *s, *p;
X{
X	register int scc;
X	int ok, lc;
X	int c, cc;
X
X	for (;;) {
X		scc = *s++ & TRIM;
X		switch (c = *p++) {
X
X		case '[':
X			ok = 0;
X			lc = 077777;
X			while (cc = *p++) {
X				if (cc == ']') {
X					if (ok)
X						break;
X					return (0);
X				}
X				if (cc == '-') {
X					if (lc <= scc && scc <= *p++)
X						ok++;
X				} else
X					if (scc == (lc = cc))
X						ok++;
X			}
X			if (cc == 0)
X				if (ok)
X					p--;
X				else
X					return 0;
X			continue;
X
X		case '*':
X			if (!*p)
X				return (1);
X			for (s--; *s; s++)
X				if (Gmatch(s, p))
X					return (1);
X			return (0);
X
X		case 0:
X			return (scc == 0);
X
X		default:
X			if ((c & TRIM) != scc)
X				return (0);
X			continue;
X
X		case '?':
X			if (scc == 0)
X				return (0);
X			continue;
X
X		}
X	}
X}
X
Xstatic
XGcat(s1, s2)
X	register char *s1, *s2;
X{
X	register int len = strlen(s1) + strlen(s2) + 1;
X
X	if (len >= gnleft || gargc >= GAVSIZ - 1)
X		globerr = "Arguments too long";
X	else {
X		gargc++;
X		gnleft -= len;
X		gargv[gargc] = 0;
X		gargv[gargc - 1] = strspl(s1, s2);
X	}
X}
X
Xstatic
Xaddpath(c)
X	char c;
X{
X
X	if (gpathp >= lastgpathp)
X		globerr = "Pathname too long";
X	else {
X		*gpathp++ = c;
X		*gpathp = 0;
X	}
X}
X
Xstatic
Xrscan(t, f)
X	register char **t;
X	int (*f)();
X{
X	register char *p, c;
X
X	while (p = *t++) {
X		if (f == tglob)
X			if (*p == '~')
X				gflag |= 2;
X			else if (eq(p, "{") || eq(p, "{}"))
X				continue;
X		while (c = *p++)
X			(*f)(c);
X	}
X}
X/*
Xstatic
Xscan(t, f)
X	register char **t;
X	int (*f)();
X{
X	register char *p, c;
X
X	while (p = *t++)
X		while (c = *p)
X			*p++ = (*f)(c);
X} */
X
Xstatic
Xtglob(c)
X	register char c;
X{
X
X	if (any(c, globchars))
X		gflag |= c == '{' ? 2 : 1;
X	return (c);
X}
X/*
Xstatic
Xtrim(c)
X	char c;
X{
X
X	return (c & TRIM);
X} */
X
X
Xletter(c)
X	register char c;
X{
X
X	return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
X}
X
Xdigit(c)
X	register char c;
X{
X
X	return (c >= '0' && c <= '9');
X}
X
Xany(c, s)
X	register int c;
X	register char *s;
X{
X
X	while (*s)
X		if (*s++ == c)
X			return(1);
X	return(0);
X}
Xblklen(av)
X	register char **av;
X{
X	register int i = 0;
X
X	while (*av++)
X		i++;
X	return (i);
X}
X
Xchar **
Xblkcpy(oav, bv)
X	char **oav;
X	register char **bv;
X{
X	register char **av = oav;
X
X	while (*av++ = *bv++)
X		continue;
X	return (oav);
X}
X
Xblkfree(av0)
X	char **av0;
X{
X	register char **av = av0;
X
X	while (*av)
X		free(*av++);
X	free((char *)av0);
X}
X
Xstatic
Xchar *
Xstrspl(cp, dp)
X	register char *cp, *dp;
X{
X	register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
X
X	if (ep == (char *)0)
X		fatal("Out of memory");
X	(void) strcpy(ep, cp);
X	(void) strcat(ep, dp);
X	return (ep);
X}
X
Xchar **
Xcopyblk(v)
X	register char **v;
X{
X	register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
X						sizeof(char **)));
X	if (nv == (char **)0)
X		fatal("Out of memory");
X
X	return (blkcpy(nv, v));
X}
X
Xstatic
Xchar *
Xstrend(cp)
X	register char *cp;
X{
X
X	while (*cp)
X		cp++;
X	return (cp);
X}
X/*
X * Extract a home directory from the password file
X * The argument points to a buffer where the name of the
X * user whose home directory is sought is currently.
X * We write the home directory of the user back there.
X */
Xgethdir(home)
X	char *home;
X{
X	register struct passwd *pp = getpwnam(home);
X
X	if (pp == 0)
X		return (1);
X	(void) strcpy(home, pp->pw_dir);
X	return (0);
X}
END_OF_FILE
if test 10222 -ne `wc -c <'glob.c'`; then
    echo shar: \"'glob.c'\" unpacked with wrong size!
fi
# end of 'glob.c'
fi
if test -f 'logwtmp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'logwtmp.c'\"
else
echo shar: Extracting \"'logwtmp.c'\" \(1687 characters\)
sed "s/^X//" >'logwtmp.c' <<'END_OF_FILE'
X/*
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 are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * static char sccsid[] = "@(#)logwtmp.c	5.2 (Berkeley) 9/20/88";
X */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)logwtmp.c	5.2 (Berkeley) 9/22/88";
X#endif /* not lint */
X
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/time.h>
X#include <sys/stat.h>
X#include <utmp.h>
X
X#define	WTMPFILE	"/usr/adm/wtmp"
X
Xstatic int fd;
X
Xlogwtmp(line, name, host)
X	char *line, *name, *host;
X{
X	struct utmp ut;
X	struct stat buf;
X	time_t time();
X	char *strncpy();
X
X	if (!fd && (fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
X		return;
X	if (!fstat(fd, &buf)) {
X		(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
X		(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
X		(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
X		(void)time(&ut.ut_time);
X		if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
X		    sizeof(struct utmp))
X			(void)ftruncate(fd, buf.st_size);
X	}
X}
END_OF_FILE
if test 1687 -ne `wc -c <'logwtmp.c'`; then
    echo shar: \"'logwtmp.c'\" unpacked with wrong size!
fi
# end of 'logwtmp.c'
fi
if test -f 'newvers.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'newvers.sh'\"
else
echo shar: Extracting \"'newvers.sh'\" \(1100 characters\)
sed "s/^X//" >'newvers.sh' <<'END_OF_FILE'
X#!/bin/sh -
X#
X# Copyright (c) 1983 The Regents of the University of California.
X# All rights reserved.
X#
X# Redistribution and use in source and binary forms are permitted
X# provided that the above copyright notice and this paragraph are
X# duplicated in all such forms and that any documentation,
X# advertising materials, and other materials related to such
X# distribution and use acknowledge that the software was developed
X# by the University of California, Berkeley.  The name of the
X# University may not be used to endorse or promote products derived
X# from this software without specific prior written permission.
X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X#
X#	@(#)newvers.sh	5.3 (Berkeley) 10/31/88
X#
Xif [ ! -r version ]; then echo 0 > version; fi
Xtouch version
Xawk '	{	version = $1 + 1; }\
XEND	{	printf "char version[] = \"Version 4.%d ", version > "vers.c";\
X		printf "%d\n", version > "version"; }' < version
Xecho `date`'";' >> vers.c
END_OF_FILE
if test 1100 -ne `wc -c <'newvers.sh'`; then
    echo shar: \"'newvers.sh'\" unpacked with wrong size!
fi
# end of 'newvers.sh'
fi
if test -f 'popen.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'popen.c'\"
else
echo shar: Extracting \"'popen.c'\" \(3643 characters\)
sed "s/^X//" >'popen.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1988 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software written by Ken Arnold and
X * published in UNIX Review, Vol. 6, No. 8.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * static char sccsid[] = "@(#)popen.c	5.7 (Berkeley) 9/1/88";
X */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)popen.c	5.2 (Berkeley) 9/22/88";
X#endif /* not lint */
X
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <stdio.h>
X
X/*
X * Special version of popen which avoids call to shell.  This insures noone
X * may create a pipe to a hidden program as a side effect of a list or dir
X * command.
X */
X#ifdef ultrix
Xtypedef short uid_t;
X#endif
X
Xstatic uid_t *pids;
Xstatic int fds;
X
XFILE *
Xpopen(program, type)
X	char *program, *type;
X{
X	register char *cp;
X	FILE *iop;
X	int argc, gargc, pdes[2], pid;
X	char **pop, *argv[100], *gargv[1000], *vv[2];
X	extern char **glob(), **copyblk(), *strtok();
X
X	if (*type != 'r' && *type != 'w' || type[1])
X		return(NULL);
X
X	if (!pids) {
X		if ((fds = getdtablesize()) <= 0)
X			return(NULL);
X		if (!(pids =
X		    (uid_t *)malloc((u_int)(fds * sizeof(uid_t)))))
X			return(NULL);
X		bzero(pids, fds * sizeof(uid_t));
X	}
X	if (pipe(pdes) < 0)
X		return(NULL);
X
X	/* break up string into pieces */
X	for (argc = 0, cp = program;; cp = NULL)
X		if (!(argv[argc++] = strtok(cp, " \t\n")))
X			break;
X
X	/* glob each piece */
X	gargv[0] = argv[0];
X	for (gargc = argc = 1; argv[argc]; argc++) {
X		if (!(pop = glob(argv[argc]))) {	/* globbing failed */
X			vv[0] = argv[argc];
X			vv[1] = NULL;
X			pop = copyblk(vv);
X		}
X		argv[argc] = (char *)pop;		/* save to free later */
X		while (*pop && gargc < 1000)
X			gargv[gargc++] = *pop++;
X	}
X	gargv[gargc] = NULL;
X
X	iop = NULL;
X	switch(pid = vfork()) {
X	case -1:			/* error */
X		(void)close(pdes[0]);
X		(void)close(pdes[1]);
X		goto free;
X		/* NOTREACHED */
X	case 0:				/* child */
X		if (*type == 'r') {
X			if (pdes[1] != 1) {
X				dup2(pdes[1], 1);
X				(void)close(pdes[1]);
X			}
X			(void)close(pdes[0]);
X		} else {
X			if (pdes[0] != 0) {
X				dup2(pdes[0], 0);
X				(void)close(pdes[0]);
X			}
X			(void)close(pdes[1]);
X		}
X		execv(gargv[0], gargv);
X		_exit(1);
X	}
X	/* parent; assume fdopen can't fail...  */
X	if (*type == 'r') {
X		iop = fdopen(pdes[0], type);
X		(void)close(pdes[1]);
X	} else {
X		iop = fdopen(pdes[1], type);
X		(void)close(pdes[0]);
X	}
X	pids[fileno(iop)] = pid;
X
Xfree:	for (argc = 1; argv[argc] != NULL; argc++)
X		blkfree((char **)argv[argc]);
X	return(iop);
X}
X
Xpclose(iop)
X	FILE *iop;
X{
X	register int fdes;
X	long omask;
X	int pid, stat_loc;
X	u_int waitpid();
X
X	/*
X	 * pclose returns -1 if stream is not associated with a
X	 * `popened' command, or, if already `pclosed'.
X	 */
X	if (pids[fdes = fileno(iop)] == 0)
X		return(-1);
X	(void)fclose(iop);
X	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
X	while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1);
X	(void)sigsetmask(omask);
X	pids[fdes] = 0;
X	return(stat_loc);
X}
END_OF_FILE
if test 3643 -ne `wc -c <'popen.c'`; then
    echo shar: \"'popen.c'\" unpacked with wrong size!
fi
# end of 'popen.c'
fi
if test -f 'strtok.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'strtok.c'\"
else
echo shar: Extracting \"'strtok.c'\" \(744 characters\)
sed "s/^X//" >'strtok.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1980 Regents of the University of California.
X * All rights reserved.  The Berkeley software License Agreement
X * specifies the terms and conditions for redistribution.
X */
X
X/*
X * Sys5 compat routine
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)strtok.c	5.2 (Berkeley) 86/03/09";
X#endif
X
Xchar *
Xstrtok(s, sep)
X	register char *s, *sep;
X{
X	register char *p;
X	register c;
X	static char *lasts;
X
X	if (s == 0)
X		s = lasts;
X	if (s == 0)
X		return (0);
X
X	while (c = *s) {
X		if (!index(sep, c))
X			break;
X		s++;
X	}
X
X	if (c == '\0') {
X		lasts = 0;
X		return (0);
X	}
X
X	for (p = s; c = *++p; )
X		if (index(sep, c))
X			break;
X
X	if (c == '\0')
X		lasts = 0;
X	else {
X		*p++ = '\0';
X		lasts = p;
X	}
X	return (s);
X}
END_OF_FILE
if test 744 -ne `wc -c <'strtok.c'`; then
    echo shar: \"'strtok.c'\" unpacked with wrong size!
fi
# end of 'strtok.c'
fi
if test -f 'vers.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'vers.c'\"
else
echo shar: Extracting \"'vers.c'\" \(63 characters\)
sed "s/^X//" >'vers.c' <<'END_OF_FILE'
Xchar version[] = "Version 4.206 Thu Oct 11 14:35:13 EDT 1990";
END_OF_FILE
if test 63 -ne `wc -c <'vers.c'`; then
    echo shar: \"'vers.c'\" unpacked with wrong size!
fi
# end of 'vers.c'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
