summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
Diffstat (limited to 'libexec')
-rw-r--r--libexec/Makefile8
-rw-r--r--libexec/atrun/Makefile13
-rw-r--r--libexec/atrun/atrun.877
-rw-r--r--libexec/atrun/atrun.c327
-rw-r--r--libexec/atrun/atrun.h33
-rw-r--r--libexec/bootpd/Makefile20
-rw-r--r--libexec/bootpd/README102
-rw-r--r--libexec/bootpd/Version.c48
-rw-r--r--libexec/bootpd/announce46
-rw-r--r--libexec/bootpd/announce.2.137
-rw-r--r--libexec/bootpd/announce.2.251
-rw-r--r--libexec/bootpd/bootp.h137
-rw-r--r--libexec/bootpd/bootpd.8164
-rw-r--r--libexec/bootpd/bootpd.c1729
-rw-r--r--libexec/bootpd/bootpd.h228
-rw-r--r--libexec/bootpd/bootptab125
-rw-r--r--libexec/bootpd/bootptab.5404
-rw-r--r--libexec/bootpd/hash.c386
-rw-r--r--libexec/bootpd/hash.h137
-rw-r--r--libexec/bootpd/newvers.sh24
-rw-r--r--libexec/bootpd/readfile.c2128
-rw-r--r--libexec/bugfiler/bugformat2
-rw-r--r--libexec/comsat/comsat.88
-rw-r--r--libexec/comsat/comsat.c51
-rw-r--r--libexec/crond/Makefile17
-rw-r--r--libexec/crond/Makefile.vixie123
-rw-r--r--libexec/crond/README93
-rw-r--r--libexec/crond/THANKS29
-rw-r--r--libexec/crond/config.h115
-rw-r--r--libexec/crond/cron.h263
-rw-r--r--libexec/crond/crond.856
-rw-r--r--libexec/crond/crond.c317
-rw-r--r--libexec/crond/database.c273
-rw-r--r--libexec/crond/do_command.c583
-rw-r--r--libexec/crond/entry.c486
-rw-r--r--libexec/crond/env.c162
-rw-r--r--libexec/crond/job.c76
-rw-r--r--libexec/crond/misc.c706
-rw-r--r--libexec/crond/user.c133
-rw-r--r--libexec/ftpd/ftpcmd.y12
-rw-r--r--libexec/getty/gettytab.56
-rw-r--r--libexec/pppd/pppd.8663
-rw-r--r--libexec/rlogind/rlogind.c4
-rw-r--r--libexec/rpc.rstatd/Makefile6
-rw-r--r--libexec/rpc.rusersd/Makefile6
-rw-r--r--libexec/rpc.rusersd/rusers_proc.c19
-rw-r--r--libexec/rpc.rwalld/Makefile6
-rw-r--r--libexec/rshd/rshd.c2
-rw-r--r--libexec/telnetd/Makefile2
-rw-r--r--libexec/telnetd/ext.h4
-rw-r--r--libexec/telnetd/sys_term.c12
-rw-r--r--libexec/telnetd/telnetd.c8
52 files changed, 6805 insertions, 3662 deletions
diff --git a/libexec/Makefile b/libexec/Makefile
index 542f0890732a..ac0119481fc2 100644
--- a/libexec/Makefile
+++ b/libexec/Makefile
@@ -1,10 +1,10 @@
-# $Id: Makefile,v 1.4 1993/09/16 00:50:45 jtc Exp $
+# $Id: Makefile,v 1.7 1994/01/25 22:51:39 martin Exp $
# From: @(#)Makefile 5.7 (Berkeley) 4/1/91
#
-SUBDIR= bugfiler comsat crond elvispreserve fingerd ftpd getNAME getty \
- mail.local makekey pppd rexecd rlogind rpc.rstatd rpc.rusersd \
- rpc.rwalld rshd talkd telnetd tftpd uucpd
+SUBDIR= atrun bugfiler bootpd comsat elvispreserve fingerd ftpd getNAME \
+ getty mail.local makekey pppd rexecd rlogind rpc.rstatd \
+ rpc.rusersd rpc.rwalld rshd talkd telnetd tftpd uucpd
# kpasswdd not ported, it is old kerberosIV
diff --git a/libexec/atrun/Makefile b/libexec/atrun/Makefile
new file mode 100644
index 000000000000..356718a4e6ef
--- /dev/null
+++ b/libexec/atrun/Makefile
@@ -0,0 +1,13 @@
+# $Id: Makefile,v 1.1 1994/01/05 01:02:56 nate Exp $
+
+PROG= atrun
+MAN8= atrun.8
+
+BINDIR= /usr/libexec
+BINOWN= root
+
+CFLAGS+= -I${.CURDIR}/../../usr.bin/at
+LDADD+= -lutil
+DPADD+= ${LIBUTIL}
+
+.include <bsd.prog.mk>
diff --git a/libexec/atrun/atrun.8 b/libexec/atrun/atrun.8
new file mode 100644
index 000000000000..b4166d93d5e7
--- /dev/null
+++ b/libexec/atrun/atrun.8
@@ -0,0 +1,77 @@
+.\"
+.\" Copyright (c) 1993 Christopher G. Demetriou
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Christopher G. Demetriou.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software withough specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: atrun.8,v 1.2 1994/01/05 01:03:58 nate Exp $
+.\"
+.Dd December 5, 1993
+.Dt ATRUN 8
+.Os FreeBSD 1.1
+.Sh NAME
+.Nm atrun
+.Nd run jobs queued for later execution
+.\"
+.Sh SYOPSIS
+.Nm atrun
+.Sh DESCRIPTION
+The
+.Nm atrun
+utility runs commands queued by
+.Xr at 1 .
+It is usually invoked by
+.Xr crond 8
+every ten minutes.
+.Sh FILES
+.Bl -tag -width /var/at/lockfile -compact
+.It Pa /var/at/jobs
+Directory containing job files
+.It Pa /var/at/spool
+Directory containing output spool files
+.It Pa /var/at/lockfile
+Job-creation lock file.
+.El
+.Sh SEE ALSO
+.Xr crond 8 ,
+.Xr at 1
+.Sh AUTHOR
+.Bl -tag
+Thomas Koenig, ig25@rz.uni-karlsruhe.de
+.El
+.Sh BUGS
+The functionality of
+.Nm atrun
+should arguaby be merged into
+.Xr crond 8 .
+.Sh CAVEATS
+Since the default configuration causes
+.Nm atrun
+to be invoked every ten minutes,
+commands queued by
+.Xr at 1
+may end up being executed up to nine minutes
+later than would be otherwise expected.
diff --git a/libexec/atrun/atrun.c b/libexec/atrun/atrun.c
new file mode 100644
index 000000000000..5594533e8d75
--- /dev/null
+++ b/libexec/atrun/atrun.c
@@ -0,0 +1,327 @@
+/*
+ * atrun.c - run jobs queued by at; run with root privileges.
+ * Copyright (c) 1993 by Thomas Koenig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* System Headers */
+
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include <paths.h>
+
+/* Local headers */
+
+#define MAIN
+#include "privs.h"
+#include "pathnames.h"
+#include "atrun.h"
+
+/* File scope variables */
+
+static char *namep;
+static char rcsid[] = "$Id: atrun.c,v 1.1 1994/01/05 01:03:00 nate Exp $";
+
+/* Local functions */
+static void
+perr(a)
+ const char *a;
+{
+ syslog(LOG_ERR, "%s: %m", a);
+ exit(EXIT_FAILURE);
+}
+
+static int
+write_string(fd, a)
+ int fd;
+ const char *a;
+{
+ return write(fd, a, strlen(a));
+}
+
+static void
+run_file(filename, uid, gid)
+ const char *filename;
+ uid_t uid;
+ gid_t gid;
+{
+ /*
+ * Run a file by by spawning off a process which redirects I/O,
+ * spawns a subshell, then waits for it to complete and spawns another
+ * process to send mail to the user.
+ */
+ pid_t pid;
+ int fd_out, fd_in;
+ int queue;
+ char mailbuf[9];
+ char *mailname = NULL;
+ FILE *stream;
+ int send_mail = 0;
+ struct stat buf;
+ off_t size;
+ struct passwd *pentry;
+ int fflags;
+
+ pid = fork();
+ if (pid == -1)
+ perr("Cannot fork");
+ else if (pid > 0)
+ return;
+
+ /*
+ * Let's see who we mail to. Hopefully, we can read it from the
+ * command file; if not, send it to the owner, or, failing that, to
+ * root.
+ */
+
+ PRIV_START
+
+ stream = fopen(filename, "r");
+
+ PRIV_END
+
+ if (stream == NULL)
+ perr("Cannot open input file");
+
+ if ((fd_in = dup(fileno(stream))) < 0)
+ perr("Error duplicating input file descriptor");
+
+ if ((fflags = fcntl(fd_in, F_GETFD)) < 0)
+ perr("Error in fcntl");
+
+ fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC);
+
+ if (fscanf(stream, "#! /bin/sh\n# mail %8s %d", mailbuf, &send_mail) == 2) {
+ mailname = mailbuf;
+ } else {
+ pentry = getpwuid(uid);
+ if (pentry == NULL)
+ mailname = "root";
+ else
+ mailname = pentry->pw_name;
+ }
+ fclose(stream);
+ if (chdir(_PATH_ATSPOOL) < 0)
+ perr("Cannot chdir to " _PATH_ATSPOOL);
+
+ /*
+ * Create a file to hold the output of the job we are about to
+ * run. Write the mail header.
+ */
+ if ((fd_out = open(filename,
+ O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR)) < 0)
+ perr("Cannot create output file");
+
+ write_string(fd_out, "Subject: Output from your job ");
+ write_string(fd_out, filename);
+ write_string(fd_out, "\n\n");
+ fstat(fd_out, &buf);
+ size = buf.st_size;
+
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ pid = fork();
+ if (pid < 0)
+ perr("Error in fork");
+ else if (pid == 0) {
+ char *nul = NULL;
+ char **nenvp = &nul;
+
+ /*
+ * Set up things for the child; we want standard input from
+ * the input file, and standard output and error sent to
+ * our output file.
+ */
+
+ if (lseek(fd_in, (off_t) 0, SEEK_SET) < 0)
+ perr("Error in lseek");
+
+ if (dup(fd_in) != STDIN_FILENO)
+ perr("Error in I/O redirection");
+
+ if (dup(fd_out) != STDOUT_FILENO)
+ perr("Error in I/O redirection");
+
+ if (dup(fd_out) != STDERR_FILENO)
+ perr("Error in I/O redirection");
+
+ close(fd_in);
+ close(fd_out);
+ if (chdir(_PATH_ATJOBS) < 0)
+ perr("Cannot chdir to " _PATH_ATJOBS);
+
+ queue = *filename;
+
+ PRIV_START
+
+ if (queue > 'b')
+ nice(queue - 'b');
+
+ if (setgid(gid) < 0)
+ perr("Cannot change group");
+
+ if (setuid(uid) < 0)
+ perr("Cannot set user id");
+
+ chdir("/");
+
+ if (execle("/bin/sh", "sh", (char *) NULL, nenvp) != 0)
+ perr("Exec failed");
+
+ PRIV_END
+ }
+ /* We're the parent. Let's wait. */
+ close(fd_in);
+ close(fd_out);
+ waitpid(pid, (int *) NULL, 0);
+
+ stat(filename, &buf);
+ if ((buf.st_size != size) || send_mail) {
+ /* Fork off a child for sending mail */
+ pid = fork();
+ if (pid < 0)
+ perr("Fork failed");
+ else if (pid == 0) {
+ if (open(filename, O_RDONLY) != STDIN_FILENO)
+ perr("Cannot reopen output file");
+
+ execl(_PATH_SENDMAIL, _PATH_SENDMAIL, mailname,
+ (char *) NULL);
+ perr("Exec failed");
+ }
+ waitpid(pid, (int *) NULL, 0);
+ }
+ unlink(filename);
+ exit(EXIT_SUCCESS);
+}
+
+/* Global functions */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ /*
+ * Browse through _PATH_ATJOBS, checking all the jobfiles wether
+ * they should be executed and or deleted. The queue is coded into
+ * the first byte of the job filename, the date (in minutes since
+ * Eon) as a hex number in the following eight bytes, followed by
+ * a dot and a serial number. A file which has not been executed
+ * yet is denoted by its execute - bit set. For those files which
+ * are to be executed, run_file() is called, which forks off a
+ * child which takes care of I/O redirection, forks off another
+ * child for execution and yet another one, optionally, for sending
+ * mail. Files which already have run are removed during the
+ * next invocation.
+ */
+ DIR *spool;
+ struct dirent *dirent;
+ struct stat buf;
+ int older;
+ unsigned long ctm;
+ char queue;
+
+ /*
+ * We don't need root privileges all the time; running under uid
+ * and gid daemon is fine.
+ */
+
+ RELINQUISH_PRIVS_ROOT(0) /* it's setuid root */
+ openlog("atrun", LOG_PID, LOG_CRON);
+
+ namep = argv[0];
+ if (chdir(_PATH_ATJOBS) != 0)
+ perr("Cannot change to " _PATH_ATJOBS);
+
+ /*
+ * Main loop. Open spool directory for reading and look over all
+ * the files in there. If the filename indicates that the job
+ * should be run and the x bit is set, fork off a child which sets
+ * its user and group id to that of the files and exec a /bin/sh
+ * which executes the shell script. Unlink older files if they
+ * should no longer be run. For deletion, their r bit has to be
+ * turned on.
+ */
+ if ((spool = opendir(".")) == NULL)
+ perr("Cannot read " _PATH_ATJOBS);
+
+ while ((dirent = readdir(spool)) != NULL) {
+ double la;
+
+ if (stat(dirent->d_name, &buf) != 0)
+ perr("Cannot stat in " _PATH_ATJOBS);
+
+ /* We don't want directories */
+ if (!S_ISREG(buf.st_mode))
+ continue;
+
+ if (sscanf(dirent->d_name, "%c%8lx", &queue, &ctm) != 2)
+ continue;
+
+ if ((queue == 'b') && ((getloadavg(&la, 1) != 1) ||
+ (la > ATRUN_MAXLOAD)))
+ continue;
+
+ older = (time_t) ctm *60 <= time(NULL);
+
+ /* The file is executable and old enough */
+ if (older && (S_IXUSR & buf.st_mode)) {
+ /*
+ * Now we know we want to run the file, we can turn
+ * off the execute bit
+ */
+
+ PRIV_START
+
+ if (chmod(dirent->d_name, S_IRUSR) != 0)
+ perr("Cannot change file permissions");
+
+ PRIV_END
+
+ run_file(dirent->d_name, buf.st_uid, buf.st_gid);
+ }
+ /* Delete older files */
+ if (older && !(S_IXUSR & buf.st_mode) &&
+ (S_IRUSR & buf.st_mode))
+ unlink(dirent->d_name);
+ }
+ closelog();
+ exit(EXIT_SUCCESS);
+}
diff --git a/libexec/atrun/atrun.h b/libexec/atrun/atrun.h
new file mode 100644
index 000000000000..74e9b1514097
--- /dev/null
+++ b/libexec/atrun/atrun.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: atrun.h,v 1.1 1994/01/05 01:03:02 nate Exp $
+ */
+
+#define ATRUN_MAXLOAD 1.5
diff --git a/libexec/bootpd/Makefile b/libexec/bootpd/Makefile
new file mode 100644
index 000000000000..00d9d6fcfce7
--- /dev/null
+++ b/libexec/bootpd/Makefile
@@ -0,0 +1,20 @@
+# The next few lines may be uncommented and changed to alter the default
+# filenames bootpd uses for its configuration and dump files.
+#CONFFILE=-DCONFIG_FILE=\"/usr/etc/bootptab\"
+#DUMPFILE=-DDUMP_FILE=\"/usr/etc/bootpd.dump\"
+#FILESPECS=${CONFFILE} ${DUMPFILE}
+
+# Remove the -DVEND_CMU if you don't wish to support the "CMU vendor format"
+# in addition to the RFC1048 format.
+
+PROG= bootpd
+CFLAGS+=-DSYSLOG -DDEBUG -DVEND_CMU -DPRIVATE=static ${FILESPECS} -traditional
+SRCS= bootpd.c readfile.c hash.c version.c
+MAN5= bootptab.5
+MAN8= bootpd.8
+CLEANFILES+=version.c version
+
+version.c:
+ sh ${.CURDIR}/newvers.sh ${.CURDIR}/Version.c
+
+.include <bsd.prog.mk>
diff --git a/libexec/bootpd/README b/libexec/bootpd/README
new file mode 100644
index 000000000000..f99f2efc341a
--- /dev/null
+++ b/libexec/bootpd/README
@@ -0,0 +1,102 @@
+This is a port of bootpd (CMU version 2.2a) to NetBSD-current.
+
+BOOTPD is a useful adjunct to the nfs diskless boot EPROM code.
+
+The alternatives for initiating a boot of a kernel across a network
+are to use RARP protocol, or BOOTP protocol. BOOTP is more flexible;
+it allows additional items of information to be returned to the
+booting client; it also supports booting across gateways.
+
+There are two parts to this package:
+
+- The bootpd sources to be compiled and installed.
+
+- A patch to etc/services and etc/inetd.conf to define the bootpd
+network service names and to define the bootpd task to inetd. These
+items are in the PATCH file.
+
+If you have problems or questions about this port, send me email at
+mckim@lerc.nasa.gov
+
+- Jim McKim
+
+enclosed below is the original README:
+
+
+This directory contains the source for the CMU BOOTP server. The files
+include:
+
+README This file
+bootpd.8 The manual page
+bootp.h The protocol header file
+bootpd.h The server header file
+bootpd.c The main server module
+readfile.c The configuration file-reading routines
+hash.h The hash table header file
+hash.c The hash table module
+Version.c The version module
+newvers.sh A shell script to generate new version numbers
+Makefile The makefile
+bootptab An example database file for the server
+gmods Text describing optional gateway modifications
+
+
+Notes:
+1) BOOTP was originally designed and implemented by Bill Croft at Stanford.
+ Much of the credit for the ideas and the code goes to him. We've added
+ code to support the vendor specific area of the packet as specified in
+ RFC1048. We've also improved the host lookup algorithm and added some
+ extra logging.
+
+2) The server now uses syslog to do logging. Specifically it uses the 4.3bsd
+ version. I've #ifdef'd all of these calls. If you are running 4.2 you
+ should compile without the -DSYSLOG switch.
+
+3) You must update your /etc/services file to contain the following two lines:
+ bootps 67/udp # bootp server
+ bootpc 68/udp # bootp client
+
+4) The code and the bootptab should be reasonably well commented. If you
+ have any questions, just let us know.
+
+Construction:
+ Make sure all of the files exist first. If anything is missing,
+ please contact either Walt Wimer or Drew Perkins by E-mail or phone.
+ Addresses and phone numbers are listed below.
+
+ Type 'make'. The options at present are: -DSYSLOG which enables logging
+ code, -DDEBUG which enables table dumping via signals, and -DVEND_CMU
+ which enables the CMU extensions for CMU PC/IP.
+
+ Edit the bootptab. The man page and the comments in the file should
+ explain how to go about doing so. If you have any problems, let me know.
+
+ Type 'make install'. This should put all of the files in the right place.
+
+ Edit your /etc/rc.local or /etc/inetd.conf file to start up bootpd upon
+ reboot.
+
+Care and feeding:
+ If you change the interface cards on your host or add new hosts you will
+ need to update /etc/bootptab. Just edit it as before. Once you write
+ it back out, bootpd will notice that there is a new copy and will
+ reread it the next time it gets a request.
+
+ If your bootp clients don't get a response then several things might be
+ wrong. Most often, the entry for that host is not in the database.
+ Check the hardware address and then check the entry and make sure
+ everything is right. Other problems include the server machine crashing,
+ bad cables, and the like. If your network is very congested you should
+ try making your bootp clients send additional requests before giving up.
+
+
+November 7, 1988
+
+
+Walter L. Wimer Drew D. Perkins
+ww0n@andrew.cmu.edu ddp@andrew.cmu.edu
+(412) 268-6252 (412) 268-8576
+
+4910 Forbes Ave
+Pittsburgh, PA 15213
+
diff --git a/libexec/bootpd/Version.c b/libexec/bootpd/Version.c
new file mode 100644
index 000000000000..cc908f5115cc
--- /dev/null
+++ b/libexec/bootpd/Version.c
@@ -0,0 +1,48 @@
+#ifndef _BLURB_
+#define _BLURB_
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+#endif /* _BLURB_ */
+
+
+/*
+ * Version.c (this file):
+ *
+ * Copyright (c) 1986, 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ *
+ * @(#)Version.c 4.8 (Berkeley) 4/7/88
+ */
+
+#ifndef lint
+char sccsid[] = "@(#)bootpd 2.2-ALPHA %VERSION% %WHOANDWHERE%\n";
+char rcsid[] = "$Header: /home/cvs/386BSD/src/libexec/bootpd/Version.c,v 1.1 1994/01/25 22:53:29 martin Exp $";
+#endif /* not lint */
+
+char Version[] = "bootpd 2.2-ALPHA %VERSION%\n\t%WHOANDWHERE%\n";
diff --git a/libexec/bootpd/announce b/libexec/bootpd/announce
new file mode 100644
index 000000000000..a3d2cfb40b1c
--- /dev/null
+++ b/libexec/bootpd/announce
@@ -0,0 +1,46 @@
+Subject: RFC-1048 compatible BOOTP server now available
+
+
+An RFC-1048 (BOOTP Vendor Information Extensions) compatible BOOTP (RFC-951)
+server is now available for anonymous FTP from lancaster.andrew.cmu.edu
+(128.2.13.21). The new server can be found in pub/bootp.2.0.tar. This is
+an enhanced version of the existing CMU BOOTP server which was derived from
+the original BOOTP server created by Bill Croft at Stanford.
+
+New features and changes in version 2.0 include:
+
+o Full support for the vendor information extensions described in RFC-1048.
+o Faster response time (host lookup via hash table instead of linear search).
+o New termcap-like configuration file format which allows greater flexibility
+ in specifying the variable vendor information of RFC-1048. Host entries
+ may refer to other hosts as templates so that redundant information need
+ be specified only once.
+o Continued support for the CMU vendor information format. The server may
+ be configured on a per-host basis to always reply with a certain vendor
+ information format or to reply based on the client's request.
+o Expanded logging.
+o The server may now be run by inetd or as a standalone program like the
+ old version.
+o The configuration and debugging dump files may be specified on the command
+ line.
+
+
+The server has been successfully tested on the following machines:
+
+ IBM RT PC running ACIS 4.3 (4.3 BSD)
+ Sun 3/50 running SunOS 3.5
+ DEC MicroVAX II running Ultrix 1.1
+ DEC MicroVAX II running Ultrix 2.2
+
+
+
+Please direct questions, comments, and bug reports to
+Walt Wimer <ww0n@andrew.cmu.edu> or Drew Perkins <ddp@andrew.cmu.edu>.
+
+
+
+Sincerely,
+
+Walt Wimer
+Network Development
+Carnegie Mellon University
diff --git a/libexec/bootpd/announce.2.1 b/libexec/bootpd/announce.2.1
new file mode 100644
index 000000000000..28ddca6a63ee
--- /dev/null
+++ b/libexec/bootpd/announce.2.1
@@ -0,0 +1,37 @@
+Subject: Updated RFC1048 BOOTP server now available
+
+Well, no surprise, bootpd 2.0 had a few bugs. A new improved version,
+bootpd 2.1, is now available for anonymous FTP from lancaster.andrew.cmu.edu
+(128.2.13.21). The new server can be found in pub/bootp.2.1.tar.
+
+Bug fixes and improvements in version 2.1 include:
+
+o The definition of "access to the bootfile" has been changed to require the
+ public read access bit to be set. This is required by tftpd(8), so the
+ server will not reply with a file which a client cannot obtain via TFTP.
+o The RFC1084 bootfile size tag has been implemented. It allows either
+ automatic or manual specification of the bootfile size in 512-octet blocks.
+o Generic tags now work as advertised.
+o A subtle bug which caused strange parsing behavior under certain conditions
+ has been fixed.
+o The RFC1048 vendor information now has the correct byte order on
+ little-endien machines such as the VAX.
+o Failure to specify the bootfile home directory and/or default bootfile in
+ the configuration file no longer causes server crashes. The server now
+ makes a reasonably intelligent choice if this configuration information is
+ missing. This is documented in the man page.
+o BOOTP requests from clients which already know their IP addresses no longer
+ cause server crashes.
+
+
+
+Please direct questions, comments, and bug reports to
+Walt Wimer <ww0n@andrew.cmu.edu> or Drew Perkins <ddp@andrew.cmu.edu>.
+
+
+
+Good luck,
+
+Walt Wimer
+Network Development
+Carnegie Mellon University
diff --git a/libexec/bootpd/announce.2.2 b/libexec/bootpd/announce.2.2
new file mode 100644
index 000000000000..34f2e3982a5b
--- /dev/null
+++ b/libexec/bootpd/announce.2.2
@@ -0,0 +1,51 @@
+
+New features in version 2.2 include:
+
+o A new "td" tag allows the specification of a "TFTP directory" for use
+ with so-called "secure" implementations of tftpd which chroot(2) to a
+ particular directory.
+
+o A new "sa" tag allows the explicit specification of the TFTP
+ "server address." Formerly, the 'siaddr' field of the BOOTREPLY was
+ always filled with the IP address of the BOOTP server. The "sa" tag
+ now allows the BOOTP server and the TFTP server to be two different
+ machines, if desired.
+
+o The server now automatically determines whether it is running as a
+ standalone program (e.g. invoked by hand from a shell) or as a child of
+ /etc/inetd. The -s option and a new -i option are provided to force
+ standalone or inetd mode if necessary.
+
+o When the vendor magic cookie is zero, BOOTP replies now default to the
+ RFC 1084 vendor format, rather than the old CMU format. This helps
+ interoperability with uncooperative BOOTP clients which want RFC 1084
+ format but don't bother filling in the magic cookie properly to tell
+ the server... *sigh* (This makes the ":vm=rfc1048:" tag unnecessary
+ in most cases now. Oh, the "vm" tag now accepts "rfc1084" as well as
+ "rfc1048" -- they mean the same thing.)
+
+o Log messages now include the specific network type. For example, rather
+ than saying "request from hardware address ABCDEF012345", the message is
+ now "request from Ethernet address ABCEDF012345", or "request from
+ IEEE802 address 4000A1B2C3D4".
+
+
+Bug fixes in this version include:
+
+o The automatic bootfile-size calculation now works correctly when the
+ file size is an exact multiple of 512 octets. It used to return a number
+ which was one 512-octet unit greater than necessary.
+
+o A bug in comparing subnet masks has been fixed.
+
+o A bug in calculating the size of the vendor information area when
+ inserting the hostname has been fixed.
+
+
+Other changes:
+
+o The man page has been split into two man pages. One covers the server
+ itself (bootpd.8) and the other covers the configuration file format
+ (bootptab.5).
+
+
diff --git a/libexec/bootpd/bootp.h b/libexec/bootpd/bootp.h
new file mode 100644
index 000000000000..5b373e2b284d
--- /dev/null
+++ b/libexec/bootpd/bootp.h
@@ -0,0 +1,137 @@
+#ifndef _BLURB_
+#define _BLURB_
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+#endif /* _BLURB_ */
+
+/*
+ * Bootstrap Protocol (BOOTP). RFC951 and RFC1395.
+ *
+ * $Header: /home/cvs/386BSD/src/libexec/bootpd/bootp.h,v 1.1 1994/01/25 22:53:32 martin Exp $
+ *
+ *
+ * This file specifies the "implementation-independent" BOOTP protocol
+ * information which is common to both client and server.
+ *
+ */
+
+#define BP_CHADDR_LEN 16
+#define BP_SNAME_LEN 64
+#define BP_FILE_LEN 128
+#define BP_VEND_LEN 64
+
+struct bootp {
+ unsigned char bp_op; /* packet opcode type */
+ unsigned char bp_htype; /* hardware addr type */
+ unsigned char bp_hlen; /* hardware addr length */
+ unsigned char bp_hops; /* gateway hops */
+ unsigned long bp_xid; /* transaction ID */
+ unsigned short bp_secs; /* seconds since boot began */
+ unsigned short bp_unused;
+ struct in_addr bp_ciaddr; /* client IP address */
+ struct in_addr bp_yiaddr; /* 'your' IP address */
+ struct in_addr bp_siaddr; /* server IP address */
+ struct in_addr bp_giaddr; /* gateway IP address */
+ unsigned char bp_chaddr[BP_CHADDR_LEN]; /* client hardware address */
+ unsigned char bp_sname[BP_SNAME_LEN]; /* server host name */
+ unsigned char bp_file[BP_FILE_LEN]; /* boot file name */
+ unsigned char bp_vend[BP_VEND_LEN]; /* vendor-specific area */
+};
+
+/*
+ * UDP port numbers, server and client.
+ */
+#define IPPORT_BOOTPS 67
+#define IPPORT_BOOTPC 68
+
+#define BOOTREPLY 2
+#define BOOTREQUEST 1
+
+/*
+ * Hardware types from Assigned Numbers RFC.
+ */
+#define HTYPE_DIRECT 0 /* non-standard */
+#define HTYPE_ETHERNET 1
+#define HTYPE_EXP_ETHERNET 2
+#define HTYPE_AX25 3
+#define HTYPE_PRONET 4
+#define HTYPE_CHAOS 5
+#define HTYPE_IEEE802 6
+#define HTYPE_ARCNET 7
+
+/*
+ * Vendor magic cookie (v_magic) for CMU
+ */
+#define VM_CMU "CMU"
+
+/*
+ * Vendor magic cookie (v_magic) for RFC1048
+ */
+#define VM_RFC1048 { 99, 130, 83, 99 }
+
+
+
+/*
+ * RFC1395 tag values used to specify what information is being supplied in
+ * the vendor field of the packet.
+ */
+
+#define TAG_PAD ((unsigned char) 0)
+#define TAG_SUBNET_MASK ((unsigned char) 1)
+#define TAG_TIME_OFFSET ((unsigned char) 2)
+#define TAG_GATEWAY ((unsigned char) 3)
+#define TAG_TIME_SERVER ((unsigned char) 4)
+#define TAG_NAME_SERVER ((unsigned char) 5)
+#define TAG_DOMAIN_SERVER ((unsigned char) 6)
+#define TAG_LOG_SERVER ((unsigned char) 7)
+#define TAG_COOKIE_SERVER ((unsigned char) 8)
+#define TAG_LPR_SERVER ((unsigned char) 9)
+#define TAG_IMPRESS_SERVER ((unsigned char) 10)
+#define TAG_RLP_SERVER ((unsigned char) 11)
+#define TAG_HOSTNAME ((unsigned char) 12)
+#define TAG_BOOTSIZE ((unsigned char) 13)
+#define TAG_DUMPFILE ((unsigned char) 14)
+#define TAG_DOMAINNAME ((unsigned char) 15)
+#define TAG_SWAPSERVER ((unsigned char) 16)
+#define TAG_ROOTPATH ((unsigned char) 17)
+#define TAG_END ((unsigned char) 255)
+
+
+
+/*
+ * "vendor" data permitted for CMU bootp clients.
+ */
+
+struct cmu_vend {
+ unsigned char v_magic[4]; /* magic number */
+ unsigned long v_flags; /* flags/opcodes, etc. */
+ struct in_addr v_smask; /* Subnet mask */
+ struct in_addr v_dgate; /* Default gateway */
+ struct in_addr v_dns1, v_dns2; /* Domain name servers */
+ struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */
+ struct in_addr v_ts1, v_ts2; /* Time servers */
+ unsigned char v_unused[25]; /* currently unused */
+};
+
+
+/* v_flags values */
+#define VF_SMASK 1 /* Subnet mask field contains valid data */
diff --git a/libexec/bootpd/bootpd.8 b/libexec/bootpd/bootpd.8
new file mode 100644
index 000000000000..bf0c69a62beb
--- /dev/null
+++ b/libexec/bootpd/bootpd.8
@@ -0,0 +1,164 @@
+.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
+.\"
+.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootpd.8,v 1.1.2.1 1994/05/01 16:06:34 jkh Exp $
+.\"
+.TH BOOTPD 8 "November 11, 1991" "Carnegie Mellon University"
+.UC 6
+
+.SH NAME
+bootpd \- Internet Boot Protocol server
+.SH SYNOPSIS
+.B /usr/libexec/bootpd
+[
+.B \-i
+.B \-s
+.B \-t
+timeout
+.B \-d
+level
+]
+[
+.I configfile
+[
+.I dumpfile
+] ]
+.SH DESCRIPTION
+.I Bootpd
+implements an Internet Bootstrap Protocol server as defined in RFC951,
+RFC1048, and RFC1084. It is normally run by
+.I /usr/sbin/inetd
+by including the following line in the file
+.IR /etc/inetd.conf :
+.PP
+.br
+ bootps dgram udp wait root /usr/libexec/bootpd bootpd
+.PP
+This mode of operation is referred to as "inetd mode" and causes
+.I bootpd
+to be started only when a boot request arrives. If
+.I bootpd
+does not receive another boot request within fifteen minutes of the last one
+it received, it will exit to conserve system resources. The
+.B \-t
+switch may be used to specify a different timeout value in minutes (e.g.
+-t 20). A timeout value of zero means forever.
+.PP
+It is also possible to run
+.I bootpd
+in "standalone mode" (without
+.IR inetd )
+by simply invoking it from a shell like any other regular command.
+Standalone mode is probably the desired mode of operation for large network
+installations with many BOOTP clients. (The greater the number of clients
+listed in the configuration database,
+.IR /etc/bootptab ,
+the longer it takes
+.I bootpd
+to start up. To ensure quick response to clients in a large network,
+it is better to start
+.I bootpd
+once during the server machine's bootup sequence. This can be done by invoking
+.I bootpd
+from within
+.IR /etc/rc.local ,
+for example.)
+.
+In standalone mode, the
+.B \-t
+switch has no effect since
+.I bootpd
+will never exit.
+.PP
+The server automatically detects whether it was invoked from inetd or from a
+shell and automatically selects the appropriate mode. For compatibility with
+older versions of
+.IR bootpd ,
+the
+.B \-s
+switch may be used to force standalone operation. Similarly, the
+.B \-i
+switch may be used to force the inetd mode of operation. Normally, though,
+it should be unnecessary to use these switches.
+.PP
+The
+.B \-d
+switch takes a numeric parameter which sets the level of debugging output.
+For example, -d4 or -d 4 will set the debugging level to 4.
+For compatibility with older versions of
+.IR bootpd ,
+omitting the numeric parameter (i.e. just -d) will
+simply increment the debug level by one.
+.PP
+Upon startup,
+.I bootpd
+first reads its configuration file,
+.IR /etc/bootptab ,
+and then begins listening for BOOTREQUEST packets.
+.PP
+.I Bootpd
+looks in
+.I /etc/services
+to find the UDP port numbers it should use. Two entries are extracted:
+.BR bootps ,
+the bootp server listening port, and
+.BR bootpc ,
+the destination port used to reply to clients. If the port numbers cannot
+be determined this way,
+.I bootpd
+defaults to using 67 for the server and 68 for the client.
+.PP
+.I Bootpd
+completely reloads its configuration file when it receives a hangup signal,
+SIGHUP, or when it receives a BOOTREQUEST packet and detects that the file
+has been updated. If
+.I bootpd
+is compiled with the -DDEBUG option, receipt of a SIGUSR1 signal causes it
+to dump its memory-resident database to
+the file
+.I /etc/bootpd.dump
+or the command-line-specified dumpfile.
+
+.SH FILES
+/etc/bootptab
+.br
+/etc/bootpd.dump
+.br
+/etc/services
+
+.SH BUGS
+Individual host entries must not exceed 1024 characters.
+
+.SH HISTORY
+.TP
+22-Jan-86 Bill Croft at Stanford University
+.br
+Created.
+
+.TP
+30-Jul-86 David Kovar at Carnegie Mellon University
+.br
+Modified to CMU specifications.
+
+.TP
+24-Jul-87 Drew D. Perkins at Carnegie Mellon University
+.br
+Modified to use syslog. Added debugging dumps. Other bug fixes.
+
+.TP
+17-Jul-88 Walter L. Wimer at Carnegie Mellon University
+.br
+Added vendor information to conform to RFC1048.
+Adopted termcap-like file format to allow variable data.
+
+.TP
+11-Nov-91 Walter L. Wimer at Carnegie Mellon University
+.br
+Added TFTP directory- and server-specification features. Added automatic
+detection of inetd/standalone mode, making -s switch no longer necessary.
+Other minor improvements and bug fixes.
+
+.SH "SEE ALSO"
+.br
+bootptab(5), inetd(8), tftpd(8),
+.br
+DARPA Internet Request For Comments RFC951, RFC1048, RFC1084, Assigned Numbers
diff --git a/libexec/bootpd/bootpd.c b/libexec/bootpd/bootpd.c
new file mode 100644
index 000000000000..dd119e426c3d
--- /dev/null
+++ b/libexec/bootpd/bootpd.c
@@ -0,0 +1,1729 @@
+#ifndef _BLURB_
+#define _BLURB_
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+#endif /* _BLURB_ */
+
+
+#ifndef lint
+static char sccsid[] = "@(#)bootp.c 1.1 (Stanford) 1/22/86";
+static char rcsid[] = "$Header: /home/cvs/386BSD/src/libexec/bootpd/bootpd.c,v 1.1 1994/01/25 22:53:36 martin Exp $";
+#endif
+
+
+/*
+ * BOOTP (bootstrap protocol) server daemon.
+ *
+ * Answers BOOTP request packets from booting client machines.
+ * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
+ * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
+ * See accompanying man page -- bootpd.8
+ *
+ *
+ * HISTORY
+ *
+ * 01/22/86 Bill Croft at Stanford University
+ * Created.
+ *
+ * 07/30/86 David Kovar at Carnegie Mellon University
+ * Modified to work at CMU.
+ *
+ * 07/24/87 Drew D. Perkins at Carnegie Mellon University
+ * Modified to use syslog instead of Kovar's
+ * routines. Add debugging dumps. Many other fixups.
+ *
+ * 07/15/88 Walter L. Wimer at Carnegie Mellon University
+ * Added vendor information to conform to RFC1048.
+ * Adopted termcap-like file format to support above.
+ * Added hash table lookup instead of linear search.
+ * Other cleanups.
+ *
+ *
+ * BUGS
+ *
+ * Currently mallocs memory in a very haphazard manner. As such, most of
+ * the program ends up core-resident all the time just to follow all the
+ * stupid pointers around. . . .
+ *
+ */
+
+
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <net/if.h>
+#ifdef SUNOS40
+#include <sys/sockio.h>
+#include <net/if_arp.h>
+#endif
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdio.h>
+#include <strings.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <syslog.h>
+
+#include "bootp.h"
+#include "hash.h"
+#include "bootpd.h"
+
+#define HASHTABLESIZE 257 /* Hash table size (prime) */
+#define DEFAULT_TIMEOUT 15L /* Default timeout in minutes */
+
+#ifndef CONFIG_FILE
+#define CONFIG_FILE "/etc/bootptab"
+#endif
+#ifndef DUMP_FILE
+#define DUMP_FILE "/etc/bootpd.dump"
+#endif
+
+
+
+/*
+ * Externals, forward declarations, and global variables
+ */
+
+extern char Version[];
+extern char *sys_errlist[];
+extern int errno, sys_nerr;
+
+void usage();
+void insert_u_long();
+void dump_host();
+void list_ipaddresses();
+#ifdef VEND_CMU
+void dovend_cmu();
+#endif
+void dovend_rfc1048();
+boolean hwlookcmp();
+boolean iplookcmp();
+void insert_generic();
+void insert_ip();
+int dumptab();
+int chk_access();
+void report();
+char *get_errmsg();
+
+/*
+ * IP port numbers for client and server obtained from /etc/services
+ */
+
+u_short bootps_port, bootpc_port;
+
+
+/*
+ * Internet socket and interface config structures
+ */
+
+struct sockaddr_in s_in;
+struct sockaddr_in from; /* Packet source */
+struct ifreq ifreq[10]; /* Holds interface configuration */
+struct ifconf ifconf; /* Int. config ioctl block (pnts to ifreq) */
+struct arpreq arpreq; /* Arp request ioctl block */
+
+
+/*
+ * General
+ */
+
+int debug = 0; /* Debugging flag (level) */
+int s; /* Socket file descriptor */
+byte buf[1024]; /* Receive packet buffer */
+struct timezone tzp; /* Time zone offset for clients */
+struct timeval tp; /* Time (extra baggage) */
+long secondswest; /* Time zone offset in seconds */
+char hostname[MAXHOSTNAMELEN]; /* System host name */
+
+/*
+ * Globals below are associated with the bootp database file (bootptab).
+ */
+
+char *bootptab = NULL;
+#ifdef DEBUG
+char *bootpd_dump = NULL;
+#endif
+
+
+
+/*
+ * Vendor magic cookies for CMU and RFC1048
+ */
+
+unsigned char vm_cmu[4] = VM_CMU;
+unsigned char vm_rfc1048[4] = VM_RFC1048;
+
+
+/*
+ * Hardware address lengths (in bytes) and network name based on hardware
+ * type code. List in order specified by Assigned Numbers RFC; Array index
+ * is hardware type code. Entries marked as zero are unknown to the author
+ * at this time. . . .
+ */
+
+struct hwinfo hwinfolist[MAXHTYPES + 1] = {
+ { 0, "Reserved" }, /* Type 0: Reserved (don't use this) */
+ { 6, "Ethernet" }, /* Type 1: 10Mb Ethernet (48 bits) */
+ { 1, "3Mb Ethernet" }, /* Type 2: 3Mb Ethernet (8 bits) */
+ { 0, "AX.25" }, /* Type 3: Amateur Radio AX.25 */
+ { 1, "ProNET" }, /* Type 4: Proteon ProNET Token Ring */
+ { 0, "Chaos" }, /* Type 5: Chaos */
+ { 6, "IEEE 802" }, /* Type 6: IEEE 802 Networks */
+ { 0, "ARCNET" } /* Type 7: ARCNET */
+};
+
+
+/*
+ * Main hash tables
+ */
+
+hash_tbl *hwhashtable;
+hash_tbl *iphashtable;
+hash_tbl *nmhashtable;
+
+
+
+
+/*
+ * Initialization such as command-line processing is done and then the main
+ * server loop is started.
+ */
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct timeval actualtimeout, *timeout;
+ struct bootp *bp = (struct bootp *) buf;
+ struct servent *servp;
+ char *stmp;
+ int n, tolen, fromlen;
+ int nfound, readfds;
+ int standalone;
+
+ stmp = NULL;
+ standalone = FALSE;
+ actualtimeout.tv_usec = 0L;
+ actualtimeout.tv_sec = 60 * DEFAULT_TIMEOUT;
+ timeout = &actualtimeout;
+
+
+ /*
+ * Assume a socket was passed to us from inetd.
+ *
+ * Use getsockname() to determine if descriptor 0 is indeed a socket
+ * (and thus we are probably a child of inetd) or if it is instead
+ * something else and we are running standalone.
+ */
+ s = 0;
+ tolen = sizeof(s_in);
+ bzero((char *) &s_in, tolen);
+ errno = 0;
+ if (getsockname(s, &s_in, &tolen) == 0) {
+ /*
+ * Descriptor 0 is a socket. Assume we're running as a child of inetd.
+ */
+ bootps_port = ntohs(s_in.sin_port);
+ standalone = FALSE;
+ } else {
+ if (errno == ENOTSOCK) {
+ /*
+ * Descriptor 0 is NOT a socket. Run in standalone mode.
+ */
+ standalone = TRUE;
+ } else {
+ /*
+ * Something else went wrong. Punt.
+ */
+ fprintf(stderr, "bootpd: getsockname: %s\n",
+ get_network_errmsg());
+ exit(1);
+ }
+ }
+
+
+ /*
+ * Read switches.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 't':
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "bootpd: invalid timeout specification\n");
+ break;
+ }
+ actualtimeout.tv_sec = (long) (60 * n);
+ /*
+ * If the actual timeout is zero, pass a NULL pointer
+ * to select so it blocks indefinitely, otherwise,
+ * point to the actual timeout value.
+ */
+ timeout = (n > 0) ? &actualtimeout : NULL;
+ break;
+ case 'd':
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else if (argv[1] && argv[1][0] == '-') {
+ /*
+ * Backwards-compatible behavior:
+ * no parameter, so just increment the debug flag.
+ */
+ debug++;
+ break;
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "bootpd: invalid debug level\n");
+ break;
+ }
+ debug = n;
+ break;
+ case 's':
+ standalone = TRUE;
+ break;
+ case 'i':
+ standalone = FALSE;
+ break;
+ default:
+ fprintf(stderr, "bootpd: unknown switch: -%c\n",
+ argv[0][1]);
+ usage();
+ break;
+ }
+ } else {
+ if (!bootptab) {
+ bootptab = argv[0];
+#ifdef DEBUG
+ } else if (!bootpd_dump) {
+ bootpd_dump = argv[0];
+#endif
+ } else {
+ fprintf(stderr, "bootpd: unknown argument: %s\n", argv[0]);
+ usage();
+ }
+ }
+ }
+
+ /*
+ * Get hostname.
+ */
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ fprintf(stderr, "bootpd: can't get hostname\n");
+ exit(1);
+ }
+
+ /*
+ * Set default file names if not specified on command line
+ */
+ if (!bootptab) {
+ bootptab = CONFIG_FILE;
+ }
+#ifdef DEBUG
+ if (!bootpd_dump) {
+ bootpd_dump = DUMP_FILE;
+ }
+#endif
+
+
+ if (standalone) {
+ /*
+ * Go into background and disassociate from controlling terminal.
+ */
+ if (debug < 3) {
+ if (fork())
+ exit(0);
+ for (n = 0; n < 10; n++)
+ (void) close(n);
+ (void) open("/", O_RDONLY);
+ (void) dup2(0, 1);
+ (void) dup2(0, 2);
+ n = open("/dev/tty", O_RDWR);
+ if (n >= 0) {
+ ioctl(n, TIOCNOTTY, (char *) 0);
+ (void) close(n);
+ }
+ }
+ /*
+ * Nuke any timeout value
+ */
+ timeout = NULL;
+ }
+
+
+#ifdef SYSLOG
+ /*
+ * Initialize logging.
+ */
+#ifndef LOG_CONS
+#define LOG_CONS 0 /* Don't bother if not defined... */
+#endif
+#ifndef LOG_DAEMON
+#define LOG_DAEMON 0
+#endif
+ openlog("bootpd", LOG_PID | LOG_CONS, LOG_DAEMON);
+#endif
+
+ /*
+ * Log startup
+ */
+ report(LOG_INFO, "%s", Version);
+
+ /*
+ * Get our timezone offset so we can give it to clients if the
+ * configuration file doesn't specify one.
+ */
+ if (gettimeofday(&tp, &tzp) < 0) {
+ secondswest = 0L; /* Assume GMT for lack of anything better */
+ report(LOG_ERR, "gettimeofday: %s\n", get_errmsg());
+ } else {
+ secondswest = 60L * tzp.tz_minuteswest; /* Convert to seconds */
+ }
+
+ /*
+ * Allocate hash tables for hardware address, ip address, and hostname
+ */
+ hwhashtable = hash_Init(HASHTABLESIZE);
+ iphashtable = hash_Init(HASHTABLESIZE);
+ nmhashtable = hash_Init(HASHTABLESIZE);
+ if (!(hwhashtable && iphashtable && nmhashtable)) {
+ report(LOG_ERR, "Unable to allocate hash tables.\n");
+ exit(1);
+ }
+
+
+ /*
+ * Read the bootptab file once immediately upon startup.
+ */
+ readtab();
+
+
+ if (standalone) {
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "socket: %s\n", get_network_errmsg());
+ exit(1);
+ }
+
+ /*
+ * Get server's listening port number
+ */
+ servp = getservbyname("bootps", "udp");
+ if (servp) {
+ bootps_port = ntohs((u_short) servp->s_port);
+ } else {
+ report(LOG_ERR,
+ "udp/bootps: unknown service -- assuming port %d\n",
+ IPPORT_BOOTPS);
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ }
+
+ /*
+ * Bind socket to BOOTPS port.
+ */
+ s_in.sin_family = AF_INET;
+ s_in.sin_addr.s_addr = INADDR_ANY;
+ s_in.sin_port = htons(bootps_port);
+ if (bind(s, &s_in, sizeof(s_in)) < 0) {
+ report(LOG_ERR, "bind: %s\n", get_network_errmsg());
+ exit(1);
+ }
+ }
+
+
+ /*
+ * Get destination port number so we can reply to client
+ */
+ servp = getservbyname("bootpc", "udp");
+ if (servp) {
+ bootpc_port = ntohs(servp->s_port);
+ } else {
+ report(LOG_ERR,
+ "udp/bootpc: unknown service -- assuming port %d\n",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
+ }
+
+
+ /*
+ * Determine network configuration.
+ */
+ ifconf.ifc_len = sizeof(ifreq);
+ ifconf.ifc_req = ifreq;
+ if ((ioctl(s, SIOCGIFCONF, (caddr_t) &ifconf) < 0) ||
+ (ifconf.ifc_len <= 0)) {
+ report(LOG_ERR, "ioctl: %s\n", get_network_errmsg());
+ exit(1);
+ }
+
+
+ /*
+ * Set up signals to read or dump the table.
+ */
+ if ((int) signal(SIGHUP, readtab) < 0) {
+ report(LOG_ERR, "signal: %s\n", get_errmsg());
+ exit(1);
+ }
+#ifdef DEBUG
+ if ((int) signal(SIGUSR1, dumptab) < 0) {
+ report(LOG_ERR, "signal: %s\n", get_errmsg());
+ exit(1);
+ }
+#endif
+
+ /*
+ * Process incoming requests.
+ */
+ for (;;) {
+ readfds = 1 << s;
+ nfound = select(s + 1, &readfds, NULL, NULL, timeout);
+ if (nfound < 0) {
+ if (errno != EINTR) {
+ report(LOG_ERR, "select: %s\n", get_errmsg());
+ }
+ continue;
+ }
+ if (!(readfds & (1 << s))) {
+ report(LOG_INFO, "exiting after %ld minutes of inactivity\n",
+ actualtimeout.tv_sec / 60);
+ exit(0);
+ }
+ fromlen = sizeof(from);
+ n = recvfrom(s, buf, sizeof(buf), 0, &from, &fromlen);
+ if (n <= 0) {
+ continue;
+ }
+
+ if (n < sizeof(struct bootp)) {
+ if (debug) {
+ report(LOG_INFO, "received short packet\n");
+ }
+ continue;
+ }
+
+ readtab(); /* maybe re-read bootptab */
+ switch (bp->bp_op) {
+ case BOOTREQUEST:
+ request();
+ break;
+
+ case BOOTREPLY:
+ reply();
+ break;
+ }
+ }
+}
+
+
+
+
+/*
+ * Print "usage" message and exit
+ */
+
+void usage()
+{
+ fprintf(stderr,
+"usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
+ fprintf(stderr, "\t -d n\tset debug level\n");
+ fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
+ fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
+ fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
+ exit(1);
+}
+
+
+
+/*
+ * Process BOOTREQUEST packet.
+ *
+ * (Note, this version of the bootpd.c server never forwards
+ * the request to another server. In our environment the
+ * stand-alone gateways perform that function.)
+ *
+ * (Also this version does not interpret the hostname field of
+ * the request packet; it COULD do a name->address lookup and
+ * forward the request there.)
+ */
+request()
+{
+ struct bootp *bp = (struct bootp *) buf;
+ struct host *hp;
+ int n;
+ char *path;
+ struct host dummyhost;
+ long bootsize;
+ unsigned hlen, hashcode;
+ char realpath[1024];
+
+ /*
+ * If the servername field is set, compare it against us.
+ * If we're not being addressed, ignore this request.
+ * If the server name field is null, throw in our name.
+ */
+ if (strlen(bp->bp_sname)) {
+ if (strcmp((char *)bp->bp_sname, hostname)) {
+ return;
+ }
+ } else {
+ strcpy((char *)bp->bp_sname, hostname);
+ }
+ bp->bp_op = BOOTREPLY;
+ if (bp->bp_ciaddr.s_addr == 0) {
+ /*
+ * client doesnt know his IP address,
+ * search by hardware address.
+ */
+ if (debug) {
+ report(LOG_INFO, "request from %s address %s\n",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_htype));
+ }
+
+ dummyhost.htype = bp->bp_htype;
+ hlen = haddrlength(bp->bp_htype);
+ bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
+ hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
+ hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
+ &dummyhost);
+ if (hp == NULL) {
+ report(LOG_NOTICE, "%s address not found: %s\n",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_htype));
+ return; /* not found */
+ }
+ (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
+
+ } else {
+
+ /*
+ * search by IP address.
+ */
+ if (debug) {
+ report(LOG_INFO, "request from IP addr %s\n",
+ inet_ntoa(bp->bp_ciaddr));
+ }
+ dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
+ hashcode = hash_HashFunction((char *) &(bp->bp_ciaddr.s_addr), 4);
+ hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
+ &dummyhost);
+ if (hp == NULL) {
+ report(LOG_NOTICE,
+ "IP address not found: %s\n", inet_ntoa(bp->bp_ciaddr));
+ return;
+ }
+ }
+
+ if (debug) {
+ report(LOG_INFO, "found %s %s\n", inet_ntoa(hp->iaddr),
+ hp->hostname->string);
+ }
+
+ /*
+ * If a specific TFTP server address was specified in the bootptab file,
+ * fill it in, otherwise zero it.
+ */
+ (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
+ hp->bootserver.s_addr : 0L;
+
+ /*
+ * This next line is a bit of a mystery. It seems to be vestigial
+ * code (from Stanford???) which should probably be axed.
+ */
+ if (strcmp(bp->bp_file, "sunboot14") == 0)
+ bp->bp_file[0] = 0; /* pretend it's null */
+
+
+ /*
+ * Fill in the client's proper bootfile.
+ *
+ * If the client specifies an absolute path, try that file with a
+ * ".host" suffix and then without. If the file cannot be found, no
+ * reply is made at all.
+ *
+ * If the client specifies a null or relative file, use the following
+ * table to determine the appropriate action:
+ *
+ * Homedir Bootfile Client's file
+ * specified? specified? specification Action
+ * -------------------------------------------------------------------
+ * No No Null Send null filename
+ * No No Relative Discard request
+ * No Yes Null Send if absolute else null
+ * No Yes Relative Discard request
+ * Yes No Null Send null filename
+ * Yes No Relative Lookup with ".host"
+ * Yes Yes Null Send home/boot or bootfile
+ * Yes Yes Relative Lookup with ".host"
+ *
+ */
+
+ if (hp->flags.tftpdir) {
+ strcpy(realpath, hp->tftpdir->string);
+ path = &realpath[strlen(realpath)];
+ } else {
+ path = realpath;
+ }
+
+ if (bp->bp_file[0]) {
+ /*
+ * The client specified a file.
+ */
+ if (bp->bp_file[0] == '/') {
+ strcpy(path, bp->bp_file); /* Absolute pathname */
+ } else {
+ if (hp->flags.homedir) {
+ strcpy(path, hp->homedir->string);
+ strcat(path, "/");
+ strcat(path, bp->bp_file);
+ } else {
+ report(LOG_NOTICE,
+ "requested file \"%s\" not found: hd unspecified\n",
+ bp->bp_file);
+ return;
+ }
+ }
+ } else {
+ /*
+ * No file specified by the client.
+ */
+ if (hp->flags.bootfile && ((hp->bootfile->string)[0] == '/')) {
+ strcpy(path, hp->bootfile->string);
+ } else if (hp->flags.homedir && hp->flags.bootfile) {
+ strcpy(path, hp->homedir->string);
+ strcat(path, "/");
+ strcat(path, hp->bootfile->string);
+ } else {
+ bzero(bp->bp_file, sizeof(bp->bp_file));
+ goto skip_file; /* Don't bother trying to access the file */
+ }
+ }
+
+ /*
+ * First try to find the file with a ".host" suffix
+ */
+ n = strlen(path);
+ strcat(path, ".");
+ strcat(path, hp->hostname->string);
+ if (chk_access(realpath, &bootsize) < 0) {
+ path[n] = 0; /* Try it without the suffix */
+ if (chk_access(realpath, &bootsize) < 0) {
+ if (bp->bp_file[0]) {
+ /*
+ * Client wanted specific file
+ * and we didn't have it.
+ */
+ report(LOG_NOTICE,
+ "requested file not found: \"%s\"\n", path);
+ return;
+ } else {
+ /*
+ * Client didn't ask for a specific file and we couldn't
+ * access the default file, so just zero-out the bootfile
+ * field in the packet and continue processing the reply.
+ */
+ bzero(bp->bp_file, sizeof(bp->bp_file));
+ goto skip_file;
+ }
+ }
+ }
+ strcpy(bp->bp_file, path);
+
+skip_file: ;
+
+
+
+ if (debug > 1) {
+ report(LOG_INFO, "vendor magic field is %d.%d.%d.%d\n",
+ (int) ((bp->bp_vend)[0]),
+ (int) ((bp->bp_vend)[1]),
+ (int) ((bp->bp_vend)[2]),
+ (int) ((bp->bp_vend)[3]));
+ }
+
+ /*
+ * If this host isn't set for automatic vendor info then copy the
+ * specific cookie into the bootp packet, thus forcing a certain
+ * reply format.
+ */
+ if (!hp->flags.vm_auto) {
+ bcopy(hp->vm_cookie, bp->bp_vend, 4);
+ }
+
+ /*
+ * Figure out the format for the vendor-specific info.
+ */
+ if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
+ /* Not an RFC1048 bootp client */
+#ifdef VEND_CMU
+ dovend_cmu(bp, hp);
+#else
+ dovend_rfc1048(bp, hp, bootsize);
+#endif
+ } else {
+ /* RFC1048 conformant bootp client */
+ dovend_rfc1048(bp, hp, bootsize);
+ }
+ sendreply(0);
+}
+
+
+
+/*
+ * Process BOOTREPLY packet (something is using us as a gateway).
+ */
+
+reply()
+{
+ if (debug) {
+ report(LOG_INFO, "processing boot reply\n");
+ }
+ sendreply(1);
+}
+
+
+
+/*
+ * Send a reply packet to the client. 'forward' flag is set if we are
+ * not the originator of this reply packet.
+ */
+sendreply(forward)
+ int forward;
+{
+ struct bootp *bp = (struct bootp *) buf;
+ struct in_addr dst;
+ struct sockaddr_in to;
+
+ to = s_in;
+
+ to.sin_port = htons(bootpc_port);
+ /*
+ * If the client IP address is specified, use that
+ * else if gateway IP address is specified, use that
+ * else make a temporary arp cache entry for the client's NEW
+ * IP/hardware address and use that.
+ */
+ if (bp->bp_ciaddr.s_addr) {
+ dst = bp->bp_ciaddr;
+ } else if (bp->bp_giaddr.s_addr && forward == 0) {
+ dst = bp->bp_giaddr;
+ to.sin_port = htons(bootps_port);
+ } else {
+ dst = bp->bp_yiaddr;
+ setarp(&dst, bp->bp_chaddr, bp->bp_hlen);
+ }
+
+ if (forward == 0) {
+ /*
+ * If we are originating this reply, we
+ * need to find our own interface address to
+ * put in the bp_siaddr field of the reply.
+ * If this server is multi-homed, pick the
+ * 'best' interface (the one on the same net
+ * as the client).
+ */
+#if 0
+ int maxmatch = 0;
+ int len, m;
+ struct ifreq *ifrq, *ifrmax;
+
+ ifrmax = ifrq = &ifreq[0];
+ len = ifconf.ifc_len;
+ for (; len > 0; len -= sizeof(ifreq[0]), ifrq++) {
+ m = nmatch(&dst, &((struct sockaddr_in *)
+ (&ifrq->ifr_addr))->sin_addr);
+ if (m > maxmatch) {
+ maxmatch = m;
+ ifrmax = ifrq;
+ }
+ }
+#endif
+ int maxmatch = 0;
+ int len, m;
+ struct ifreq *ifrq, *ifrmax;
+ char *p;
+
+ ifrmax = &ifreq[0];
+ p = (char *)&ifreq[0];
+ len = ifconf.ifc_len;
+ for (; len > 0; ) {
+ ifrq = (struct ifreq *)p;
+ m = nmatch(&dst, &((struct sockaddr_in *)
+ (&ifrq->ifr_addr))->sin_addr);
+ if (m > maxmatch) {
+ maxmatch = m;
+ ifrmax = ifrq;
+ }
+ p += ifrq->ifr_addr.sa_len + IFNAMSIZ;
+ len -= ifrq->ifr_addr.sa_len + IFNAMSIZ;
+ }
+
+ if (bp->bp_giaddr.s_addr == 0) {
+ if (maxmatch == 0) {
+ return;
+ }
+ bp->bp_giaddr = ((struct sockaddr_in *)
+ (&ifrmax->ifr_addr))->sin_addr;
+ }
+
+ /*
+ * If a specific TFTP server address wasn't specified
+ * in the bootptab file, fill in our own address.
+ */
+ if (bp->bp_siaddr.s_addr == 0) {
+ bp->bp_siaddr = ((struct sockaddr_in *)
+ (&ifrmax->ifr_addr))->sin_addr;
+ }
+ }
+
+ to.sin_addr = dst;
+ if (sendto(s, bp, sizeof(struct bootp), 0, &to, sizeof(to)) < 0) {
+ report(LOG_ERR, "sendto: %s\n", get_network_errmsg());
+ }
+}
+
+
+
+/*
+ * Return the number of leading bytes matching in the
+ * internet addresses supplied.
+ */
+nmatch(ca,cb)
+ char *ca, *cb;
+{
+ int n,m;
+
+ for (m = n = 0 ; n < 4 ; n++) {
+ if (*ca++ != *cb++)
+ return(m);
+ m++;
+ }
+ return(m);
+}
+
+
+
+/*
+ * Setup the arp cache so that IP address 'ia' will be temporarily
+ * bound to hardware address 'ha' of length 'len'.
+ */
+setarp(ia, ha, len)
+ struct in_addr *ia;
+ byte *ha;
+ int len;
+{
+ struct sockaddr_in *si;
+
+ bzero((caddr_t)&arpreq, sizeof(arpreq));
+
+ arpreq.arp_pa.sa_family = AF_INET;
+ si = (struct sockaddr_in *) &arpreq.arp_pa;
+ si->sin_addr = *ia;
+
+ arpreq.arp_flags = ATF_INUSE | ATF_COM;
+
+ bcopy(ha, arpreq.arp_ha.sa_data, len);
+
+ if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ report(LOG_ERR, "ioctl(SIOCSARP): %s\n", get_network_errmsg());
+ }
+}
+
+
+
+/*
+ * This call checks read access to a file. It returns 0 if the file given
+ * by "path" exists and is publically readable. A value of -1 is returned if
+ * access is not permitted or an error occurs. Successful calls also
+ * return the file size in bytes using the long pointer "filesize".
+ *
+ * The read permission bit for "other" users is checked. This bit must be
+ * set for tftpd(8) to allow clients to read the file.
+ */
+
+int chk_access(path, filesize)
+char *path;
+long *filesize;
+{
+ struct stat buf;
+
+ if ((stat(path, &buf) == 0) && (buf.st_mode & (S_IREAD >> 6))) {
+ *filesize = (long) buf.st_size;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+
+
+#ifdef DEBUG
+
+/*
+ * Dump the internal memory database to bootpd_dump.
+ */
+
+dumptab()
+{
+ int n;
+ struct host *hp;
+ FILE *fp;
+ long t;
+
+ /*
+ * Open bootpd.dump file.
+ */
+ if ((fp = fopen(bootpd_dump, "w")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s\n", bootpd_dump,
+ get_errmsg());
+ exit(1);
+ }
+
+ t = time(NULL);
+ fprintf(fp, "\n# %s\n", Version);
+ fprintf(fp, "# %s: dump of bootp server database.\n", bootpd_dump);
+ fprintf(fp, "#\n# Dump taken %s", ctime(&t));
+ fprintf(fp, "#\n#\n# Legend:\n");
+ fprintf(fp, "#\tbf -- bootfile\n");
+ fprintf(fp, "#\tbs -- bootfile size in 512-octet blocks\n");
+ fprintf(fp, "#\tcs -- cookie servers\n");
+ fprintf(fp, "#\tdf -- dump file name\n");
+ fprintf(fp, "#\tdn -- domain name\n");
+ fprintf(fp, "#\tds -- domain name servers\n");
+ fprintf(fp, "#\tgw -- gateways\n");
+ fprintf(fp, "#\tha -- hardware address\n");
+ fprintf(fp, "#\thd -- home directory for bootfiles\n");
+ fprintf(fp, "#\tht -- hardware type\n");
+ fprintf(fp, "#\tim -- impress servers\n");
+ fprintf(fp, "#\tip -- host IP address\n");
+ fprintf(fp, "#\tlg -- log servers\n");
+ fprintf(fp, "#\tlp -- LPR servers\n");
+ fprintf(fp, "#\tns -- IEN-116 name servers\n");
+ fprintf(fp, "#\trl -- resource location protocol servers\n");
+ fprintf(fp, "#\trp -- root path\n");
+ fprintf(fp, "#\tsm -- subnet mask\n");
+ fprintf(fp, "#\tsw -- swap server\n");
+ fprintf(fp, "#\tto -- time offset (seconds)\n");
+ fprintf(fp, "#\tts -- time servers\n\n\n");
+
+ n = 0;
+ for (hp = (struct host *) hash_FirstEntry(nmhashtable); hp != NULL;
+ hp = (struct host *) hash_NextEntry(nmhashtable)) {
+ dump_host(fp, hp);
+ fprintf(fp, "\n");
+ n++;
+ }
+ fclose(fp);
+
+ report(LOG_INFO, "dumped %d entries to \"%s\".\n", n, bootpd_dump);
+}
+
+
+
+/*
+ * Dump all the available information on the host pointed to by "hp".
+ * The output is sent to the file pointed to by "fp".
+ */
+
+void dump_host(fp, hp)
+FILE *fp;
+struct host *hp;
+{
+ int i;
+ byte *dataptr;
+
+ if (hp) {
+ if (hp->hostname) {
+ fprintf(fp, "%s:", hp->hostname->string);
+ }
+ if (hp->flags.bootfile) {
+ fprintf(fp, "bf=%s:", hp->bootfile->string);
+ }
+ if (hp->flags.bootsize) {
+ fprintf(fp, "bs=");
+ if (hp->flags.bootsize_auto) {
+ fprintf(fp, "auto:");
+ } else {
+ fprintf(fp, "%d:", hp->bootsize);
+ }
+ }
+ if (hp->flags.cookie_server) {
+ fprintf(fp, "cs=");
+ list_ipaddresses(fp, hp->cookie_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.domain_server) {
+ fprintf(fp, "ds=");
+ list_ipaddresses(fp, hp->domain_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.gateway) {
+ fprintf(fp, "gw=");
+ list_ipaddresses(fp, hp->gateway);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.homedir) {
+ fprintf(fp, "hd=%s:", hp->homedir->string);
+ }
+ if (hp->flags.name_switch && hp->flags.send_name) {
+ fprintf(fp, "hn:");
+ }
+ if (hp->flags.htype) {
+ fprintf(fp, "ht=%u:", (unsigned) hp->htype);
+ if (hp->flags.haddr) {
+ fprintf(fp, "ha=%s:", haddrtoa(hp->haddr, hp->htype));
+ }
+ }
+ if (hp->flags.impress_server) {
+ fprintf(fp, "im=");
+ list_ipaddresses(fp, hp->impress_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.swap_server) {
+ fprintf(fp, "sw=%s:", inet_ntoa(hp->subnet_mask));
+ }
+ if (hp->flags.iaddr) {
+ fprintf(fp, "ip=%s:", inet_ntoa(hp->iaddr));
+ }
+ if (hp->flags.log_server) {
+ fprintf(fp, "lg=");
+ list_ipaddresses(fp, hp->log_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.lpr_server) {
+ fprintf(fp, "lp=");
+ list_ipaddresses(fp, hp->lpr_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.name_server) {
+ fprintf(fp, "ns=");
+ list_ipaddresses(fp, hp->name_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.rlp_server) {
+ fprintf(fp, "rl=");
+ list_ipaddresses(fp, hp->rlp_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.bootserver) {
+ fprintf(fp, "sa=%s:", inet_ntoa(hp->bootserver));
+ }
+ if (hp->flags.subnet_mask) {
+ fprintf(fp, "sm=%s:", inet_ntoa(hp->subnet_mask));
+ }
+ if (hp->flags.tftpdir) {
+ fprintf(fp, "td=%s:", hp->tftpdir->string);
+ }
+ if (hp->flags.rootpath) {
+ fprintf(fp, "rp=%s:", hp->rootpath->string);
+ }
+ if (hp->flags.domainname) {
+ fprintf(fp, "dn=%s:", hp->domainname->string);
+ }
+ if (hp->flags.dumpfile) {
+ fprintf(fp, "df=%s:", hp->dumpfile->string);
+ }
+ if (hp->flags.time_offset) {
+ if (hp->flags.timeoff_auto) {
+ fprintf(fp, "to=auto:");
+ } else {
+ fprintf(fp, "to=%ld:", hp->time_offset);
+ }
+ }
+ if (hp->flags.time_server) {
+ fprintf(fp, "ts=");
+ list_ipaddresses(fp, hp->time_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.vendor_magic) {
+ fprintf(fp, "vm=");
+ if (hp->flags.vm_auto) {
+ fprintf(fp, "auto:");
+ } else if (!bcmp(hp->vm_cookie, vm_cmu, 4)) {
+ fprintf(fp, "cmu:");
+ } else if (!bcmp(hp->vm_cookie, vm_rfc1048, 4)) {
+ fprintf(fp, "rfc1048");
+ } else {
+ fprintf(fp, "%d.%d.%d.%d:",
+ (int) ((hp->vm_cookie)[0]),
+ (int) ((hp->vm_cookie)[1]),
+ (int) ((hp->vm_cookie)[2]),
+ (int) ((hp->vm_cookie)[3]));
+ }
+ }
+ if (hp->flags.generic) {
+ fprintf(fp, "generic=");
+ dataptr = hp->generic->data;
+ for (i = hp->generic->length; i > 0; i--) {
+ fprintf(fp, "%02X", (int) *dataptr++);
+ }
+ fprintf(fp, ":");
+ }
+ }
+}
+
+
+
+/*
+ * Dump an entire struct in_addr_list of IP addresses to the indicated file.
+ *
+ * The addresses are printed in standard ASCII "dot" notation and separated
+ * from one another by a single space. A single leading space is also
+ * printed before the first adddress.
+ *
+ * Null lists produce no output (and no error).
+ */
+
+void list_ipaddresses(fp, ipptr)
+ FILE *fp;
+ struct in_addr_list *ipptr;
+{
+ unsigned count;
+ struct in_addr *addrptr;
+
+ if (ipptr) {
+ count = ipptr->addrcount;
+ addrptr = ipptr->addr;
+ if (count-- > 0) {
+ fprintf(fp, "%s", inet_ntoa(*addrptr++));
+ while (count-- > 0) {
+ fprintf(fp, " %s", inet_ntoa(*addrptr++));
+ }
+ }
+ }
+}
+#endif /* DEBUG */
+
+
+
+#ifdef VEND_CMU
+
+/*
+ * Insert the CMU "vendor" data for the host pointed to by "hp" into the
+ * bootp packet pointed to by "bp".
+ */
+
+void dovend_cmu(bp, hp)
+ struct bootp *bp;
+ struct host *hp;
+{
+ struct cmu_vend *vendp;
+ struct in_addr_list *taddr;
+
+ /*
+ * Initialize the entire vendor field to zeroes.
+ */
+ bzero(bp->bp_vend, sizeof(bp->bp_vend));
+
+ /*
+ * Fill in vendor information. Subnet mask, default gateway,
+ * domain name server, ien name server, time server
+ */
+ vendp = (struct cmu_vend *) bp->bp_vend;
+ if (hp->flags.subnet_mask) {
+ (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
+ (vendp->v_flags) |= VF_SMASK;
+ if (hp->flags.gateway) {
+ (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
+ }
+ }
+ if (hp->flags.domain_server) {
+ taddr = hp->domain_server;
+ if (taddr->addrcount > 0) {
+ (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
+ if (taddr->addrcount > 1) {
+ (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
+ }
+ }
+ }
+ if (hp->flags.name_server) {
+ taddr = hp->name_server;
+ if (taddr->addrcount > 0) {
+ (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
+ if (taddr->addrcount > 1) {
+ (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
+ }
+ }
+ }
+ if (hp->flags.time_server) {
+ taddr = hp->time_server;
+ if (taddr->addrcount > 0) {
+ (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
+ if (taddr->addrcount > 1) {
+ (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
+ }
+ }
+ }
+ strcpy(vendp->v_magic, vm_cmu);
+
+ if (debug > 1) {
+ report(LOG_INFO, "sending CMU-style reply\n");
+ }
+}
+
+#endif /* VEND_CMU */
+
+
+
+/*
+ * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
+ * bootp packet pointed to by "bp".
+ */
+
+void dovend_rfc1048(bp, hp, bootsize)
+ struct bootp *bp;
+ struct host *hp;
+ long bootsize;
+{
+ int bytesleft, len;
+ byte *vp;
+ char *tmpstr;
+
+ vp = bp->bp_vend;
+ bytesleft = sizeof(bp->bp_vend); /* Initial vendor area size */
+ bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
+ vp += 4;
+ bytesleft -= 4;
+
+ if (hp->flags.time_offset) {
+ *vp++ = TAG_TIME_OFFSET; /* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ if (hp->flags.timeoff_auto) {
+ insert_u_long(htonl(secondswest), &vp);
+ } else {
+ insert_u_long(htonl(hp->time_offset), &vp); /* -4 bytes */
+ }
+ bytesleft -= 6;
+ }
+ if (hp->flags.subnet_mask) {
+ *vp++ = TAG_SUBNET_MASK; /* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
+ bytesleft -= 6; /* Fix real count */
+ if (hp->flags.gateway) {
+ insert_ip(TAG_GATEWAY, hp->gateway, &vp, &bytesleft);
+ }
+ }
+ if (hp->flags.bootsize) {
+ bootsize = (hp->flags.bootsize_auto) ?
+ ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
+ *vp++ = TAG_BOOTSIZE;
+ *vp++ = 2;
+ *vp++ = (byte) ((bootsize >> 8) & 0xFF);
+ *vp++ = (byte) (bootsize & 0xFF);
+ bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
+ }
+ if (hp->flags.swap_server) {
+ *vp++ = TAG_SWAPSERVER; /* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(hp->swapserver.s_addr, &vp); /* -4 bytes */
+ bytesleft -= 6; /* Fix real count */
+ }
+ if (hp->flags.rootpath) {
+ /*
+ * Check for room for rootpath. Add 2 to account for
+ * TAG_ROOTPATH and length.
+ */
+ len = strlen(hp->rootpath->string);
+ if ((len + 2) <= bytesleft) {
+ *vp++ = TAG_ROOTPATH;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->rootpath->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ }
+ if (hp->flags.dumpfile) {
+ /*
+ * Check for room for dumpfile. Add 2 to account for
+ * TAG_DUMPFILE and length.
+ */
+ len = strlen(hp->dumpfile->string);
+ if ((len + 2) <= bytesleft) {
+ *vp++ = TAG_DUMPFILE;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->dumpfile->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ }
+ if (hp->flags.domain_server) {
+ insert_ip(TAG_DOMAIN_SERVER, hp->domain_server, &vp, &bytesleft);
+ }
+ if (hp->flags.domainname) {
+ /*
+ * Check for room for domainname. Add 2 to account for
+ * TAG_DOMAINNAME and length.
+ */
+ len = strlen(hp->domainname->string);
+ if ((len + 2) <= bytesleft) {
+ *vp++ = TAG_DOMAINNAME;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->domainname->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ }
+ if (hp->flags.name_server) {
+ insert_ip(TAG_NAME_SERVER, hp->name_server, &vp, &bytesleft);
+ }
+ if (hp->flags.rlp_server) {
+ insert_ip(TAG_RLP_SERVER, hp->rlp_server, &vp, &bytesleft);
+ }
+ if (hp->flags.time_server) {
+ insert_ip(TAG_TIME_SERVER, hp->time_server, &vp, &bytesleft);
+ }
+ if (hp->flags.lpr_server) {
+ insert_ip(TAG_LPR_SERVER, hp->lpr_server, &vp, &bytesleft);
+ }
+ if (hp->flags.name_switch && hp->flags.send_name) {
+ /*
+ * Check for room for hostname. Add 2 to account for
+ * TAG_HOSTNAME and length.
+ */
+ len = strlen(hp->hostname->string);
+ if ((len + 2) > bytesleft) {
+ /*
+ * Not enough room for full (domain-qualified) hostname, try
+ * stripping it down to just the first field (host).
+ */
+ tmpstr = hp->hostname->string;
+ len = 0;
+ while (*tmpstr && (*tmpstr != '.')) {
+ tmpstr++;
+ len++;
+ }
+ }
+ if ((len + 2) <= bytesleft) {
+ *vp++ = TAG_HOSTNAME;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->hostname->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ }
+ if (hp->flags.cookie_server) {
+ insert_ip(TAG_COOKIE_SERVER, hp->cookie_server, &vp, &bytesleft);
+ }
+ if (hp->flags.log_server) {
+ insert_ip(TAG_LOG_SERVER, hp->log_server, &vp, &bytesleft);
+ }
+
+ if (hp->flags.generic) {
+ insert_generic(hp->generic, &vp, &bytesleft);
+ }
+
+ if (bytesleft >= 1) {
+ *vp++ = TAG_END;
+ bytesleft--;
+ }
+
+ if (debug > 1) {
+ report(LOG_INFO, "sending RFC1048-style reply\n");
+ }
+
+ if (bytesleft > 0) {
+ /*
+ * Zero out any remaining part of the vendor area.
+ */
+ bzero(vp, bytesleft);
+ }
+}
+
+
+
+/*
+ * Compare function to determine whether two hardware addresses are
+ * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
+ * otherwise.
+ *
+ * This function is used when retrieving elements from the hardware address
+ * hash table.
+ */
+
+boolean hwlookcmp(host1, host2)
+ struct host *host1, *host2;
+{
+ if (host1->htype != host2->htype) {
+ return FALSE;
+ }
+ if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+
+/*
+ * Compare function for doing IP address hash table lookup.
+ */
+
+boolean iplookcmp(host1, host2)
+ struct host *host1, *host2;
+{
+ return (host1->iaddr.s_addr == host2->iaddr.s_addr);
+}
+
+
+
+/*
+ * Insert a tag value, a length value, and a list of IP addresses into the
+ * memory buffer indirectly pointed to by "dest". "tag" is the RFC1048 tag
+ * number to use, "iplist" is a pointer to a list of IP addresses
+ * (struct in_addr_list), and "bytesleft" points to an integer which
+ * indicates the size of the "dest" buffer. The number of IP addresses
+ * actually inserted
+ *
+ * This is used to fill the vendor-specific area of a bootp packet in
+ * conformance to RFC1048.
+ */
+
+void insert_ip(tag, iplist, dest, bytesleft)
+ byte tag;
+ struct in_addr_list *iplist;
+ byte **dest;
+ int *bytesleft;
+{
+ struct in_addr *addrptr;
+ unsigned addrcount;
+ byte *d;
+
+ if (iplist && (*bytesleft >= 6)) {
+ d = *dest; /* Save pointer for later */
+ **dest = tag;
+ (*dest) += 2;
+ (*bytesleft) -= 2; /* Account for tag and length */
+ addrptr = iplist->addr;
+ addrcount = iplist->addrcount;
+ while ((*bytesleft >= 4) && (addrcount > 0)) {
+ insert_u_long(addrptr->s_addr, dest);
+ addrptr++;
+ addrcount--;
+ (*bytesleft) -= 4; /* Four bytes per address */
+ }
+ d[1] = (byte) ((*dest - d - 2) & 0xFF);
+ }
+}
+
+
+
+/*
+ * Insert generic data into a bootp packet. The data is assumed to already
+ * be in RFC1048 format. It is inserted using a first-fit algorithm which
+ * attempts to insert as many tags as possible. Tags and data which are
+ * too large to fit are skipped; any remaining tags are tried until they
+ * have all been exhausted.
+ */
+
+void insert_generic(gendata, buff, bytesleft)
+ struct shared_bindata *gendata;
+ byte **buff;
+ int *bytesleft;
+{
+ byte *srcptr;
+ int length, numbytes;
+
+ if (gendata) {
+ srcptr = gendata->data;
+ length = gendata->length;
+ while ((length > 0) && (*bytesleft > 0)) {
+ switch (*srcptr) {
+ case TAG_END:
+ length = 0; /* Force an exit on next iteration */
+ break;
+ case TAG_PAD:
+ *(*buff)++ = *srcptr++;
+ (*bytesleft)--;
+ length--;
+ break;
+ default:
+ numbytes = srcptr[1] + 2;
+ if (*bytesleft >= numbytes) {
+ bcopy(srcptr, *buff, numbytes);
+ (*buff) += numbytes;
+ (*bytesleft) -= numbytes;
+ }
+ srcptr += numbytes;
+ length -= numbytes;
+ break;
+ }
+ }
+ }
+}
+
+
+
+
+/*
+ * Convert a hardware address to an ASCII string.
+ */
+
+char *haddrtoa(haddr, htype)
+ byte *haddr;
+ byte htype;
+{
+ static char haddrbuf[2 * MAXHADDRLEN + 1];
+ char *bufptr;
+ unsigned count;
+
+ bufptr = haddrbuf;
+ for (count = haddrlength(htype); count > 0; count--) {
+ sprintf(bufptr, "%02X", (unsigned) (*haddr++ & 0xFF));
+ bufptr += 2;
+ }
+ return (haddrbuf);
+}
+
+
+
+/*
+ * Insert the unsigned long "value" into memory starting at the byte
+ * pointed to by the byte pointer (*dest). (*dest) is updated to
+ * point to the next available byte.
+ *
+ * Since it is desirable to internally store network addresses in network
+ * byte order (in struct in_addr's), this routine expects longs to be
+ * passed in network byte order.
+ *
+ * However, due to the nature of the main algorithm, the long must be in
+ * host byte order, thus necessitating the use of ntohl() first.
+ */
+
+void insert_u_long(value, dest)
+ unsigned long value;
+ byte **dest;
+{
+ byte *temp;
+ int n;
+
+ value = ntohl(value); /* Must use host byte order here */
+ temp = (*dest += 4);
+ for (n = 4; n > 0; n--) {
+ *--temp = (byte) (value & 0xFF);
+ value >>= 8;
+ }
+ /* Final result is network byte order */
+}
+
+
+
+/*
+ * Return pointer to static string which gives full filesystem error message.
+ */
+
+char *get_errmsg()
+{
+ static char errmsg[80];
+
+ if (errno < sys_nerr) {
+ return sys_errlist[errno];
+ } else {
+ sprintf(errmsg, "Error %d", errno);
+ return errmsg;
+ }
+}
+
+
+
+/*
+ * This routine reports errors and such via stderr and syslog() if
+ * appopriate. It just helps avoid a lot of "#ifdef SYSLOG" constructs
+ * from being scattered throughout the code.
+ *
+ * The syntax is identical to syslog(3), but %m is not considered special
+ * for output to stderr (i.e. you'll see "%m" in the output. . .). Also,
+ * control strings should normally end with \n since newlines aren't
+ * automatically generated for stderr output (whereas syslog strips out all
+ * newlines and adds its own at the end).
+ */
+
+/*VARARGS2*/
+void report(priority, fmt, p0, p1, p2, p3, p4)
+ int priority;
+ char *fmt;
+{
+#ifdef LOG_SALERT
+ static char *levelnames[] = {
+ "unknown level: ",
+ "alert(1): ",
+ "subalert(2): ",
+ "emergency(3): ",
+ "error(4): ",
+ "critical(5): ",
+ "warning(6): ",
+ "notice(7): ",
+ "information(8):",
+ "debug(9): ",
+ "unknown level: "
+ };
+#else
+ static char *levelnames[] = {
+ "emergency(0): ",
+ "alert(1): ",
+ "critical(2): ",
+ "error(3): ",
+ "warning(4): ",
+ "notice(5): ",
+ "information(6):",
+ "debug(7): ",
+ "unknown level: "
+ };
+#endif
+
+ if ((priority < 0) || (priority >= sizeof(levelnames)/sizeof(char *))) {
+ priority = sizeof(levelnames) / sizeof(char *) - 1;
+ }
+
+ /*
+ * Print the message
+ */
+ if (debug > 2) {
+ fprintf(stderr, "bootpd: %s ", levelnames[priority]);
+ fprintf(stderr, fmt, p0, p1, p2, p3, p4);
+ }
+#ifdef SYSLOG
+ syslog(priority, fmt, p0, p1, p2, p3, p4);
+#endif
+}
diff --git a/libexec/bootpd/bootpd.h b/libexec/bootpd/bootpd.h
new file mode 100644
index 000000000000..94fb86e855f1
--- /dev/null
+++ b/libexec/bootpd/bootpd.h
@@ -0,0 +1,228 @@
+#ifndef _BLURB_
+#define _BLURB_
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+#endif /* _BLURB_ */
+
+
+/*
+ * bootpd.h -- common header file for all the modules of the bootpd program.
+ */
+
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef PRIVATE
+#define PRIVATE static
+#endif
+
+#ifndef SIGUSR1
+#define SIGUSR1 30 /* From 4.3 <signal.h> */
+#endif
+
+#define MAXHTYPES 7 /* Number of htypes defined */
+#define MAXHADDRLEN 6 /* Max hw address length in bytes */
+#define MAXSTRINGLEN 80 /* Max string length */
+
+/*
+ * Return the length in bytes of a hardware address of the given type.
+ * Return the canonical name of the network of the given type.
+ */
+#define haddrlength(type) ((hwinfolist[(int) (type)]).hlen)
+#define netname(type) ((hwinfolist[(int) (type)]).name)
+
+
+/*
+ * Return pointer to static string which gives full network error message.
+ */
+#define get_network_errmsg get_errmsg
+
+
+/*
+ * Variables shared among modules.
+ */
+
+extern int debug;
+extern char *bootptab;
+
+extern struct hwinfo hwinfolist[];
+
+extern hash_tbl *hwhashtable;
+extern hash_tbl *iphashtable;
+extern hash_tbl *nmhashtable;
+extern unsigned char vm_cmu[4];
+extern unsigned char vm_rfc1048[4];
+
+
+/*
+ * Functions shared among modules
+ */
+
+extern void report();
+extern char *get_errmsg();
+extern char *haddrtoa();
+extern int readtab();
+
+
+
+/*
+ * Nice typedefs. . .
+ */
+
+typedef int boolean;
+typedef unsigned char byte;
+
+
+/*
+ * This structure holds information about a specific network type. The
+ * length of the network hardware address is stored in "hlen".
+ * The string pointed to by "name" is the cononical name of the network.
+ */
+struct hwinfo {
+ unsigned hlen;
+ char *name;
+};
+
+
+/*
+ * Data structure used to hold an arbitrary-lengthed list of IP addresses.
+ * The list may be shared among multiple hosts by setting the linkcount
+ * appropriately.
+ */
+
+struct in_addr_list {
+ unsigned linkcount, addrcount;
+ struct in_addr addr[1]; /* Dynamically extended */
+};
+
+
+/*
+ * Data structures used to hold shared strings and shared binary data.
+ * The linkcount must be set appropriately.
+ */
+
+struct shared_string {
+ unsigned linkcount;
+ char string[1]; /* Dynamically extended */
+};
+
+struct shared_bindata {
+ unsigned linkcount, length;
+ byte data[1]; /* Dynamically extended */
+};
+
+
+/*
+ * Flag structure which indicates which symbols have been defined for a
+ * given host. This information is used to determine which data should or
+ * should not be reported in the bootp packet vendor info field.
+ */
+
+struct flag {
+ unsigned bootfile :1,
+ bootserver :1,
+ bootsize :1,
+ bootsize_auto :1,
+ cookie_server :1,
+ domain_server :1,
+ gateway :1,
+ generic :1,
+ haddr :1,
+ homedir :1,
+ htype :1,
+ impress_server :1,
+ iaddr :1,
+ log_server :1,
+ lpr_server :1,
+ name_server :1,
+ name_switch :1,
+ rlp_server :1,
+ send_name :1,
+ subnet_mask :1,
+ tftpdir :1,
+ time_offset :1,
+ timeoff_auto :1,
+ time_server :1,
+ vendor_magic :1,
+ dumpfile :1,
+ domainname :1,
+ swap_server :1,
+ rootpath :1,
+ vm_auto :1;
+};
+
+
+
+/*
+ * The flags structure contains TRUE flags for all the fields which
+ * are considered valid, regardless of whether they were explicitly
+ * specified or indirectly inferred from another entry.
+ *
+ * The gateway and the various server fields all point to a shared list of
+ * IP addresses.
+ *
+ * The hostname, home directory, and bootfile are all shared strings.
+ *
+ * The generic data field is a shared binary data structure. It is used to
+ * hold future RFC1048 vendor data until bootpd is updated to understand it.
+ *
+ * The vm_cookie field specifies the four-octet vendor magic cookie to use
+ * if it is desired to always send the same response to a given host.
+ *
+ * Hopefully, the rest is self-explanatory.
+ */
+
+struct host {
+ struct flag flags; /* ALL valid fields */
+ struct in_addr_list *cookie_server,
+ *domain_server,
+ *gateway,
+ *impress_server,
+ *log_server,
+ *lpr_server,
+ *name_server,
+ *rlp_server,
+ *time_server;
+ struct shared_string *bootfile,
+ *hostname,
+ *domainname,
+ *homedir,
+ *tftpdir,
+ *dumpfile,
+ *rootpath;
+ struct shared_bindata *generic;
+ byte vm_cookie[4],
+ htype, /* RFC826 says this should be 16-bits but
+ RFC951 only allocates 1 byte. . . */
+ haddr[MAXHADDRLEN];
+ long time_offset;
+ unsigned int bootsize;
+ struct in_addr bootserver,
+ iaddr,
+ swapserver,
+ subnet_mask;
+};
diff --git a/libexec/bootpd/bootptab b/libexec/bootpd/bootptab
new file mode 100644
index 000000000000..4b1e5464da25
--- /dev/null
+++ b/libexec/bootpd/bootptab
@@ -0,0 +1,125 @@
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# Last update Mon 11/7/88 18:03
+# Blank lines and lines beginning with '#' are ignored.
+#
+# Legend:
+#
+# first field -- hostname
+# (may be full domain name and probably should be)
+#
+# hd -- home directory
+# bf -- bootfile
+# cs -- cookie servers
+# df -- dumpfile
+# dn -- domain name
+# ds -- domain name servers
+# gw -- gateways
+# ha -- hardware address
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# rl -- resource location protocol servers
+# rp -- root path
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# to -- time offset (seconds)
+# ts -- time servers
+
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+#
+
+
+# First, we define a global entry which specifies the stuff every host uses.
+
+global.dummy:\
+ :sm=255.255.255.0:\
+ :hd=/usr/boot:bf=null:\
+ :ds=128.2.35.50 128.2.13.21:\
+ :ns=0x80020b4d 0x80020ffd:\
+ :ts=0x80020b4d 0x80020ffd:\
+ :to=auto:\
+ :dn=cmu.edu:
+
+
+# Next, we can define different master entries for each subnet. . .
+
+subnet13.dummy:\
+ :tc=global.dummy:gw=128.2.13.1:
+
+subnet232.dummy:\
+ :tc=global.dummy:gw=128.2.232.1:
+
+subnet19.dummy:\
+ :tc=global.dummy:gw=128.2.19.1:
+
+
+#
+# We should be able to use as many levels of indirection as desired. Use
+# your imagination. . .
+#
+
+
+# Individual entries (could also have different servers for some/all of these
+# hosts, but we don't really use this feature at CMU):
+
+carnegie:tc=subnet13.dummy:ht=ieee802:ha=7FF8100000AF:ip=128.2.11.1:
+baldwin:tc=subnet19.dummy:ht=ethernet:ha=0800200159C3:ip=128.2.11.10:
+wylie:tc=subnet232.dummy:ht=ethernet:ha=00DD00CADF00:ip=128.2.11.100:
+arnold:tc=subnet19.dummy:ht=ethernet:ha=0800200102AD:ip=128.2.11.102:
+bairdford:tc=subnet19.dummy:ht=ethernet:ha=08002B02A2F9:ip=128.2.11.103:
+bakerstown:tc=subnet19.dummy:ht=ethernet:ha=08002B0287C8:ip=128.2.11.104:
+butlerjct:tc=subnet232.dummy:ht=ethernet:ha=08002001560D:ip=128.2.11.108:
+gastonville:tc=subnet232.dummy:ht=ieee802:ha=7FFF81000A47:ip=128.2.11.115:
+hahntown:tc=subnet13.dummy:ht=ieee802:ha=7FFF81000434:ip=128.2.11.117:
+hickman:tc=subnet19.dummy:ht=ieee802:ha=7FFF810001BA:ip=128.2.11.118:
+lowber:tc=subnet13.dummy:ht=ethernet:ha=00DD00CAF000:ip=128.2.11.121:
+mtoliver:tc=subnet19.dummy:ht=ethernet:ha=00DD00FE1600:ip=128.2.11.122:
+osborne:tc=subnet232.dummy:ht=ethernet:ha=00DD00CAD600:ip=128.2.11.124:
+russelton:tc=subnet232.dummy:ht=ethernet:ha=080020017FC3:ip=128.2.11.126:
+thornburg:tc=subnet13.dummy:ht=ethernet:ha=080020012A33:ip=128.2.11.128:
+
+
+# Hmmm. . . Let's throw in some whitespace for readability. . . .
+
+andrew: tc=subnet19.dummy: ht=ethernet:ha=00DD00C88900: ip=128.2.11.131:
+birdville: tc=subnet19.dummy: ht=ethernet:ha=00DD00FE2D00: ip=128.2.11.14:
+coudersport: tc=subnet13.dummy: ht=ethernet:ha=00DD00CB1E00: ip=128.2.11.143:
+bridgeville: tc=subnet232.dummy: ht=ethernet:ha=080020011394: ip=128.2.11.15:
+franklin: tc=subnet19.dummy: ht=ethernet:ha=08002B02A5D5: ip=128.2.11.150:
+hollidaysburg: tc=subnet19.dummy: ht=ieee802:ha=7FFF810002C8: ip=128.2.11.154:
+honesdale: tc=subnet19.dummy: ht=ethernet:ha=08002B02F83F: ip=128.2.11.155:
+huntingdon: tc=subnet19.dummy: ht=ethernet:ha=08002B02E410: ip=128.2.11.156:
+indiana: tc=subnet13.dummy: ht=ethernet:ha=08002B029BEC: ip=128.2.11.157:
+jimthorpe: tc=subnet232.dummy: ht=ethernet:ha=08002B02FBBA: ip=128.2.11.158:
+kittanning: tc=subnet232.dummy: ht=ethernet:ha=08002B0273FC: ip=128.2.11.159:
+lebanon: tc=subnet232.dummy: ht=ethernet:ha=08002B037F67: ip=128.2.11.162:
+lewisburg: tc=subnet19.dummy: ht=ethernet:ha=50005A1A0DE4: ip=128.2.11.163:
+middleburg: tc=subnet232.dummy: ht=ethernet:ha=00DD00FE1200: ip=128.2.11.169:
+aspinwall: tc=subnet13.dummy: ht=ethernet:ha=08002B03C163: ip=128.2.11.17:
+berlin: tc=subnet13.dummy: ht=ethernet:ha=00DD000A4400: ip=128.2.11.171:
+norristown: tc=subnet13.dummy: ht=ethernet:ha=08002001455B: ip=128.2.11.174:
+pottsville: tc=subnet13.dummy: ht=ethernet:ha=00DD000A3700: ip=128.2.11.177:
+ridgway: tc=subnet19.dummy: ht=ethernet:ha=08002B029425: ip=128.2.11.179:
+scranton: tc=subnet232.dummy: ht=ethernet:ha=0800200113A1: ip=128.2.11.180:
+chalfont: tc=subnet13.dummy: ht=ethernet:ha=08002001124B: ip=128.2.11.19:
+washington: tc=subnet19.dummy: ht=ethernet:ha=00DD00656E00: ip=128.2.11.190:
+wellsboro: tc=subnet13.dummy: ht=ethernet:ha=00DD00CB1C00: ip=128.2.11.192:
+bb1: tc=subnet19.dummy: ht=ethernet:ha=00DD000A1F00: ip=128.2.11.197:
+adamstown: tc=subnet13.dummy: ht=ethernet:ha=08002B02D0E6: ip=128.2.11.199:
+beta: tc=subnet19.dummy: ht=ethernet:ha=02070100B197: ip=128.2.11.2:
+carbondale: tc=subnet232.dummy: ht=ethernet:ha=08002B022A73: ip=128.2.11.206:
+clairton: tc=subnet19.dummy: ht=ethernet:ha=080020010FD1: ip=128.2.11.21:
+egypt: tc=subnet13.dummy: ht=ethernet:ha=00DD00847B00: ip=128.2.11.211:
+fairchance: tc=subnet232.dummy: ht=ethernet:ha=00DD000AB100: ip=128.2.11.212:
+fairhope: tc=subnet232.dummy: ht=ethernet:ha=00DD00CB0800: ip=128.2.11.213:
+galeton: tc=subnet232.dummy: ht=ethernet:ha=08002001138C: ip=128.2.11.215:
+imperial: tc=subnet232.dummy: ht=ethernet:ha=08002001130C: ip=128.2.11.219:
+kingston: tc=subnet232.dummy: ht=ethernet:ha=080020011382: ip=128.2.11.224:
+knox: tc=subnet232.dummy: ht=ethernet:ha=50005A1A0D2A: ip=128.2.11.225:
+lakecity: tc=subnet13.dummy: ht=ethernet:ha=080020011380: ip=128.2.11.226:
diff --git a/libexec/bootpd/bootptab.5 b/libexec/bootpd/bootptab.5
new file mode 100644
index 000000000000..874ed48bad56
--- /dev/null
+++ b/libexec/bootpd/bootptab.5
@@ -0,0 +1,404 @@
+.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
+.\"
+.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootptab.5,v 1.1.2.1 1994/05/01 16:06:36 jkh Exp $
+.\"
+.TH BOOTPTAB 5 "October 31, 1991" "Carnegie Mellon University"
+.UC 6
+
+.SH NAME
+bootptab \- Internet Bootstrap Protocol server database
+.SH DESCRIPTION
+The
+.I bootptab
+file is the configuration database file for
+.IR bootpd ,
+the Internet Bootstrap Protocol server.
+It's format is similar to that of
+.IR termcap (5)
+in which two-character case-sensitive tag symbols are used to
+represent host parameters. These parameter declarations are separated by
+colons (:), with a general format of:
+.PP
+.I " hostname:tg=value. . . :tg=value. . . :tg=value. . . ."
+.PP
+where
+.I hostname
+is the actual name of a bootp client and
+.I tg
+is a two-character tag symbol. Most tags must be followed by an equals-sign
+and a value as above. Some may also appear in a boolean form with no
+value (i.e.
+.RI : tg :).
+The currently recognized tags are:
+.PP
+.br
+ bf Bootfile
+.br
+ bs Bootfile size in 512-octet blocks
+.br
+ cs Cookie server address list
+.br
+ df Merit dump file
+.br
+ dn Domain name
+.br
+ ds Domain name server address list
+.br
+ gw Gateway address list
+.br
+ ha Host hardware address
+.br
+ hd Bootfile home directory
+.br
+ hn Send client's hostname to client
+.br
+ ht Host hardware type (see Assigned Numbers RFC)
+.br
+ im Impress server address list
+.br
+ ip Host IP address
+.br
+ lg Log server address list
+.br
+ lp LPR server address list
+.br
+ ns IEN-116 name server address list
+.br
+ rl Resource location protocol server address list
+.br
+ rp Root path to mount as root
+.br
+ sa TFTP server address client should use
+.br
+ sm Host subnet mask
+.br
+ sw Swap server address
+.br
+ tc Table continuation (points to similar "template" host entry)
+.br
+ td TFTP root directory used by "secure" TFTP servers
+.br
+ to Time offset in seconds from UTC
+.br
+ ts Time server address list
+.br
+ vm Vendor magic cookie selector
+
+.PP
+There is also a generic tag,
+.RI T n ,
+where
+.I n
+is an RFC1084 vendor field tag number. Thus it is possible to immediately
+take advantage of future extensions to RFC1084 without being forced to modify
+.I bootpd
+first. Generic data may be represented as either a stream of hexadecimal
+numbers or as a quoted string of ASCII characters. The length of the generic
+data is automatically determined and inserted into the proper field(s) of the
+RFC1084-style bootp reply.
+.PP
+The following tags take a whitespace-separated list of IP addresses:
+.BR cs ,
+.BR ds ,
+.BR gw ,
+.BR im ,
+.BR lg ,
+.BR lp ,
+.BR ns ,
+.BR rl ,
+and
+.BR ts .
+The
+.BR ip ,
+.BR sa ,
+.BR sw ,
+and
+.B sm
+tags each take a single IP address.
+All IP addresses are specified in standard Internet "dot" notation and may use
+decimal, octal, or hexadecimal numbers (octal numbers begin with 0,
+hexadecimal numbers begin with '0x' or '0X').
+.PP
+The
+.B ht
+tag specifies the hardware type code as either an unsigned decimal, octal, or
+hexadecimal integer or one of the following symbolic names:
+.B ethernet
+or
+.B ether
+for 10Mb Ethernet,
+.B ethernet3
+or
+.B ether3
+for 3Mb experimental Ethernet,
+.BR ieee802 ,
+.BR tr ,
+or
+.B token-ring
+for IEEE 802 networks,
+.B pronet
+for Proteon ProNET Token Ring, or
+.BR chaos ,
+.BR arcnet ,
+or
+.B ax.25
+for Chaos, ARCNET, and AX.25 Amateur Radio networks, respectively.
+The
+.B ha
+tag takes a hardware address which
+.I must
+be specified in hexadecimal; optional periods and/or a leading '0x' may be
+included for readability. The
+.B ha
+tag must be preceded by the
+.B ht
+tag (either explicitly or implicitly; see
+.B tc
+below).
+.PP
+The hostname, home directory, and bootfile are ASCII strings which may be
+optionally surrounded by double quotes ("). The client's request and the
+values of the
+.B hd
+and
+.B bf
+symbols determine how the server fills in the bootfile field of the bootp
+reply packet.
+.PP
+If the client specifies an absolute pathname and that file exists on the
+server machine, that pathname is returned in the reply packet. If the file
+cannot be found, the request is discarded; no reply is sent. If the client
+specifies a relative pathname, a full pathname is formed by prepending the
+value of the
+.B hd
+tag and testing for existence of the file. If the
+.B hd
+tag is not supplied in the configuration file or if the resulting boot file
+cannot be found, then the request is discarded.
+.PP
+Clients which specify null boot files will always elicit a reply from the
+server. The exact reply will again depend upon the
+.B hd
+and
+.B bf
+tags. If the
+.B bf
+tag gives an absolute pathname and the file exists, that pathname is returned
+in the reply packet. Otherwise, if the
+.B hd
+and
+.B bf
+tags together specify an accessible file, that filename is returned in the
+reply. If a complete filename cannot be determined or the file does not
+exist, the reply will contain a zeroed-out bootfile field.
+.PP
+In all these cases, existence of the file means that, in addition to actually
+being present, the file must have its public read access bit set, since this
+is required by
+.IR tftpd (8)
+to permit the file transfer. Also, all filenames are first tried as
+.I filename.hostname
+and then simply as
+.IR filename ,
+thus providing for individual per-host bootfiles.
+.PP
+Some newer versions of
+.I tftpd
+provide a security feature to change their root directory using
+the
+.IR chroot (2)
+system call.
+The
+.B td
+tag may be used to inform
+.I bootpd
+of this special root directory used by
+.IR tftpd .
+The
+.B hd
+tag is actually relative to the root directory specified by the
+.B td
+tag.
+For example, if the real absolute path to your BOOTP client bootfile is
+/tftpboot/bootfiles/bootimage, and
+.IR tftpd
+uses /tftpboot as its "secure" directory, then specify the following in
+.IR bootptab :
+.PP
+.br
+ :td=/tftpboot:hd=/bootfiles:bf=bootimage:
+.PP
+If your bootfiles are located directly in /tftpboot, use:
+.PP
+.br
+ :td=/tftpboot:hd=/:bf=bootimage:
+.PP
+The
+.B sa
+tag may be used to specify the IP address of the particular TFTP server
+you wish the client to use. In the absence of this tag,
+.I bootpd
+will tell the client to perform TFTP to the same machine
+.I bootpd
+is running on.
+.PP
+The time offset
+.B to
+may be either a signed decimal integer specifying the client's
+time zone offset in seconds from UTC, or the keyword
+.B auto
+which uses the server's time zone offset. Specifying the
+.B to
+symbol as a boolean has the same effect as specifying
+.B auto
+as its value.
+.PP
+The bootfile size
+.B bs
+may be either a decimal, octal, or hexadecimal integer specifying the size of
+the bootfile in 512-octet blocks, or the keyword
+.B auto
+which causes the server to automatically calculate the bootfile size at each
+request. As with the time offset, specifying the
+.B bs
+symbol as a boolean has the same effect as specifying
+.B auto
+as its value.
+.PP
+The vendor magic cookie selector (the
+.B vm
+tag) may take one of the following keywords:
+.B auto
+(indicating that vendor information is determined by the client's request),
+.B rfc1048
+or
+.B rfc1084
+(which always forces an RFC1084-style reply), or
+.B cmu
+(which always forces a CMU-style reply).
+.PP
+The
+.B hn
+tag is strictly a boolean tag; it does not take the usual equals-sign and
+value. It's presence indicates that the hostname should be sent to RFC1084
+clients.
+.I Bootpd
+attempts to send the entire hostname as it is specified in the configuration
+file; if this will not fit into the reply packet, the name is shortened to
+just the host field (up to the first period, if present) and then tried.
+In no case is an arbitrarily-truncated hostname sent (if nothing reasonable
+will fit, nothing is sent).
+.PP
+Often, many host entries share common values for certain tags (such as name
+servers, etc.). Rather than repeatedly specifying these tags, a full
+specification can be listed for one host entry and shared by others via the
+.B tc
+(table continuation) mechanism.
+Often, the template entry is a dummy host which doesn't actually exist and
+never sends bootp requests. This feature is similar to the
+.B tc
+feature of
+.IR termcap (5)
+for similar terminals. Note that
+.I bootpd
+allows the
+.B tc
+tag symbol to appear anywhere in the host entry, unlike
+.I termcap
+which requires it to be the last tag. Information explicitly specified for a
+host always overrides information implied by a
+.B tc
+tag symbol, regardless of its location within the entry. The
+value of the
+.B tc
+tag may be the hostname or IP address of any host entry
+previously listed in the configuration file.
+.PP
+Sometimes it is necessary to delete a specific tag after it has been inferred
+via
+.BR tc .
+This can be done using the construction
+.IB tag @
+which removes the effect of
+.I tag
+as in
+.IR termcap (5).
+For example, to completely undo an IEN-116 name server specification, use
+":ns@:" at an appropriate place in the configuration entry. After removal
+with
+.BR @ ,
+a tag is eligible to be set again through the
+.B tc
+mechanism.
+.PP
+Blank lines and lines beginning with "#" are ignored in the configuration
+file. Host entries are separated from one another by newlines; a single host
+entry may be extended over multiple lines if the lines end with a backslash
+(\\). It is also acceptable for lines to be longer than 80 characters. Tags
+may appear in any order, with the following exceptions: the hostname must be
+the very first field in an entry, and the hardware type must precede the
+hardware address.
+.PP
+An example
+.I /etc/bootptab
+file follows:
+.PP
+
+.br
+ # Sample bootptab file
+
+.br
+ default1:\\
+.br
+ :hd=/usr/boot:bf=null:\\
+.br
+ :ds=128.2.35.50 128.2.13.21:\\
+.br
+ :ns=0x80020b4d 0x80020ffd:\\
+.br
+ :ts=0x80020b4d 0x80020ffd:\\
+.br
+ :sm=255.255.0.0:gw=0x8002fe24:\\
+.br
+ :hn:vm=auto:to=-18000:\\
+.br
+ :T37=0x12345927AD3BCF:T99="Special ASCII string":
+
+.br
+ carnegie:ht=6:ha=7FF8100000AF:ip=128.2.11.1:tc=default1:
+.br
+ baldwin:ht=1:ha=0800200159C3:ip=128.2.11.10:tc=default1:
+.br
+ wylie:ht=1:ha=00DD00CADF00:ip=128.2.11.100:tc=default1:
+.br
+ arnold:ht=1:ha=0800200102AD:ip=128.2.11.102:tc=default1:
+.br
+ bairdford:ht=1:ha=08002B02A2F9:ip=128.2.11.103:tc=default1:
+.br
+ bakerstown:ht=1:ha=08002B0287C8:ip=128.2.11.104:tc=default1:
+
+.br
+ # Special domain name server for next host
+.br
+ butlerjct:ht=1:ha=08002001560D:ip=128.2.11.108:ds=128.2.13.42:tc=default1:
+
+.br
+ gastonville:ht=6:ha=7FFF81000A47:ip=128.2.11.115:tc=default1:
+.br
+ hahntown:ht=6:ha=7FFF81000434:ip=128.2.11.117:tc=default1:
+.br
+ hickman:ht=6:ha=7FFF810001BA:ip=128.2.11.118:tc=default1:
+.br
+ lowber:ht=1:ha=00DD00CAF000:ip=128.2.11.121:tc=default1:
+.br
+ mtoliver:ht=1:ha=00DD00FE1600:ip=128.2.11.122:tc=default1:
+
+
+.SH FILES
+/etc/bootptab
+
+.SH "SEE ALSO"
+.br
+bootpd(8), tftpd(8),
+.br
+DARPA Internet Request For Comments RFC951, RFC1048, RFC1084, Assigned Numbers
diff --git a/libexec/bootpd/hash.c b/libexec/bootpd/hash.c
new file mode 100644
index 000000000000..839b5f706cdc
--- /dev/null
+++ b/libexec/bootpd/hash.c
@@ -0,0 +1,386 @@
+#ifndef _BLURB_
+#define _BLURB_
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+#endif /* _BLURB_ */
+
+
+#ifndef lint
+static char rcsid[] = "$Header: /home/cvs/386BSD/src/libexec/bootpd/hash.c,v 1.1 1994/01/25 22:53:45 martin Exp $";
+#endif
+
+
+/*
+ * Generalized hash table ADT
+ *
+ * Provides multiple, dynamically-allocated, variable-sized hash tables on
+ * various data and keys.
+ *
+ * This package attempts to follow some of the coding conventions suggested
+ * by Bob Sidebotham and the AFS Clean Code Committee of the
+ * Information Technology Center at Carnegie Mellon.
+ */
+
+
+#include "hash.h"
+
+#define TRUE 1
+#define FALSE 0
+#define NULL 0
+
+/*
+ * This can be changed to make internal routines visible to debuggers, etc.
+ */
+#define PRIVATE static
+
+
+
+/*
+ * Hash table initialization routine.
+ *
+ * This routine creates and intializes a hash table of size "tablesize"
+ * entries. Successful calls return a pointer to the hash table (which must
+ * be passed to other hash routines to identify the hash table). Failed
+ * calls return NULL.
+ */
+
+hash_tbl *hash_Init(tablesize)
+unsigned tablesize;
+{
+ register hash_tbl *hashtblptr;
+ register unsigned totalsize;
+
+ if (tablesize > 0) {
+ totalsize = sizeof(hash_tbl)
+ + sizeof(hash_member *) * (tablesize - 1);
+ hashtblptr = (hash_tbl *) malloc(totalsize);
+ if (hashtblptr) {
+ bzero((char *) hashtblptr, totalsize);
+ hashtblptr->size = tablesize; /* Success! */
+ hashtblptr->bucketnum = 0;
+ hashtblptr->member = (hashtblptr->table)[0];
+ }
+ } else {
+ hashtblptr = NULL; /* Disallow zero-length tables */
+ }
+ return hashtblptr; /* NULL if failure */
+}
+
+
+
+/*
+ * Recursively frees an entire linked list of bucket members (used in the open
+ * hashing scheme). Does nothing if the passed pointer is NULL.
+ */
+
+PRIVATE void hashi_FreeMember(bucketptr, free_data)
+hash_member *bucketptr;
+void (*free_data)();
+{
+ if (bucketptr) {
+ /*
+ * Free next member if necessary
+ */
+ hashi_FreeMember(bucketptr->next, free_data);
+ (*free_data)(bucketptr->data);
+ free((char *) bucketptr);
+ }
+}
+
+
+
+
+/*
+ * This routine re-initializes the hash table. It frees all the allocated
+ * memory and resets all bucket pointers to NULL.
+ */
+
+void hash_Reset(hashtable, free_data)
+hash_tbl *hashtable;
+void (*free_data)();
+{
+ hash_member **bucketptr;
+ unsigned i;
+
+ bucketptr = hashtable->table;
+ for (i = 0; i < hashtable->size; i++) {
+ hashi_FreeMember(*bucketptr, free_data);
+ *bucketptr++ = NULL;
+ }
+ hashtable->bucketnum = 0;
+ hashtable->member = (hashtable->table)[0];
+}
+
+
+
+/*
+ * Generic hash function to calculate a hash code from the given string.
+ *
+ * For each byte of the string, this function left-shifts the value in an
+ * accumulator and then adds the byte into the accumulator. The contents of
+ * the accumulator is returned after the entire string has been processed.
+ * It is assumed that this result will be used as the "hashcode" parameter in
+ * calls to other functions in this package. These functions automatically
+ * adjust the hashcode for the size of each hashtable.
+ *
+ * This algorithm probably works best when the hash table size is a prime
+ * number.
+ *
+ * Hopefully, this function is better than the previous one which returned
+ * the sum of the squares of all the bytes. I'm still open to other
+ * suggestions for a default hash function. The programmer is more than
+ * welcome to supply his/her own hash function as that is one of the design
+ * features of this package.
+ */
+
+unsigned hash_HashFunction(string, len)
+unsigned char *string;
+register unsigned len;
+{
+ register unsigned accum;
+
+ accum = 0;
+ for (; len > 0; len--) {
+ accum <<= 1;
+ accum += (unsigned) (*string++ & 0xFF);
+ }
+ return accum;
+}
+
+
+
+/*
+ * Returns TRUE if at least one entry for the given key exists; FALSE
+ * otherwise.
+ */
+
+int hash_Exists(hashtable, hashcode, compare, key)
+hash_tbl *hashtable;
+unsigned hashcode;
+int (*compare)();
+hash_datum *key;
+{
+ register hash_member *memberptr;
+
+ memberptr = (hashtable->table)[hashcode % (hashtable->size)];
+ while (memberptr) {
+ if ((*compare)(key, memberptr->data)) {
+ return TRUE; /* Entry does exist */
+ }
+ memberptr = memberptr->next;
+ }
+ return FALSE; /* Entry does not exist */
+}
+
+
+
+/*
+ * Insert the data item "element" into the hash table using "hashcode"
+ * to determine the bucket number, and "compare" and "key" to determine
+ * its uniqueness.
+ *
+ * If the insertion is successful 0 is returned. If a matching entry
+ * already exists in the given bucket of the hash table, or some other error
+ * occurs, -1 is returned and the insertion is not done.
+ */
+
+int hash_Insert(hashtable, hashcode, compare, key, element)
+hash_tbl *hashtable;
+unsigned hashcode;
+int (*compare)();
+hash_datum *key, *element;
+{
+ hash_member *memberptr, *temp;
+
+ hashcode %= hashtable->size;
+ if (hash_Exists(hashtable, hashcode, compare, key)) {
+ return -1; /* At least one entry already exists */
+ }
+ memberptr = (hashtable->table)[hashcode];
+ temp = (hash_member *) malloc(sizeof(hash_member));
+ if (temp) {
+ (hashtable->table)[hashcode] = temp;
+ temp->data = element;
+ temp->next = memberptr;
+ return 0; /* Success */
+ } else {
+ return -1; /* malloc failed! */
+ }
+}
+
+
+
+/*
+ * Delete all data elements which match the given key. If at least one
+ * element is found and the deletion is successful, 0 is returned.
+ * If no matching elements can be found in the hash table, -1 is returned.
+ */
+
+int hash_Delete(hashtable, hashcode, compare, key, free_data)
+hash_tbl *hashtable;
+unsigned hashcode;
+int (*compare)();
+hash_datum *key;
+void (*free_data)();
+{
+ hash_member *memberptr, *previous, *tempptr;
+ int retval;
+
+ retval = -1;
+ hashcode %= hashtable->size;
+
+ /*
+ * Delete the first member of the list if it matches. Since this moves
+ * the second member into the first position we have to keep doing this
+ * over and over until it no longer matches.
+ */
+ memberptr = (hashtable->table)[hashcode];
+ while (memberptr && (*compare)(key, memberptr->data)) {
+ (hashtable->table)[hashcode] = memberptr->next;
+ /*
+ * Stop hashi_FreeMember() from recursively deleting the whole list!
+ */
+ memberptr->next = NULL;
+ hashi_FreeMember(memberptr, free_data);
+ memberptr = (hashtable->table)[hashcode];
+ retval = 0;
+ }
+
+ /*
+ * Now traverse the rest of the list
+ */
+ if (memberptr) {
+ previous = memberptr;
+ memberptr = memberptr->next;
+ }
+ while (memberptr) {
+ if ((*compare)(key, memberptr->data)) {
+ tempptr = memberptr;
+ previous->next = memberptr = memberptr->next;
+ /*
+ * Put the brakes on hashi_FreeMember(). . . .
+ */
+ tempptr->next = NULL;
+ hashi_FreeMember(tempptr, free_data);
+ retval = 0;
+ } else {
+ previous = memberptr;
+ memberptr = memberptr->next;
+ }
+ }
+ return retval;
+}
+
+
+
+/*
+ * Locate and return the data entry associated with the given key.
+ *
+ * If the data entry is found, a pointer to it is returned. Otherwise,
+ * NULL is returned.
+ */
+
+hash_datum *hash_Lookup(hashtable, hashcode, compare, key)
+hash_tbl *hashtable;
+unsigned hashcode;
+int (*compare)();
+hash_datum *key;
+{
+ hash_member *memberptr;
+
+ memberptr = (hashtable->table)[hashcode % (hashtable->size)];
+ while (memberptr) {
+ if ((*compare)(key, memberptr->data)) {
+ return (memberptr->data);
+ }
+ memberptr = memberptr->next;
+ }
+ return NULL;
+}
+
+
+
+/*
+ * Return the next available entry in the hashtable for a linear search
+ */
+
+hash_datum *hash_NextEntry(hashtable)
+hash_tbl *hashtable;
+{
+ register unsigned bucket;
+ register hash_member *memberptr;
+
+ /*
+ * First try to pick up where we left off.
+ */
+ memberptr = hashtable->member;
+ if (memberptr) {
+ hashtable->member = memberptr->next; /* Set up for next call */
+ return memberptr->data; /* Return the data */
+ }
+
+ /*
+ * We hit the end of a chain, so look through the array of buckets
+ * until we find a new chain (non-empty bucket) or run out of buckets.
+ */
+ bucket = hashtable->bucketnum + 1;
+ while ((bucket < hashtable->size) &&
+ !(memberptr = (hashtable->table)[bucket])) {
+ bucket++;
+ }
+
+ /*
+ * Check to see if we ran out of buckets.
+ */
+ if (bucket >= hashtable->size) {
+ /*
+ * Reset to top of table for next call.
+ */
+ hashtable->bucketnum = 0;
+ hashtable->member = (hashtable->table)[0];
+ /*
+ * But return end-of-table indication to the caller this time.
+ */
+ return NULL;
+ }
+
+ /*
+ * Must have found a non-empty bucket.
+ */
+ hashtable->bucketnum = bucket;
+ hashtable->member = memberptr->next; /* Set up for next call */
+ return memberptr->data; /* Return the data */
+}
+
+
+
+/*
+ * Return the first entry in a hash table for a linear search
+ */
+
+hash_datum *hash_FirstEntry(hashtable)
+hash_tbl *hashtable;
+{
+ hashtable->bucketnum = 0;
+ hashtable->member = (hashtable->table)[0];
+ return hash_NextEntry(hashtable);
+}
diff --git a/libexec/bootpd/hash.h b/libexec/bootpd/hash.h
new file mode 100644
index 000000000000..2a1d8b8e5a3b
--- /dev/null
+++ b/libexec/bootpd/hash.h
@@ -0,0 +1,137 @@
+#ifndef _BLURB_
+#define _BLURB_
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+#endif /* _BLURB_ */
+
+
+/*
+ * Generalized hash table ADT
+ *
+ * Provides multiple, dynamically-allocated, variable-sized hash tables on
+ * various data and keys.
+ *
+ * This package attempts to follow some of the coding conventions suggested
+ * by Bob Sidebotham and the AFS Clean Code Committee.
+ */
+
+
+/*
+ * The user must supply the following:
+ *
+ * 1. A comparison function which is declared as:
+ *
+ * int compare(data1, data2)
+ * hash_datum *data1, *data2;
+ *
+ * This function must compare the desired fields of data1 and
+ * data2 and return TRUE (1) if the data should be considered
+ * equivalent (i.e. have the same key value) or FALSE (0)
+ * otherwise. This function is called through a pointer passed to
+ * the various hashtable functions (thus pointers to different
+ * functions may be passed to effect different tests on different
+ * hash tables).
+ *
+ * Internally, all the functions of this package always call the
+ * compare function with the "key" parameter as the first parameter,
+ * and a full data element as the second parameter. Thus, the key
+ * and element arguments to functions such as hash_Lookup() may
+ * actually be of different types and the programmer may provide a
+ * compare function which compares the two different object types
+ * as desired.
+ *
+ * Example:
+ *
+ * int compare(key, element)
+ * char *key;
+ * struct some_complex_structure *element;
+ * {
+ * return !strcmp(key, element->name);
+ * }
+ *
+ * key = "John C. Doe"
+ * element = &some_complex_structure
+ * hash_Lookup(table, hashcode, compare, key);
+ *
+ * 2. A hash function yielding an unsigned integer value to be used
+ * as the hashcode (index into the hashtable). Thus, the user
+ * may hash on whatever data is desired and may use several
+ * different hash functions for various different hash tables.
+ * The actual hash table index will be the passed hashcode modulo
+ * the hash table size.
+ *
+ * A generalized hash function, hash_HashFunction(), is included
+ * with this package to make things a little easier. It is not
+ * guarenteed to use the best hash algorithm in existence. . . .
+ */
+
+
+
+/*
+ * Various hash table definitions
+ */
+
+
+#ifndef __HASHXYZ973__
+
+#define __HASHXYZ973__
+
+/*
+ * Define "hash_datum" as a universal data type
+ */
+#ifdef __STDC__
+typedef void hash_datum;
+#else
+typedef char hash_datum;
+#endif
+
+typedef struct hash_memberstruct hash_member;
+typedef struct hash_tblstruct hash_tbl;
+typedef struct hash_tblstruct_hdr hash_tblhdr;
+
+struct hash_memberstruct {
+ hash_member *next;
+ hash_datum *data;
+};
+
+struct hash_tblstruct_hdr {
+ unsigned size, bucketnum;
+ hash_member *member;
+};
+
+struct hash_tblstruct {
+ unsigned size, bucketnum;
+ hash_member *member; /* Used for linear dump */
+ hash_member *table[1]; /* Dynamically extended */
+};
+
+extern hash_tbl *hash_Init();
+extern void hash_Reset();
+extern unsigned hash_HashFunction();
+extern int hash_Exists();
+extern int hash_Insert();
+extern int hash_Delete();
+extern hash_datum *hash_Lookup();
+extern hash_datum *hash_FirstEntry();
+extern hash_datum *hash_NextEntry();
+
+#endif
diff --git a/libexec/bootpd/newvers.sh b/libexec/bootpd/newvers.sh
new file mode 100644
index 000000000000..c98259d12a52
--- /dev/null
+++ b/libexec/bootpd/newvers.sh
@@ -0,0 +1,24 @@
+#!/bin/sh -
+#
+# Copyright (c) 1987 Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that this notice is preserved and that due credit is given
+# to the University of California at Berkeley. The name of the University
+# may not be used to endorse or promote products derived from this
+# software without specific prior written permission. This software
+# is provided ``as is'' without express or implied warranty.
+#
+# @(#)newvers.sh 4.4 (Berkeley) 3/28/88
+#
+if [ ! -r version ]
+then
+ echo 0 > version
+fi
+touch version
+rm -f version.[oc]
+v=`cat version` u=${USER-root} d=`pwd` h=`hostname` t=`date`
+sed -e "s|%VERSION%|#${v}: ${t}|" -e "s|%WHOANDWHERE%|${u}@${h}:${d}|" \
+ < $1 >version.c
+/bin/echo `expr ${v} + 1` > version
diff --git a/libexec/bootpd/readfile.c b/libexec/bootpd/readfile.c
new file mode 100644
index 000000000000..e437193eb1b2
--- /dev/null
+++ b/libexec/bootpd/readfile.c
@@ -0,0 +1,2128 @@
+#ifndef _BLURB_
+#define _BLURB_
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+#endif /* _BLURB_ */
+
+
+#ifndef lint
+static char rcsid[] = "$Header: /home/cvs/386BSD/src/libexec/bootpd/readfile.c,v 1.1 1994/01/25 22:53:48 martin Exp $";
+#endif
+
+
+/*
+ * bootpd configuration file reading code.
+ *
+ * The routines in this file deal with reading, interpreting, and storing
+ * the information found in the bootpd configuration file (usually
+ * /etc/bootptab).
+ */
+
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#ifdef SYSLOG
+#include <syslog.h>
+#endif
+#include "bootp.h"
+#include "hash.h"
+#include "bootpd.h"
+
+
+#define SUCCESS 0
+#define E_END_OF_ENTRY (-1)
+#define E_SYNTAX_ERROR (-2)
+#define E_UNKNOWN_SYMBOL (-3)
+#define E_BAD_IPADDR (-4)
+#define E_BAD_HADDR (-5)
+#define E_BAD_SMASK (-6)
+#define E_BAD_TIMEOFF (-7)
+#define E_BAD_VM_COOKIE (-8)
+#define E_BAD_HTYPE (-9)
+#define E_BAD_BOOTSIZE (-10)
+#define E_BAD_BOOT_SERVER (-11)
+#define E_BAD_HOMEDIR (-12)
+#define E_BAD_TFTPDIR (-13)
+#define E_BAD_SWAP_SERVER (-14)
+
+#define SYM_NULL 0
+#define SYM_BOOTFILE 1
+#define SYM_COOKIE_SERVER 2
+#define SYM_DOMAIN_SERVER 3
+#define SYM_GATEWAY 4
+#define SYM_HADDR 5
+#define SYM_HOMEDIR 6
+#define SYM_HTYPE 7
+#define SYM_IMPRESS_SERVER 8
+#define SYM_IPADDR 9
+#define SYM_LOG_SERVER 10
+#define SYM_LPR_SERVER 11
+#define SYM_NAME_SERVER 12
+#define SYM_RLP_SERVER 13
+#define SYM_SUBNET_MASK 14
+#define SYM_TIME_OFFSET 15
+#define SYM_TIME_SERVER 16
+#define SYM_VENDOR_MAGIC 17
+#define SYM_SIMILAR_ENTRY 18
+#define SYM_NAME_SWITCH 19
+#define SYM_BOOTSIZE 20
+#define SYM_BOOT_SERVER 22
+#define SYM_TFTPDIR 23
+#define SYM_DUMPFILE 24
+#define SYM_DOMAIN_NAME 25
+#define SYM_SWAP_SERVER 26
+#define SYM_ROOTPATH 27
+
+#define OP_ADDITION 1 /* Operations on tags */
+#define OP_DELETION 2
+#define OP_BOOLEAN 3
+
+#define MAXINADDRS 16 /* Max size of an IP address list */
+#define MAXBUFLEN 64 /* Max temp buffer space */
+#define MAXENTRYLEN 2048 /* Max size of an entire entry */
+
+
+
+/*
+ * Structure used to map a configuration-file symbol (such as "ds") to a
+ * unique integer.
+ */
+
+struct symbolmap {
+ char *symbol;
+ int symbolcode;
+};
+
+
+struct htypename {
+ char *name;
+ byte htype;
+};
+
+
+PRIVATE int nhosts; /* Number of hosts (/w hw or IP address) */
+PRIVATE int nentries; /* Total number of entries */
+PRIVATE long modtime = 0; /* Last modification time of bootptab */
+
+
+/*
+ * List of symbolic names used in the bootptab file. The order and actual
+ * values of the symbol codes (SYM_. . .) are unimportant, but they must
+ * all be unique.
+ */
+
+PRIVATE struct symbolmap symbol_list[] = {
+ { "bf", SYM_BOOTFILE },
+ { "bs", SYM_BOOTSIZE },
+ { "cs", SYM_COOKIE_SERVER },
+ { "df", SYM_DUMPFILE },
+ { "dn", SYM_DOMAIN_NAME },
+ { "ds", SYM_DOMAIN_SERVER },
+ { "gw", SYM_GATEWAY },
+ { "ha", SYM_HADDR },
+ { "hd", SYM_HOMEDIR },
+ { "hn", SYM_NAME_SWITCH },
+ { "ht", SYM_HTYPE },
+ { "im", SYM_IMPRESS_SERVER },
+ { "ip", SYM_IPADDR },
+ { "lg", SYM_LOG_SERVER },
+ { "lp", SYM_LPR_SERVER },
+ { "ns", SYM_NAME_SERVER },
+ { "rl", SYM_RLP_SERVER },
+ { "rp", SYM_ROOTPATH },
+ { "sa", SYM_BOOT_SERVER },
+ { "sm", SYM_SUBNET_MASK },
+ { "sw", SYM_SWAP_SERVER },
+ { "tc", SYM_SIMILAR_ENTRY },
+ { "td", SYM_TFTPDIR },
+ { "to", SYM_TIME_OFFSET },
+ { "ts", SYM_TIME_SERVER },
+ { "vm", SYM_VENDOR_MAGIC },
+};
+
+
+/*
+ * List of symbolic names for hardware types. Name translates into
+ * hardware type code listed with it. Names must begin with a letter
+ * and must be all lowercase. This is searched linearly, so put
+ * commonly-used entries near the beginning.
+ */
+
+PRIVATE struct htypename htnamemap[] = {
+ { "ethernet", HTYPE_ETHERNET },
+ { "ethernet3", HTYPE_EXP_ETHERNET },
+ { "ether", HTYPE_ETHERNET },
+ { "ether3", HTYPE_EXP_ETHERNET },
+ { "ieee802", HTYPE_IEEE802 },
+ { "tr", HTYPE_IEEE802 },
+ { "token-ring", HTYPE_IEEE802 },
+ { "pronet", HTYPE_PRONET },
+ { "chaos", HTYPE_CHAOS },
+ { "arcnet", HTYPE_ARCNET },
+ { "ax.25", HTYPE_AX25 },
+ { "direct", HTYPE_DIRECT },
+ { "serial", HTYPE_DIRECT },
+ { "slip", HTYPE_DIRECT },
+ { "ppp", HTYPE_DIRECT }
+};
+
+
+
+/*
+ * Externals and forward declarations.
+ */
+
+extern char *malloc();
+extern boolean iplookcmp();
+extern int errno;
+
+PRIVATE char *smalloc();
+PRIVATE void fill_defaults();
+PRIVATE void del_string();
+PRIVATE void del_bindata();
+PRIVATE void del_iplist();
+PRIVATE void free_host();
+PRIVATE u_long get_u_long();
+PRIVATE void process_generic();
+PRIVATE char *get_string();
+PRIVATE struct shared_string *get_shared_string();
+PRIVATE void read_entry();
+PRIVATE boolean nullcmp();
+PRIVATE boolean nmcmp();
+PRIVATE boolean hwinscmp();
+PRIVATE void adjust();
+PRIVATE void eat_whitespace();
+PRIVATE void makelower();
+PRIVATE struct in_addr_list *get_addresses();
+PRIVATE byte *prs_haddr();
+
+
+
+
+
+/*
+ * Read bootptab database file. Avoid rereading the file if the
+ * write date hasn't changed since the last time we read it.
+ */
+
+int readtab()
+{
+ struct host *hp;
+ FILE *fp;
+ struct stat st;
+ unsigned hashcode, buflen;
+ static char buffer[MAXENTRYLEN];
+#ifdef DEBUG
+ char timestr[26];
+#endif
+
+ /*
+ * Check the last modification time.
+ */
+ if (stat(bootptab, &st) < 0) {
+ report(LOG_ERR, "stat on \"%s\": %s\n", bootptab, get_errmsg());
+ return -1;
+ }
+#ifdef DEBUG
+ if (debug > 3) {
+ strcpy(timestr, ctime(&(st.st_mtime)));
+ report(LOG_INFO, "bootptab mtime is %s",
+ timestr);
+ }
+#endif
+ if (st.st_mtime == modtime && st.st_nlink) {
+ /*
+ * hasn't been modified or deleted yet.
+ */
+ return 0;
+ }
+ report(LOG_INFO, "reading %s\"%s\"\n",
+ (modtime != 0L) ? "new " : "",
+ bootptab);
+
+ /*
+ * Open bootptab file.
+ */
+ if ((fp = fopen(bootptab, "r")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s\n", bootptab, get_errmsg());
+ return -1;
+ }
+
+ /*
+ * Record file modification time.
+ */
+ if (fstat(fileno(fp), &st) < 0) {
+ report(LOG_ERR, "fstat: %s\n", get_errmsg());
+ fclose(fp);
+ return -1;
+ }
+ modtime = st.st_mtime;
+
+ /*
+ * Entirely erase all hash tables.
+ */
+ hash_Reset(hwhashtable, free_host);
+ hash_Reset(iphashtable, free_host);
+ hash_Reset(nmhashtable, free_host);
+
+ nhosts = 0;
+ nentries = 0;
+ while (TRUE) {
+ buflen = sizeof(buffer);
+ read_entry(fp, buffer, &buflen);
+ if (buflen == 0) { /* More entries? */
+ break;
+ }
+ hp = (struct host *) smalloc(sizeof(struct host));
+
+ /*
+ * Get individual info
+ */
+ hp->flags.vm_auto = TRUE;
+ bcopy(vm_rfc1048, hp->vm_cookie, 4);
+ if (process_entry(hp, buffer) < 0) {
+ free_host(hp);
+ continue;
+ }
+
+ if ((hp->flags.htype && hp->flags.haddr) || hp->flags.iaddr) {
+ nhosts++;
+ }
+ if (hp->flags.htype && hp->flags.haddr) {
+ hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
+ if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
+ report(LOG_WARNING, "duplicate %s address: %s\n",
+ netname(hp->htype),
+ haddrtoa(hp->haddr, hp->htype));
+ free_host(hp);
+ continue;
+ }
+ }
+ if (hp->flags.iaddr) {
+ hashcode = hash_HashFunction(&(hp->iaddr.s_addr), 4);
+ if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
+ report(LOG_ERR,
+ "hash_Insert() failed on IP address insertion\n");
+ }
+ }
+
+ hashcode = hash_HashFunction(hp->hostname->string,
+ strlen(hp->hostname->string));
+ if (hash_Insert(nmhashtable, hashcode, nullcmp, hp->hostname->string, hp) < 0) {
+ report(LOG_ERR,
+ "hash_Insert() failed on insertion of hostname: \"%s\"\n",
+ hp->hostname->string);
+ }
+ nentries++;
+ }
+
+done:
+ fclose(fp);
+ report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"\n",
+ nentries, nhosts, bootptab);
+ return 0;
+}
+
+
+
+/*
+ * Read an entire host entry from the file pointed to by "fp" and insert it
+ * into the memory pointed to by "buffer". Leading whitespace and comments
+ * starting with "#" are ignored (removed). Backslashes (\) always quote
+ * the next character except that newlines preceeded by a backslash cause
+ * line-continuation onto the next line. The entry is terminated by a
+ * newline character which is not preceeded by a backslash. Sequences
+ * surrounded by double quotes are taken literally (including newlines, but
+ * not backslashes).
+ *
+ * The "bufsiz" parameter points to an unsigned int which specifies the
+ * maximum permitted buffer size. Upon return, this value will be replaced
+ * with the actual length of the entry (not including the null terminator).
+ *
+ * This code is a little scary. . . . I don't like using gotos in C
+ * either, but I first wrote this as an FSM diagram and gotos seemed like
+ * the easiest way to implement it. Maybe later I'll clean it up.
+ */
+
+PRIVATE void read_entry(fp, buffer, bufsiz)
+FILE *fp;
+char *buffer;
+unsigned *bufsiz;
+{
+ int c, length;
+
+ length = 0;
+
+ /*
+ * Eat whitespace, blank lines, and comment lines.
+ */
+top:
+ c = fgetc(fp);
+ if (c < 0) {
+ goto done; /* Exit if end-of-file */
+ }
+ if (isspace(c)) {
+ goto top; /* Skip over whitespace */
+ }
+ if (c == '#') {
+ while (TRUE) { /* Eat comments after # */
+ c = fgetc(fp);
+ if (c < 0) {
+ goto done; /* Exit if end-of-file */
+ }
+ if (c == '\n') {
+ goto top; /* Try to read the next line */
+ }
+ }
+ }
+ ungetc(c, fp); /* Other character, push it back to reprocess it */
+
+
+ /*
+ * Now we're actually reading a data entry. Get each character and
+ * assemble it into the data buffer, processing special characters like
+ * double quotes (") and backslashes (\).
+ */
+
+mainloop:
+ c = fgetc(fp);
+ switch (c) {
+ case EOF:
+ case '\n':
+ goto done; /* Exit on EOF or newline */
+ case '\\':
+ c = fgetc(fp); /* Backslash, read a new character */
+ if (c < 0) {
+ goto done; /* Exit on EOF */
+ }
+ *buffer++ = c; /* Store the literal character */
+ length++;
+ if (length < *bufsiz - 1) {
+ goto mainloop;
+ } else {
+ goto done;
+ }
+ case '"':
+ *buffer++ = '"'; /* Store double-quote */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+ while (TRUE) { /* Special quote processing loop */
+ c = fgetc(fp);
+ switch (c) {
+ case EOF:
+ goto done; /* Exit on EOF . . . */
+ case '"':
+ *buffer++ = '"'; /* Store matching quote */
+ length++;
+ if (length < *bufsiz - 1) {
+ goto mainloop; /* And continue main loop */
+ } else {
+ goto done;
+ }
+ case '\\':
+ if ((c = fgetc(fp)) < 0) { /* Backslash */
+ goto done; /* EOF. . . .*/
+ } /* else fall through */
+ default:
+ *buffer++ = c; /* Other character, store it */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+ }
+ }
+ case ':':
+ *buffer++ = c; /* Store colons */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+
+ do { /* But remove whitespace after them */
+ c = fgetc(fp);
+ if ((c < 0) || (c == '\n')) {
+ goto done;
+ }
+ } while (isspace(c)); /* Skip whitespace */
+
+ if (c == '\\') { /* Backslash quotes next character */
+ c = fgetc(fp);
+ if (c < 0) {
+ goto done;
+ }
+ if (c == '\n') {
+ goto top; /* Backslash-newline continuation */
+ }
+ }
+ /* fall through if "other" character */
+ default:
+ *buffer++ = c; /* Store other characters */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+ }
+ goto mainloop; /* Keep going */
+
+done:
+ *buffer = '\0'; /* Terminate string */
+ *bufsiz = length; /* Tell the caller its length */
+}
+
+
+
+/*
+ * Parse out all the various tags and parameters in the host entry pointed
+ * to by "src". Stuff all the data into the appropriate fields of the
+ * host structure pointed to by "host". If there is any problem with the
+ * entry, an error message is reported via report(), no further processing
+ * is done, and -1 is returned. Successful calls return 0.
+ *
+ * (Some errors probably shouldn't be so completely fatal. . . .)
+ */
+
+PRIVATE int process_entry(host, src)
+struct host *host;
+char *src;
+{
+ int retval;
+
+ if (!host || *src == '\0') {
+ return -1;
+ }
+ host->hostname = get_shared_string(&src);
+ if (!goodname(host->hostname->string)) {
+ report(LOG_ERR, "bad hostname: \"%s\"\n", host->hostname->string);
+ del_string(host->hostname);
+ return -1;
+ }
+ adjust(&src);
+ while (TRUE) {
+ retval = eval_symbol(&src, host);
+ switch (retval) {
+ case SUCCESS:
+ break;
+ case E_SYNTAX_ERROR:
+ report(LOG_ERR, "syntax error in entry for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_UNKNOWN_SYMBOL:
+ report(LOG_ERR, "unknown symbol in entry for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_BAD_IPADDR:
+ report(LOG_ERR, "bad IP address for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_BAD_HADDR:
+ report(LOG_ERR, "bad hardware address for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_BAD_SMASK:
+ report(LOG_ERR, "bad subnet mask for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_BAD_TIMEOFF:
+ report(LOG_ERR, "bad time offset for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_BAD_VM_COOKIE:
+ report(LOG_ERR, "bad vendor magic cookie for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_BAD_HOMEDIR:
+ report(LOG_ERR, "bad home directory for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_BAD_TFTPDIR:
+ report(LOG_ERR, "bad TFTP directory for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_BAD_BOOT_SERVER:
+ report(LOG_ERR, "bad boot server IP address for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_BAD_SWAP_SERVER:
+ report(LOG_ERR, "bad swap server IP address for host \"%s\"\n",
+ host->hostname->string);
+ return -1;
+ case E_END_OF_ENTRY:
+ default:
+#if 0
+ /*
+ * For now, don't try to make-up a subnet mask if one
+ * wasn't specified.
+ *
+ * This algorithm is also not entirely correct.
+ */
+ if (!(hp->flags.subnet_mask)) {
+ /*
+ * Try to deduce the subnet mask from the network class
+ */
+ value = (ntohl(value) >> 30) & 0x03;
+ switch (value) {
+ case 0:
+ case 1:
+ hp->subnet_mask.s_addr = htonl(0xFF000000L);
+ break;
+ case 2:
+ hp->subnet_mask.s_addr = htonl(0xFFFF0000L);
+ break;
+ case 3:
+ hp->subnet_mask.s_addr = htonl(0xFFFFFF00L);
+ break;
+ }
+ hp->flags.subnet_mask = TRUE;
+ }
+#endif
+ /*
+ * And now we're done with this entry
+ */
+ return 0;
+ }
+ adjust(&src);
+ }
+}
+
+
+
+/*
+ * Evaluate the two-character tag symbol pointed to by "symbol" and place
+ * the data in the structure pointed to by "hp". The pointer pointed to
+ * by "symbol" is updated to point past the source string (but may not
+ * point to the next tag entry).
+ *
+ * Obviously, this need a few more comments. . . .
+ */
+
+PRIVATE eval_symbol(symbol, hp)
+char **symbol;
+struct host *hp;
+{
+ char tmpstr[MAXSTRINGLEN];
+ byte *tmphaddr, *ustr;
+ struct shared_string *ss;
+ struct symbolmap *symbolptr;
+ u_long value;
+ long timeoff;
+ int i, numsymbols;
+ unsigned len;
+ int optype; /* Indicates boolean, addition, or deletion */
+
+ if ((*symbol)[0] == '\0') {
+ return E_END_OF_ENTRY;
+ }
+ if ((*symbol)[0] == ':') {
+ return SUCCESS;
+ }
+ if ((*symbol)[0] == 'T') { /* generic symbol */
+ (*symbol)++;
+ value = get_u_long(symbol);
+ eat_whitespace(symbol);
+ if ((*symbol)[0] != '=') {
+ return E_SYNTAX_ERROR;
+ }
+ (*symbol)++;
+ if (!(hp->generic)) {
+ hp->generic = (struct shared_bindata *)
+ smalloc(sizeof(struct shared_bindata));
+ }
+ process_generic(symbol, &(hp->generic), (byte) (value & 0xFF));
+ hp->flags.generic = TRUE;
+ return SUCCESS;
+ }
+
+ eat_whitespace(symbol);
+
+ /*
+ * Determine the type of operation to be done on this symbol
+ */
+ switch ((*symbol)[2]) {
+ case '=':
+ optype = OP_ADDITION;
+ break;
+ case '@':
+ optype = OP_DELETION;
+ break;
+ case ':':
+ case '\0':
+ optype = OP_BOOLEAN;
+ break;
+ default:
+ return E_SYNTAX_ERROR;
+ }
+
+ symbolptr = symbol_list;
+ numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
+ for (i = 0; i < numsymbols; i++) {
+ if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
+ ((symbolptr->symbol)[1] == (*symbol)[1])) {
+ break;
+ }
+ symbolptr++;
+ }
+ if (i >= numsymbols) {
+ return E_UNKNOWN_SYMBOL;
+ }
+
+ /*
+ * Skip past the = or @ character (to point to the data) if this
+ * isn't a boolean operation. For boolean operations, just skip
+ * over the two-character tag symbol (and nothing else. . . .).
+ */
+ (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
+
+ switch (symbolptr->symbolcode) {
+ case SYM_BOOTFILE:
+ switch (optype) {
+ case OP_ADDITION:
+ if (ss = get_shared_string(symbol)) {
+ if (hp->bootfile) {
+ del_string(hp->bootfile);
+ }
+ hp->bootfile = ss;
+ hp->flags.bootfile = TRUE;
+ }
+ break;
+ case OP_DELETION:
+ if (hp->bootfile) {
+ del_string(hp->bootfile);
+ }
+ hp->bootfile = NULL;
+ hp->flags.bootfile = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_COOKIE_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.cookie_server && hp->cookie_server) {
+ del_iplist(hp->cookie_server);
+ }
+ hp->cookie_server = get_addresses(symbol);
+ hp->flags.cookie_server = TRUE;
+ break;
+ case OP_DELETION:
+ if (hp->flags.cookie_server && hp->cookie_server) {
+ del_iplist(hp->cookie_server);
+ }
+ hp->cookie_server = NULL;
+ hp->flags.cookie_server = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_DOMAIN_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.domain_server && hp->domain_server) {
+ del_iplist(hp->domain_server);
+ }
+ hp->domain_server = get_addresses(symbol);
+ hp->flags.domain_server = TRUE;
+ break;
+ case OP_DELETION:
+ if (hp->flags.domain_server && hp->domain_server) {
+ del_iplist(hp->domain_server);
+ }
+ hp->domain_server = NULL;
+ hp->flags.domain_server = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_GATEWAY:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.gateway && hp->gateway) {
+ del_iplist(hp->gateway);
+ }
+ hp->gateway = get_addresses(symbol);
+ hp->flags.gateway = TRUE;
+ break;
+ case OP_DELETION:
+ if (hp->flags.gateway && hp->gateway) {
+ del_iplist(hp->gateway);
+ }
+ hp->gateway = NULL;
+ hp->flags.gateway = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_HADDR:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.htype && hp->htype &&
+ (tmphaddr = prs_haddr(symbol, hp->htype))) {
+ bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
+ hp->flags.haddr = TRUE;
+ } else {
+ return E_BAD_HADDR;
+ }
+ break;
+ case OP_DELETION:
+ hp->flags.haddr = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_HOMEDIR:
+ switch (optype) {
+ case OP_ADDITION:
+ if (ss = get_shared_string(symbol)) {
+ if ((ss->string)[0] == '/') {
+ if (hp->homedir) {
+ del_string(hp->homedir);
+ }
+ hp->homedir = ss;
+ hp->flags.homedir = TRUE;
+ } else {
+ return E_BAD_HOMEDIR;
+ }
+ } else {
+ return E_BAD_HOMEDIR;
+ }
+ break;
+ case OP_DELETION:
+ if (hp->homedir) {
+ del_string(hp->homedir);
+ }
+ hp->homedir = NULL;
+ hp->flags.homedir = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_HTYPE:
+ switch (optype) {
+ case OP_ADDITION:
+ value = 0L; /* Assume an illegal value */
+ eat_whitespace(symbol);
+ if (isdigit(**symbol)) {
+ value = get_u_long(symbol);
+ } else {
+ len = sizeof(tmpstr);
+ (void) get_string(symbol, tmpstr, &len);
+ makelower(tmpstr);
+ numsymbols = sizeof(htnamemap) /
+ sizeof(struct htypename);
+ for (i = 0; i < numsymbols; i++) {
+ if (!strcmp(htnamemap[i].name, tmpstr)) {
+ break;
+ }
+ }
+ if (i < numsymbols) {
+ value = htnamemap[i].htype;
+ }
+ }
+ if ((value < 0) || (value > MAXHTYPES)) {
+ return E_BAD_HTYPE;
+ }
+ hp->htype = (byte) (value & 0xFF);
+ hp->flags.htype = TRUE;
+ break;
+ case OP_DELETION:
+ hp->flags.htype = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_IMPRESS_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.impress_server && hp->impress_server) {
+ del_iplist(hp->impress_server);
+ }
+ hp->impress_server = get_addresses(symbol);
+ hp->flags.impress_server = TRUE;
+ break;
+ case OP_DELETION:
+ if (hp->flags.impress_server && hp->impress_server) {
+ del_iplist(hp->impress_server);
+ }
+ hp->impress_server = NULL;
+ hp->flags.impress_server = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_IPADDR:
+ switch (optype) {
+ case OP_ADDITION:
+ if (prs_inetaddr(symbol, &value) < 0) {
+ return E_BAD_IPADDR;
+ } else {
+ hp->iaddr.s_addr = value;
+ hp->flags.iaddr = TRUE;
+ }
+ break;
+ case OP_DELETION:
+ hp->flags.iaddr = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_LOG_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.log_server && hp->log_server) {
+ del_iplist(hp->log_server);
+ }
+ hp->log_server = get_addresses(symbol);
+ hp->flags.log_server = TRUE;
+ break;
+ case OP_DELETION:
+ if (hp->flags.log_server && hp->log_server) {
+ del_iplist(hp->log_server);
+ }
+ hp->log_server = NULL;
+ hp->flags.log_server = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_LPR_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.lpr_server && hp->lpr_server) {
+ del_iplist(hp->lpr_server);
+ }
+ hp->lpr_server = get_addresses(symbol);
+ hp->flags.lpr_server = TRUE;
+ break;
+ case OP_DELETION:
+ if (hp->flags.lpr_server && hp->lpr_server) {
+ del_iplist(hp->lpr_server);
+ }
+ hp->lpr_server = NULL;
+ hp->flags.lpr_server = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_NAME_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.name_server && hp->name_server) {
+ del_iplist(hp->name_server);
+ }
+ hp->name_server = get_addresses(symbol);
+ hp->flags.name_server = TRUE;
+ break;
+ case OP_DELETION:
+ if (hp->flags.name_server && hp->name_server) {
+ del_iplist(hp->name_server);
+ }
+ hp->name_server = NULL;
+ hp->flags.name_server = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_RLP_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.rlp_server && hp->rlp_server) {
+ del_iplist(hp->rlp_server);
+ }
+ hp->rlp_server = get_addresses(symbol);
+ hp->flags.rlp_server = TRUE;
+ break;
+ case OP_DELETION:
+ if (hp->flags.rlp_server && hp->rlp_server) {
+ del_iplist(hp->rlp_server);
+ }
+ hp->rlp_server = NULL;
+ hp->flags.rlp_server = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_SUBNET_MASK:
+ switch (optype) {
+ case OP_ADDITION:
+ if (prs_inetaddr(symbol, &value) < 0) {
+ return E_BAD_SMASK;
+ } else {
+ hp->subnet_mask.s_addr = value;
+ hp->flags.subnet_mask = TRUE;
+ }
+ break;
+ case OP_DELETION:
+ hp->flags.subnet_mask = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_TIME_OFFSET:
+ switch (optype) {
+ case OP_ADDITION:
+ len = sizeof(tmpstr);
+ (void) get_string(symbol, tmpstr, &len);
+ if (!strncmp(tmpstr, "auto", 4)) {
+ hp->flags.timeoff_auto = TRUE;
+ hp->flags.time_offset = TRUE;
+ } else {
+ if (sscanf(tmpstr, "%ld", &timeoff) != 1) {
+ return E_BAD_TIMEOFF;
+ } else {
+ hp->time_offset = timeoff;
+ hp->flags.timeoff_auto = FALSE;
+ hp->flags.time_offset = TRUE;
+ }
+ }
+ break;
+ case OP_DELETION:
+ hp->flags.time_offset = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_TIME_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (hp->flags.time_server && hp->time_server) {
+ del_iplist(hp->time_server);
+ }
+ hp->time_server = get_addresses(symbol);
+ hp->flags.time_server = TRUE;
+ break;
+ case OP_DELETION:
+ if (hp->flags.time_server && hp->time_server) {
+ del_iplist(hp->time_server);
+ }
+ hp->time_server = NULL;
+ hp->flags.time_server = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_VENDOR_MAGIC:
+ switch (optype) {
+ case OP_ADDITION:
+ if (!strncmp(*symbol, "auto", 4)) {
+ hp->flags.vm_auto = TRUE; /* Make it auto */
+ } else if (!strncmp(*symbol, "rfc1048", 7) ||
+ !strncmp(*symbol, "rfc1084", 7)) {
+ hp->flags.vm_auto = FALSE; /* Make it manual */
+ bcopy(vm_rfc1048, hp->vm_cookie, 4);
+ } else if (!strncmp(*symbol, "cmu", 3)) {
+ hp->flags.vm_auto = FALSE; /* Make it manual */
+ bcopy(vm_cmu, hp->vm_cookie, 4);
+ } else {
+ if (prs_inetaddr(symbol, &value) < 0) {
+ return E_BAD_VM_COOKIE;
+ }
+ hp->flags.vm_auto = FALSE; /* Make it manual */
+ ustr = hp->vm_cookie;
+ insert_u_long(value, &ustr);
+ }
+ hp->flags.vendor_magic = TRUE;
+ break;
+ case OP_DELETION:
+ hp->flags.vendor_magic = FALSE;
+ break;
+ case OP_BOOLEAN:
+ hp->flags.vm_auto = TRUE;
+ hp->flags.vendor_magic = TRUE;
+ break;
+ }
+ break;
+
+ case SYM_SIMILAR_ENTRY:
+ switch (optype) {
+ case OP_ADDITION:
+ fill_defaults(hp, symbol);
+ break;
+ default:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_NAME_SWITCH:
+ switch (optype) {
+ case OP_ADDITION:
+ return E_SYNTAX_ERROR;
+ case OP_DELETION:
+ hp->flags.send_name = FALSE;
+ hp->flags.name_switch = FALSE;
+ break;
+ case OP_BOOLEAN:
+ hp->flags.send_name = TRUE;
+ hp->flags.name_switch = TRUE;
+ break;
+ }
+ break;
+
+ case SYM_BOOTSIZE:
+ switch (optype) {
+ case OP_ADDITION:
+ if (!strncmp(*symbol, "auto", 4)) {
+ hp->flags.bootsize = TRUE;
+ hp->flags.bootsize_auto = TRUE;
+ } else {
+ hp->bootsize = (unsigned int) get_u_long(symbol);
+ hp->flags.bootsize = TRUE;
+ hp->flags.bootsize_auto = FALSE;
+ }
+ break;
+ case OP_DELETION:
+ hp->flags.bootsize = FALSE;
+ break;
+ case OP_BOOLEAN:
+ hp->flags.bootsize = TRUE;
+ hp->flags.bootsize_auto = TRUE;
+ break;
+ }
+ break;
+
+ case SYM_BOOT_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (prs_inetaddr(symbol, &value) < 0) {
+ return E_BAD_BOOT_SERVER;
+ } else {
+ hp->bootserver.s_addr = value;
+ hp->flags.bootserver = TRUE;
+ }
+ break;
+ case OP_DELETION:
+ hp->flags.bootserver = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_TFTPDIR:
+ switch (optype) {
+ case OP_ADDITION:
+ if (ss = get_shared_string(symbol)) {
+ if ((ss->string)[0] == '/') {
+ if (hp->tftpdir) {
+ del_string(hp->tftpdir);
+ }
+ hp->tftpdir = ss;
+ hp->flags.tftpdir = TRUE;
+ } else {
+ return E_BAD_TFTPDIR;
+ }
+ } else {
+ return E_BAD_TFTPDIR;
+ }
+ break;
+ case OP_DELETION:
+ if (hp->tftpdir) {
+ del_string(hp->tftpdir);
+ }
+ hp->tftpdir = NULL;
+ hp->flags.tftpdir = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_DUMPFILE:
+ switch (optype) {
+ case OP_ADDITION:
+ if (ss = get_shared_string(symbol)) {
+ if (hp->dumpfile) {
+ del_string(hp->dumpfile);
+ }
+ hp->dumpfile = ss;
+ hp->flags.dumpfile = TRUE;
+ }
+ break;
+ case OP_DELETION:
+ if (hp->dumpfile) {
+ del_string(hp->dumpfile);
+ }
+ hp->dumpfile = NULL;
+ hp->flags.dumpfile = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_DOMAIN_NAME:
+ switch (optype) {
+ case OP_ADDITION:
+ if (ss = get_shared_string(symbol)) {
+ if (hp->domainname) {
+ del_string(hp->domainname);
+ }
+ hp->domainname = ss;
+ hp->flags.domainname = TRUE;
+ }
+ break;
+ case OP_DELETION:
+ if (hp->domainname) {
+ del_string(hp->domainname);
+ }
+ hp->domainname = NULL;
+ hp->flags.domainname = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_ROOTPATH:
+ switch (optype) {
+ case OP_ADDITION:
+ if (ss = get_shared_string(symbol)) {
+ if (hp->rootpath) {
+ del_string(hp->rootpath);
+ }
+ hp->rootpath = ss;
+ hp->flags.rootpath = TRUE;
+ }
+ break;
+ case OP_DELETION:
+ if (hp->rootpath) {
+ del_string(hp->rootpath);
+ }
+ hp->rootpath = NULL;
+ hp->flags.rootpath = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ case SYM_SWAP_SERVER:
+ switch (optype) {
+ case OP_ADDITION:
+ if (prs_inetaddr(symbol, &value) < 0) {
+ return E_BAD_SWAP_SERVER;
+ } else {
+ hp->swapserver.s_addr = value;
+ hp->flags.swap_server = TRUE;
+ }
+ break;
+ case OP_DELETION:
+ hp->flags.swap_server = FALSE;
+ break;
+ case OP_BOOLEAN:
+ return E_SYNTAX_ERROR;
+ }
+ break;
+
+ default:
+ return E_UNKNOWN_SYMBOL;
+ }
+ return SUCCESS;
+}
+
+
+
+/*
+ * Read a string from the buffer indirectly pointed to through "src" and
+ * move it into the buffer pointed to by "dest". A pointer to the maximum
+ * allowable length of the string (including null-terminator) is passed as
+ * "length". The actual length of the string which was read is returned in
+ * the unsigned integer pointed to by "length". This value is the same as
+ * that which would be returned by applying the strlen() function on the
+ * destination string (i.e the terminating null is not counted as a
+ * character). Trailing whitespace is removed from the string. For
+ * convenience, the function returns the new value of "dest".
+ *
+ * The string is read until the maximum number of characters, an unquoted
+ * colon (:), or a null character is read. The return string in "dest" is
+ * null-terminated.
+ */
+
+PRIVATE char *get_string(src, dest, length)
+char **src, *dest;
+unsigned *length;
+{
+ int n, len, quoteflag;
+
+ quoteflag = FALSE;
+ n = 0;
+ len = *length - 1;
+ while ((n < len) && (**src)) {
+ if (!quoteflag && (**src == ':')) {
+ break;
+ }
+ if (**src == '"') {
+ (*src)++;
+ quoteflag = !quoteflag;
+ continue;
+ }
+ if (**src == '\\') {
+ (*src)++;
+ if (! **src) {
+ break;
+ }
+ }
+ *dest++ = *(*src)++;
+ n++;
+ }
+
+ /*
+ * Remove that troublesome trailing whitespace. . .
+ */
+ while ((n > 0) && isspace(dest[-1])) {
+ dest--;
+ n--;
+ }
+
+ *dest = '\0';
+ *length = n;
+ return dest;
+}
+
+
+
+/*
+ * Read the string indirectly pointed to by "src", update the caller's
+ * pointer, and return a pointer to a malloc'ed shared_string structure
+ * containing the string.
+ *
+ * The string is read using the same rules as get_string() above.
+ */
+
+PRIVATE struct shared_string *get_shared_string(src)
+char **src;
+{
+ char retstring[MAXSTRINGLEN];
+ struct shared_string *s;
+ unsigned length;
+
+ length = sizeof(retstring);
+ (void) get_string(src, retstring, &length);
+
+ s = (struct shared_string *) smalloc(sizeof(struct shared_string)
+ + length);
+ s->linkcount = 1;
+ strcpy(s->string, retstring);
+
+ return s;
+}
+
+
+
+/*
+ * Load RFC1048 generic information directly into a memory buffer.
+ *
+ * "src" indirectly points to the ASCII representation of the generic data.
+ * "dest" points to a string structure which is updated to point to a new
+ * string with the new data appended to the old string. The old string is
+ * freed.
+ *
+ * The given tag value is inserted with the new data.
+ *
+ * The data may be represented as either a stream of hexadecimal numbers
+ * representing bytes (any or all bytes may optionally start with '0x' and
+ * be separated with periods ".") or as a quoted string of ASCII
+ * characters (the quotes are required).
+ */
+
+PRIVATE void process_generic(src, dest, tagvalue)
+char **src;
+struct shared_bindata **dest;
+byte tagvalue;
+{
+ byte tmpbuf[MAXBUFLEN];
+ byte *str;
+ struct shared_bindata *bdata;
+ int newlength, oldlength;
+
+ str = tmpbuf;
+ *str++ = tagvalue; /* Store tag value */
+ str++; /* Skip over length field */
+ if ((*src)[0] == '"') { /* ASCII data */
+ newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
+ (void) get_string(src, str, &newlength);
+ } else { /* Numeric data */
+ newlength = 0;
+ while (newlength < sizeof(tmpbuf) - 2) {
+ if (interp_byte(src, str++) < 0) {
+ break;
+ } else {
+ newlength++;
+ }
+ if (**src == '.') {
+ (*src)++;
+ }
+ }
+ }
+ tmpbuf[1] = (byte) (newlength & 0xFF);
+ oldlength = ((*dest)->length);
+ bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
+ + oldlength + newlength + 1);
+ if (oldlength > 0) {
+ bcopy((*dest)->data, bdata->data, oldlength);
+ }
+ bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
+ bdata->length = oldlength + newlength + 2;
+ bdata->linkcount = 1;
+ if (*dest) {
+ del_bindata(*dest);
+ }
+ *dest = bdata;
+}
+
+
+
+/*
+ * Verify that the given string makes sense as a hostname (according to
+ * Appendix 1, page 29 of RFC882).
+ *
+ * Return TRUE for good names, FALSE otherwise.
+ */
+
+PRIVATE boolean goodname(hostname)
+register char *hostname;
+{
+ do {
+ if (!isalpha(*hostname++)) { /* First character must be a letter */
+ return FALSE;
+ }
+ while (isalnum(*hostname) || (*hostname == '-')) {
+ hostname++; /* Alphanumeric or a hyphen */
+ }
+ if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
+ return FALSE;
+ }
+ if (*hostname == '\0') { /* Done? */
+ return TRUE;
+ }
+ } while (*hostname++ == '.'); /* Dot, loop for next label */
+
+ return FALSE; /* If it's not a dot, lose */
+}
+
+
+
+/*
+ * Null compare function -- always returns FALSE so an element is always
+ * inserted into a hash table (i.e. there is never a collision with an
+ * existing element).
+ */
+
+PRIVATE boolean nullcmp(host1, host2)
+struct host *host1, *host2;
+{
+ return FALSE;
+}
+
+
+/*
+ * Function for comparing a string with the hostname field of a host
+ * structure.
+ */
+
+PRIVATE boolean nmcmp(name, hp)
+char *name;
+struct host *hp;
+{
+ return !strcmp(name, hp->hostname->string);
+}
+
+
+/*
+ * Compare function to determine whether two hardware addresses are
+ * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
+ * otherwise.
+ *
+ * If the hardware addresses of "host1" and "host2" are identical, but
+ * they are on different IP subnets, this function returns FALSE.
+ *
+ * This function is used when inserting elements into the hardware address
+ * hash table.
+ */
+
+PRIVATE boolean hwinscmp(host1, host2)
+struct host *host1, *host2;
+{
+ if (host1->htype != host2->htype) {
+ return FALSE;
+ }
+ if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
+ return FALSE;
+ }
+ if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
+ if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
+ ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr))) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+
+/*
+ * Process the "similar entry" symbol.
+ *
+ * The host specified as the value of the "tc" symbol is used as a template
+ * for the current host entry. Symbol values not explicitly set in the
+ * current host entry are inferred from the template entry.
+ */
+
+PRIVATE void fill_defaults(hp, src)
+struct host *hp;
+char **src;
+{
+ unsigned tlen, hashcode;
+ struct host *hp2, thp;
+ char tstring[MAXSTRINGLEN];
+
+ tlen = sizeof(tstring);
+ (void) get_string(src, tstring, &tlen);
+ if (goodname(tstring)) {
+ hashcode = hash_HashFunction(tstring, tlen);
+ hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp,
+ tstring);
+ } else {
+ thp.iaddr.s_addr = inet_addr(tstring);
+ hashcode = hash_HashFunction(&(thp.iaddr.s_addr), 4);
+ hp2 = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
+ &thp);
+ }
+ if (hp2 == NULL) {
+ report(LOG_ERR, "can't find tc=\"%s\"\n", tstring);
+ } else {
+ /*
+ * Assignments inside "if" conditionals are intended here.
+ */
+ if (!hp->flags.cookie_server) {
+ if (hp->flags.cookie_server = hp2->flags.cookie_server) {
+ hp->cookie_server = hp2->cookie_server;
+ (hp->cookie_server->linkcount)++;
+ }
+ }
+ if (!hp->flags.domain_server) {
+ if (hp->flags.domain_server = hp2->flags.domain_server) {
+ hp->domain_server = hp2->domain_server;
+ (hp->domain_server->linkcount)++;
+ }
+ }
+ if (!hp->flags.gateway) {
+ if (hp->flags.gateway = hp2->flags.gateway) {
+ hp->gateway = hp2->gateway;
+ (hp->gateway->linkcount)++;
+ }
+ }
+ if (!hp->flags.impress_server) {
+ if (hp->flags.impress_server = hp2->flags.impress_server) {
+ hp->impress_server = hp2->impress_server;
+ (hp->impress_server->linkcount)++;
+ }
+ }
+ if (!hp->flags.log_server) {
+ if (hp->flags.log_server = hp2->flags.log_server) {
+ hp->log_server = hp2->log_server;
+ (hp->log_server->linkcount)++;
+ }
+ }
+ if (!hp->flags.lpr_server) {
+ if (hp->flags.lpr_server = hp2->flags.lpr_server) {
+ hp->lpr_server = hp2->lpr_server;
+ (hp->lpr_server->linkcount)++;
+ }
+ }
+ if (!hp->flags.name_server) {
+ if (hp->flags.name_server = hp2->flags.name_server) {
+ hp->name_server = hp2->name_server;
+ (hp->name_server->linkcount)++;
+ }
+ }
+ if (!hp->flags.rlp_server) {
+ if (hp->flags.rlp_server = hp2->flags.rlp_server) {
+ hp->rlp_server = hp2->rlp_server;
+ (hp->rlp_server->linkcount)++;
+ }
+ }
+ if (!hp->flags.time_server) {
+ if (hp->flags.time_server = hp2->flags.time_server) {
+ hp->time_server = hp2->time_server;
+ (hp->time_server->linkcount)++;
+ }
+ }
+ if (!hp->flags.homedir) {
+ if (hp->flags.homedir = hp2->flags.homedir) {
+ hp->homedir = hp2->homedir;
+ (hp->homedir->linkcount)++;
+ }
+ }
+ if (!hp->flags.bootfile) {
+ if (hp->flags.bootfile = hp2->flags.bootfile) {
+ hp->bootfile = hp2->bootfile;
+ (hp->bootfile->linkcount)++;
+ }
+ }
+ if (!hp->flags.generic) {
+ if (hp->flags.generic = hp2->flags.generic) {
+ hp->generic = hp2->generic;
+ (hp->generic->linkcount)++;
+ }
+ }
+ if (!hp->flags.vendor_magic) {
+ hp->flags.vm_auto = hp2->flags.vm_auto;
+ if (hp->flags.vendor_magic = hp2->flags.vendor_magic) {
+ bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
+ }
+ }
+ if (!hp->flags.name_switch) {
+ if (hp->flags.name_switch = hp2->flags.name_switch) {
+ hp->flags.send_name = hp2->flags.send_name;
+ }
+ }
+ if (!hp->flags.htype) {
+ if (hp->flags.htype = hp2->flags.htype) {
+ hp->htype = hp2->htype;
+ }
+ }
+ if (!hp->flags.time_offset) {
+ if (hp->flags.time_offset = hp2->flags.time_offset) {
+ hp->flags.timeoff_auto = hp2->flags.timeoff_auto;
+ hp->time_offset = hp2->time_offset;
+ }
+ }
+ if (!hp->flags.subnet_mask) {
+ if (hp->flags.subnet_mask = hp2->flags.subnet_mask) {
+ hp->subnet_mask.s_addr = hp2->subnet_mask.s_addr;
+ }
+ }
+ if (!hp->flags.swap_server) {
+ if (hp->flags.swap_server = hp2->flags.swap_server) {
+ hp->swapserver.s_addr = hp2->swapserver.s_addr;
+ }
+ }
+ if (!hp->flags.bootsize) {
+ if (hp->flags.bootsize = hp2->flags.bootsize) {
+ hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
+ hp->bootsize = hp2->bootsize;
+ }
+ }
+ if (!hp->flags.tftpdir) {
+ if (hp->flags.tftpdir = hp2->flags.tftpdir) {
+ hp->tftpdir = hp2->tftpdir;
+ (hp->tftpdir->linkcount)++;
+ }
+ }
+ if (!hp->flags.rootpath) {
+ if (hp->flags.rootpath = hp2->flags.rootpath) {
+ hp->rootpath = hp2->rootpath;
+ (hp->rootpath->linkcount)++;
+ }
+ }
+ if (!hp->flags.domainname) {
+ if (hp->flags.domainname = hp2->flags.domainname) {
+ hp->domainname = hp2->domainname;
+ (hp->domainname->linkcount)++;
+ }
+ }
+ if (!hp->flags.dumpfile) {
+ if (hp->flags.dumpfile = hp2->flags.dumpfile) {
+ hp->dumpfile = hp2->dumpfile;
+ (hp->dumpfile->linkcount)++;
+ }
+ }
+ }
+}
+
+
+
+/*
+ * This function adjusts the caller's pointer to point just past the
+ * first-encountered colon. If it runs into a null character, it leaves
+ * the pointer pointing to it.
+ */
+
+PRIVATE void adjust(s)
+char **s;
+{
+ register char *t;
+
+ t = *s;
+ while (*t && (*t != ':')) {
+ t++;
+ }
+ if (*t) {
+ t++;
+ }
+ *s = t;
+}
+
+
+
+
+/*
+ * This function adjusts the caller's pointer to point to the first
+ * non-whitespace character. If it runs into a null character, it leaves
+ * the pointer pointing to it.
+ */
+
+PRIVATE void eat_whitespace(s)
+char **s;
+{
+ register char *t;
+
+ t = *s;
+ while (*t && isspace(*t)) {
+ t++;
+ }
+ *s = t;
+}
+
+
+
+/*
+ * This function converts the given string to all lowercase.
+ */
+
+PRIVATE void makelower(s)
+char *s;
+{
+ while (*s) {
+ if (isupper(*s)) {
+ *s = tolower(*s);
+ }
+ s++;
+ }
+}
+
+
+
+/*
+ *
+ * N O T E :
+ *
+ * In many of the functions which follow, a parameter such as "src" or
+ * "symbol" is passed as a pointer to a pointer to something. This is
+ * done for the purpose of letting the called function update the
+ * caller's copy of the parameter (i.e. to effect call-by-reference
+ * parameter passing). The value of the actual parameter is only used
+ * to locate the real parameter of interest and then update this indirect
+ * parameter.
+ *
+ * I'm sure somebody out there won't like this. . . .
+ *
+ *
+ */
+
+
+
+/*
+ * "src" points to a character pointer which points to an ASCII string of
+ * whitespace-separated IP addresses. A pointer to an in_addr_list
+ * structure containing the list of addresses is returned. NULL is
+ * returned if no addresses were found at all. The pointer pointed to by
+ * "src" is updated to point to the first non-address (illegal) character.
+ */
+
+PRIVATE struct in_addr_list *get_addresses(src)
+char **src;
+{
+ struct in_addr tmpaddrlist[MAXINADDRS];
+ struct in_addr *address1, *address2;
+ struct in_addr_list *result;
+ unsigned addrcount, totalsize;
+
+ address1 = tmpaddrlist;
+ for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
+ while (**src && isspace(**src)) { /* Skip whitespace */
+ (*src)++;
+ }
+ if (! **src) { /* Quit if nothing more */
+ break;
+ }
+ if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
+ break;
+ }
+ address1++; /* Point to next address slot */
+ }
+ if (addrcount < 1) {
+ result = NULL;
+ } else {
+ totalsize = sizeof(struct in_addr_list)
+ + (addrcount - 1) * sizeof(struct in_addr);
+ result = (struct in_addr_list *) smalloc(totalsize);
+ result->linkcount = 1;
+ result->addrcount = addrcount;
+ address1 = tmpaddrlist;
+ address2 = result->addr;
+ for (; addrcount > 0; addrcount--) {
+ address2->s_addr = address1->s_addr;
+ address1++;
+ address2++;
+ }
+ }
+ return result;
+}
+
+
+
+/*
+ * prs_inetaddr(src, result)
+ *
+ * "src" is a value-result parameter; the pointer it points to is updated
+ * to point to the next data position. "result" points to an unsigned long
+ * in which an address is returned.
+ *
+ * This function parses the IP address string in ASCII "dot notation" pointed
+ * to by (*src) and places the result (in network byte order) in the unsigned
+ * long pointed to by "result". For malformed addresses, -1 is returned,
+ * (*src) points to the first illegal character, and the unsigned long pointed
+ * to by "result" is unchanged. Successful calls return 0.
+ */
+
+PRIVATE prs_inetaddr(src, result)
+char **src;
+u_long *result;
+{
+ register u_long value;
+ u_long parts[4], *pp = parts;
+ int n;
+
+ if (!isdigit(**src)) {
+ return -1;
+ }
+loop:
+ value = get_u_long(src);
+ if (**src == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16-bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 4) {
+ return (-1);
+ }
+ *pp++ = value;
+ (*src)++;
+ goto loop;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (**src && !(isspace(**src) || (**src == ':'))) {
+ return (-1);
+ }
+ *pp++ = value;
+ /*
+ * Construct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts;
+ switch (n) {
+ case 1: /* a -- 32 bits */
+ value = parts[0];
+ break;
+ case 2: /* a.b -- 8.24 bits */
+ value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
+ break;
+ case 3: /* a.b.c -- 8.8.16 bits */
+ value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
+ (parts[2] & 0xFFFF);
+ break;
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
+ ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
+ break;
+ default:
+ return (-1);
+ }
+ *result = htonl(value);
+ return (0);
+}
+
+
+
+/*
+ * "src" points to a pointer which in turn points to a hexadecimal ASCII
+ * string. This string is interpreted as a hardware address and returned
+ * as a pointer to the actual hardware address, represented as an array of
+ * bytes.
+ *
+ * The ASCII string must have the proper number of digits for the specified
+ * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
+ * Two-digit sequences (bytes) may be separated with periods (.) and/or
+ * prefixed with '0x' for readability, but this is not required.
+ *
+ * For bad addresses, the pointer which "src" points to is updated to point
+ * to the start of the first two-digit sequence which was bad, and the
+ * function returns a NULL pointer.
+ */
+
+PRIVATE byte *prs_haddr(src, htype)
+char **src;
+byte htype;
+{
+ static byte haddr[MAXHADDRLEN];
+ byte *hptr;
+ unsigned hlen;
+
+ hlen = haddrlength(htype); /* Get length of this address type */
+ hptr = haddr;
+ while (hptr < haddr + hlen) {
+ if (**src == '.') {
+ (*src)++;
+ }
+ if (interp_byte(src, hptr++) < 0) {
+ return NULL;
+ }
+ }
+ return haddr;
+}
+
+
+
+/*
+ * "src" is a pointer to a character pointer which in turn points to a
+ * hexadecimal ASCII representation of a byte. This byte is read, the
+ * character pointer is updated, and the result is deposited into the
+ * byte pointed to by "retbyte".
+ *
+ * The usual '0x' notation is allowed but not required. The number must be
+ * a two digit hexadecimal number. If the number is invalid, "src" and
+ * "retbyte" are left untouched and -1 is returned as the function value.
+ * Successful calls return 0.
+ */
+
+PRIVATE int interp_byte(src, retbyte)
+char **src;
+byte *retbyte;
+{
+ int v;
+
+ if ((*src)[0] == '0' && (*src)[1] == 'x' || (*src)[1] == 'X') {
+ (*src) += 2; /* allow 0x for hex, but don't require it */
+ }
+ if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
+ return -1;
+ }
+ if (sscanf(*src, "%2x", &v) != 1) {
+ return -1;
+ }
+ (*src) += 2;
+ *retbyte = (byte) (v & 0xFF);
+ return 0;
+}
+
+
+
+/*
+ * The parameter "src" points to a character pointer which points to an
+ * ASCII string representation of an unsigned number. The number is
+ * returned as an unsigned long and the character pointer is updated to
+ * point to the first illegal character.
+ */
+
+PRIVATE u_long get_u_long(src)
+char **src;
+{
+ register u_long value, base;
+ char c;
+
+ /*
+ * Collect number up to first illegal character. Values are specified
+ * as for C: 0x=hex, 0=octal, other=decimal.
+ */
+ value = 0;
+ base = 10;
+ if (**src == '0') {
+ base = 8, (*src)++;
+ }
+ if (**src == 'x' || **src == 'X') {
+ base = 16, (*src)++;
+ }
+ while (c = **src) {
+ if (isdigit(c)) {
+ value = (value * base) + (c - '0');
+ (*src)++;
+ continue;
+ }
+ if (base == 16 && isxdigit(c)) {
+ value = (value << 4) + ((c & ~32) + 10 - 'A');
+ (*src)++;
+ continue;
+ }
+ break;
+ }
+ return value;
+}
+
+
+
+/*
+ * Routines for deletion of data associated with the main data structure.
+ */
+
+
+/*
+ * Frees the entire host data structure given. Does nothing if the passed
+ * pointer is NULL.
+ */
+
+PRIVATE void free_host(hostptr)
+struct host *hostptr;
+{
+ if (hostptr) {
+ del_iplist(hostptr->cookie_server);
+ del_iplist(hostptr->domain_server);
+ del_iplist(hostptr->gateway);
+ del_iplist(hostptr->impress_server);
+ del_iplist(hostptr->log_server);
+ del_iplist(hostptr->lpr_server);
+ del_iplist(hostptr->name_server);
+ del_iplist(hostptr->rlp_server);
+ del_iplist(hostptr->time_server);
+ del_string(hostptr->hostname);
+ del_string(hostptr->homedir);
+ del_string(hostptr->bootfile);
+ del_string(hostptr->tftpdir);
+ del_string(hostptr->rootpath);
+ del_string(hostptr->domainname);
+ del_string(hostptr->dumpfile);
+ del_bindata(hostptr->generic);
+ free((char *) hostptr);
+ }
+}
+
+
+
+/*
+ * Decrements the linkcount on the given IP address data structure. If the
+ * linkcount goes to zero, the memory associated with the data is freed.
+ */
+
+PRIVATE void del_iplist(iplist)
+struct in_addr_list *iplist;
+{
+ if (iplist) {
+ if (! (--(iplist->linkcount))) {
+ free((char *) iplist);
+ }
+ }
+}
+
+
+
+/*
+ * Decrements the linkcount on a string data structure. If the count
+ * goes to zero, the memory associated with the string is freed. Does
+ * nothing if the passed pointer is NULL.
+ */
+
+PRIVATE void del_string(stringptr)
+struct shared_string *stringptr;
+{
+ if (stringptr) {
+ if (! (--(stringptr->linkcount))) {
+ free((char *) stringptr);
+ }
+ }
+}
+
+
+
+/*
+ * Decrements the linkcount on a shared_bindata data structure. If the
+ * count goes to zero, the memory associated with the data is freed. Does
+ * nothing if the passed pointer is NULL.
+ */
+
+PRIVATE void del_bindata(dataptr)
+struct shared_bindata *dataptr;
+{
+ if (dataptr) {
+ if (! (--(dataptr->linkcount))) {
+ free((char *) dataptr);
+ }
+ }
+}
+
+
+
+
+/* smalloc() -- safe malloc()
+ *
+ * Always returns a valid pointer (if it returns at all). The allocated
+ * memory is initialized to all zeros. If malloc() returns an error, a
+ * message is printed using the report() function and the program aborts
+ * with a status of 1.
+ */
+
+PRIVATE char *smalloc(nbytes)
+unsigned nbytes;
+{
+ char *retvalue;
+
+ retvalue = malloc(nbytes);
+ if (!retvalue) {
+ report(LOG_ERR, "malloc() failure -- exiting\n");
+ exit(1);
+ }
+ bzero(retvalue, nbytes);
+ return retvalue;
+}
diff --git a/libexec/bugfiler/bugformat b/libexec/bugfiler/bugformat
index 939f4188f49a..5cc51f20a4f7 100644
--- a/libexec/bugfiler/bugformat
+++ b/libexec/bugfiler/bugformat
@@ -18,7 +18,7 @@ To ensure that your bug report is handled correctly by bugfiler(8),
you must replace "folder" (on the line above starting with "Index:")
with one of the following values:
- folder ::= bin | doc | etc | games | ideas | include | lib
+ folder ::= bin | doc | etc | games | gnu | ideas | include | lib
| libexec | man | misc | sbin | share | sys
| usr.bin | usr.sbin
diff --git a/libexec/comsat/comsat.8 b/libexec/comsat/comsat.8
index 317b7490cb1f..e4e2b8978289 100644
--- a/libexec/comsat/comsat.8
+++ b/libexec/comsat/comsat.8
@@ -53,7 +53,7 @@ and
.Xr inetd 8 ) .
The one line messages are of the form:
.Pp
-.Dl user@mailbox-offset
+.Dl user@mailbox-offset[:mailbox-name]
.Pp
If the
.Em user
@@ -72,10 +72,14 @@ the message header other than the
or
.Dq Subject
lines are not included in the displayed message.
+.Pp
+If mailbox-name omitted, standard mailbox assumed.
.Sh FILES
-.Bl -tag -width /var/run/utmp -compact
+.Bl -tag -width /var/mail/user -compact
.It Pa /var/run/utmp
to find out who's logged on and on what terminals
+.It Pa /var/mail/user
+standard mailbox
.El
.Sh SEE ALSO
.Xr biff 1 ,
diff --git a/libexec/comsat/comsat.c b/libexec/comsat/comsat.c
index 1bcd4d18a582..89e0211a0e8c 100644
--- a/libexec/comsat/comsat.c
+++ b/libexec/comsat/comsat.c
@@ -42,6 +42,7 @@ static char sccsid[] = "@(#)comsat.c 5.24 (Berkeley) 2/25/91";
#endif /* not lint */
#include <sys/param.h>
+#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/file.h>
@@ -59,6 +60,7 @@ static char sccsid[] = "@(#)comsat.c 5.24 (Berkeley) 2/25/91";
#include <ctype.h>
#include <string.h>
#include <paths.h>
+#include <pwd.h>
int debug = 0;
#define dsyslog if (debug) syslog
@@ -165,22 +167,33 @@ mailfor(name)
{
register struct utmp *utp = &utmp[nutmp];
register char *cp;
+ char *file;
off_t offset;
+ int folder;
+ char buf[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1];
if (!(cp = index(name, '@')))
return;
*cp = '\0';
offset = atoi(cp + 1);
+ if (!(cp = index(cp + 1, ':')))
+ file = name;
+ else
+ file = cp + 1;
+ sprintf(buf, "%s/%.*s", _PATH_MAILDIR, sizeof(utmp[0].ut_name), name);
+ folder = strcmp(buf, file);
while (--utp >= utmp)
if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name)))
- notify(utp, offset);
+ notify(utp, file, offset, folder);
}
static char *cr;
-notify(utp, offset)
+notify(utp, file, offset, folder)
register struct utmp *utp;
+ char *file;
off_t offset;
+ int folder;
{
static char tty[20] = _PATH_DEV;
struct sgttyb gttybuf;
@@ -208,9 +221,11 @@ notify(utp, offset)
"\n" : "\n\r";
(void)strncpy(name, utp->ut_name, sizeof(utp->ut_name));
name[sizeof(name) - 1] = '\0';
- (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s",
- cr, name, sizeof(hostname), hostname, cr, cr);
- jkfprintf(tp, name, offset);
+ (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s",
+ cr, name, sizeof(hostname), hostname,
+ folder ? cr : "", folder ? "to " : "", folder ? file : "",
+ cr, cr);
+ jkfprintf(tp, file, offset);
(void)fclose(tp);
_exit(0);
}
@@ -220,10 +235,19 @@ jkfprintf(tp, name, offset)
char name[];
off_t offset;
{
- register char *cp, ch;
+ register char *cp;
+ unsigned char ch;
register FILE *fi;
register int linecnt, charcnt, inheader;
char line[BUFSIZ];
+ struct passwd *pw;
+
+ if((pw = getpwnam(name))==NULL) {
+ /* Should not happen */
+ return;
+ }
+ setgid(pw->pw_gid);
+ setuid(pw->pw_uid);
if ((fi = fopen(name, "r")) == NULL)
return;
@@ -253,10 +277,17 @@ jkfprintf(tp, name, offset)
}
/* strip weird stuff so can't trojan horse stupid terminals */
for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) {
- ch = toascii(ch);
- if (!isprint(ch) && !isspace(ch))
- ch |= 0x40;
- (void)fputc(ch, tp);
+ char dest;
+ /* XXX:
+ * because *BSD don't have setlocale() (yet)
+ * here simple hack that allows ISO8859-x
+ * and koi8-r charsets in terminal mode.
+ * Note: range 0x80-0x9F skipped to avoid
+ * some kinda security hole on poor DEC VTs
+ */
+ dest = (ch >= 0xA0 || isprint(ch)) ? ch : '?';
+
+ (void)fputc(dest, tp);
}
(void)fputs(cr, tp);
--linecnt;
diff --git a/libexec/crond/Makefile b/libexec/crond/Makefile
deleted file mode 100644
index f722dae12197..000000000000
--- a/libexec/crond/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-#
-#
-# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
-# -------------------- ----- ----------------------
-# CURRENT PATCH LEVEL: 1 00037
-# -------------------- ----- ----------------------
-#
-# 15 Sep 92 Adrian Hall Fixes SRCS line
-#
-
-PROG= crond
-SRCS= crond.c database.c user.c entry.c misc.c job.c do_command.c env.c
-CFLAGS+=-I${.CURDIR} -DDEBUGGING=1 -DBSD -DCRONDIR='"/var/cron"' -fstrength-reduce
-MAN8= crond.8
-
-.include <bsd.prog.mk>
diff --git a/libexec/crond/Makefile.vixie b/libexec/crond/Makefile.vixie
deleted file mode 100644
index 9e5ee8a3a808..000000000000
--- a/libexec/crond/Makefile.vixie
+++ /dev/null
@@ -1,123 +0,0 @@
-# Makefile for vixie's cron
-#
-# $Header: /a/cvs/386BSD/src/libexec/crond/Makefile.vixie,v 1.1.1.1 1993/06/12 14:55:04 rgrimes Exp $
-#
-# vix 03mar88 [moved to RCS, rest of log is in there]
-# vix 30mar87 [goodbye, time.c; hello, getopt]
-# vix 12feb87 [cleanup for distribution]
-# vix 30dec86 [written]
-
-#/* Copyright 1988,1990 by Paul Vixie
-# * All rights reserved
-# *
-# * Distribute freely, except: don't remove my name from the source or
-# * documentation (don't take credit for my work), mark your changes (don't
-# * get me blamed for your possible bugs), don't alter or remove this
-# * notice. May be sold if buildable source is provided to buyer. No
-# * warrantee of any kind, express or implied, is included with this
-# * software; use at your own risk, responsibility for damages (if any) to
-# * anyone resulting from the use of this software rests entirely with the
-# * user.
-# *
-# * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
-# * I'll try to keep a version up to date. I can be reached as follows:
-# * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
-# * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
-# */
-
-# NOTES:
-# 'make' can be done by anyone
-# 'make install' must be done by root
-#
-# this package needs getopt(3), bitstring(3), and BSD install(8).
-#
-# the configurable stuff in this makefile consists of compilation
-# options (use -O, cron runs forever) and destination directories.
-# SHELL is for the 'augumented make' systems where 'make' imports
-# SHELL from the environment and then uses it to run its commands.
-# if your environment SHELL variable is /bin/csh, make goes real
-# slow and sometimes does the wrong thing. BINDIR is where the
-# 'crontab' command goes, and should be a common place like /usr/bin.
-# LIBDIR is where the cron daemon lives; /usr/etc is common.
-#
-# this package needs the 'bitstring macros' library, which is
-# available from me or from the comp.sources.unix archive. if you
-# put 'bitstring.h' in a non-standard place (i.e., not intuited by
-# cc(1)), you will have to define INCLUDE to set the include
-# directory for cc. INCLUDE should be `-Isomethingorother'.
-#
-# there's more configuration info in config.h; edit that first!
-
-#################################### begin configurable stuff
-#<<DESTROOT is assumed to have ./etc, ./bin, and ./man subdirectories>>
-DESTROOT = /usr/
-#<<CRONDIR will be created by crond or crontab if nec'y>>
-CRONDIR = /var/cron
-#<<need bitstring.h>>
-INCLUDE = -I.
-#INCLUDE =
-#<<need getopt()>>
-#LIBS = /usr/local/lib/getopt.o
-LIBS =
-#<<optimize or debug?>>
-OPTIM = -O -fstrength-reduce
-#OPTIM = -g
-#<<want -x flag for debugging?>>
-DEBUGGING = -DDEBUGGING=1
-#DEBUGGING = -DDEBUGGING=0
-#<<ATT or BSD?>>
-# (ATT untested)
-#COMPAT = -DATT
-COMPAT = -DBSD
-#<<lint flags of choice?>>
-LINTFLAGS = -hbxa $(INCLUDE) $(COMPAT) $(DEBUGGING)
-#<<want to use a nonstandard CC?>>
-#CC = vcc
-#<<manifest defines>>
-DEFS = '-DCRONDIR="$(CRONDIR)"'
-#################################### end configurable stuff
-
-SHELL = /bin/sh
-CFLAGS = $(OPTIM) $(INCLUDE) $(COMPAT) $(DEBUGGING) $(DEFS)
-
-INFOS = README CHANGES.V2 FEATURES INSTALL CONVERSION THANKS
-MANPAGES = bitstring.3 crontab.5 crontab.1 crond.8
-HEADERS = bitstring.h cron.h config.h
-SOURCES = crond.c crontab.c database.c do_command.c \
- entry.c env.c job.c misc.c user.c
-SHAR_SOURCE = $(INFOS) $(MANPAGES) Makefile $(HEADERS) $(SOURCES)
-LINT_CROND = crond.c database.c user.c entry.c \
- misc.c job.c do_command.c env.c
-LINT_CRONTAB = crontab.c misc.c entry.c env.c
-CRON_OBJ = crond.o database.o user.o entry.o \
- misc.o job.o do_command.o env.o
-CRONTAB_OBJ = crontab.o misc.o entry.o env.o
-
-all : crond crontab
-
-lint :
- lint $(LINTFLAGS) $(LINT_CROND) $(LIBS) \
- |grep -v "constant argument to NOT" 2>&1
- lint $(LINTFLAGS) $(LINT_CRONTAB) $(LIBS) \
- |grep -v "constant argument to NOT" 2>&1
-
-crond : $(CRON_OBJ)
- $(CC) -o crond $(CRON_OBJ) $(LIBS)
-
-crontab : $(CRONTAB_OBJ)
- $(CC) -o crontab $(CRONTAB_OBJ) $(LIBS)
-
-install : all
- install -c -m 111 -o root -s crond $(DESTROOT)/libexec/
- install -c -m 4111 -o root -s crontab $(DESTROOT)/bin/
- #install -c crontab.1 $(DESTROOT)/man/man1/crontab.1
- #install -c crond.8 $(DESTROOT)/man/man8/crond.8
- install -c crontab.5 $(DESTROOT)/man/man5/crontab.5
-
-clean :; rm -f *.o crond crontab a.out core tags *~ #*
-
-kit : $(SHAR_SOURCE)
- makekit -m -s50k $(SHAR_SOURCE)
-
-$(CRON_OBJ) : cron.h config.h Makefile
-$(CRONTAB_OBJ) : cron.h config.h Makefile
diff --git a/libexec/crond/README b/libexec/crond/README
deleted file mode 100644
index dcc6fcfbbbfd..000000000000
--- a/libexec/crond/README
+++ /dev/null
@@ -1,93 +0,0 @@
-Vixie's Cron V2.1
-May 29, 1991
-[V2.0 was July 5, 1990]
-[V2.0-beta was December 9, 1988]
-[V1.0 was May 6, 1987]
-Paul Vixie
-
-This is a version of 'cron' that is known to run on BSD 4.[23] systems. It
-is functionally based on the SysV cron, which means that each user can have
-their own crontab file (all crontab files are stored in a read-protected
-directory, usually /var/cron/tabs). No direct support is provided for
-'at'; you can continue to run 'atrun' from the crontab as you have been
-doing. If you don't have atrun (i.e., System V) you are in trouble.
-
-A messages is logged each time a command is executed; also, the files
-"allow" and "deny" in /var/cron can be used to control access to the
-"crontab" command (which installs crontabs). It hasn't been tested on
-SysV, although some effort has gone into making the port an easy one.
-
-The code was all written by me, and is (quoted from Makefile):
-
-#/* Copyright 1988,1990 by Paul Vixie
-# * All rights reserved
-# *
-# * Distribute freely, except: don't remove my name from the source or
-# * documentation (don't take credit for my work), mark your changes (don't
-# * get me blamed for your possible bugs), don't alter or remove this
-# * notice. May be sold if buildable source is provided to buyer. No
-# * warrantee of any kind, express or implied, is included with this
-# * software; use at your own risk, responsibility for damages (if any) to
-# * anyone resulting from the use of this software rests entirely with the
-# * user.
-# *
-# * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
-# * I'll try to keep a version up to date. I can be reached as follows:
-# * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
-# * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
-# */
-
-This is more or less the copyright that USENET contributed software usually
-has. Since ATT couldn't use this version if they had to freely distribute
-source, and since I'd love to see them use it, I'll offer some rediculously
-low license fee just to have them take it. In the unlikely event that they
-do this, I will continue to support and distribute the pseudo-PD version, so
-please, don't flame me for wanting my work to see a wider distribution.
-
-To use this: Sorry, folks, there is no cutesy 'Configure' script. You'll
-have to go edit a couple of files... So, here's the checklist:
-
- Read all the FEATURES, INSTALL, and CONVERSION files
- Edit config.h
- Edit Makefile
- (both of these files have instructions inside; note that
- some things in config.h are definable in Makefile and are
- therefore surrounded by #ifndef...#endif)
- 'make'
- 'su' and 'make install'
- (you may have to install the man pages by hand)
- kill your existing cron process
- (actually you can run your existing cron if you want, but why?)
- build new crontabs using /usr/lib/{crontab,crontab.local}
- (either put them all in "root"'s crontab, or divide it up
- and rip out all the 'su' commands, collapse the lengthy
- lists into ranges with steps -- basically, this step is
- as much work as you want to make it)
- start up the new cron
- (must be done as root)
- watch it. test it with 'crontab -r' and watch the daemon track your
- changes.
- if you like it, change your /etc/{rc,rc.local} to use it instead of
- the old one.
-
-$Header: /a/cvs/386BSD/src/libexec/crond/README,v 1.1.1.1 1993/06/12 14:55:04 rgrimes Exp $
-$Source: /a/cvs/386BSD/src/libexec/crond/README,v $
-$Revision: 1.1.1.1 $
-$Log: README,v $
-# Revision 1.1.1.1 1993/06/12 14:55:04 rgrimes
-# Initial import, 0.1 + pk 0.2.4-B1
-#
-Revision 2.2 91/05/29 11:37:38 vixie
-vixie
-
-Revision 2.1 90/07/18 00:23:54 vixie
-Baseline for 4.4BSD release
-
-Revision 2.0 88/12/10 04:57:50 vixie
-V2 Beta
-
-Revision 1.2 87/07/10 11:36:45 paul
-misc
-
-Revision 1.1 87/07/10 11:15:05 paul
-Initial revision
diff --git a/libexec/crond/THANKS b/libexec/crond/THANKS
deleted file mode 100644
index 3787c2943d7a..000000000000
--- a/libexec/crond/THANKS
+++ /dev/null
@@ -1,29 +0,0 @@
-15 January 1990
-Paul Vixie
-
-Many people have contributed to cron. Many more than I can remember, in fact.
-Rich Salz and Carl Gutekunst were each of enormous help to me in V1; Carl for
-helping me understand UNIX well enough to write it, and Rich for helping me
-get the features right.
-
-John Gilmore wrote me a wonderful review of V2, which took me a whole year to
-answer even though it made me clean up some really awful things in the code.
-(According to John the most awful things are still in here, of course.)
-
-Paul Close made a suggestion which led to /etc/crond.pid and the mutex locking
-on it. Kevin Braunsdorf of Purdue made a suggestion that led to @reboot and
-its brothers and sisters; he also sent some diffs that lead cron toward compil-
-ability with System V, though without at(1) capabilities, this cron isn't going
-to be that useful on System V. Bob Alverson fixed a silly bug in the line
-number counting. Brian Reid made suggestions which led to the run queue and
-the source-file labelling in installed crontabs.
-
-Scott Narveson ported V2 to a Sequent, and sent in the most useful single batch
-of diffs I got from anybody. Changes attributable to Scott are:
- -> sendmail won't time out if the command is slow to generate output
- -> day-of-week names aren't off by one anymore
- -> crontab says the right thing if you do something you shouldn't do
- -> crontab(5) man page is longer and more informative
- -> misc changes related to the side effects of fclose()
- -> Sequent "universe" support added (may also help on Pyramids)
- -> null pw_shell is dealt with now; default is /bin/sh
diff --git a/libexec/crond/config.h b/libexec/crond/config.h
deleted file mode 100644
index f2a6756e18bd..000000000000
--- a/libexec/crond/config.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* config.h - configurables for Vixie Cron
- *
- * $Header: /a/cvs/386BSD/src/libexec/crond/config.h,v 1.1.1.1 1993/06/12 14:55:04 rgrimes Exp $
- */
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- */
-
-#ifndef _CONFIG_FLAG
-#define _CONFIG_FLAG
-
-/*
- * these are site-dependent
- */
- /*
- * choose one of these MAILCMD commands. I use
- * /bin/mail for speed; it makes biff bark but doesn't
- * do aliasing. /usr/lib/sendmail does aliasing but is
- * a hog for short messages. aliasing is not needed
- * if you make use of the MAILTO= feature in crontabs.
- * (hint: MAILTO= was added for this reason).
- */
-
-# define MAILCMD "/usr/sbin/sendmail -F\"Cron Daemon\" -odi -oem -or0s %s" /*-*/
- /* -Fx = set full-name of sender
- * -odi = Option Deliverymode Interactive
- * -oem = Option Errors Mailedtosender
- * -or0s = Option Readtimeout -- don't time out
- */
-
-/* # define MAILCMD "/bin/mail -d %s" /*-*/
- /* -d = undocumented but common flag: deliver locally?
- */
-
-#ifndef CRONDIR
- /* CRONDIR is where crond(8) and crontab(1) both chdir
- * to; SPOOL_DIR, ALLOW_FILE, DENY_FILE, and LOG_FILE
- * are all relative to this directory.
- *
- * this can and should be set in the Makefile.
- */
-# define CRONDIR "/var/cron"
-#endif
-
- /* SPOOLDIR is where the crontabs live.
- * This directory will have its modtime updated
- * whenever crontab(1) changes a crontab; this is
- * the signal for crond(8) to look at each individual
- * crontab file and reload those whose modtimes are
- * newer than they were last time around (or which
- * didn't exist last time around...)
- */
-#define SPOOL_DIR "tabs"
-
- /* undefining these turns off their features. note
- * that ALLOW_FILE and DENY_FILE must both be defined
- * in order to enable the allow/deny code. If neither
- * LOG_FILE or SYSLOG is defined, we don't log. If
- * both are defined, we log both ways.
- */
-#define ALLOW_FILE "allow" /*-*/
-#define DENY_FILE "deny" /*-*/
-#define LOG_FILE "log" /*-*/
-
- /* if ALLOW_FILE and DENY_FILE are not defined or are
- * defined but neither exists, should crontab(1) be
- * usable only by root?
- */
-/*#define ALLOW_ONLY_ROOT /*-*/
-
- /* if you want to use syslog(3) instead of appending
- * to CRONDIR/LOG_FILE (/var/cron/log, e.g.), define
- * SYSLOG here. Note that quite a bit of logging
- * info is written, and that you probably don't want
- * to use this on 4.2bsd since everything goes in
- * /usr/spool/mqueue/syslog. On 4.[34]bsd you can
- * tell /etc/syslog.conf to send cron's logging to
- * a separate file.
- */
-/*#define SYSLOG /*-*/
-
- /* this is the name of the environment variable
- * that contains the user name. it isn't read by
- * cron, but it is SET by crond in the environments
- * it creates for subprocesses. on BSD, it will
- * always be USER; on SysV it could be LOGNAME or
- * something else.
- */
-#if defined(BSD)
-# define USERENV "USER"
-#endif
-#if defined(ATT)
-# define USERENV "LOGNAME"
-#endif
-
- /* where should the daemon stick its PID?
- */
-#define PIDFILE "/var/run/crond.pid"
-
-#endif /*CONFIG_FLAG*/
diff --git a/libexec/crond/cron.h b/libexec/crond/cron.h
deleted file mode 100644
index de89f9fb05f1..000000000000
--- a/libexec/crond/cron.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/* cron.h - header for vixie's cron
- *
- * $Header: /a/cvs/386BSD/src/libexec/crond/cron.h,v 1.1.1.1 1993/06/12 14:55:04 rgrimes Exp $
- * $Source: /a/cvs/386BSD/src/libexec/crond/cron.h,v $
- * $Revision: 1.1.1.1 $
- * $Log: cron.h,v $
- * Revision 1.1.1.1 1993/06/12 14:55:04 rgrimes
- * Initial import, 0.1 + pk 0.2.4-B1
- *
- * Revision 2.1 90/07/18 00:23:47 vixie
- * Baseline for 4.4BSD release
- *
- * Revision 2.0 88/12/10 04:57:39 vixie
- * V2 Beta
- *
- * Revision 1.2 88/11/29 13:05:46 vixie
- * seems to work on Ultrix 3.0 FT1
- *
- * Revision 1.1 88/11/14 12:27:49 vixie
- * Initial revision
- *
- * Revision 1.4 87/05/02 17:33:08 paul
- * baseline for mod.sources release
- *
- * vix 14jan87 [0 or 7 can be sunday; thanks, mwm@berkeley]
- * vix 30dec86 [written]
- */
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- */
-
-#ifndef _CRON_FLAG
-#define _CRON_FLAG
-
-#include <stdio.h>
-#include <ctype.h>
-#include <bitstring.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "config.h"
-
- /* these are really immutable, and are
- * defined for symbolic convenience only
- * TRUE, FALSE, and ERR must be distinct
- */
-#define TRUE 1
-#define FALSE 0
- /* system calls return this on success */
-#define OK 0
- /* or this on error */
-#define ERR (-1)
-
- /* meaningless cookie for smart compilers that will pick their
- * own register variables; this makes the code neater.
- */
-#define local /**/
-
- /* turn this on to get '-x' code */
-#ifndef DEBUGGING
-#define DEBUGGING FALSE
-#endif
-
-#define READ_PIPE 0 /* which end of a pipe pair do you read? */
-#define WRITE_PIPE 1 /* or write to? */
-#define STDIN 0 /* what is stdin's file descriptor? */
-#define STDOUT 1 /* stdout's? */
-#define STDERR 2 /* stderr's? */
-#define ERROR_EXIT 1 /* exit() with this will scare the shell */
-#define OK_EXIT 0 /* exit() with this is considered 'normal' */
-#define MAX_FNAME 100 /* max length of internally generated fn */
-#define MAX_COMMAND 1000 /* max length of internally generated cmd */
-#define MAX_ENVSTR 1000 /* max length of envvar=value\0 strings */
-#define MAX_TEMPSTR 100 /* obvious */
-#define MAX_UNAME 20 /* max length of username, should be overkill */
-#define ROOT_UID 0 /* don't change this, it really must be root */
-#define ROOT_USER "root" /* ditto */
-
- /* NOTE: these correspond to DebugFlagNames,
- * defined below.
- */
-#define DEXT 0x0001 /* extend flag for other debug masks */
-#define DSCH 0x0002 /* scheduling debug mask */
-#define DPROC 0x0004 /* process control debug mask */
-#define DPARS 0x0008 /* parsing debug mask */
-#define DLOAD 0x0010 /* database loading debug mask */
-#define DMISC 0x0020 /* misc debug mask */
-#define DTEST 0x0040 /* test mode: don't execute any commands */
-
- /* the code does not depend on any of vfork's
- * side-effects; it just uses it as a quick
- * fork-and-exec.
- */
-#if defined(BSD)
-# define VFORK vfork
-#endif
-#if defined(ATT)
-# define VFORK fork
-#endif
-
-#define CRON_TAB(u) "%s/%s", SPOOL_DIR, u
-#define REG register
-#define PPC_NULL ((char **)NULL)
-
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN 64
-#endif
-
-#define Skip_Blanks(c, f) \
- while (c == '\t' || c == ' ') \
- c = get_char(f);
-
-#define Skip_Nonblanks(c, f) \
- while (c!='\t' && c!=' ' && c!='\n' && c != EOF) \
- c = get_char(f);
-
-#define Skip_Line(c, f) \
- do {c = get_char(f);} while (c != '\n' && c != EOF);
-
-#if DEBUGGING
-# define Debug(mask, message) \
- if ( (DebugFlags & (mask) ) == (mask) ) \
- printf message;
-#else /* !DEBUGGING */
-# define Debug(mask, message) \
- ;
-#endif /* DEBUGGING */
-
-#define MkLower(ch) (isupper(ch) ? tolower(ch) : ch)
-#define MkUpper(ch) (islower(ch) ? toupper(ch) : ch)
-#define Set_LineNum(ln) {Debug(DPARS|DEXT,("linenum=%d\n",ln)); \
- LineNumber = ln; \
- }
-
-#define FIRST_MINUTE 0
-#define LAST_MINUTE 59
-#define MINUTE_COUNT (LAST_MINUTE - FIRST_MINUTE + 1)
-
-#define FIRST_HOUR 0
-#define LAST_HOUR 23
-#define HOUR_COUNT (LAST_HOUR - FIRST_HOUR + 1)
-
-#define FIRST_DOM 1
-#define LAST_DOM 31
-#define DOM_COUNT (LAST_DOM - FIRST_DOM + 1)
-
-#define FIRST_MONTH 1
-#define LAST_MONTH 12
-#define MONTH_COUNT (LAST_MONTH - FIRST_MONTH + 1)
-
-/* note on DOW: 0 and 7 are both Sunday, for compatibility reasons. */
-#define FIRST_DOW 0
-#define LAST_DOW 7
-#define DOW_COUNT (LAST_DOW - FIRST_DOW + 1)
-
- /* each user's crontab will be held as a list of
- * the following structure.
- *
- * These are the cron commands.
- */
-
-typedef struct _entry
- {
- struct _entry *next;
- char *cmd;
- bitstr_t bit_decl(minute, MINUTE_COUNT);
- bitstr_t bit_decl(hour, HOUR_COUNT);
- bitstr_t bit_decl(dom, DOM_COUNT);
- bitstr_t bit_decl(month, MONTH_COUNT);
- bitstr_t bit_decl(dow, DOW_COUNT);
- int flags;
-# define DOM_STAR 0x1
-# define DOW_STAR 0x2
-# define WHEN_REBOOT 0x4
- }
- entry;
-
- /* the crontab database will be a list of the
- * following structure, one element per user.
- *
- * These are the crontabs.
- */
-
-typedef struct _user
- {
- struct _user *next, *prev; /* links */
- int uid; /* uid from passwd file */
- int gid; /* gid from passwd file */
- char **envp; /* environ for commands */
- time_t mtime; /* last modtime of crontab */
- entry *crontab; /* this person's crontab */
- }
- user;
-
-typedef struct _cron_db
- {
- user *head, *tail; /* links */
- time_t mtime; /* last modtime on spooldir */
- }
- cron_db;
-
- /* in the C tradition, we only create
- * variables for the main program, just
- * extern them elsewhere.
- */
-
-#ifdef MAIN_PROGRAM
-
-# if !defined(LINT) && !defined(lint)
- static char *copyright[] = {
- "@(#) Copyright (C) 1988, 1989, 1990 by Paul Vixie",
- "@(#) All rights reserved"
- };
-# endif
-
- char *MonthNames[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
- NULL};
- char *DowNames[] = {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
- NULL};
- char *ProgramName;
- int LineNumber;
- time_t TargetTime;
-
-# if DEBUGGING
- int DebugFlags;
- char *DebugFlagNames[] = { /* sync with #defines */
- "ext", "sch", "proc", "pars", "load", "misc", "test",
- NULL}; /* NULL must be last element */
-# endif /* DEBUGGING */
-
-#else /* !MAIN_PROGRAM */
-
- extern char *MonthNames[];
- extern char *DowNames[];
- extern char *ProgramName;
- extern int LineNumber;
- extern time_t TargetTime;
-# if DEBUGGING
- extern int DebugFlags;
- extern char *DebugFlagNames[];
-# endif /* DEBUGGING */
-#endif /* MAIN_PROGRAM */
-
-
-#endif /* _CRON_FLAG */
diff --git a/libexec/crond/crond.8 b/libexec/crond/crond.8
deleted file mode 100644
index 71a4d2eef872..000000000000
--- a/libexec/crond/crond.8
+++ /dev/null
@@ -1,56 +0,0 @@
-.\" $Header: /a/cvs/386BSD/src/libexec/crond/crond.8,v 1.1.1.1 1993/06/12 14:55:04 rgrimes Exp $
-.\"
-.\"/* Copyright 1988,1990 by Paul Vixie
-.\" * All rights reserved
-.\" *
-.\" * Distribute freely, except: don't remove my name from the source or
-.\" * documentation (don't take credit for my work), mark your changes (don't
-.\" * get me blamed for your possible bugs), don't alter or remove this
-.\" * notice. May be sold if buildable source is provided to buyer. No
-.\" * warrantee of any kind, express or implied, is included with this
-.\" * software; use at your own risk, responsibility for damages (if any) to
-.\" * anyone resulting from the use of this software rests entirely with the
-.\" * user.
-.\" *
-.\" * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
-.\" * I'll try to keep a version up to date. I can be reached as follows:
-.\" * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
-.\" * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
-.\" */
-.TH CROND 8 "15 Nov 1988"
-.UC 4
-.SH NAME
-crond \- daemon to execute scheduled commands (Vixie Cron)
-.SH SYNOPSIS
-crond
-.SH DESCRIPTION
-.I Crond
-should be started from /etc/rc or /etc/rc.local. It will return immediately,
-so you don't need to start it with '&'.
-.PP
-.I Crond
-searches /var/cron/tabs for crontab files which are named after accounts in
-/etc/passwd; crontabs found are loaded into memory.
-.I Crond
-then wakes up every minute, examining all stored crontabs, checking each
-command to see if it should be run in the current minute. When executing
-commands, any output is mailed to the owner of the crontab (or to the user
-named in the MAILTO environment variable in the crontab, if such exists).
-.PP
-Additionally,
-.I crond
-checks each minute to see if its spool directory's modtime has changed, and
-if it has,
-.I crond
-will then examine the modtime on all crontabs and reload those which have
-changed. Thus
-.I crond
-need not be restarted whenever a crontab file is modified. Note that the
-.IR Crontab (1)
-command updates the modtime of the spool directory whenever it changes a
-crontab.
-.SH "SEE ALSO"
-crontab(1), crontab(5)
-.SH AUTHOR
-.nf
-Paul Vixie, paul@vixie.sf.ca.us
diff --git a/libexec/crond/crond.c b/libexec/crond/crond.c
deleted file mode 100644
index aaeb9812a1a1..000000000000
--- a/libexec/crond/crond.c
+++ /dev/null
@@ -1,317 +0,0 @@
-#if !defined(lint) && !defined(LINT)
-static char rcsid[] = "$Header: /a/cvs/386BSD/src/libexec/crond/crond.c,v 1.1.1.1 1993/06/12 14:55:04 rgrimes Exp $";
-#endif
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- *
- * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
- * -------------------- ----- ----------------------
- * CURRENT PATCH LEVEL: 1 00131
- * -------------------- ----- ----------------------
- *
- * 06 Apr 93 Adam Glass Fixes so it compiles quitely
- *
- */
-
-
-#define MAIN_PROGRAM
-
-
-#include "cron.h"
-#include <sys/time.h>
-#include <sys/signal.h>
-#include <sys/types.h>
-#if defined(BSD)
-# include <sys/wait.h>
-# include <sys/resource.h>
-#endif /*BSD*/
-
-extern int fork(), unlink();
-extern time_t time();
-extern void exit();
-extern unsigned sleep();
-
-void
-usage()
-{
- (void) fprintf(stderr, "usage: %s [-x debugflag[,...]]\n", ProgramName);
- (void) exit(ERROR_EXIT);
-}
-
-
-int
-main(argc, argv)
- int argc;
- char *argv[];
-{
- extern void set_cron_uid(), be_different(), load_database(),
- set_cron_cwd(), open_logfile();
-
- static void cron_tick(), cron_sleep(), cron_sync(),
- sigchld_handler(), parse_args(), run_reboot_jobs();
-
- auto cron_db database;
-
- ProgramName = argv[0];
-
-#if defined(BSD)
- setlinebuf(stdout);
- setlinebuf(stderr);
-#endif
-
- parse_args(argc, argv);
-
-# if DEBUGGING
- /* if there are no debug flags turned on, fork as a daemon should.
- */
- if (DebugFlags)
- {
- (void) fprintf(stderr, "[%d] crond started\n", getpid());
- }
- else
-# endif /*DEBUGGING*/
- {
- switch (fork())
- {
- case -1:
- log_it("CROND",getpid(),"DEATH","can't fork");
- exit(0);
- break;
- case 0:
- /* child process */
- be_different();
- break;
- default:
- /* parent process should just die */
- _exit(0);
- }
- }
-
-#if defined(BSD)
- (void) signal(SIGCHLD, sigchld_handler);
-#endif /*BSD*/
-
-#if defined(ATT)
- (void) signal(SIGCLD, SIG_IGN);
-#endif /*ATT*/
-
- acquire_daemonlock();
- set_cron_uid();
- set_cron_cwd();
- database.head = NULL;
- database.tail = NULL;
- database.mtime = (time_t) 0;
- load_database(&database);
- run_reboot_jobs(&database);
- cron_sync();
- while (TRUE)
- {
-# if DEBUGGING
- if (!(DebugFlags & DTEST))
-# endif /*DEBUGGING*/
- cron_sleep();
-
- load_database(&database);
-
- /* do this iteration
- */
- cron_tick(&database);
-
- /* sleep 1 minute
- */
- TargetTime += 60;
- }
-}
-
-
-static void
-run_reboot_jobs(db)
- cron_db *db;
-{
- extern void job_add();
- extern int job_runqueue();
- register user *u;
- register entry *e;
-
- for (u = db->head; u != NULL; u = u->next) {
- for (e = u->crontab; e != NULL; e = e->next) {
- if (e->flags & WHEN_REBOOT) {
- job_add(e->cmd, u);
- }
- }
- }
- (void) job_runqueue();
-}
-
-
-static void
-cron_tick(db)
- cron_db *db;
-{
- extern void job_add();
- extern char *env_get();
- extern struct tm *localtime();
- register struct tm *tm = localtime(&TargetTime);
- local int minute, hour, dom, month, dow;
- register user *u;
- register entry *e;
-
- /* make 0-based values out of these so we can use them as indicies
- */
- minute = tm->tm_min -FIRST_MINUTE;
- hour = tm->tm_hour -FIRST_HOUR;
- dom = tm->tm_mday -FIRST_DOM;
- month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
- dow = tm->tm_wday -FIRST_DOW;
-
- Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
- getpid(), minute, hour, dom, month, dow))
-
- /* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
- * first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
- * on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
- * is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre.
- * like many bizarre things, it's the standard.
- */
- for (u = db->head; u != NULL; u = u->next) {
- Debug(DSCH|DEXT, ("user [%s:%d:%d:...]\n",
- env_get(USERENV,u->envp), u->uid, u->gid))
- for (e = u->crontab; e != NULL; e = e->next) {
- Debug(DSCH|DEXT, ("entry [%s]\n", e->cmd))
- if (bit_test(e->minute, minute)
- && bit_test(e->hour, hour)
- && bit_test(e->month, month)
- && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
- ? (bit_test(e->dow,dow) && bit_test(e->dom,dom))
- : (bit_test(e->dow,dow) || bit_test(e->dom,dom))
- )
- ) {
- job_add(e->cmd, u);
- }
- }
- }
-}
-
-
-/* the task here is to figure out how long it's going to be until :00 of the
- * following minute and initialize TargetTime to this value. TargetTime
- * will subsequently slide 60 seconds at a time, with correction applied
- * implicitly in cron_sleep(). it would be nice to let crond execute in
- * the "current minute" before going to sleep, but by restarting cron you
- * could then get it to execute a given minute's jobs more than once.
- * instead we have the chance of missing a minute's jobs completely, but
- * that's something sysadmin's know to expect what with crashing computers..
- */
-static void
-cron_sync()
-{
- extern struct tm *localtime();
- register struct tm *tm;
-
- TargetTime = time((time_t*)0);
- tm = localtime(&TargetTime);
- TargetTime += (60 - tm->tm_sec);
-}
-
-
-static void
-cron_sleep()
-{
- extern void do_command();
- extern int job_runqueue();
- register int seconds_to_wait;
-
- do {
- seconds_to_wait = (int) (TargetTime - time((time_t*)0));
- Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
- getpid(), TargetTime, seconds_to_wait))
-
- /* if we intend to sleep, this means that it's finally
- * time to empty the job queue (execute it).
- *
- * if we run any jobs, we'll probably screw up our timing,
- * so go recompute.
- *
- * note that we depend here on the left-to-right nature
- * of &&, and the short-circuiting.
- */
- } while (seconds_to_wait > 0 && job_runqueue());
-
- if (seconds_to_wait > 0)
- {
- Debug(DSCH, ("[%d] sleeping for %d seconds\n",
- getpid(), seconds_to_wait))
- (void) sleep((unsigned int) seconds_to_wait);
- }
-}
-
-
-#if defined(BSD)
-static void
-sigchld_handler()
-{
- union wait waiter;
- int pid;
-
- for (;;)
- {
- pid = wait3((int *) &waiter, WNOHANG, (struct rusage *)0);
- switch (pid)
- {
- case -1:
- Debug(DPROC,
- ("[%d] sigchld...no children\n", getpid()))
- return;
- case 0:
- Debug(DPROC,
- ("[%d] sigchld...no dead kids\n", getpid()))
- return;
- default:
- Debug(DPROC,
- ("[%d] sigchld...pid #%d died, stat=%d\n",
- getpid(), pid, waiter.w_status))
- }
- }
-}
-#endif /*BSD*/
-
-
-static void
-parse_args(argc, argv)
- int argc;
- char *argv[];
-{
- extern int optind, getopt();
- extern void usage();
- extern char *optarg;
-
- int argch;
-
- while (EOF != (argch = getopt(argc, argv, "x:")))
- {
- switch (argch)
- {
- default:
- usage();
- case 'x':
- if (!set_debug_flags(optarg))
- usage();
- break;
- }
- }
-}
diff --git a/libexec/crond/database.c b/libexec/crond/database.c
deleted file mode 100644
index 6fde09efa5a3..000000000000
--- a/libexec/crond/database.c
+++ /dev/null
@@ -1,273 +0,0 @@
-#if !defined(lint) && !defined(LINT)
-static char rcsid[] = "$Header: /a/cvs/386BSD/src/libexec/crond/database.c,v 1.1.1.1 1993/06/12 14:55:04 rgrimes Exp $";
-#endif
-
-/* vix 26jan87 [RCS has the log]
- */
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- */
-
-
-#include "cron.h"
-#include <pwd.h>
-#if defined(BSD)
-# include <sys/file.h>
-# include <sys/dir.h>
-#endif
-#if defined(ATT)
-# include <sys/file.h>
-# include <ndir.h>
-# include <fcntl.h>
-#endif
-
-
-extern void perror(), exit();
-
-
-void
-load_database(old_db)
- cron_db *old_db;
-{
- extern void link_user(), unlink_user(), free_user();
- extern user *load_user(), *find_user();
- extern char *env_get();
-
- static DIR *dir = NULL;
-
- struct stat statbuf;
- struct direct *dp;
- cron_db new_db;
- user *u;
-
- Debug(DLOAD, ("[%d] load_database()\n", getpid()))
-
- /* before we start loading any data, do a stat on SPOOL_DIR
- * so that if anything changes as of this moment (i.e., before we've
- * cached any of the database), we'll see the changes next time.
- */
- if (stat(SPOOL_DIR, &statbuf) < OK)
- {
- log_it("CROND", getpid(), "STAT FAILED", SPOOL_DIR);
- (void) exit(ERROR_EXIT);
- }
-
- /* if spooldir's mtime has not changed, we don't need to fiddle with
- * the database. Note that if /etc/passwd changes (like, someone's
- * UID/GID/HOME/SHELL, we won't see it. Maybe we should
- * keep an mtime for the passwd file? HINT
- *
- * Note that old_db->mtime is initialized to 0 in main(), and
- * so is guaranteed to be different than the stat() mtime the first
- * time this function is called.
- */
- if (old_db->mtime == statbuf.st_mtime)
- {
- Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n",
- getpid()))
- return;
- }
-
- /* make sure the dir is open. only happens the first time, since
- * the DIR is static and we don't close it. Rewind the dir.
- */
- if (dir == NULL)
- {
- if (!(dir = opendir(SPOOL_DIR)))
- {
- log_it("CROND", getpid(), "OPENDIR FAILED", SPOOL_DIR);
- (void) exit(ERROR_EXIT);
- }
- }
- (void) rewinddir(dir);
-
- /* something's different. make a new database, moving unchanged
- * elements from the old database, reloading elements that have
- * actually changed. Whatever is left in the old database when
- * we're done is chaff -- crontabs that disappeared.
- */
- new_db.mtime = statbuf.st_mtime;
- new_db.head = new_db.tail = NULL;
-
- while (NULL != (dp = readdir(dir)))
- {
- extern struct passwd *getpwnam();
- struct passwd *pw;
- int crontab_fd;
- char fname[MAXNAMLEN+1],
- tabname[MAXNAMLEN+1];
-
- (void) strncpy(fname, dp->d_name, (int) dp->d_namlen);
- fname[dp->d_namlen] = '\0';
-
- /* avoid file names beginning with ".". this is good
- * because we would otherwise waste two guaranteed calls
- * to getpwnam() for . and .., and also because user names
- * starting with a period are just too nasty to consider.
- */
- if (fname[0] == '.')
- goto next_crontab;
-
- if (NULL == (pw = getpwnam(fname)))
- {
- /* file doesn't have a user in passwd file.
- */
- log_it(fname, getpid(), "ORPHAN", "no passwd entry");
- goto next_crontab;
- }
-
- sprintf(tabname, CRON_TAB(fname));
- if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK)
- {
- /* crontab not accessible?
- */
- log_it(fname, getpid(), "CAN'T OPEN", tabname);
- goto next_crontab;
- }
-
- if (fstat(crontab_fd, &statbuf) < OK)
- {
- log_it(fname, getpid(), "FSTAT FAILED", tabname);
- goto next_crontab;
- }
-
- Debug(DLOAD, ("\t%s:", fname))
- u = find_user(old_db, fname);
- if (u != NULL)
- {
- /* if crontab has not changed since we last read it
- * in, then we can just use our existing entry.
- * note that we do not check for changes in the
- * passwd entry (uid, home dir, etc). HINT
- */
- if (u->mtime == statbuf.st_mtime)
- {
- Debug(DLOAD, (" [no change, using old data]"))
- unlink_user(old_db, u);
- link_user(&new_db, u);
- goto next_crontab;
- }
-
- /* before we fall through to the code that will reload
- * the user, let's deallocate and unlink the user in
- * the old database. This is more a point of memory
- * efficiency than anything else, since all leftover
- * users will be deleted from the old database when
- * we finish with the crontab...
- */
- Debug(DLOAD, (" [delete old data]"))
- unlink_user(old_db, u);
- free_user(u);
- }
- u = load_user(
- crontab_fd,
- pw->pw_name,
- pw->pw_uid,
- pw->pw_gid,
- pw->pw_dir,
- pw->pw_shell
- );
- if (u != NULL)
- {
- u->mtime = statbuf.st_mtime;
- link_user(&new_db, u);
- }
-next_crontab:
- if (crontab_fd >= OK) {
- Debug(DLOAD, (" [done]\n"))
- close(crontab_fd);
- }
- }
- /* if we don't do this, then when our children eventually call
- * getpwnam() in do_command.c's child_process to verify MAILTO=,
- * they will screw us up (and v-v).
- *
- * (this was lots of fun to find...)
- */
- endpwent();
-
- /* whatever's left in the old database is now junk.
- */
- Debug(DLOAD, ("unlinking old database:\n"))
- for (u = old_db->head; u != NULL; u = u->next)
- {
- Debug(DLOAD, ("\t%s\n", env_get(USERENV, u->envp)))
- unlink_user(old_db, u);
- free_user(u);
- }
-
- /* overwrite the database control block with the new one.
- */
- Debug(DLOAD, ("installing new database\n"))
-#if defined(BSD)
- /* BSD has structure assignments */
- *old_db = new_db;
-#endif
-#if defined(ATT)
- /* ATT, well, I don't know. Use memcpy(). */
- memcpy(old_db, &new_db, sizeof(cron_db));
-#endif
- Debug(DLOAD, ("load_database is done\n"))
-}
-
-
-void
-link_user(db, u)
- cron_db *db;
- user *u;
-{
- if (db->head == NULL)
- db->head = u;
- if (db->tail)
- db->tail->next = u;
- u->prev = db->tail;
- u->next = NULL;
- db->tail = u;
-}
-
-
-void
-unlink_user(db, u)
- cron_db *db;
- user *u;
-{
- if (u->prev == NULL)
- db->head = u->next;
- else
- u->prev->next = u->next;
-
- if (u->next == NULL)
- db->tail = u->prev;
- else
- u->next->prev = u->prev;
-}
-
-
-user *
-find_user(db, name)
- cron_db *db;
- char *name;
-{
- char *env_get();
- user *u;
-
- for (u = db->head; u != NULL; u = u->next)
- if (!strcmp(env_get(USERENV, u->envp), name))
- break;
- return u;
-}
diff --git a/libexec/crond/do_command.c b/libexec/crond/do_command.c
deleted file mode 100644
index 4dd28909da10..000000000000
--- a/libexec/crond/do_command.c
+++ /dev/null
@@ -1,583 +0,0 @@
-#if !defined(lint) && !defined(LINT)
-static char rcsid[] = "$Header: /a/cvs/386BSD/src/libexec/crond/do_command.c,v 1.1.1.1 1993/06/12 14:55:03 rgrimes Exp $";
-#endif
-
-/* $Source: /a/cvs/386BSD/src/libexec/crond/do_command.c,v $
- * $Revision: 1.1.1.1 $
- * $Log: do_command.c,v $
- * Revision 1.1.1.1 1993/06/12 14:55:03 rgrimes
- * Initial import, 0.1 + pk 0.2.4-B1
- *
- * Revision 2.1 90/07/18 00:23:38 vixie
- * Baseline for 4.4BSD release
- *
- * Revision 2.0 88/12/10 04:57:44 vixie
- * V2 Beta
- *
- * Revision 1.5 88/11/29 13:06:06 vixie
- * seems to work on Ultrix 3.0 FT1
- *
- * Revision 1.4 87/05/02 17:33:35 paul
- * baseline for mod.sources release
- *
- * Revision 1.3 87/04/09 00:03:58 paul
- * improved data hiding, locality of declaration/references
- * fixed a rs@mirror bug by redesigning the mailto stuff completely
- *
- * Revision 1.2 87/03/19 12:46:24 paul
- * implemented suggestions from rs@mirror (Rich $alz):
- * MAILTO="" means no mail should be sent
- * various fixes of bugs or lint complaints
- * put a To: line in the mail message
- *
- * Revision 1.1 87/01/26 23:47:00 paul
- * Initial revision
- *
- * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
- * -------------------- ----- ----------------------
- * CURRENT PATCH LEVEL: 1 00131
- * -------------------- ----- ----------------------
- *
- * 06 Apr 93 Adam Glass Fixes so it compiles quitely
- *
- */
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- */
-
-
-#include "cron.h"
-#include <signal.h>
-#include <pwd.h>
-#if defined(BSD)
-# include <sys/wait.h>
-#endif /*BSD*/
-#if defined(sequent)
-# include <strings.h>
-# include <sys/universe.h>
-#endif
-
-
-void
-do_command(cmd, u)
- char *cmd;
- user *u;
-{
- extern int fork(), _exit();
- extern void child_process(), log_it();
- extern char *env_get();
-
- Debug(DPROC, ("[%d] do_command(%s, (%s,%d,%d))\n",
- getpid(), cmd, env_get(USERENV, u->envp), u->uid, u->gid))
-
- /* fork to become asynchronous -- parent process is done immediately,
- * and continues to run the normal cron code, which means return to
- * tick(). the child and grandchild don't leave this function, alive.
- *
- * vfork() is unsuitable, since we have much to do, and the parent
- * needs to be able to run off and fork other processes.
- */
- switch (fork())
- {
- case -1:
- log_it("CROND",getpid(),"error","can't fork");
- break;
- case 0:
- /* child process */
- child_process(cmd, u);
- Debug(DPROC, ("[%d] child process done, exiting\n", getpid()))
- _exit(OK_EXIT);
- break;
- }
- Debug(DPROC, ("[%d] main process returning to work\n", getpid()))
-}
-
-
-void
-child_process(cmd, u)
- char *cmd;
- user *u;
-{
- extern struct passwd *getpwnam();
- extern void sigpipe_func(), be_different(), log_it();
- extern int VFORK();
- extern char *index(), *env_get();
-
- auto int stdin_pipe[2], stdout_pipe[2];
- register char *input_data, *usernm, *mailto;
- auto int children = 0;
-#if defined(sequent)
- extern void do_univ();
-#endif
-
- Debug(DPROC, ("[%d] child_process('%s')\n", getpid(), cmd))
-
- /* mark ourselves as different to PS command watchers by upshifting
- * our program name. This has no effect on some kernels.
- */
- {
- register char *pch;
-
- for (pch = ProgramName; *pch; pch++)
- *pch = MkUpper(*pch);
- }
-
- /* discover some useful and important environment settings
- */
- usernm = env_get(USERENV, u->envp);
- mailto = env_get("MAILTO", u->envp);
-
-#if defined(BSD)
- /* our parent is watching for our death by catching SIGCHLD. we
- * do not care to watch for our children's deaths this way -- we
- * use wait() explictly. so we have to disable the signal (which
- * was inherited from the parent).
- *
- * this isn't needed for system V, since our parent is already
- * SIG_IGN on SIGCLD -- which, hopefully, will cause children to
- * simply vanish when they die.
- */
- (void) signal(SIGCHLD, SIG_IGN);
-#endif /*BSD*/
-
- /* create some pipes to talk to our future child
- */
- pipe(stdin_pipe); /* child's stdin */
- pipe(stdout_pipe); /* child's stdout */
-
- /* since we are a forked process, we can diddle the command string
- * we were passed -- nobody else is going to use it again, right?
- *
- * if a % is present in the command, previous characters are the
- * command, and subsequent characters are the additional input to
- * the command. Subsequent %'s will be transformed into newlines,
- * but that happens later.
- */
- if (NULL == (input_data = index(cmd, '%')))
- {
- /* no %. point input_data at a null string.
- */
- input_data = "";
- }
- else
- {
- /* % found. replace with a null (remember, we're a forked
- * process and the string won't be reused), and increment
- * input_data to point at the following character.
- */
- *input_data++ = '\0';
- }
-
- /* fork again, this time so we can exec the user's command. Vfork()
- * is okay this time, since we are going to exec() pretty quickly.
- * I'm assuming that closing pipe ends &whatnot will not affect our
- * suspended pseudo-parent/alter-ego.
- */
- if (VFORK() == 0)
- {
- Debug(DPROC, ("[%d] grandchild process VFORK()'ed\n", getpid()))
-
- /* write a log message. we've waited this long to do it
- * because it was not until now that we knew the PID that
- * the actual user command shell was going to get and the
- * PID is part of the log message.
- */
-#ifdef LOG_FILE
- {
- extern char *mkprints();
- char *x = mkprints(cmd, strlen(cmd));
-
- log_it(usernm, getpid(), "CMD", x);
- free(x);
- }
-#endif
-
- /* get new pgrp, void tty, etc.
- */
- be_different();
-
- /* close the pipe ends that we won't use. this doesn't affect
- * the parent, who has to read and write them; it keeps the
- * kernel from recording us as a potential client TWICE --
- * which would keep it from sending SIGPIPE in otherwise
- * appropriate circumstances.
- */
- close(stdin_pipe[WRITE_PIPE]);
- close(stdout_pipe[READ_PIPE]);
-
- /* grandchild process. make std{in,out} be the ends of
- * pipes opened by our daddy; make stderr go to stdout.
- */
- close(STDIN); dup2(stdin_pipe[READ_PIPE], STDIN);
- close(STDOUT); dup2(stdout_pipe[WRITE_PIPE], STDOUT);
- close(STDERR); dup2(STDOUT, STDERR);
-
- /* close the pipes we just dup'ed. The resources will remain,
- * since they've been dup'ed... :-)...
- */
- close(stdin_pipe[READ_PIPE]);
- close(stdout_pipe[WRITE_PIPE]);
-
-# if defined(sequent)
- /* set our login universe. Do this in the grandchild
- * so that the child can invoke /usr/lib/sendmail
- * without surprises.
- */
- do_univ(u);
-# endif
-
- /* set our directory, uid and gid. Set gid first, since once
- * we set uid, we've lost root privledges. (oops!)
- */
- setgid(u->gid);
-# if defined(BSD)
- initgroups(env_get(USERENV, u->envp), u->gid);
-# endif
- setuid(u->uid); /* you aren't root after this... */
- chdir(env_get("HOME", u->envp));
-
- /* exec the command.
- */
- {
- char *shell = env_get("SHELL", u->envp);
-
-# if DEBUGGING
- if (DebugFlags & DTEST) {
- fprintf(stderr,
- "debug DTEST is on, not exec'ing command.\n");
- fprintf(stderr,
- "\tcmd='%s' shell='%s'\n", cmd, shell);
- _exit(OK_EXIT);
- }
-# endif /*DEBUGGING*/
- /* normally you can't put debugging stuff here because
- * it gets mailed with the command output.
- */
- /*
- Debug(DPROC, ("[%d] execle('%s', '%s', -c, '%s')\n",
- getpid(), shell, shell, cmd))
- */
-
-# ifdef bad_idea
- /* files writable by non-owner are a no-no
- */
- {
- struct stat sb;
-
- if (0 != stat(cmd, &sb)) {
- fputs("crond: stat(2): ", stderr);
- perror(cmd);
- _exit(ERROR_EXIT);
- } else if (sb.st_mode & 022) {
- fprintf(stderr,
- "crond: %s writable by nonowner\n",
- cmd);
- _exit(ERROR_EXIT);
- } else if (sb.st_uid & 022) {
- fprintf(stderr,
- "crond: %s owned by uid %d\n",
- cmd, sb.st_uid);
- _exit(ERROR_EXIT);
- }
- }
-# endif /*bad_idea*/
-
- execle(shell, shell, "-c", cmd, (char *)0, u->envp);
- fprintf(stderr, "execl: couldn't exec `%s'\n", shell);
- perror("execl");
- _exit(ERROR_EXIT);
- }
- }
-
- children++;
-
- /* middle process, child of original cron, parent of process running
- * the user's command.
- */
-
- Debug(DPROC, ("[%d] child continues, closing pipes\n", getpid()))
-
- /* close the ends of the pipe that will only be referenced in the
- * grandchild process...
- */
- close(stdin_pipe[READ_PIPE]);
- close(stdout_pipe[WRITE_PIPE]);
-
- /*
- * write, to the pipe connected to child's stdin, any input specified
- * after a % in the crontab entry. while we copy, convert any
- * additional %'s to newlines. when done, if some characters were
- * written and the last one wasn't a newline, write a newline.
- *
- * Note that if the input data won't fit into one pipe buffer (2K
- * or 4K on most BSD systems), and the child doesn't read its stdin,
- * we would block here. the solution, of course, is to fork again.
- */
-
- if (*input_data && fork() == 0) {
- register FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w");
- register int need_newline = FALSE;
- register int escaped = FALSE;
- register int ch;
-
- Debug(DPROC, ("[%d] child2 sending data to grandchild\n", getpid()))
-
- /* close the pipe we don't use, since we inherited it and
- * are part of its reference count now.
- */
- close(stdout_pipe[READ_PIPE]);
-
- /* translation:
- * \% -> %
- * % -> \n
- * \x -> \x for all x != %
- */
- while (ch = *input_data++)
- {
- if (escaped) {
- if (ch != '%')
- putc('\\', out);
- } else {
- if (ch == '%')
- ch = '\n';
- }
-
- if (!(escaped = (ch == '\\'))) {
- putc(ch, out);
- need_newline = (ch != '\n');
- }
- }
- if (escaped)
- putc('\\', out);
- if (need_newline)
- putc('\n', out);
-
- /* close the pipe, causing an EOF condition. fclose causes
- * stdin_pipe[WRITE_PIPE] to be closed, too.
- */
- fclose(out);
-
- Debug(DPROC, ("[%d] child2 done sending to grandchild\n", getpid()))
- exit(0);
- }
-
- /* close the pipe to the grandkiddie's stdin, since its wicked uncle
- * ernie back there has it open and will close it when he's done.
- */
- close(stdin_pipe[WRITE_PIPE]);
-
- children++;
-
- /*
- * read output from the grandchild. it's stderr has been redirected to
- * it's stdout, which has been redirected to our pipe. if there is any
- * output, we'll be mailing it to the user whose crontab this is...
- * when the grandchild exits, we'll get EOF.
- */
-
- Debug(DPROC, ("[%d] child reading output from grandchild\n", getpid()))
-
- {
- register FILE *in = fdopen(stdout_pipe[READ_PIPE], "r");
- register int ch = getc(in);
-
- if (ch != EOF)
- {
- register FILE *mail;
- register int bytes = 1;
- union wait status;
-
- Debug(DPROC|DEXT,
- ("[%d] got data (%x:%c) from grandchild\n",
- getpid(), ch, ch))
-
- /* get name of recipient. this is MAILTO if set to a
- * valid local username; USER otherwise.
- */
- if (mailto)
- {
- /* MAILTO was present in the environment
- */
- if (!*mailto)
- {
- /* ... but it's empty. set to NULL
- */
- mailto = NULL;
- }
- }
- else
- {
- /* MAILTO not present, set to USER.
- */
- mailto = usernm;
- }
-
- /* if we are supposed to be mailing, MAILTO will
- * be non-NULL. only in this case should we set
- * up the mail command and subjects and stuff...
- */
-
- if (mailto)
- {
- extern FILE *popen();
- extern char *print_cmd();
- register char **env;
- auto char mailcmd[MAX_COMMAND];
- auto char hostname[MAXHOSTNAMELEN];
-
- (void) gethostname(hostname, MAXHOSTNAMELEN);
- (void) sprintf(mailcmd, MAILCMD, mailto);
- if (!(mail = popen(mailcmd, "w")))
- {
- perror(MAILCMD);
- (void) _exit(ERROR_EXIT);
- }
- fprintf(mail, "From: root (Cron Daemon)\n");
- fprintf(mail, "To: %s\n", mailto);
- fprintf(mail,
- "Subject: cron for %s@%s said this\n",
- usernm, first_word(hostname, ".")
- );
- fprintf(mail, "Date: %s", ctime(&TargetTime));
- fprintf(mail, "X-Cron-Cmd: <%s>\n", cmd);
- for (env = u->envp; *env; env++)
- fprintf(mail, "X-Cron-Env: <%s>\n",
- *env);
- fprintf(mail, "\n");
-
- /* this was the first char from the pipe
- */
- putc(ch, mail);
- }
-
- /* we have to read the input pipe no matter whether
- * we mail or not, but obviously we only write to
- * mail pipe if we ARE mailing.
- */
-
- while (EOF != (ch = getc(in)))
- {
- bytes++;
- if (mailto)
- putc(ch, mail);
- }
-
- /* only close pipe if we opened it -- i.e., we're
- * mailing...
- */
-
- if (mailto) {
- Debug(DPROC, ("[%d] closing pipe to mail\n",
- getpid()))
- /* Note: the pclose will probably see
- * the termination of the grandchild
- * in addition to the mail process, since
- * it (the grandchild) is likely to exit
- * after closing its stdout.
- */
- status.w_status = pclose(mail);
- }
-
- /* if there was output and we could not mail it,
- * log the facts so the poor user can figure out
- * what's going on.
- */
- if (mailto && status.w_status) {
- char buf[MAX_TEMPSTR];
-
- sprintf(buf,
- "mailed %d byte%s of output but got status 0x%04x\n",
- bytes, (bytes==1)?"":"s",
- status.w_status);
- log_it(usernm, getpid(), "MAIL", buf);
- }
-
- } /*if data from grandchild*/
-
- Debug(DPROC, ("[%d] got EOF from grandchild\n", getpid()))
-
- fclose(in); /* also closes stdout_pipe[READ_PIPE] */
- }
-
-#if defined(BSD)
- /* wait for children to die.
- */
- for (; children > 0; children--)
- {
- int pid;
- union wait waiter;
-
- Debug(DPROC, ("[%d] waiting for grandchild #%d to finish\n",
- getpid(), children))
- pid = wait((int *) &waiter);
- if (pid < OK) {
- Debug(DPROC, ("[%d] no more grandchildren--mail written?\n",
- getpid()))
- break;
- }
- Debug(DPROC, ("[%d] grandchild #%d finished, status=%04x",
- getpid(), pid, waiter.w_status))
- if (waiter.w_coredump)
- Debug(DPROC, (", dumped core"))
- Debug(DPROC, ("\n"))
- }
-#endif /*BSD*/
-}
-
-
-#if defined(sequent)
-/* Dynix (Sequent) hack to put the user associated with
- * the passed user structure into the ATT universe if
- * necessary. We have to dig the gecos info out of
- * the user's password entry to see if the magic
- * "universe(att)" string is present. If we do change
- * the universe, also set "LOGNAME".
- */
-
-void
-do_univ(u)
- user *u;
-{
- struct passwd *p;
- char *s;
- int i;
- char envstr[MAX_ENVSTR], **env_set();
-
- p = getpwuid(u->uid);
- (void) endpwent();
-
- if (p == NULL)
- return;
-
- s = p->pw_gecos;
-
- for (i = 0; i < 4; i++)
- {
- if ((s = index(s, ',')) == NULL)
- return;
- s++;
- }
- if (strcmp(s, "universe(att)"))
- return;
-
- (void) sprintf(envstr, "LOGNAME=%s", p->pw_name);
- u->envp = env_set(u->envp, envstr);
-
- (void) universe(U_ATT);
-}
-#endif
diff --git a/libexec/crond/entry.c b/libexec/crond/entry.c
deleted file mode 100644
index a20ddf8f5825..000000000000
--- a/libexec/crond/entry.c
+++ /dev/null
@@ -1,486 +0,0 @@
-#if !defined(lint) && !defined(LINT)
-static char rcsid[] = "$Header: /a/cvs/386BSD/src/libexec/crond/entry.c,v 1.1.1.1 1993/06/12 14:55:03 rgrimes Exp $";
-#endif
-
-/* vix 26jan87 [RCS'd; rest of log is in RCS file]
- * vix 01jan87 [added line-level error recovery]
- * vix 31dec86 [added /step to the from-to range, per bob@acornrc]
- * vix 30dec86 [written]
- */
-
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- */
-
-
-#include "cron.h"
-
-typedef enum
- {e_none, e_minute, e_hour, e_dom, e_month, e_dow, e_cmd, e_timespec}
- ecode_e;
-static char *ecodes[] =
- {
- "no error",
- "bad minute",
- "bad hour",
- "bad day-of-month",
- "bad month",
- "bad day-of-week",
- "bad command",
- "bad time specifier"
- };
-
-void
-free_entry(e)
- entry *e;
-{
- int free();
-
- (void) free(e->cmd);
- (void) free(e);
-}
-
-
-entry *
-load_entry(file, error_func)
- FILE *file;
- void (*error_func)();
-{
- /* this function reads one crontab entry -- the next -- from a file.
- * it skips any leading blank lines, ignores comments, and returns
- * EOF if for any reason the entry can't be read and parsed.
- *
- * the entry IS parsed here, btw.
- *
- * syntax:
- * minutes hours doms months dows cmd\n
- */
-
- extern int free();
- extern char *malloc(), *savestr();
- extern void unget_char();
- static char get_list();
-
- ecode_e ecode = e_none;
- entry *e;
- int ch;
- void skip_comments();
- char cmd[MAX_COMMAND];
-
- e = (entry *) calloc(sizeof(entry), sizeof(char));
-
- Debug(DPARS, ("load_entry()...about to eat comments\n"))
-
- skip_comments(file);
-
- ch = get_char(file);
-
- /* ch is now the first useful character of a useful line.
- * it may be an @special or it may be the first character
- * of a list of minutes.
- */
-
- if (ch == '@')
- {
- /* all of these should be flagged and load-limited; i.e.,
- * instead of @hourly meaning "0 * * * *" it should mean
- * "close to the front of every hour but not 'til the
- * system load is low". Problems are: how do you know
- * what "low" means? (save me from /etc/crond.conf!) and:
- * how to guarantee low variance (how low is low?), which
- * means how to we run roughly every hour -- seems like
- * we need to keep a history or let the first hour set
- * the schedule, which means we aren't load-limited
- * anymore. too much for my overloaded brain. (vix, jan90)
- * HINT
- */
- ch = get_string(cmd, MAX_COMMAND, file, " \t\n");
- if (!strcmp("reboot", cmd)) {
- e->flags |= WHEN_REBOOT;
- } else if (!strcmp("yearly", cmd) || !strcmp("annually", cmd)){
- bit_set(e->minute, 0);
- bit_set(e->hour, 0);
- bit_set(e->dom, 0);
- bit_set(e->month, 0);
- bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
- } else if (!strcmp("monthly", cmd)) {
- bit_set(e->minute, 0);
- bit_set(e->hour, 0);
- bit_set(e->dom, 0);
- bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
- bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
- } else if (!strcmp("weekly", cmd)) {
- bit_set(e->minute, 0);
- bit_set(e->hour, 0);
- bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
- bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
- bit_set(e->dow, 0);
- } else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) {
- bit_set(e->minute, 0);
- bit_set(e->hour, 0);
- bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
- bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
- bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
- } else if (!strcmp("hourly", cmd)) {
- bit_set(e->minute, 0);
- bit_set(e->hour, (LAST_HOUR-FIRST_HOUR+1));
- bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
- bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
- bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
- } else {
- ecode = e_timespec;
- goto eof;
- }
- }
- else
- {
- Debug(DPARS, ("load_entry()...about to parse numerics\n"))
-
- ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE,
- PPC_NULL, ch, file);
- if (ch == EOF)
- {
- ecode = e_minute;
- goto eof;
- }
-
- /* hours
- */
-
- ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR,
- PPC_NULL, ch, file);
- if (ch == EOF)
- {
- ecode = e_hour;
- goto eof;
- }
-
- /* DOM (days of month)
- */
-
- if (ch == '*') e->flags |= DOM_STAR;
- ch = get_list(e->dom, FIRST_DOM, LAST_DOM, PPC_NULL, ch, file);
- if (ch == EOF)
- {
- ecode = e_dom;
- goto eof;
- }
-
- /* month
- */
-
- ch = get_list(e->month, FIRST_MONTH, LAST_MONTH,
- MonthNames, ch, file);
- if (ch == EOF)
- {
- ecode = e_month;
- goto eof;
- }
-
- /* DOW (days of week)
- */
-
- if (ch == '*') e->flags |= DOW_STAR;
- ch = get_list(e->dow, FIRST_DOW, LAST_DOW,
- DowNames, ch, file);
- if (ch == EOF)
- {
- ecode = e_dow;
- goto eof;
- }
- }
-
- /* make sundays equivilent */
- if (bit_test(e->dow, 0) || bit_test(e->dow, 7))
- {
- bit_set(e->dow, 0);
- bit_set(e->dow, 7);
- }
-
- Debug(DPARS, ("load_entry()...about to parse command\n"))
-
- /* ch is first character of a command. everything up to the next
- * \n or EOF is part of the command... too bad we don't know in
- * advance how long it will be, since we need to malloc a string
- * for it... so, we limit it to MAX_COMMAND
- */
- unget_char(ch, file);
- ch = get_string(cmd, MAX_COMMAND, file, "\n");
-
- /* a file without a \n before the EOF is rude, so we'll complain...
- */
- if (ch == EOF)
- {
- ecode = e_cmd;
- goto eof;
- }
-
- /* got the command in the 'cmd' string; save it in *e.
- */
- e->cmd = savestr(cmd);
-
- Debug(DPARS, ("load_entry()...returning successfully\n"))
-
- /* success, fini, return pointer to the entry we just created...
- */
- return e;
-
-eof: /* if we want to return EOF, we have to jump down here and
- * free the entry we've been building.
- *
- * now, in some cases, a parse routine will have returned EOF to
- * indicate an error, but the file is not actually done. since, in
- * that case, we only want to skip the line with the error on it,
- * we'll do that here.
- *
- * many, including the author, see what's below as evil programming
- * practice: since I didn't want to change the structure of this
- * whole function to support this error recovery, I recurse. Cursed!
- * (At least it's tail-recursion, as if it matters in C - vix/8feb88)
- * I'm seriously considering using (another) GOTO... argh!
- * (this does not get less disgusting over time. vix/15nov88)
- */
-
- (void) free(e);
-
- if (feof(file))
- return NULL;
-
- if (error_func)
- (*error_func)(ecodes[(int)ecode]);
- do {ch = get_char(file);}
- while (ch != EOF && ch != '\n');
- if (ch == EOF)
- return NULL;
- return load_entry(file, error_func);
-}
-
-
-static char
-get_list(bits, low, high, names, ch, file)
- bitstr_t *bits; /* one bit per flag, default=FALSE */
- int low, high; /* bounds, impl. offset for bitstr */
- char *names[]; /* NULL or *[] of names for these elements */
- int ch; /* current character being processed */
- FILE *file; /* file being read */
-{
- static char get_range();
- register int done;
-
- /* we know that we point to a non-blank character here;
- * must do a Skip_Blanks before we exit, so that the
- * next call (or the code that picks up the cmd) can
- * assume the same thing.
- */
-
- Debug(DPARS|DEXT, ("get_list()...entered\n"))
-
- /* list = "*" | range {"," range}
- */
-
- if (ch == '*')
- {
- /* '*' means 'all elements'.
- */
- bit_nset(bits, 0, (high-low+1));
- goto exit;
- }
-
- /* clear the bit string, since the default is 'off'.
- */
- bit_nclear(bits, 0, (high-low+1));
-
- /* process all ranges
- */
- done = FALSE;
- while (!done)
- {
- ch = get_range(bits, low, high, names, ch, file);
- if (ch == ',')
- ch = get_char(file);
- else
- done = TRUE;
- }
-
-exit: /* exiting. skip to some blanks, then skip over the blanks.
- */
- Skip_Nonblanks(ch, file)
- Skip_Blanks(ch, file)
-
- Debug(DPARS|DEXT, ("get_list()...exiting w/ %02x\n", ch))
-
- return ch;
-}
-
-
-static char
-get_range(bits, low, high, names, ch, file)
- bitstr_t *bits; /* one bit per flag, default=FALSE */
- int low, high; /* bounds, impl. offset for bitstr */
- char *names[]; /* NULL or names of elements */
- int ch; /* current character being processed */
- FILE *file; /* file being read */
-{
- /* range = number | number "-" number [ "/" number ]
- */
-
- static int set_element();
- static char get_number();
- register int i;
- auto int num1, num2, num3;
-
- Debug(DPARS|DEXT, ("get_range()...entering, exit won't show\n"))
-
- if (EOF == (ch = get_number(&num1, low, names, ch, file)))
- return EOF;
-
- if (ch != '-')
- {
- /* not a range, it's a single number.
- */
- if (EOF == set_element(bits, low, high, num1))
- return EOF;
- }
- else
- {
- /* eat the dash
- */
- ch = get_char(file);
- if (ch == EOF)
- return EOF;
-
- /* get the number following the dash
- */
- ch = get_number(&num2, low, names, ch, file);
- if (ch == EOF)
- return EOF;
-
- /* check for step size
- */
- if (ch == '/')
- {
- /* eat the slash
- */
- ch = get_char(file);
- if (ch == EOF)
- return EOF;
-
- /* get the step size -- note: we don't pass the
- * names here, because the number is not an
- * element id, it's a step size. 'low' is
- * sent as a 0 since there is no offset either.
- */
- ch = get_number(&num3, 0, PPC_NULL, ch, file);
- if (ch == EOF)
- return EOF;
- }
- else
- {
- /* no step. default==1.
- */
- num3 = 1;
- }
-
- /* range. set all elements from num1 to num2, stepping
- * by num3. (the step is a downward-compatible extension
- * proposed conceptually by bob@acornrc, syntactically
- * designed then implmented by paul vixie).
- */
- for (i = num1; i <= num2; i += num3)
- if (EOF == set_element(bits, low, high, i))
- return EOF;
- }
- return ch;
-}
-
-
-static char
-get_number(numptr, low, names, ch, file)
- int *numptr;
- int low;
- char *names[];
- char ch;
- FILE *file;
-{
- char temp[MAX_TEMPSTR], *pc;
- int len, i, all_digits;
-
- /* collect alphanumerics into our fixed-size temp array
- */
- pc = temp;
- len = 0;
- all_digits = TRUE;
- while (isalnum(ch))
- {
- if (++len >= MAX_TEMPSTR)
- return EOF;
-
- *pc++ = ch;
-
- if (!isdigit(ch))
- all_digits = FALSE;
-
- ch = get_char(file);
- }
- *pc = '\0';
-
- /* try to find the name in the name list
- */
- if (names)
- for (i = 0; names[i] != NULL; i++)
- {
- Debug(DPARS|DEXT,
- ("get_num, compare(%s,%s)\n", names[i], temp))
- if (!nocase_strcmp(names[i], temp))
- {
- *numptr = i+low;
- return ch;
- }
- }
-
- /* no name list specified, or there is one and our string isn't
- * in it. either way: if it's all digits, use its magnitude.
- * otherwise, it's an error.
- */
- if (all_digits)
- {
- *numptr = atoi(temp);
- return ch;
- }
-
- return EOF;
-}
-
-
-static int
-set_element(bits, low, high, number)
- bitstr_t *bits; /* one bit per flag, default=FALSE */
- int low;
- int high;
- int number;
-{
- Debug(DPARS|DEXT, ("set_element(?,%d,%d,%d)\n", low, high, number))
-
- if (number < low || number > high)
- return EOF;
-
- Debug(DPARS|DEXT, ("bit_set(%x,%d)\n",bits,(number-low)))
- bit_set(bits, (number-low));
- Debug(DPARS|DEXT, ("bit_set succeeded\n"))
- return OK;
-}
diff --git a/libexec/crond/env.c b/libexec/crond/env.c
deleted file mode 100644
index 1750b99a49a1..000000000000
--- a/libexec/crond/env.c
+++ /dev/null
@@ -1,162 +0,0 @@
-#if !defined(lint) && !defined(LINT)
-static char rcsid[] = "$Header: /a/cvs/386BSD/src/libexec/crond/env.c,v 1.1.1.1 1993/06/12 14:55:03 rgrimes Exp $";
-#endif
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- *
- * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
- * -------------------- ----- ----------------------
- * CURRENT PATCH LEVEL: 1 00131
- * -------------------- ----- ----------------------
- *
- * 06 Apr 93 Adam Glass Fixes so it compiles quitely
- *
- */
-
-
-#include "cron.h"
-
-
-char **
-env_init()
-{
- extern char *malloc();
- register char **p = (char **) malloc(sizeof(char **));
-
- p[0] = NULL;
- return p;
-}
-
-
-char **
-env_set(envp, envstr)
- char **envp;
- char *envstr;
-{
- extern char *realloc(), *savestr();
- register int count, found;
- register char **p;
-
- /*
- * count the number of elements, including the null pointer;
- * also set 'found' to -1 or index of entry if already in here.
- */
- found = -1;
- for (count = 0; envp[count] != NULL; count++)
- {
- if (!strcmp_until(envp[count], envstr, '='))
- found = count;
- }
- count++; /* for the null pointer
- */
-
- if (found != -1)
- {
- /*
- * it exists already, so just free the existing setting,
- * save our new one there, and return the existing array.
- */
- free(envp[found]);
- envp[found] = savestr(envstr);
- return envp;
- }
-
- /*
- * it doesn't exist yet, so resize the array, move null pointer over
- * one, save our string over the old null pointer, and return resized
- * array.
- */
- p = (char **) realloc(
- (char *) envp,
- (unsigned) ((count+1) * sizeof(char **))
- );
- p[count] = p[count-1];
- p[count-1] = savestr(envstr);
- return p;
-}
-
-
-int
-load_env(envstr, f)
- char *envstr;
- FILE *f;
-{
- /* return ERR = end of file
- * FALSE = not an env setting (file was repositioned)
- * TRUE = was an env setting
- */
- long filepos;
- int fileline;
- char name[MAX_TEMPSTR], val[MAX_ENVSTR];
- int fields, strdtb();
- void skip_comments();
-
- filepos = ftell(f);
- fileline = LineNumber;
- skip_comments(f);
- if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
- return ERR;
-
- Debug(DPARS, ("load_env, read <%s>\n", envstr))
-
- name[0] = val[0] = '\0';
- fields = sscanf(envstr, "%[^ =] = %[^\n#]", name, val);
- if (fields != 2)
- {
- Debug(DPARS, ("load_env, not 2 fields (%d)\n", fields))
- fseek(f, filepos, 0);
- Set_LineNum(fileline);
- return FALSE;
- }
-
- /* 2 fields from scanf; looks like an env setting
- */
-
- /*
- * process value string
- */
- {
- int len = strdtb(val);
-
- if (len >= 2)
- if (val[0] == '\'' || val[0] == '"')
- if (val[len-1] == val[0])
- {
- val[len-1] = '\0';
- (void) strcpy(val, val+1);
- }
- }
-
- (void) sprintf(envstr, "%s=%s", name, val);
- Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr))
- return TRUE;
-}
-
-
-char *
-env_get(name, envp)
- char *name;
- char **envp;
-{
- char *index();
-
- for (; *envp; envp++)
- if (!strcmp_until(*envp, name, '='))
- return index(*envp, '=') + 1;
- return NULL;
-}
diff --git a/libexec/crond/job.c b/libexec/crond/job.c
deleted file mode 100644
index 3d9090c3f595..000000000000
--- a/libexec/crond/job.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#if !defined(lint) && !defined(LINT)
-static char rcsid[] = "$Header: /a/cvs/386BSD/src/libexec/crond/job.c,v 1.1.1.1 1993/06/12 14:55:03 rgrimes Exp $";
-#endif
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- */
-
-
-#include "cron.h"
-
-
-typedef struct _job
- {
- struct _job *next;
- char *cmd;
- user *u;
- }
- job;
-
-
-static job *jhead = NULL, *jtail = NULL;
-
-
-void
-job_add(cmd, u)
- register char *cmd;
- register user *u;
-{
- register job *j;
-
- /* if already on queue, keep going */
- for (j=jhead; j; j=j->next)
- if (j->cmd == cmd && j->u == u) { return; }
-
- /* build a job queue element */
- j = (job*)malloc(sizeof(job));
- j->next = (job*) NULL;
- j->cmd = cmd;
- j->u = u;
-
- /* add it to the tail */
- if (!jhead) { jhead=j; }
- else { jtail->next=j; }
- jtail = j;
-}
-
-
-int
-job_runqueue()
-{
- register job *j;
- register int run = 0;
-
- for (j=jhead; j; j=j->next) {
- do_command(j->cmd, j->u);
- free(j);
- run++;
- }
- jhead = jtail = NULL;
- return run;
-}
diff --git a/libexec/crond/misc.c b/libexec/crond/misc.c
deleted file mode 100644
index 9aebc07d7805..000000000000
--- a/libexec/crond/misc.c
+++ /dev/null
@@ -1,706 +0,0 @@
-#if !defined(lint) && !defined(LINT)
-static char rcsid[] = "$Header: /a/cvs/386BSD/src/libexec/crond/misc.c,v 1.1.1.1 1993/06/12 14:55:03 rgrimes Exp $";
-#endif
-
-/* vix 26jan87 [RCS has the rest of the log]
- * vix 15jan87 [added TIOCNOTTY, thanks csg@pyramid]
- * vix 30dec86 [written]
- *
- * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
- * -------------------- ----- ----------------------
- * CURRENT PATCH LEVEL: 1 00131
- * -------------------- ----- ----------------------
- *
- * 06 Apr 93 Adam Glass Fixes so it compiles quitely
- *
- */
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- */
-
-
-#include "cron.h"
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/ioctl.h>
-#include <sys/file.h>
-#include <errno.h>
-#if defined(ATT)
-# include <fcntl.h>
-#endif
-
-
-void log_it(), be_different(), acquire_daemonlock();
-
-
-char *
-savestr(str)
- char *str;
-{
- extern int strlen();
- extern char *malloc(), *strcpy();
- /**/ char *temp;
-
- temp = malloc((unsigned) (strlen(str) + 1));
- (void) strcpy(temp, str);
- return temp;
-}
-
-
-int
-nocase_strcmp(left, right)
- char *left;
- char *right;
-{
- while (*left && (MkLower(*left) == MkLower(*right)))
- {
- left++;
- right++;
- }
- return MkLower(*left) - MkLower(*right);
-}
-
-
-int
-strcmp_until(left, right, until)
- char *left;
- char *right;
- char until;
-{
- register int diff;
-
- Debug(DPARS|DEXT, ("strcmp_until(%s,%s,%c) ... ", left, right, until))
-
- while (*left && *left != until && *left == *right)
- {
- left++;
- right++;
- }
-
- if ( (*left=='\0' || *left == until)
- && (*right=='\0' || *right == until)
- )
- diff = 0;
- else
- diff = *left - *right;
-
- Debug(DPARS|DEXT, ("%d\n", diff))
-
- return diff;
-}
-
-
-/* strdtb(s) - delete trailing blanks in string 's' and return new length
- */
-int
-strdtb(s)
- register char *s;
-{
- register char *x = s;
-
- /* scan forward to the null
- */
- while (*x)
- x++;
-
- /* scan backward to either the first character before the string,
- * or the last non-blank in the string, whichever comes first.
- */
- do {x--;}
- while (x >= s && isspace(*x));
-
- /* one character beyond where we stopped above is where the null
- * goes.
- */
- *++x = '\0';
-
- /* the difference between the position of the null character and
- * the position of the first character of the string is the length.
- */
- return x - s;
-}
-
-
-int
-set_debug_flags(flags)
- char *flags;
-{
- /* debug flags are of the form flag[,flag ...]
- *
- * if an error occurs, print a message to stdout and return FALSE.
- * otherwise return TRUE after setting ERROR_FLAGS.
- */
-
-#if !DEBUGGING
-
- printf("this program was compiled without debugging enabled\n");
- return FALSE;
-
-#else /* DEBUGGING */
-
- char *pc = flags;
-
- DebugFlags = 0;
-
- while (*pc)
- {
- char **test;
- int mask;
-
- /* try to find debug flag name in our list.
- */
- for ( test = DebugFlagNames, mask = 1;
- *test && strcmp_until(*test, pc, ',');
- test++, mask <<= 1
- )
- ;
-
- if (!*test)
- {
- fprintf(stderr,
- "unrecognized debug flag <%s> <%s>\n",
- flags, pc);
- return FALSE;
- }
-
- DebugFlags |= mask;
-
- /* skip to the next flag
- */
- while (*pc && *pc != ',')
- pc++;
- if (*pc == ',')
- pc++;
- }
-
- if (DebugFlags)
- {
- int flag;
-
- fprintf(stderr, "debug flags enabled:");
-
- for (flag = 0; DebugFlagNames[flag]; flag++)
- if (DebugFlags & (1 << flag))
- fprintf(stderr, " %s", DebugFlagNames[flag]);
- fprintf(stderr, "\n");
- }
-
- return TRUE;
-
-#endif /* DEBUGGING */
-}
-
-
-#if defined(BSD)
-void
-set_cron_uid()
-{
- int seteuid();
-
- if (seteuid(ROOT_UID) < OK)
- {
- perror("seteuid");
- exit(ERROR_EXIT);
- }
-}
-#endif
-
-#if defined(ATT)
-void
-set_cron_uid()
-{
- int setuid();
-
- if (setuid(ROOT_UID) < OK)
- {
- perror("setuid");
- exit(ERROR_EXIT);
- }
-}
-#endif
-
-void
-set_cron_cwd()
-{
- extern int errno;
- struct stat sb;
-
- /* first check for CRONDIR ("/var/cron" or some such)
- */
- if (stat(CRONDIR, &sb) < OK && errno == ENOENT) {
- perror(CRONDIR);
- if (OK == mkdir(CRONDIR, 0700)) {
- fprintf(stderr, "%s: created\n", CRONDIR);
- stat(CRONDIR, &sb);
- } else {
- fprintf(stderr, "%s: ", CRONDIR);
- perror("mkdir");
- exit(ERROR_EXIT);
- }
- }
- if (!(sb.st_mode & S_IFDIR)) {
- fprintf(stderr, "'%s' is not a directory, bailing out.\n",
- CRONDIR);
- exit(ERROR_EXIT);
- }
- if (chdir(CRONDIR) < OK) {
- fprintf(stderr, "cannot chdir(%s), bailing out.\n", CRONDIR);
- perror(CRONDIR);
- exit(ERROR_EXIT);
- }
-
- /* CRONDIR okay (now==CWD), now look at SPOOL_DIR ("tabs" or some such)
- */
- if (stat(SPOOL_DIR, &sb) < OK && errno == ENOENT) {
- perror(SPOOL_DIR);
- if (OK == mkdir(SPOOL_DIR, 0700)) {
- fprintf(stderr, "%s: created\n", SPOOL_DIR);
- stat(SPOOL_DIR, &sb);
- } else {
- fprintf(stderr, "%s: ", SPOOL_DIR);
- perror("mkdir");
- exit(ERROR_EXIT);
- }
- }
- if (!(sb.st_mode & S_IFDIR)) {
- fprintf(stderr, "'%s' is not a directory, bailing out.\n",
- SPOOL_DIR);
- exit(ERROR_EXIT);
- }
-}
-
-
-#if defined(BSD)
-void
-be_different()
-{
- /* release the control terminal:
- * get new pgrp (name after our PID)
- * do an IOCTL to void tty association
- */
-
- auto int fd;
-
- (void) setpgrp(0, getpid());
-
- if ((fd = open("/dev/tty", 2)) >= 0)
- {
- (void) ioctl(fd, TIOCNOTTY, (char*)0);
- (void) close(fd);
- }
-}
-#endif /*BSD*/
-
-#if defined(ATT)
-void
-be_different()
-{
- /* not being a system V wiz, I don't know if this is what you have
- * to do to release your control terminal. what I want to accomplish
- * is to keep this process from getting any signals from the tty.
- *
- * some system V person should let me know if this works... (vixie)
- */
- int setpgrp(), close(), open();
-
- (void) setpgrp();
-
- (void) close(STDIN); (void) open("/dev/null", 0);
- (void) close(STDOUT); (void) open("/dev/null", 1);
- (void) close(STDERR); (void) open("/dev/null", 2);
-}
-#endif /*ATT*/
-
-
-/* acquire_daemonlock() - write our PID into /etc/crond.pid, unless
- * another daemon is already running, which we detect here.
- */
-void
-acquire_daemonlock()
-{
- int fd = open(PIDFILE, O_RDWR|O_CREAT, 0644);
- FILE *fp = fdopen(fd, "r+");
- int pid = getpid(), otherpid;
- char buf[MAX_TEMPSTR];
-
- if (fd < 0 || fp == NULL) {
- sprintf(buf, "can't open or create %s, errno %d", PIDFILE, errno);
- log_it("CROND", pid, "DEATH", buf);
- exit(ERROR_EXIT);
- }
-
- if (flock(fd, LOCK_EX|LOCK_NB) < OK) {
- int save_errno = errno;
-
- fscanf(fp, "%d", &otherpid);
- sprintf(buf, "can't lock %s, otherpid may be %d, errno %d",
- PIDFILE, otherpid, save_errno);
- log_it("CROND", pid, "DEATH", buf);
- exit(ERROR_EXIT);
- }
-
- rewind(fp);
- fprintf(fp, "%d\n", pid);
- fflush(fp);
- ftruncate(fd, ftell(fp));
-
- /* abandon fd and fp even though the file is open. we need to
- * keep it open and locked, but we don't need the handles elsewhere.
- */
-}
-
-/* get_char(file) : like getc() but increment LineNumber on newlines
- */
-int
-get_char(file)
- FILE *file;
-{
- int ch;
-
- ch = getc(file);
- if (ch == '\n')
- Set_LineNum(LineNumber + 1)
- return ch;
-}
-
-
-/* unget_char(ch, file) : like ungetc but do LineNumber processing
- */
-void
-unget_char(ch, file)
- int ch;
- FILE *file;
-{
- ungetc(ch, file);
- if (ch == '\n')
- Set_LineNum(LineNumber - 1)
-}
-
-
-/* get_string(str, max, file, termstr) : like fgets() but
- * (1) has terminator string which should include \n
- * (2) will always leave room for the null
- * (3) uses get_char() so LineNumber will be accurate
- * (4) returns EOF or terminating character, whichever
- */
-int
-get_string(string, size, file, terms)
- char *string;
- int size;
- FILE *file;
- char *terms;
-{
- int ch;
- char *index();
-
- while (EOF != (ch = get_char(file)) && !index(terms, ch))
- if (size > 1)
- {
- *string++ = (char) ch;
- size--;
- }
-
- if (size > 0)
- *string = '\0';
-
- return ch;
-}
-
-
-/* skip_comments(file) : read past comment (if any)
- */
-void
-skip_comments(file)
- FILE *file;
-{
- int ch;
-
- while (EOF != (ch = get_char(file)))
- {
- /* ch is now the first character of a line.
- */
-
- while (ch == ' ' || ch == '\t')
- ch = get_char(file);
-
- if (ch == EOF)
- break;
-
- /* ch is now the first non-blank character of a line.
- */
-
- if (ch != '\n' && ch != '#')
- break;
-
- /* ch must be a newline or comment as first non-blank
- * character on a line.
- */
-
- while (ch != '\n' && ch != EOF)
- ch = get_char(file);
-
- /* ch is now the newline of a line which we're going to
- * ignore.
- */
- }
- unget_char(ch, file);
-}
-
-/* int in_file(char *string, FILE *file)
- * return TRUE if one of the lines in file matches string exactly,
- * FALSE otherwise.
- */
-int
-in_file(string, file)
- char *string;
- FILE *file;
-{
- char line[MAX_TEMPSTR];
-
- /* let's be persnickety today.
- */
- if (!file) {
- if (!string)
- string = "0x0";
- fprintf(stderr,
- "in_file(\"%s\", 0x%x): called with NULL file--botch",
- string, file);
- exit(ERROR_EXIT);
- }
-
- rewind(file);
- while (fgets(line, MAX_TEMPSTR, file)) {
- if (line[0] != '\0')
- line[strlen(line)-1] = '\0';
- if (0 == strcmp(line, string))
- return TRUE;
- }
- return FALSE;
-}
-
-
-/* int allowed(char *username)
- * returns TRUE if (ALLOW_FILE exists and user is listed)
- * or (DENY_FILE exists and user is NOT listed)
- * or (neither file exists but user=="root" so it's okay)
- */
-int
-allowed(username)
- char *username;
-{
- static int init = FALSE;
- static FILE *allow, *deny;
-
- if (!init) {
- init = TRUE;
-#if defined(ALLOW_FILE) && defined(DENY_FILE)
- allow = fopen(ALLOW_FILE, "r");
- deny = fopen(DENY_FILE, "r");
- Debug(DMISC, ("allow/deny enabled, %d/%d\n", !!allow, !!deny))
-#else
- allow = NULL;
- deny = NULL;
-#endif
- }
-
- if (allow)
- return (in_file(username, allow));
- if (deny)
- return (!in_file(username, deny));
-
-#if defined(ALLOW_ONLY_ROOT)
- return (strcmp(username, ROOT_USER) == 0);
-#else
- return TRUE;
-#endif
-}
-
-
-#if defined(LOG_FILE) || defined(SYSLOG)
-void
-log_it(username, pid, event, detail)
- char *username;
- int pid;
- char *event;
- char *detail;
-{
-#if defined(LOG_FILE)
- extern struct tm *localtime();
- extern long time();
- extern char *malloc();
- auto char *msg;
- auto long now = time((long *) 0);
- register struct tm *t = localtime(&now);
- static int log_fd = -1;
-#endif /*LOG_FILE*/
-
-#if defined(SYSLOG)
- static int syslog_open = 0;
-#endif
-
-
-#if defined(LOG_FILE)
- /* we assume that MAX_TEMPSTR will hold the date, time, &punctuation.
- */
- msg = malloc(strlen(username)
- + strlen(event)
- + strlen(detail)
- + MAX_TEMPSTR);
-
- if (log_fd < OK) {
- log_fd = open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0600);
- if (log_fd < OK) {
- fprintf(stderr, "%s: can't open log file\n", ProgramName);
- perror(LOG_FILE);
- }
- }
-
- /* we have to sprintf() it because fprintf() doesn't always write
- * everything out in one chunk and this has to be atomically appended
- * to the log file.
- */
- sprintf(msg, "%s (%02d/%02d-%02d:%02d:%02d-%d) %s (%s)\n",
- username,
- t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, pid,
- event, detail);
-
- /* we have to run strlen() because sprintf() returns (char*) on BSD
- */
- if (log_fd < OK || write(log_fd, msg, strlen(msg)) < OK) {
- fprintf(stderr, "%s: can't write to log file\n", ProgramName);
- if (log_fd >= OK)
- perror(LOG_FILE);
- write(STDERR, msg, strlen(msg));
- }
-
- /* I suppose we could use alloca()...
- */
- free(msg);
-#endif /*LOG_FILE*/
-
-#if defined(SYSLOG)
- if (!syslog_open) {
- /* we don't use LOG_PID since the pid passed to us by
- * our client may not be our own. therefore we want to
- * print the pid ourselves.
- */
-# ifdef LOG_CRON
- openlog(ProgramName, 0, LOG_CRON);
-# else
-# ifdef LOG_DAEMON
- openlog(ProgramName, 0, LOG_DAEMON);
-# else
- openlog(ProgramName, 0);
-# endif /*LOG_DAEMON*/
-# endif /*LOG_CRON*/
- syslog_open = TRUE; /* assume openlog success */
- }
-
- syslog(LOG_INFO, "(%s %d) %s (%s)\n",
- username, pid, event, detail);
-
-#endif /*SYSLOG*/
-
- if (DebugFlags) {
- fprintf(stderr, "log_it: (%s %d) %s (%s)",
- username, pid, event, detail);
- }
-}
-#endif /*LOG_FILE || SYSLOG */
-
-
-/* two warnings:
- * (1) this routine is fairly slow
- * (2) it returns a pointer to static storage
- */
-char *
-first_word(s, t)
- local char *s; /* string we want the first word of */
- local char *t; /* terminators, implicitly including \0 */
-{
- static char retbuf[2][MAX_TEMPSTR + 1]; /* sure wish I had GC */
- static int retsel = 0;
- local char *rb, *rp;
- extern char *index();
-
- /* select a return buffer */
- retsel = 1-retsel;
- rb = &retbuf[retsel][0];
- rp = rb;
-
- /* skip any leading terminators */
- while (*s && (NULL != index(t, *s))) {s++;}
-
- /* copy until next terminator or full buffer */
- while (*s && (NULL == index(t, *s)) && (rp < &rb[MAX_TEMPSTR])) {
- *rp++ = *s++;
- }
-
- /* finish the return-string and return it */
- *rp = '\0';
- return rb;
-}
-
-
-/* warning:
- * heavily ascii-dependent.
- */
-
-void
-mkprint(dst, src, len)
- register char *dst;
- register unsigned char *src;
- register int len;
-{
- while (len-- > 0)
- {
- register unsigned char ch = *src++;
-
- if (ch < ' ') { /* control character */
- *dst++ = '^';
- *dst++ = ch + '@';
- } else if (ch < 0177) { /* printable */
- *dst++ = ch;
- } else if (ch == 0177) { /* delete/rubout */
- *dst++ = '^';
- *dst++ = '?';
- } else { /* parity character */
- sprintf(dst, "\\%03o", ch);
- dst += 4;
- }
- }
- *dst = NULL;
-}
-
-
-/* warning:
- * returns a pointer to malloc'd storage, you must call free yourself.
- */
-
-char *
-mkprints(src, len)
- register unsigned char *src;
- register unsigned int len;
-{
- extern char *malloc();
- register char *dst = malloc(len*4 + 1);
-
- mkprint(dst, src, len);
-
- return dst;
-}
diff --git a/libexec/crond/user.c b/libexec/crond/user.c
deleted file mode 100644
index 4ca0fa3ff51d..000000000000
--- a/libexec/crond/user.c
+++ /dev/null
@@ -1,133 +0,0 @@
-#if !defined(lint) && !defined(LINT)
-static char rcsid[] = "$Header: /a/cvs/386BSD/src/libexec/crond/user.c,v 1.1.1.1 1993/06/12 14:55:03 rgrimes Exp $";
-#endif
-
-/* vix 26jan87 [log is in RCS file]
- *
- * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
- * -------------------- ----- ----------------------
- * CURRENT PATCH LEVEL: 1 00131
- * -------------------- ----- ----------------------
- *
- * 06 Apr 93 Adam Glass Fixes so it compiles quitely
- *
- */
-
-/* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- */
-
-
-#include "cron.h"
-
-
-void
-free_user(u)
- user *u;
-{
- void free_entry();
- int free();
- entry *e;
- char **env;
-
- for (e = u->crontab; e != NULL; e = e->next)
- free_entry(e);
- for (env = u->envp; *env; env++)
- (void) free(*env);
- (void) free(u->envp);
- (void) free(u);
-}
-
-
-user *
-load_user(crontab_fd, name, uid, gid, dir, shell)
- int crontab_fd;
- char *name;
- int uid;
- int gid;
- char *dir;
- char *shell;
-{
- char **env_init(), **env_set();
- int load_env();
- entry *load_entry();
-
- char envstr[MAX_ENVSTR];
- FILE *file;
- user *u;
- entry *e;
- int status;
-
- if (!(file = fdopen(crontab_fd, "r")))
- {
- perror("fdopen on crontab_fd in load_user");
- return NULL;
- }
-
- Debug(DPARS, ("load_user()\n"))
-
- /* file is open. build user entry, then read the crontab file.
- */
- u = (user *) malloc(sizeof(user));
- u->uid = uid;
- u->gid = gid;
- u->envp = env_init();
- u->crontab = NULL;
-
- /*
- * do auto env settings that the user could reset in the cron tab
- */
- sprintf(envstr, "SHELL=%s", (*shell) ?shell :"/bin/sh");
- u->envp = env_set(u->envp, envstr);
-
- sprintf(envstr, "HOME=%s", dir);
- u->envp = env_set(u->envp, envstr);
-
- /* load the crontab
- */
- while ((status = load_env(envstr, file)) >= OK)
- {
- if (status == TRUE)
- {
- u->envp = env_set(u->envp, envstr);
- }
- else
- {
- if (NULL != (e = load_entry(file, NULL)))
- {
- e->next = u->crontab;
- u->crontab = e;
- }
- }
- }
-
- /*
- * do automatic env settings that should have precedence over any
- * set in the cron tab.
- */
- (void) sprintf(envstr, "%s=%s", USERENV, name);
- u->envp = env_set(u->envp, envstr);
-
- /*
- * done. close file, return pointer to 'user' structure
- */
- fclose(file);
-
- Debug(DPARS, ("...load_user() done\n"))
-
- return u;
-}
diff --git a/libexec/ftpd/ftpcmd.y b/libexec/ftpd/ftpcmd.y
index ac4b3bdddd2b..56d061ba6965 100644
--- a/libexec/ftpd/ftpcmd.y
+++ b/libexec/ftpd/ftpcmd.y
@@ -425,8 +425,20 @@ cmd: USER SP username CRLF
= {
#ifdef unix
#ifdef BSD
+ /* UNIX is a registered trademark of
+ somebody (it's changed hands so many times
+ that I can't keep track of who owns it
+ today). FreeBSD is not UNIX, but we
+ continue to use this response because it's
+ a mandatory part of the protocol we participate
+ in with users' `ftp' commands. */
+#ifdef __FreeBSD__
+ reply(215, "UNIX Type: L%d Version: FreeBSD",
+ NBBY);
+#else
reply(215, "UNIX Type: L%d Version: BSD-%d",
NBBY, BSD);
+#endif /* not FreeBSD */
#else /* BSD */
reply(215, "UNIX Type: L%d", NBBY);
#endif /* BSD */
diff --git a/libexec/getty/gettytab.5 b/libexec/getty/gettytab.5
index 50285dd90aff..3a3ef7a3926c 100644
--- a/libexec/getty/gettytab.5
+++ b/libexec/getty/gettytab.5
@@ -101,7 +101,7 @@ after login prompt
.Pq Dv EOF
character
.It "ev str" Ta Dv NULL Ta
-.No "initial enviroment"
+.No "initial environment"
.It "f0 num unused tty mode flags to write messages"
.It "f1 num unused tty mode flags to read login name"
.It "f2 num unused tty mode flags to leave terminal as"
@@ -180,7 +180,7 @@ for input of the login name,
and to leave the terminal set as upon completion,
are derived from the boolean flags specified.
If the derivation should prove inadequate,
-any (or all) of these three may be overriden
+any (or all) of these three may be overridden
with one of the
.Em \&f0 ,
.Em \&f1 ,
@@ -251,7 +251,7 @@ in the
string (usually
.Dq Pa /usr/bin/login ) ,
it will have set
-the enviroment to include the terminal type, as indicated
+the environment to include the terminal type, as indicated
by the
.Em \&tt
string (if it exists).
diff --git a/libexec/pppd/pppd.8 b/libexec/pppd/pppd.8
index ab57223caa33..d64c26f40b11 100644
--- a/libexec/pppd/pppd.8
+++ b/libexec/pppd/pppd.8
@@ -1,4 +1,5 @@
-.\" manual page v0.4 [3/3/93] for pppd 1.2beta
+.\" manual page [] for pppd 2.0
+.\" $Id: pppd.8,v 1.1.2.1 1994/05/01 16:06:43 jkh Exp $
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
@@ -10,215 +11,489 @@ pppd \- Point to Point Protocol daemon
.SH SYNOPSIS
.B pppd
[
-.I option
-]
-.B tty_name speed
-[
-.I local_IP_address
-]:[
-.I remote_IP_address
+.I options
+] [
+.I tty_name
+] [
+.I speed
]
.SH DESCRIPTION
.LP
The Point-to-Point Protocol (PPP) provides a method for transmitting
-datagrams over serial point-to-point links.
+datagrams over serial point-to-point links. PPP
+is composed of three parts: a method for encapsulating datagrams over
+serial links, an extensible Link Control Protocol (LCP), and
+a family of Network Control Protocols (NCP) for establishing
+and configuring different network-layer protocols.
+.LP
+The encapsulation scheme is provided by driver code in the kernel.
+.B pppd
+provides the basic LCP, authentication support, and an
+NCP for establishing and configuring the Internet Protocol (IP)
+(called the IP Control Protocol, IPCP).
+.SH FREQUENTLY USED OPTIONS
+.TP
+.I <tty_name>
+Communicate over the named device. The string "/dev/"
+is prepended if necessary. If no device name is given,
.I pppd
-is composed of three parts:
+will use the controlling terminal, and will not fork to put itself in
+the background.
.TP
-1. A method for encapsulating datagrams over serial links.
+.I <speed>
+Set the baud rate to <speed>. On systems such as 4.4BSD and NetBSD,
+any speed can be specified. Other systems (e.g. SunOS) allow only a
+limited set of speeds.
.TP
-2. An extensible Link Control Protocol (LCP).
+.B asyncmap \fI<map>
+Set the async character map to <map>.
+This map describes which control characters cannot be successfully
+received over the serial line.
+.I pppd
+will ask the peer to send these characters as a 2-byte "escape" sequence.
+The argument is a 32 bit hex number
+with each bit representing a character to escape.
+Bit 0 (00000001) represents the character 0x00;
+bit 31 (80000000) represents the character 0x1f or ^_.
+The default asyncmap is 0. If multiple \fBasyncmap\fR options are
+given, the values are ORed together.
.TP
-3. A family of Network Control Protocols (NCP) for establishing
-and configuring different network-layer protocols.
-.LP
+.B auth
+Require the peer to authenticate itself before allowing network
+packets to be sent or received.
+.TP
+.B connect \fI<p>
+Use the executable or shell command specified by <p> to set up the
+serial line. This script would typically use the "chat" program to
+dial the modem and start the remote ppp session.
+.TP
+.B crtscts
+Use hardware flow control (i.e. RTS/CTS) to control the flow of data on
+the serial port.
+.TP
+.B defaultroute
+Add a default route to the system routing tables, using the peer as
+the gateway, when IPCP negotiation is successfully completed.
+This entry is removed when the PPP connection is broken.
+.TP
+.B file \fI<f>
+Read options from file <f> (the format is described below).
+.TP
+.B mru \fI<n>
+Set the MRU [Maximum Receive Unit] value to <n> for negotiation.
.I pppd
-currently supports the encapsulation scheme, the basic LCP, and an
-NCP for establishing and configuring the Internet Protocol (IP)
-(called the IP Control Protocol, IPCP).
+will ask the peer to send packets of no more than <n> bytes.
+ The minimum MRU value is 128.
+The default MRU value is 1500. A value of 296 is recommended for slow
+links (40 bytes for TCP/IP header + 256 bytes of data).
+.TP
+.B netmask \fI<n>
+Set the interface netmask to <n>, a 32 bit netmask in "decimal dot" notation
+(e.g. 255.255.255.0).
+.TP
+.B passive
+Enables the "passive" option in the LCP. With this option,
+.I pppd
+will attempt to initiate a connection; if no reply is received from
+the peer,
+.I pppd
+will then just wait passively for a valid LCP packet from the peer
+(instead of exiting, as it does without this option).
+.TP
+.B silent
+With this option,
+.I pppd
+will not transmit LCP packets to initiate a connection until a valid
+LCP packet is received from the peer (as for the "passive" option with
+old versions of \fIpppd\fR).
.SH OPTIONS
.TP
+.I <local_IP_address>\fB:\fI<remote_IP_address>
+Set the local and/or remote interface IP addresses. Either one may be
+omitted. The IP addresses can be specified with a host name or in
+decimal dot notation (e.g. 150.234.56.78). The default local
+address is the (first) IP address of the system (unless the
+.B noipdefault
+option is given). The remote address will be obtained from the peer
+if not specified in any option. Thus, in simple cases, this option is
+not required.
+If a local and/or remote IP address is specified with this option,
+.I pppd
+will not accept a different value from the peer in the IPCP
+negotiation, unless the
+.B ipcp-accept-local
+and/or
+.B ipcp-accept-remote
+options are given, respectively.
+.TP
.B -all
-Don't request/allow any options
+Don't request or allow negotiation of any options for LCP and IPCP (use
+default values).
.TP
.B -ac
-Disable Address/Control compression negotiation
+Disable Address/Control compression negotiation (use default, i.e.
+disabled).
.TP
.B -am
-Disable asyncmap negotiation
+Disable asyncmap negotiation (use default, i.e. 0xffffffff).
.TP
-.B -as <n>
-Set the desired async map to hex <n>. The default async map is 0xffffffff.
+.B -as \fI<n>
+Same as
+.B asyncmap \fI<n>
.TP
.B -d
-Increase debugging level
+Increase debugging level.
.TP
.B -detach
-Don't fork to become a background process
+Don't fork to become a background process (otherwise
+.I pppd
+will do so if a serial device is specified).
.TP
.B -ip
-Disable IP address negotiation
+Disable IP address negotiation (with this option, the remote IP
+address must be specified with an option on the command line or in an
+options file).
.TP
.B -mn
-Disable magic number negotiation
+Disable magic number negotiation. With this option,
+.I pppd
+cannot detect a looped-back line.
.TP
.B -mru
-Disable MRU [Maximum Receive Unit] negotiation
+Disable MRU [Maximum Receive Unit] negotiation (use default, i.e. 1500).
.TP
.B -p
-Set passive mode
+Same as the
+.B passive
+option.
.TP
.B -pc
-Disable protocol field compression negotiation
+Disable protocol field compression negotiation (use default, i.e. disabled).
.TP
-.B +ua <p>
-Require UPAP [User/Password Authentication Protocol] authentication.
-Use the data in file <p> for the user and password to send to the
+.B +ua \fI<p>
+Agree to authenticate using PAP [Password Authentication Protocol] if
+requested by the peer, and
+use the data in file <p> for the user and password to send to the
peer. The file contains the remote user name, followed by a newline,
-followed by the remote password.
+followed by the remote password, followed by a newline. This option
+is obsolescent.
+.TP
+.B +pap
+Require the peer to authenticate itself using PAP.
.TP
-.B -ua
-Don't allow UPAP authentication
+.B -pap
+Don't agree to authenticate using PAP.
.TP
.B +chap
-Require CHAP [Cryptographic Handshake Authentication Protocol] authentication.
-Use the data in file /usr/local/etc/ppp/chap, which contains
-host name/secret pairs separated by newlines, to authenticate the peer.
-In the data file, a host name of "default" will match any host name
-not already specified in the file.
+Require the peer to authenticate itself using CHAP [Cryptographic
+Handshake Authentication Protocol] authentication.
.TP
.B -chap
-Don't allow CHAP authentication
-.TP
-.B asyncmap <map>
-Set the async character map to <map>.
-This map describes which control characters to "escape" in the serial data
-stream.
-The argument is a 32 bit hex number represented as 8 hex characters,
-with each bit representing a character to escape.
-The lowest bit (i.e. 00000001) represents the character 0x00
-The highest bit (i.e. 80000000) represents the character 0x1f or ^_.
+Don't agree to authenticate using CHAP.
.TP
-.B connect <p>
-Use the executable or shell command specified by <p> to set-up the
-serial line. This script would typically use the "chat" program to
-dial the modem and start the remote ppp session.
-.TP
-.B crtscts
-Use hardware flow control (i.e. RTS/CTS) to control the flow of data on
-the serial port.
+.B -vj
+Disable negotiation of Van Jacobson style IP header compression (use
+default, i.e. no compression).
.TP
.B debug
-Increase debugging level
+Increase debugging level (same as
+.B -d
+).
.TP
-.B domain <d>
+.B domain \fI<d>
Append the domain name <d> to the local host name for authentication
-purposes. I.e., if gethostname() returns the name porsche, but the
+purposes. For example, if gethostname() returns the name porsche, but the
fully qualified domain name is porsche.Quotron.COM, you would use the
domain option to set the domain name to Quotron.COM.
.TP
-.B mru <n>
-Set MRU value to <n> for negotiation. The minimum MRU value is 128.
-The default MRU value is 1500.
+.B modem
+Use the modem control lines. (This option is not fully implemented.)
.TP
-.B netmask <n>
-Set the interface netmask to <n>, a 32 bit netmask in "decimal dot notation"
-(i.e. 255.255.255.0).
+.B local
+Don't use the modem control lines.
.TP
-.B passive
-Set passive mode; Don't send LCP configure requests. Sets initial state to
-"listen".
+.B name \fI<n>
+Set the name of the local system for authentication purposes to <n>.
.TP
-.B vjmode <m>
-Specifies which version of IPCP Van Jacobson Compression negotiation
-to use. Specify
-.I old
-for <m> to have backward compatibility with early versions of
-.I pppd
-which operated "incorrectly" when negotiating Compression-Type due to a
-typographical error in the RFC.
-.I pppd
-(4.1, patch level 4 and later)
-have this problem corrected but to allow interoperability with older versions
-you can force this "incorrect" behavior. Specify
-.I rfc1172
-for <m> to use the RFC1172 value for negotiation. To use the
-new version of negotiation specified in RFC1132 for
-IPCP (the default), specify
-.I rfc1132
-for <m>.
+.B user \fI<u>
+Set the user name to use for authenticating this machine with the peer
+using PAP to <u>.
.TP
-.B -vj
-This disables the use of Van Jacobson style IP header compression
-altogether.
+.B usehostname
+Enforce the use of the hostname as the name of the local system for
+authentication purposes (overrides the
+.B name
+option).
.TP
-.B <tty_name>
-Communicate over the named device
+.B remotename \fI<n>
+Set the assumed name of the remote system for authentication purposes
+to <n>.
.TP
-.B <speed>
-Set the baud rate to <speed>
+.B proxyarp
+Add an entry to this system's ARP [Address Resolution Protocol] table
+with the IP address of the peer and the Ethernet address of this
+system.
.TP
-.B <local_IP_address>:<remote_IP_address>
-Set the local and/or remote interface IP addresses. Either one may be omitted.
-\".SH EXAMPLES
-\".SH FILES
-.SH SEE ALSO
+.B login
+Use the system password database for authenticating the peer using
+PAP.
.TP
-.B RFC1144
-Jacobson, V.
-.I Compressing TCP/IP headers for low-speed serial links.
-1990 February.
+.B noipdefault
+Disables the default behavior when no local IP address is specified,
+which is to determine (if possible) the local IP address from the
+hostname. With this option, the peer will have to supply the local IP
+address during IPCP negotiation (unless it specified explicitly on the
+command line or in an options file).
.TP
-.B RFC1171
-Perkins, D.
-.I Point\-to\-Point Protocol for the transmission of multi\-protocol
-.I datagrams over Point\-to\-Point links.
-1990 July.
+.B lcp-restart \fI<n>
+Set the LCP restart interval (retransmission timeout) to <n> seconds
+(default 3).
.TP
-.B RFC1172
-Perkins, D.; Hobby, R.
-.I Point\-to\-Point Protocol (PPP) initial configuration options.
-1990 July.
+.B lcp-max-terminate \fI<n>
+Set the maximum number of LCP terminate-request transmissions to <n>
+(default 3).
.TP
-.B RFC1331
-Simpson, W.
-.I The Point\-to\-Point Protocol (PPP) for the Transmission of Multi-protocol
-.I Datagrams over Point\-to\-Point Links
-1992 May.
+.B lcp-max-configure \fI<n>
+Set the maximum number of LCP configure-request transmissions to <n>
+(default 10).
.TP
-.B RFC1332
-McGregor, G.
-.I The PPP Internet Protocol Control Protocol (IPCP).
-1991 August.
+.B lcp-max-failure \fI<n>
+Set the maximum number of LCP configure-NAKs returned before starting
+to send configure-Rejects instead to <n> (default 10).
.TP
-.B RFC1333
-Simpson, W.
-.I PPP Link Quality Monitoring
-1992 May.
+.B ipcp-restart \fI<n>
+Set the IPCP restart interval (retransmission timeout) to <n> seconds
+(default 3).
.TP
-.B Internet Draft
-Lloyd, B.; Simpson, W.
-.I PPP Authentication Protocols.
-1991 November.
+.B ipcp-max-terminate \fI<n>
+Set the maximum number of IPCP terminate-request transmissions to <n>
+(default 3).
.TP
-.B Internet Draft
-Rivest, R.
-.I The MD5 Message-Digest Algorithm.
-1991 July.
-.SH DIAGNOSTICS
+.B ipcp-max-configure \fI<n>
+Set the maximum number of IPCP configure-request transmissions to <n>
+(default 10).
+.TP
+.B ipcp-max-failure \fI<n>
+Set the maximum number of IPCP configure-NAKs returned before starting
+to send configure-Rejects instead to <n> (default 10).
+.TP
+.B pap-restart \fI<n>
+Set the PAP restart interval (retransmission timeout) to <n> seconds
+(default 3).
+.TP
+.B pap-max-authreq \fI<n>
+Set the maximum number of PAP authenticate-request transmissions to
+<n> (default 10).
+.TP
+.B chap-restart \fI<n>
+Set the CHAP restart interval (retransmission timeout for challenges)
+to <n> seconds (default 3).
+.TP
+.B chap-max-challenge \fI<n>
+Set the maximum number of CHAP challenge transmissions to <n> (default
+10).
+.TP
+.B chap-interval \fI<n>
+If this option is given,
+.I pppd
+will rechallenge the peer every <n> seconds.
+.TP
+.B ipcp-accept-local
+With this option,
+.I pppd
+will accept the peer's idea of our local IP address, even if the
+local IP address was specified in an option.
+.TP
+.B ipcp-accept-remote
+With this option,
+.I pppd
+will accept the peer's idea of its (remote) IP address, even if the
+remote IP address was specified in an option.
+.SH OPTIONS FILES
+Options can be taken from files as well as the command line.
+.I pppd
+reads options from the files /etc/ppp/options and $HOME/.ppprc before
+looking at the command line. An options file is parsed into a series
+of words, delimited by whitespace. Whitespace can be included in a
+word by enclosing the word in quotes ("). A backslash (\\) quotes the
+following character. A hash (#) starts a comment, which continues
+until the end of the line.
+.SH AUTHENTICATION
+.I pppd
+provides system administrators with sufficient access control that PPP
+access to a server machine can be provided to legitimate users without
+fear of compromising the security of the server or the network it's
+on. In part this is provided by the /etc/ppp/options file, where the
+administrator can place options to require authentication whenever
+.I pppd
+is run, and in part by the PAP and CHAP secrets files, where the
+administrator can restrict the set of IP addresses which individual
+users may use.
.LP
-There is, currently, only one level of debugging available. Debugging is
-enabled by setting the -d or debug flag on the command line. Debugging may
-also be enabled after
+The default behavior of
.I pppd
-is running by sending a SIGUSR1 to the
+is to agree to authenticate if requested, and to not
+require authentication from the peer. However,
.I pppd
-process.
-Debugging may be disabled by sending a SIGUSR2 to the
+will not agree to
+authenticate itself with a particular protocol if it has no secrets
+which could be used to do so.
+.LP
+Authentication is based on secrets, which are selected from secrets
+files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP).
+Both secrets files have the same format, and both can store secrets
+for several combinations of server (authenticating peer) and client
+(peer being authenticated). Note that
.I pppd
-process.
+can be both a server
+and client, and that different protocols can be used in the two
+directions if desired.
+.LP
+A secrets file is parsed into words as for a options file. A secret
+is specified by a line containing at least 3 words, in the order
+client, server, secret. Any following words on the same line are
+taken to be a list of acceptable IP addresses for that client. If
+there are only 3 words on the line, it is assumed that any IP address
+is OK; to disallow all IP addresses, use "-". If the secret starts
+with an `@', what follows is assumed to be the name of a file from
+which to read the secret. A "*" as the client or server name matches
+any name. When selecting a secret, \fIpppd\fR takes the best match, i.e.
+the match with the fewest wildcards.
+.LP
+Thus a secrets file contains both secrets for use in authenticating
+other hosts, plus secrets which we use for authenticating ourselves to
+others. Which secret to use is chosen based on the names of the host
+(the `local name') and its peer (the `remote name'). The local name
+is set as follows:
+.TP 3
+if the \fBusehostname\fR option is given,
+then the local name is the hostname of this machine
+(with the domain appended, if given)
+.TP 3
+else if the \fBname\fR option is given,
+then use the argument of the first \fBname\fR option seen
+.TP 3
+else if the local IP address is specified with a hostname,
+then use that name
+.TP 3
+else use the hostname of this machine (with the domain appended, if given)
.LP
-Error and warning messages are sent to the syslog daemon using facility
+When authenticating ourselves using PAP, there is also a `username'
+which is the local name by default, but can be set with the \fBuser\fR
+option or the \fB+ua\fR option.
+.LP
+The remote name is set as follows:
+.TP 3
+if the \fBremotename\fR option is given,
+then use the argument of the last \fBremotename\fR option seen
+.TP 3
+else if the remote IP address is specified with a hostname,
+then use that host name
+.TP 3
+else the remote name is the null string "".
+.LP
+Secrets are selected from the PAP secrets file as follows:
+.TP 2
+*
+For authenticating the peer, look for a secret with client ==
+username specified in the PAP authenticate-request, and server ==
+local name.
+.TP 2
+*
+For authenticating ourselves to the peer, look for a secret with
+client == our username, server == remote name.
+.LP
+When authenticating the peer with PAP, a secret of "" matches any
+password supplied by the peer. If the password doesn't match the
+secret, the password is encrypted using crypt() and checked against
+the secret again; thus secrets for authenticating the peer can be
+stored in encrypted form. If the \fBlogin\fR option was specified, the
+username and password are also checked against the system password
+database. Thus, the system administrator can set up the pap-secrets
+file to allow PPP access only to certain users, and to restrict the
+set of IP addresses that each user can use.
+.LP
+Secrets are selected from the CHAP secrets file as follows:
+.TP 2
+*
+For authenticating the peer, look for a secret with client == name
+specified in the CHAP-Response message, and server == local name.
+.TP 2
+*
+For authenticating ourselves to the peer, look for a secret with
+client == local name, and server == name specified in the
+CHAP-Challenge message.
+.LP
+Authentication must be satisfactorily completed before IPCP (or any
+other Network Control Protocol) can be started. If authentication
+fails, \fIpppd\fR will terminated the link (by closing LCP). If IPCP
+negotiates an unacceptable IP address for the remote host, IPCP will
+be closed. IP packets can only be sent or received when IPCP is open.
+.SH ROUTING
+.LP
+When IPCP negotiation is completed successfully,
+.I pppd
+will inform the kernel of the local and remote IP addresses for the
+ppp interface. This is sufficient to create a
+host route to the remote end of the link, which will enable the peers
+to exchange IP packets. Communication with other machines generally
+requires further modification to routing tables and/or ARP (Address
+Resolution Protocol) tables. In some cases this will be done
+automatically through the actions of the \fIrouted\fR or \fIgated\fR
+daemons, but in most cases some further intervention is required.
+.LP
+Sometimes it is desirable
+to add a default route through the remote host, as in the case of a
+machine whose only connection to the Internet is through the ppp
+interface. The \fBdefaultroute\fR option causes \fIpppd\fR to create such a
+default route when IPCP comes up, and delete it when the link is
+terminated.
+.LP
+In some cases it is desirable to use proxy ARP, for example on a
+server machine connected to a LAN, in order to allow other hosts to
+communicate with the remote host. The \fBproxyarp\fR option causes \fIpppd\fR
+to look for a network interface on the same subnet as the remote host
+(an interface supporting broadcast and ARP, which is up and not a
+point-to-point or loopback interface). If found, \fIpppd\fR creates a
+permanent, published ARP entry with the IP address of the remote host
+and the hardware address of the network interface found.
+.SH EXAMPLES
+.LP
+In the simplest case, you can connect the serial ports of two machines
+and issue a command like
+.IP
+pppd /dev/ttya 9600 passive
+.LP
+to each machine, assuming there is no \fIgetty\fR running on the
+serial ports. If one machine has a \fIgetty\fR running, you can use
+\fIkermit\fR or \fItip\fR on the other machine to log in to the first
+machine and issue a command like
+.IP
+pppd passive
+.LP
+Then exit from the communications program (making sure the connection
+isn't dropped), and issue a command like
+.IP
+pppd /dev/ttya 9600
+.LP
+The process of logging in to the other machine and starting \fIpppd\fR
+can be automated by using the \fBconnect\fR option to run \fIchat\fR,
+for example:
+.IP
+pppd /dev/ttya 38400 connect 'chat "" "" "login:" "username"
+"Password:" "password" "% " "exec pppd passive"'
+.LP
+If your serial connection is any more complicated than a piece of
+wire, you may need to arrange for some control characters to be
+escaped. In particular, it is often useful to escape XON (^Q) and
+XOFF (^S), using \fBasyncmap a0000\fR. If the path includes a telnet,
+you probably should escape ^] as well (\fBasyncmap 200a0000\fR).
+Don't use an rlogin in the path - many implementations are not
+transparent; they will remove the sequence [0xff, 0xff, 0x73, 0x73,
+followed by any 8 bytes] from the stream.
+.SH DIAGNOSTICS
+.LP
+Messages are sent to the syslog daemon using facility
LOG_DAEMON unless
.I pppd
has been compiled with debugging code. In this case the logging
@@ -229,53 +504,79 @@ and recompiling. In order to see the error and debug messages, you
will need to edit your /etc/syslog.conf file to direct the messages to
the desired output device or file.
.LP
-Debugging is currently available for
-.I fsm.c
-\- the {Link, IP} Control Protocol Finite State Machine module;
-.I lcp.c
-\- the PPP Link Control Protocol module;
-.I ipcp.c
-\- the PPP IP Control Protocol module;
-.I upap.c
-\- the User/Password Authentication Protocol module;
-and
-.I chap.c
-\- the Challenge Handshake Authentication Protocol module.
-.SH NOTES
-The following signals have the specified effect when sent to the
+If enabled at compile time, debugging printout can be enabled by
+setting the -d or debug flag on the command line, or by sending a
+SIGUSR1 to the
.I pppd
process.
-.TP
-.B SIGINT
-This signal is normally generated by a Ctrl-C or DEL.
-Causes
-.I pppd
-to initiate a graceful disconnect and exit.
+Debugging may be disabled by sending a SIGUSR2 to the
.I pppd
-will adjust the timeouts and close the connection.
+process.
+.SH FILES
.TP
-.B SIGTERM
-Causes
-.I pppd
-to initiate a graceful disconnect and exit.
+.B /var/run/ppp\fIn\fB.pid \fR(BSD), \fB/etc/ppp/ppp\fIn\fB.pid \fR(SunOS)
+Process-ID for \fIpppd\fR process on ppp interface unit \fIn\fR.
+.TP
+.B /etc/ppp/pap-secrets
+Usernames, passwords and IP addresses for PAP authentication.
+.TP
+.B /etc/ppp/chap-secrets
+Names, secrets and IP addresses for CHAP authentication.
+.TP
+.B /etc/ppp/options
+System default options for
+.I pppd,
+read before user default options or command-line options.
+.TP
+.B $HOME/.ppprc
+User default options, read before command-line options.
+.SH SEE ALSO
+.TP
+.B RFC1144
+Jacobson, V.
+.I Compressing TCP/IP headers for low-speed serial links.
+1990 February.
+.TP
+.B RFC1321
+Rivest, R.
+.I The MD5 Message-Digest Algorithm.
+1992 April.
+.TP
+.B RFC1331
+Simpson, W.A.
+.I Point\-to\-Point Protocol (PPP) for the transmission of multi\-protocol
+.I datagrams over point\-to\-point links.
+1992 May.
+.TP
+.B RFC1332
+McGregor, G.
+.I PPP Internet Protocol Control Protocol (IPCP).
+1992 May.
+.TP
+.B RFC1334
+Lloyd, B.; Simpson, W.A.
+.I PPP authentication protocols.
+1992 October.
+.SH NOTES
+The following signals have the specified effect when sent to the
.I pppd
-will adjust the timeouts and close the connection.
+process.
+.TP
+.B SIGINT, SIGTERM
+These signals cause \fIpppd\fR to terminate the link (by closing LCP),
+restore the serial device settings, and exit.
.TP
.B SIGHUP
-Indicates that the physical layer has been disconnected. You will
-probably see "Bad file number" errors in the log output due to the way
-the STREAMS-based tty driver handles a hangup. You can ignore
-these errors in this case.
-.I pppd
-will adjust the timeouts and reset the connection.
+Indicates that the physical layer has been disconnected. \fIpppd\fR
+will attempt to restore the serial device settings (this may produce
+error messages on Suns), and then exit.
.SH BUGS
-Note that sections the current implementation of
-.I pppd
- are based on older RFCs and draft RFCs and may not be fully
-compatible with the latest draft RFC versions.
+The use of the modem control lines and the effects of the \fBmodem\fR
+and \fBlocal\fR options are not well defined.
.SH AUTHORS
Drew Perkins,
Brad Clements,
Karl Fox,
Greg Christy,
-Brad Parker (brad@fcr.com)
+Brad Parker (brad@fcr.com),
+Paul Mackerras (paulus@cs.anu.edu.au)
diff --git a/libexec/rlogind/rlogind.c b/libexec/rlogind/rlogind.c
index 1b96aaa70c34..f3b50b696be4 100644
--- a/libexec/rlogind/rlogind.c
+++ b/libexec/rlogind/rlogind.c
@@ -43,8 +43,8 @@ static char sccsid[] = "@(#)rlogind.c 5.53 (Berkeley) 4/20/91";
#ifdef KERBEROS
/* From:
- * $Source: /a/cvs/386BSD/src/libexec/rlogind/rlogind.c,v $
- * $Header: /a/cvs/386BSD/src/libexec/rlogind/rlogind.c,v 1.1.1.1 1993/06/12 14:54:58 rgrimes Exp $
+ * $Source: /home/cvs/386BSD/src/libexec/rlogind/rlogind.c,v $
+ * $Header: /home/cvs/386BSD/src/libexec/rlogind/rlogind.c,v 1.1.1.1 1993/06/12 14:54:58 rgrimes Exp $
*/
#endif
diff --git a/libexec/rpc.rstatd/Makefile b/libexec/rpc.rstatd/Makefile
index 0de5641d61d3..3e14e3b52225 100644
--- a/libexec/rpc.rstatd/Makefile
+++ b/libexec/rpc.rstatd/Makefile
@@ -1,10 +1,10 @@
-# $Id: Makefile,v 1.1 1993/09/16 00:27:42 jtc Exp $
+# $Id: Makefile,v 1.2 1993/11/10 03:45:40 smace Exp $
PROG = rpc.rstatd
SRCS = rstatd.c rstat_proc.c
MAN8 = rpc.rstatd.8
-DPADD= ${LIBRPCSVC} ${LIBRPC} ${LIBUTIL}
-LDADD= -lrpcsvc -lrpc -lutil
+DPADD= ${LIBRPCSVC} ${LIBUTIL}
+LDADD= -lrpcsvc -lutil
.include <bsd.prog.mk>
diff --git a/libexec/rpc.rusersd/Makefile b/libexec/rpc.rusersd/Makefile
index 611727304fb8..1c689397232d 100644
--- a/libexec/rpc.rusersd/Makefile
+++ b/libexec/rpc.rusersd/Makefile
@@ -1,11 +1,11 @@
-# $Id: Makefile,v 1.1 1993/09/16 00:34:36 jtc Exp $
+# $Id: Makefile,v 1.2 1993/11/10 03:46:04 smace Exp $
PROG = rpc.rusersd
SRCS = rusersd.c rusers_proc.c
MAN8 = rpc.rusersd.8
-DPADD= ${LIBRPCSVC} ${LIBRPC} ${LIBUTIL}
-LDADD= -lrpcsvc -lrpc -lutil
+DPADD= ${LIBRPCSVC} ${LIBUTIL}
+LDADD= -lrpcsvc -lutil
.if exists(/usr/include/X11/extensions/xidle.h)
CFLAGS+= -DXIDLE
diff --git a/libexec/rpc.rusersd/rusers_proc.c b/libexec/rpc.rusersd/rusers_proc.c
index 06beec62bd9f..31f4bfe50d9f 100644
--- a/libexec/rpc.rusersd/rusers_proc.c
+++ b/libexec/rpc.rusersd/rusers_proc.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char rcsid[] = "$Id: rusers_proc.c,v 1.1 1993/09/16 00:34:46 jtc Exp $";
+static char rcsid[] = "$Id: rusers_proc.c,v 1.1.2.1 1994/03/07 02:28:00 rgrimes Exp $";
#endif /* not lint */
#include <signal.h>
@@ -78,9 +78,9 @@ static char rcsid[] = "$Id: rusers_proc.c,v 1.1 1993/09/16 00:34:46 jtc Exp $";
#define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host)
#endif
-typedef char ut_line_t[UT_LINESIZE];
-typedef char ut_name_t[UT_NAMESIZE];
-typedef char ut_host_t[UT_HOSTSIZE];
+typedef char ut_line_t[UT_LINESIZE+1];
+typedef char ut_name_t[UT_NAMESIZE+1];
+typedef char ut_host_t[UT_HOSTSIZE+1];
utmpidle utmp_idle[MAXUSERS];
rutmp old_utmp[MAXUSERS];
@@ -218,11 +218,16 @@ do_names_2(int all)
utmp_idle[nusers].ui_idle =
getidle(usr.ut_line, usr.ut_host);
utmp_idle[nusers].ui_utmp.ut_line = line[nusers];
- strncpy(line[nusers], usr.ut_line, sizeof(line[nusers]));
+ strncpy(line[nusers], usr.ut_line, UT_LINESIZE);
utmp_idle[nusers].ui_utmp.ut_name = name[nusers];
- strncpy(name[nusers], usr.ut_name, sizeof(name[nusers]));
+ strncpy(name[nusers], usr.ut_name, UT_NAMESIZE);
utmp_idle[nusers].ui_utmp.ut_host = host[nusers];
- strncpy(host[nusers], usr.ut_host, sizeof(host[nusers]));
+ strncpy(host[nusers], usr.ut_host, UT_HOSTSIZE);
+
+ /* Make sure entries are NUL terminated */
+ line[nusers][UT_LINESIZE] =
+ name[nusers][UT_NAMESIZE] =
+ host[nusers][UT_HOSTSIZE] = '\0';
nusers++;
}
diff --git a/libexec/rpc.rwalld/Makefile b/libexec/rpc.rwalld/Makefile
index 286c54535975..5d7b492a8a40 100644
--- a/libexec/rpc.rwalld/Makefile
+++ b/libexec/rpc.rwalld/Makefile
@@ -1,10 +1,10 @@
-# $Id: Makefile,v 1.1 1993/09/16 00:36:39 jtc Exp $
+# $Id: Makefile,v 1.2 1993/11/10 03:46:23 smace Exp $
PROG = rpc.rwalld
SRCS = rwalld.c
MAN8 = rpc.rwalld.8
-DPADD= ${LIBRPCSVC} ${LIBRPC} ${LIBUTIL}
-LDADD= -lrpcsvc -lrpc -lutil
+DPADD= ${LIBRPCSVC} ${LIBUTIL}
+LDADD= -lrpcsvc -lutil
.include <bsd.prog.mk>
diff --git a/libexec/rshd/rshd.c b/libexec/rshd/rshd.c
index 89d4591ee785..26ffb57daf2b 100644
--- a/libexec/rshd/rshd.c
+++ b/libexec/rshd/rshd.c
@@ -43,7 +43,7 @@ static char sccsid[] = "@(#)rshd.c 5.38 (Berkeley) 3/2/91";
/*
* From:
- * $Source: /a/cvs/386BSD/src/libexec/rshd/rshd.c,v $
+ * $Source: /home/cvs/386BSD/src/libexec/rshd/rshd.c,v $
* $Header: /mit/kerberos/ucb/mit/rshd/RCS/rshd.c,v
* 5.2 89/07/31 19:30:04 kfall Exp $
*/
diff --git a/libexec/telnetd/Makefile b/libexec/telnetd/Makefile
index a09465173171..382885be9a1f 100644
--- a/libexec/telnetd/Makefile
+++ b/libexec/telnetd/Makefile
@@ -1,7 +1,7 @@
# @(#)Makefile 5.16 (Berkeley) 5/13/91
PROG= telnetd
-CFLAGS+=-DLINEMODE -DUSE_TERMIO -DDIAGNOSTICS
+CFLAGS+=-DUSE_TERMIO -DDIAGNOSTICS
CFLAGS+=-I${.CURDIR}/../../lib
SRCS= global.c slc.c state.c sys_term.c telnetd.c \
termstat.c utility.c
diff --git a/libexec/telnetd/ext.h b/libexec/telnetd/ext.h
index c6fd173feef4..c5f4d883f0da 100644
--- a/libexec/telnetd/ext.h
+++ b/libexec/telnetd/ext.h
@@ -218,7 +218,11 @@ extern int needtermstat;
#endif
#ifndef CRAY
+#ifndef __FreeBSD__
#define DEFAULT_IM "\r\n\r\n4.3 BSD UNIX (%h) (%t)\r\n\r\r\n\r"
#else
+#define DEFAULT_IM "\r\n\r\n%s (%%h) (%%t)\r\n\r\r\n\r"
+#endif
+#else
#define DEFAULT_IM "\r\n\r\nCray UNICOS (%h) (%t)\r\n\r\r\n\r"
#endif
diff --git a/libexec/telnetd/sys_term.c b/libexec/telnetd/sys_term.c
index e06d3b5bf065..cde67833dfb4 100644
--- a/libexec/telnetd/sys_term.c
+++ b/libexec/telnetd/sys_term.c
@@ -611,17 +611,11 @@ tty_israw()
tty_binaryin(on)
int on;
{
+/* Make 8-bit clean mode in any case */
#ifndef USE_TERMIO
- if (on)
- termbuf.lflags |= LPASS8;
- else
- termbuf.lflags &= ~LPASS8;
+ termbuf.lflags |= LPASS8;
#else
- if (on) {
- termbuf.c_iflag &= ~ISTRIP;
- } else {
- termbuf.c_iflag |= ISTRIP;
- }
+ termbuf.c_iflag &= ~ISTRIP;
#endif
}
diff --git a/libexec/telnetd/telnetd.c b/libexec/telnetd/telnetd.c
index 9708956745fd..2e504a401a41 100644
--- a/libexec/telnetd/telnetd.c
+++ b/libexec/telnetd/telnetd.c
@@ -901,7 +901,15 @@ telnet(f, p, host)
if (IM == 0)
IM = "";
} else {
+#ifdef __FreeBSD__
+ static char issue_message[256];
+ extern char *_osnamever();
+ snprintf(issue_message, sizeof issue_message,
+ DEFAULT_IM, _osnamever());
+ IM = issue_message;
+#else
IM = DEFAULT_IM;
+#endif
HE = 0;
}
edithost(HE, host_name);