summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
Diffstat (limited to 'libexec')
-rw-r--r--libexec/Makefile22
-rw-r--r--libexec/atrun/LEGAL31
-rw-r--r--libexec/atrun/Makefile26
-rw-r--r--libexec/atrun/atrun.c486
-rw-r--r--libexec/atrun/atrun.man66
-rw-r--r--libexec/atrun/gloadavg.c69
-rw-r--r--libexec/atrun/gloadavg.h29
-rw-r--r--libexec/bootpd/Announce65
-rw-r--r--libexec/bootpd/Changes294
-rwxr-xr-xlibexec/bootpd/ConvOldTab.sh141
-rw-r--r--libexec/bootpd/Installation29
-rw-r--r--libexec/bootpd/Makefile17
-rw-r--r--libexec/bootpd/Makefile.UNIX204
-rw-r--r--libexec/bootpd/Makefile.inc3
-rw-r--r--libexec/bootpd/Problems66
-rw-r--r--libexec/bootpd/README136
-rw-r--r--libexec/bootpd/ToDo61
-rw-r--r--libexec/bootpd/bootp.h147
-rw-r--r--libexec/bootpd/bootpd.8305
-rw-r--r--libexec/bootpd/bootpd.c1406
-rw-r--r--libexec/bootpd/bootpd.h211
-rw-r--r--libexec/bootpd/bootpgw/Makefile12
-rw-r--r--libexec/bootpd/bootpgw/bootpgw.c688
-rw-r--r--libexec/bootpd/bootptab.5395
-rw-r--r--libexec/bootpd/bootptab.cmu124
-rw-r--r--libexec/bootpd/bootptab.mcs91
-rw-r--r--libexec/bootpd/bptypes.h23
-rw-r--r--libexec/bootpd/dovend.c414
-rw-r--r--libexec/bootpd/dovend.h13
-rw-r--r--libexec/bootpd/dumptab.c384
-rw-r--r--libexec/bootpd/getether.c386
-rw-r--r--libexec/bootpd/getether.h7
-rw-r--r--libexec/bootpd/getif.c147
-rw-r--r--libexec/bootpd/getif.h7
-rw-r--r--libexec/bootpd/hash.c423
-rw-r--r--libexec/bootpd/hash.h158
-rw-r--r--libexec/bootpd/hwaddr.c352
-rw-r--r--libexec/bootpd/hwaddr.h44
-rw-r--r--libexec/bootpd/lookup.c129
-rw-r--r--libexec/bootpd/lookup.h15
-rw-r--r--libexec/bootpd/patchlevel.h8
-rw-r--r--libexec/bootpd/readfile.c2088
-rw-r--r--libexec/bootpd/readfile.h19
-rw-r--r--libexec/bootpd/report.c154
-rw-r--r--libexec/bootpd/report.h13
-rw-r--r--libexec/bootpd/rtmsg.c254
-rw-r--r--libexec/bootpd/syslog.conf63
-rw-r--r--libexec/bootpd/tools/Makefile6
-rw-r--r--libexec/bootpd/tools/Makefile.inc4
-rw-r--r--libexec/bootpd/tools/bootpef/Makefile13
-rw-r--r--libexec/bootpd/tools/bootpef/bootpef.852
-rw-r--r--libexec/bootpd/tools/bootpef/bootpef.c343
-rw-r--r--libexec/bootpd/tools/bootptest/Makefile12
-rw-r--r--libexec/bootpd/tools/bootptest/bootptest.874
-rw-r--r--libexec/bootpd/tools/bootptest/bootptest.c520
-rw-r--r--libexec/bootpd/tools/bootptest/bootptest.h30
-rw-r--r--libexec/bootpd/tools/bootptest/print-bootp.c492
-rw-r--r--libexec/bootpd/trygetea.c55
-rw-r--r--libexec/bootpd/trygetif.c74
-rw-r--r--libexec/bootpd/trylook.c58
-rw-r--r--libexec/bootpd/tzone.c44
-rw-r--r--libexec/bootpd/tzone.h3
-rw-r--r--libexec/bugfiler/Makefile17
-rw-r--r--libexec/bugfiler/bug.h92
-rw-r--r--libexec/bugfiler/bugfiler.8290
-rw-r--r--libexec/bugfiler/bugfiler.c167
-rw-r--r--libexec/bugfiler/bugformat32
-rw-r--r--libexec/bugfiler/gethead.c165
-rw-r--r--libexec/bugfiler/process.c115
-rw-r--r--libexec/bugfiler/redist.c131
-rw-r--r--libexec/bugfiler/reply.c118
-rw-r--r--libexec/bugfiler/sendbug.sh66
-rw-r--r--libexec/comsat/Makefile3
-rw-r--r--libexec/comsat/comsat.89
-rw-r--r--libexec/comsat/comsat.c67
-rw-r--r--libexec/fingerd/Makefile3
-rw-r--r--libexec/fingerd/fingerd.87
-rw-r--r--libexec/fingerd/fingerd.c45
-rw-r--r--libexec/ftpd/Makefile28
-rw-r--r--libexec/ftpd/extern.h10
-rw-r--r--libexec/ftpd/ftpcmd.y72
-rw-r--r--libexec/ftpd/ftpd.8189
-rw-r--r--libexec/ftpd/ftpd.c818
-rw-r--r--libexec/ftpd/logwtmp.c18
-rw-r--r--libexec/ftpd/pathnames.h8
-rw-r--r--libexec/ftpd/popen.c36
-rw-r--r--libexec/ftpd/skey-stuff.c29
-rw-r--r--libexec/getNAME/Makefile2
-rw-r--r--libexec/getNAME/getNAME.165
-rw-r--r--libexec/getNAME/getNAME.c8
-rw-r--r--libexec/getty/Makefile14
-rw-r--r--libexec/getty/chat.c515
-rw-r--r--libexec/getty/extern.h (renamed from libexec/telnetd/authenc.c)88
-rw-r--r--libexec/getty/getty.8128
-rw-r--r--libexec/getty/gettytab.5516
-rw-r--r--libexec/getty/gettytab.h173
-rw-r--r--libexec/getty/init.c146
-rw-r--r--libexec/getty/main.c763
-rw-r--r--libexec/getty/pathnames.h (renamed from libexec/bugfiler/pathnames.h)10
-rw-r--r--libexec/getty/subr.c853
-rw-r--r--libexec/getty/ttys.5163
-rw-r--r--libexec/kpasswdd/Makefile11
-rw-r--r--libexec/kpasswdd/kpasswdd.c271
-rw-r--r--libexec/lfs_cleanerd/Makefile7
-rw-r--r--libexec/lfs_cleanerd/clean.h11
-rw-r--r--libexec/lfs_cleanerd/cleanerd.c167
-rw-r--r--libexec/lfs_cleanerd/lfs_cleanerd.86
-rw-r--r--libexec/lfs_cleanerd/library.c114
-rw-r--r--libexec/lfs_cleanerd/print.c30
-rw-r--r--libexec/mail.local/Makefile6
-rw-r--r--libexec/mail.local/mail.local.87
-rw-r--r--libexec/mail.local/mail.local.c443
-rw-r--r--libexec/makekey/Makefile10
-rw-r--r--libexec/makekey/makekey.8 (renamed from libexec/kpasswdd/kpasswdd.8)46
-rw-r--r--libexec/makekey/makekey.c (renamed from libexec/getty/ttydefaults.c)58
-rw-r--r--libexec/mknetid/Makefile8
-rw-r--r--libexec/mknetid/hash.c179
-rw-r--r--libexec/mknetid/hash.h54
-rw-r--r--libexec/mknetid/mknetid.8141
-rw-r--r--libexec/mknetid/mknetid.c291
-rw-r--r--libexec/mknetid/parse_group.c169
-rw-r--r--libexec/named-xfer/Makefile20
-rw-r--r--libexec/rbootd/Makefile8
-rw-r--r--libexec/rbootd/bpf.c419
-rw-r--r--libexec/rbootd/conf.c90
-rw-r--r--libexec/rbootd/defs.h184
-rw-r--r--libexec/rbootd/parseconf.c359
-rw-r--r--libexec/rbootd/pathnames.h (renamed from libexec/bugfiler/extern.h)28
-rw-r--r--libexec/rbootd/rbootd.8156
-rw-r--r--libexec/rbootd/rbootd.c447
-rw-r--r--libexec/rbootd/rmp.h95
-rw-r--r--libexec/rbootd/rmp_var.h244
-rw-r--r--libexec/rbootd/rmpproto.c600
-rw-r--r--libexec/rbootd/utils.c556
-rw-r--r--libexec/revnetgroup/Makefile8
-rw-r--r--libexec/revnetgroup/hash.c214
-rw-r--r--libexec/revnetgroup/hash.h67
-rw-r--r--libexec/revnetgroup/parse_netgroup.c372
-rw-r--r--libexec/revnetgroup/revnetgroup.8137
-rw-r--r--libexec/revnetgroup/revnetgroup.c184
-rw-r--r--libexec/rexecd/Makefile7
-rw-r--r--libexec/rexecd/rexecd.818
-rw-r--r--libexec/rexecd/rexecd.c81
-rw-r--r--libexec/rlogind/Makefile17
-rw-r--r--libexec/rlogind/rlogind.830
-rw-r--r--libexec/rlogind/rlogind.c92
-rw-r--r--libexec/rpc.rquotad/Makefile10
-rw-r--r--libexec/rpc.rquotad/rpc.rquotad.861
-rw-r--r--libexec/rpc.rquotad/rquotad.c331
-rw-r--r--libexec/rpc.rstatd/Makefile10
-rw-r--r--libexec/rpc.rstatd/rpc.rstatd.861
-rw-r--r--libexec/rpc.rstatd/rstat_proc.c416
-rw-r--r--libexec/rpc.rstatd/rstatd.c118
-rw-r--r--libexec/rpc.rusersd/Makefile16
-rw-r--r--libexec/rpc.rusersd/rpc.rusersd.864
-rw-r--r--libexec/rpc.rusersd/rusers_proc.c390
-rw-r--r--libexec/rpc.rusersd/rusersd.c (renamed from libexec/bugfiler/error.c)104
-rw-r--r--libexec/rpc.rwalld/Makefile10
-rw-r--r--libexec/rpc.rwalld/rpc.rwalld.867
-rw-r--r--libexec/rpc.rwalld/rwalld.c210
-rw-r--r--libexec/rpc.sprayd/Makefile11
-rw-r--r--libexec/rpc.sprayd/rpc.sprayd.854
-rw-r--r--libexec/rpc.sprayd/sprayd.c169
-rw-r--r--libexec/rshd/Makefile18
-rw-r--r--libexec/rshd/rshd.835
-rw-r--r--libexec/rshd/rshd.c146
-rw-r--r--libexec/rtld-aout/Makefile20
-rw-r--r--libexec/rtld-aout/dynamic.h380
-rw-r--r--libexec/rtld-aout/i386/md-static-funcs.c17
-rw-r--r--libexec/rtld-aout/i386/md.c384
-rw-r--r--libexec/rtld-aout/i386/md.h245
-rw-r--r--libexec/rtld-aout/i386/mdprologue.S93
-rw-r--r--libexec/rtld-aout/md-prologue.c39
-rw-r--r--libexec/rtld-aout/rtld.1224
-rw-r--r--libexec/rtld-aout/rtld.1aout224
-rw-r--r--libexec/rtld-aout/rtld.c2120
-rw-r--r--libexec/rtld-aout/shlib.c342
-rw-r--r--libexec/rtld-aout/shlib.h43
-rw-r--r--libexec/rtld-aout/support.c86
-rw-r--r--libexec/rtld-aout/support.h35
-rw-r--r--libexec/rtld-elf/rtld.1224
-rw-r--r--libexec/talkd/Makefile3
-rw-r--r--libexec/talkd/announce.c40
-rw-r--r--libexec/talkd/print.c8
-rw-r--r--libexec/talkd/process.c25
-rw-r--r--libexec/talkd/table.c6
-rw-r--r--libexec/talkd/talkd.c8
-rw-r--r--libexec/telnetd/Makefile39
-rw-r--r--libexec/telnetd/ext.h8
-rw-r--r--libexec/telnetd/pathnames.h3
-rw-r--r--libexec/telnetd/slc.c8
-rw-r--r--libexec/telnetd/state.c96
-rw-r--r--libexec/telnetd/sys_term.c282
-rw-r--r--libexec/telnetd/telnetd.821
-rw-r--r--libexec/telnetd/telnetd.c140
-rw-r--r--libexec/telnetd/termstat.c72
-rw-r--r--libexec/telnetd/utility.c181
-rw-r--r--libexec/tftpd/Makefile3
-rw-r--r--libexec/tftpd/tftpd.815
-rw-r--r--libexec/tftpd/tftpd.c46
-rw-r--r--libexec/uucpd/Makefile6
-rw-r--r--libexec/uucpd/pathnames.h4
-rw-r--r--libexec/uucpd/uucpd.8 (renamed from libexec/bugfiler/sendbug.1)77
-rw-r--r--libexec/uucpd/uucpd.c269
-rw-r--r--libexec/xtend/Makefile14
-rw-r--r--libexec/xtend/packet.c319
-rw-r--r--libexec/xtend/paths.h13
-rw-r--r--libexec/xtend/status.c111
-rw-r--r--libexec/xtend/user.c175
-rw-r--r--libexec/xtend/xten.h60
-rw-r--r--libexec/xtend/xtend.8176
-rw-r--r--libexec/xtend/xtend.c370
-rw-r--r--libexec/xtend/xtend.h79
-rw-r--r--libexec/ypxfr/Makefile41
-rw-r--r--libexec/ypxfr/yp_dbwrite.c118
-rw-r--r--libexec/ypxfr/ypxfr.8231
-rw-r--r--libexec/ypxfr/ypxfr_extern.h63
-rw-r--r--libexec/ypxfr/ypxfr_getmap.c103
-rw-r--r--libexec/ypxfr/ypxfr_main.c567
-rw-r--r--libexec/ypxfr/ypxfr_misc.c305
-rw-r--r--libexec/ypxfr/ypxfrd_getmap.c147
221 files changed, 32132 insertions, 3343 deletions
diff --git a/libexec/Makefile b/libexec/Makefile
index 90d75f0..b38f970 100644
--- a/libexec/Makefile
+++ b/libexec/Makefile
@@ -1,10 +1,28 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id: Makefile,v 1.24 1997/02/22 14:20:52 peter Exp $
-SUBDIR= bugfiler comsat fingerd ftpd getNAME getty kpasswdd lfs_cleanerd \
- mail.local makekey rexecd rlogind rshd talkd telnetd tftpd uucpd
+SUBDIR= atrun bootpd comsat fingerd ftpd getNAME getty lfs_cleanerd \
+ mail.local makekey mknetid named-xfer revnetgroup rexecd rlogind \
+ rpc.rquotad \
+ rpc.rstatd rpc.rusersd rpc.rwalld rpc.sprayd rshd talkd tftpd uucpd \
+ xtend ypxfr
+
+.if !exists(${.CURDIR}/../eBones) || defined(NOSECURE) || !defined(MAKE_EBONES)
+SUBDIR+=telnetd
+.else
+.if defined(RELEASEDIR)
+# make release needs both
+SUBDIR+=telnetd
+.endif
+SUBDIR+= ../eBones/libexec/telnetd
+.endif
+
+# Present but disabled: kpasswdd
.if ${MACHINE} == "hp300"
SUBDIR+=rbootd
+.elif ${MACHINE} == "i386"
+SUBDIR+=rbootd
.elif ${MACHINE} == "luna68k"
SUBDIR+=rbootd
.endif
diff --git a/libexec/atrun/LEGAL b/libexec/atrun/LEGAL
new file mode 100644
index 0000000..2cd9453
--- /dev/null
+++ b/libexec/atrun/LEGAL
@@ -0,0 +1,31 @@
+# $Id$
+
+-----BEGIN PGP SIGNED MESSAGE-----
+
+Sorry for the long wait, but there still were a few things to
+be ironed out in at, which I've finally done :-)
+
+The FreeBSD team does have my permission to use at, version 2.9,
+under the BSD license.
+
+You'll find it on sunsite.unc.edu's Incoming, hopefully; the
+md5 checksum is
+
+3ba2ca3c0e87e1a04feae2c6c1376b0d at-2.9.tgz
+
+Best regards
+ Thomas
+- --
+Thomas Koenig, Thomas.Koenig@ciw.uni-karlsruhe.de, ig25@dkauni2.bitnet.
+The joy of engineering is to find a straight line on a double
+logarithmic diagram.
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.2i
+
+iQCVAwUBMCjVrPBu+cbJcKCVAQFNiQP/dpWP57s/E8plVGUD3zfgOXDmKUvg8U7a
+VwRzJrIMuSgnSJs0wkpvcomc3NLicipfX7hhWLh/xatPM2YbF7O5HZoNdvWvexD2
+1Y67zJ+0HFb1mPnSBOrS5RFiQAe3KqmGec6E14Rih/qNoFQZBVRFXZ4xxuwP+0Rs
+e2U+TVTUz6A=
+=TvyW
+-----END PGP SIGNATURE-----
diff --git a/libexec/atrun/Makefile b/libexec/atrun/Makefile
new file mode 100644
index 0000000..118bed1
--- /dev/null
+++ b/libexec/atrun/Makefile
@@ -0,0 +1,26 @@
+# $Id$
+
+MAINSRC= ${.CURDIR}/../../usr.bin/at
+
+.include "$(MAINSRC)/Makefile.inc"
+
+PROG= atrun
+MAN8= atrun.8
+SRCS= atrun.c gloadavg.c
+
+BINDIR= $(ATLIB_DIR)
+MANSRC= .
+CLEANFILES += ${MAN8}
+MANDEPEND = ${MAN8}
+
+CFLAGS+= -I$(MAINSRC) -I${.CURDIR}
+
+${MAN8}: atrun.man
+ sed -e \
+ "s@_ATSPOOL_DIR@$(ATSPOOL_DIR)@g; \
+ s@_ATJOB_DIR@$(ATJOB_DIR)@g; \
+ s@_ATLIB_DIR@$(ATLIB_DIR)@g; \
+ s@_LOADAVG_MX@$(LOADAVG_MX)@g;" \
+ < $? > $@
+
+.include <bsd.prog.mk>
diff --git a/libexec/atrun/atrun.c b/libexec/atrun/atrun.c
new file mode 100644
index 0000000..b96969d
--- /dev/null
+++ b/libexec/atrun/atrun.c
@@ -0,0 +1,486 @@
+/*
+ * atrun.c - run jobs queued by at; run with root privileges.
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * 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(S) 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 <sys/param.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.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 <utmp.h>
+#ifdef __FreeBSD__
+#include <paths.h>
+#else
+#include <getopt.h>
+#endif
+
+#if (MAXLOGNAME-1) > UT_NAMESIZE
+#define LOGNAMESIZE UT_NAMESIZE
+#else
+#define LOGNAMESIZE (MAXLOGNAME-1)
+#endif
+
+/* Local headers */
+
+#include "gloadavg.h"
+#define MAIN
+#include "privs.h"
+
+/* Macros */
+
+#ifndef ATJOB_DIR
+#define ATJOB_DIR "/usr/spool/atjobs/"
+#endif
+
+#ifndef ATSPOOL_DIR
+#define ATSPOOL_DIR "/usr/spool/atspool/"
+#endif
+
+#ifndef LOADAVG_MX
+#define LOADAVG_MX 1.5
+#endif
+
+/* File scope variables */
+
+static char *namep;
+static char rcsid[] = "$Id: atrun.c,v 1.9 1997/03/28 15:48:03 imp Exp $";
+static debug = 0;
+
+void perr(const char *a);
+
+/* Local functions */
+static int
+write_string(int fd, const char* a)
+{
+ return write(fd, a, strlen(a));
+}
+
+#undef DEBUG_FORK
+#ifdef DEBUG_FORK
+static pid_t
+myfork()
+{
+ pid_t res;
+ res = fork();
+ if (res == 0)
+ kill(getpid(),SIGSTOP);
+ return res;
+}
+
+#define fork myfork
+#endif
+
+static void
+run_file(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 sends
+ * mail to the user.
+ */
+ pid_t pid;
+ int fd_out, fd_in;
+ int queue;
+ char mailbuf[LOGNAMESIZE + 1], fmt[49];
+ char *mailname = NULL;
+ FILE *stream;
+ int send_mail = 0;
+ struct stat buf, lbuf;
+ off_t size;
+ struct passwd *pentry;
+ int fflags;
+ long nuid;
+ long ngid;
+
+
+ PRIV_START
+
+ if (chmod(filename, S_IRUSR) != 0)
+ {
+ perr("Cannot change file permissions");
+ }
+
+ PRIV_END
+
+ 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.
+ */
+
+ pentry = getpwuid(uid);
+ if (pentry == NULL)
+ {
+ syslog(LOG_ERR,"Userid %lu not found - aborting job %s",
+ (unsigned long) uid, filename);
+ exit(EXIT_FAILURE);
+ }
+ PRIV_START
+
+ stream=fopen(filename, "r");
+
+ PRIV_END
+
+#ifdef __FreeBSD__
+ if (pentry->pw_expire && time(NULL) >= pentry->pw_expire)
+ {
+ syslog(LOG_ERR, "Userid %lu is expired - aborting job %s",
+ (unsigned long) uid, filename);
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ if (stream == NULL)
+ perr("Cannot open input file");
+
+ if ((fd_in = dup(fileno(stream))) <0)
+ perr("Error duplicating input file descriptor");
+
+ if (fstat(fd_in, &buf) == -1)
+ perr("Error in fstat of input file descriptor");
+
+ if (lstat(filename, &lbuf) == -1)
+ perr("Error in fstat of input file");
+
+ if (S_ISLNK(lbuf.st_mode)) {
+ syslog(LOG_ERR,"Symbolic link encountered in job %s - aborting",
+ filename);
+ exit(EXIT_FAILURE);
+ }
+ if ((lbuf.st_dev != buf.st_dev) || (lbuf.st_ino != buf.st_ino) ||
+ (lbuf.st_uid != buf.st_uid) || (lbuf.st_gid != buf.st_gid) ||
+ (lbuf.st_size!=buf.st_size)) {
+ syslog(LOG_ERR,"Somebody changed files from under us for job %s - "
+ "aborting",filename);
+ exit(EXIT_FAILURE);
+ }
+ if (buf.st_nlink > 1) {
+ syslog(LOG_ERR,"Someboy is trying to run a linked script for job %s",
+ filename);
+ exit(EXIT_FAILURE);
+ }
+ if ((fflags = fcntl(fd_in, F_GETFD)) <0)
+ perr("Error in fcntl");
+
+ fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC);
+
+ snprintf(fmt, 49, "#!/bin/sh\n# atrun uid=%%ld gid=%%ld\n# mail %%%ds %%d",
+ LOGNAMESIZE);
+ if (fscanf(stream, fmt, &nuid, &ngid, mailbuf, &send_mail) != 4) {
+ syslog(LOG_ERR,"File %s is in wrong format - aborting", filename);
+ exit(EXIT_FAILURE);
+ }
+ if (mailbuf[0] == '-') {
+ syslog(LOG_ERR,"illegal mail name %s in %s",mailbuf,filename);
+ exit(EXIT_FAILURE);
+ }
+ mailname = mailbuf;
+ if (nuid != uid) {
+ syslog(LOG_ERR,"Job %s - userid %d does not match file uid %d",
+ filename, nuid, uid);
+ exit(EXIT_FAILURE);
+ }
+ if (ngid != gid) {
+ syslog(LOG_ERR,"Job %s - groupid %d does not match file gid %d",
+ filename, ngid, gid);
+ exit(EXIT_FAILURE);
+ }
+ fclose(stream);
+ if (chdir(ATSPOOL_DIR) < 0)
+ perr("Cannot chdir to " ATSPOOL_DIR);
+
+ /* 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(ATJOB_DIR) < 0)
+ perr("Cannot chdir to " ATJOB_DIR);
+
+ queue = *filename;
+
+ PRIV_START
+
+ nice(tolower(queue) - 'a');
+
+ if (chdir(pentry->pw_dir))
+ chdir("/");
+
+ if (initgroups(pentry->pw_name,pentry->pw_gid))
+ perr("Cannot delete saved userids");
+
+ if (setgid(gid) < 0)
+ perr("Cannot change group");
+
+ if (setuid(uid) < 0)
+ perr("Cannot set user id");
+
+ if(execle("/bin/sh","sh",(char *) NULL, nenvp) != 0)
+ perr("Exec failed for /bin/sh");
+
+ PRIV_END
+ }
+ /* We're the parent. Let's wait.
+ */
+ close(fd_in);
+ close(fd_out);
+ waitpid(pid, (int *) NULL, 0);
+
+ /* Send mail. Unlink the output file first, so it is deleted after
+ * the run.
+ */
+ stat(filename, &buf);
+ if (open(filename, O_RDONLY) != STDIN_FILENO)
+ perr("Open of jobfile failed");
+
+ unlink(filename);
+ if ((buf.st_size != size) || send_mail)
+ {
+ PRIV_START
+
+ if (chdir(pentry->pw_dir))
+ chdir("/");
+
+ if (initgroups(pentry->pw_name,pentry->pw_gid))
+ perr("Cannot delete saved userids");
+
+ if (setgid(gid) < 0)
+ perr("Cannot change group");
+
+ if (setuid(uid) < 0)
+ perr("Cannot set user id");
+
+#ifdef __FreeBSD__
+ execl(_PATH_SENDMAIL, "sendmail", "-F", "Atrun Service",
+ "-odi", "-oem",
+ mailname, (char *) NULL);
+#else
+ execl(MAIL_CMD, MAIL_CMD, mailname, (char *) NULL);
+#endif
+ perr("Exec failed for mail command");
+
+ PRIV_END
+ }
+ exit(EXIT_SUCCESS);
+}
+
+/* Global functions */
+
+/* Needed in gloadavg.c */
+void
+perr(const char *a)
+{
+ if (debug)
+ {
+ perror(a);
+ }
+ else
+ syslog(LOG_ERR, "%s: %m", a);
+
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+/* Browse through ATJOB_DIR, 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;
+ unsigned long ctm;
+ unsigned long jobno;
+ char queue;
+ time_t now, run_time;
+ char batch_name[] = "Z2345678901234";
+ uid_t batch_uid;
+ gid_t batch_gid;
+ int c;
+ int run_batch;
+ double load_avg = LOADAVG_MX;
+
+/* We don't need root privileges all the time; running under uid and gid daemon
+ * is fine.
+ */
+
+ RELINQUISH_PRIVS_ROOT(DAEMON_UID, DAEMON_GID)
+
+ openlog("atrun", LOG_PID, LOG_CRON);
+
+ opterr = 0;
+ errno = 0;
+ while((c=getopt(argc, argv, "dl:"))!= -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ if (sscanf(optarg, "%lf", &load_avg) != 1)
+ perr("garbled option -l");
+ if (load_avg <= 0.)
+ load_avg = LOADAVG_MX;
+ break;
+
+ case 'd':
+ debug ++;
+ break;
+
+ case '?':
+ perr("unknown option");
+ break;
+
+ default:
+ perr("idiotic option - aborted");
+ break;
+ }
+ }
+
+ namep = argv[0];
+ if (chdir(ATJOB_DIR) != 0)
+ perr("Cannot change to " ATJOB_DIR);
+
+ /* 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.
+ *
+ * Also, pick the oldest batch job to run, at most one per invocation of
+ * atrun.
+ */
+ if ((spool = opendir(".")) == NULL)
+ perr("Cannot read " ATJOB_DIR);
+
+ now = time(NULL);
+ run_batch = 0;
+ batch_uid = (uid_t) -1;
+ batch_gid = (gid_t) -1;
+
+ while ((dirent = readdir(spool)) != NULL) {
+ if (stat(dirent->d_name,&buf) != 0)
+ perr("Cannot stat in " ATJOB_DIR);
+
+ /* We don't want directories
+ */
+ if (!S_ISREG(buf.st_mode))
+ continue;
+
+ if (sscanf(dirent->d_name,"%c%5lx%8lx",&queue,&jobno,&ctm) != 3)
+ continue;
+
+ run_time = (time_t) ctm*60;
+
+ if ((S_IXUSR & buf.st_mode) && (run_time <=now)) {
+ if (isupper(queue) && (strcmp(batch_name,dirent->d_name) > 0)) {
+ run_batch = 1;
+ strncpy(batch_name, dirent->d_name, sizeof(batch_name));
+ batch_uid = buf.st_uid;
+ batch_gid = buf.st_gid;
+ }
+
+ /* The file is executable and old enough
+ */
+ if (islower(queue))
+ run_file(dirent->d_name, buf.st_uid, buf.st_gid);
+ }
+ /* Delete older files
+ */
+ if ((run_time < now) && !(S_IXUSR & buf.st_mode) && (S_IRUSR & buf.st_mode))
+ unlink(dirent->d_name);
+ }
+ /* run the single batch file, if any
+ */
+ if (run_batch && (gloadavg() < load_avg))
+ run_file(batch_name, batch_uid, batch_gid);
+
+ closelog();
+ exit(EXIT_SUCCESS);
+}
diff --git a/libexec/atrun/atrun.man b/libexec/atrun/atrun.man
new file mode 100644
index 0000000..b33de68
--- /dev/null
+++ b/libexec/atrun/atrun.man
@@ -0,0 +1,66 @@
+.\" $Id$
+.Dd April 12, 1995
+.Dt ATRUN 8
+.Os "FreeBSD 2.1"
+.Sh NAME
+.Nm atrun
+.Nd run jobs queued for later execution
+.Sh SYNOPSIS
+.Nm atrun
+.Op Fl l Ar load_avg
+.Op Fl d
+.Sh DESCRIPTION
+.Nm Atrun
+runs jobs queued by
+.Xr at 1 .
+Root's
+.Xr crontab 5
+file
+.Pa /etc/crontab
+has to contain the line
+.nf
+*/5 * * * * root _ATLIB_DIR/atrun
+.fi
+so
+.Xr atrun 8
+gets called every five minutes.
+.Pp
+At every invocation, every job in lowercase queues whose starting time
+has passed is started.
+A maximum of one batch jobs (denoted by uppercase queues) are started
+each time
+.Nm atrun
+is invoked.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl l Ar load_avg
+Specifies a limiting load factor, over which batch jobs should
+not be run, instead of the compiled \- in value of _LOADAVG_MX.
+.It Fl d
+Debug; print error messages to standard error instead of using
+.Xr syslog 3 .
+.El
+.Sh WARNINGS
+For
+.Nm atrun
+to work, you have to start up a
+.Xr cron 8
+daemon.
+.Sh FILES
+.Bl -tag -width _ATSPOOL_DIR -compact
+.It Pa _ATSPOOL_DIR
+Directory containing output spool files
+.It Pa _ATJOB_DIR
+Directory containing job files
+.El
+.Sh SEE ALSO
+.Xr cron 8 ,
+.Xr crontab 1 ,
+.Xr crontab 5 ,
+.Xr at 1 ,
+.Xr syslog 3 .
+.Sh BUGS
+The functionality of
+.Nm atrun
+should be merged into
+.Xr cron 8 .
diff --git a/libexec/atrun/gloadavg.c b/libexec/atrun/gloadavg.c
new file mode 100644
index 0000000..289fa29
--- /dev/null
+++ b/libexec/atrun/gloadavg.c
@@ -0,0 +1,69 @@
+/*
+ * gloadavg.c - get load average for Linux
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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(S) 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.
+ */
+
+#ifndef __FreeBSD__
+#define _POSIX_SOURCE 1
+
+/* System Headers */
+
+#include <stdio.h>
+#else
+#include <stdlib.h>
+#endif
+
+/* Local headers */
+
+#include "gloadavg.h"
+
+/* File scope variables */
+
+static char rcsid[] = "$Id$";
+
+/* Global functions */
+
+double
+gloadavg(void)
+/* return the current load average as a floating point number, or <0 for
+ * error
+ */
+{
+ double result;
+#ifndef __FreeBSD__
+ FILE *fp;
+
+ if((fp=fopen(PROC_DIR "loadavg","r")) == NULL)
+ result = -1.0;
+ else
+ {
+ if(fscanf(fp,"%lf",&result) != 1)
+ result = -1.0;
+ fclose(fp);
+ }
+#else
+ if (getloadavg(&result, 1) != 1)
+ perr("Error in getloadavg");
+#endif
+ return result;
+}
diff --git a/libexec/atrun/gloadavg.h b/libexec/atrun/gloadavg.h
new file mode 100644
index 0000000..24c4e12
--- /dev/null
+++ b/libexec/atrun/gloadavg.h
@@ -0,0 +1,29 @@
+/*
+ * gloadavg.h - header for atrun(8)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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(S) 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.
+ */
+
+double gloadavg(void);
+#if 0
+static char atrun_h_rcsid[] = "$Id$";
+#endif
diff --git a/libexec/bootpd/Announce b/libexec/bootpd/Announce
new file mode 100644
index 0000000..a605c6a
--- /dev/null
+++ b/libexec/bootpd/Announce
@@ -0,0 +1,65 @@
+# $Id$
+
+This is an enhanced version of the CMU BOOTP server which was derived
+from the original BOOTP server created by Bill Croft at Stanford.
+This version merges most of the enhancements and bug-fixes from the
+NetBSD, Columbia, and other versions.
+
+New features in version 2.4 include:
+
+ Added a simple BOOTP gateway program: bootpgw
+ Allow host name anywhere IP address is expected.
+ Automatically lookup the IP address when the name of a
+ bootptab entry is a valid hostname.
+ (Dummy entries names should start with '.')
+ Merged changes from NetBSD and Columbia versions.
+ Merged changes for Solaris-2.X and SVR4 systems.
+ Combined bootptest into the bootp release.
+ Merged tag 18 support (:ef=...:) from Jason Zions.
+ Use :ef=extension_file_name: and make the
+ extension files for all clients using bootpef.
+ Merged HP compatibility (:ra=...:) from David R Linn.
+ Allows you to override the reply address.
+ (i.e. send the reply to a broadcast address)
+ Add /etc/ethers support for NetBSD.
+ More systems support getether (Ultrix, OSF, NetBSD)
+ Added RFC 1533 tags 40,41,42
+ :yd=<NIS domain>:ys=<NIS server>:nt=<NTP server>:
+ ConvOldTab.sh to convert old (1.1) bootptab to new format.
+ Permits extended-length replies with more option data.
+
+Problems fixed in this version:
+
+ Fixed references to free host structures.
+ (used to cause core dump on Solaris)
+ Remove change that added null terminator to string options.
+ (this annoyed some clients...)
+ Add missing symbols to dump routine, fix order.
+ Works (again) with no -DSYSLOGD defined.
+ Fixed several more NULL references in readfile.
+ Added proper length checks to option insertions.
+ Fixed bootptest IP address printing.
+ Cleaned-up signed/unsigned and byteorder bugs.
+ Added SVR4/Streams support to getif and getether
+ Removed extra newlines in syslog messages.
+ Specify facility code when calling syslog(3)
+ When lookup_hwa fails, assume numeric HW address.
+
+Systems on which I have seen this code work:
+ NetBSD-1.0 (BSD-4.4 derivative)
+ SunOS 4.X (Solaris 1.X)
+ SunOS 5.X (Solaris 2.X)
+ System V/386 Rel. 4.0
+
+Systems on which others say this code works:
+ CDC EP/IX (1.4.3, 2.1.1)
+ DEC Ultrix (4.2, 4.3)
+ Linux 1.1.81
+ OSF/1 (DEC Alpha CPU)
+
+Please direct questions, comments, and bug reports to:
+ <bootp@andrew.cmu.edu>
+
+Gordon W. Ross Mercury Computer Systems
+gwr@mc.com 199 Riverneck Road
+508-256-1300 Chelmsford, MA 01824-2820
diff --git a/libexec/bootpd/Changes b/libexec/bootpd/Changes
new file mode 100644
index 0000000..23310e1
--- /dev/null
+++ b/libexec/bootpd/Changes
@@ -0,0 +1,294 @@
+# $Id$
+
+Changes, most recent first
+Date, <email> Real Name
+ what...
+
+--> bootp-2.4.3
+
+03/27/96 gwr@mc.com (Gordon W. Ross)
+ Use LOG_NOTICE in place of LOG_INFO for messages related
+ to unsatisfied clients [at request of <otto@tukki.jyu.fi>]
+ Fix the irix Makefile targets, and other misc.
+
+03/25/95 gwr@mc.com (Gordon W. Ross)
+ Corrected a bug I introduced into SunOS setarp, where
+ bad IP address caused "network unreachable" errors.
+ [Thanks to andrew@ntplx.net (Andrew Lindh) for the fix!]
+
+--> bootp-2.4.2
+
+01/14/95 middelin@polyware.iaf.nl (Pauline Middelink)
+ Corrected support for the Linux networking code.
+ Fixed lots of warnings (gcc -Wall)
+ Added "linux" Makefile target.
+
+01/02/95 Jukka Ukkonen <ukkonen@csc.fi>
+ Allow bootptab syntax: ha="0:0:c0:80:e8:a7"
+
+11/30/94 Tonny van Lankveld <A.L.M.G.v.Lankveld@urc.tue.nl>
+ Fix reporting of duplicate Ethernet addresses.
+
+09/06/94 longyear@netcom.com (Al Longyear)
+ Better setarp for linux, allows non-ether types.
+
+09/02/94 Robert MacKinnon <rbm@montrouge.mis.slb.com>
+ Add support for IBM's AIX 3.2.5
+
+08/30/94 piercarl@ltd.c-d.com (Piercarlo Grandi)
+ Fix select calls on linux (modifies timeval arg).
+ Fix setarp (specify Ethernet type for now).
+
+08/27/94 drew@drewsun.FEITH.COM (Andrew B. Sudell)
+ Add support for Wollongong Win-TCP (SysVr4 variant).
+
+08/24/94 gwr@mc.com (Gordon W. Ross)
+ Use sigaction() on systems that define SA_NOCLDSTOP
+ (a symbol required by POSIX) for HP/UX and others.
+
+--> bootp-2.4.1
+
+08/24/94 gwr@mc.com (Gordon W. Ross)
+ Fix bug in boot file name generation (missing init)
+
+--> bootp-2.4.0
+
+08/20/94 gwr@mc.com (Gordon W. Ross)
+ Fix code to build bootfile name based on combination of
+ client requested name and bootfile specifications.
+ Behave similarly with or without CHECK_FILE_ACCESS.
+
+07/30/94 Dirk Koeppen <dirk@incom.de>
+ Add "min wait" option (mw) to cause bootpd to ignore
+ requests from clients that have not waited long enough.
+ Add code to honor client requests containing the DHCP
+ option "Maximum Message Size" and use its value to
+ determine the size of the reply message.
+
+--> bootp-2.3.8
+
+06/25/94 Christos Zoulas <christos@deshaw.com>
+ Add "-h" flag to override host name (affects default IP
+ address provided in reply messages. (Also minor bug fix)
+
+05/27/94 gwr@mc.com (Gordon W. Ross)
+ Add code to call "arp -s IPADDR HWADDR" on systems
+ that do not provide an SIOCSARP ioctl (i.e. NetBSD)
+
+--> bootp-2.3.7
+
+05/05/94 Walter Wong <wcw+@CMU.EDU>
+ Reduce noize at debug level one, where log messages
+ are generated only for hosts that are recognized
+ and replied to by bootpd. (At request of HP folks.)
+
+04/30/94 gwr@mc.com (Gordon W. Ross)
+ Use memxxx functions unless USE_BFUNCS is defined.
+ Added -f <file> option to bootptest (requested file).
+
+04/29/94 tpaquett@ita.lgc.com (Trevor Paquette)
+ Remove call to haddr_conv802() in sendreply().
+ The setarp should get the non-transformed address.
+
+04/27/94 gwr@mc.com
+ Improve logic for building bootfile pathname, so a path
+ will be put in the reply if either the client or bootpd
+ specifies a boot file. (Needed for NetBSD diskless boot)
+
+04/25/94 shamash@boxhill.com (Ari Shamash)
+ Fix prs_inetaddr() so it allows '_' in hostnames.
+
+04/16/94 gwr@mc.com (Gordon W. Ross)
+ Fix setarp for SVR4 (needs to use I_STR ioctl)
+ Thanks to several people: (all sent the same fix)
+ Barney Wolff <barney@databus.com>,
+ bear@upsys.se (Bj|rn Sj|holm),
+ Michael Kuschke <Michael.Kuschke@Materna.DE>,
+
+03/25/95 Ulrich Heuer </I=zhhi9/G=Ulrich/S=Heuer/@zhflur.ubs.ubs.ch>
+ Make option string lengths not include a null terminator.
+ The trailing null breaks some clients.
+
+03/15/94 "Edmund J. Sutcliffe" <ejs1@tower.york.ac.uk>
+ Add support for the "EX" option: Execute a program
+ before sending a BOOTREPLY to a client. Support for
+ this option is conditional on YORK_EX_OPTION.
+
+03/10/94 Nigel Metheringham <nigelm@ohm.york.ac.uk>
+ Make getether.c work on Linux.
+
+03/09/94 Koch@Math.Uni-Duisburg.DE (Peter Koch)
+ Add missing MANDIR definition to Makefile.
+
+03/08/94 Jeroen.Scheerder@let.ruu.nl
+ Fix args to report in getether code for Ultrix.
+ Run install individually for each program.
+
+--> bootp-2.3.6
+03/07/94 gwr@mc.com
+ Cleanup for release (run gnu indent, tab-size=4)
+
+02/24/94 Jeroen.Scheerder@let.ruu.nl
+ Allow underscore in host names - readfile.c:goodname()
+ Add ConvOldTab.sh - converts 1.1 bootptab to new format.
+
+02/20/94 gwr@mc.com (Gordon W. Ross)
+ Make readfile tolerant of hardware addresses that start
+ with a letter. (If lookup_hwa() fails, assume numeric.)
+ Fix whitespace skip before :vm= auto: and avoid lookup.
+
+02/12/94 walker@zk3.dec.com (Mary Walker)
+ Added support for 64-bit longs (for the DEC Alpha)
+ Allow ieee802 hardware address in bit-reversed oreder
+
+02/07/94 hl@tekla.fi (Harald Lundberg)
+ Fix conflict with DUMP_FILE in syslog.h on OSF1
+ Use int for (struct bootp).bp_xid (for DEC Alpha)
+ Added Ultrix support to bootptest (getether)
+
+02/06/94 brezak@ch.hp.com (John Brezak)
+ Add man-page and install targets to Makefile.NetBSD
+ Add getether support for NetBSD
+
+02/05/94 gwr@mc.com (Gordon W. Ross)
+ Added tags 40,41,42 (NIS domain, NIS server, NTP server)
+ Add stub to getether for machines not yet supported.
+
+--> bootp-2.3.5
+01/29/94 gwr@mc.com (Gordon W. Ross)
+ Make bootpgw put a correct address in "giaddr" when
+ the client request came via broadcast.
+
+01/22/94 gwr@mc.com (Gordon W. Ross)
+ Fix syslog call (missing "facility" code)
+ Add SVR4/Streams support to getif() and getether()
+ Fix getif bug (matched when it should not)
+ Macro-ize lots of similar cases in readfile.c
+
+12/27/93 brezak@ch.hp.com (John Brezak)
+ Remove all newlines passed to syslog(3)
+ Add /etc/ethers support for NetBSD.
+
+12/18/93 gwr@mc.com (Gordon W. Ross)
+ Fix bootptest IP address printing.
+ Fix byte-order bugs in bootpgw and bootptest.
+ Clean-up signed/unsigned mismatches.
+ Back out SLIP support changes for now
+ (code fragment saved in ToDo).
+
+--> bootp-2.3.4 (beta test release)
+12/12/93 gwr@mc.com (Gordon W. Ross)
+ Fixed several more NULL references in readfile.
+ Added proper length checks to option insertions.
+
+--> bootp-2.3.3 (beta test release)
+12/09/93 gwr@mc.com (Gordon W. Ross)
+ Added ASSERT checks to readfile.c:fill_defaults()
+
+12/08/93 brezak@ch.hp.com (John Brezak)
+ New Makefile.NetBSD
+ Added setsid() and #ifdef TIOCNOTTY
+ (bootpd.c, bootpgw.c)
+ Moved #include <net/if.h> out of #ifdef SUNOS
+ Fixed several multiple declaration problems
+
+12/04/93 gwr@mc.com (Gordon W. Ross)
+ Re-implemented Extension File support
+ based on work by Jason Zions <jazz@hal.com>
+ Added support for Reply-Address-Override to support
+ HP clients (need reply sent to broadcast address)
+ from David R. Linn <drl@vuse.vanderbilt.edu>
+
+--> bootp-2.3.2 (beta test release)
+11/27/93 gwr@mc.com (Gordon W. Ross)
+ Incorporated bootptest into the bootp release.
+ Added ANSI function prototypes everywhere.
+
+11/17/93 dpm@depend.com (David P. Maynard)
+ Added automatic SLIP address determination.
+ (This is NOT dynamic IP address assignment.)
+ Cleaned up some type warnings from gcc.
+
+11/11/93 gwr@mc.com (Gordon W. Ross)
+ Works (again) with no -DSYSLOGD defined.
+ Provide a default value for the subnet mask.
+ More #ifdef's for SunOS specific code (lookup_hwa)
+ Added a simple BOOTP gateway program: bootpgw
+ Reorganized for more code sharing (with bootpgw)
+
+--> bootp-2.3.1 (alpha test release)
+11/08/93 gwr@mc.com (Gordon W. Ross)
+ Back-out changes to honor option structure in request
+ (this needs to be a per-client option).
+ Merged changes from NetBSD and Columbia versions.
+ Allow host name anywhere IP address is expected.
+ Add null terminators to option strings.
+ Add missing symbols to dump routine, dump symbols
+ in alphabetical order, one tag per line.
+
+--> bootp-2.2.D (posted as patch 2)
+10/19/93 gwr@mc.com (Gordon W. Ross)
+ Fix references to free memory (leads to core dumps).
+
+--> bootp-2.2.C (posted as patch 1)
+10/14/93 gwr@mc.com (Gordon W. Ross)
+ Fix data access alignment problems on SPARC/Solaris.
+
+--> bootp-2.2.B (posted to usenet)
+10/11/93 gwr@mc.com (Gordon W. Ross)
+ Allow extended-length BOOTP packets (more vendor options)
+ Honor option format specified in client requests.
+ Added Solaris-2.X changes from db@sunbim.be (Danny Backx).
+
+All history before this point may be inaccurate. Please send
+changes if any of the credits are incorrect. -gwr
+
+--> bootp-2.2+NetBSD released
+08/27/93 brezak@ch.hp.com (John Brezak)
+ Added RFC 1396 support (tags 14-17)
+
+--> bootp-2.2+NetBSD (version?)
+??/??/93 mckim@lerc.nasa.gov (Jim McKim)
+ Ported to NetBSD (see Makefile.NetBSD)
+ Set server host name in responses.
+ Check all interfaces in address match routine.
+
+--> bootp-2.2+FdC released
+01/27/93 <fdc@watsun.cc.columbia.edu> Frank da Cruz
+ Added RFC 1395 information: Merit dump file,
+ client domain name, swap server address, root path.
+
+--> bootp-2.2alpha released
+11/14/91 <walt+@cmu.edu> Walter L. Wimer
+ Add "td" to TFTP directory for "secure" (chroot) TFTP.
+ Add "sa" tag to set explicit server address.
+ Automatically determine if child of inetd.
+ Use RFC 1048 format when request has magic number zero.
+ Fixed various bugs. Give bootptab a separate man page.
+
+--> bootp-2.1 released
+01/09/89 <walt+@cmu.edu> Walter L. Wimer
+ Check world read bit on TFTP boot file.
+ Add support for rfc1085 "bootfile size" tag.
+ Add generic tags. Fix byte order of rfc1048 data.
+ Fix various crashing bugs.
+
+--> bootp-2.0 released
+07/15/88 <walt+@cmu.edu> Walter L. Wimer
+ 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.
+
+--> bootp-1.3(?) released
+07/24/87 <ddp@andrew.cmu.edu> Drew D. Perkins
+ Modified to use syslog instead of Kovar's
+ routines. Add debugging dumps. Many other fixups.
+
+--> bootp-1.2(?) released
+07/30/86 David Kovar at Carnegie Mellon University
+ Modified to work at CMU.
+
+--> bootp-1.1 released
+01/22/86 Bill Croft at Stanford University
+ Original created.
diff --git a/libexec/bootpd/ConvOldTab.sh b/libexec/bootpd/ConvOldTab.sh
new file mode 100755
index 0000000..00683f0
--- /dev/null
+++ b/libexec/bootpd/ConvOldTab.sh
@@ -0,0 +1,141 @@
+#!/bin/sh
+# convert_bootptab Jeroen.Scheerder@let.ruu.nl 02/25/94
+# This script can be used to convert bootptab files in old format
+# to new (termcap-like) bootptab files
+#
+# The old format - real entries are commented out by '###'
+#
+# Old-style bootp files consist of two sections.
+# The first section has two entries:
+# First, a line that specifies the home directory
+# (where boot file paths are relative to)
+
+###/tftpboot
+
+# The next non-empty non-comment line specifies the default bootfile
+
+###no-file
+
+# End of first section - indicated by '%%' at the start of the line
+
+###%%
+
+# The remainder of this file contains one line per client
+# interface with the information shown by the table headings
+# below. The host name is also tried as a suffix for the
+# bootfile when searching the home directory (that is,
+# bootfile.host)
+#
+# Note that htype is always 1, indicating the hardware type Ethernet.
+# Conversion therefore always yields ':ha=ether:'.
+#
+# host htype haddr iaddr bootfile
+#
+
+###somehost 1 00:0b:ad:01:de:ad 128.128.128.128 dummy
+
+# That's all for the description of the old format.
+# For the new-and-improved format, see bootptab(5).
+
+set -u$DX
+
+case $#
+in 2 ) OLDTAB=$1 ; NEWTAB=$2 ;;
+ * ) echo "Usage: `basename $0` <Input> <Output>"
+ exit 1
+esac
+
+if [ ! -r $OLDTAB ]
+then
+ echo "`basename $0`: $OLDTAB does not exist or is unreadable."
+ exit 1
+fi
+
+if touch $NEWTAB 2> /dev/null
+then
+ :
+else
+ echo "`basename $0`: cannot write to $NEWTAB."
+ exit 1
+fi
+
+
+cat << END_OF_HEADER >> $NEWTAB
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# This file was generated automagically
+
+# Blank lines and lines beginning with '#' are ignored.
+#
+# Legend: (see bootptab.5)
+# first field -- hostname (not indented)
+# bf -- bootfile
+# bs -- bootfile size in 512-octet blocks
+# cs -- cookie servers
+# df -- dump file name
+# dn -- domain name
+# ds -- domain name servers
+# ef -- extension file
+# gw -- gateways
+# ha -- hardware address
+# hd -- home directory for bootfiles
+# hn -- host name set for client
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# ra -- reply address
+# rl -- resource location protocol servers
+# rp -- root path
+# sa -- boot server address
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# td -- TFTP directory
+# to -- time offset (seconds)
+# ts -- time servers
+# vm -- vendor magic number
+# Tn -- generic option tag n
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+# Also, note that generic option data must be either a string or a
+# sequence of bytes where each byte is a two-digit hex value.
+
+# First, we define a global entry which specifies the stuff every host uses.
+# (Host name lookups are relative to the domain: your.domain.name)
+
+END_OF_HEADER
+
+# Fix up HW addresses in aa:bb:cc:dd:ee:ff and aa-bb-cc-dd-ee-ff style first
+# Then awk our stuff together
+sed -e 's/[:-]//g' < $OLDTAB | \
+nawk 'BEGIN { PART = 0 ; FIELD=0 ; BOOTPATH="unset" ; BOOTFILE="unset" }
+ /^%%/ {
+ PART = 1
+ printf ".default:\\\n\t:ht=ether:\\\n\t:hn:\\\n\t:dn=your.domain.name:\\\n\t:ds=your,dns,servers:\\\n\t:sm=255.255.0.0:\\\n\t:hd=%s:\\\n\t:rp=%s:\\\n\t:td=%s:\\\n\t:bf=%s:\\\n\t:to=auto:\n\n", BOOTPATH, BOOTPATH, BOOTPATH, BOOTFILE
+ next
+ }
+ /^$/ { next }
+ /^#/ { next }
+ {
+ if ( PART == 0 && FIELD < 2 )
+ {
+ if ( FIELD == 0 ) BOOTPATH=$1
+ if ( FIELD == 1 ) BOOTFILE=$1
+ FIELD++
+ }
+ }
+ {
+ if ( PART == 1 )
+ {
+ HOST=$1
+ HA=$3
+ IP=$4
+ BF=$5
+ printf "%s:\\\n\t:tc=.default:\\\n\t:ha=0x%s:\\\n\t:ip=%s:\\\n\t:bf=%s:\n", HOST, HA, IP, BF
+ }
+ }' >> $NEWTAB
+
+exit 0
diff --git a/libexec/bootpd/Installation b/libexec/bootpd/Installation
new file mode 100644
index 0000000..466cabc
--- /dev/null
+++ b/libexec/bootpd/Installation
@@ -0,0 +1,29 @@
+
+Installation instructions for SunOS
+
+Compile the executable:
+For SunOS 4.X:
+ make sunos4
+For SunOS 5.X: (Solaris)
+ make sunos5
+
+Install the executables:
+
+ make install
+
+Edit (or create) the bootptab:
+(See bootptab.sample and bootptab.5 manual entry)
+ edit /etc/bootptab
+
+Edit /etc/services to add these two lines:
+bootps 67/udp bootp # BOOTP Server
+bootpc 68/udp # BOOTP Client
+
+Edit /etc/inetd.conf to add the line:
+bootp dgram udp wait root /usr/etc/bootpd bootpd -i
+
+If you compiled report.c with LOG_LOCAL2 (defined in the Makefile)
+then you may want to capture syslog messages from BOOTP by changing
+your syslog.conf file. (See the sample syslog.conf file here).
+Test the change with: logger -t test -p local2.info "message"
+
diff --git a/libexec/bootpd/Makefile b/libexec/bootpd/Makefile
new file mode 100644
index 0000000..bc07225
--- /dev/null
+++ b/libexec/bootpd/Makefile
@@ -0,0 +1,17 @@
+# bootpd/Makefile
+# $Id$
+
+PROG= bootpd
+CFLAGS+= -DETC_ETHERS
+CFLAGS+= -DSYSLOG -DDEBUG -DVEND_CMU
+
+SUBDIR= bootpgw tools
+
+SRCS= bootpd.c dovend.c readfile.c hash.c dumptab.c \
+ lookup.c getif.c hwaddr.c report.c tzone.c rtmsg.c
+
+MAN5= bootptab.5
+MAN8= bootpd.8
+MLINKS= bootpd.8 bootpgw.8
+
+.include <bsd.prog.mk>
diff --git a/libexec/bootpd/Makefile.UNIX b/libexec/bootpd/Makefile.UNIX
new file mode 100644
index 0000000..50187da
--- /dev/null
+++ b/libexec/bootpd/Makefile.UNIX
@@ -0,0 +1,204 @@
+# $Id$
+#
+# Makefile for the BOOTP programs:
+# bootpd - BOOTP server daemon
+# bootpef - BOOTP extension file builder
+# bootpgw - BOOTP gateway daemon
+# bootptest - BOOTP tester (client)
+#
+
+# OPTion DEFinitions:
+# Remove the -DVEND_CMU if you don't wish to support the "CMU vendor format"
+# in addition to the RFC1048 format. Leaving out DEBUG saves little.
+OPTDEFS= -DSYSLOG -DVEND_CMU -DDEBUG
+
+# Uncomment and edit this to choose the facility code used for syslog.
+# LOG_FACILITY= "-DLOG_BOOTP=LOG_LOCAL2"
+
+# SYStem DEFinitions:
+# Either uncomment some of the following, or do:
+# "make sunos4" (or "make sunos5", etc.)
+# SYSDEFS= -DSUNOS -DETC_ETHERS
+# SYSDEFS= -DSVR4
+# SYSLIBS= -lsocket -lnsl
+
+# Uncomment this if your system does not provide streror(3)
+# STRERROR=strerror.o
+
+# FILE DEFinitions:
+# 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= -DDUMPTAB_FILE=\"/usr/etc/bootpd.dump\"
+#FILEDEFS= $(CONFFILE) $(DUMPFILE)
+
+# MORE DEFinitions (whatever you might want to add)
+# One might define NDEBUG (to remove "assert()" checks).
+MOREDEFS=
+
+INSTALL=/usr/bin/install
+DESTDIR=
+BINDIR=/usr/etc
+MANDIR=/usr/local/man
+
+CFLAGS= $(OPTDEFS) $(SYSDEFS) $(FILEDEFS) $(MOREDEFS)
+PROGS= bootpd bootpef bootpgw bootptest
+TESTS= trylook trygetif trygetea
+
+all: $(PROGS) $(TESTS)
+
+system: install
+
+install: $(PROGS)
+ -for f in $(PROGS) ;\
+ do \
+ $(INSTALL) -c -s $$f $(DESTDIR)$(BINDIR) ;\
+ done
+
+MAN5= bootptab.5
+MAN8= bootpd.8 bootpef.8 bootptest.8
+install.man: $(MAN5) $(MAN8)
+ -for f in $(MAN5) ;\
+ do \
+ $(INSTALL) -c -m 644 $$f $(DESTDIR)$(MANDIR)/man5 ;\
+ done
+ -for f in $(MAN8) ;\
+ do \
+ $(INSTALL) -c -m 644 $$f $(DESTDIR)$(MANDIR)/man8 ;\
+ done
+
+clean:
+ -rm -f core *.o
+ -rm -f $(PROGS) $(TESTS)
+
+distclean:
+ -rm -f *.BAK *.CKP *~ .emacs*
+
+#
+# Handy targets for systems needing special treatment:
+# (Most POSIX systems should work with just "make all")
+#
+
+# DEC/OSF1 on the Alpha
+alpha:
+ $(MAKE) SYSDEFS="-DETC_ETHERS -Dint32=int -D_SOCKADDR_LEN" \
+ STRERROR=strerror.o
+
+# Control Data EP/IX 1.4.3 system, BSD 4.3 mode
+epix143:
+ $(MAKE) CC="cc -systype bsd43" \
+ SYSDEFS="-Dconst= -D_SIZE_T -DNO_UNISTD -DUSE_BFUNCS" \
+ STRERROR=strerror.o
+
+# Control Data EP/IX 2.1.1 system, SVR4 mode
+epix211:
+ $(MAKE) CC="cc -systype svr4" \
+ SYSDEFS="-DSVR4" \
+ SYSLIBS="-lsocket -lnsl"
+
+# IRIX 5.X (Silicon Graphics)
+irix:
+ $(MAKE) SYSDEFS= SYSLIBS=
+
+# Linux 1.1.80+ on [34]86
+linux:
+ $(MAKE) SYSDEFS="-O6 -Wall -fomit-frame-pointer"
+
+# SunOS 4.X
+sunos4:
+ $(MAKE) SYSDEFS="-DSUNOS -DETC_ETHERS" \
+ STRERROR=strerror.o
+
+# Solaris 2.X (i.e. SunOS 5.X)
+sunos5:
+ $(MAKE) SYSDEFS="-DSVR4 -DETC_ETHERS" \
+ SYSLIBS="-lsocket -lnsl"
+
+# Solaris 2.X (i.e. SunOS 5.X) with GCC. Note that GCC normally
+# defines __STDC__=1 which breaks many Solaris header files...
+sunos5gcc:
+ $(MAKE) SYSDEFS="-DSVR4 -DETC_ETHERS -D__STDC__=0" \
+ SYSLIBS="-lsocket -lnsl" CC="gcc -Wall"
+
+# UNIX System V Rel. 3
+svr3:
+ $(MAKE) SYSDEFS="-DSYSV"
+
+# UNIX System V Rel. 4
+svr4:
+ $(MAKE) SYSDEFS="-DSVR4" \
+ SYSLIBS="-lsocket -lnsl"
+
+# AT&T/GIS - Both AT&T StarServer and NCR 3000
+# may work for others using Wollongong's WIN-TCP
+wollongong gis :
+ $(MAKE) SYSDEFS="-DSVR4 -DWIN_TCP" \
+ SYSLIBS="-lsocket -lnsl"
+
+#
+# How to build each program:
+#
+
+OBJ_D= bootpd.o dovend.o readfile.o hash.o dumptab.o \
+ lookup.o getif.o hwaddr.o tzone.o report.o $(STRERROR)
+bootpd: $(OBJ_D)
+ $(CC) -o $@ $(OBJ_D) $(SYSLIBS)
+
+OBJ_EF= bootpef.o dovend.o readfile.o hash.o dumptab.o \
+ lookup.o hwaddr.o tzone.o report.o $(STRERROR)
+bootpef: $(OBJ_EF)
+ $(CC) -o $@ $(OBJ_EF) $(SYSLIBS)
+
+OBJ_GW= bootpgw.o getif.o hwaddr.o report.o $(STRERROR)
+bootpgw: $(OBJ_GW)
+ $(CC) -o $@ $(OBJ_GW) $(SYSLIBS)
+
+OBJ_TEST= bootptest.o print-bootp.o getif.o getether.o \
+ report.o $(STRERROR)
+bootptest: $(OBJ_TEST)
+ $(CC) -o $@ $(OBJ_TEST) $(SYSLIBS)
+
+# This is just for testing the lookup functions.
+TRYLOOK= trylook.o lookup.o report.o $(STRERROR)
+trylook : $(TRYLOOK)
+ $(CC) -o $@ $(TRYLOOK) $(SYSLIBS)
+
+# This is just for testing getif.
+TRYGETIF= trygetif.o getif.o report.o $(STRERROR)
+trygetif : $(TRYGETIF)
+ $(CC) -o $@ $(TRYGETIF) $(SYSLIBS)
+
+# This is just for testing getether.
+TRYGETEA= trygetea.o getether.o report.o $(STRERROR)
+trygetea : $(TRYGETEA)
+ $(CC) -o $@ $(TRYGETEA) $(SYSLIBS)
+
+# This rule just keeps the LOG_BOOTP define localized.
+report.o : report.c
+ $(CC) $(CFLAGS) $(LOG_FACILITY) -c $<
+
+# Punt SunOS -target noise
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+#
+# Header file dependencies:
+#
+
+bootpd.o : bootp.h bptypes.h hash.h hwaddr.h bootpd.h dovend.h
+bootpd.o : readfile.h report.h tzone.h patchlevel.h getif.h
+bootpef.o : bootp.h bptypes.h hash.h hwaddr.h bootpd.h dovend.h
+bootpef.o : readfile.h report.h tzone.h patchlevel.h
+bootpgw.o : bootp.h bptypes.h getif.h hwaddr.h report.h patchlevel.h
+bootptest.o : bootp.h bptypes.h bootptest.h getif.h patchlevel.h
+dovend.o : bootp.h bptypes.h bootpd.h hash.h hwaddr.h report.h dovend.h
+dumptab.o : bootp.h bptypes.h hash.h hwaddr.h report.h patchlevel.h bootpd.h
+getif.o : getif.h report.h
+hash.o : hash.h
+hwaddr.o : bptypes.h hwaddr.h report.h
+lookup.o : bootp.h bptypes.h lookup.h report.h
+print-bootp.o : bootp.h bptypes.h bootptest.h
+readfile.o : bootp.h bptypes.h hash.h hwaddr.h lookup.h readfile.h
+readfile.o : report.h tzone.h bootpd.h
+report.o : report.h
+tzone.o : bptypes.h report.h tzone.h
diff --git a/libexec/bootpd/Makefile.inc b/libexec/bootpd/Makefile.inc
new file mode 100644
index 0000000..d055f52
--- /dev/null
+++ b/libexec/bootpd/Makefile.inc
@@ -0,0 +1,3 @@
+# $Id$
+
+BINDIR?= /usr/libexec
diff --git a/libexec/bootpd/Problems b/libexec/bootpd/Problems
new file mode 100644
index 0000000..bec9ac0
--- /dev/null
+++ b/libexec/bootpd/Problems
@@ -0,0 +1,66 @@
+# $Id$
+
+Common problems and ways to work around them:
+
+Bootpd complains: "bind: Address already in use" and fails to start.
+ You are already running something that has bound the
+ BOOTP listening port number. Check /etc/inetd.conf or
+ the equivalent for a bootp line (or in startup files).
+
+Bootpd complains that it "can not get IP addr for HOSTNAME"
+
+ If the entry is a "dummy" (not a real host) used only for
+ reference by other entries, put '.' in front of the name.
+
+ If the entry is for a real client and the IP address for
+ the client can not be found using gethostbyname(), specify
+ the IP address for the client using numeric form.
+
+Bootpd takes a long time to finish parsing the bootptab file:
+
+ Excessive startup time is usually caused by waiting for
+ timeouts on failed DNS lookup operations. If this is the
+ problem, find the client names for which DNS lookup fails
+ and change the bootptab to specify the IP addresses for
+ those clients using numeric form.
+
+ When bootptab entries do not specify an ip address, bootpd
+ attempts to lookup the tagname as a host name to find the
+ IP address. To suppress this default action, either make
+ the entry a "dummy" or specify its IP numeric address.
+
+ If your DNS lookups work but are just slow, consider either
+ running bootpd on the same machine as the DNS server or
+ running a caching DNS server on the host running bootpd.
+
+My huge bootptab file causes startup time to be so long that clients
+give up waiting for a reply.
+
+ Truly huge bootptab files make "inetd" mode impractical.
+ Start bootpd in "standalone" mode when the server boots.
+
+ Another possibility is to run one bootpd on each network
+ segment so each one can have a smaller bootptab. Only one
+ instance of bootpd may run on one server, so you would need
+ to use a different server for each network segment.
+
+My bootp clients are given responses with a boot file name that is
+not a fully specified path.
+
+ Make sure the TFTP directory or home directory tags are set:
+ :td=/tftpboot: (or)
+ :hd=/usr/boot: (for example)
+
+My PC clients running Sun's PC-NFS Pro v1.1 fail to receive
+acceptable responses from the bootp server.
+
+ These clients send a request with the DHCP "message length"
+ option and the (new) BOOTP "broadcast flag" both set.
+ The bootp server (on SunOS) will send a fragmented reply
+ unless you override the length with :ms=1024: (or less).
+ The "broadcast flag" is not yet supported, but there is
+ a simple work-around, just add :ra=255.255.255.255:
+ for any clients that need their reply broadcasted.
+ You may need to use a differnet broadcast address.
+ (Thanks to Ivan Auger <ivan.auger@wadsworth.org>)
+
diff --git a/libexec/bootpd/README b/libexec/bootpd/README
new file mode 100644
index 0000000..ddfaebe
--- /dev/null
+++ b/libexec/bootpd/README
@@ -0,0 +1,136 @@
+# $Id$
+
+This is an enhanced version of the CMU BOOTP server which was derived
+from the original BOOTP server created by Bill Croft at Stanford.
+This version merges all the enhancements and bug-fixes from the
+NetBSD, Columbia, and other versions.
+
+Please direct questions, comments, and bug reports to the list:
+ <bootp@andrew.cmu.edu>
+
+You can subscribe to this mailing list by sending mail to:
+ bootp-request@andrew.cmu.edu
+(The body of the message should contain: "Add <your-address>")
+
+[ From the NetBSD README file: ]
+
+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.
+
+[ From the CMU README file: ]
+
+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 # BOOTP Server
+ bootpc 68/udp # BOOTP Client
+
+4) Edit the bootptab. It has some explanitory comments, and there
+ is a manual entry describing its format (bootptab.5)
+ If you have any questions, just let us know.
+
+Construction:
+ [ See the file Installation which is more up-to-date. -gwr ]
+
+ 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. The following is a sample /etc/inetd.conf entry:
+ # BOOTP server
+ bootps dgram udp wait root /usr/etc/bootpd bootpd -i
+
+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
+
+[ Contents description by file: ]
+
+Announce* Text of release announcements
+Changes Change history, reverse chronological
+ConvOldTab.sh Script to convert old (1.x) bootptab files
+Installation Instructions for building and installing
+Makefile* for "make"
+README This file
+ToDo Things not yet done
+bootp.h The protocol header file
+bootpd.8 Manual page for bootpd, boopgw
+bootpd.c BOOTP server main module
+bootpd.h header for above (and others)
+bootpef.8 Manual page for bootpef
+bootpef.c BOOTP extension file compiler
+bootpgw.c BOOTP gateway main module
+bootptab.5 A manual describing the bootptab format
+bootptab.cmu A sample database file for the server
+bootptab.mcs Another sample from <gwr@mc.com>
+bootptest.8 Manual page for bootptest
+bootptest.c BOOTP test program (fake client)
+bootptest.h header for above
+dovend.c Vendor Option builder (for bootpd, bootpef)
+dovend.h header for above
+dumptab.c Implements debugging dump for bootpd
+getether.c For bootptest (not used yet)
+getether.h header for above
+getif.c Get network interface info.
+getif.h header for above
+hash.c The hash table module
+hash.h header for above
+hwaddr.c Hardware address support
+hwaddr.h header for above
+lookup.c Internet Protocol address lookup
+lookup.h header for above
+patchlevel.h Holds version numbers
+print-bootp.c Prints BOOTP packets (taken from BSD tcpdump)
+readfile.c The configuration file-reading routines
+readfile.h header for above
+report.c Does syslog-style messages
+report.h header for above
+strerror.c Library errno-to-string (for systems lacking it)
+syslog.conf Sample config file for syslogd(8)
+syslog.h For systems that lack syslog(3)
+try*.c Test programs (for debugging)
+tzone.c Get timezone offset
+tzone.h header for above
diff --git a/libexec/bootpd/ToDo b/libexec/bootpd/ToDo
new file mode 100644
index 0000000..261d24c
--- /dev/null
+++ b/libexec/bootpd/ToDo
@@ -0,0 +1,61 @@
+ToDo: -*- text -*-
+
+----------------------------------------------------------------------
+Memory allocation locality:
+
+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. . . .
+
+----------------------------------------------------------------------
+Input parser:
+
+The reader implemented in readfile.c could use improvement. Some sort
+of "data-driven" parser should be used so the big switch statements
+would have only one case for each data type instead of one case for
+every recognized option symbol. Then adding a new tag would involve
+only adding a new element to the data table describing known symbols.
+Hopefully, this would shrink the code a bit too. -gwr
+
+----------------------------------------------------------------------
+SLIP Initialization via BOOTP:
+
+In the function handle_request(), both in bootpd and bootpgw,
+we might want to add code like the following just before testing
+the client IP address field for zero. (bp->bp_ciaddr == 0)
+(David suggests we leave this out for now. -gwr)
+
+#if 1 /* XXX - Experimental */
+ /*
+ * SLIP initialization support.
+ *
+ * If this packet came from a SLIP driver that does
+ * automatic IP address initialization, then the socket
+ * will have the IP address and the packet will
+ * have zeros for both the IP and HW addresses.
+ *
+ * Thanks to David P. Maynard <dpm@depend.com>
+ * for explaining how this works. -gwr
+ */
+ if ((bp->bp_ciaddr.s_addr == 0) &&
+ (bp->bp_htype == 0))
+ {
+ /* Pretend the client knows its address. It will soon. */
+ bp->bp_ciaddr = recv_addr.sin_addr;
+ if (debug)
+ report(LOG_INFO, "fixed blank request from IP addr %s",
+ inet_ntoa(recv_addr.sin_addr));
+ }
+#endif
+
+----------------------------------------------------------------------
+DHCP Support:
+
+There is a set of patches from Jeanette Pauline Middelink
+<middelin@calvin.polyware.iaf.nl> to add DHCP support.
+
+Those patches will be integrated into the BOOTP release stream
+very soon, but if you can't wait, you can get them from:
+nimbus.anu.edu.au:/pub/tridge/samba/contributed/DHCP.patch
+
+----------------------------------------------------------------------
diff --git a/libexec/bootpd/bootp.h b/libexec/bootpd/bootp.h
new file mode 100644
index 0000000..88f7ed2
--- /dev/null
+++ b/libexec/bootpd/bootp.h
@@ -0,0 +1,147 @@
+/************************************************************************
+ 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.
+************************************************************************/
+
+/*
+ * Bootstrap Protocol (BOOTP). RFC951 and RFC1395.
+ *
+ * $Id$
+ *
+ *
+ * This file specifies the "implementation-independent" BOOTP protocol
+ * information which is common to both client and server.
+ *
+ */
+
+#include "bptypes.h" /* for int32, u_int32 */
+
+#define BP_CHADDR_LEN 16
+#define BP_SNAME_LEN 64
+#define BP_FILE_LEN 128
+#define BP_VEND_LEN 64
+#define BP_MINPKTSZ 300 /* to check sizeof(struct bootp) */
+
+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 int32 bp_xid; /* transaction ID */
+ unsigned short bp_secs; /* seconds since boot began */
+ unsigned short bp_flags; /* RFC1532 broadcast, etc. */
+ 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 */
+ char bp_sname[BP_SNAME_LEN]; /* server host name */
+ char bp_file[BP_FILE_LEN]; /* boot file name */
+ unsigned char bp_vend[BP_VEND_LEN]; /* vendor-specific area */
+ /* note that bp_vend can be longer, extending to end of packet. */
+};
+
+/*
+ * 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_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 }
+
+
+
+/*
+ * Tag values used to specify what information is being supplied in
+ * the vendor (options) data area of the packet.
+ */
+/* RFC 1048 */
+#define TAG_END ((unsigned char) 255)
+#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_HOST_NAME ((unsigned char) 12)
+#define TAG_BOOT_SIZE ((unsigned char) 13)
+/* RFC 1395 */
+#define TAG_DUMP_FILE ((unsigned char) 14)
+#define TAG_DOMAIN_NAME ((unsigned char) 15)
+#define TAG_SWAP_SERVER ((unsigned char) 16)
+#define TAG_ROOT_PATH ((unsigned char) 17)
+/* RFC 1497 */
+#define TAG_EXTEN_FILE ((unsigned char) 18)
+/* RFC 1533 */
+#define TAG_NIS_DOMAIN ((unsigned char) 40)
+#define TAG_NIS_SERVER ((unsigned char) 41)
+#define TAG_NTP_SERVER ((unsigned char) 42)
+/* DHCP maximum message size. */
+#define TAG_MAX_MSGSZ ((unsigned char) 57)
+
+/* XXX - Add new tags here */
+
+
+/*
+ * "vendor" data permitted for CMU bootp clients.
+ */
+
+struct cmu_vend {
+ char v_magic[4]; /* magic number */
+ unsigned int32 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 */
+ int32 v_unused[6]; /* 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 0000000..5e0069c
--- /dev/null
+++ b/libexec/bootpd/bootpd.8
@@ -0,0 +1,305 @@
+.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
+.\"
+.\" $Header: /home/ncvs/src/libexec/bootpd/bootpd.8,v 1.4 1996/09/19 08:21:18 phk Exp $
+.\"
+.TH BOOTPD 8 "November 06, 1993" "Carnegie Mellon University"
+.SH NAME
+bootpd, bootpgw \- Internet Boot Protocol server/gateway
+.SH SYNOPSIS
+.B bootpd
+[
+.B \-i
+.B \-s
+.B \-t
+timeout
+.B \-d
+level
+.B \-c
+chdir\-path
+]
+[
+.I bootptab
+[
+.I dumpfile
+] ]
+.br
+.B bootpgw
+[
+.B \-i
+.B \-s
+.B \-t
+timeout
+.B \-d
+level
+] server
+.SH DESCRIPTION
+.I Bootpd
+implements an Internet Bootstrap Protocol (BOOTP) server as defined in
+RFC951, RFC1532, and RFC1533.
+.I Bootpgw
+implements a simple BOOTP gateway which can be used to forward
+requests and responses between clients on one subnet and a
+BOOTP server (i.e.
+.IR bootpd )
+on another subnet. While either
+.I bootpd
+or
+.I bootpgw
+will forward BOOTREPLY packets, only
+.I bootpgw
+will forward BOOTREQUEST packets.
+.PP
+One host on each network segment is normally configured to run either
+.I bootpd
+or
+.I bootpgw
+from
+.I inetd
+by including one of the following lines in the file
+.IR /etc/inetd.conf :
+.IP
+bootps dgram udp wait root /usr/libexec/bootpd bootpd /etc/bootptab
+.br
+bootps dgram udp wait root /usr/libexec/bootpgw bootpgw server
+.PP
+This mode of operation is referred to as "inetd mode" and causes
+.I bootpd
+(or
+.IR bootpgw )
+to be started only when a boot request arrives. If it does not
+receive another packet within fifteen minutes of the last one
+it received, it will exit to conserve system resources. The
+.B \-t
+option controls this timeout (see OPTIONS).
+.PP
+It is also possible to run
+.I bootpd
+(or
+.IR bootpgw )
+in "standalone mode" (without
+.IR inetd )
+by simply invoking it from a shell like any other regular command.
+Standalone mode is particularly useful when
+.I bootpd
+is used with a large configuration database, where the start up
+delay might otherwise prevent timely response to client requests.
+(Automatic start up in standalone mode can be done by invoking
+.I bootpd
+from within
+.IR /etc/rc.local ,
+for example.)
+Standalone mode is less useful for
+.I bootgw
+which
+has very little start up delay because
+it does not read a configuration file.
+.PP
+Either program automatically detects whether it was invoked from inetd
+or from a shell and automatically selects the appropriate mode.
+The
+.B \-s
+or
+.B \-i
+option may be used to force standalone or inetd mode respectively
+(see OPTIONS).
+.SH OPTIONS
+.TP
+.BI \-t \ timeout
+Specifies the
+.I timeout
+value (in minutes) that a
+.I bootpd
+or
+.I bootpgw
+process will wait for a BOOTP packet before exiting.
+If no packets are recieved for
+.I timeout
+seconds, then the program will exit.
+A timeout value of zero means "run forever".
+In standalone mode, this option is forced to zero.
+.TP
+.BI \-d \ debug\-level
+Sets the
+.I debug\-level
+variable that controls the amount of debugging messages generated.
+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.
+.TP
+.BI \-c \ chdir\-path
+Sets the current directory used by
+.I bootpd
+while checking the existence and size of client boot files. This is
+useful when client boot files are specified as relative pathnames, and
+.I bootpd
+needs to use the same current directory as the TFTP server
+(typically /tftpboot). This option is not recoginzed by
+.IR bootpgw .
+.TP
+.B \-i
+Force inetd mode. This option is obsolete, but remains for
+compatibility with older versions of
+.IR bootpd .
+.TP
+.B \-s
+Force standalone mode. This option is obsolete, but remains for
+compatibility with older versions of
+.IR bootpd .
+.TP
+.I bootptab
+Specifies the name of the configuration file from which
+.I bootpd
+loads its database of known clients and client options
+.RI ( bootpd
+only).
+.TP
+.I dumpfile
+Specifies the name of the file that
+.I bootpd
+will dump its internal database into when it receives a
+SIGUSR1 signal
+.RI ( bootpd
+only). This option is only recognized if
+.I bootpd
+was compiled with the -DDEBUG flag.
+.TP
+.I server
+Specifies the name of a BOOTP server to which
+.I bootpgw
+will forward all BOOTREQUEST packets it receives
+.RI ( bootpgw
+only).
+.SH OPERATION
+.PP
+Both
+.I bootpd
+and
+.I bootpgw
+operate similarly in that both listen for any packets sent to the
+.I bootps
+port, and both simply forward any BOOTREPLY packets.
+They differ in their handling of BOOTREQUEST packets.
+.PP
+When
+.I bootpgw
+is started, it determines the address of a BOOTP server
+whose name is provided as a command line parameter. When
+.I bootpgw
+receives a BOOTREQUEST packet, it sets the "gateway address"
+and "hop count" fields in the packet and forwards the packet
+to the BOOTP server at the address determined earlier.
+Requests are forwarded only if they indicate that
+the client has been waiting for at least three seconds.
+.PP
+When
+.I bootpd
+is started it reads a configuration file, (normally
+.IR /etc/bootptab )
+that initializes the internal database of known clients and client
+options. This internal database is reloaded
+from the configuration file when
+.I bootpd
+receives a hangup signal (SIGHUP) or when it discovers that the
+configuration file has changed.
+.PP
+When
+.I bootpd
+receives a BOOTREQUEST packet, it
+.\" checks the modification time of the
+.\" configuration file and reloads the database if necessary. Then it
+looks for a database entry matching the client request.
+If the client is known,
+.I bootpd
+composes a BOOTREPLY packet using the database entry found above,
+and sends the reply to the client (possibly using a gateway).
+If the client is unknown, the request is discarded
+(with a notice if debug > 0).
+.PP
+If
+.I bootpd
+is compiled with the -DDEBUG option, receipt of a SIGUSR1 signal causes
+it to dump its internal database to the file
+.I /tmp/bootpd.dump
+or the dumpfile specified as a command line parameter.
+.PP
+During initialization, both programs
+determine the UDP port numbers to be used by calling
+.I getservbyname
+(which nomally uses
+.IR /etc/services).
+Two service names (and port numbers) are used:
+.IP
+bootps \- BOOTP Server listening port
+.br
+bootpc \- BOOTP Client destination port
+.LP
+If the port numbers cannot
+be determined using
+.I getservbyname
+then the values default to bootps=67 and bootpc=68.
+.SH FILES
+.TP 20
+/etc/bootptab
+Database file read by
+.IR bootpd .
+.TP
+/tmp/bootpd.dump
+Debugging dump file created by
+.IR bootpd .
+.TP
+/etc/services
+Internet service numbers.
+.TP
+/tftpboot
+Current directory typically used by the TFTP server and
+.IR bootpd .
+
+.SH BUGS
+Individual host entries must not exceed 1024 characters.
+
+.SH CREDITS
+.PP
+This distribution is currently maintained by
+Walter L. Wimer <walt+@cmu.edu>.
+.PP
+The original BOOTP server was created by
+Bill Croft at Stanford University in January 1986.
+.PP
+The current version of
+.I bootpd
+is primarily the work of David Kovar,
+Drew D. Perkins, and Walter L. Wimer,
+at Carnegie Mellon University.
+.TP
+Enhancements and bug\-fixes have been contributed by:
+(in alphabetical order)
+.br
+Danny Backx <db@sunbim.be>
+.br
+John Brezak <brezak@ch.hp.com>
+.br
+Frank da Cruz <fdc@cc.columbia.edu>
+.br
+David R. Linn <drl@vuse.vanderbilt.edu>
+.br
+Jim McKim <mckim@lerc.nasa.gov>
+.br
+Gordon W. Ross <gwr@mc.com>
+.br
+Jason Zions <jazz@hal.com>
+.SH "SEE ALSO"
+.LP
+bootptab(5), inetd(8), tftpd(8)
+.LP
+DARPA Internet Request For Comments:
+.TP 10
+RFC951
+Bootstrap Protocol
+.TP 10
+RFC1532
+Clarifications and Extensions for the Bootstrap Protocol
+.TP 10
+RFC1533
+DHCP Options and BOOTP Vendor Extensions
diff --git a/libexec/bootpd/bootpd.c b/libexec/bootpd/bootpd.c
new file mode 100644
index 0000000..0fe07e1
--- /dev/null
+++ b/libexec/bootpd/bootpd.c
@@ -0,0 +1,1406 @@
+/************************************************************************
+ 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.
+
+ $Id: bootpd.c,v 1.6 1997/02/22 14:21:02 peter Exp $
+
+************************************************************************/
+
+/*
+ * 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 RFC 1395 for option tags 14-17.
+ * See accompanying man page -- bootpd.8
+ *
+ * HISTORY
+ * See ./Changes
+ *
+ * BUGS
+ * See ./ToDo
+ */
+
+
+
+#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 <sys/utsname.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <assert.h>
+
+#ifdef NO_SETSID
+# include <fcntl.h> /* for O_RDONLY, etc */
+#endif
+
+#ifndef USE_BFUNCS
+# include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+# define bcopy(a,b,c) memcpy(b,a,c)
+# define bzero(p,l) memset(p,0,l)
+# define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "bootpd.h"
+#include "dovend.h"
+#include "getif.h"
+#include "readfile.h"
+#include "report.h"
+#include "tzone.h"
+#include "patchlevel.h"
+
+#ifndef CONFIG_FILE
+#define CONFIG_FILE "/etc/bootptab"
+#endif
+#ifndef DUMPTAB_FILE
+#define DUMPTAB_FILE "/tmp/bootpd.dump"
+#endif
+
+
+
+/*
+ * Externals, forward declarations, and global variables
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern void dumptab P((char *));
+
+PRIVATE void catcher P((int));
+PRIVATE int chk_access P((char *, int32 *));
+#ifdef VEND_CMU
+PRIVATE void dovend_cmu P((struct bootp *, struct host *));
+#endif
+PRIVATE void dovend_rfc1048 P((struct bootp *, struct host *, int32));
+PRIVATE void handle_reply P((void));
+PRIVATE void handle_request P((void));
+PRIVATE void sendreply P((int forward, int32 dest_override));
+PRIVATE void usage P((void));
+
+#undef P
+
+/*
+ * 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 bind_addr; /* Listening */
+struct sockaddr_in recv_addr; /* Packet source */
+struct sockaddr_in send_addr; /* destination */
+
+
+/*
+ * option defaults
+ */
+int debug = 0; /* Debugging flag (level) */
+struct timeval actualtimeout =
+{ /* fifteen minutes */
+ 15 * 60L, /* tv_sec */
+ 0 /* tv_usec */
+};
+
+/*
+ * General
+ */
+
+int s; /* Socket file descriptor */
+char *pktbuf; /* Receive packet buffer */
+int pktlen;
+char *progname;
+char *chdir_path;
+struct in_addr my_ip_addr;
+
+struct utsname my_uname;
+char *hostname;
+
+/* Flags set by signal catcher. */
+PRIVATE int do_readtab = 0;
+PRIVATE int do_dumptab = 0;
+
+/*
+ * Globals below are associated with the bootp database file (bootptab).
+ */
+
+char *bootptab = CONFIG_FILE;
+char *bootpd_dump = DUMPTAB_FILE;
+
+
+
+/*
+ * Initialization such as command-line processing is done and then the
+ * main server loop is started.
+ */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct timeval *timeout;
+ struct bootp *bp;
+ struct servent *servp;
+ struct hostent *hep;
+ char *stmp;
+ int n, ba_len, ra_len;
+ int nfound, readfds;
+ int standalone;
+#ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
+ struct sigaction sa;
+#endif
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+
+ /*
+ * Initialize logging.
+ */
+ report_init(0); /* uses progname */
+
+ /*
+ * Log startup
+ */
+ report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
+
+ /* Debugging for compilers with struct padding. */
+ assert(sizeof(struct bootp) == BP_MINPKTSZ);
+
+ /* Get space for receiving packets and composing replies. */
+ pktbuf = malloc(MAX_MSG_SIZE);
+ if (!pktbuf) {
+ report(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+ bp = (struct bootp *) pktbuf;
+
+ /*
+ * Check to see if 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;
+ ba_len = sizeof(bind_addr);
+ bzero((char *) &bind_addr, ba_len);
+ errno = 0;
+ standalone = TRUE;
+ if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
+ /*
+ * Descriptor 0 is a socket. Assume we are a child of inetd.
+ */
+ if (bind_addr.sin_family == AF_INET) {
+ standalone = FALSE;
+ bootps_port = ntohs(bind_addr.sin_port);
+ } else {
+ /* Some other type of socket? */
+ report(LOG_ERR, "getsockname: not an INET socket");
+ }
+ }
+
+ /*
+ * Set defaults that might be changed by option switches.
+ */
+ stmp = NULL;
+ timeout = &actualtimeout;
+
+ if (uname(&my_uname) < 0) {
+ report(LOG_ERR, "bootpd: can't get hostname\n");
+ exit(1);
+ }
+ hostname = my_uname.nodename;
+
+ /*
+ * Read switches.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'c': /* chdir_path */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (stmp[0] != '/')) {
+ report(LOG_ERR,
+ "bootpd: invalid chdir specification\n");
+ break;
+ }
+ chdir_path = stmp;
+ break;
+
+ case 'd': /* debug level */
+ 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)) {
+ report(LOG_ERR,
+ "%s: invalid debug level\n", progname);
+ break;
+ }
+ debug = n;
+ break;
+
+ case 'h': /* override hostname */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp) {
+ report(LOG_ERR,
+ "bootpd: missing hostname\n");
+ break;
+ }
+ hostname = stmp;
+ break;
+
+ case 'i': /* inetd mode */
+ standalone = FALSE;
+ break;
+
+ case 's': /* standalone mode */
+ standalone = TRUE;
+ break;
+
+ case 't': /* timeout */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ report(LOG_ERR,
+ "%s: invalid timeout specification\n", progname);
+ break;
+ }
+ actualtimeout.tv_sec = (int32) (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;
+
+ default:
+ report(LOG_ERR, "%s: unknown switch: -%c\n",
+ progname, argv[0][1]);
+ usage();
+ break;
+
+ } /* switch */
+ } /* for args */
+
+ /*
+ * Override default file names if specified on the command line.
+ */
+ if (argc > 0)
+ bootptab = argv[0];
+
+ if (argc > 1)
+ bootpd_dump = argv[1];
+
+ /*
+ * Get my hostname and IP address.
+ */
+
+ hep = gethostbyname(hostname);
+ if (!hep) {
+ report(LOG_ERR, "Can not get my IP address\n");
+ exit(1);
+ }
+ bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
+
+ if (standalone) {
+ /*
+ * Go into background and disassociate from controlling terminal.
+ */
+ if (debug < 3) {
+ if (fork())
+ exit(0);
+#ifdef NO_SETSID
+ setpgrp(0,0);
+#ifdef TIOCNOTTY
+ n = open("/dev/tty", O_RDWR);
+ if (n >= 0) {
+ ioctl(n, TIOCNOTTY, (char *) 0);
+ (void) close(n);
+ }
+#endif /* TIOCNOTTY */
+#else /* SETSID */
+ if (setsid() < 0)
+ perror("setsid");
+#endif /* SETSID */
+ } /* if debug < 3 */
+
+ /*
+ * Nuke any timeout value
+ */
+ timeout = NULL;
+
+ } /* if standalone (1st) */
+
+ /* Set the cwd (i.e. to /tftpboot) */
+ if (chdir_path) {
+ if (chdir(chdir_path) < 0)
+ report(LOG_ERR, "%s: chdir failed", chdir_path);
+ }
+
+ /* Get the timezone. */
+ tzone_init();
+
+ /* Allocate hash tables. */
+ rdtab_init();
+
+ /*
+ * Read the bootptab file.
+ */
+ readtab(1); /* force read */
+
+ if (standalone) {
+
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "socket: %s", 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 {
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ report(LOG_ERR,
+ "udp/bootps: unknown service -- assuming port %d",
+ bootps_port);
+ }
+
+ /*
+ * Bind socket to BOOTPS port.
+ */
+ bind_addr.sin_family = AF_INET;
+ bind_addr.sin_addr.s_addr = INADDR_ANY;
+ bind_addr.sin_port = htons(bootps_port);
+ if (bind(s, (struct sockaddr *) &bind_addr,
+ sizeof(bind_addr)) < 0)
+ {
+ report(LOG_ERR, "bind: %s", get_network_errmsg());
+ exit(1);
+ }
+ } /* if standalone (2nd)*/
+
+ /*
+ * 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",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
+ }
+
+ /*
+ * Set up signals to read or dump the table.
+ */
+#ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
+ sa.sa_handler = catcher;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ if (sigaction(SIGHUP, &sa, NULL) < 0) {
+ report(LOG_ERR, "sigaction: %s", get_errmsg());
+ exit(1);
+ }
+ if (sigaction(SIGUSR1, &sa, NULL) < 0) {
+ report(LOG_ERR, "sigaction: %s", get_errmsg());
+ exit(1);
+ }
+#else /* SA_NOCLDSTOP */
+ /* Old-fashioned UNIX signals */
+ if ((int) signal(SIGHUP, catcher) < 0) {
+ report(LOG_ERR, "signal: %s", get_errmsg());
+ exit(1);
+ }
+ if ((int) signal(SIGUSR1, catcher) < 0) {
+ report(LOG_ERR, "signal: %s", get_errmsg());
+ exit(1);
+ }
+#endif /* SA_NOCLDSTOP */
+
+ /*
+ * Process incoming requests.
+ */
+ for (;;) {
+ struct timeval tv;
+
+ readfds = 1 << s;
+ if (timeout)
+ tv = *timeout;
+
+ nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL,
+ (timeout) ? &tv : NULL);
+ if (nfound < 0) {
+ if (errno != EINTR) {
+ report(LOG_ERR, "select: %s", get_errmsg());
+ }
+ /*
+ * Call readtab() or dumptab() here to avoid the
+ * dangers of doing I/O from a signal handler.
+ */
+ if (do_readtab) {
+ do_readtab = 0;
+ readtab(1); /* force read */
+ }
+ if (do_dumptab) {
+ do_dumptab = 0;
+ dumptab(bootpd_dump);
+ }
+ continue;
+ }
+ if (!(readfds & (1 << s))) {
+ if (debug > 1)
+ report(LOG_INFO, "exiting after %ld minutes of inactivity",
+ actualtimeout.tv_sec / 60);
+ exit(0);
+ }
+ ra_len = sizeof(recv_addr);
+ n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
+ (struct sockaddr *) &recv_addr, &ra_len);
+ if (n <= 0) {
+ continue;
+ }
+ if (debug > 1) {
+ report(LOG_INFO, "recvd pkt from IP addr %s",
+ inet_ntoa(recv_addr.sin_addr));
+ }
+ if (n < sizeof(struct bootp)) {
+ if (debug) {
+ report(LOG_NOTICE, "received short packet");
+ }
+ continue;
+ }
+ pktlen = n;
+
+ readtab(0); /* maybe re-read bootptab */
+
+ switch (bp->bp_op) {
+ case BOOTREQUEST:
+ handle_request();
+ break;
+ case BOOTREPLY:
+ handle_reply();
+ break;
+ }
+ }
+}
+
+
+
+
+/*
+ * Print "usage" message and exit
+ */
+
+PRIVATE void
+usage()
+{
+ fprintf(stderr,
+ "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
+ fprintf(stderr, "\t -c n\tset current directory\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);
+}
+
+/* Signal catchers */
+PRIVATE void
+catcher(sig)
+ int sig;
+{
+ if (sig == SIGHUP)
+ do_readtab = 1;
+ if (sig == SIGUSR1)
+ do_dumptab = 1;
+#if !defined(SA_NOCLDSTOP) && defined(SYSV)
+ /* For older "System V" derivatives with no sigaction(). */
+ signal(sig, catcher);
+#endif
+}
+
+
+
+/*
+ * Process BOOTREQUEST packet.
+ *
+ * Note: This version of the bootpd.c server never forwards
+ * a request to another server. That is the job of a gateway
+ * program such as the "bootpgw" program included here.
+ *
+ * (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.)
+ */
+PRIVATE void
+handle_request()
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct host *hp = NULL;
+ struct host dummyhost;
+ int32 bootsize = 0;
+ unsigned hlen, hashcode;
+ int32 dest;
+ char realpath[1024];
+ char *clntpath;
+ char *homedir, *bootfile;
+ int n;
+
+ /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
+
+ /*
+ * 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(bp->bp_sname, hostname)) {
+ if (debug)
+ report(LOG_INFO, "\
+ignoring request for server %s from client at %s address %s",
+ bp->bp_sname, netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_hlen));
+ /* XXX - Is it correct to ignore such a request? -gwr */
+ return;
+ }
+ } else {
+ strcpy(bp->bp_sname, hostname);
+ }
+
+ /* Convert the request into a reply. */
+ bp->bp_op = BOOTREPLY;
+ if (bp->bp_ciaddr.s_addr == 0) {
+ /*
+ * client doesnt know his IP address,
+ * search by hardware address.
+ */
+ if (debug > 1) {
+ report(LOG_INFO, "request from %s address %s",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_hlen));
+ }
+ hlen = haddrlength(bp->bp_htype);
+ if (hlen != bp->bp_hlen) {
+ report(LOG_NOTICE, "bad addr len from from %s address %s",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, hlen));
+ }
+ dummyhost.htype = 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 &&
+ bp->bp_htype == HTYPE_IEEE802)
+ {
+ /* Try again with address in "canonical" form. */
+ haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
+ if (debug > 1) {
+ report(LOG_INFO, "\
+HW addr type is IEEE 802. convert to %s and check again\n",
+ haddrtoa(dummyhost.haddr, bp->bp_hlen));
+ }
+ hashcode = hash_HashFunction(dummyhost.haddr, hlen);
+ hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
+ hwlookcmp, &dummyhost);
+ }
+ if (hp == NULL) {
+ /*
+ * XXX - Add dynamic IP address assignment?
+ */
+ if (debug)
+ report(LOG_NOTICE, "unknown client %s address %s",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_hlen));
+ return; /* not found */
+ }
+ (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
+
+ } else {
+
+ /*
+ * search by IP address.
+ */
+ if (debug > 1) {
+ report(LOG_INFO, "request from IP addr %s",
+ inet_ntoa(bp->bp_ciaddr));
+ }
+ dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
+ hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
+ hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
+ &dummyhost);
+ if (hp == NULL) {
+ if (debug) {
+ report(LOG_NOTICE, "IP address not found: %s",
+ inet_ntoa(bp->bp_ciaddr));
+ }
+ return;
+ }
+ }
+
+ if (debug) {
+ report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
+ hp->hostname->string);
+ }
+
+ /*
+ * If there is a response delay threshold, ignore requests
+ * with a timestamp lower than the threshold.
+ */
+ if (hp->flags.min_wait) {
+ u_int32 t = (u_int32) ntohs(bp->bp_secs);
+ if (t < hp->min_wait) {
+ if (debug > 1)
+ report(LOG_INFO,
+ "ignoring request due to timestamp (%d < %d)",
+ t, hp->min_wait);
+ return;
+ }
+ }
+
+#ifdef YORK_EX_OPTION
+ /*
+ * The need for the "ex" tag arose out of the need to empty
+ * shared networked drives on diskless PCs. This solution is
+ * not very clean but it does work fairly well.
+ * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
+ *
+ * XXX - This could compromise security if a non-trusted user
+ * managed to write an entry in the bootptab with :ex=trojan:
+ * so I would leave this turned off unless you need it. -gwr
+ */
+ /* Run a program, passing the client name as a parameter. */
+ if (hp->flags.exec_file) {
+ char tst[100];
+ /* XXX - Check string lengths? -gwr */
+ strcpy (tst, hp->exec_file->string);
+ strcat (tst, " ");
+ strcat (tst, hp->hostname->string);
+ strcat (tst, " &");
+ if (debug)
+ report(LOG_INFO, "executing %s", tst);
+ system(tst); /* Hope this finishes soon... */
+ }
+#endif /* YORK_EX_OPTION */
+
+ /*
+ * If a specific TFTP server address was specified in the bootptab file,
+ * fill it in, otherwise zero it.
+ * XXX - Rather than zero it, should it be the bootpd address? -gwr
+ */
+ (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
+ hp->bootserver.s_addr : 0L;
+
+#ifdef STANFORD_PROM_COMPAT
+ /*
+ * Stanford bootp PROMs (for a Sun?) have no way to leave
+ * the boot file name field blank (because the boot file
+ * name is automatically generated from some index).
+ * As a work-around, this little hack allows those PROMs to
+ * specify "sunboot14" with the same effect as a NULL name.
+ * (The user specifies boot device 14 or some such magic.)
+ */
+ if (strcmp(bp->bp_file, "sunboot14") == 0)
+ bp->bp_file[0] = '\0'; /* treat it as unspecified */
+#endif
+
+ /*
+ * 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 *XXX
+ * 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" *XXX
+ *
+ */
+
+ /*
+ * XXX - I don't like the policy of ignoring a client when the
+ * boot file is not accessible. The TFTP server might not be
+ * running on the same machine as the BOOTP server, in which
+ * case checking accessibility of the boot file is pointless.
+ *
+ * Therefore, file accessibility is now demanded ONLY if you
+ * define CHECK_FILE_ACCESS in the Makefile options. -gwr
+ */
+
+ /*
+ * The "real" path is as seen by the BOOTP daemon on this
+ * machine, while the client path is relative to the TFTP
+ * daemon chroot directory (i.e. /tftpboot).
+ */
+ if (hp->flags.tftpdir) {
+ strcpy(realpath, hp->tftpdir->string);
+ clntpath = &realpath[strlen(realpath)];
+ } else {
+ realpath[0] = '\0';
+ clntpath = realpath;
+ }
+
+ /*
+ * Determine client's requested homedir and bootfile.
+ */
+ homedir = NULL;
+ bootfile = NULL;
+ if (bp->bp_file[0]) {
+ homedir = bp->bp_file;
+ bootfile = strrchr(homedir, '/');
+ if (bootfile) {
+ if (homedir == bootfile)
+ homedir = NULL;
+ *bootfile++ = '\0';
+ } else {
+ /* no "/" in the string */
+ bootfile = homedir;
+ homedir = NULL;
+ }
+ if (debug > 2) {
+ report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
+ (homedir) ? homedir : "",
+ (bootfile) ? bootfile : "");
+ }
+ }
+
+ /*
+ * Specifications in bootptab override client requested values.
+ */
+ if (hp->flags.homedir)
+ homedir = hp->homedir->string;
+ if (hp->flags.bootfile)
+ bootfile = hp->bootfile->string;
+
+ /*
+ * Construct bootfile path.
+ */
+ if (homedir) {
+ if (homedir[0] != '/')
+ strcat(clntpath, "/");
+ strcat(clntpath, homedir);
+ homedir = NULL;
+ }
+ if (bootfile) {
+ if (bootfile[0] != '/')
+ strcat(clntpath, "/");
+ strcat(clntpath, bootfile);
+ bootfile = NULL;
+ }
+
+ /*
+ * First try to find the file with a ".host" suffix
+ */
+ n = strlen(clntpath);
+ strcat(clntpath, ".");
+ strcat(clntpath, hp->hostname->string);
+ if (chk_access(realpath, &bootsize) < 0) {
+ clntpath[n] = 0; /* Try it without the suffix */
+ if (chk_access(realpath, &bootsize) < 0) {
+ /* neither "file.host" nor "file" was found */
+#ifdef CHECK_FILE_ACCESS
+
+ if (bp->bp_file[0]) {
+ /*
+ * Client wanted specific file
+ * and we didn't have it.
+ */
+ report(LOG_NOTICE,
+ "requested file not found: \"%s\"", clntpath);
+ return;
+ }
+ /*
+ * 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 null_file_name;
+
+#else /* CHECK_FILE_ACCESS */
+
+ /* Complain only if boot file size was needed. */
+ if (hp->flags.bootsize_auto) {
+ report(LOG_ERR, "can not determine size of file \"%s\"",
+ clntpath);
+ }
+
+#endif /* CHECK_FILE_ACCESS */
+ }
+ }
+ strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
+ if (debug > 2)
+ report(LOG_INFO, "bootfile=\"%s\"", clntpath);
+
+#ifdef CHECK_FILE_ACCESS
+null_file_name:
+#endif /* CHECK_FILE_ACCESS */
+
+
+ /*
+ * Handle vendor options based on magic number.
+ */
+
+ if (debug > 1) {
+ report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
+ (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. Only force reply format if user specified it.
+ */
+ if (hp->flags.vm_cookie) {
+ /* Slam in the user specified magic number. */
+ bcopy(hp->vm_cookie, bp->bp_vend, 4);
+ }
+ /*
+ * Figure out the format for the vendor-specific info.
+ * Note that bp->bp_vend may have been set above.
+ */
+ if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
+ /* RFC1048 conformant bootp client */
+ dovend_rfc1048(bp, hp, bootsize);
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply (with RFC1048 options)");
+ }
+ }
+#ifdef VEND_CMU
+ else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
+ dovend_cmu(bp, hp);
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply (with CMU options)");
+ }
+ }
+#endif
+ else {
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply (with no options)");
+ }
+ }
+
+ dest = (hp->flags.reply_addr) ?
+ hp->reply_addr.s_addr : 0L;
+
+ /* not forwarded */
+ sendreply(0, dest);
+}
+
+
+/*
+ * Process BOOTREPLY packet.
+ */
+PRIVATE void
+handle_reply()
+{
+ if (debug) {
+ report(LOG_INFO, "processing boot reply");
+ }
+ /* forwarded, no destination override */
+ sendreply(1, 0);
+}
+
+
+/*
+ * Send a reply packet to the client. 'forward' flag is set if we are
+ * not the originator of this reply packet.
+ */
+PRIVATE void
+sendreply(forward, dst_override)
+ int forward;
+ int32 dst_override;
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct in_addr dst;
+ u_short port = bootpc_port;
+ unsigned char *ha;
+ int len, haf;
+
+ /*
+ * XXX - Should honor bp_flags "broadcast" bit here.
+ * Temporary workaround: use the :ra=ADDR: option to
+ * set the reply address to the broadcast address.
+ */
+
+ /*
+ * If the destination address was specified explicitly
+ * (i.e. the broadcast address for HP compatiblity)
+ * then send the response to that address. Otherwise,
+ * act in accordance with RFC951:
+ * 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 (dst_override) {
+ dst.s_addr = dst_override;
+ if (debug > 1) {
+ report(LOG_INFO, "reply address override: %s",
+ inet_ntoa(dst));
+ }
+ } else if (bp->bp_ciaddr.s_addr) {
+ dst = bp->bp_ciaddr;
+ } else if (bp->bp_giaddr.s_addr && forward == 0) {
+ dst = bp->bp_giaddr;
+ port = bootps_port;
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply to gateway %s",
+ inet_ntoa(dst));
+ }
+ } else {
+ dst = bp->bp_yiaddr;
+ ha = bp->bp_chaddr;
+ len = bp->bp_hlen;
+ if (len > MAXHADDRLEN)
+ len = MAXHADDRLEN;
+ haf = (int) bp->bp_htype;
+ if (haf == 0)
+ haf = HTYPE_ETHERNET;
+
+ if (debug > 1)
+ report(LOG_INFO, "setarp %s - %s",
+ inet_ntoa(dst), haddrtoa(ha, len));
+ setarp(s, &dst, haf, ha, len);
+ }
+
+ if ((forward == 0) &&
+ (bp->bp_siaddr.s_addr == 0))
+ {
+ struct ifreq *ifr;
+ struct in_addr siaddr;
+ /*
+ * 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). Of course, the client may
+ * be on the other side of a BOOTP gateway...
+ */
+ ifr = getif(s, &dst);
+ if (ifr) {
+ struct sockaddr_in *sip;
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ siaddr = sip->sin_addr;
+ } else {
+ /* Just use my "official" IP address. */
+ siaddr = my_ip_addr;
+ }
+
+ /* XXX - No need to set bp_giaddr here. */
+
+ /* Finally, set the server address field. */
+ bp->bp_siaddr = siaddr;
+ }
+ /* Set up socket address for send. */
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_port = htons(port);
+ send_addr.sin_addr = dst;
+
+ /* Send reply with same size packet as request used. */
+ if (sendto(s, pktbuf, pktlen, 0,
+ (struct sockaddr *) &send_addr,
+ sizeof(send_addr)) < 0)
+ {
+ report(LOG_ERR, "sendto: %s", get_network_errmsg());
+ }
+} /* sendreply */
+
+
+/* nmatch() - now in getif.c */
+/* setarp() - now in hwaddr.c */
+
+
+/*
+ * 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.
+ */
+
+PRIVATE int
+chk_access(path, filesize)
+ char *path;
+ int32 *filesize;
+{
+ struct stat st;
+
+ if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
+ *filesize = (int32) st.st_size;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+
+/*
+ * Now in dumptab.c :
+ * dumptab()
+ * dump_host()
+ * list_ipaddresses()
+ */
+
+#ifdef VEND_CMU
+
+/*
+ * Insert the CMU "vendor" data for the host pointed to by "hp" into the
+ * bootp packet pointed to by "bp".
+ */
+
+PRIVATE 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;
+ strcpy(vendp->v_magic, (char *)vm_cmu);
+ 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;
+ }
+ }
+ }
+ /* Log message now done by caller. */
+} /* dovend_cmu */
+
+#endif /* VEND_CMU */
+
+
+
+/*
+ * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
+ * bootp packet pointed to by "bp".
+ */
+#define NEED(LEN, MSG) do \
+ if (bytesleft < (LEN)) { \
+ report(LOG_NOTICE, noroom, \
+ hp->hostname->string, MSG); \
+ return; \
+ } while (0)
+PRIVATE void
+dovend_rfc1048(bp, hp, bootsize)
+ struct bootp *bp;
+ struct host *hp;
+ int32 bootsize;
+{
+ int bytesleft, len;
+ byte *vp;
+
+ static char noroom[] = "%s: No room for \"%s\" option";
+
+ vp = bp->bp_vend;
+
+ if (hp->flags.msg_size) {
+ pktlen = hp->msg_size;
+ } else {
+ /*
+ * If the request was longer than the official length, build
+ * a response of that same length where the additional length
+ * is assumed to be part of the bp_vend (options) area.
+ */
+ if (pktlen > sizeof(*bp)) {
+ if (debug > 1)
+ report(LOG_INFO, "request message length=%d", pktlen);
+ }
+ /*
+ * Check whether the request contains the option:
+ * Maximum DHCP Message Size (RFC1533 sec. 9.8)
+ * and if so, override the response length with its value.
+ * This request must lie within the first BP_VEND_LEN
+ * bytes of the option space.
+ */
+ {
+ byte *p, *ep;
+ byte tag, len;
+ short msgsz = 0;
+
+ p = vp + 4;
+ ep = p + BP_VEND_LEN - 4;
+ while (p < ep) {
+ tag = *p++;
+ /* Check for tags with no data first. */
+ if (tag == TAG_PAD)
+ continue;
+ if (tag == TAG_END)
+ break;
+ /* Now scan the length byte. */
+ len = *p++;
+ switch (tag) {
+ case TAG_MAX_MSGSZ:
+ if (len == 2) {
+ bcopy(p, (char*)&msgsz, 2);
+ msgsz = ntohs(msgsz);
+ }
+ break;
+ case TAG_SUBNET_MASK:
+ /* XXX - Should preserve this if given... */
+ break;
+ } /* swtich */
+ p += len;
+ }
+
+ if (msgsz > sizeof(*bp)) {
+ if (debug > 1)
+ report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
+ pktlen = msgsz;
+ }
+ }
+ }
+
+ if (pktlen < sizeof(*bp)) {
+ report(LOG_ERR, "invalid response length=%d", pktlen);
+ pktlen = sizeof(*bp);
+ }
+ bytesleft = ((byte*)bp + pktlen) - vp;
+ if (pktlen > sizeof(*bp)) {
+ if (debug > 1)
+ report(LOG_INFO, "extended reply, length=%d, options=%d",
+ pktlen, bytesleft);
+ }
+
+ /* Copy in the magic cookie */
+ bcopy(vm_rfc1048, vp, 4);
+ vp += 4;
+ bytesleft -= 4;
+
+ if (hp->flags.subnet_mask) {
+ /* always enough room here. */
+ *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) {
+ (void) insert_ip(TAG_GATEWAY,
+ hp->gateway,
+ &vp, &bytesleft);
+ }
+ }
+ if (hp->flags.bootsize) {
+ /* always enough room here */
+ bootsize = (hp->flags.bootsize_auto) ?
+ ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
+ *vp++ = TAG_BOOT_SIZE;
+ *vp++ = 2;
+ *vp++ = (byte) ((bootsize >> 8) & 0xFF);
+ *vp++ = (byte) (bootsize & 0xFF);
+ bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
+ }
+ /*
+ * This one is special: Remaining options go in the ext file.
+ * Only the subnet_mask, bootsize, and gateway should precede.
+ */
+ if (hp->flags.exten_file) {
+ /*
+ * Check for room for exten_file. Add 3 to account for
+ * TAG_EXTEN_FILE, length, and TAG_END.
+ */
+ len = strlen(hp->exten_file->string);
+ NEED((len + 3), "ef");
+ *vp++ = TAG_EXTEN_FILE;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->exten_file->string, vp, len);
+ vp += len;
+ *vp++ = TAG_END;
+ bytesleft -= len + 3;
+ return; /* no more options here. */
+ }
+ /*
+ * The remaining options are inserted by the following
+ * function (which is shared with bootpef.c).
+ * Keep back one byte for the TAG_END.
+ */
+ len = dovend_rfc1497(hp, vp, bytesleft - 1);
+ vp += len;
+ bytesleft -= len;
+
+ /* There should be at least one byte left. */
+ NEED(1, "(end)");
+ *vp++ = TAG_END;
+ bytesleft--;
+
+ /* Log message done by caller. */
+ if (bytesleft > 0) {
+ /*
+ * Zero out any remaining part of the vendor area.
+ */
+ bzero(vp, bytesleft);
+ }
+} /* dovend_rfc1048 */
+#undef NEED
+
+
+/*
+ * Now in readfile.c:
+ * hwlookcmp()
+ * iplookcmp()
+ */
+
+/* haddrtoa() - now in hwaddr.c */
+/*
+ * Now in dovend.c:
+ * insert_ip()
+ * insert_generic()
+ * insert_u_long()
+ */
+
+/* get_errmsg() - now in report.c */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/bootpd.h b/libexec/bootpd/bootpd.h
new file mode 100644
index 0000000..e5ce341
--- /dev/null
+++ b/libexec/bootpd/bootpd.h
@@ -0,0 +1,211 @@
+/************************************************************************
+ 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.
+************************************************************************/
+
+
+/*
+ * bootpd.h -- common header file for all the modules of the bootpd program.
+ */
+
+#include "bptypes.h"
+#include "hash.h"
+#include "hwaddr.h"
+
+#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 MAXSTRINGLEN 80 /* Max string length */
+
+/* Local definitions: */
+#define MAX_MSG_SIZE (3*512) /* Maximum packet size */
+
+
+/*
+ * Return pointer to static string which gives full network error message.
+ */
+#define get_network_errmsg get_errmsg
+
+
+/*
+ * 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 int 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 int linkcount;
+ char string[1]; /* Dynamically extended */
+};
+
+struct shared_bindata {
+ unsigned int 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,
+ time_server :1,
+ dump_file :1,
+ domain_name :1,
+ swap_server :1,
+ root_path :1,
+ exten_file :1,
+ reply_addr :1,
+ nis_domain :1,
+ nis_server :1,
+ ntp_server :1,
+ exec_file :1,
+ msg_size :1,
+ min_wait :1,
+ /* XXX - Add new tags here */
+ vm_cookie :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 {
+ unsigned linkcount; /* hash list inserts */
+ 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,
+ *nis_server,
+ *ntp_server;
+ struct shared_string *bootfile,
+ *hostname,
+ *domain_name,
+ *homedir,
+ *tftpdir,
+ *dump_file,
+ *exten_file,
+ *root_path,
+ *nis_domain,
+ *exec_file;
+ struct shared_bindata *generic;
+ byte vm_cookie[4],
+ htype, /* RFC826 says this should be 16-bits but
+ RFC951 only allocates 1 byte. . . */
+ haddr[MAXHADDRLEN];
+ int32 time_offset;
+ unsigned int32 bootsize,
+ msg_size,
+ min_wait;
+ struct in_addr bootserver,
+ iaddr,
+ swap_server,
+ reply_addr,
+ subnet_mask;
+ /* XXX - Add new tags here (or above as appropriate) */
+};
+
+
+
+/*
+ * Variables shared among modules.
+ */
+
+extern int debug;
+extern char *bootptab;
+extern char *progname;
+
+extern u_char vm_cmu[4];
+extern u_char vm_rfc1048[4];
+
+extern hash_tbl *hwhashtable;
+extern hash_tbl *iphashtable;
+extern hash_tbl *nmhashtable;
+
diff --git a/libexec/bootpd/bootpgw/Makefile b/libexec/bootpd/bootpgw/Makefile
new file mode 100644
index 0000000..04f02eb
--- /dev/null
+++ b/libexec/bootpd/bootpgw/Makefile
@@ -0,0 +1,12 @@
+# Makefile
+# $Id$
+
+PROG= bootpgw
+NOMAN= true
+SRCS= bootpgw.c getif.c hwaddr.c report.c rtmsg.c
+
+SRCDIR= ${.CURDIR}/..
+CFLAGS+=-I${SRCDIR}
+.PATH: ${SRCDIR}
+
+.include <bsd.prog.mk>
diff --git a/libexec/bootpd/bootpgw/bootpgw.c b/libexec/bootpd/bootpgw/bootpgw.c
new file mode 100644
index 0000000..c289352
--- /dev/null
+++ b/libexec/bootpd/bootpgw/bootpgw.c
@@ -0,0 +1,688 @@
+/*
+ * bootpgw.c - BOOTP GateWay
+ * This program forwards BOOTP Request packets to a BOOTP server.
+ */
+
+/************************************************************************
+ 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.
+************************************************************************/
+
+/*
+ * BOOTPGW is typically used to forward BOOTP client requests from
+ * one subnet to a BOOTP server on a different subnet.
+ */
+
+#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 <sys/utsname.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <assert.h>
+
+#ifdef NO_SETSID
+# include <fcntl.h> /* for O_RDONLY, etc */
+#endif
+
+#ifndef USE_BFUNCS
+# include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+# define bcopy(a,b,c) memcpy(b,a,c)
+# define bzero(p,l) memset(p,0,l)
+# define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "getif.h"
+#include "hwaddr.h"
+#include "report.h"
+#include "patchlevel.h"
+
+/* Local definitions: */
+#define MAX_MSG_SIZE (3*512) /* Maximum packet size */
+#define TRUE 1
+#define FALSE 0
+#define get_network_errmsg get_errmsg
+
+
+
+/*
+ * Externals, forward declarations, and global variables
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+static void usage P((void));
+static void handle_reply P((void));
+static void handle_request P((void));
+
+#undef P
+
+/*
+ * 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 bind_addr; /* Listening */
+struct sockaddr_in recv_addr; /* Packet source */
+struct sockaddr_in send_addr; /* destination */
+
+
+/*
+ * option defaults
+ */
+int debug = 0; /* Debugging flag (level) */
+struct timeval actualtimeout =
+{ /* fifteen minutes */
+ 15 * 60L, /* tv_sec */
+ 0 /* tv_usec */
+};
+u_char maxhops = 4; /* Number of hops allowed for requests. */
+u_int minwait = 3; /* Number of seconds client must wait before
+ its bootrequest packets are forwarded. */
+
+/*
+ * General
+ */
+
+int s; /* Socket file descriptor */
+char *pktbuf; /* Receive packet buffer */
+int pktlen;
+char *progname;
+char *servername;
+int32 server_ipa; /* Real server IP address, network order. */
+
+struct in_addr my_ip_addr;
+
+struct utsname my_uname;
+char *hostname;
+
+
+
+
+
+/*
+ * Initialization such as command-line processing is done and then the
+ * main server loop is started.
+ */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct timeval *timeout;
+ struct bootp *bp;
+ struct servent *servp;
+ struct hostent *hep;
+ char *stmp;
+ int n, ba_len, ra_len;
+ int nfound, readfds;
+ int standalone;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+
+ /*
+ * Initialize logging.
+ */
+ report_init(0); /* uses progname */
+
+ /*
+ * Log startup
+ */
+ report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
+
+ /* Debugging for compilers with struct padding. */
+ assert(sizeof(struct bootp) == BP_MINPKTSZ);
+
+ /* Get space for receiving packets and composing replies. */
+ pktbuf = malloc(MAX_MSG_SIZE);
+ if (!pktbuf) {
+ report(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+ bp = (struct bootp *) pktbuf;
+
+ /*
+ * Check to see if 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;
+ ba_len = sizeof(bind_addr);
+ bzero((char *) &bind_addr, ba_len);
+ errno = 0;
+ standalone = TRUE;
+ if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
+ /*
+ * Descriptor 0 is a socket. Assume we are a child of inetd.
+ */
+ if (bind_addr.sin_family == AF_INET) {
+ standalone = FALSE;
+ bootps_port = ntohs(bind_addr.sin_port);
+ } else {
+ /* Some other type of socket? */
+ report(LOG_INFO, "getsockname: not an INET socket");
+ }
+ }
+ /*
+ * Set defaults that might be changed by option switches.
+ */
+ stmp = NULL;
+ timeout = &actualtimeout;
+
+ if (uname(&my_uname) < 0) {
+ fprintf(stderr, "bootpgw: can't get hostname\n");
+ exit(1);
+ }
+ hostname = my_uname.nodename;
+
+ hep = gethostbyname(hostname);
+ if (!hep) {
+ printf("Can not get my IP address\n");
+ exit(1);
+ }
+ bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
+
+ /*
+ * Read switches.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'd': /* debug level */
+ 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,
+ "%s: invalid debug level\n", progname);
+ break;
+ }
+ debug = n;
+ break;
+
+ case 'h': /* hop count limit */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) ||
+ (n < 0) || (n > 16))
+ {
+ fprintf(stderr,
+ "bootpgw: invalid hop count limit\n");
+ break;
+ }
+ maxhops = (u_char)n;
+ break;
+
+ case 'i': /* inetd mode */
+ standalone = FALSE;
+ break;
+
+ case 's': /* standalone mode */
+ standalone = TRUE;
+ break;
+
+ case 't': /* timeout */
+ 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,
+ "%s: invalid timeout specification\n", progname);
+ break;
+ }
+ actualtimeout.tv_sec = (int32) (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 'w': /* wait time */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) ||
+ (n < 0) || (n > 60))
+ {
+ fprintf(stderr,
+ "bootpgw: invalid wait time\n");
+ break;
+ }
+ minwait = (u_int)n;
+ break;
+
+ default:
+ fprintf(stderr, "%s: unknown switch: -%c\n",
+ progname, argv[0][1]);
+ usage();
+ break;
+
+ } /* switch */
+ } /* for args */
+
+ /* Make sure server name argument is suplied. */
+ servername = argv[0];
+ if (!servername) {
+ fprintf(stderr, "bootpgw: missing server name\n");
+ usage();
+ }
+ /*
+ * Get address of real bootp server.
+ */
+ if (isdigit(servername[0]))
+ server_ipa = inet_addr(servername);
+ else {
+ hep = gethostbyname(servername);
+ if (!hep) {
+ fprintf(stderr, "bootpgw: can't get addr for %s\n", servername);
+ exit(1);
+ }
+ bcopy(hep->h_addr, (char *)&server_ipa, sizeof(server_ipa));
+ }
+
+ if (standalone) {
+ /*
+ * Go into background and disassociate from controlling terminal.
+ * XXX - This is not the POSIX way (Should use setsid). -gwr
+ */
+ if (debug < 3) {
+ if (fork())
+ exit(0);
+#ifdef NO_SETSID
+ setpgrp(0,0);
+#ifdef TIOCNOTTY
+ n = open("/dev/tty", O_RDWR);
+ if (n >= 0) {
+ ioctl(n, TIOCNOTTY, (char *) 0);
+ (void) close(n);
+ }
+#endif /* TIOCNOTTY */
+#else /* SETSID */
+ if (setsid() < 0)
+ perror("setsid");
+#endif /* SETSID */
+ } /* if debug < 3 */
+ /*
+ * Nuke any timeout value
+ */
+ timeout = NULL;
+
+ /*
+ * Here, bootpd would do:
+ * chdir
+ * tzone_init
+ * rdtab_init
+ * readtab
+ */
+
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "socket: %s", 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 {
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ report(LOG_ERR,
+ "udp/bootps: unknown service -- assuming port %d",
+ bootps_port);
+ }
+
+ /*
+ * Bind socket to BOOTPS port.
+ */
+ bind_addr.sin_family = AF_INET;
+ bind_addr.sin_port = htons(bootps_port);
+ bind_addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(s, (struct sockaddr *) &bind_addr,
+ sizeof(bind_addr)) < 0)
+ {
+ report(LOG_ERR, "bind: %s", get_network_errmsg());
+ exit(1);
+ }
+ } /* if standalone */
+ /*
+ * 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",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
+ }
+
+ /* no signal catchers */
+
+ /*
+ * Process incoming requests.
+ */
+ for (;;) {
+ struct timeval tv;
+
+ readfds = 1 << s;
+ if (timeout)
+ tv = *timeout;
+
+ nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL,
+ (timeout) ? &tv : NULL);
+ if (nfound < 0) {
+ if (errno != EINTR) {
+ report(LOG_ERR, "select: %s", get_errmsg());
+ }
+ continue;
+ }
+ if (!(readfds & (1 << s))) {
+ report(LOG_INFO, "exiting after %ld minutes of inactivity",
+ actualtimeout.tv_sec / 60);
+ exit(0);
+ }
+ ra_len = sizeof(recv_addr);
+ n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
+ (struct sockaddr *) &recv_addr, &ra_len);
+ if (n <= 0) {
+ continue;
+ }
+ if (debug > 3) {
+ report(LOG_INFO, "recvd pkt from IP addr %s",
+ inet_ntoa(recv_addr.sin_addr));
+ }
+ if (n < sizeof(struct bootp)) {
+ if (debug) {
+ report(LOG_INFO, "received short packet");
+ }
+ continue;
+ }
+ pktlen = n;
+
+ switch (bp->bp_op) {
+ case BOOTREQUEST:
+ handle_request();
+ break;
+ case BOOTREPLY:
+ handle_reply();
+ break;
+ }
+ }
+}
+
+
+
+
+/*
+ * Print "usage" message and exit
+ */
+
+static void
+usage()
+{
+ fprintf(stderr,
+ "usage: bootpgw [-d level] [-i] [-s] [-t timeout] server\n");
+ fprintf(stderr, "\t -d n\tset debug level\n");
+ fprintf(stderr, "\t -h n\tset max hop count\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");
+ fprintf(stderr, "\t -w n\tset min wait time (secs)\n");
+ exit(1);
+}
+
+
+
+/*
+ * Process BOOTREQUEST packet.
+ *
+ * Note, this just forwards the request to a real server.
+ */
+static void
+handle_request()
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ u_short secs;
+ u_char hops;
+
+ /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
+
+ if (debug) {
+ report(LOG_INFO, "request from %s",
+ inet_ntoa(recv_addr.sin_addr));
+ }
+ /* Has the client been waiting long enough? */
+ secs = ntohs(bp->bp_secs);
+ if (secs < minwait)
+ return;
+
+ /* Has this packet hopped too many times? */
+ hops = bp->bp_hops;
+ if (++hops > maxhops) {
+ report(LOG_NOTICE, "reqest from %s reached hop limit",
+ inet_ntoa(recv_addr.sin_addr));
+ return;
+ }
+ bp->bp_hops = hops;
+
+ /*
+ * Here one might discard a request from the same subnet as the
+ * real server, but we can assume that the real server will send
+ * a reply to the client before it waits for minwait seconds.
+ */
+
+ /* If gateway address is not set, put in local interface addr. */
+ if (bp->bp_giaddr.s_addr == 0) {
+#if 0 /* BUG */
+ struct sockaddr_in *sip;
+ struct ifreq *ifr;
+ /*
+ * XXX - This picks the wrong interface when the receive addr
+ * is the broadcast address. There is no portable way to
+ * find out which interface a broadcast was received on. -gwr
+ * (Thanks to <walker@zk3.dec.com> for finding this bug!)
+ */
+ ifr = getif(s, &recv_addr.sin_addr);
+ if (!ifr) {
+ report(LOG_NOTICE, "no interface for request from %s",
+ inet_ntoa(recv_addr.sin_addr));
+ return;
+ }
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ bp->bp_giaddr = sip->sin_addr;
+#else /* BUG */
+ /*
+ * XXX - Just set "giaddr" to our "official" IP address.
+ * RFC 1532 says giaddr MUST be set to the address of the
+ * interface on which the request was received. Setting
+ * it to our "default" IP address is not strictly correct,
+ * but is good enough to allow the real BOOTP server to
+ * get the reply back here. Then, before we forward the
+ * reply to the client, the giaddr field is corrected.
+ * (In case the client uses giaddr, which it should not.)
+ * See handle_reply()
+ */
+ bp->bp_giaddr = my_ip_addr;
+#endif /* BUG */
+
+ /*
+ * XXX - DHCP says to insert a subnet mask option into the
+ * options area of the request (if vendor magic == std).
+ */
+ }
+ /* Set up socket address for send. */
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_port = htons(bootps_port);
+ send_addr.sin_addr.s_addr = server_ipa;
+
+ /* Send reply with same size packet as request used. */
+ if (sendto(s, pktbuf, pktlen, 0,
+ (struct sockaddr *) &send_addr,
+ sizeof(send_addr)) < 0)
+ {
+ report(LOG_ERR, "sendto: %s", get_network_errmsg());
+ }
+}
+
+
+
+/*
+ * Process BOOTREPLY packet.
+ */
+static void
+handle_reply()
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct ifreq *ifr;
+ struct sockaddr_in *sip;
+ unsigned char *ha;
+ int len, haf;
+
+ if (debug) {
+ report(LOG_INFO, " reply for %s",
+ inet_ntoa(bp->bp_yiaddr));
+ }
+ /* Make sure client is directly accessible. */
+ ifr = getif(s, &(bp->bp_yiaddr));
+ if (!ifr) {
+ report(LOG_NOTICE, "no interface for reply to %s",
+ inet_ntoa(bp->bp_yiaddr));
+ return;
+ }
+#if 1 /* Experimental (see BUG above) */
+/* #ifdef CATER_TO_OLD_CLIENTS ? */
+ /*
+ * The giaddr field has been set to our "default" IP address
+ * which might not be on the same interface as the client.
+ * In case the client looks at giaddr, (which it should not)
+ * giaddr is now set to the address of the correct interface.
+ */
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ bp->bp_giaddr = sip->sin_addr;
+#endif
+
+ /* Set up socket address for send to client. */
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_addr = bp->bp_yiaddr;
+ send_addr.sin_port = htons(bootpc_port);
+
+ /* Create an ARP cache entry for the client. */
+ ha = bp->bp_chaddr;
+ len = bp->bp_hlen;
+ if (len > MAXHADDRLEN)
+ len = MAXHADDRLEN;
+ haf = (int) bp->bp_htype;
+ if (haf == 0)
+ haf = HTYPE_ETHERNET;
+
+ if (debug > 1)
+ report(LOG_INFO, "setarp %s - %s",
+ inet_ntoa(bp->bp_yiaddr), haddrtoa(ha, len));
+ setarp(s, &bp->bp_yiaddr, haf, ha, len);
+
+ /* Send reply with same size packet as request used. */
+ if (sendto(s, pktbuf, pktlen, 0,
+ (struct sockaddr *) &send_addr,
+ sizeof(send_addr)) < 0)
+ {
+ report(LOG_ERR, "sendto: %s", get_network_errmsg());
+ }
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/bootptab.5 b/libexec/bootpd/bootptab.5
new file mode 100644
index 0000000..c79116a
--- /dev/null
+++ b/libexec/bootpd/bootptab.5
@@ -0,0 +1,395 @@
+.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
+.\"
+.\" $Header: $
+.\"
+.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 (or a "dummy entry"), and
+.I tg
+is a two-character tag symbol. Dummy entries have an invalid hostname
+(one with a "." as the first character) and are used to provide
+default values used by other entries via the
+.B tc=.dummy-entry
+mechanism. 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
+ ef Extension file
+.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
+ nt NTP (time) Server (RFC 1129)
+.br
+ ra Reply address override
+.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
+.br
+ yd YP (NIS) domain name
+.br
+ ys YP (NIS) server address
+
+.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 nt ,
+.BR ra ,
+.BR rl ,
+and
+.BR ts .
+The
+.BR ip ,
+.BR sa ,
+.BR sw ,
+.BR sm ,
+and
+.B ys
+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').
+Any IP addresses may alternatively be specified as a hostname, causing
+.I bootpd
+to lookup the IP address for that host name using gethostbyname(3).
+If the
+.B ip
+tag is not specified,
+.I bootpd
+will determine the IP address using the entry name as the host name.
+(Dummy entries use an invalid host name to avoid automatic IP lookup.)
+.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 may be specified as a host name
+or in numeric form. Note that the numeric form
+.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).
+If the hardware address is not specified and the type is specified
+as either "ethernet" or "ieee802", then
+.I bootpd
+will try to determine the hardware address using ether_hton(3).
+.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 provides a file name it is left as is.
+Otherwise, if the
+.B bf
+option is specified its value is copied into the reply packet.
+If the
+.B hd
+option is specified as well, its value is prepended to the
+boot file copied into the reply packet.
+The existence of the boot file is checked only if the
+.BR bs =auto
+option is used (to determine the boot file size).
+A reply may be sent whether or not the boot file exists.
+.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 .
+(One may alternatively use the
+.I bootpd
+"-c chdir" option.)
+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
+.nf
+ # Sample bootptab file (domain=andrew.cmu.edu)
+
+ .default:\\
+ :hd=/usr/boot:bf=null:\\
+ :ds=netserver, lancaster:\\
+ :ns=pcs2, pcs1:\\
+ :ts=pcs2, pcs1:\\
+ :sm=255.255.255.0:\\
+ :gw=gw.cs.cmu.edu:\\
+ :hn:to=-18000:
+
+ carnegie:ht=6:ha=7FF8100000AF:tc=.default:
+ baldwin:ht=1:ha=0800200159C3:tc=.default:
+ wylie:ht=1:ha=00DD00CADF00:tc=.default:
+ arnold:ht=1:ha=0800200102AD:tc=.default:
+ bairdford:ht=1:ha=08002B02A2F9:tc=.default:
+ bakerstown:ht=1:ha=08002B0287C8:tc=.default:
+
+ # Special domain name server and option tags for next host
+ butlerjct:ha=08002001560D:ds=128.2.13.42:\\
+ :T37=0x12345927AD3BCF:\\
+ :T99="Special ASCII string":\\
+ :tc=.default:
+
+ gastonville:ht=6:ha=7FFF81000A47:tc=.default:
+ hahntown:ht=6:ha=7FFF81000434:tc=.default:
+ hickman:ht=6:ha=7FFF810001BA:tc=.default:
+ lowber:ht=1:ha=00DD00CAF000:tc=.default:
+ mtoliver:ht=1:ha=00DD00FE1600:tc=.default:
+
+.fi
+.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/bootptab.cmu b/libexec/bootpd/bootptab.cmu
new file mode 100644
index 0000000..66212d4
--- /dev/null
+++ b/libexec/bootpd/bootptab.cmu
@@ -0,0 +1,124 @@
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# (I've hacked on this but can't test it... -gwr)
+
+# Blank lines and lines beginning with '#' are ignored.
+#
+# Legend: (see bootptab.5)
+# first field -- hostname (not indented)
+# bf -- bootfile
+# bs -- bootfile size in 512-octet blocks
+# cs -- cookie servers
+# df -- dump file name
+# dn -- domain name
+# ds -- domain name servers
+# ef -- extension file
+# gw -- gateways
+# ha -- hardware address
+# hd -- home directory for bootfiles
+# hn -- host name set for client
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# ra -- reply address
+# rl -- resource location protocol servers
+# rp -- root path
+# sa -- boot server address
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# td -- TFTP directory
+# to -- time offset (seconds)
+# ts -- time servers
+# vm -- vendor magic number
+# Tn -- generic option tag n
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+# Also, note that generic option data must be either a string or a
+# sequence of bytes where each byte is a two-digit hex value.
+
+# First, we define a global entry which specifies the stuff every host uses.
+# (Host name lookups are relative to the domain: andrew.cmu.edu)
+.default:\
+ :hn:dn=cmu.edu:\
+ :hd=/usr/boot:\
+ :ds=netserver, lancaster:\
+ :ns=pcs2, pcs1:\
+ :ts=pcs2, pcs1:\
+ :sm=255.255.0.0:\
+ :gw=gw.cs.cmu.edu:\
+ to=auto:
+
+
+# Next, we can define different master entries for each subnet. . .
+.subnet13 :sm=255.255.255.0:gw=128.2.13.1 :tc=.default:
+.subnet19 :sm=255.255.255.0:gw=128.2.19.1 :tc=.default:
+.subnet232 :sm=255.255.255.0:gw=128.2.232.1 :tc=.default:
+
+#
+# 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:ht=ieee802:ha=7FF8100000AF:
+baldwin:tc=.subnet19:ha=0800200159C3:
+wylie:tc=.subnet232:ha=00DD00CADF00:
+arnold:tc=.subnet19:ha=0800200102AD:
+bairdford:tc=.subnet19:ha=08002B02A2F9:
+bakerstown:tc=.subnet19:ha=08002B0287C8:
+butlerjct:tc=.subnet232:ha=08002001560D:
+gastonville:tc=.subnet232:ht=ieee802:ha=7FFF81000A47:
+hahntown:tc=.subnet13:ht=ieee802:ha=7FFF81000434:
+hickman:tc=.subnet19:ht=ieee802:ha=7FFF810001BA:
+lowber:tc=.subnet13:ha=00DD00CAF000:
+mtoliver:tc=.subnet19:ha=00DD00FE1600:
+osborne:tc=.subnet232:ha=00DD00CAD600:
+russelton:tc=.subnet232:ha=080020017FC3:
+thornburg:tc=.subnet13:ha=080020012A33:
+
+
+# Hmmm. . . Let's throw in some whitespace for readability. . . .
+
+andrew: tc=.subnet19:ha=00DD00C88900:
+birdville: tc=.subnet19:ha=00DD00FE2D00:
+coudersport: tc=.subnet13:ha=00DD00CB1E00:
+bridgeville: tc=.subnet232:ha=080020011394:
+franklin: tc=.subnet19:ha=08002B02A5D5:
+hollidaysburg: tc=.subnet19:ht=ieee802:ha=7FFF810002C8:
+honesdale: tc=.subnet19:ha=08002B02F83F:
+huntingdon: tc=.subnet19:ha=08002B02E410:
+indiana: tc=.subnet13:ha=08002B029BEC:
+jimthorpe: tc=.subnet232:ha=08002B02FBBA:
+kittanning: tc=.subnet232:ha=08002B0273FC:
+lebanon: tc=.subnet232:ha=08002B037F67:
+lewisburg: tc=.subnet19:ha=50005A1A0DE4:
+middleburg: tc=.subnet232:ha=00DD00FE1200:
+aspinwall: tc=.subnet13:ha=08002B03C163:
+berlin: tc=.subnet13:ha=00DD000A4400:
+norristown: tc=.subnet13:ha=08002001455B:
+pottsville: tc=.subnet13:ha=00DD000A3700:
+ridgway: tc=.subnet19:ha=08002B029425:
+scranton: tc=.subnet232:ha=0800200113A1:
+chalfont: tc=.subnet13:ha=08002001124B:
+washington: tc=.subnet19:ha=00DD00656E00:
+wellsboro: tc=.subnet13:ha=00DD00CB1C00:
+bb1: tc=.subnet19:ha=00DD000A1F00:
+adamstown: tc=.subnet13:ha=08002B02D0E6:
+beta: tc=.subnet19:ha=02070100B197:
+carbondale: tc=.subnet232:ha=08002B022A73:
+clairton: tc=.subnet19:ha=080020010FD1:
+egypt: tc=.subnet13:ha=00DD00847B00:
+fairchance: tc=.subnet232:ha=00DD000AB100:
+fairhope: tc=.subnet232:ha=00DD00CB0800:
+galeton: tc=.subnet232:ha=08002001138C:
+imperial: tc=.subnet232:ha=08002001130C:
+kingston: tc=.subnet232:ha=080020011382:
+knox: tc=.subnet232:ha=50005A1A0D2A:
+lakecity: tc=.subnet13:ha=080020011380:
diff --git a/libexec/bootpd/bootptab.mcs b/libexec/bootpd/bootptab.mcs
new file mode 100644
index 0000000..a798f8a
--- /dev/null
+++ b/libexec/bootpd/bootptab.mcs
@@ -0,0 +1,91 @@
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# Last update: gwr, Sun Dec 12 19:00:00 EDT 1993
+# Blank lines and lines beginning with '#' are ignored.
+#
+# $Id$
+#
+# Legend: (see bootptab.5)
+# first field -- hostname (not indented)
+# bf -- bootfile
+# bs -- bootfile size in 512-octet blocks
+# cs -- cookie servers
+# df -- dump file name
+# dn -- domain name
+# ds -- domain name servers
+# ef -- extension file
+# gw -- gateways
+# ha -- hardware address
+# hd -- home directory for bootfiles
+# hn -- host name set for client
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# ra -- reply address
+# rl -- resource location protocol servers
+# rp -- root path
+# sa -- boot server address
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# td -- TFTP directory
+# to -- time offset (seconds)
+# ts -- time servers
+# vm -- vendor magic number
+# Tn -- generic option tag n
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+# Also, note that generic option data must be either a string or a
+# sequence of bytes where each byte is a two-digit hex value.
+
+# First, we define a global entry which specifies the stuff every host uses.
+
+# If you leave "td" empty, run bootpd with the "-c /tftpboot" switch
+# so path names (boot files) will be interpreted relative to the same
+# directory as tftpd will use when opening files.
+.default:\
+ :hn:dn="mc.com":\
+ :td=/tftpboot:\
+ :ds=merlin, jericho:\
+ :to=auto:
+
+# Next, we can define different master entries for each subnet. . .
+
+.subnet16:\
+ :tc=.default:\
+ :sm=255.255.255.0:\
+ :gw=merlin:\
+ :sa=merlin:
+
+.subnet17:\
+ :tc=.default:\
+ :sm=255.255.255.0:\
+ :gw=merlin-gw:\
+ :sa=merlin-gw:
+
+#
+# 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):
+
+# Emulex terminal server
+emulex: tc=.subnet16:ha=00.00.C9.00.42.E0:bf=P4KTL0E:
+
+# Lantronix eps1
+eps1: tc=.subnet16:ha=00.80.A3.04.1D.78:
+
+# Tadpole 885 board.
+tp885: tc=.subnet17:ha=08.00.4C.00.2F.74:bf=tp885sys2.cfe:
+
+# MVME147 VxWorks board.
+#mvme147:tc=.subnet17:ha=08.00.3e.20.da.47:bf=mv147vxw.st:
+
+# These are just for testing
+bach: tc=.subnet16:ha="08:00:20:04:98:8d":bf=boot.sun4m:
+xanadu:tc=.subnet17:ha="00:80:42:42:04:c7":bf=boot.sun4c:
diff --git a/libexec/bootpd/bptypes.h b/libexec/bootpd/bptypes.h
new file mode 100644
index 0000000..537da4e
--- /dev/null
+++ b/libexec/bootpd/bptypes.h
@@ -0,0 +1,23 @@
+/* bptypes.h */
+
+#ifndef BPTYPES_H
+#define BPTYPES_H
+
+/*
+ * 32 bit integers are different types on various architectures
+ */
+
+#ifndef int32
+#define int32 long
+#endif
+typedef unsigned int32 u_int32;
+
+/*
+ * Nice typedefs. . .
+ */
+
+typedef int boolean;
+typedef unsigned char byte;
+
+
+#endif /* BPTYPES_H */
diff --git a/libexec/bootpd/dovend.c b/libexec/bootpd/dovend.c
new file mode 100644
index 0000000..447826f
--- /dev/null
+++ b/libexec/bootpd/dovend.c
@@ -0,0 +1,414 @@
+/*
+ * dovend.c : Inserts all but the first few vendor options.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+# include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+# define bcopy(a,b,c) memcpy(b,a,c)
+# define bzero(p,l) memset(p,0,l)
+# define bcmp(a,b,c) memcmp(a,b,c)
+# define index strchr
+#endif
+
+#include "bootp.h"
+#include "bootpd.h"
+#include "report.h"
+#include "dovend.h"
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+PRIVATE int insert_generic P((struct shared_bindata *, byte **, int *));
+
+/*
+ * Insert the 2nd part of the options into an option buffer.
+ * Return amount of space used.
+ *
+ * This inserts everything EXCEPT:
+ * magic cookie, subnet mask, gateway, bootsize, extension file
+ * Those are handled separately (in bootpd.c) to allow this function
+ * to be shared between bootpd and bootpef.
+ *
+ * When an "extension file" is in use, the options inserted by
+ * this function go into the exten_file, not the bootp response.
+ */
+
+int
+dovend_rfc1497(hp, buf, len)
+ struct host *hp;
+ byte *buf;
+ int len;
+{
+ int bytesleft = len;
+ byte *vp = buf;
+
+ static char noroom[] = "%s: No room for \"%s\" option";
+#define NEED(LEN, MSG) do \
+ if (bytesleft < (LEN)) { \
+ report(LOG_NOTICE, noroom, \
+ hp->hostname->string, MSG); \
+ return (vp - buf); \
+ } while (0)
+
+ /*
+ * Note that the following have already been inserted:
+ * magic_cookie, subnet_mask, gateway, bootsize
+ *
+ * The remaining options are inserted in order of importance.
+ * (Of course the importance of each is a matter of opinion.)
+ * The option insertion order should probably be configurable.
+ *
+ * This is the order used in the NetBSD version. Can anyone
+ * explain why the time_offset and swap_server are first?
+ * Also, why is the hostname so far down the list? -gwr
+ */
+
+ if (hp->flags.time_offset) {
+ NEED(6, "to");
+ *vp++ = TAG_TIME_OFFSET;/* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(htonl(hp->time_offset), &vp); /* -4 bytes */
+ bytesleft -= 6;
+ }
+ /*
+ * swap server, root path, dump path
+ */
+ if (hp->flags.swap_server) {
+ NEED(6, "sw");
+ /* There is just one SWAP_SERVER, so it is not an iplist. */
+ *vp++ = TAG_SWAP_SERVER;/* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(hp->swap_server.s_addr, &vp); /* -4 bytes */
+ bytesleft -= 6; /* Fix real count */
+ }
+ if (hp->flags.root_path) {
+ /*
+ * Check for room for root_path. Add 2 to account for
+ * TAG_ROOT_PATH and length.
+ */
+ len = strlen(hp->root_path->string);
+ NEED((len + 2), "rp");
+ *vp++ = TAG_ROOT_PATH;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->root_path->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ if (hp->flags.dump_file) {
+ /*
+ * Check for room for dump_file. Add 2 to account for
+ * TAG_DUMP_FILE and length.
+ */
+ len = strlen(hp->dump_file->string);
+ NEED((len + 2), "df");
+ *vp++ = TAG_DUMP_FILE;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->dump_file->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /*
+ * DNS server and domain
+ */
+ if (hp->flags.domain_server) {
+ if (insert_ip(TAG_DOMAIN_SERVER,
+ hp->domain_server,
+ &vp, &bytesleft))
+ NEED(8, "ds");
+ }
+ if (hp->flags.domain_name) {
+ /*
+ * Check for room for domain_name. Add 2 to account for
+ * TAG_DOMAIN_NAME and length.
+ */
+ len = strlen(hp->domain_name->string);
+ NEED((len + 2), "dn");
+ *vp++ = TAG_DOMAIN_NAME;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->domain_name->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /*
+ * NIS (YP) server and domain
+ */
+ if (hp->flags.nis_server) {
+ if (insert_ip(TAG_NIS_SERVER,
+ hp->nis_server,
+ &vp, &bytesleft))
+ NEED(8, "ds");
+ }
+ if (hp->flags.nis_domain) {
+ /*
+ * Check for room for nis_domain. Add 2 to account for
+ * TAG_NIS_DOMAIN and length.
+ */
+ len = strlen(hp->nis_domain->string);
+ NEED((len + 2), "dn");
+ *vp++ = TAG_NIS_DOMAIN;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->nis_domain->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /* IEN 116 name server */
+ if (hp->flags.name_server) {
+ if (insert_ip(TAG_NAME_SERVER,
+ hp->name_server,
+ &vp, &bytesleft))
+ NEED(8, "ns");
+ }
+ if (hp->flags.rlp_server) {
+ if (insert_ip(TAG_RLP_SERVER,
+ hp->rlp_server,
+ &vp, &bytesleft))
+ NEED(8, "rl");
+ }
+ /* Time server (RFC 868) */
+ if (hp->flags.time_server) {
+ if (insert_ip(TAG_TIME_SERVER,
+ hp->time_server,
+ &vp, &bytesleft))
+ NEED(8, "ts");
+ }
+ /* NTP (time) Server (RFC 1129) */
+ if (hp->flags.ntp_server) {
+ if (insert_ip(TAG_NTP_SERVER,
+ hp->ntp_server,
+ &vp, &bytesleft))
+ NEED(8, "ts");
+ }
+ /*
+ * I wonder: If the hostname were "promoted" into the BOOTP
+ * response part, might these "extension" files possibly be
+ * shared between several clients?
+ *
+ * Also, why not just use longer BOOTP packets with all the
+ * additional length used as option data. This bootpd version
+ * already supports that feature by replying with the same
+ * packet length as the client request packet. -gwr
+ */
+ if (hp->flags.name_switch && hp->flags.send_name) {
+ /*
+ * Check for room for hostname. Add 2 to account for
+ * TAG_HOST_NAME and length.
+ */
+ len = strlen(hp->hostname->string);
+#if 0
+ /*
+ * XXX - Too much magic. The user can always set the hostname
+ * to the short version in the bootptab file. -gwr
+ */
+ if ((len + 2) > bytesleft) {
+ /*
+ * Not enough room for full (domain-qualified) hostname, try
+ * stripping it down to just the first field (host).
+ */
+ char *tmpstr = hp->hostname->string;
+ len = 0;
+ while (*tmpstr && (*tmpstr != '.')) {
+ tmpstr++;
+ len++;
+ }
+ }
+#endif
+ NEED((len + 2), "hn");
+ *vp++ = TAG_HOST_NAME;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->hostname->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /*
+ * The rest of these are less important, so they go last.
+ */
+ if (hp->flags.lpr_server) {
+ if (insert_ip(TAG_LPR_SERVER,
+ hp->lpr_server,
+ &vp, &bytesleft))
+ NEED(8, "lp");
+ }
+ if (hp->flags.cookie_server) {
+ if (insert_ip(TAG_COOKIE_SERVER,
+ hp->cookie_server,
+ &vp, &bytesleft))
+ NEED(8, "cs");
+ }
+ if (hp->flags.log_server) {
+ if (insert_ip(TAG_LOG_SERVER,
+ hp->log_server,
+ &vp, &bytesleft))
+ NEED(8, "lg");
+ }
+ /*
+ * XXX - Add new tags here (to insert options)
+ */
+ if (hp->flags.generic) {
+ if (insert_generic(hp->generic, &vp, &bytesleft))
+ NEED(64, "(generic)");
+ }
+ /*
+ * The end marker is inserted by the caller.
+ */
+ return (vp - buf);
+#undef NEED
+} /* dovend_rfc1497 */
+
+
+
+/*
+ * 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.
+ *
+ * Return zero if everything fits.
+ *
+ * This is used to fill the vendor-specific area of a bootp packet in
+ * conformance to RFC1048.
+ */
+
+int
+insert_ip(tag, iplist, dest, bytesleft)
+ byte tag;
+ struct in_addr_list *iplist;
+ byte **dest;
+ int *bytesleft;
+{
+ struct in_addr *addrptr;
+ unsigned addrcount = 1;
+ byte *d;
+
+ if (iplist == NULL)
+ return (0);
+
+ if (*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);
+ }
+ return (addrcount);
+}
+
+
+
+/*
+ * 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.
+ * Return zero if everything fits.
+ */
+
+static int
+insert_generic(gendata, buff, bytesleft)
+ struct shared_bindata *gendata;
+ byte **buff;
+ int *bytesleft;
+{
+ byte *srcptr;
+ int length, numbytes;
+ int skipped = 0;
+
+ if (gendata == NULL)
+ return (0);
+
+ 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)
+ skipped += numbytes;
+ else {
+ bcopy(srcptr, *buff, numbytes);
+ (*buff) += numbytes;
+ (*bytesleft) -= numbytes;
+ }
+ srcptr += numbytes;
+ length -= numbytes;
+ break;
+ }
+ } /* while */
+ return (skipped);
+}
+
+/*
+ * 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)
+ u_int32 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 */
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/dovend.h b/libexec/bootpd/dovend.h
new file mode 100644
index 0000000..b30c982
--- /dev/null
+++ b/libexec/bootpd/dovend.h
@@ -0,0 +1,13 @@
+/* dovend.h */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern int dovend_rfc1497 P((struct host *hp, u_char *buf, int len));
+extern int insert_ip P((int, struct in_addr_list *, u_char **, int *));
+extern void insert_u_long P((u_int32, u_char **));
+
+#undef P
diff --git a/libexec/bootpd/dumptab.c b/libexec/bootpd/dumptab.c
new file mode 100644
index 0000000..3827fd9
--- /dev/null
+++ b/libexec/bootpd/dumptab.c
@@ -0,0 +1,384 @@
+/*
+ * dumptab.c - handles dumping the database
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <time.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "report.h"
+#include "patchlevel.h"
+#include "bootpd.h"
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+static void dump_generic P((FILE *, struct shared_bindata *));
+static void dump_host P((FILE *, struct host *));
+static void list_ipaddresses P((FILE *, struct in_addr_list *));
+
+#undef P
+
+#ifndef DEBUG
+void
+dumptab(filename)
+ char *filename;
+{
+ report(LOG_INFO, "No dumptab support!");
+}
+
+#else /* DEBUG */
+
+/*
+ * Dump the internal memory database to bootpd_dump.
+ */
+
+void
+dumptab(filename)
+ char *filename;
+{
+ int n;
+ struct host *hp;
+ FILE *fp;
+ long t;
+ /* Print symbols in alphabetical order for reader's convenience. */
+ static char legend[] = "#\n# Legend:\t(see bootptab.5)\n\
+#\tfirst field -- hostname (not indented)\n\
+#\tbf -- bootfile\n\
+#\tbs -- bootfile size in 512-octet blocks\n\
+#\tcs -- cookie servers\n\
+#\tdf -- dump file name\n\
+#\tdn -- domain name\n\
+#\tds -- domain name servers\n\
+#\tef -- extension file\n\
+#\tex -- exec file (YORK_EX_OPTION)\n\
+#\tgw -- gateways\n\
+#\tha -- hardware address\n\
+#\thd -- home directory for bootfiles\n\
+#\thn -- host name set for client\n\
+#\tht -- hardware type\n\
+#\tim -- impress servers\n\
+#\tip -- host IP address\n\
+#\tlg -- log servers\n\
+#\tlp -- LPR servers\n\
+#\tms -- message size\n\
+#\tmw -- min wait (secs)\n\
+#\tns -- IEN-116 name servers\n\
+#\tnt -- NTP servers (RFC 1129)\n\
+#\tra -- reply address override\n\
+#\trl -- resource location protocol servers\n\
+#\trp -- root path\n\
+#\tsa -- boot server address\n\
+#\tsm -- subnet mask\n\
+#\tsw -- swap server\n\
+#\ttc -- template host (points to similar host entry)\n\
+#\ttd -- TFTP directory\n\
+#\tto -- time offset (seconds)\n\
+#\tts -- time servers\n\
+#\tvm -- vendor magic number\n\
+#\tyd -- YP (NIS) domain\n\
+#\tys -- YP (NIS) servers\n\
+#\tTn -- generic option tag n\n\
+\n";
+
+ /*
+ * Open bootpd.dump file.
+ */
+ if ((fp = fopen(filename, "w")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s",
+ filename, get_errmsg());
+ exit(1);
+ }
+ t = time(NULL);
+ fprintf(fp, "\n# %s %s.%d\n", progname, VERSION, PATCHLEVEL);
+ fprintf(fp, "# %s: dump of bootp server database.\n", filename);
+ fprintf(fp, "# Dump taken %s", ctime(&t));
+ fwrite(legend, 1, sizeof(legend) - 1, fp);
+
+ 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, filename);
+}
+
+
+
+/*
+ * Dump all the available information on the host pointed to by "hp".
+ * The output is sent to the file pointed to by "fp".
+ */
+
+static void
+dump_host(fp, hp)
+ FILE *fp;
+ struct host *hp;
+{
+ /* Print symbols in alphabetical order for reader's convenience. */
+ if (hp) {
+ fprintf(fp, "%s:", (hp->hostname ?
+ hp->hostname->string : "?"));
+ if (hp->flags.bootfile) {
+ fprintf(fp, "\\\n\t:bf=%s:", hp->bootfile->string);
+ }
+ if (hp->flags.bootsize) {
+ fprintf(fp, "\\\n\t:bs=");
+ if (hp->flags.bootsize_auto) {
+ fprintf(fp, "auto:");
+ } else {
+ fprintf(fp, "%d:", hp->bootsize);
+ }
+ }
+ if (hp->flags.cookie_server) {
+ fprintf(fp, "\\\n\t:cs=");
+ list_ipaddresses(fp, hp->cookie_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.dump_file) {
+ fprintf(fp, "\\\n\t:df=%s:", hp->dump_file->string);
+ }
+ if (hp->flags.domain_name) {
+ fprintf(fp, "\\\n\t:dn=%s:", hp->domain_name->string);
+ }
+ if (hp->flags.domain_server) {
+ fprintf(fp, "\\\n\t:ds=");
+ list_ipaddresses(fp, hp->domain_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.exten_file) {
+ fprintf(fp, "\\\n\t:ef=%s:", hp->exten_file->string);
+ }
+ if (hp->flags.exec_file) {
+ fprintf(fp, "\\\n\t:ex=%s:", hp->exec_file->string);
+ }
+ if (hp->flags.gateway) {
+ fprintf(fp, "\\\n\t:gw=");
+ list_ipaddresses(fp, hp->gateway);
+ fprintf(fp, ":");
+ }
+ /* FdC: swap_server (see below) */
+ if (hp->flags.homedir) {
+ fprintf(fp, "\\\n\t:hd=%s:", hp->homedir->string);
+ }
+ /* FdC: dump_file (see above) */
+ /* FdC: domain_name (see above) */
+ /* FdC: root_path (see below) */
+ if (hp->flags.name_switch && hp->flags.send_name) {
+ fprintf(fp, "\\\n\t:hn:");
+ }
+ if (hp->flags.htype) {
+ int hlen = haddrlength(hp->htype);
+ fprintf(fp, "\\\n\t:ht=%u:", (unsigned) hp->htype);
+ if (hp->flags.haddr) {
+ fprintf(fp, "ha=\"%s\":",
+ haddrtoa(hp->haddr, hlen));
+ }
+ }
+ if (hp->flags.impress_server) {
+ fprintf(fp, "\\\n\t:im=");
+ list_ipaddresses(fp, hp->impress_server);
+ fprintf(fp, ":");
+ }
+ /* NetBSD: swap_server (see below) */
+ if (hp->flags.iaddr) {
+ fprintf(fp, "\\\n\t:ip=%s:", inet_ntoa(hp->iaddr));
+ }
+ if (hp->flags.log_server) {
+ fprintf(fp, "\\\n\t:lg=");
+ list_ipaddresses(fp, hp->log_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.lpr_server) {
+ fprintf(fp, "\\\n\t:lp=");
+ list_ipaddresses(fp, hp->lpr_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.msg_size) {
+ fprintf(fp, "\\\n\t:ms=%d:", hp->msg_size);
+ }
+ if (hp->flags.min_wait) {
+ fprintf(fp, "\\\n\t:mw=%d:", hp->min_wait);
+ }
+ if (hp->flags.name_server) {
+ fprintf(fp, "\\\n\t:ns=");
+ list_ipaddresses(fp, hp->name_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.ntp_server) {
+ fprintf(fp, "\\\n\t:nt=");
+ list_ipaddresses(fp, hp->ntp_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.reply_addr) {
+ fprintf(fp, "\\\n\t:ra=%s:", inet_ntoa(hp->reply_addr));
+ }
+ if (hp->flags.rlp_server) {
+ fprintf(fp, "\\\n\t:rl=");
+ list_ipaddresses(fp, hp->rlp_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.root_path) {
+ fprintf(fp, "\\\n\t:rp=%s:", hp->root_path->string);
+ }
+ if (hp->flags.bootserver) {
+ fprintf(fp, "\\\n\t:sa=%s:", inet_ntoa(hp->bootserver));
+ }
+ if (hp->flags.subnet_mask) {
+ fprintf(fp, "\\\n\t:sm=%s:", inet_ntoa(hp->subnet_mask));
+ }
+ if (hp->flags.swap_server) {
+ fprintf(fp, "\\\n\t:sw=%s:", inet_ntoa(hp->subnet_mask));
+ }
+ if (hp->flags.tftpdir) {
+ fprintf(fp, "\\\n\t:td=%s:", hp->tftpdir->string);
+ }
+ /* NetBSD: rootpath (see above) */
+ /* NetBSD: domainname (see above) */
+ /* NetBSD: dumpfile (see above) */
+ if (hp->flags.time_offset) {
+ fprintf(fp, "\\\n\t:to=%ld:", hp->time_offset);
+ }
+ if (hp->flags.time_server) {
+ fprintf(fp, "\\\n\t:ts=");
+ list_ipaddresses(fp, hp->time_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.vm_cookie) {
+ fprintf(fp, "\\\n\t:vm=");
+ if (!bcmp(hp->vm_cookie, vm_rfc1048, 4)) {
+ fprintf(fp, "rfc1048:");
+ } else if (!bcmp(hp->vm_cookie, vm_cmu, 4)) {
+ fprintf(fp, "cmu:");
+ } 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.nis_domain) {
+ fprintf(fp, "\\\n\t:yd=%s:",
+ hp->nis_domain->string);
+ }
+ if (hp->flags.nis_server) {
+ fprintf(fp, "\\\n\t:ys=");
+ list_ipaddresses(fp, hp->nis_server);
+ fprintf(fp, ":");
+ }
+ /*
+ * XXX - Add new tags here (or above,
+ * so they print in alphabetical order).
+ */
+
+ if (hp->flags.generic) {
+ dump_generic(fp, hp->generic);
+ }
+ }
+}
+
+
+static void
+dump_generic(fp, generic)
+ FILE *fp;
+ struct shared_bindata *generic;
+{
+ u_char *bp = generic->data;
+ u_char *ep = bp + generic->length;
+ u_char tag;
+ int len;
+
+ while (bp < ep) {
+ tag = *bp++;
+ if (tag == TAG_PAD)
+ continue;
+ if (tag == TAG_END)
+ return;
+ len = *bp++;
+ if (bp + len > ep) {
+ fprintf(fp, " #junk in generic! :");
+ return;
+ }
+ fprintf(fp, "\\\n\t:T%d=", tag);
+ while (len) {
+ fprintf(fp, "%02X", *bp);
+ bp++;
+ len--;
+ if (len)
+ fprintf(fp, ".");
+ }
+ 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).
+ */
+
+static 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;
+ while (count > 0) {
+ fprintf(fp, "%s", inet_ntoa(*addrptr++));
+ count--;
+ if (count)
+ fprintf(fp, ", ");
+ }
+ }
+}
+
+#endif /* DEBUG */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/getether.c b/libexec/bootpd/getether.c
new file mode 100644
index 0000000..cf01b03
--- /dev/null
+++ b/libexec/bootpd/getether.c
@@ -0,0 +1,386 @@
+/*
+ * getether.c : get the ethernet address of an interface
+ *
+ * All of this code is quite system-specific. As you may well
+ * guess, it took a good bit of detective work to figure out!
+ *
+ * If you figure out how to do this on another system,
+ * please let me know. <gwr@mc.com>
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+
+#include <ctype.h>
+#include <syslog.h>
+
+#include "getether.h"
+#include "report.h"
+#define EALEN 6
+
+#if defined(ultrix) || (defined(__osf__) && defined(__alpha))
+/*
+ * This is really easy on Ultrix! Thanks to
+ * Harald Lundberg <hl@tekla.fi> for this code.
+ *
+ * The code here is not specific to the Alpha, but that was the
+ * only symbol we could find to identify DEC's version of OSF.
+ * (Perhaps we should just define DEC in the Makefile... -gwr)
+ */
+
+#include <sys/ioctl.h>
+#include <net/if.h> /* struct ifdevea */
+
+getether(ifname, eap)
+ char *ifname, *eap;
+{
+ int rc = -1;
+ int fd;
+ struct ifdevea phys;
+ bzero(&phys, sizeof(phys));
+ strcpy(phys.ifr_name, ifname);
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
+ return -1;
+ }
+ if (ioctl(fd, SIOCRPHYSADDR, &phys) < 0) {
+ report(LOG_ERR, "getether: ioctl SIOCRPHYSADDR failed");
+ } else {
+ bcopy(&phys.current_pa[0], eap, EALEN);
+ rc = 0;
+ }
+ close(fd);
+ return rc;
+}
+
+#define GETETHER
+#endif /* ultrix|osf1 */
+
+
+#ifdef SUNOS
+
+#include <sys/sockio.h>
+#include <sys/time.h> /* needed by net_if.h */
+#include <net/nit_if.h> /* for NIOCBIND */
+#include <net/if.h> /* for struct ifreq */
+
+getether(ifname, eap)
+ char *ifname; /* interface name from ifconfig structure */
+ char *eap; /* Ether address (output) */
+{
+ int rc = -1;
+
+ struct ifreq ifrnit;
+ int nit;
+
+ bzero((char *) &ifrnit, sizeof(ifrnit));
+ strncpy(&ifrnit.ifr_name[0], ifname, IFNAMSIZ);
+
+ nit = open("/dev/nit", 0);
+ if (nit < 0) {
+ report(LOG_ERR, "getether: open /dev/nit: %s",
+ get_errmsg());
+ return rc;
+ }
+ do {
+ if (ioctl(nit, NIOCBIND, &ifrnit) < 0) {
+ report(LOG_ERR, "getether: NIOCBIND on nit");
+ break;
+ }
+ if (ioctl(nit, SIOCGIFADDR, &ifrnit) < 0) {
+ report(LOG_ERR, "getether: SIOCGIFADDR on nit");
+ break;
+ }
+ bcopy(&ifrnit.ifr_addr.sa_data[0], eap, EALEN);
+ rc = 0;
+ } while (0);
+ close(nit);
+ return rc;
+}
+
+#define GETETHER
+#endif /* SUNOS */
+
+
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+/* Thanks to John Brezak <brezak@ch.hp.com> for this code. */
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+getether(ifname, eap)
+ char *ifname; /* interface name from ifconfig structure */
+ char *eap; /* Ether address (output) */
+{
+ int fd, rc = -1;
+ register int n;
+ struct ifreq ibuf[16], ifr;
+ struct ifconf ifc;
+ register struct ifreq *ifrp, *ifend;
+
+ /* Fetch the interface configuration */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ report(LOG_ERR, "getether: socket %s: %s", ifname, get_errmsg());
+ return (fd);
+ }
+ ifc.ifc_len = sizeof(ibuf);
+ ifc.ifc_buf = (caddr_t) ibuf;
+ if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ report(LOG_ERR, "getether: SIOCGIFCONF: %s", get_errmsg);
+ goto out;
+ }
+ /* Search interface configuration list for link layer address. */
+ ifrp = ibuf;
+ ifend = (struct ifreq *) ((char *) ibuf + ifc.ifc_len);
+ while (ifrp < ifend) {
+ /* Look for interface */
+ if (strcmp(ifname, ifrp->ifr_name) == 0 &&
+ ifrp->ifr_addr.sa_family == AF_LINK &&
+ ((struct sockaddr_dl *) &ifrp->ifr_addr)->sdl_type == IFT_ETHER) {
+ bcopy(LLADDR((struct sockaddr_dl *) &ifrp->ifr_addr), eap, EALEN);
+ rc = 0;
+ break;
+ }
+ /* Bump interface config pointer */
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ n = sizeof(*ifrp);
+ ifrp = (struct ifreq *) ((char *) ifrp + n);
+ }
+
+ out:
+ close(fd);
+ return (rc);
+}
+
+#define GETETHER
+#endif /* __NetBSD__ */
+
+
+#ifdef SVR4
+/*
+ * This is for "Streams TCP/IP" by Lachman Associates.
+ * They sure made this cumbersome! -gwr
+ */
+
+#include <sys/sockio.h>
+#include <sys/dlpi.h>
+#include <stropts.h>
+#include <string.h>
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getether(ifname, eap)
+ char *ifname; /* interface name from ifconfig structure */
+ char *eap; /* Ether address (output) */
+{
+ int rc = -1;
+ char devname[32];
+ char tmpbuf[sizeof(union DL_primitives) + 16];
+ struct strbuf cbuf;
+ int fd, flags;
+ union DL_primitives *dlp;
+ char *enaddr;
+ int unit = -1; /* which unit to attach */
+
+ sprintf(devname, "/dev/%s", ifname);
+ fd = open(devname, 2);
+ if (fd < 0) {
+ /* Try without the trailing digit. */
+ char *p = devname + 5;
+ while (isalpha(*p))
+ p++;
+ if (isdigit(*p)) {
+ unit = *p - '0';
+ *p = '\0';
+ }
+ fd = open(devname, 2);
+ if (fd < 0) {
+ report(LOG_ERR, "getether: open %s: %s",
+ devname, get_errmsg());
+ return rc;
+ }
+ }
+#ifdef DL_ATTACH_REQ
+ /*
+ * If this is a "Style 2" DLPI, then we must "attach" first
+ * to tell the driver which unit (board, port) we want.
+ * For now, decide this based on the device name.
+ * (Should do "info_req" and check dl_provider_style ...)
+ */
+ if (unit >= 0) {
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ dlp = (union DL_primitives *) tmpbuf;
+ dlp->dl_primitive = DL_ATTACH_REQ;
+ dlp->attach_req.dl_ppa = unit;
+ cbuf.buf = tmpbuf;
+ cbuf.len = DL_ATTACH_REQ_SIZE;
+ if (putmsg(fd, &cbuf, NULL, 0) < 0) {
+ report(LOG_ERR, "getether: attach: putmsg: %s", get_errmsg());
+ goto out;
+ }
+ /* Recv the ack. */
+ cbuf.buf = tmpbuf;
+ cbuf.maxlen = sizeof(tmpbuf);
+ flags = 0;
+ if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
+ report(LOG_ERR, "getether: attach: getmsg: %s", get_errmsg());
+ goto out;
+ }
+ /*
+ * Check the type, etc.
+ */
+ if (dlp->dl_primitive == DL_ERROR_ACK) {
+ report(LOG_ERR, "getether: attach: dlpi_errno=%d, unix_errno=%d",
+ dlp->error_ack.dl_errno,
+ dlp->error_ack.dl_unix_errno);
+ goto out;
+ }
+ if (dlp->dl_primitive != DL_OK_ACK) {
+ report(LOG_ERR, "getether: attach: not OK or ERROR");
+ goto out;
+ }
+ } /* unit >= 0 */
+#endif /* DL_ATTACH_REQ */
+
+ /*
+ * Get the Ethernet address the same way the ARP module
+ * does when it is pushed onto a new stream (bind).
+ * One should instead be able just do an dl_info_req
+ * but many drivers do not supply the hardware address
+ * in the response to dl_info_req (they MUST supply it
+ * for dl_bind_ack because the ARP module requires it).
+ */
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ dlp = (union DL_primitives *) tmpbuf;
+ dlp->dl_primitive = DL_BIND_REQ;
+ dlp->bind_req.dl_sap = 0x8FF; /* XXX - Unused SAP */
+ cbuf.buf = tmpbuf;
+ cbuf.len = DL_BIND_REQ_SIZE;
+ if (putmsg(fd, &cbuf, NULL, 0) < 0) {
+ report(LOG_ERR, "getether: bind: putmsg: %s", get_errmsg());
+ goto out;
+ }
+ /* Recv the ack. */
+ cbuf.buf = tmpbuf;
+ cbuf.maxlen = sizeof(tmpbuf);
+ flags = 0;
+ if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
+ report(LOG_ERR, "getether: bind: getmsg: %s", get_errmsg());
+ goto out;
+ }
+ /*
+ * Check the type, etc.
+ */
+ if (dlp->dl_primitive == DL_ERROR_ACK) {
+ report(LOG_ERR, "getether: bind: dlpi_errno=%d, unix_errno=%d",
+ dlp->error_ack.dl_errno,
+ dlp->error_ack.dl_unix_errno);
+ goto out;
+ }
+ if (dlp->dl_primitive != DL_BIND_ACK) {
+ report(LOG_ERR, "getether: bind: not OK or ERROR");
+ goto out;
+ }
+ if (dlp->bind_ack.dl_addr_offset == 0) {
+ report(LOG_ERR, "getether: bind: ack has no address");
+ goto out;
+ }
+ if (dlp->bind_ack.dl_addr_length < EALEN) {
+ report(LOG_ERR, "getether: bind: ack address truncated");
+ goto out;
+ }
+ /*
+ * Copy the Ethernet address out of the message.
+ */
+ enaddr = tmpbuf + dlp->bind_ack.dl_addr_offset;
+ memcpy(eap, enaddr, EALEN);
+ rc = 0;
+
+ out:
+ close(fd);
+ return rc;
+}
+
+#define GETETHER
+#endif /* SVR4 */
+
+
+#ifdef __linux__
+/*
+ * This is really easy on Linux! This version (for linux)
+ * written by Nigel Metheringham <nigelm@ohm.york.ac.uk> and
+ * updated by Pauline Middelink <middelin@polyware.iaf.nl>
+ *
+ * The code is almost identical to the Ultrix code - however
+ * the names are different to confuse the innocent :-)
+ * Most of this code was stolen from the Ultrix bit above.
+ */
+
+#include <memory.h>
+#include <sys/ioctl.h>
+#include <net/if.h> /* struct ifreq */
+#include <sys/socketio.h> /* Needed for IOCTL defs */
+
+int
+getether(ifname, eap)
+ char *ifname, *eap;
+{
+ int rc = -1;
+ int fd;
+ struct ifreq phys;
+
+ memset(&phys, 0, sizeof(phys));
+ strcpy(phys.ifr_name, ifname);
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
+ return -1;
+ }
+ if (ioctl(fd, SIOCGIFHWADDR, &phys) < 0) {
+ report(LOG_ERR, "getether: ioctl SIOCGIFHWADDR failed");
+ } else {
+ memcpy(eap, &phys.ifr_hwaddr.sa_data, EALEN);
+ rc = 0;
+ }
+ close(fd);
+ return rc;
+}
+
+#define GETETHER
+#endif /* __linux__ */
+
+
+/* If we don't know how on this system, just return an error. */
+#ifndef GETETHER
+int
+getether(ifname, eap)
+ char *ifname, *eap;
+{
+ return -1;
+}
+
+#endif /* !GETETHER */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/getether.h b/libexec/bootpd/getether.h
new file mode 100644
index 0000000..2f98299
--- /dev/null
+++ b/libexec/bootpd/getether.h
@@ -0,0 +1,7 @@
+/* getether.h */
+
+#ifdef __STDC__
+extern int getether(char *ifname, char *eaptr);
+#else
+extern int getether();
+#endif
diff --git a/libexec/bootpd/getif.c b/libexec/bootpd/getif.c
new file mode 100644
index 0000000..ecfa610
--- /dev/null
+++ b/libexec/bootpd/getif.c
@@ -0,0 +1,147 @@
+/*
+ * getif.c : get an interface structure
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+#ifdef SVR4
+#include <sys/stropts.h>
+#endif
+
+#include <sys/time.h> /* for struct timeval in net/if.h */
+#include <net/if.h> /* for struct ifreq */
+#include <netinet/in.h>
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <syslog.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "getif.h"
+#include "report.h"
+
+#ifdef __bsdi__
+#define BSD 43
+#endif
+
+static struct ifreq ifreq[10]; /* Holds interface configuration */
+static struct ifconf ifconf; /* points to ifreq */
+
+static int nmatch();
+
+/* Return a pointer to the interface struct for the passed address. */
+struct ifreq *
+getif(s, addrp)
+ int s; /* socket file descriptor */
+ struct in_addr *addrp; /* destination address on interface */
+{
+ int maxmatch;
+ int len, m, incr;
+ struct ifreq *ifrq, *ifrmax;
+ struct sockaddr_in *sip;
+ char *p;
+
+ /* If no address was supplied, just return NULL. */
+ if (!addrp)
+ return (struct ifreq *) 0;
+
+ /* Get the interface config if not done already. */
+ if (ifconf.ifc_len == 0) {
+#ifdef SVR4
+ /*
+ * SysVr4 returns garbage if you do this the obvious way!
+ * This one took a while to figure out... -gwr
+ */
+ struct strioctl ioc;
+ ioc.ic_cmd = SIOCGIFCONF;
+ ioc.ic_timout = 0;
+ ioc.ic_len = sizeof(ifreq);
+ ioc.ic_dp = (char *) ifreq;
+ m = ioctl(s, I_STR, (char *) &ioc);
+ ifconf.ifc_len = ioc.ic_len;
+ ifconf.ifc_req = ifreq;
+#else /* SVR4 */
+ ifconf.ifc_len = sizeof(ifreq);
+ ifconf.ifc_req = ifreq;
+ m = ioctl(s, SIOCGIFCONF, (caddr_t) & ifconf);
+#endif /* SVR4 */
+ if ((m < 0) || (ifconf.ifc_len <= 0)) {
+ report(LOG_ERR, "ioctl SIOCGIFCONF");
+ return (struct ifreq *) 0;
+ }
+ }
+ maxmatch = 7; /* this many bits or less... */
+ ifrmax = (struct ifreq *) 0;/* ... is not a valid match */
+ p = (char *) ifreq;
+ len = ifconf.ifc_len;
+ while (len > 0) {
+ ifrq = (struct ifreq *) p;
+ sip = (struct sockaddr_in *) &ifrq->ifr_addr;
+ m = nmatch(addrp, &(sip->sin_addr));
+ if (m > maxmatch) {
+ maxmatch = m;
+ ifrmax = ifrq;
+ }
+#ifndef IFNAMSIZ
+ /* BSD not defined or earlier than 4.3 */
+ incr = sizeof(*ifrq);
+#else
+ incr = ifrq->ifr_addr.sa_len + IFNAMSIZ;
+#endif
+
+ p += incr;
+ len -= incr;
+ }
+
+ return ifrmax;
+}
+
+/*
+ * Return the number of leading bits matching in the
+ * internet addresses supplied.
+ */
+static int
+nmatch(ca, cb)
+ u_char *ca, *cb; /* ptrs to IP address, network order */
+{
+ u_int m = 0; /* count of matching bits */
+ u_int n = 4; /* bytes left, then bitmask */
+
+ /* Count matching bytes. */
+ while (n && (*ca == *cb)) {
+ ca++;
+ cb++;
+ m += 8;
+ n--;
+ }
+ /* Now count matching bits. */
+ if (n) {
+ n = 0x80;
+ while (n && ((*ca & n) == (*cb & n))) {
+ m++;
+ n >>= 1;
+ }
+ }
+ return (m);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/getif.h b/libexec/bootpd/getif.h
new file mode 100644
index 0000000..c51dafd
--- /dev/null
+++ b/libexec/bootpd/getif.h
@@ -0,0 +1,7 @@
+/* getif.h */
+
+#ifdef __STDC__
+extern struct ifreq *getif(int, struct in_addr *);
+#else
+extern struct ifreq *getif();
+#endif
diff --git a/libexec/bootpd/hash.c b/libexec/bootpd/hash.c
new file mode 100644
index 0000000..f959751
--- /dev/null
+++ b/libexec/bootpd/hash.c
@@ -0,0 +1,423 @@
+/************************************************************************
+ 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.
+
+ $Id$
+
+************************************************************************/
+
+/*
+ * 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 <sys/types.h>
+#include <stdlib.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "hash.h"
+
+#define TRUE 1
+#define FALSE 0
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * This can be changed to make internal routines visible to debuggers, etc.
+ */
+#ifndef PRIVATE
+#define PRIVATE static
+#endif
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+PRIVATE void hashi_FreeMembers P((hash_member *, hash_freefp));
+
+#undef P
+
+
+
+/*
+ * 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 */
+}
+
+
+
+/*
+ * 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_FreeMembers(bucketptr, free_data)
+ hash_member *bucketptr;
+ hash_freefp free_data;
+{
+ hash_member *nextbucket;
+ while (bucketptr) {
+ nextbucket = bucketptr->next;
+ (*free_data) (bucketptr->data);
+ free((char *) bucketptr);
+ bucketptr = nextbucket;
+ }
+}
+
+
+
+
+/*
+ * 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;
+ hash_freefp free_data;
+{
+ hash_member **bucketptr;
+ unsigned i;
+
+ bucketptr = hashtable->table;
+ for (i = 0; i < hashtable->size; i++) {
+ hashi_FreeMembers(*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;
+ hash_cmpfp 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;
+ hash_cmpfp compare;
+ hash_datum *key, *element;
+{
+ hash_member *temp;
+
+ hashcode %= hashtable->size;
+ if (hash_Exists(hashtable, hashcode, compare, key)) {
+ return -1; /* At least one entry already exists */
+ }
+ temp = (hash_member *) malloc(sizeof(hash_member));
+ if (!temp)
+ return -1; /* malloc failed! */
+
+ temp->data = element;
+ temp->next = (hashtable->table)[hashcode];
+ (hashtable->table)[hashcode] = temp;
+ return 0; /* Success */
+}
+
+
+
+/*
+ * 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;
+ hash_cmpfp compare;
+ hash_datum *key;
+ hash_freefp free_data;
+{
+ hash_member *memberptr, *tempptr;
+ hash_member *previous = NULL;
+ 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_FreeMembers() from deleting the whole list!
+ */
+ memberptr->next = NULL;
+ hashi_FreeMembers(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_FreeMembers(). . . .
+ */
+ tempptr->next = NULL;
+ hashi_FreeMembers(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;
+ hash_cmpfp 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);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/hash.h b/libexec/bootpd/hash.h
new file mode 100644
index 0000000..51d0a5e
--- /dev/null
+++ b/libexec/bootpd/hash.h
@@ -0,0 +1,158 @@
+#ifndef HASH_H
+#define HASH_H
+/* hash.h */
+/************************************************************************
+ 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.
+************************************************************************/
+
+/*
+ * 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
+ */
+
+
+/*
+ * 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 */
+};
+
+/* ANSI function prototypes or empty arg list? */
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+typedef int (*hash_cmpfp) P((hash_datum *, hash_datum *));
+typedef void (*hash_freefp) P((hash_datum *));
+
+extern hash_tbl *hash_Init P((u_int tablesize));
+
+extern void hash_Reset P((hash_tbl *tbl, hash_freefp));
+
+extern unsigned hash_HashFunction P((u_char *str, u_int len));
+
+extern int hash_Exists P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key));
+
+extern int hash_Insert P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key,
+ hash_datum *element));
+
+extern int hash_Delete P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key,
+ hash_freefp));
+
+extern hash_datum *hash_Lookup P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key));
+
+extern hash_datum *hash_FirstEntry P((hash_tbl *));
+
+extern hash_datum *hash_NextEntry P((hash_tbl *));
+
+#undef P
+
+#endif /* HASH_H */
diff --git a/libexec/bootpd/hwaddr.c b/libexec/bootpd/hwaddr.c
new file mode 100644
index 0000000..bc41cff
--- /dev/null
+++ b/libexec/bootpd/hwaddr.c
@@ -0,0 +1,352 @@
+/*
+ * hwaddr.c - routines that deal with hardware addresses.
+ * (i.e. Ethernet)
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+#ifdef SVR4
+#include <sys/stream.h>
+#include <stropts.h>
+#include <fcntl.h>
+#endif
+
+#ifdef _AIX32
+#include <sys/time.h> /* for struct timeval in net/if.h */
+#include <net/if.h> /* for struct ifnet in net/if_arp.h */
+#endif
+
+#include <net/if_arp.h>
+#include <netinet/in.h>
+
+#ifdef WIN_TCP
+#include <netinet/if_ether.h>
+#include <sys/dlpi.h>
+#endif
+
+#include <stdio.h>
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+/* Yes, memcpy is OK here (no overlapped copies). */
+#include <memory.h>
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#ifndef ATF_INUSE /* Not defined on some systems (i.e. Linux) */
+#define ATF_INUSE 0
+#endif
+
+/* For BSD 4.4, set arp entry by writing to routing socket */
+#if defined(BSD)
+#if BSD >= 199306
+extern int bsd_arp_set __P((struct in_addr *, char *, int));
+#endif
+#endif
+
+#include "bptypes.h"
+#include "hwaddr.h"
+#include "report.h"
+
+extern int debug;
+
+/*
+ * 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[] =
+{
+ {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 */
+};
+int hwinfocnt = sizeof(hwinfolist) / sizeof(hwinfolist[0]);
+
+
+/*
+ * Setup the arp cache so that IP address 'ia' will be temporarily
+ * bound to hardware address 'ha' of length 'len'.
+ */
+void
+setarp(s, ia, hafamily, haddr, halen)
+ int s; /* socket fd */
+ struct in_addr *ia; /* protocol address */
+ int hafamily; /* HW address family */
+ u_char *haddr; /* HW address data */
+ int halen;
+{
+#ifdef SIOCSARP
+#ifdef WIN_TCP
+ /* This is an SVR4 with different networking code from
+ * Wollongong WIN-TCP. Not quite like the Lachman code.
+ * Code from: drew@drewsun.FEITH.COM (Andrew B. Sudell)
+ */
+#undef SIOCSARP
+#define SIOCSARP ARP_ADD
+ struct arptab arpreq; /* Arp table entry */
+
+ bzero((caddr_t) &arpreq, sizeof(arpreq));
+ arpreq.at_flags = ATF_COM;
+
+ /* Set up IP address */
+ arpreq.at_in = ia->s_addr;
+
+ /* Set up Hardware Address */
+ bcopy(haddr, arpreq.at_enaddr, halen);
+
+ /* Set the Date Link type. */
+ /* XXX - Translate (hafamily) to dltype somehow? */
+ arpreq.at_dltype = DL_ETHER;
+
+#else /* WIN_TCP */
+ /* Good old Berkeley way. */
+ struct arpreq arpreq; /* Arp request ioctl block */
+ struct sockaddr_in *si;
+ char *p;
+
+ bzero((caddr_t) &arpreq, sizeof(arpreq));
+ arpreq.arp_flags = ATF_INUSE | ATF_COM;
+
+ /* Set up the protocol address. */
+ arpreq.arp_pa.sa_family = AF_INET;
+ si = (struct sockaddr_in *) &arpreq.arp_pa;
+ si->sin_addr = *ia;
+
+ /* Set up the hardware address. */
+#ifdef __linux__ /* XXX - Do others need this? -gwr */
+ /*
+ * Linux requires the sa_family field set.
+ * longyear@netcom.com (Al Longyear)
+ */
+ arpreq.arp_ha.sa_family = hafamily;
+#endif /* linux */
+
+ /* This variable is just to help catch type mismatches. */
+ p = arpreq.arp_ha.sa_data;
+ bcopy(haddr, p, halen);
+#endif /* WIN_TCP */
+
+#ifdef SVR4
+ /*
+ * And now the stuff for System V Rel 4.x which does not
+ * appear to allow SIOCxxx ioctls on a socket descriptor.
+ * Thanks to several people: (all sent the same fix)
+ * Barney Wolff <barney@databus.com>,
+ * bear@upsys.se (Bj|rn Sj|holm),
+ * Michael Kuschke <Michael.Kuschke@Materna.DE>,
+ */
+ {
+ int fd;
+ struct strioctl iocb;
+
+ if ((fd=open("/dev/arp", O_RDWR)) < 0) {
+ report(LOG_ERR, "open /dev/arp: %s\n", get_errmsg());
+ }
+ iocb.ic_cmd = SIOCSARP;
+ iocb.ic_timout = 0;
+ iocb.ic_dp = (char *)&arpreq;
+ iocb.ic_len = sizeof(arpreq);
+ if (ioctl(fd, I_STR, (caddr_t)&iocb) < 0) {
+ report(LOG_ERR, "ioctl I_STR: %s\n", get_errmsg());
+ }
+ close (fd);
+ }
+#else /* SVR4 */
+ /*
+ * On SunOS, the ioctl sometimes returns ENXIO, and it
+ * appears to happen when the ARP cache entry you tried
+ * to add is already in the cache. (Sigh...)
+ * XXX - Should this error simply be ignored? -gwr
+ */
+ if (ioctl(s, SIOCSARP, (caddr_t) &arpreq) < 0) {
+ report(LOG_ERR, "ioctl SIOCSARP: %s", get_errmsg());
+ }
+#endif /* SVR4 */
+#else /* SIOCSARP */
+#if defined(BSD) && (BSD >= 199306)
+ bsd_arp_set(ia, haddr, halen);
+#else
+ /*
+ * Oh well, SIOCSARP is not defined. Just run arp(8).
+ * Need to delete partial entry first on some systems.
+ * XXX - Gag!
+ */
+ int status;
+ char buf[256];
+ char *a;
+ extern char *inet_ntoa();
+
+ a = inet_ntoa(*ia);
+ sprintf(buf, "arp -d %s; arp -s %s %s temp",
+ a, a, haddrtoa(haddr, halen));
+ if (debug > 2)
+ report(LOG_INFO, buf);
+ status = system(buf);
+ if (status)
+ report(LOG_ERR, "arp failed, exit code=0x%x", status);
+ return;
+#endif /* ! 4.4 BSD */
+#endif /* SIOCSARP */
+}
+
+
+/*
+ * Convert a hardware address to an ASCII string.
+ */
+char *
+haddrtoa(haddr, hlen)
+ u_char *haddr;
+ int hlen;
+{
+ static char haddrbuf[3 * MAXHADDRLEN + 1];
+ char *bufptr;
+
+ if (hlen > MAXHADDRLEN)
+ hlen = MAXHADDRLEN;
+
+ bufptr = haddrbuf;
+ while (hlen > 0) {
+ sprintf(bufptr, "%02X:", (unsigned) (*haddr++ & 0xFF));
+ bufptr += 3;
+ hlen--;
+ }
+ bufptr[-1] = 0;
+ return (haddrbuf);
+}
+
+
+/*
+ * haddr_conv802()
+ * --------------
+ *
+ * Converts a backwards address to a canonical address and a canonical address
+ * to a backwards address.
+ *
+ * INPUTS:
+ * adr_in - pointer to six byte string to convert (unsigned char *)
+ * addr_len - how many bytes to convert
+ *
+ * OUTPUTS:
+ * addr_out - The string is updated to contain the converted address.
+ *
+ * CALLER:
+ * many
+ *
+ * DATA:
+ * Uses conv802table to bit-reverse the address bytes.
+ */
+
+static u_char conv802table[256] =
+{
+ /* 0x00 */ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ /* 0x08 */ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ /* 0x10 */ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ /* 0x18 */ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ /* 0x20 */ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ /* 0x28 */ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ /* 0x30 */ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ /* 0x38 */ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ /* 0x40 */ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ /* 0x48 */ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ /* 0x50 */ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ /* 0x58 */ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ /* 0x60 */ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ /* 0x68 */ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ /* 0x70 */ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ /* 0x78 */ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ /* 0x80 */ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ /* 0x88 */ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ /* 0x90 */ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ /* 0x98 */ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ /* 0xA0 */ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ /* 0xA8 */ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ /* 0xB0 */ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ /* 0xB8 */ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ /* 0xC0 */ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ /* 0xC8 */ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ /* 0xD0 */ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ /* 0xD8 */ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ /* 0xE0 */ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ /* 0xE8 */ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ /* 0xF0 */ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ /* 0xF8 */ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
+};
+
+void
+haddr_conv802(addr_in, addr_out, len)
+ register u_char *addr_in, *addr_out;
+ int len;
+{
+ u_char *lim;
+
+ lim = addr_out + len;
+ while (addr_out < lim)
+ *addr_out++ = conv802table[*addr_in++];
+}
+
+#if 0
+/*
+ * For the record, here is a program to generate the
+ * bit-reverse table above.
+ */
+static int
+bitrev(n)
+ int n;
+{
+ int i, r;
+
+ r = 0;
+ for (i = 0; i < 8; i++) {
+ r <<= 1;
+ r |= (n & 1);
+ n >>= 1;
+ }
+ return r;
+}
+
+main()
+{
+ int i;
+ for (i = 0; i <= 0xFF; i++) {
+ if ((i & 7) == 0)
+ printf("/* 0x%02X */", i);
+ printf(" 0x%02X,", bitrev(i));
+ if ((i & 7) == 7)
+ printf("\n");
+ }
+}
+
+#endif
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/hwaddr.h b/libexec/bootpd/hwaddr.h
new file mode 100644
index 0000000..b0a8c29
--- /dev/null
+++ b/libexec/bootpd/hwaddr.h
@@ -0,0 +1,44 @@
+/*
+ * hwaddr.h
+ *
+ * $Id$
+ */
+
+#ifndef HWADDR_H
+#define HWADDR_H
+
+#define MAXHADDRLEN 8 /* Max hw address length in bytes */
+
+/*
+ * 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 int hlen;
+ char *name;
+};
+
+extern struct hwinfo hwinfolist[];
+extern int hwinfocnt;
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern void setarp P((int, struct in_addr *, int, u_char *, int));
+extern char *haddrtoa P((u_char *, int));
+extern void haddr_conv802 P((u_char *, u_char *, int));
+
+#undef P
+
+/*
+ * 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)
+
+#endif /* HWADDR_H */
diff --git a/libexec/bootpd/lookup.c b/libexec/bootpd/lookup.c
new file mode 100644
index 0000000..af3b37a
--- /dev/null
+++ b/libexec/bootpd/lookup.c
@@ -0,0 +1,129 @@
+/*
+ * lookup.c - Lookup IP address, HW address, netmask
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <sys/time.h> /* for struct timeval in net/if.h */
+#include <net/if.h>
+#include <netinet/in.h>
+
+#ifdef ETC_ETHERS
+#include <net/ethernet.h>
+extern int ether_hostton();
+#endif
+
+#include <netdb.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#endif
+
+#include "bootp.h"
+#include "lookup.h"
+#include "report.h"
+
+/*
+ * Lookup an Ethernet address and return it.
+ * Return NULL if addr not found.
+ */
+u_char *
+lookup_hwa(hostname, htype)
+ char *hostname;
+ int htype;
+{
+ switch (htype) {
+
+ /* XXX - How is this done on other systems? -gwr */
+#ifdef ETC_ETHERS
+ case HTYPE_ETHERNET:
+ case HTYPE_IEEE802:
+ {
+ static struct ether_addr ea;
+ /* This does a lookup in /etc/ethers */
+ if (ether_hostton(hostname, &ea)) {
+ report(LOG_ERR, "no HW addr for host \"%s\"",
+ hostname);
+ return (u_char *) 0;
+ }
+ return (u_char *) & ea;
+ }
+#endif /* ETC_ETHERS */
+
+ default:
+ report(LOG_ERR, "no lookup for HW addr type %d", htype);
+ } /* switch */
+
+ /* If the system can't do it, just return an error. */
+ return (u_char *) 0;
+}
+
+
+/*
+ * Lookup an IP address.
+ * Return non-zero on failure.
+ */
+int
+lookup_ipa(hostname, result)
+ char *hostname;
+ u_int32 *result;
+{
+ struct hostent *hp;
+ hp = gethostbyname(hostname);
+ if (!hp)
+ return -1;
+ bcopy(hp->h_addr, result, sizeof(*result));
+ return 0;
+}
+
+
+/*
+ * Lookup a netmask
+ * Return non-zero on failure.
+ *
+ * XXX - This is OK as a default, but to really make this automatic,
+ * we would need to get the subnet mask from the ether interface.
+ * If this is wrong, specify the correct value in the bootptab.
+ */
+int
+lookup_netmask(addr, result)
+ u_int32 addr; /* both in network order */
+ u_int32 *result;
+{
+ int32 m, a;
+
+ a = ntohl(addr);
+ m = 0;
+
+ if (IN_CLASSA(a))
+ m = IN_CLASSA_NET;
+
+ if (IN_CLASSB(a))
+ m = IN_CLASSB_NET;
+
+ if (IN_CLASSC(a))
+ m = IN_CLASSC_NET;
+
+ if (!m)
+ return -1;
+ *result = htonl(m);
+ return 0;
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/lookup.h b/libexec/bootpd/lookup.h
new file mode 100644
index 0000000..04805d8
--- /dev/null
+++ b/libexec/bootpd/lookup.h
@@ -0,0 +1,15 @@
+/* lookup.h */
+
+#include "bptypes.h" /* for int32, u_int32 */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern u_char *lookup_hwa P((char *hostname, int htype));
+extern int lookup_ipa P((char *hostname, u_int32 *addr));
+extern int lookup_netmask P((u_int32 addr, u_int32 *mask));
+
+#undef P
diff --git a/libexec/bootpd/patchlevel.h b/libexec/bootpd/patchlevel.h
new file mode 100644
index 0000000..85566b5
--- /dev/null
+++ b/libexec/bootpd/patchlevel.h
@@ -0,0 +1,8 @@
+/*
+ * patchlevel.h
+ *
+ * $Id$
+ */
+
+#define VERSION "2.4"
+#define PATCHLEVEL 3
diff --git a/libexec/bootpd/readfile.c b/libexec/bootpd/readfile.c
new file mode 100644
index 0000000..8dfd430
--- /dev/null
+++ b/libexec/bootpd/readfile.c
@@ -0,0 +1,2088 @@
+/************************************************************************
+ 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.
+
+ $Id$
+
+************************************************************************/
+
+/*
+ * 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 <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "lookup.h"
+#include "readfile.h"
+#include "report.h"
+#include "tzone.h"
+#include "bootpd.h"
+
+#define HASHTABLESIZE 257 /* Hash table size (prime) */
+
+/* Non-standard hardware address type (see bootp.h) */
+#define HTYPE_DIRECT 0
+
+/* Error codes returned by eval_symbol: */
+#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_HWADDR (-5)
+#define E_BAD_LONGWORD (-6)
+#define E_BAD_HWATYPE (-7)
+#define E_BAD_PATHNAME (-8)
+#define E_BAD_VALUE (-9)
+
+/* Tag idendities. */
+#define SYM_NULL 0
+#define SYM_BOOTFILE 1
+#define SYM_COOKIE_SERVER 2
+#define SYM_DOMAIN_SERVER 3
+#define SYM_GATEWAY 4
+#define SYM_HWADDR 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_DUMP_FILE 24
+#define SYM_DOMAIN_NAME 25
+#define SYM_SWAP_SERVER 26
+#define SYM_ROOT_PATH 27
+#define SYM_EXTEN_FILE 28
+#define SYM_REPLY_ADDR 29
+#define SYM_NIS_DOMAIN 30 /* RFC 1533 */
+#define SYM_NIS_SERVER 31 /* RFC 1533 */
+#define SYM_NTP_SERVER 32 /* RFC 1533 */
+#define SYM_EXEC_FILE 33 /* YORK_EX_OPTION */
+#define SYM_MSG_SIZE 34
+#define SYM_MIN_WAIT 35
+/* XXX - Add new tags here */
+
+#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 256 /* 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 int32 modtime = 0; /* Last modification time of bootptab */
+PRIVATE char *current_hostname; /* Name of the current entry. */
+PRIVATE char current_tagname[8];
+
+/*
+ * 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_DUMP_FILE},
+ {"dn", SYM_DOMAIN_NAME},
+ {"ds", SYM_DOMAIN_SERVER},
+ {"ef", SYM_EXTEN_FILE},
+ {"ex", SYM_EXEC_FILE}, /* YORK_EX_OPTION */
+ {"gw", SYM_GATEWAY},
+ {"ha", SYM_HWADDR},
+ {"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},
+ {"ms", SYM_MSG_SIZE},
+ {"mw", SYM_MIN_WAIT},
+ {"ns", SYM_NAME_SERVER},
+ {"nt", SYM_NTP_SERVER},
+ {"ra", SYM_REPLY_ADDR},
+ {"rl", SYM_RLP_SERVER},
+ {"rp", SYM_ROOT_PATH},
+ {"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},
+ {"yd", SYM_NIS_DOMAIN},
+ {"ys", SYM_NIS_SERVER},
+ /* XXX - Add new tags here */
+};
+
+
+/*
+ * 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.
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern boolean iplookcmp();
+boolean nmcmp P((hash_datum *, hash_datum *));
+
+PRIVATE void
+ adjust P((char **));
+PRIVATE void
+ del_string P((struct shared_string *));
+PRIVATE void
+ del_bindata P((struct shared_bindata *));
+PRIVATE void
+ del_iplist P((struct in_addr_list *));
+PRIVATE void
+ eat_whitespace P((char **));
+PRIVATE int
+ eval_symbol P((char **, struct host *));
+PRIVATE void
+ fill_defaults P((struct host *, char **));
+PRIVATE void
+ free_host P((hash_datum *));
+PRIVATE struct in_addr_list *
+ get_addresses P((char **));
+PRIVATE struct shared_string *
+ get_shared_string P((char **));
+PRIVATE char *
+ get_string P((char **, char *, u_int *));
+PRIVATE u_int32
+ get_u_long P((char **));
+PRIVATE boolean
+ goodname P((char *));
+PRIVATE boolean
+ hwinscmp P((hash_datum *, hash_datum *));
+PRIVATE int
+ interp_byte P((char **, byte *));
+PRIVATE void
+ makelower P((char *));
+PRIVATE boolean
+ nullcmp P((hash_datum *, hash_datum *));
+PRIVATE int
+ process_entry P((struct host *, char *));
+PRIVATE int
+ process_generic P((char **, struct shared_bindata **, u_int));
+PRIVATE byte *
+ prs_haddr P((char **, u_int));
+PRIVATE int
+ prs_inetaddr P((char **, u_int32 *));
+PRIVATE void
+ read_entry P((FILE *, char *, u_int *));
+PRIVATE char *
+ smalloc P((u_int));
+
+#undef P
+
+
+/*
+ * Vendor magic cookies for CMU and RFC1048
+ */
+u_char vm_cmu[4] = VM_CMU;
+u_char vm_rfc1048[4] = VM_RFC1048;
+
+/*
+ * Main hash tables
+ */
+hash_tbl *hwhashtable;
+hash_tbl *iphashtable;
+hash_tbl *nmhashtable;
+
+/*
+ * Allocate hash tables for hardware address, ip address, and hostname
+ * (shared by bootpd and bootpef)
+ */
+void
+rdtab_init()
+{
+ hwhashtable = hash_Init(HASHTABLESIZE);
+ iphashtable = hash_Init(HASHTABLESIZE);
+ nmhashtable = hash_Init(HASHTABLESIZE);
+ if (!(hwhashtable && iphashtable && nmhashtable)) {
+ report(LOG_ERR, "Unable to allocate hash tables.");
+ exit(1);
+ }
+}
+
+
+/*
+ * Read bootptab database file. Avoid rereading the file if the
+ * write date hasn't changed since the last time we read it.
+ */
+
+void
+readtab(force)
+ int force;
+{
+ struct host *hp;
+ FILE *fp;
+ struct stat st;
+ unsigned hashcode, buflen;
+ static char buffer[MAXENTRYLEN];
+
+ /*
+ * Check the last modification time.
+ */
+ if (stat(bootptab, &st) < 0) {
+ report(LOG_ERR, "stat on \"%s\": %s",
+ bootptab, get_errmsg());
+ return;
+ }
+#ifdef DEBUG
+ if (debug > 3) {
+ char timestr[28];
+ strcpy(timestr, ctime(&(st.st_mtime)));
+ /* zap the newline */
+ timestr[24] = '\0';
+ report(LOG_INFO, "bootptab mtime: %s",
+ timestr);
+ }
+#endif
+ if ((force == 0) &&
+ (st.st_mtime == modtime) &&
+ st.st_nlink) {
+ /*
+ * hasn't been modified or deleted yet.
+ */
+ return;
+ }
+ if (debug)
+ report(LOG_INFO, "reading %s\"%s\"",
+ (modtime != 0L) ? "new " : "",
+ bootptab);
+
+ /*
+ * Open bootptab file.
+ */
+ if ((fp = fopen(bootptab, "r")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
+ return;
+ }
+ /*
+ * Record file modification time.
+ */
+ if (fstat(fileno(fp), &st) < 0) {
+ report(LOG_ERR, "fstat: %s", get_errmsg());
+ fclose(fp);
+ return;
+ }
+ 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));
+ bzero((char *) hp, sizeof(*hp));
+ /* the link count it zero */
+
+ /*
+ * Get individual info
+ */
+ if (process_entry(hp, buffer) < 0) {
+ hp->linkcount = 1;
+ free_host((hash_datum *) hp);
+ continue;
+ }
+ /*
+ * If this is not a dummy entry, and the IP or HW
+ * address is not yet set, try to get them here.
+ * Dummy entries have . as first char of name.
+ */
+ if (goodname(hp->hostname->string)) {
+ char *hn = hp->hostname->string;
+ u_int32 value;
+ if (hp->flags.iaddr == 0) {
+ if (lookup_ipa(hn, &value)) {
+ report(LOG_ERR, "can not get IP addr for %s", hn);
+ report(LOG_ERR, "(dummy names should start with '.')");
+ } else {
+ hp->iaddr.s_addr = value;
+ hp->flags.iaddr = TRUE;
+ }
+ }
+ /* Set default subnet mask. */
+ if (hp->flags.subnet_mask == 0) {
+ if (lookup_netmask(hp->iaddr.s_addr, &value)) {
+ report(LOG_ERR, "can not get netmask for %s", hn);
+ } else {
+ hp->subnet_mask.s_addr = value;
+ hp->flags.subnet_mask = TRUE;
+ }
+ }
+ }
+ if (hp->flags.iaddr) {
+ nhosts++;
+ }
+ /* Register by HW addr if known. */
+ if (hp->flags.htype && hp->flags.haddr) {
+ /* We will either insert it or free it. */
+ hp->linkcount++;
+ hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
+ if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
+ report(LOG_NOTICE, "duplicate %s address: %s",
+ netname(hp->htype),
+ haddrtoa(hp->haddr, haddrlength(hp->htype)));
+ free_host((hash_datum *) hp);
+ continue;
+ }
+ }
+ /* Register by IP addr if known. */
+ if (hp->flags.iaddr) {
+ hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
+ if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
+ report(LOG_ERR,
+ "hash_Insert() failed on IP address insertion");
+ } else {
+ /* Just inserted the host struct in a new hash list. */
+ hp->linkcount++;
+ }
+ }
+ /* Register by Name (always known) */
+ hashcode = hash_HashFunction((u_char *) 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\"",
+ hp->hostname->string);
+ } else {
+ /* Just inserted the host struct in a new hash list. */
+ hp->linkcount++;
+ }
+
+ nentries++;
+ }
+
+ fclose(fp);
+ if (debug)
+ report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
+ nentries, nhosts, bootptab);
+ return;
+}
+
+
+
+/*
+ * 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;
+ char *msg;
+
+ if (!host || *src == '\0') {
+ return -1;
+ }
+ host->hostname = get_shared_string(&src);
+#if 0
+ /* Be more liberal for the benefit of dummy tag names. */
+ if (!goodname(host->hostname->string)) {
+ report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
+ del_string(host->hostname);
+ return -1;
+ }
+#endif
+ current_hostname = host->hostname->string;
+ adjust(&src);
+ while (TRUE) {
+ retval = eval_symbol(&src, host);
+ if (retval == SUCCESS) {
+ adjust(&src);
+ continue;
+ }
+ if (retval == E_END_OF_ENTRY) {
+ /* The default subnet mask is set in readtab() */
+ return 0;
+ }
+ /* Some kind of error. */
+ switch (retval) {
+ case E_SYNTAX_ERROR:
+ msg = "bad syntax";
+ break;
+ case E_UNKNOWN_SYMBOL:
+ msg = "unknown symbol";
+ break;
+ case E_BAD_IPADDR:
+ msg = "bad INET address";
+ break;
+ case E_BAD_HWADDR:
+ msg = "bad hardware address";
+ break;
+ case E_BAD_LONGWORD:
+ msg = "bad longword value";
+ break;
+ case E_BAD_HWATYPE:
+ msg = "bad HW address type";
+ break;
+ case E_BAD_PATHNAME:
+ msg = "bad pathname (need leading '/')";
+ case E_BAD_VALUE:
+ msg = "bad value";
+ default:
+ msg = "unkown error";
+ break;
+ } /* switch */
+ report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
+ current_hostname, current_tagname, msg);
+ return -1;
+ }
+}
+
+
+/*
+ * Macros for use in the function below:
+ */
+
+/* Parse one INET address stored directly in MEMBER. */
+#define PARSE_IA1(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = FALSE; \
+ if (optype == OP_ADDITION) { \
+ if (prs_inetaddr(symbol, &value) < 0) \
+ return E_BAD_IPADDR; \
+ hp->MEMBER.s_addr = value; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/* Parse a list of INET addresses pointed to by MEMBER */
+#define PARSE_IAL(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ if (hp->flags.MEMBER) { \
+ hp->flags.MEMBER = FALSE; \
+ assert(hp->MEMBER); \
+ del_iplist(hp->MEMBER); \
+ hp->MEMBER = NULL; \
+ } \
+ if (optype == OP_ADDITION) { \
+ hp->MEMBER = get_addresses(symbol); \
+ if (hp->MEMBER == NULL) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/* Parse a shared string pointed to by MEMBER */
+#define PARSE_STR(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ if (hp->flags.MEMBER) { \
+ hp->flags.MEMBER = FALSE; \
+ assert(hp->MEMBER); \
+ del_string(hp->MEMBER); \
+ hp->MEMBER = NULL; \
+ } \
+ if (optype == OP_ADDITION) { \
+ hp->MEMBER = get_shared_string(symbol); \
+ if (hp->MEMBER == NULL) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/* Parse an unsigned integer value for MEMBER */
+#define PARSE_UINT(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = FALSE; \
+ if (optype == OP_ADDITION) { \
+ value = get_u_long(symbol); \
+ hp->MEMBER = value; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/*
+ * 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 int
+eval_symbol(symbol, hp)
+ char **symbol;
+ struct host *hp;
+{
+ char tmpstr[MAXSTRINGLEN];
+ byte *tmphaddr;
+ struct symbolmap *symbolptr;
+ u_int32 value;
+ int32 timeoff;
+ int i, numsymbols;
+ unsigned len;
+ int optype; /* Indicates boolean, addition, or deletion */
+
+ eat_whitespace(symbol);
+
+ /* Make sure this is set before returning. */
+ current_tagname[0] = (*symbol)[0];
+ current_tagname[1] = (*symbol)[1];
+ current_tagname[2] = 0;
+
+ 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);
+ sprintf(current_tagname, "T%d", (int)value);
+ eat_whitespace(symbol);
+ if ((*symbol)[0] != '=') {
+ return E_SYNTAX_ERROR;
+ }
+ (*symbol)++;
+ if (!(hp->generic)) {
+ hp->generic = (struct shared_bindata *)
+ smalloc(sizeof(struct shared_bindata));
+ }
+ if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
+ return E_SYNTAX_ERROR;
+ hp->flags.generic = TRUE;
+ return SUCCESS;
+ }
+ /*
+ * 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;
+
+ eat_whitespace(symbol);
+
+ /* The cases below are in order by symbolcode value. */
+ switch (symbolptr->symbolcode) {
+
+ case SYM_BOOTFILE:
+ PARSE_STR(bootfile);
+ break;
+
+ case SYM_COOKIE_SERVER:
+ PARSE_IAL(cookie_server);
+ break;
+
+ case SYM_DOMAIN_SERVER:
+ PARSE_IAL(domain_server);
+ break;
+
+ case SYM_GATEWAY:
+ PARSE_IAL(gateway);
+ break;
+
+ case SYM_HWADDR:
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.haddr = FALSE;
+ if (optype == OP_ADDITION) {
+ /* Default the HW type to Ethernet */
+ if (hp->flags.htype == 0) {
+ hp->flags.htype = TRUE;
+ hp->htype = HTYPE_ETHERNET;
+ }
+ tmphaddr = prs_haddr(symbol, hp->htype);
+ if (!tmphaddr)
+ return E_BAD_HWADDR;
+ bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
+ hp->flags.haddr = TRUE;
+ }
+ break;
+
+ case SYM_HOMEDIR:
+ PARSE_STR(homedir);
+ break;
+
+ case SYM_HTYPE:
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.htype = FALSE;
+ if (optype == 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 >= hwinfocnt) {
+ return E_BAD_HWATYPE;
+ }
+ hp->htype = (byte) (value & 0xFF);
+ hp->flags.htype = TRUE;
+ }
+ break;
+
+ case SYM_IMPRESS_SERVER:
+ PARSE_IAL(impress_server);
+ break;
+
+ case SYM_IPADDR:
+ PARSE_IA1(iaddr);
+ break;
+
+ case SYM_LOG_SERVER:
+ PARSE_IAL(log_server);
+ break;
+
+ case SYM_LPR_SERVER:
+ PARSE_IAL(lpr_server);
+ break;
+
+ case SYM_NAME_SERVER:
+ PARSE_IAL(name_server);
+ break;
+
+ case SYM_RLP_SERVER:
+ PARSE_IAL(rlp_server);
+ break;
+
+ case SYM_SUBNET_MASK:
+ PARSE_IA1(subnet_mask);
+ break;
+
+ case SYM_TIME_OFFSET:
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.time_offset = FALSE;
+ if (optype == OP_ADDITION) {
+ len = sizeof(tmpstr);
+ (void) get_string(symbol, tmpstr, &len);
+ if (!strncmp(tmpstr, "auto", 4)) {
+ hp->time_offset = secondswest;
+ } else {
+ if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
+ return E_BAD_LONGWORD;
+ hp->time_offset = timeoff;
+ }
+ hp->flags.time_offset = TRUE;
+ }
+ break;
+
+ case SYM_TIME_SERVER:
+ PARSE_IAL(time_server);
+ break;
+
+ case SYM_VENDOR_MAGIC:
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.vm_cookie = FALSE;
+ if (optype == OP_ADDITION) {
+ if (strncmp(*symbol, "auto", 4)) {
+ /* The string is not "auto" */
+ if (!strncmp(*symbol, "rfc", 3)) {
+ bcopy(vm_rfc1048, hp->vm_cookie, 4);
+ } else if (!strncmp(*symbol, "cmu", 3)) {
+ bcopy(vm_cmu, hp->vm_cookie, 4);
+ } else {
+ if (!isdigit(**symbol))
+ return E_BAD_IPADDR;
+ if (prs_inetaddr(symbol, &value) < 0)
+ return E_BAD_IPADDR;
+ bcopy(&value, hp->vm_cookie, 4);
+ }
+ hp->flags.vm_cookie = TRUE;
+ }
+ }
+ 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:
+ PARSE_IA1(bootserver);
+ break;
+
+ case SYM_TFTPDIR:
+ PARSE_STR(tftpdir);
+ if ((hp->tftpdir != NULL) &&
+ (hp->tftpdir->string[0] != '/'))
+ return E_BAD_PATHNAME;
+ break;
+
+ case SYM_DUMP_FILE:
+ PARSE_STR(dump_file);
+ break;
+
+ case SYM_DOMAIN_NAME:
+ PARSE_STR(domain_name);
+ break;
+
+ case SYM_SWAP_SERVER:
+ PARSE_IA1(swap_server);
+ break;
+
+ case SYM_ROOT_PATH:
+ PARSE_STR(root_path);
+ break;
+
+ case SYM_EXTEN_FILE:
+ PARSE_STR(exten_file);
+ break;
+
+ case SYM_REPLY_ADDR:
+ PARSE_IA1(reply_addr);
+ break;
+
+ case SYM_NIS_DOMAIN:
+ PARSE_STR(nis_domain);
+ break;
+
+ case SYM_NIS_SERVER:
+ PARSE_IAL(nis_server);
+ break;
+
+ case SYM_NTP_SERVER:
+ PARSE_IAL(ntp_server);
+ break;
+
+#ifdef YORK_EX_OPTION
+ case SYM_EXEC_FILE:
+ PARSE_STR(exec_file);
+ break;
+#endif
+
+ case SYM_MSG_SIZE:
+ PARSE_UINT(msg_size);
+ if (hp->msg_size < BP_MINPKTSZ ||
+ hp->msg_size > MAX_MSG_SIZE)
+ return E_BAD_VALUE;
+ break;
+
+ case SYM_MIN_WAIT:
+ PARSE_UINT(min_wait);
+ break;
+
+ /* XXX - Add new tags here */
+
+ default:
+ return E_UNKNOWN_SYMBOL;
+
+ } /* switch symbolcode */
+
+ return SUCCESS;
+}
+#undef PARSE_IA1
+#undef PARSE_IAL
+#undef PARSE_STR
+
+
+
+
+/*
+ * 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 int
+process_generic(src, dest, tagvalue)
+ char **src;
+ struct shared_bindata **dest;
+ u_int tagvalue;
+{
+ byte tmpbuf[MAXBUFLEN];
+ byte *str;
+ struct shared_bindata *bdata;
+ u_int newlength, oldlength;
+
+ str = tmpbuf;
+ *str++ = (tagvalue & 0xFF); /* 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, (char *) str, &newlength);
+ newlength++; /* null terminator */
+ } else { /* Numeric data */
+ newlength = 0;
+ while (newlength < sizeof(tmpbuf) - 2) {
+ if (interp_byte(src, str++) < 0)
+ break;
+ newlength++;
+ if (**src == '.') {
+ (*src)++;
+ }
+ }
+ }
+ if ((*src)[0] != ':')
+ return -1;
+
+ tmpbuf[1] = (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;
+ return 0;
+}
+
+
+
+/*
+ * 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 == '_') )
+ {
+ 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(d1, d2)
+ hash_datum *d1, *d2;
+{
+ return FALSE;
+}
+
+
+/*
+ * Function for comparing a string with the hostname field of a host
+ * structure.
+ */
+
+boolean
+nmcmp(d1, d2)
+ hash_datum *d1, *d2;
+{
+ char *name = (char *) d1; /* XXX - OK? */
+ struct host *hp = (struct host *) d2;
+
+ 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(d1, d2)
+ hash_datum *d1, *d2;
+{
+ struct host *host1 = (struct host *) d1;
+ struct host *host2 = (struct host *) d2;
+
+ if (host1->htype != host2->htype) {
+ return FALSE;
+ }
+ if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
+ return FALSE;
+ }
+ /* XXX - Is the subnet_mask field set yet? */
+ 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;
+}
+
+
+/*
+ * Macros for use in the function below:
+ */
+
+#define DUP_COPY(MEMBER) do \
+{ \
+ if (!hp->flags.MEMBER) { \
+ if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
+ hp->MEMBER = hp2->MEMBER; \
+ } \
+ } \
+} while (0)
+
+#define DUP_LINK(MEMBER) do \
+{ \
+ if (!hp->flags.MEMBER) { \
+ if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
+ assert(hp2->MEMBER); \
+ hp->MEMBER = hp2->MEMBER; \
+ (hp->MEMBER->linkcount)++; \
+ } \
+ } \
+} while (0)
+
+/*
+ * 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 int tlen, hashcode;
+ struct host *hp2;
+ char tstring[MAXSTRINGLEN];
+
+ tlen = sizeof(tstring);
+ (void) get_string(src, tstring, &tlen);
+ hashcode = hash_HashFunction((u_char *) tstring, tlen);
+ hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
+
+ if (hp2 == NULL) {
+ report(LOG_ERR, "can't find tc=\"%s\"", tstring);
+ return;
+ }
+ DUP_LINK(bootfile);
+ DUP_LINK(cookie_server);
+ DUP_LINK(domain_server);
+ DUP_LINK(gateway);
+ /* haddr not copied */
+ DUP_LINK(homedir);
+ DUP_COPY(htype);
+
+ DUP_LINK(impress_server);
+ /* iaddr not copied */
+ DUP_LINK(log_server);
+ DUP_LINK(lpr_server);
+ DUP_LINK(name_server);
+ DUP_LINK(rlp_server);
+
+ DUP_COPY(subnet_mask);
+ DUP_COPY(time_offset);
+ DUP_LINK(time_server);
+
+ if (!hp->flags.vm_cookie) {
+ if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
+ 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.bootsize) {
+ if ((hp->flags.bootsize = hp2->flags.bootsize)) {
+ hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
+ hp->bootsize = hp2->bootsize;
+ }
+ }
+ DUP_COPY(bootserver);
+
+ DUP_LINK(tftpdir);
+ DUP_LINK(dump_file);
+ DUP_LINK(domain_name);
+
+ DUP_COPY(swap_server);
+ DUP_LINK(root_path);
+ DUP_LINK(exten_file);
+
+ DUP_COPY(reply_addr);
+
+ DUP_LINK(nis_domain);
+ DUP_LINK(nis_server);
+ DUP_LINK(ntp_server);
+
+#ifdef YORK_EX_OPTION
+ DUP_LINK(exec_file);
+#endif
+
+ DUP_COPY(msg_size);
+ DUP_COPY(min_wait);
+
+ /* XXX - Add new tags here */
+
+ DUP_LINK(generic);
+
+}
+#undef DUP_COPY
+#undef DUP_LINK
+
+
+
+/*
+ * 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. . . .
+ * (Yea, because it usually makes code slower... -gwr)
+ *
+ */
+
+
+
+/*
+ * "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 (isspace(**src) || (**src == ',')) {
+ (*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 int
+prs_inetaddr(src, result)
+ char **src;
+ u_int32 *result;
+{
+ char tmpstr[MAXSTRINGLEN];
+ register u_int32 value;
+ u_int32 parts[4], *pp;
+ int n;
+ char *s, *t;
+
+ /* Leading alpha char causes IP addr lookup. */
+ if (isalpha(**src)) {
+ /* Lookup IP address. */
+ s = *src;
+ t = tmpstr;
+ while ((isalnum(*s) || (*s == '.') ||
+ (*s == '-') || (*s == '_') ) &&
+ (t < &tmpstr[MAXSTRINGLEN - 1]) )
+ *t++ = *s++;
+ *t = '\0';
+ *src = s;
+
+ n = lookup_ipa(tmpstr, result);
+ if (n < 0)
+ report(LOG_ERR, "can not get IP addr for %s", tmpstr);
+ return n;
+ }
+
+ /*
+ * Parse an address in Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16-bits)
+ * a.b (with b treated as 24 bits)
+ */
+ pp = parts;
+ loop:
+ /* If it's not a digit, return error. */
+ if (!isdigit(**src))
+ return -1;
+ *pp++ = get_u_long(src);
+ if (**src == '.') {
+ if (pp < (parts + 4)) {
+ (*src)++;
+ goto loop;
+ }
+ return (-1);
+ }
+#if 0
+ /* This is handled by the caller. */
+ if (**src && !(isspace(**src) || (**src == ':'))) {
+ return (-1);
+ }
+#endif
+
+ /*
+ * 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;
+ u_int htype;
+{
+ static byte haddr[MAXHADDRLEN];
+ byte *hap;
+ char tmpstr[MAXSTRINGLEN];
+ u_int tmplen;
+ unsigned hal;
+ char *p;
+
+ hal = haddrlength(htype); /* Get length of this address type */
+ if (hal <= 0) {
+ report(LOG_ERR, "Invalid addr type for HW addr parse");
+ return NULL;
+ }
+ tmplen = sizeof(tmpstr);
+ get_string(src, tmpstr, &tmplen);
+ p = tmpstr;
+
+ /* If it's a valid host name, try to lookup the HW address. */
+ if (goodname(p)) {
+ /* Lookup Hardware Address for hostname. */
+ if ((hap = lookup_hwa(p, htype)) != NULL)
+ return hap; /* success */
+ report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
+ /* OK, assume it must be numeric. */
+ }
+
+ hap = haddr;
+ while (hap < haddr + hal) {
+ if ((*p == '.') || (*p == ':'))
+ p++;
+ if (interp_byte(&p, hap++) < 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_int32
+get_u_long(src)
+ char **src;
+{
+ register u_int32 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(hmp)
+ hash_datum *hmp;
+{
+ struct host *hostptr = (struct host *) hmp;
+ if (hostptr == NULL)
+ return;
+ assert(hostptr->linkcount > 0);
+ if (--(hostptr->linkcount))
+ return; /* Still has references */
+ 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_iplist(hostptr->nis_server);
+ del_iplist(hostptr->ntp_server);
+
+ /*
+ * XXX - Add new tags here
+ * (if the value is an IP list)
+ */
+
+ del_string(hostptr->hostname);
+ del_string(hostptr->homedir);
+ del_string(hostptr->bootfile);
+ del_string(hostptr->tftpdir);
+ del_string(hostptr->root_path);
+ del_string(hostptr->domain_name);
+ del_string(hostptr->dump_file);
+ del_string(hostptr->exten_file);
+ del_string(hostptr->nis_domain);
+
+#ifdef YORK_EX_OPTION
+ del_string(hostptr->exec_file);
+#endif
+
+ /*
+ * XXX - Add new tags here
+ * (if it is a shared string)
+ */
+
+ 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");
+ exit(1);
+ }
+ bzero(retvalue, nbytes);
+ return retvalue;
+}
+
+
+/*
+ * 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(d1, d2)
+ hash_datum *d1, *d2;
+{
+ struct host *host1 = (struct host *) d1;
+ struct host *host2 = (struct host *) d2;
+
+ 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(d1, d2)
+ hash_datum *d1, *d2;
+{
+ struct host *host1 = (struct host *) d1;
+ struct host *host2 = (struct host *) d2;
+
+ return (host1->iaddr.s_addr == host2->iaddr.s_addr);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/readfile.h b/libexec/bootpd/readfile.h
new file mode 100644
index 0000000..3913455
--- /dev/null
+++ b/libexec/bootpd/readfile.h
@@ -0,0 +1,19 @@
+/* readfile.h */
+
+#include "bptypes.h"
+#include "hash.h"
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern boolean hwlookcmp P((hash_datum *, hash_datum *));
+extern boolean iplookcmp P((hash_datum *, hash_datum *));
+extern boolean nmcmp P((hash_datum *, hash_datum *));
+extern void readtab P((int));
+extern void rdtab_init P((void));
+
+#undef P
+
diff --git a/libexec/bootpd/report.c b/libexec/bootpd/report.c
new file mode 100644
index 0000000..4f7f036
--- /dev/null
+++ b/libexec/bootpd/report.c
@@ -0,0 +1,154 @@
+/*
+ * report() - calls syslog
+ */
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include "report.h"
+
+#ifndef LOG_NDELAY
+#define LOG_NDELAY 0
+#endif
+#ifndef LOG_DAEMON
+#define LOG_DAEMON 0
+#endif
+#ifndef LOG_BOOTP
+#define LOG_BOOTP LOG_DAEMON
+#endif
+
+extern int debug;
+extern char *progname;
+
+/*
+ * This is initialized so you get stderr until you call
+ * report_init()
+ */
+static int stderr_only = 1;
+
+void
+report_init(nolog)
+ int nolog;
+{
+ stderr_only = nolog;
+#ifdef SYSLOG
+ if (!stderr_only) {
+ openlog(progname, LOG_PID | LOG_NDELAY, LOG_BOOTP);
+ }
+#endif
+}
+
+/*
+ * 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).
+ */
+
+static char *levelnames[] = {
+#ifdef LOG_SALERT
+ "level(0): ",
+ "alert(1): ",
+ "alert(2): ",
+ "emerg(3): ",
+ "error(4): ",
+ "crit(5): ",
+ "warn(6): ",
+ "note(7): ",
+ "info(8): ",
+ "debug(9): ",
+ "level(?): "
+#else
+ "emerg(0): ",
+ "alert(1): ",
+ "crit(2): ",
+ "error(3): ",
+ "warn(4): ",
+ "note(5): ",
+ "info(6): ",
+ "debug(7): ",
+ "level(?): "
+#endif
+};
+static int numlevels = sizeof(levelnames) / sizeof(levelnames[0]);
+
+
+/*
+ * Print a log message using syslog(3) and/or stderr.
+ * The message passed in should not include a newline.
+ */
+#ifdef __STDC__
+void
+report(int priority, char *fmt,...)
+#else
+/*VARARGS2*/
+void
+report(priority, fmt, va_alist)
+ int priority;
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+ static char buf[128];
+
+ if ((priority < 0) || (priority >= numlevels)) {
+ priority = numlevels - 1;
+ }
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ /*
+ * Print the message
+ */
+ if (stderr_only || (debug > 2)) {
+ fprintf(stderr, "%s: %s %s\n",
+ progname, levelnames[priority], buf);
+ }
+#ifdef SYSLOG
+ if (!stderr_only)
+ syslog((priority | LOG_BOOTP), "%s", buf);
+#endif
+}
+
+
+
+/*
+ * Return pointer to static string which gives full filesystem error message.
+ */
+char *
+get_errmsg()
+{
+ extern int errno;
+ extern char *strerror();
+
+ return strerror(errno);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/report.h b/libexec/bootpd/report.h
new file mode 100644
index 0000000..0bf63d6
--- /dev/null
+++ b/libexec/bootpd/report.h
@@ -0,0 +1,13 @@
+/* report.h */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern void report_init P((int nolog));
+extern void report P((int, char *, ...));
+extern char *get_errmsg P((void));
+
+#undef P
diff --git a/libexec/bootpd/rtmsg.c b/libexec/bootpd/rtmsg.c
new file mode 100644
index 0000000..b6bd363
--- /dev/null
+++ b/libexec/bootpd/rtmsg.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 1984, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1994
+ * Geoffrey M. Rehmet, All rights reserved.
+ *
+ * This code is derived from software which forms part of the 4.4-Lite
+ * Berkeley software distribution, which was in derived from software
+ * contributed to Berkeley by Sun Microsystems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * from arp.c 8.2 (Berkeley) 1/2/94
+ * $Id$
+ */
+
+#include <sys/param.h>
+/*
+ * Verify that we are at least 4.4 BSD
+ */
+#if defined(BSD)
+#if BSD >= 199306
+
+#include <sys/socket.h>
+#include <sys/filio.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_var.h> /* needed for if_ether.h XXX */
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "report.h"
+
+
+static int rtmsg __P((int));
+
+static int s = -1; /* routing socket */
+
+
+/*
+ * Open the routing socket
+ */
+static void getsocket () {
+ if (s < 0) {
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ report(LOG_ERR, "socket %s", strerror(errno));
+ exit(1);
+ }
+ } else {
+ /*
+ * Drain the socket of any unwanted routing messages.
+ */
+ int n;
+ char buf[512];
+
+ ioctl(s, FIONREAD, &n);
+ while (n > 0) {
+ read(s, buf, sizeof buf);
+ ioctl(s, FIONREAD, &n);
+ }
+ }
+}
+
+static struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
+static struct sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m;
+static struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
+static int expire_time, flags, export_only, doing_proxy;
+static struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+/*
+ * Set an individual arp entry
+ */
+int bsd_arp_set(ia, eaddr, len)
+ struct in_addr *ia;
+ char *eaddr;
+ int len;
+{
+ register struct sockaddr_inarp *sin = &sin_m;
+ register struct sockaddr_dl *sdl;
+ register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
+ u_char *ea;
+ struct timeval time;
+ int op = RTM_ADD;
+
+ getsocket();
+ sdl_m = blank_sdl;
+ sin_m = blank_sin;
+ sin->sin_addr = *ia;
+
+ ea = (u_char *)LLADDR(&sdl_m);
+ bcopy(eaddr, ea, len);
+ sdl_m.sdl_alen = len;
+ doing_proxy = flags = export_only = expire_time = 0;
+
+ /* make arp entry temporary */
+ gettimeofday(&time, 0);
+ expire_time = time.tv_sec + 20 * 60;
+
+tryagain:
+ if (rtmsg(RTM_GET) < 0) {
+ report(LOG_WARNING, "rtmget: %s", strerror(errno));
+ return (1);
+ }
+ sin = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
+ if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
+ case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
+ case IFT_ISO88024: case IFT_ISO88025:
+ op = RTM_CHANGE;
+ goto overwrite;
+ }
+ if (doing_proxy == 0) {
+ report(LOG_WARNING, "set: can only proxy for %s\n",
+ inet_ntoa(sin->sin_addr));
+ return (1);
+ }
+ if (sin_m.sin_other & SIN_PROXY) {
+ report(LOG_WARNING,
+ "set: proxy entry exists for non 802 device\n");
+ return(1);
+ }
+ sin_m.sin_other = SIN_PROXY;
+ export_only = 1;
+ goto tryagain;
+ }
+overwrite:
+ if (sdl->sdl_family != AF_LINK) {
+ report(LOG_WARNING,
+ "cannot intuit interface index and type for %s\n",
+ inet_ntoa(sin->sin_addr));
+ return (1);
+ }
+ sdl_m.sdl_type = sdl->sdl_type;
+ sdl_m.sdl_index = sdl->sdl_index;
+ return (rtmsg(op));
+}
+
+
+static int rtmsg(cmd)
+ int cmd;
+{
+ static int seq;
+ int rlen;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ register char *cp = m_rtmsg.m_space;
+ register int l;
+
+ errno = 0;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+ rtm->rtm_flags = flags;
+ rtm->rtm_version = RTM_VERSION;
+
+ switch (cmd) {
+ default:
+ report(LOG_ERR, "set_arp: internal wrong cmd - exiting");
+ exit(1);
+ case RTM_ADD:
+ case RTM_CHANGE:
+ rtm->rtm_addrs |= RTA_GATEWAY;
+ rtm->rtm_rmx.rmx_expire = expire_time;
+ rtm->rtm_inits = RTV_EXPIRE;
+ rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
+ sin_m.sin_other = 0;
+ if (doing_proxy) {
+ if (export_only)
+ sin_m.sin_other = SIN_PROXY;
+ else {
+ rtm->rtm_addrs |= RTA_NETMASK;
+ rtm->rtm_flags &= ~RTF_HOST;
+ }
+ }
+ /* FALLTHROUGH */
+ case RTM_GET:
+ rtm->rtm_addrs |= RTA_DST;
+ }
+#define NEXTADDR(w, s) \
+ if (rtm->rtm_addrs & (w)) { \
+ bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
+
+ NEXTADDR(RTA_DST, sin_m);
+ NEXTADDR(RTA_GATEWAY, sdl_m);
+ NEXTADDR(RTA_NETMASK, so_mask);
+
+ rtm->rtm_msglen = cp - (char *)&m_rtmsg;
+
+ l = rtm->rtm_msglen;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_type = cmd;
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ if ((errno != ESRCH) && !(errno == EEXIST && cmd == RTM_ADD)){
+ report(LOG_WARNING, "writing to routing socket: %s",
+ strerror(errno));
+ return (-1);
+ }
+ }
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm->rtm_type != cmd || rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
+ if (l < 0)
+ report(LOG_WARNING, "arp: read from routing socket: %s\n",
+ strerror(errno));
+ return (0);
+}
+
+#endif /* BSD */
+#endif /* BSD >= 199306 */
diff --git a/libexec/bootpd/syslog.conf b/libexec/bootpd/syslog.conf
new file mode 100644
index 0000000..2c135af
--- /dev/null
+++ b/libexec/bootpd/syslog.conf
@@ -0,0 +1,63 @@
+#
+# syslog configuration file for SunOS 4.X
+# (modified to do local2 separately)
+#
+# This file is processed by m4 so be careful to quote (`') names
+# that match m4 reserved words. Also, within ifdef's, arguments
+# containing commas must be quoted.
+#
+# Note: Have to exclude user from most lines so that user.alert
+# and user.emerg are not included, because old sendmails
+# will generate them for debugging information. If you
+# have no 4.2BSD based systems doing network logging, you
+# can remove all the special cases for "user" logging.
+
+#*.err;kern.debug;auth.notice;user.none /dev/console
+kern.debug;user,mail.crit;auth.notice /dev/console
+daemon,syslog,lpr,news,uucp,cron.err /dev/console
+
+#*.err;kern.debug;daemon,auth.notice;mail.crit;user.none /var/adm/messages
+kern.debug;user,mail.crit;auth.notice /var/adm/messages
+daemon.notice;syslog,news,uucp,cron.err /var/adm/messages
+
+lpr.debug /var/adm/lpd-errs
+
+*.alert;kern.err;daemon.err;user.none operator
+*.alert;user.none root
+
+*.emerg;user.none *
+
+# for loghost machines, to have authentication messages (su, login, etc.)
+# logged to a file, un-comment out the following line and adjust the file name
+# as appropriate.
+#
+# if a non-loghost machine chooses to have such messages
+# sent to the loghost machine, un-comment out the following line.
+#
+#auth.notice ifdef(`LOGHOST', /var/log/authlog, @loghost)
+
+mail.debug ifdef(`LOGHOST', /var/log/syslog, @loghost)
+
+# following line for compatibility with old sendmails. they will send
+# messages with no facility code, which will be turned into "user" messages
+# by the local syslog daemon. only the "loghost" machine needs the following
+# line, to cause these old sendmail log messages to be logged in the
+# mail syslog file.
+#
+ifdef(`LOGHOST',
+user.alert /var/log/syslog
+)
+#
+# non-loghost machines will use the following lines to cause "user"
+# log messages to be logged locally.
+#
+ifdef(`LOGHOST', ,
+user.err /dev/console
+user.err /var/adm/messages
+user.alert `root, operator'
+user.emerg *
+)
+
+# Local2: (bootpd, pppd)
+local2.debug /dev/console
+#local2.debug /var/log/local2
diff --git a/libexec/bootpd/tools/Makefile b/libexec/bootpd/tools/Makefile
new file mode 100644
index 0000000..b1f38e7
--- /dev/null
+++ b/libexec/bootpd/tools/Makefile
@@ -0,0 +1,6 @@
+# Makefile
+# $Id$
+
+SUBDIR= bootpef bootptest
+
+.include <bsd.subdir.mk>
diff --git a/libexec/bootpd/tools/Makefile.inc b/libexec/bootpd/tools/Makefile.inc
new file mode 100644
index 0000000..0a2ab66
--- /dev/null
+++ b/libexec/bootpd/tools/Makefile.inc
@@ -0,0 +1,4 @@
+# Makefile.inc
+# $Id$
+
+BINDIR=/usr/sbin
diff --git a/libexec/bootpd/tools/bootpef/Makefile b/libexec/bootpd/tools/bootpef/Makefile
new file mode 100644
index 0000000..7d17606
--- /dev/null
+++ b/libexec/bootpd/tools/bootpef/Makefile
@@ -0,0 +1,13 @@
+# Makefile
+# $Id$
+
+PROG= bootpef
+MAN8= bootpef.8
+SRCS= bootpef.c dovend.c readfile.c hash.c dumptab.c lookup.c \
+ hwaddr.c report.c tzone.c rtmsg.c
+
+SRCDIR= ${.CURDIR}/../..
+CFLAGS+=-I${SRCDIR}
+.PATH: ${SRCDIR}
+
+.include <bsd.prog.mk>
diff --git a/libexec/bootpd/tools/bootpef/bootpef.8 b/libexec/bootpd/tools/bootpef/bootpef.8
new file mode 100644
index 0000000..0f0b1fc
--- /dev/null
+++ b/libexec/bootpd/tools/bootpef/bootpef.8
@@ -0,0 +1,52 @@
+.\" bootpef.8
+.TH BOOTPEF 8 "4 Dec 1993" "MAINTENANCE COMMANDS"
+.SH NAME
+bootpef \- BOOTP Extension File compiler
+.SH SYNOPSIS
+.LP
+.B bootpef
+.RI [ "-c chdir" ]
+.RI [ "-d debug-level" ]
+.RI [ "-f config-file" ]
+.RI [ client-name " [...]]"
+.SH DESCRIPTION
+.B bootpef
+builds the
+.I Extension Path
+files described by RFC 1497 (tag 18).
+If any
+.I client-name
+arguments are specified, then
+.I bootpef
+compiles the extension files for only those clients.
+.SH OPTIONS
+.TP
+.BI \-c \ chdir\-path
+Sets the current directory used by
+.I bootpef
+while creating extension files. This is useful when the
+extension file names are specified as relative pathnames, and
+.I bootpef
+needs to use the same current directory as the TFTP server
+(typically /tftpboot).
+.TP
+.BI \-d \ debug\-level
+Sets the
+.I debug\-level
+variable that controls the amount of debugging messages generated.
+For example, -d4 or -d 4 will set the debugging level to 4.
+.TP
+.BI \-f \ config\-file
+Set the name of the config file that specifies the option
+data to be sent to each client.
+.SH "SEE ALSO"
+bootpd(8), tftpd(8)
+.SH REFERENCES
+.TP
+RFC951
+BOOTSTRAP PROTOCOL (BOOTP)
+.TP
+RFC1497
+BOOTP Vendor Information Extensions
+
+
diff --git a/libexec/bootpd/tools/bootpef/bootpef.c b/libexec/bootpd/tools/bootpef/bootpef.c
new file mode 100644
index 0000000..c7e9276
--- /dev/null
+++ b/libexec/bootpd/tools/bootpef/bootpef.c
@@ -0,0 +1,343 @@
+/************************************************************************
+ 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.
+
+ $Id$
+
+************************************************************************/
+
+/*
+ * bootpef - BOOTP Extension File generator
+ * Makes an "Extension File" for each host entry that
+ * defines an and Extension File. (See RFC1497, tag 18.)
+ *
+ * HISTORY
+ * See ./Changes
+ *
+ * BUGS
+ * See ./ToDo
+ */
+
+
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "bootpd.h"
+#include "dovend.h"
+#include "readfile.h"
+#include "report.h"
+#include "tzone.h"
+#include "patchlevel.h"
+
+#define BUFFERSIZE 0x4000
+
+#ifndef CONFIG_FILE
+#define CONFIG_FILE "/etc/bootptab"
+#endif
+
+
+
+/*
+ * Externals, forward declarations, and global variables
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+static void mktagfile P((struct host *));
+static void usage P((void));
+
+#undef P
+
+
+/*
+ * General
+ */
+
+char *progname;
+char *chdir_path;
+int debug = 0; /* Debugging flag (level) */
+byte *buffer;
+
+/*
+ * Globals below are associated with the bootp database file (bootptab).
+ */
+
+char *bootptab = CONFIG_FILE;
+
+
+/*
+ * Print "usage" message and exit
+ */
+static void
+usage()
+{
+ fprintf(stderr,
+ "usage: $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
+ fprintf(stderr, "\t -c n\tset current directory\n");
+ fprintf(stderr, "\t -d n\tset debug level\n");
+ fprintf(stderr, "\t -f n\tconfig file name\n");
+ exit(1);
+}
+
+
+/*
+ * Initialization such as command-line processing is done and then the
+ * main server loop is started.
+ */
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct host *hp;
+ char *stmp;
+ int n;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+
+ /* Get work space for making tag 18 files. */
+ buffer = (byte *) malloc(BUFFERSIZE);
+ if (!buffer) {
+ report(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+ /*
+ * Set defaults that might be changed by option switches.
+ */
+ stmp = NULL;
+
+ /*
+ * Read switches.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'c': /* chdir_path */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (stmp[0] != '/')) {
+ fprintf(stderr,
+ "bootpd: invalid chdir specification\n");
+ break;
+ }
+ chdir_path = stmp;
+ break;
+
+ case 'd': /* debug */
+ 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 'f': /* config file */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ bootptab = stmp;
+ break;
+
+ default:
+ fprintf(stderr, "bootpd: unknown switch: -%c\n",
+ argv[0][1]);
+ usage();
+ break;
+ }
+ }
+
+ /* Get the timezone. */
+ tzone_init();
+
+ /* Allocate hash tables. */
+ rdtab_init();
+
+ /*
+ * Read the bootptab file.
+ */
+ readtab(1); /* force read */
+
+ /* Set the cwd (i.e. to /tftpboot) */
+ if (chdir_path) {
+ if (chdir(chdir_path) < 0)
+ report(LOG_ERR, "%s: chdir failed", chdir_path);
+ }
+ /* If there are host names on the command line, do only those. */
+ if (argc > 0) {
+ unsigned int tlen, hashcode;
+
+ while (argc) {
+ tlen = strlen(argv[0]);
+ hashcode = hash_HashFunction((u_char *)argv[0], tlen);
+ hp = (struct host *) hash_Lookup(nmhashtable,
+ hashcode,
+ nmcmp, argv[0]);
+ if (!hp) {
+ printf("%s: no matching entry\n", argv[0]);
+ exit(1);
+ }
+ if (!hp->flags.exten_file) {
+ printf("%s: no extension file\n", argv[0]);
+ exit(1);
+ }
+ mktagfile(hp);
+ argv++;
+ argc--;
+ }
+ exit(0);
+ }
+ /* No host names specified. Do them all. */
+ hp = (struct host *) hash_FirstEntry(nmhashtable);
+ while (hp != NULL) {
+ mktagfile(hp);
+ hp = (struct host *) hash_NextEntry(nmhashtable);
+ }
+}
+
+
+
+/*
+ * Make a "TAG 18" file for this host.
+ * (Insert the RFC1497 options.)
+ */
+
+static void
+mktagfile(hp)
+ struct host *hp;
+{
+ FILE *fp;
+ int bytesleft, len;
+ byte *vp;
+
+ if (!hp->flags.exten_file)
+ return;
+
+ vp = buffer;
+ bytesleft = BUFFERSIZE;
+ bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
+ vp += 4;
+ bytesleft -= 4;
+
+ /*
+ * The "extension file" options are appended by the following
+ * function (which is shared with bootpd.c).
+ */
+ len = dovend_rfc1497(hp, vp, bytesleft);
+ vp += len;
+ bytesleft -= len;
+
+ if (bytesleft < 1) {
+ report(LOG_ERR, "%s: too much option data",
+ hp->exten_file->string);
+ return;
+ }
+ *vp++ = TAG_END;
+ bytesleft--;
+
+ /* Write the buffer to the extension file. */
+ printf("Updating \"%s\"\n", hp->exten_file->string);
+ if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s",
+ hp->exten_file->string, get_errmsg());
+ return;
+ }
+ len = vp - buffer;
+ if (len != fwrite(buffer, 1, len, fp)) {
+ report(LOG_ERR, "write failed on \"%s\" : %s",
+ hp->exten_file->string, get_errmsg());
+ }
+ fclose(fp);
+
+} /* mktagfile */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/tools/bootptest/Makefile b/libexec/bootpd/tools/bootptest/Makefile
new file mode 100644
index 0000000..148a556
--- /dev/null
+++ b/libexec/bootpd/tools/bootptest/Makefile
@@ -0,0 +1,12 @@
+# Makefile
+# $Id$
+
+PROG= bootptest
+MAN8= bootptest.8
+SRCS= bootptest.c getether.c getif.c print-bootp.c report.c
+
+SRCDIR= ${.CURDIR}/../..
+CFLAGS+=-I${SRCDIR}
+.PATH: ${SRCDIR}
+
+.include <bsd.prog.mk>
diff --git a/libexec/bootpd/tools/bootptest/bootptest.8 b/libexec/bootpd/tools/bootptest/bootptest.8
new file mode 100644
index 0000000..d076c8b
--- /dev/null
+++ b/libexec/bootpd/tools/bootptest/bootptest.8
@@ -0,0 +1,74 @@
+.\" bootptest.8
+.TH BOOTPTEST 8 "10 June 1993" "MAINTENANCE COMMANDS"
+.SH NAME
+bootptest \- send BOOTP queries and print responses
+.SH SYNOPSIS
+.LP
+.B bootptest
+[
+.B \-f
+.I bootfile
+]
+[
+.B \-h
+]
+[
+.B \-m
+.I magic_number
+]
+.I server\-name
+.RI [ template-file ]
+.SH DESCRIPTION
+.B bootptest
+sends BOOTP requests to the host specified as
+.I server\-name
+at one\-second intervals until either a response is received,
+or until ten requests have gone unanswered.
+After a response is received,
+.B bootptest
+will wait one more second listening for additional responses.
+.SH OPTIONS
+.TP
+.B \-f
+.I bootfile
+Fill in the boot file field of the request with
+.IR bootfile .
+.TP
+.B \-h
+Use the hardware (Ethernet) address to identify the client.
+By default, the IP address is copied into the request
+indicating that this client already knows its IP address.
+.TP
+.B \-m
+.I magic_number
+Initialize the first word of the vendor options field with
+.IR magic_number .
+.LP
+A
+.I template-file
+may be specified, in which case
+.B bootptest
+uses the (binary) contents of this file to initialize the
+.I options
+area of the request packet.
+.SH CREDITS
+.LP
+The bootptest program is a combination of original and derived works.
+The main program module (bootptest.c) is original work by
+Gordon W. Ross <gwr@mc.com>.
+The packet printing module (print-bootp.c) is a slightly modified
+version of a file from the BSD tcpdump program.
+.LP
+This program includes software developed by the University of
+California, Lawrence Berkeley Laboratory and its contributors.
+(See the copyright notice in print-bootp.c)
+.SH "SEE ALSO"
+.LP
+bootpd(8)
+.SH REFERENCES
+.TP
+RFC951
+BOOTSTRAP PROTOCOL (BOOTP)
+.TP
+RFC1048
+BOOTP Vendor Information Extensions
diff --git a/libexec/bootpd/tools/bootptest/bootptest.c b/libexec/bootpd/tools/bootptest/bootptest.c
new file mode 100644
index 0000000..2e23112
--- /dev/null
+++ b/libexec/bootpd/tools/bootptest/bootptest.c
@@ -0,0 +1,520 @@
+/*
+ * bootptest.c - Test out a bootp server.
+ *
+ * This simple program was put together from pieces taken from
+ * various places, including the CMU BOOTP client and server.
+ * The packet printing routine is from the Berkeley "tcpdump"
+ * program with some enhancements I added. The print-bootp.c
+ * file was shared with my copy of "tcpdump" and therefore uses
+ * some unusual utility routines that would normally be provided
+ * by various parts of the tcpdump program. Gordon W. Ross
+ *
+ * Boilerplate:
+ *
+ * This program includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory and its contributors.
+ * (See the copyright notice in print-bootp.c)
+ *
+ * The remainder of this program is public domain. You may do
+ * whatever you like with it except claim that you wrote it.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * HISTORY:
+ *
+ * 12/02/93 Released version 1.4 (with bootp-2.3.2)
+ * 11/05/93 Released version 1.3
+ * 10/14/93 Released version 1.2
+ * 10/11/93 Released version 1.1
+ * 09/28/93 Released version 1.0
+ * 09/93 Original developed by Gordon W. Ross <gwr@mc.com>
+ *
+ * $Id$
+ */
+
+char *usage = "bootptest [-h] server-name [vendor-data-template-file]";
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <assert.h>
+
+#include "bootp.h"
+#include "bootptest.h"
+#include "getif.h"
+#include "getether.h"
+
+#include "patchlevel.h"
+
+static void send_request();
+
+#define LOG_ERR 1
+#define BUFLEN 1024
+#define WAITSECS 1
+#define MAXWAIT 10
+
+int vflag = 1;
+int tflag = 0;
+int thiszone;
+char *progname;
+unsigned char *packetp;
+unsigned char *snapend;
+int snaplen;
+
+
+/*
+ * 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 sin_server; /* where to send requests */
+struct sockaddr_in sin_client; /* for bind and listen */
+struct sockaddr_in sin_from; /* Packet source */
+u_char eaddr[16]; /* Ethernet address */
+
+/*
+ * General
+ */
+
+int debug = 1; /* Debugging flag (level) */
+char *sndbuf; /* Send packet buffer */
+char *rcvbuf; /* Receive packet buffer */
+
+struct utsname my_uname;
+char *hostname;
+
+/*
+ * Vendor magic cookies for CMU and RFC1048
+ */
+
+unsigned char vm_cmu[4] = VM_CMU;
+unsigned char vm_rfc1048[4] = VM_RFC1048;
+short secs; /* How long client has waited */
+
+char *get_errmsg();
+extern void bootp_print();
+
+/*
+ * Initialization such as command-line processing is done, then
+ * the receiver loop is started. Die when interrupted.
+ */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct bootp *bp;
+ struct servent *sep;
+ struct hostent *hep;
+
+ char *servername = NULL;
+ char *vendor_file = NULL;
+ char *bp_file = NULL;
+ int32 server_addr; /* inet addr, network order */
+ int s; /* Socket file descriptor */
+ int n, fromlen, recvcnt;
+ int use_hwa = 0;
+ int32 vend_magic;
+ int32 xid;
+
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+ argc--;
+ argv++;
+
+ if (debug)
+ printf("%s: version %s.%d\n", progname, VERSION, PATCHLEVEL);
+
+ /*
+ * Verify that "struct bootp" has the correct official size.
+ * (Catch evil compilers that do struct padding.)
+ */
+ assert(sizeof(struct bootp) == BP_MINPKTSZ);
+
+ if (uname(&my_uname) < 0) {
+ fprintf(stderr, "%s: can't get hostname\n", argv[0]);
+ exit(1);
+ }
+ hostname = my_uname.nodename;
+
+ sndbuf = malloc(BUFLEN);
+ rcvbuf = malloc(BUFLEN);
+ if (!sndbuf || !rcvbuf) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+
+ /* default magic number */
+ bcopy(vm_rfc1048, (char*)&vend_magic, 4);
+
+ /* Handle option switches. */
+ while (argc > 0) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'f': /* File name to reqest. */
+ if (argc < 2)
+ goto error;
+ argc--; argv++;
+ bp_file = *argv;
+ break;
+
+ case 'h': /* Use hardware address. */
+ use_hwa = 1;
+ break;
+
+ case 'm': /* Magic number value. */
+ if (argc < 2)
+ goto error;
+ argc--; argv++;
+ vend_magic = inet_addr(*argv);
+ break;
+
+ error:
+ default:
+ puts(usage);
+ exit(1);
+
+ }
+ argc--;
+ argv++;
+ }
+
+ /* Get server name (or address) for query. */
+ if (argc > 0) {
+ servername = *argv;
+ argc--;
+ argv++;
+ }
+ /* Get optional vendor-data-template-file. */
+ if (argc > 0) {
+ vendor_file = *argv;
+ argc--;
+ argv++;
+ }
+ if (!servername) {
+ printf("missing server name.\n");
+ puts(usage);
+ exit(1);
+ }
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+ /*
+ * Get server's listening port number
+ */
+ sep = getservbyname("bootps", "udp");
+ if (sep) {
+ bootps_port = ntohs((u_short) sep->s_port);
+ } else {
+ fprintf(stderr, "udp/bootps: unknown service -- using port %d\n",
+ IPPORT_BOOTPS);
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ }
+
+ /*
+ * Set up server socket address (for send)
+ */
+ if (servername) {
+ if (isdigit(servername[0]))
+ server_addr = inet_addr(servername);
+ else {
+ hep = gethostbyname(servername);
+ if (!hep) {
+ fprintf(stderr, "%s: unknown host\n", servername);
+ exit(1);
+ }
+ bcopy(hep->h_addr, &server_addr, sizeof(server_addr));
+ }
+ } else {
+ /* Get broadcast address */
+ /* XXX - not yet */
+ server_addr = INADDR_ANY;
+ }
+ sin_server.sin_family = AF_INET;
+ sin_server.sin_port = htons(bootps_port);
+ sin_server.sin_addr.s_addr = server_addr;
+
+ /*
+ * Get client's listening port number
+ */
+ sep = getservbyname("bootpc", "udp");
+ if (sep) {
+ bootpc_port = ntohs(sep->s_port);
+ } else {
+ fprintf(stderr, "udp/bootpc: unknown service -- using port %d\n",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
+ }
+
+ /*
+ * Set up client socket address (for listen)
+ */
+ sin_client.sin_family = AF_INET;
+ sin_client.sin_port = htons(bootpc_port);
+ sin_client.sin_addr.s_addr = INADDR_ANY;
+
+ /*
+ * Bind client socket to BOOTPC port.
+ */
+ if (bind(s, (struct sockaddr *) &sin_client, sizeof(sin_client)) < 0) {
+ perror("bind BOOTPC port");
+ if (errno == EACCES)
+ fprintf(stderr, "You need to run this as root\n");
+ exit(1);
+ }
+ /*
+ * Build a request.
+ */
+ bp = (struct bootp *) sndbuf;
+ bzero(bp, sizeof(*bp));
+ bp->bp_op = BOOTREQUEST;
+ xid = (int32) getpid();
+ bp->bp_xid = (u_int32) htonl(xid);
+ if (bp_file)
+ strncpy(bp->bp_file, bp_file, BP_FILE_LEN);
+
+ /*
+ * Fill in the hardware address (or client IP address)
+ */
+ if (use_hwa) {
+ struct ifreq *ifr;
+
+ ifr = getif(s, &sin_server.sin_addr);
+ if (!ifr) {
+ printf("No interface for %s\n", servername);
+ exit(1);
+ }
+ if (getether(ifr->ifr_name, (char*)eaddr)) {
+ printf("Can not get ether addr for %s\n", ifr->ifr_name);
+ exit(1);
+ }
+ /* Copy Ethernet address into request packet. */
+ bp->bp_htype = 1;
+ bp->bp_hlen = 6;
+ bcopy(eaddr, bp->bp_chaddr, bp->bp_hlen);
+ } else {
+ /* Fill in the client IP address. */
+ hep = gethostbyname(hostname);
+ if (!hep) {
+ printf("Can not get my IP address\n");
+ exit(1);
+ }
+ bcopy(hep->h_addr, &bp->bp_ciaddr, hep->h_length);
+ }
+
+ /*
+ * Copy in the default vendor data.
+ */
+ bcopy((char*)&vend_magic, bp->bp_vend, 4);
+ if (vend_magic)
+ bp->bp_vend[4] = TAG_END;
+
+ /*
+ * Read in the "options" part of the request.
+ * This also determines the size of the packet.
+ */
+ snaplen = sizeof(*bp);
+ if (vendor_file) {
+ int fd = open(vendor_file, 0);
+ if (fd < 0) {
+ perror(vendor_file);
+ exit(1);
+ }
+ /* Compute actual space for options. */
+ n = BUFLEN - sizeof(*bp) + BP_VEND_LEN;
+ n = read(fd, bp->bp_vend, n);
+ close(fd);
+ if (n < 0) {
+ perror(vendor_file);
+ exit(1);
+ }
+ printf("read %d bytes of vendor template\n", n);
+ if (n > BP_VEND_LEN) {
+ printf("warning: extended options in use (len > %d)\n",
+ BP_VEND_LEN);
+ snaplen += (n - BP_VEND_LEN);
+ }
+ }
+ /*
+ * Set globals needed by print_bootp
+ * (called by send_request)
+ */
+ packetp = (unsigned char *) eaddr;
+ snapend = (unsigned char *) sndbuf + snaplen;
+
+ /* Send a request once per second while waiting for replies. */
+ recvcnt = 0;
+ bp->bp_secs = secs = 0;
+ send_request(s);
+ while (1) {
+ struct timeval tv;
+ int readfds;
+
+ tv.tv_sec = WAITSECS;
+ tv.tv_usec = 0L;
+ readfds = (1 << s);
+ n = select(s + 1, (fd_set *) & readfds, NULL, NULL, &tv);
+ if (n < 0) {
+ perror("select");
+ break;
+ }
+ if (n == 0) {
+ /*
+ * We have not received a response in the last second.
+ * If we have ever received any responses, exit now.
+ * Otherwise, bump the "wait time" field and re-send.
+ */
+ if (recvcnt > 0)
+ exit(0);
+ secs += WAITSECS;
+ if (secs > MAXWAIT)
+ break;
+ bp->bp_secs = htons(secs);
+ send_request(s);
+ continue;
+ }
+ fromlen = sizeof(sin_from);
+ n = recvfrom(s, rcvbuf, BUFLEN, 0,
+ (struct sockaddr *) &sin_from, &fromlen);
+ if (n <= 0) {
+ continue;
+ }
+ if (n < sizeof(struct bootp)) {
+ printf("received short packet\n");
+ continue;
+ }
+ recvcnt++;
+
+ /* Print the received packet. */
+ printf("Recvd from %s", inet_ntoa(sin_from.sin_addr));
+ /* set globals needed by bootp_print() */
+ snaplen = n;
+ snapend = (unsigned char *) rcvbuf + snaplen;
+ bootp_print(rcvbuf, n, sin_from.sin_port, 0);
+ putchar('\n');
+ /*
+ * This no longer exits immediately after receiving
+ * one response because it is useful to know if the
+ * client might get multiple responses. This code
+ * will now listen for one second after a response.
+ */
+ }
+ fprintf(stderr, "no response from %s\n", servername);
+ exit(1);
+}
+
+static void
+send_request(s)
+ int s;
+{
+ /* Print the request packet. */
+ printf("Sending to %s", inet_ntoa(sin_server.sin_addr));
+ bootp_print(sndbuf, snaplen, sin_from.sin_port, 0);
+ putchar('\n');
+
+ /* Send the request packet. */
+ if (sendto(s, sndbuf, snaplen, 0,
+ (struct sockaddr *) &sin_server,
+ sizeof(sin_server)) < 0)
+ {
+ perror("sendto server");
+ exit(1);
+ }
+}
+
+/*
+ * Print out a filename (or other ascii string).
+ * Return true if truncated.
+ */
+int
+printfn(s, ep)
+ register u_char *s, *ep;
+{
+ register u_char c;
+
+ putchar('"');
+ while ((c = *s++) != '\0') {
+ if (s > ep) {
+ putchar('"');
+ return (1);
+ }
+ if (!isascii(c)) {
+ c = toascii(c);
+ putchar('M');
+ putchar('-');
+ }
+ if (!isprint(c)) {
+ c ^= 0x40; /* DEL to ?, others to alpha */
+ putchar('^');
+ }
+ putchar(c);
+ }
+ putchar('"');
+ return (0);
+}
+
+/*
+ * Convert an IP addr to a string.
+ * (like inet_ntoa, but ina is a pointer)
+ */
+char *
+ipaddr_string(ina)
+ struct in_addr *ina;
+{
+ static char b[24];
+ u_char *p;
+
+ p = (u_char *) ina;
+ sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ return (b);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/tools/bootptest/bootptest.h b/libexec/bootpd/tools/bootptest/bootptest.h
new file mode 100644
index 0000000..27f78ba
--- /dev/null
+++ b/libexec/bootpd/tools/bootptest/bootptest.h
@@ -0,0 +1,30 @@
+/* bootptest.h */
+/*
+ * Hacks for sharing print-bootp.c between tcpdump and bootptest.
+ */
+#define ESRC(p) (p)
+#define EDST(p) (p)
+
+#ifndef USE_BFUNCS
+/* Use mem/str functions */
+/* There are no overlapped copies, so memcpy is OK. */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+extern int vflag; /* verbose flag */
+
+/* global pointers to beginning and end of current packet (during printing) */
+extern unsigned char *packetp;
+extern unsigned char *snapend;
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern char *ipaddr_string P((struct in_addr *));
+
+#undef P
diff --git a/libexec/bootpd/tools/bootptest/print-bootp.c b/libexec/bootpd/tools/bootptest/print-bootp.c
new file mode 100644
index 0000000..c8e1c2e
--- /dev/null
+++ b/libexec/bootpd/tools/bootptest/print-bootp.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 1988-1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print bootp packets.
+ *
+ * This file was copied from tcpdump-2.1.1 and modified.
+ * There is an e-mail list for tcpdump: <tcpdump@ee.lbl.gov>
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <sys/time.h> /* for struct timeval in net/if.h */
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <string.h>
+#include <ctype.h>
+
+#include "bootp.h"
+#include "bootptest.h"
+
+/* These decode the vendor data. */
+extern int printfn();
+static void rfc1048_print();
+static void cmu_print();
+static void other_print();
+static void dump_hex();
+
+/*
+ * Print bootp requests
+ */
+void
+bootp_print(bp, length, sport, dport)
+ struct bootp *bp;
+ int length;
+ u_short sport, dport;
+{
+ static char tstr[] = " [|bootp]";
+ static unsigned char vm_cmu[4] = VM_CMU;
+ static unsigned char vm_rfc1048[4] = VM_RFC1048;
+ u_char *ep;
+ int vdlen;
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+ /* Note funny sized packets */
+ if (length != sizeof(struct bootp))
+ (void) printf(" [len=%d]", length);
+
+ /* 'ep' points to the end of avaible data. */
+ ep = (u_char *) snapend;
+
+ switch (bp->bp_op) {
+
+ case BOOTREQUEST:
+ /* Usually, a request goes from a client to a server */
+ if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS)
+ printf(" (request)");
+ break;
+
+ case BOOTREPLY:
+ /* Usually, a reply goes from a server to a client */
+ if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC)
+ printf(" (reply)");
+ break;
+
+ default:
+ printf(" bootp-#%d", bp->bp_op);
+ }
+
+ /* The usual hardware address type is 1 (10Mb Ethernet) */
+ if (bp->bp_htype != 1)
+ printf(" htype:%d", bp->bp_htype);
+
+ /* The usual length for 10Mb Ethernet address is 6 bytes */
+ if (bp->bp_hlen != 6)
+ printf(" hlen:%d", bp->bp_hlen);
+
+ /* Client's Hardware address */
+ if (bp->bp_hlen) {
+ register struct ether_header *eh;
+ register char *e;
+
+ TCHECK(bp->bp_chaddr[0], 6);
+ eh = (struct ether_header *) packetp;
+ if (bp->bp_op == BOOTREQUEST)
+ e = (char *) ESRC(eh);
+ else if (bp->bp_op == BOOTREPLY)
+ e = (char *) EDST(eh);
+ else
+ e = 0;
+ if (e == 0 || bcmp((char *) bp->bp_chaddr, e, 6))
+ dump_hex(bp->bp_chaddr, bp->bp_hlen);
+ }
+ /* Only print interesting fields */
+ if (bp->bp_hops)
+ printf(" hops:%d", bp->bp_hops);
+
+ if (bp->bp_xid)
+ printf(" xid:%d", ntohl(bp->bp_xid));
+
+ if (bp->bp_secs)
+ printf(" secs:%d", ntohs(bp->bp_secs));
+
+ /* Client's ip address */
+ TCHECK(bp->bp_ciaddr, sizeof(bp->bp_ciaddr));
+ if (bp->bp_ciaddr.s_addr)
+ printf(" C:%s", ipaddr_string(&bp->bp_ciaddr));
+
+ /* 'your' ip address (bootp client) */
+ TCHECK(bp->bp_yiaddr, sizeof(bp->bp_yiaddr));
+ if (bp->bp_yiaddr.s_addr)
+ printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr));
+
+ /* Server's ip address */
+ TCHECK(bp->bp_siaddr, sizeof(bp->bp_siaddr));
+ if (bp->bp_siaddr.s_addr)
+ printf(" S:%s", ipaddr_string(&bp->bp_siaddr));
+
+ /* Gateway's ip address */
+ TCHECK(bp->bp_giaddr, sizeof(bp->bp_giaddr));
+ if (bp->bp_giaddr.s_addr)
+ printf(" G:%s", ipaddr_string(&bp->bp_giaddr));
+
+ TCHECK(bp->bp_sname[0], sizeof(bp->bp_sname));
+ if (*bp->bp_sname) {
+ printf(" sname:");
+ if (printfn(bp->bp_sname, ep)) {
+ fputs(tstr + 1, stdout);
+ return;
+ }
+ }
+ TCHECK(bp->bp_file[0], sizeof(bp->bp_file));
+ if (*bp->bp_file) {
+ printf(" file:");
+ if (printfn(bp->bp_file, ep)) {
+ fputs(tstr + 1, stdout);
+ return;
+ }
+ }
+ /* Don't try to decode the vendor buffer unless we're verbose */
+ if (vflag <= 0)
+ return;
+
+ vdlen = sizeof(bp->bp_vend);
+ /* Vendor data can extend to the end of the packet. */
+ if (vdlen < (ep - bp->bp_vend))
+ vdlen = (ep - bp->bp_vend);
+
+ TCHECK(bp->bp_vend[0], vdlen);
+ printf(" vend");
+ if (!bcmp(bp->bp_vend, vm_rfc1048, sizeof(u_int32)))
+ rfc1048_print(bp->bp_vend, vdlen);
+ else if (!bcmp(bp->bp_vend, vm_cmu, sizeof(u_int32)))
+ cmu_print(bp->bp_vend, vdlen);
+ else
+ other_print(bp->bp_vend, vdlen);
+
+ return;
+ trunc:
+ fputs(tstr, stdout);
+#undef TCHECK
+}
+
+/*
+ * Option description data follows.
+ * These are decribed in: RFC-1048, RFC-1395, RFC-1497, RFC-1533
+ *
+ * The first char of each option string encodes the data format:
+ * ?: unknown
+ * a: ASCII
+ * b: byte (8-bit)
+ * i: inet address
+ * l: int32
+ * s: short (16-bit)
+ */
+char *
+rfc1048_opts[] = {
+ /* Originally from RFC-1048: */
+ "?PAD", /* 0: Padding - special, no data. */
+ "iSM", /* 1: subnet mask (RFC950)*/
+ "lTZ", /* 2: time offset, seconds from UTC */
+ "iGW", /* 3: gateways (or routers) */
+ "iTS", /* 4: time servers (RFC868) */
+ "iINS", /* 5: IEN name servers (IEN116) */
+ "iDNS", /* 6: domain name servers (RFC1035)(1034?) */
+ "iLOG", /* 7: MIT log servers */
+ "iCS", /* 8: cookie servers (RFC865) */
+ "iLPR", /* 9: lpr server (RFC1179) */
+ "iIPS", /* 10: impress servers (Imagen) */
+ "iRLP", /* 11: resource location servers (RFC887) */
+ "aHN", /* 12: host name (ASCII) */
+ "sBFS", /* 13: boot file size (in 512 byte blocks) */
+
+ /* Added by RFC-1395: */
+ "aDUMP", /* 14: Merit Dump File */
+ "aDNAM", /* 15: Domain Name (for DNS) */
+ "iSWAP", /* 16: Swap Server */
+ "aROOT", /* 17: Root Path */
+
+ /* Added by RFC-1497: */
+ "aEXTF", /* 18: Extensions Path (more options) */
+
+ /* Added by RFC-1533: (many, many options...) */
+#if 1 /* These might not be worth recognizing by name. */
+
+ /* IP Layer Parameters, per-host (RFC-1533, sect. 4) */
+ "bIP-forward", /* 19: IP Forwarding flag */
+ "bIP-srcroute", /* 20: IP Source Routing Enable flag */
+ "iIP-filters", /* 21: IP Policy Filter (addr pairs) */
+ "sIP-maxudp", /* 22: IP Max-UDP reassembly size */
+ "bIP-ttlive", /* 23: IP Time to Live */
+ "lIP-pmtuage", /* 24: IP Path MTU aging timeout */
+ "sIP-pmtutab", /* 25: IP Path MTU plateau table */
+
+ /* IP parameters, per-interface (RFC-1533, sect. 5) */
+ "sIP-mtu-sz", /* 26: IP MTU size */
+ "bIP-mtu-sl", /* 27: IP MTU all subnets local */
+ "bIP-bcast1", /* 28: IP Broadcast Addr ones flag */
+ "bIP-mask-d", /* 29: IP do mask discovery */
+ "bIP-mask-s", /* 30: IP do mask supplier */
+ "bIP-rt-dsc", /* 31: IP do router discovery */
+ "iIP-rt-sa", /* 32: IP router solicitation addr */
+ "iIP-routes", /* 33: IP static routes (dst,router) */
+
+ /* Link Layer parameters, per-interface (RFC-1533, sect. 6) */
+ "bLL-trailer", /* 34: do tralier encapsulation */
+ "lLL-arp-tmo", /* 35: ARP cache timeout */
+ "bLL-ether2", /* 36: Ethernet version 2 (IEEE 802.3) */
+
+ /* TCP parameters (RFC-1533, sect. 7) */
+ "bTCP-def-ttl", /* 37: default time to live */
+ "lTCP-KA-tmo", /* 38: keepalive time interval */
+ "bTCP-KA-junk", /* 39: keepalive sends extra junk */
+
+ /* Application and Service Parameters (RFC-1533, sect. 8) */
+ "aNISDOM", /* 40: NIS Domain (Sun YP) */
+ "iNISSRV", /* 41: NIS Servers */
+ "iNTPSRV", /* 42: NTP (time) Servers (RFC 1129) */
+ "?VSINFO", /* 43: Vendor Specific Info (encapsulated) */
+ "iNBiosNS", /* 44: NetBIOS Name Server (RFC-1001,1..2) */
+ "iNBiosDD", /* 45: NetBIOS Datagram Dist. Server. */
+ "bNBiosNT", /* 46: NetBIOS Note Type */
+ "?NBiosS", /* 47: NetBIOS Scope */
+ "iXW-FS", /* 48: X Window System Font Servers */
+ "iXW-DM", /* 49: X Window System Display Managers */
+
+ /* DHCP extensions (RFC-1533, sect. 9) */
+#endif
+};
+#define KNOWN_OPTIONS (sizeof(rfc1048_opts) / sizeof(rfc1048_opts[0]))
+
+static void
+rfc1048_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ u_char tag;
+ u_char *ep;
+ register int len;
+ u_int32 ul;
+ u_short us;
+ struct in_addr ia;
+ char *optstr;
+
+ printf("-rfc1395");
+
+ /* Step over magic cookie */
+ bp += sizeof(int32);
+ /* Setup end pointer */
+ ep = bp + length;
+ while (bp < ep) {
+ tag = *bp++;
+ /* Check for tags with no data first. */
+ if (tag == TAG_PAD)
+ continue;
+ if (tag == TAG_END)
+ return;
+ if (tag < KNOWN_OPTIONS) {
+ optstr = rfc1048_opts[tag];
+ printf(" %s:", optstr + 1);
+ } else {
+ printf(" T%d:", tag);
+ optstr = "?";
+ }
+ /* Now scan the length byte. */
+ len = *bp++;
+ if (bp + len > ep) {
+ /* truncated option */
+ printf(" |(%d>%d)", len, ep - bp);
+ return;
+ }
+ /* Print the option value(s). */
+ switch (optstr[0]) {
+
+ case 'a': /* ASCII string */
+ printfn(bp, bp + len);
+ bp += len;
+ len = 0;
+ break;
+
+ case 's': /* Word formats */
+ while (len >= 2) {
+ bcopy((char *) bp, (char *) &us, 2);
+ printf("%d", ntohs(us));
+ bp += 2;
+ len -= 2;
+ if (len) printf(",");
+ }
+ if (len) printf("(junk=%d)", len);
+ break;
+
+ case 'l': /* Long words */
+ while (len >= 4) {
+ bcopy((char *) bp, (char *) &ul, 4);
+ printf("%d", ntohl(ul));
+ bp += 4;
+ len -= 4;
+ if (len) printf(",");
+ }
+ if (len) printf("(junk=%d)", len);
+ break;
+
+ case 'i': /* INET addresses */
+ while (len >= 4) {
+ bcopy((char *) bp, (char *) &ia, 4);
+ printf("%s", ipaddr_string(&ia));
+ bp += 4;
+ len -= 4;
+ if (len) printf(",");
+ }
+ if (len) printf("(junk=%d)", len);
+ break;
+
+ case 'b':
+ default:
+ break;
+
+ } /* switch */
+
+ /* Print as characters, if appropriate. */
+ if (len) {
+ dump_hex(bp, len);
+ if (isascii(*bp) && isprint(*bp)) {
+ printf("(");
+ printfn(bp, bp + len);
+ printf(")");
+ }
+ bp += len;
+ len = 0;
+ }
+ } /* while bp < ep */
+}
+
+static void
+cmu_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ struct cmu_vend *v;
+ u_char *ep;
+
+ printf("-cmu");
+
+ v = (struct cmu_vend *) bp;
+ if (length < sizeof(*v)) {
+ printf(" |L=%d", length);
+ return;
+ }
+ /* Setup end pointer */
+ ep = bp + length;
+
+ /* Subnet mask */
+ if (v->v_flags & VF_SMASK) {
+ printf(" SM:%s", ipaddr_string(&v->v_smask));
+ }
+ /* Default gateway */
+ if (v->v_dgate.s_addr)
+ printf(" GW:%s", ipaddr_string(&v->v_dgate));
+
+ /* Domain name servers */
+ if (v->v_dns1.s_addr)
+ printf(" DNS1:%s", ipaddr_string(&v->v_dns1));
+ if (v->v_dns2.s_addr)
+ printf(" DNS2:%s", ipaddr_string(&v->v_dns2));
+
+ /* IEN-116 name servers */
+ if (v->v_ins1.s_addr)
+ printf(" INS1:%s", ipaddr_string(&v->v_ins1));
+ if (v->v_ins2.s_addr)
+ printf(" INS2:%s", ipaddr_string(&v->v_ins2));
+
+ /* Time servers */
+ if (v->v_ts1.s_addr)
+ printf(" TS1:%s", ipaddr_string(&v->v_ts1));
+ if (v->v_ts2.s_addr)
+ printf(" TS2:%s", ipaddr_string(&v->v_ts2));
+
+}
+
+
+/*
+ * Print out arbitrary, unknown vendor data.
+ */
+
+static void
+other_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ u_char *ep; /* end pointer */
+ u_char *zp; /* points one past last non-zero byte */
+
+ /* Setup end pointer */
+ ep = bp + length;
+
+ /* Find the last non-zero byte. */
+ for (zp = ep; zp > bp; zp--) {
+ if (zp[-1] != 0)
+ break;
+ }
+
+ /* Print the all-zero case in a compact representation. */
+ if (zp == bp) {
+ printf("-all-zero");
+ return;
+ }
+ printf("-unknown");
+
+ /* Are there enough trailing zeros to make "00..." worthwhile? */
+ if (zp + 2 > ep)
+ zp = ep; /* print them all normally */
+
+ /* Now just print all the non-zero data. */
+ while (bp < zp) {
+ printf(".%02X", *bp);
+ bp++;
+ }
+
+ if (zp < ep)
+ printf(".00...");
+
+ return;
+}
+
+static void
+dump_hex(bp, len)
+ u_char *bp;
+ int len;
+{
+ while (len > 0) {
+ printf("%02X", *bp);
+ bp++;
+ len--;
+ if (len) printf(".");
+ }
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/trygetea.c b/libexec/bootpd/trygetea.c
new file mode 100644
index 0000000..41800d7
--- /dev/null
+++ b/libexec/bootpd/trygetea.c
@@ -0,0 +1,55 @@
+/*
+ * trygetea.c - test program for getether.c
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+
+#ifdef _AIX32
+#include <sys/time.h> /* for struct timeval in net/if.h */
+#endif
+#include <net/if.h> /* for struct ifreq */
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "getether.h"
+
+int debug = 0;
+char *progname;
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ u_char ea[16]; /* Ethernet address */
+ int i;
+
+ progname = argv[0]; /* for report */
+
+ if (argc < 2) {
+ printf("need interface name\n");
+ exit(1);
+ }
+ if ((i = getether(argv[1], (char*)ea)) < 0) {
+ printf("Could not get Ethernet address (rc=%d)\n", i);
+ exit(1);
+ }
+ printf("Ether-addr");
+ for (i = 0; i < 6; i++)
+ printf(":%x", ea[i] & 0xFF);
+ printf("\n");
+
+ exit(0);
+}
diff --git a/libexec/bootpd/trygetif.c b/libexec/bootpd/trygetif.c
new file mode 100644
index 0000000..e6226dc
--- /dev/null
+++ b/libexec/bootpd/trygetif.c
@@ -0,0 +1,74 @@
+/*
+ * trygetif.c - test program for getif.c
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+
+#ifdef _AIX32
+#include <sys/time.h> /* for struct timeval in net/if.h */
+#endif
+#include <net/if.h> /* for struct ifreq */
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "getif.h"
+
+int debug = 0;
+char *progname;
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct hostent *hep;
+ struct sockaddr_in *sip; /* Interface address */
+ struct ifreq *ifr;
+ struct in_addr dst_addr;
+ struct in_addr *dap;
+ int s;
+
+ progname = argv[0]; /* for report */
+
+ dap = NULL;
+ if (argc > 1) {
+ dap = &dst_addr;
+ if (isdigit(argv[1][0]))
+ dst_addr.s_addr = inet_addr(argv[1]);
+ else {
+ hep = gethostbyname(argv[1]);
+ if (!hep) {
+ printf("gethostbyname(%s)\n", argv[1]);
+ exit(1);
+ }
+ memcpy(&dst_addr, hep->h_addr, sizeof(dst_addr));
+ }
+ }
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket open");
+ exit(1);
+ }
+ ifr = getif(s, dap);
+ if (!ifr) {
+ printf("no interface for address\n");
+ exit(1);
+ }
+ printf("Intf-name:%s\n", ifr->ifr_name);
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ printf("Intf-addr:%s\n", inet_ntoa(sip->sin_addr));
+
+ exit(0);
+}
diff --git a/libexec/bootpd/trylook.c b/libexec/bootpd/trylook.c
new file mode 100644
index 0000000..0681dce
--- /dev/null
+++ b/libexec/bootpd/trylook.c
@@ -0,0 +1,58 @@
+/*
+ * trylook.c - test program for lookup.c
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+#include "report.h"
+#include "lookup.h"
+
+extern char *ether_ntoa();
+extern char *inet_ntoa();
+
+int debug = 0;
+char *progname;
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ struct in_addr in;
+ char *a;
+ u_char *hwa;
+
+ progname = argv[0]; /* for report */
+
+ for (i = 1; i < argc; i++) {
+
+ /* Host name */
+ printf("%s:", argv[i]);
+
+ /* IP addr */
+ if (lookup_ipa(argv[i], &in.s_addr))
+ a = "?";
+ else
+ a = inet_ntoa(in);
+ printf(" ipa=%s", a);
+
+ /* Ether addr */
+ printf(" hwa=");
+ hwa = lookup_hwa(argv[i], 1);
+ if (!hwa)
+ printf("?\n");
+ else {
+ int i;
+ for (i = 0; i < 6; i++)
+ printf(":%x", hwa[i] & 0xFF);
+ putchar('\n');
+ }
+
+ }
+ exit(0);
+}
diff --git a/libexec/bootpd/tzone.c b/libexec/bootpd/tzone.c
new file mode 100644
index 0000000..4adc4ae
--- /dev/null
+++ b/libexec/bootpd/tzone.c
@@ -0,0 +1,44 @@
+/*
+ * tzone.c - get the timezone
+ *
+ * This is shared by bootpd and bootpef
+ */
+
+#ifdef SVR4
+/* XXX - Is this really SunOS specific? -gwr */
+/* This is in <time.h> but only visible if (__STDC__ == 1). */
+extern long timezone;
+#else /* SVR4 */
+/* BSD or SunOS */
+# include <sys/time.h>
+# include <syslog.h>
+#endif /* SVR4 */
+
+#include "bptypes.h"
+#include "report.h"
+#include "tzone.h"
+
+/* This is what other modules use. */
+int32 secondswest;
+
+/*
+ * Get our timezone offset so we can give it to clients if the
+ * configuration file doesn't specify one.
+ */
+void
+tzone_init()
+{
+#ifdef SVR4
+ /* XXX - Is this really SunOS specific? -gwr */
+ secondswest = timezone;
+#else /* SVR4 */
+ struct timezone tzp; /* Time zone offset for clients */
+ struct timeval tp; /* Time (extra baggage) */
+ if (gettimeofday(&tp, &tzp) < 0) {
+ secondswest = 0; /* Assume GMT for lack of anything better */
+ report(LOG_ERR, "gettimeofday: %s", get_errmsg());
+ } else {
+ secondswest = 60L * tzp.tz_minuteswest; /* Convert to seconds */
+ }
+#endif /* SVR4 */
+}
diff --git a/libexec/bootpd/tzone.h b/libexec/bootpd/tzone.h
new file mode 100644
index 0000000..ddd67c4
--- /dev/null
+++ b/libexec/bootpd/tzone.h
@@ -0,0 +1,3 @@
+/* tzone.h */
+extern int32 secondswest;
+extern void tzone_init();
diff --git a/libexec/bugfiler/Makefile b/libexec/bugfiler/Makefile
deleted file mode 100644
index 98489ad..0000000
--- a/libexec/bugfiler/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# @(#)Makefile 8.1 (Berkeley) 6/4/93
-
-PROG= bugfiler
-CFLAGS+=-I${.CURDIR}
-SRCS= bugfiler.c error.c gethead.c process.c redist.c reply.c
-BINOWN= root
-BINMODE=4555
-MAN1= sendbug.0
-MAN8= bugfiler.0
-
-beforeinstall:
- install -c -o bin -g ${BINGRP} -m 555 \
- ${.CURDIR}/sendbug.sh ${DESTDIR}/usr/bin/sendbug
- install -c -o bin -g ${BINGRP} -m 444 ${.CURDIR}/bugformat \
- ${DESTDIR}/usr/share/misc
-
-.include <bsd.prog.mk>
diff --git a/libexec/bugfiler/bug.h b/libexec/bugfiler/bug.h
deleted file mode 100644
index 69ea986..0000000
--- a/libexec/bugfiler/bug.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 1986, 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)bug.h 8.1 (Berkeley) 6/4/93
- */
-
-#define BUGS_HOME "owner-bugs@ucbvax.Berkeley.EDU"
-#define BUGS_ID "bugs"
-
-/*
- * the METOO definition has the bugfiler exit with an error (-1) status
- * if there's a problem. This causes sendmail to send off a copy of the
- * report (as failed mail) to the "owner" of the mail alias that executed
- * the bugfiler. This is great if you would have otherwise lost the bug
- * report. It's not so great if you get a whole bunch of mail that you
- * really don't want.
- */
-#define METOO
-
-/* files */
-#define ACK_FILE "bug:ack" /* acknowledge file */
-#define DIST_FILE "bug:redist" /* redistribution file */
-#define ERROR_FILE "log" /* error file */
-#define LOCK_FILE "bug:lock" /* lock file name */
-#define SUMMARY_FILE "summary" /* summary file */
-#define TMP_BUG "errors/BUG_XXXXXX" /* tmp bug report */
-#define TMP_DIR "errors" /* tmp directory */
-
-#define CHN (char *)NULL /* null arg string */
-#define COMMENT '#' /* comment in redist file */
-#define EOS (char)NULL /* end of string */
-#define ERR -1 /* error return */
-#define MAXLINELEN 200 /* max line length in message */
-#define NO 0 /* no/false */
-#define OK 0 /* okay return */
-#define YES 1 /* yes/true */
-
-typedef struct {
- short found, /* line number if found */
- redist; /* if part of redist headers */
- int (*valid)(); /* validation routine */
- short len; /* length of tag */
- char *tag, /* leading tag */
- *line; /* actual line */
-} HEADER;
-extern HEADER mailhead[];
-
-#define DATE_TAG 0 /* "Date:" offset */
-#define FROM_TAG 1 /* "From " offset */
-#define CFROM_TAG 2 /* "From:" offset */
-#define INDX_TAG 3 /* "Index:" offset */
-#define MSG_TAG 4 /* "Message-Id:" offset */
-#define RPLY_TAG 5 /* "Reply-To:" offset */
-#define RET_TAG 6 /* "Return-Path:" offset */
-#define SUBJ_TAG 7 /* "Subject:" offset */
-#define TO_TAG 8 /* "To:" offset */
-#define APPAR_TO_TAG 9 /* "Apparently-To:" offset */
-
-/* so sizeof doesn't return 0 */
-extern char bfr[MAXBSIZE], /* general I/O buffer */
- dir[MAXNAMLEN], /* subject and folder */
- folder[MAXNAMLEN],
- tmpname[sizeof(TMP_BUG) + 5]; /* temp bug file */
diff --git a/libexec/bugfiler/bugfiler.8 b/libexec/bugfiler/bugfiler.8
deleted file mode 100644
index 1fc86d2..0000000
--- a/libexec/bugfiler/bugfiler.8
+++ /dev/null
@@ -1,290 +0,0 @@
-.\" Copyright (c) 1983, 1991, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" @(#)bugfiler.8 8.2 (Berkeley) 12/11/93
-.\"
-.Dd December 11, 1993
-.Dt BUGFILER 8
-.Os BSD 4.2
-.Sh NAME
-.Nm bugfiler
-.Nd file bug reports in folders automatically
-.Sh SYNOPSIS
-.Nm bugfiler
-.Op Fl ar
-.Op Fl v Ar version
-.Sh DESCRIPTION
-.Nm Bugfiler
-is a program to automatically intercept, acknowledge,
-redistribute and store bug reports.
-.Nm Bugfiler
-is normally invoked
-by the mail delivery program with a line similar to the following in
-.Pa /etc/aliases .
-.Bd -literal -offset indent
-bugs: "|bugfiler"
-.Ed
-.Pp
-It should be noted that the login
-.Dq bugs
-must exist for the bugfiler
-to run. Unless otherwise noted all paths used by
-.Nm bugfiler
-are
-relative to the home directory of this login.
-.Nm Bugfiler
-also
-expects all of its files and directories to be owned by
-.Dq bugs .
-.Pp
-Available options.
-.Bl -tag -width Ds
-.It Fl a
-Do not send automatic mail acknowledgement to the bug report filer.
-(The default is to send the acknowledgement with the file
-.Pa ~bugs/version/bug:ack
-appended).
-.It Fl r
-Do not redistribute.
-.It Fl v Ar version
-Override the
-.Ar version
-provided within the bug report itself.
-.El
-.Pp
-For the bug report to be correctly filed, it must contain a line
-in the following format:
-.Pp
-.Bd -filled -offset indent -compact
-.Bl -column Index folder
-.It Index: Ta Em folder Ta Ar version
-.El
-.Ed
-.Pp
-The directories
-.Pa ~bugs/ Ns Ar version
-and
-.Pa ~bugs/ Ns Ar version/ Ns Em folder
-must exist before
-.Nm bugfiler
-attempts to store the bug report. Bug
-reports will be stored in files named by the concatenation of
-.Ar version ,
-.Em folder ,
-and sequential numbers, i.e. if
-.Ar version
-is
-.Dq 4.3 Tn BSD
-and
-.Em folder
-is
-.Dq ucb
-the first bug report will be placed in
-.Pa ~bugs/4.3BSD/ucb/1 .
-If
-.Em folder
-contains more than one component only
-the first one will be used, e.g. if
-.Em folder
-is
-.Dq bin/from.c
-or
-.Dq bin/adb/con.c
-it will be treated as if it were simply
-.Dq bin .
-.Pp
-.Pp
-If the
-.Fl r
-flag is not supplied, redistribution of the bug reports
-is done as specified in the file
-.Pa ~bugs/version/bug:redist .
-This file
-is in the format of the
-.Xr aliases 5
-file, including comments and
-entries requiring multiple lines, with the single exception that the
-.Em folder
-component of the
-.Dq Index:
-line replaces the name to alias.
-The special folder
-.Dq all:
-receives a redistribution of all bug reports
-sent to this
-.Ar version .
-For example, the
-.Pa bug:redist
-file
-.Pp
-.Bd -literal -offset indent -compact
-# bigbug gets a copy of everything
-all: bigbug
-# ucb folder redistribution list
-ucb: karels, kjd@coke.berkeley.edu
- ra@beno.css.gov
-.Ed
-.Pp
-will send copies of all bug reports with
-.Dq ucb
-as the
-.Em folder
-to bigbug, karels, kjd, and ra.
-.Pp
-Reports that cannot be filed, due to an invalid
-.Dq Index:
-line or
-some other error, are placed in the directory
-.Pa ~bugs/errors .
-The
-.Nm bugfiler
-maintainer should correct these bug reports and then
-run
-.Nm bugfiler ,
-with the corrected report as its standard input,
-as bug reports with errors are neither acknowledged or redistributed.
-All reports that
-.Nm bugfiler
-handles are logged in
-.Pa ~bugs/log.
-.Pp
-Valid bugs are also logged in the file
-.Pa ~bugs/version/summary.
-This file has an entry for each bug report for
-.Ar version
-in the
-format:
-.Pp
-.Bd -literal -offset indent -compact
-Filename Date
- Subject:
- Index:
- Owner: Bugs Bunny
- Status: Received
-.Ed
-.Pp
-.Li Filename
-is the concatenation of
-.Ar version ,
-.Em folder ,
-and a number
-as described above.
-.Xr Date
-is the date as reported by the system
-clock, using
-.Xr ctime 3 .
-The
-.Li Subject:
-and
-.Li Index:
-lines are
-copies of the
-.Dq Subject:
-and
-.Dq index:
-lines contained in the bug
-report. The
-.Li Owner
-and
-.Li Status
-fields are intended to provide a
-rudimentary method of tracking the status of bug reports.
-.Pp
-The file
-.Pa ~bugs/bug:lock
-is the focus of all locking for
-.Nm bugfiler .
-If you wish to manipulate any of the log or error files, rename or remove
-it and
-.Nm bugfiler
-will treat all bug reports that it receives as if
-they were incorrectly formatted, i.e. it will place them in the directory
-.Pa ~bugs/errors ,
-for later recovery by the
-.Nm bugfiler
-maintainer.
-Obviously, this file must be created when you first install
-.Nm bugfiler .
-.Pp
-All errors that occur before
-.Pa ~bugs/log
-is found are logged into the system
-log file, using
-.Xr syslog 8 .
-.Sh FILES
-.Bl -tag -width /usr/share/misc/bugformatxx -compact
-.It Pa ~bugs/bug:ack
-the acknowledgement message
-.It Pa ~bugs/bug:redist
-the redistribution list
-.It Pa ~bugs/bug:lock
-the locking file
-.It Pa ~bugs/errors/BUG_??????
-bug reports with format errors
-.It Pa ~bugs/log
-the log file
-.It Pa ~bugs/folder/summary
-the summary files
-.It Pa /usr/sbin/sendmail
-the mail delivery program
-.It Pa /usr/share/misc/bugformat
-a sample bug report format
-.El
-.Sh SEE ALSO
-.Xr sendbug 1 ,
-.Xr aliases 5 ,
-.Xr syslog 8
-.Sh BUGS
-Since mail can be forwarded in a number of different ways,
-.Nm bugfiler
-does not recognize forwarded mail and will acknowledge to the forwarder
-instead of the original sender unless there is a
-.Dq Reply-To
-field in the
-header.
-.Pp
-This version of
-.Nm bugfiler
-is not compatible with the version
-released with
-.Bx 4.3
-in that it doesn't complain to the sender about
-incorrectly formatted bug reports.
-Frankly, we got tired of the profanity, not to mention the extended
-conversations
-.Nm bugfiler
-was holding with
-.Xr vacation 1 .
-.Sh HISTORY
-The
-.Nm
-command appeared in
-.Bx 4.2 .
diff --git a/libexec/bugfiler/bugfiler.c b/libexec/bugfiler/bugfiler.c
deleted file mode 100644
index 75dbef3..0000000
--- a/libexec/bugfiler/bugfiler.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (c) 1983, 1986, 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1983, 1986, 1987, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)bugfiler.c 8.1 (Berkeley) 6/4/93";
-#endif /* not lint */
-
-/*
- * Bug report processing program, designed to be invoked
- * through aliases(5).
- */
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-
-#include <dirent.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bug.h"
-#include "extern.h"
-
-char bfr[MAXBSIZE], /* general I/O buffer */
- tmpname[sizeof(TMP_BUG) + 5]; /* temp bug file */
-
-static void logit __P((void));
-static void make_copy __P((void));
-
-int
-main(argc, argv)
- int argc;
- char *argv[];
-{
- extern char *optarg; /* getopt arguments */
- register struct passwd *pwd; /* bugs password entry */
- register int ch; /* getopts char */
- int do_ack, /* acknowledge bug report */
- do_redist; /* redistribut BR */
- char *argversion; /* folder name provided */
-
- do_ack = do_redist = YES;
- argversion = NULL;
- while ((ch = getopt(argc, argv, "av:r")) != EOF)
- switch(ch) {
- case 'a':
- do_ack = NO;
- break;
- case 'v':
- argversion = optarg;
- break;
- case 'r':
- do_redist = NO;
- break;
- case '?':
- default:
- fputs("usage: bugfiler [-ar] [-v version]\n", stderr);
- error("usage: bugfiler [-ar] [-v version]", CHN);
- }
-
- if (!(pwd = getpwnam(BUGS_ID)))
- error("can't find bugs login.", BUGS_ID);
-
- if (chdir(pwd->pw_dir)) /* change to bugs home directory */
- error("can't chdir to %s.", pwd->pw_dir);
-
- if (seteuid(pwd->pw_uid))
- error("can't set id to %s.", BUGS_ID);
-
- (void)umask(02); /* everything is 664 */
- seterr(); /* redirect to log file */
- logit(); /* log report arrival */
- make_copy(); /* save copy in case */
- gethead(do_redist);
-
- if (argversion) /* specific folder requested */
- (void)strcpy(dir, argversion);
-
- process();
-
- if (seteuid(0))
- error("can't set id to root.", CHN);
- if (do_ack)
- reply();
- if (do_redist)
- redist();
- (void)unlink(tmpname);
- exit(OK);
-}
-
-/*
- * make_copy --
- * make a copy of bug report in error folder
- */
-static void
-make_copy()
-{
- register int cnt, /* read return value */
- tfd; /* temp file descriptor */
-
- if (access(TMP_DIR, F_OK))
- (void)mkdir(TMP_DIR, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH);
- (void)strcpy(tmpname, TMP_BUG);
- if (tfd = mkstemp(tmpname)) {
- while ((cnt = read(fileno(stdin),
- bfr, sizeof(bfr))) != ERR && cnt)
- write(tfd, bfr, cnt);
- (void)close(tfd);
- return;
- }
- error("can't make copy using %s.", tmpname);
-}
-
-/*
- * logit --
- * log this run of the bugfiler
- */
-static void
-logit()
-{
- struct timeval tp;
- char *C1, *C2;
-
- if (gettimeofday(&tp, (struct timezone *)NULL))
- error("can't get time of day.", CHN);
- for (C1 = C2 = ctime(&tp.tv_sec); *C1 && *C1 != '\n'; ++C1);
- *C1 = EOS;
- fputs(C2, stderr);
-}
diff --git a/libexec/bugfiler/bugformat b/libexec/bugfiler/bugformat
deleted file mode 100644
index 97a767d..0000000
--- a/libexec/bugfiler/bugformat
+++ /dev/null
@@ -1,32 +0,0 @@
-Subject: Short summary of the problem (please make this meaningful!)
-Index: folder 4.4BSD-alpha
-
-Description:
- Detailed description of the problem, suggestion, or complaint.
-Repeat-By:
- Describe the sequence of events that causes the problem
- to occur.
-Fix:
- Description of how to fix the problem. If you don't know a
- fix for the problem, don't include this section.
-
--------- Remove this line and what's below it, for reference only. --------
-
-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
- | local | man | misc | new | sys | ucb
- | usr.bin | usr.lib
-
-If you're not running 4.3BSD, you should also replace "4.3BSD" on
-the same line with one of the following values.
-
- version ::= 4.3BSD | 4.3BSD-tahoe | 4.3BSD-reno | net2
- | 4.4BSD-alpha
-
-For example, if your bug concerns the program "/usr/bin/file" and
-you're currently running 4.3BSD-Reno, you should replace "folder"
-with "usr.bin/file", and "4.4BSD-alpha" with "4.3BSD-Reno". The folder
-"ideas" is for suggestions.
diff --git a/libexec/bugfiler/gethead.c b/libexec/bugfiler/gethead.c
deleted file mode 100644
index ba7e361..0000000
--- a/libexec/bugfiler/gethead.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (c) 1986, 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)gethead.c 8.1 (Berkeley) 6/4/93";
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <dirent.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "pathnames.h"
-#include "bug.h"
-#include "extern.h"
-
-static int chk1 __P((char *));
-static int pbuf __P((char *));
-
-#define ENT(X) sizeof(X) - 1, X
-HEADER mailhead[] = { /* mail headers */
- { NO, YES, NULL, ENT("Date:"), },
- { NO, NO, NULL, ENT("From "), },
- { NO, YES, NULL, ENT("From:"), },
- { NO, NO, chk1, ENT("Index:"), },
- { NO, YES, NULL, ENT("Message-Id:"), },
- { NO, YES, NULL, ENT("Reply-To:"), },
- { NO, YES, NULL, ENT("Return-Path:"), },
- { NO, NO, pbuf, ENT("Subject:"), },
- { NO, YES, NULL, ENT("To:"), },
- { NO, NO, NULL, ENT("Apparently-To:"), },
- { ERR, }
-};
-
-FILE *dfp; /* distf file pointer */
-char dir[MAXNAMLEN], /* subject and folder */
- folder[MAXNAMLEN];
-
-/*
- * gethead --
- * read mail and bug headers from bug report, construct redist headers
- */
-void
-gethead(redist)
- int redist;
-{
- register HEADER *hp; /* mail header pointer */
-
- if (redist) {
- int fd;
- char *distf;
-
- distf = strdup(_PATH_TMP);
- if (!(fd = mkstemp(distf)) || !(dfp = fdopen(fd, "w+")))
- error("can't create redistribution file %s.", distf);
- /* disappear after last reference is closed */
- (void)unlink(distf);
- free(distf);
- }
- if (!freopen(tmpname, "r", stdin))
- error("can't read temporary bug file %s.", tmpname);
-
- while (fgets(bfr, sizeof(bfr), stdin)) {
- for (hp = mailhead; hp->found != ERR; ++hp)
- if (!hp->found)
- if (!strncmp(hp->tag, bfr, hp->len)) {
- if (hp->valid && !((*(hp->valid))(bfr)))
- break;
- if (!(hp->line =
- malloc((u_int)(strlen(bfr) + 1))))
- error("malloc failed.", CHN);
- (void)strcpy(hp->line, bfr);
- hp->found = YES;
- break;
- }
- if ((hp->found == ERR || hp->redist) && redist)
- fputs(bfr, dfp);
- }
-
- if (!mailhead[INDX_TAG].found)
- error("no readable \"Index:\" header in bug report.", CHN);
-}
-
-/*
- * chk1 --
- * parse the "Index:" line into folder and directory
- */
-static int
-chk1(line)
- char *line;
-{
- register char *C; /* tmp pointer */
- struct stat sbuf; /* existence check */
-
- if (sscanf(line, " Index: %s %s ", folder, dir) != 2)
- return(NO);
- if (C = strchr(folder, '/')) { /* deal with "bin/from.c" */
- if (C == folder)
- return(NO);
- *C = EOS;
- }
- if (stat(dir, &sbuf) || (sbuf.st_mode & S_IFMT) != S_IFDIR)
- return(NO);
- (void)pbuf(line);
- return(YES);
-}
-
-/*
- * pbuf --
- * kludge so that summary file looks pretty
- */
-static int
-pbuf(line)
- char *line;
-{
- register char *rp, /* tmp pointers */
- *wp;
-
- for (rp = line; *rp == ' ' || *rp == '\t'; ++rp);
- for (wp = line; *rp; ++wp) {
- if ((*wp = *rp++) != ' ' && *wp != '\t')
- continue;
- *wp = ' ';
- while (*rp == ' ' || *rp == '\t')
- ++rp;
- }
- if (wp[-1] == ' ') /* wp can't == line */
- --wp;
- *wp = EOS;
- return(YES);
-}
diff --git a/libexec/bugfiler/process.c b/libexec/bugfiler/process.c
deleted file mode 100644
index 6d376fd..0000000
--- a/libexec/bugfiler/process.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 1986, 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)process.c 8.1 (Berkeley) 6/4/93";
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/time.h>
-
-#include <ctype.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "bug.h"
-#include "extern.h"
-
-char pfile[MAXPATHLEN]; /* permanent file name */
-
-static int getnext __P((void));
-
-/*
- * process --
- * copy report to permanent file,
- * update summary file.
- */
-int
-process()
-{
- register int rval; /* read return value */
- struct timeval tp; /* time of day */
- int lfd; /* lock file descriptor */
-
- if (access(LOCK_FILE, R_OK) || (lfd = open(LOCK_FILE, O_RDONLY, 0)) < 0)
- error("can't find lock file %s.", LOCK_FILE);
- if (flock(lfd, LOCK_EX))
- error("can't get lock.", CHN);
- sprintf(pfile, "%s/%s/%d", dir, folder, getnext());
- fprintf(stderr, "\t%s\n", pfile);
- if (!(freopen(pfile, "w", stdout)))
- error("can't create %s.", pfile);
- rewind(stdin);
- while ((rval = read(fileno(stdin), bfr, sizeof(bfr))) != ERR && rval)
- if (write(fileno(stdout), bfr, rval) != rval)
- error("write to %s failed.", pfile);
-
- /* append information to the summary file */
- sprintf(bfr, "%s/%s", dir, SUMMARY_FILE);
- if (!(freopen(bfr, "a", stdout)))
- error("can't append to summary file %s.", bfr);
- if (gettimeofday(&tp, (struct timezone *)NULL))
- error("can't get time of day.", CHN);
- printf("\n%s\t\t%s\t%s\t%s\tOwner: Bugs Bunny\n\tStatus: Received\n",
- pfile, ctime(&tp.tv_sec), mailhead[INDX_TAG].line,
- mailhead[SUBJ_TAG].found ? mailhead[SUBJ_TAG].line : "Subject:\n");
- (void)flock(lfd, LOCK_UN);
- (void)fclose(stdout);
-}
-
-/*
- * getnext --
- * get next file name (number)
- */
-static int
-getnext()
-{
- register struct dirent *d; /* directory structure */
- register DIR *dirp; /* directory pointer */
- register int highval, newval;
- register char *p;
-
- (void)sprintf(bfr, "%s/%s", dir, folder);
- if (!(dirp = opendir(bfr)))
- error("can't read folder directory %s.", bfr);
- for (highval = -1; d = readdir(dirp);) {
- for (p = d->d_name; *p && isdigit(*p); ++p);
- if (!*p && (newval = atoi(d->d_name)) > highval)
- highval = newval;
- }
- closedir(dirp);
- return(++highval);
-}
diff --git a/libexec/bugfiler/redist.c b/libexec/bugfiler/redist.c
deleted file mode 100644
index 87a18b6..0000000
--- a/libexec/bugfiler/redist.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 1986, 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)redist.c 8.1 (Berkeley) 6/4/93";
-#endif /* not lint */
-
-#include <sys/param.h>
-
-#include <ctype.h>
-#include <dirent.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "bug.h"
-#include "pathnames.h"
-#include "extern.h"
-
-/*
- * redist --
- * Redistribute a bug report to those people indicated in the
- * redistribution list file.
- */
-void
-redist()
-{
- extern FILE *dfp; /* dist file fp */
- extern char pfile[]; /* permanent bug file */
- register char *C1, *C2;
- FILE *pf;
- int group;
-
- (void)sprintf(bfr, "%s/%s", dir, DIST_FILE);
- if (!freopen(bfr, "r", stdin))
- return;
- for (pf = NULL, group = 0; fgets(bfr, sizeof(bfr), stdin);) {
- if (C1 = strchr(bfr, '\n'))
- *C1 = '\0';
-nextline: if (*bfr == COMMENT ||
- isspace(*bfr) || !(C1 = index(bfr, ':')))
- continue;
- *C1 = EOS;
- if (!strcmp(bfr, folder) || !strcmp(bfr, "all")) {
- for (++C1; *C1 && (*C1 == ' ' || *C1 == '\t'); ++C1);
- if (!*C1) /* if empty list */
- continue;
- if (!pf) {
- if (!(pf = popen(MAIL_CMD, "w")))
- error("sendmail pipe failed.", CHN);
- if (mailhead[SUBJ_TAG].found)
- fprintf(pf,
- "%s", mailhead[SUBJ_TAG].line);
- else
- fprintf(pf,
- "Subject: Untitled Bug Report\n");
- if (!mailhead[TO_TAG].line) {
- if (mailhead[APPAR_TO_TAG].line)
- fprintf(pf, "To%s",
- strchr(mailhead[APPAR_TO_TAG].line,
- ':'));
- else
- fprintf(pf, "To: %s\n", BUGS_ID);
- }
- fputs("Resent-To: ", pf);
- }
- /*
- * write out first entry, then succeeding entries
- * backward compatible, handles back slashes at end
- * of line
- */
- if (group++)
- fputs(", ", pf);
- for (;;) {
- if (C2 = strchr(C1, '\\'))
- *C2 = EOS;
- fputs(C1, pf);
- if (!fgets(bfr, sizeof(bfr), stdin))
- break;
- if (C1 = strchr(bfr, '\n'))
- *C1 = '\0';
- if (*bfr != ' ' && *bfr != '\t')
- goto nextline;
- for (C1 = bfr;
- *C1 && (*C1 == ' ' || *C1 == '\t'); ++C1);
- }
- }
- }
- if (!pf)
- return;
-
- putc('\n', pf);
-
- rewind(dfp);
- /* add Reference header and copy bug report out */
- while (fgets(bfr, sizeof(bfr), dfp) && *bfr != '\n')
- fputs(bfr, pf);
- fprintf(pf, "\n%sReference: %s\n\n", mailhead[INDX_TAG].line, pfile);
- while (fgets(bfr, sizeof(bfr), dfp))
- fputs(bfr, pf);
- (void)pclose(pf);
-}
diff --git a/libexec/bugfiler/reply.c b/libexec/bugfiler/reply.c
deleted file mode 100644
index 0f99401..0000000
--- a/libexec/bugfiler/reply.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 1986, 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)reply.c 8.1 (Berkeley) 6/4/93";
-#endif /* not lint */
-
-#include <sys/param.h>
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bug.h"
-#include "extern.h"
-#include "pathnames.h"
-
-/*
- * reply --
- * tell the user we got their silly little bug report
- */
-void
-reply()
-{
- register char *C, /* traveling pointer */
- *to; /* who we're replying to */
- register int afd, /* ack file descriptor */
- rval; /* return value */
- FILE *pf; /* pipe pointer */
-
- if (mailhead[RPLY_TAG].found) {
- for (C = mailhead[RPLY_TAG].line + mailhead[RPLY_TAG].len;
- *C != '\n' && (*C == ' ' || *C == '\t');++C);
- if (*C)
- goto gotone;
- }
- if (mailhead[FROM_TAG].found) {
- for (C = mailhead[FROM_TAG].line + mailhead[FROM_TAG].len;
- *C != '\n' && (*C == ' ' || *C == '\t');++C);
- if (*C)
- goto gotone;
- }
- if (mailhead[CFROM_TAG].found) {
- for (C = mailhead[CFROM_TAG].line + mailhead[CFROM_TAG].len;
- *C != '\n' && (*C == ' ' || *C == '\t');++C);
- if (*C)
- goto gotone;
- }
- return;
-
- /* if it's a foo <XXX>, get the XXX, else get foo (first string) */
-gotone: if (to = strchr(C, '<'))
- for (C = ++to;
- *C != '\n' && *C != ' ' && *C != '\t' && *C != '>';++C);
- else {
- to = C;
- for (to = C++;*C != '\n' && *C != ' ' && *C != '\t';++C);
- }
- *C = EOS;
-
- if (!(pf = popen(MAIL_CMD, "w")))
- error("sendmail pipe failed.", CHN);
-
- fprintf(pf, "Reply-To: %s\nFrom: %s (Bugs Bunny)\nTo: %s\n",
- BUGS_HOME, BUGS_HOME, to);
- if (mailhead[SUBJ_TAG].found)
- fprintf(pf, "Subject: Re:%s",
- mailhead[SUBJ_TAG].line + mailhead[SUBJ_TAG].len);
- else
- fputs("Subject: Bug report acknowledgement.\n", pf);
- if (mailhead[DATE_TAG].found)
- fprintf(pf, "In-Acknowledgement-Of: Your message of %s",
- mailhead[DATE_TAG].line + mailhead[DATE_TAG].len);
- if (mailhead[MSG_TAG].found)
- fprintf(pf, "\t\t%s", mailhead[MSG_TAG].line);
- fputs("Precedence: bulk\n\n", pf); /* vacation(1) uses this... */
- fflush(pf);
-
- (void)sprintf(bfr, "%s/%s", dir, ACK_FILE);
- if ((afd = open(bfr, O_RDONLY, 0)) >= 0) {
- while ((rval = read(afd, bfr, sizeof(bfr))) != ERR && rval)
- (void)write(fileno(pf), bfr, rval);
- (void)close(afd);
- }
- pclose(pf);
-}
diff --git a/libexec/bugfiler/sendbug.sh b/libexec/bugfiler/sendbug.sh
deleted file mode 100644
index 911ef9d..0000000
--- a/libexec/bugfiler/sendbug.sh
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/sh -
-#
-# Copyright (c) 1983, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. All advertising materials mentioning features or use of this software
-# must display the following acknowledgement:
-# This product includes software developed by the University of
-# California, Berkeley and its contributors.
-# 4. Neither the name of the University nor the names of its contributors
-# may be used to endorse or promote products derived from this software
-# without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# @(#)sendbug.sh 8.1 (Berkeley) 6/4/93
-#
-
-# create a bug report and mail it to '4bsd-bugs'.
-
-PATH=/bin:/sbin:/usr/sbin:/usr/bin
-export PATH
-
-TEMP=/tmp/bug$$
-FORMAT=/usr/share/misc/bugformat
-
-# uucp sites should use ": ${BUGADDR=ucbvax!4bsd-bugs}" with a suitable path.
-: ${BUGADDR=4bsd-bugs@CS.Berkeley.EDU}
-: ${EDITOR=vi}
-
-trap 'rm -f $TEMP ; exit 1' 1 2 3 13 15
-
-cp $FORMAT $TEMP
-chmod u+w $TEMP
-if $EDITOR $TEMP
-then
- if cmp -s $FORMAT $TEMP
- then
- echo "File not changed, no bug report submitted."
- exit
- fi
- case "$#" in
- 0) sendmail -t -oi $BUGADDR < $TEMP ;;
- *) sendmail -t -oi "$@" < $TEMP ;;
- esac
-fi
-
-rm -f $TEMP
diff --git a/libexec/comsat/Makefile b/libexec/comsat/Makefile
index 0e11b5f..7352ab5 100644
--- a/libexec/comsat/Makefile
+++ b/libexec/comsat/Makefile
@@ -1,6 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
PROG= comsat
-MAN8= comsat.0
+MAN8= comsat.8
.include <bsd.prog.mk>
diff --git a/libexec/comsat/comsat.8 b/libexec/comsat/comsat.8
index 395522c..916d1c9 100644
--- a/libexec/comsat/comsat.8
+++ b/libexec/comsat/comsat.8
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)comsat.8 8.1 (Berkeley) 6/4/93
+.\" $Id$
.\"
.Dd June 4, 1993
.Dt COMSAT 8
@@ -53,7 +54,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 +73,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 e2e4477..c3b876a 100644
--- a/libexec/comsat/comsat.c
+++ b/libexec/comsat/comsat.c
@@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@@ -54,7 +56,7 @@ static char sccsid[] = "@(#)comsat.c 8.1 (Berkeley) 6/4/93";
#include <netdb.h>
#include <paths.h>
#include <pwd.h>
-#include <sgtty.h>
+#include <termios.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -73,9 +75,9 @@ struct utmp *utmp = NULL;
time_t lastmsgtime;
int nutmp, uf;
-void jkfprintf __P((FILE *, char[], off_t));
+void jkfprintf __P((FILE *, char[], char[], off_t));
void mailfor __P((char *));
-void notify __P((struct utmp *, off_t));
+void notify __P((struct utmp *, char[], off_t, int));
void onalrm __P((int));
void reapchildren __P((int));
@@ -87,7 +89,7 @@ main(argc, argv)
struct sockaddr_in from;
register int cc;
int fromlen;
- char msgbuf[100];
+ char msgbuf[256];
/* verify proper invocation */
fromlen = sizeof(from);
@@ -170,27 +172,43 @@ 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];
+ char buf2[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1];
if (!(cp = strchr(name, '@')))
return;
*cp = '\0';
offset = atoi(cp + 1);
+ if (!(cp = strchr(cp + 1, ':')))
+ file = name;
+ else
+ file = cp + 1;
+ sprintf(buf, "%s/%.*s", _PATH_MAILDIR, sizeof(utmp[0].ut_name), name);
+ if (*file != '/') {
+ sprintf(buf2, "%s/%.*s", _PATH_MAILDIR, sizeof(utmp[0].ut_name), file);
+ file = buf2;
+ }
+ 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;
void
-notify(utp, offset)
+notify(utp, file, offset, folder)
register struct utmp *utp;
+ char file[];
off_t offset;
+ int folder;
{
FILE *tp;
struct stat stb;
- struct sgttyb gttybuf;
+ struct termios tio;
char tty[20], name[sizeof(utmp[0].ut_name) + 1];
(void)snprintf(tty, sizeof(tty), "%s%.*s",
@@ -213,22 +231,24 @@ notify(utp, offset)
dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno));
_exit(-1);
}
- (void)ioctl(fileno(tp), TIOCGETP, &gttybuf);
- cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ?
- "\n" : "\n\r";
+ (void)tcgetattr(fileno(tp), &tio);
+ cr = ((tio.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) ? "\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, (int)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, (int)sizeof(hostname), hostname,
+ folder ? cr : "", folder ? "to " : "", folder ? file : "",
+ cr, cr);
+ jkfprintf(tp, name, file, offset);
(void)fclose(tp);
_exit(0);
}
void
-jkfprintf(tp, name, offset)
+jkfprintf(tp, user, file, offset)
register FILE *tp;
- char name[];
+ char user[];
+ char file[];
off_t offset;
{
register char *cp, ch;
@@ -238,10 +258,10 @@ jkfprintf(tp, name, offset)
char line[BUFSIZ];
/* Set effective uid to user in case mail drop is on nfs */
- if ((p = getpwnam(name)) != NULL)
+ if ((p = getpwnam(user)) != NULL)
(void) setuid(p->pw_uid);
- if ((fi = fopen(name, "r")) == NULL)
+ if ((fi = fopen(file, "r")) == NULL)
return;
(void)fseek(fi, offset, L_SET);
@@ -271,9 +291,18 @@ 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))
+ if (!isprint(ch)) {
+ if (ch & 0x80)
+ (void)fputs("M-", tp);
+ ch &= 0177;
+ if (!isprint(ch)) {
+ if (ch == 0177)
+ ch = '?';
+ else
ch |= 0x40;
+ (void)fputc('^', tp);
+ }
+ }
(void)fputc(ch, tp);
}
(void)fputs(cr, tp);
diff --git a/libexec/fingerd/Makefile b/libexec/fingerd/Makefile
index e2ed65c..4deac64 100644
--- a/libexec/fingerd/Makefile
+++ b/libexec/fingerd/Makefile
@@ -1,6 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
PROG= fingerd
-MAN8= fingerd.0
+MAN8= fingerd.8
.include <bsd.prog.mk>
diff --git a/libexec/fingerd/fingerd.8 b/libexec/fingerd/fingerd.8
index c5c0762..f2a5810 100644
--- a/libexec/fingerd/fingerd.8
+++ b/libexec/fingerd/fingerd.8
@@ -56,7 +56,9 @@ protocol consists mostly of specifying a single
.Dq command line .
.Pp
.Nm Fingerd
-listens for
+is started by
+.Xr inetd 8 ,
+which listens for
.Tn TCP
requests at port 79.
Once connected it reads a single command line
@@ -116,7 +118,8 @@ to have more control over what information is
provided to remote sites.
.El
.Sh SEE ALSO
-.Xr finger 1
+.Xr finger 1 ,
+.Xr inetd 8
.Sh BUGS
Connecting directly to the server from a
.Tn TIP
diff --git a/libexec/fingerd/fingerd.c b/libexec/fingerd/fingerd.c
index 74173a9..93d6f25 100644
--- a/libexec/fingerd/fingerd.c
+++ b/libexec/fingerd/fingerd.c
@@ -38,12 +38,17 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
+/*
static char sccsid[] = "@(#)fingerd.c 8.1 (Berkeley) 6/4/93";
+*/
+static const char rcsid[] =
+ "$Id: fingerd.c,v 1.7 1997/02/22 14:21:25 peter Exp $";
#endif /* not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
@@ -55,7 +60,7 @@ static char sccsid[] = "@(#)fingerd.c 8.1 (Berkeley) 6/4/93";
#include <strings.h>
#include "pathnames.h"
-void err __P((const char *, ...));
+void logerr __P((const char *, ...));
int
main(argc, argv)
@@ -75,7 +80,7 @@ main(argc, argv)
logging = secure = 0;
openlog("fingerd", LOG_PID | LOG_CONS, LOG_DAEMON);
opterr = 0;
- while ((ch = getopt(argc, argv, "slp:")) != EOF)
+ while ((ch = getopt(argc, argv, "slp:")) != -1)
switch (ch) {
case 'l':
logging = 1;
@@ -88,13 +93,13 @@ main(argc, argv)
break;
case '?':
default:
- err("illegal option -- %c", ch);
+ logerr("illegal option -- %c", ch);
}
if (logging) {
sval = sizeof(sin);
if (getpeername(0, (struct sockaddr *)&sin, &sval) < 0)
- err("getpeername: %s", strerror(errno));
+ logerr("getpeername: %s", strerror(errno));
if (hp = gethostbyaddr((char *)&sin.sin_addr.s_addr,
sizeof(sin.sin_addr.s_addr), AF_INET))
lp = hp->h_name;
@@ -103,21 +108,33 @@ main(argc, argv)
syslog(LOG_NOTICE, "query from %s", lp);
}
+ /*
+ * Enable server-side Transaction TCP.
+ */
+ {
+ int one = 1;
+ if (setsockopt(STDOUT_FILENO, IPPROTO_TCP, TCP_NOPUSH, &one,
+ sizeof one) < 0) {
+ logerr("setsockopt(TCP_NOPUSH) failed: %m");
+ }
+ }
+
if (!fgets(line, sizeof(line), stdin))
exit(1);
-
+
comp = &av[1];
- for (lp = line, ap = &av[2];;) {
+ av[2] = "--";
+ for (lp = line, ap = &av[3];;) {
*ap = strtok(lp, " \t\r\n");
if (!*ap) {
- if (secure && ap == &av[2]) {
+ if (secure && ap == &av[3]) {
puts("must provide username\r\n");
exit(1);
}
break;
}
if (secure && strchr(*ap, '@')) {
- puts("fowarding service denied\r\n");
+ puts("forwarding service denied\r\n");
exit(1);
}
@@ -136,7 +153,7 @@ main(argc, argv)
else
*comp = prog;
if (pipe(p) < 0)
- err("pipe: %s", strerror(errno));
+ logerr("pipe: %s", strerror(errno));
switch(vfork()) {
case 0:
@@ -146,14 +163,14 @@ main(argc, argv)
(void)close(p[1]);
}
execv(prog, comp);
- err("execv: %s: %s", prog, strerror(errno));
+ logerr("execv: %s: %s", prog, strerror(errno));
_exit(1);
case -1:
- err("fork: %s", strerror(errno));
+ logerr("fork: %s", strerror(errno));
}
(void)close(p[1]);
if (!(fp = fdopen(p[0], "r")))
- err("fdopen: %s", strerror(errno));
+ logerr("fdopen: %s", strerror(errno));
while ((ch = getc(fp)) != EOF) {
if (ch == '\n')
putchar('\r');
@@ -170,9 +187,9 @@ main(argc, argv)
void
#if __STDC__
-err(const char *fmt, ...)
+logerr(const char *fmt, ...)
#else
-err(fmt, va_alist)
+logerr(fmt, va_alist)
char *fmt;
va_dcl
#endif
diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile
index 946aab7..49e98d5 100644
--- a/libexec/ftpd/Makefile
+++ b/libexec/ftpd/Makefile
@@ -1,9 +1,31 @@
# @(#)Makefile 8.2 (Berkeley) 4/4/94
+# $Id: Makefile,v 1.21 1997/04/26 12:12:10 davidn Exp $
PROG= ftpd
-CFLAGS+=-DSETPROCTITLE
-SRCS= ftpd.c ftpcmd.c logwtmp.c popen.c
-MAN8= ftpd.0
+MAN8= ftpd.8
+SRCS= ftpd.c ftpcmd.c logwtmp.c popen.c skey-stuff.c
+
+CFLAGS+=-DSETPROCTITLE -DSKEY -DLOGIN_CAP -DVIRTUAL_HOSTING -Wall
+
+LDADD= -lskey -lmd -lcrypt -lutil
+DPADD= ${LIBSKEY} ${LIBMD} ${LIBCRYPT} ${LIBUTIL}
+
CLEANFILES+=ftpcmd.c y.tab.h
+.ifdef FTPD_INTERNAL_LS
+LSDIR= ../../bin/ls
+.PATH: ${.CURDIR}/${LSDIR}
+SRCS+= ls.c cmp.c print.c stat_flags.c util.c
+CFLAGS+=-DINTERNAL_LS -Dmain=ls_main -I${.CURDIR}/${LSDIR}
+.endif
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a) && defined(MAKE_EBONES)
+.PATH: ${.CURDIR}/../../usr.bin/login
+SRCS+= klogin.c
+LDADD+= -lkrb -ldes
+DPADD+= ${LIBKRB} ${LIBDES}
+CFLAGS+=-DKERBEROS
+DISTRIBUTION= krb
+.endif
+
.include <bsd.prog.mk>
diff --git a/libexec/ftpd/extern.h b/libexec/ftpd/extern.h
index e3336b5..616da79 100644
--- a/libexec/ftpd/extern.h
+++ b/libexec/ftpd/extern.h
@@ -31,6 +31,7 @@
* SUCH DAMAGE.
*
* @(#)extern.h 8.2 (Berkeley) 4/4/94
+ * $Id: extern.h,v 1.8 1997/02/22 14:21:26 peter Exp $
*/
void blkfree __P((char **));
@@ -56,10 +57,19 @@ char *renamefrom __P((char *));
void reply __P((int, const char *, ...));
void retrieve __P((char *, char *));
void send_file_list __P((char *));
+#ifdef OLD_SETPROCTITLE
void setproctitle __P((const char *, ...));
+#endif
void statcmd __P((void));
void statfilecmd __P((char *));
void store __P((char *, char *, int));
void upper __P((char *));
void user __P((char *));
void yyerror __P((char *));
+int yyparse __P((void));
+#if defined(SKEY) && defined(_PWD_H_) /* XXX evil */
+char *skey_challenge __P((char *, struct passwd *, int));
+#endif
+#if defined(INTERNAL_LS)
+int ls_main __P((int, char **));
+#endif
diff --git a/libexec/ftpd/ftpcmd.y b/libexec/ftpd/ftpcmd.y
index 6ec3d25..659081b 100644
--- a/libexec/ftpd/ftpcmd.y
+++ b/libexec/ftpd/ftpcmd.y
@@ -31,6 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ftpcmd.y 8.3 (Berkeley) 4/6/94
+ * $Id: ftpcmd.y,v 1.10 1997/02/22 14:21:27 peter Exp $
*/
/*
@@ -63,13 +64,15 @@ static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94";
#include <syslog.h>
#include <time.h>
#include <unistd.h>
+#include <libutil.h>
#include "extern.h"
-extern struct sockaddr_in data_dest;
+extern struct sockaddr_in data_dest, his_addr;
extern int logged_in;
extern struct passwd *pw;
extern int guest;
+extern int paranoid;
extern int logging;
extern int type;
extern int form;
@@ -77,7 +80,8 @@ extern int debug;
extern int timeout;
extern int maxtimeout;
extern int pdata;
-extern char hostname[], remotehost[];
+extern char *hostname;
+extern char remotehost[];
extern char proctitle[];
extern int usedefault;
extern int transflag;
@@ -148,18 +152,32 @@ cmd
pass($3);
free($3);
}
- | PORT SP host_port CRLF
- {
- usedefault = 0;
- if (pdata >= 0) {
- (void) close(pdata);
- pdata = -1;
+ | PORT check_login SP host_port CRLF
+ {
+ if ($2) {
+ if (paranoid &&
+ ((ntohs(data_dest.sin_port) <
+ IPPORT_RESERVED) ||
+ memcmp(&data_dest.sin_addr,
+ &his_addr.sin_addr,
+ sizeof(data_dest.sin_addr)))) {
+ usedefault = 1;
+ reply(500,
+ "Illegal PORT range rejected.");
+ } else {
+ usedefault = 0;
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+ reply(200, "PORT command successful.");
+ }
}
- reply(200, "PORT command successful.");
}
- | PASV CRLF
+ | PASV check_login CRLF
{
- passive();
+ if ($2)
+ passive();
}
| TYPE SP type_code CRLF
{
@@ -291,16 +309,18 @@ cmd
if ($4 != NULL)
free($4);
}
- | RNTO SP pathname CRLF
+ | RNTO check_login SP pathname CRLF
{
- if (fromname) {
- renamecmd(fromname, $3);
- free(fromname);
- fromname = (char *) 0;
- } else {
- reply(503, "Bad sequence of commands.");
+ if ($2) {
+ if (fromname) {
+ renamecmd(fromname, $4);
+ free(fromname);
+ fromname = (char *) 0;
+ } else {
+ reply(503, "Bad sequence of commands.");
+ }
}
- free($3);
+ free($4);
}
| ABOR CRLF
{
@@ -490,8 +510,9 @@ cmd
struct tm *t;
t = gmtime(&stbuf.st_mtime);
reply(213,
- "19%02d%02d%02d%02d%02d%02d",
- t->tm_year, t->tm_mon+1, t->tm_mday,
+ "%04d%02d%02d%02d%02d%02d",
+ 1900 + t->tm_year,
+ t->tm_mon+1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
}
}
@@ -552,11 +573,12 @@ host_port
{
char *a, *p;
- a = (char *)&data_dest.sin_addr;
- a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
+ data_dest.sin_len = sizeof(struct sockaddr_in);
+ data_dest.sin_family = AF_INET;
p = (char *)&data_dest.sin_port;
p[0] = $9; p[1] = $11;
- data_dest.sin_family = AF_INET;
+ a = (char *)&data_dest.sin_addr;
+ a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
}
;
@@ -976,7 +998,7 @@ yylex()
upper(cp);
p = lookup(sitetab, cp);
cbuf[cpos] = c;
- if (p != 0) {
+ if (guest == 0 && p != 0) {
if (p->implemented == 0) {
state = CMD;
nack(p->name);
diff --git a/libexec/ftpd/ftpd.8 b/libexec/ftpd/ftpd.8
index eb93c38..b3fa6bd 100644
--- a/libexec/ftpd/ftpd.8
+++ b/libexec/ftpd/ftpd.8
@@ -29,9 +29,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)ftpd.8 8.3 (Berkeley) 6/1/94
+.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
+.\" $Id: ftpd.8,v 1.17 1997/04/27 08:29:21 davidn Exp $
.\"
-.Dd June 1, 1994
+.Dd April 19, 1994
.Dt FTPD 8
.Os BSD 4.2
.Sh NAME
@@ -41,8 +42,14 @@ Internet File Transfer Protocol server
.Sh SYNOPSIS
.Nm ftpd
.Op Fl dl
+.Op Fl D
+.Op Fl R
+.Op Fl S
+.Op Fl U
.Op Fl T Ar maxtimeout
.Op Fl t Ar timeout
+.Op Fl a Ar address
+.Op Fl p Ar file
.Sh DESCRIPTION
.Nm Ftpd
is the
@@ -65,7 +72,47 @@ Each successful and failed
session is logged using syslog with a facility of LOG_FTP.
If this option is specified twice, the retrieve (get), store (put), append,
delete, make directory, remove directory and rename operations and
-their filename arguments are also logged.
+their filename arguments are also logged. Note: LOG_FTP messages
+are not displayed by
+.Xr syslogd 8
+by default, and may have to be enabled in
+.Xr syslogd 8 Ns 's
+configuration file.
+.It Fl D
+With this option set,
+.Nm ftpd
+will detach and become a daemon, accepting connections on the FTP port and
+forking children processes to handle them. This is lower overhead than
+starting
+.Nm ftpd
+from
+.Xr inetd 8
+and is thus useful on busy servers to reduce load.
+.It Fl R
+With this option set,
+.Nm ftpd
+will revert to historical behavior with regard to security checks on
+user operations and restrictions on PORT requests.
+Currently,
+.Nm ftpd
+will only honor PORT commands directed to unprivileged ports on the
+remote user's host (which violates the FTP protocol specification but
+closes some security holes).
+.
+.It Fl S
+With this option set,
+.Nm ftpd
+logs all anonymous transfers to the file
+.Pa /var/log/ftpd
+when this file exists.
+.
+.It Fl U
+In previous versions of
+.Nm ftpd ,
+when a passive mode client requested a data connection to the server,
+the server would use data ports in the range 1024..4999. Now, by default,
+the server will use data ports in the range 40000..44999. Specifying this
+option will revert to the old behavior.
.It Fl T
A client may also request a different timeout period;
the maximum period allowed may be set to
@@ -78,6 +125,18 @@ The default limit is 2 hours.
The inactivity timeout period is set to
.Ar timeout
seconds (the default is 15 minutes).
+.It Fl a
+When
+.Fl D
+is specified, accept connections only on the specified
+.Ar address .
+.It Fl p
+When
+.Fl D
+is specified, write the daemon's process ID to
+.Ar file .
+.It Fl A
+Allow only anonymous ftp access
.El
.Pp
The file
@@ -94,7 +153,7 @@ prints it before issuing the
.Dq ready
message.
If the file
-.Pa /etc/motd
+.Pa /etc/ftpmotd
exists,
.Nm
prints it after a successful login.
@@ -182,22 +241,55 @@ This allows users to utilize the metacharacters
.Dq Li \&*?[]{}~ .
.Pp
.Nm Ftpd
-authenticates users according to three rules.
+authenticates users according to five rules.
.Pp
.Bl -enum -offset indent
.It
-The login name must be in the password data base,
-.Pa /etc/passwd ,
+The login name must be in the password data base
and not have a null password.
In this case a password must be provided by the client before any
file operations may be performed.
+If the user has an S/Key key, the response from a successful USER
+command will include an S/Key challenge. The client may choose to respond
+with a PASS command giving either a standard password or an S/Key
+one-time password. The server will automatically determine which type of
+password it has been given and attempt to authenticate accordingly. See
+.Xr key 1
+for more information on S/Key authentication. S/Key is a Trademark of
+Bellcore.
.It
The login name must not appear in the file
.Pa /etc/ftpusers .
.It
+The login name must not be a member of a group specified in the file
+.Pa /etc/ftpusers .
+Entries in this file interpreted as group names are prefixed by an "at"
+.Ql \&@
+sign.
+.It
The user must have a standard shell returned by
.Xr getusershell 3 .
.It
+If the user name appears in the file
+.Pa /etc/ftpchroot ,
+or the user is a member of a group with a group entry in this file,
+i.e. one prefixed with
+.Ql \&@ ,
+the session's root will be changed to the user's login directory by
+.Xr chroot 2
+as for an
+.Dq anonymous
+or
+.Dq ftp
+account (see next item).
+This facility may also be triggered by enabling the boolean "ftp-chroot"
+capability in
+.Xr login.conf 5 .
+However, the user must still supply a password.
+This feature is intended as a compromise between a fully anonymous
+account and a fully privileged account.
+The account should also be set up as for an anonymous account.
+.It
If the user name is
.Dq anonymous
or
@@ -209,6 +301,9 @@ file (user
In this case the user is allowed
to log in by specifying any password (by convention an email address for
the user should be used as the password).
+When the
+.Fl S
+option is set, all transfers are logged as well.
.El
.Pp
In the last case,
@@ -228,7 +323,6 @@ subtree be constructed with care, following these rules:
Make the home directory owned by
.Dq root
and unwritable by anyone.
-.ne 1i
.It Pa ~ftp/bin
Make this directory owned by
.Dq root
@@ -241,8 +335,8 @@ This program should be mode 111.
Make this directory owned by
.Dq root
and unwritable by anyone (mode 555).
-The files
-.Xr passwd 5
+The files pwd.db (see
+.Xr passwd 5 )
and
.Xr group 5
must be present for the
@@ -252,7 +346,7 @@ The password field in
.Xr passwd
is not used, and should not contain real passwords.
The file
-.Pa motd ,
+.Pa ftpmotd ,
if present, will be printed after a successful login.
These files should be mode 444.
.It Pa ~ftp/pub
@@ -262,20 +356,91 @@ Guests
can then place files which are to be accessible via the anonymous
account in this directory.
.El
+.Pp
+If the system has multiple IP addresses,
+.Nm ftpd
+supports the idea of virtual hosts, which provides the ability to
+define multiple anonymous ftp areas, each one allocated to a different
+internet address.
+The file
+.Pa /etc/ftphosts
+contains information pertaining to each of the virtual hosts.
+Each host is defined on its own line which contains a number of
+fields separated by whitespace:
+.Bl -tag -offset indent -width hostname
+.It hostname
+Contains the hostname or IP address of the virtual host.
+.It user
+Contains a user record in the system password file.
+As with normal anonymous ftp, this user's access uid, gid and group
+memberships determine file access to the anonymous ftp area.
+The anonymous ftp area (to which any user is chrooted on login)
+is determined by the home directory defined for the account.
+User id and group for any ftp account may be the same as for the
+standard ftp user.
+.It statfile
+File to which all file transfers are logged, which
+defaults to
+.Pa /var/log/ftpd .
+.It welcome
+This file is the welcome message displayed before the server ready
+prompt.
+It defaults to
+.Pa /etc/ftpwelcome .
+.It motd
+This file is displayed after the user logs in.
+It defaults to
+.Pa /etc/ftpmotd .
+.El
+.Pp
+Defining a virtual host for the primary IP address or hostname
+changes the default for ftp logins to that address.
+The 'user', 'statfile', 'welcome' and 'motd' fields may be left
+blank, or a single hypen '-' used to indicate that the default
+value is to be used.
+.Pp
+As with any anonymous login configuration, due care must be given
+to setup and maintenance to guard against security related problems.
+.Pp
+If compiled with the
+.Em INTERNAL_LS
+option,
+.Nm ftpd
+will have internal support for handling remote requests to list
+files, and will not execute
+.Pa /bin/ls
+in either a chrooted or non-chrooted environment.
+In this case, the
+.Pa ~/bin/ls
+executable need not be placed into the chrooted tree, nor need the
+.Pa ~/bin
+directory exist.
+This support may be added by making ftpd with the
+.Em FTP_INTERNAL_LS
+variable set either in
+.Pa /etc/make.conf
+or in the shell's environment.
.Sh FILES
.Bl -tag -width /etc/ftpwelcome -compact
.It Pa /etc/ftpusers
List of unwelcome/restricted users.
+.It Pa /etc/ftpchroot
+List of normal users who should be chroot'd.
.It Pa /etc/ftpwelcome
Welcome notice.
-.It Pa /etc/motd
+.It Pa /etc/ftpmotd
Welcome notice after login.
.It Pa /etc/nologin
Displayed and access refused.
+.It Pa /var/log/ftpd
+Log file for anonymous transfers.
.El
.Sh SEE ALSO
.Xr ftp 1 ,
+.Xr key 1 ,
.Xr getusershell 3 ,
+.Xr login.conf 5 ,
+.Xr inetd 8 ,
.Xr syslogd 8
.Sh BUGS
The server must run as the super-user
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index 875ec62..37407a3 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -29,17 +29,23 @@
* 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: ftpd.c,v 1.40 1997/05/21 23:24:41 danny Exp $
*/
+#if 0
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
+#endif
+#if 0
#ifndef lint
-static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)ftpd.c 8.4 (Berkeley) 4/16/94";
#endif /* not lint */
+#endif
/*
* FTP server.
@@ -49,10 +55,12 @@ static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/mman.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
+#include <netinet/tcp.h>
#define FTP_NAMES
#include <arpa/ftp.h>
@@ -68,6 +76,7 @@ static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
#include <limits.h>
#include <netdb.h>
#include <pwd.h>
+#include <grp.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
@@ -76,6 +85,14 @@ static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
#include <syslog.h>
#include <time.h>
#include <unistd.h>
+#include <libutil.h>
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#endif
+
+#ifdef SKEY
+#include <skey.h>
+#endif
#include "pathnames.h"
#include "extern.h"
@@ -86,17 +103,24 @@ static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
#include <varargs.h>
#endif
+#ifdef INTERNAL_LS
+static char version[] = "Version 6.00LS";
+#undef main
+#else
static char version[] = "Version 6.00";
+#endif
extern off_t restart_point;
extern char cbuf[];
+struct sockaddr_in server_addr;
struct sockaddr_in ctrl_addr;
struct sockaddr_in data_source;
struct sockaddr_in data_dest;
struct sockaddr_in his_addr;
struct sockaddr_in pasv_addr;
+int daemon_mode;
int data;
jmp_buf errcatch, urgcatch;
int logged_in;
@@ -105,7 +129,13 @@ int debug;
int timeout = 900; /* timeout after 15 minutes of inactivity */
int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
int logging;
+int restricted_data_ports = 1;
+int paranoid = 1; /* be extra careful about security */
+int anon_only = 0; /* Only anonymous ftp allowed */
int guest;
+int dochroot;
+int stats;
+int statfd = -1;
int type;
int form;
int stru; /* avoid C keyword */
@@ -121,8 +151,39 @@ off_t byte_count;
#endif
int defumask = CMASK; /* default umask value */
char tmpline[7];
-char hostname[MAXHOSTNAMELEN];
+char *hostname;
+#ifdef VIRTUAL_HOSTING
+char *ftpuser;
+
+static struct ftphost {
+ struct ftphost *next;
+ struct in_addr hostaddr;
+ char *hostname;
+ char *anonuser;
+ char *statfile;
+ char *welcome;
+ char *loginmsg;
+} *thishost, *firsthost;
+
+#endif
char remotehost[MAXHOSTNAMELEN];
+char *ident = NULL;
+
+static char ttyline[20];
+char *tty = ttyline; /* for klogin */
+
+#ifdef KERBEROS
+int klogin __P((struct passwd *, char *, char *, char *));
+#endif
+
+struct in_addr bind_address;
+char *pid_file = NULL;
+
+#if defined(KERBEROS)
+int notickets = 1;
+int noticketsdontcomplain = 1;
+char *krbtkfile_env = NULL;
+#endif
/*
* Timeout intervals for retrying connections
@@ -136,11 +197,18 @@ int swaitmax = SWAITMAX;
int swaitint = SWAITINT;
#ifdef SETPROCTITLE
+#ifdef OLD_SETPROCTITLE
char **Argv = NULL; /* pointer to argument vector */
char *LastArgv = NULL; /* end of argv */
+#endif /* OLD_SETPROCTITLE */
char proctitle[LINE_MAX]; /* initial part of title */
#endif /* SETPROCTITLE */
+#ifdef SKEY
+int pwok = 0;
+char addr_string[20]; /* XXX */
+#endif
+
#define LOGCMD(cmd, file) \
if (logging > 1) \
syslog(LOG_INFO,"%s %s%s", cmd, \
@@ -160,9 +228,13 @@ char proctitle[LINE_MAX]; /* initial part of title */
cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
}
+#ifdef VIRTUAL_HOSTING
+static void inithosts __P((void));
+static void selecthost __P((struct in_addr *));
+#endif
static void ack __P((char *));
static void myoob __P((int));
-static int checkuser __P((char *));
+static int checkuser __P((char *, char *));
static FILE *dataconn __P((char *, off_t, char *));
static void dolog __P((struct sockaddr_in *));
static char *curdir __P((void));
@@ -171,10 +243,12 @@ static FILE *getdatasock __P((char *));
static char *gunique __P((char *));
static void lostconn __P((int));
static int receive_data __P((FILE *, FILE *));
-static void send_data __P((FILE *, FILE *, off_t));
+static void send_data __P((FILE *, FILE *, off_t, off_t, int));
static struct passwd *
sgetpwnam __P((char *));
static char *sgetsave __P((char *));
+static void reapchild __P((int));
+static void logxfer __P((char *, long, long));
static char *
curdir()
@@ -199,29 +273,9 @@ main(argc, argv, envp)
char *cp, line[LINE_MAX];
FILE *fd;
- /*
- * LOG_NDELAY sets up the logging connection immediately,
- * necessary for anonymous ftp's that chroot and can't do it later.
- */
- openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
- addrlen = sizeof(his_addr);
- if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
- syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
- exit(1);
- }
- addrlen = sizeof(ctrl_addr);
- if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
- syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
- exit(1);
- }
-#ifdef IP_TOS
- tos = IPTOS_LOWDELAY;
- if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
- syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
-#endif
- data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
- debug = 0;
-#ifdef SETPROCTITLE
+ tzset(); /* in case no timezone database in ~ftp */
+
+#ifdef OLD_SETPROCTITLE
/*
* Save start and extent of argv for setproctitle.
*/
@@ -229,22 +283,30 @@ main(argc, argv, envp)
while (*envp)
envp++;
LastArgv = envp[-1] + strlen(envp[-1]);
-#endif /* SETPROCTITLE */
+#endif /* OLD_SETPROCTITLE */
+
- while ((ch = getopt(argc, argv, "dlt:T:u:v")) != EOF) {
+ bind_address.s_addr = htonl(INADDR_ANY);
+ while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:")) != -1) {
switch (ch) {
+ case 'D':
+ daemon_mode++;
+ break;
+
case 'd':
- debug = 1;
+ debug++;
break;
case 'l':
logging++; /* > 1 == extra logging */
break;
- case 't':
- timeout = atoi(optarg);
- if (maxtimeout < timeout)
- maxtimeout = timeout;
+ case 'R':
+ paranoid = 0;
+ break;
+
+ case 'S':
+ stats++;
break;
case 'T':
@@ -253,6 +315,25 @@ main(argc, argv, envp)
timeout = maxtimeout;
break;
+ case 't':
+ timeout = atoi(optarg);
+ if (maxtimeout < timeout)
+ maxtimeout = timeout;
+ break;
+
+ case 'U':
+ restricted_data_ports = 0;
+ break;
+
+ case 'a':
+ if (!inet_aton(optarg, &bind_address))
+ errx(1, "invalid address for -a");
+ break;
+
+ case 'p':
+ pid_file = optarg;
+ break;
+
case 'u':
{
long val = 0;
@@ -264,6 +345,9 @@ main(argc, argv, envp)
defumask = val;
break;
}
+ case 'A':
+ anon_only = 1;
+ break;
case 'v':
debug = 1;
@@ -274,12 +358,133 @@ main(argc, argv, envp)
break;
}
}
+
+#ifdef VIRTUAL_HOSTING
+ inithosts();
+#endif
(void) freopen(_PATH_DEVNULL, "w", stderr);
- (void) signal(SIGPIPE, lostconn);
+
+ /*
+ * LOG_NDELAY sets up the logging connection immediately,
+ * necessary for anonymous ftp's that chroot and can't do it later.
+ */
+ openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
+
+ if (daemon_mode) {
+ int ctl_sock, fd;
+ struct servent *sv;
+
+ /*
+ * Detach from parent.
+ */
+ if (daemon(1, 1) < 0) {
+ syslog(LOG_ERR, "failed to become a daemon");
+ exit(1);
+ }
+ (void) signal(SIGCHLD, reapchild);
+ /*
+ * Get port number for ftp/tcp.
+ */
+ sv = getservbyname("ftp", "tcp");
+ if (sv == NULL) {
+ syslog(LOG_ERR, "getservbyname for ftp failed");
+ exit(1);
+ }
+ /*
+ * Open a socket, bind it to the FTP port, and start
+ * listening.
+ */
+ ctl_sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (ctl_sock < 0) {
+ syslog(LOG_ERR, "control socket: %m");
+ exit(1);
+ }
+ if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "control setsockopt: %m");;
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_addr = bind_address;
+ server_addr.sin_port = sv->s_port;
+ if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
+ syslog(LOG_ERR, "control bind: %m");
+ exit(1);
+ }
+ if (listen(ctl_sock, 32) < 0) {
+ syslog(LOG_ERR, "control listen: %m");
+ exit(1);
+ }
+ /*
+ * Atomically write process ID
+ */
+ if (pid_file)
+ {
+ int fd;
+ char buf[20];
+
+ fd = open(pid_file, O_CREAT | O_WRONLY | O_TRUNC
+ | O_NONBLOCK | O_EXLOCK, 0644);
+ if (fd < 0)
+ if (errno == EAGAIN)
+ errx(1, "%s: file locked", pid_file);
+ else
+ err(1, "%s", pid_file);
+ snprintf(buf, sizeof(buf),
+ "%lu\n", (unsigned long) getpid());
+ if (write(fd, buf, strlen(buf)) < 0)
+ err(1, "%s: write", pid_file);
+ /* Leave the pid file open and locked */
+ }
+ /*
+ * Loop forever accepting connection requests and forking off
+ * children to handle them.
+ */
+ while (1) {
+ addrlen = sizeof(his_addr);
+ fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen);
+ if (fork() == 0) {
+ /* child */
+ (void) dup2(fd, 0);
+ (void) dup2(fd, 1);
+ close(ctl_sock);
+ break;
+ }
+ close(fd);
+ }
+ } else {
+ addrlen = sizeof(his_addr);
+ if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
+ syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
+ exit(1);
+ }
+ }
+
(void) signal(SIGCHLD, SIG_IGN);
+ (void) signal(SIGPIPE, lostconn);
if ((int)signal(SIGURG, myoob) < 0)
syslog(LOG_ERR, "signal: %m");
+#ifdef SKEY
+ strncpy(addr_string, inet_ntoa(his_addr.sin_addr), sizeof(addr_string));
+#endif
+ addrlen = sizeof(ctrl_addr);
+ if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
+ syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
+ exit(1);
+ }
+#ifdef VIRTUAL_HOSTING
+ /* select our identity from virtual host table */
+ selecthost(&ctrl_addr.sin_addr);
+#endif
+#ifdef IP_TOS
+ tos = IPTOS_LOWDELAY;
+ if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
+ syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+#endif
+ data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
+
+ /* set this here so klogin can use it... */
+ (void)sprintf(ttyline, "ftp%d", getpid());
+
/* Try to handle urgent data inline */
#ifdef SO_OOBINLINE
if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
@@ -313,7 +518,11 @@ main(argc, argv, envp)
reply(530, "System not available.");
exit(0);
}
+#ifdef VIRTUAL_HOSTING
+ if ((fd = fopen(thishost->welcome, "r")) != NULL) {
+#else
if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
+#endif
while (fgets(line, sizeof(line), fd) != NULL) {
if ((cp = strchr(line, '\n')) != NULL)
*cp = '\0';
@@ -323,7 +532,11 @@ main(argc, argv, envp)
(void) fclose(fd);
/* reply(220,) must follow */
}
- (void) gethostname(hostname, sizeof(hostname));
+#ifndef VIRTUAL_HOSTING
+ if ((hostname = malloc(MAXHOSTNAMELEN)) == NULL)
+ fatal("Ran out of memory.");
+ (void) gethostname(hostname, MAXHOSTNAMELEN);
+#endif
reply(220, "%s FTP server (%s) ready.", hostname, version);
(void) setjmp(errcatch);
for (;;)
@@ -341,7 +554,146 @@ lostconn(signo)
dologout(-1);
}
-static char ttyline[20];
+#ifdef VIRTUAL_HOSTING
+/*
+ * read in virtual host tables (if they exist)
+ */
+
+static void
+inithosts()
+{
+ FILE *fp;
+ char *cp;
+ struct hostent *hp;
+ struct ftphost *hrp, *lhrp;
+ char line[1024];
+
+ /*
+ * Fill in the default host information
+ */
+ if (gethostname(line, sizeof(line)) < 0)
+ line[0] = '\0';
+ if ((hrp = malloc(sizeof(struct ftphost))) == NULL ||
+ (hrp->hostname = strdup(line)) == NULL)
+ fatal("Ran out of memory.");
+ memset(&hrp->hostaddr, 0, sizeof hrp->hostaddr);
+ if ((hp = gethostbyname(hrp->hostname)) != NULL)
+ (void) memcpy(&hrp->hostaddr,
+ hp->h_addr_list[0],
+ sizeof(hrp->hostaddr));
+ hrp->statfile = _PATH_FTPDSTATFILE;
+ hrp->welcome = _PATH_FTPWELCOME;
+ hrp->loginmsg = _PATH_FTPLOGINMESG;
+ hrp->anonuser = "ftp";
+ hrp->next = NULL;
+ thishost = firsthost = lhrp = hrp;
+ if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) {
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ int i;
+
+ if ((cp = strchr(line, '\n')) == NULL) {
+ /* ignore long lines */
+ while (fgets(line, sizeof(line), fp) != NULL &&
+ strchr(line, '\n') == NULL)
+ ;
+ continue;
+ }
+ *cp = '\0';
+ cp = strtok(line, " \t");
+ /* skip comments and empty lines */
+ if (cp == NULL || line[0] == '#')
+ continue;
+ /* first, try a standard gethostbyname() */
+ if ((hp = gethostbyname(cp)) == NULL)
+ continue;
+ for (hrp = firsthost; hrp != NULL; hrp = hrp->next) {
+ if (memcmp(&hrp->hostaddr,
+ hp->h_addr_list[0],
+ sizeof(hrp->hostaddr)) == 0)
+ break;
+ }
+ if (hrp == NULL) {
+ if ((hrp = malloc(sizeof(struct ftphost))) == NULL)
+ continue;
+ /* defaults */
+ hrp->statfile = _PATH_FTPDSTATFILE;
+ hrp->welcome = _PATH_FTPWELCOME;
+ hrp->loginmsg = _PATH_FTPLOGINMESG;
+ hrp->anonuser = "ftp";
+ hrp->next = NULL;
+ lhrp->next = hrp;
+ lhrp = hrp;
+ }
+ (void) memcpy(&hrp->hostaddr,
+ hp->h_addr_list[0],
+ sizeof(hrp->hostaddr));
+ /*
+ * determine hostname to use.
+ * force defined name if it is a valid alias
+ * otherwise fallback to primary hostname
+ */
+ if ((hp = gethostbyaddr((char*)&hrp->hostaddr,
+ sizeof(hrp->hostaddr),
+ AF_INET)) != NULL) {
+ if (strcmp(cp, hp->h_name) != 0) {
+ if (hp->h_aliases == NULL)
+ cp = hp->h_name;
+ else {
+ i = 0;
+ while (hp->h_aliases[i] &&
+ strcmp(cp, hp->h_aliases[i]) != 0)
+ ++i;
+ if (hp->h_aliases[i] == NULL)
+ cp = hp->h_name;
+ }
+ }
+ }
+ hrp->hostname = strdup(cp);
+ /* ok, now we now peel off the rest */
+ i = 0;
+ while (i < 4 && (cp = strtok(NULL, " \t")) != NULL) {
+ if (*cp != '-' && (cp = strdup(cp)) != NULL) {
+ switch (i) {
+ case 0: /* anon user permissions */
+ hrp->anonuser = cp;
+ break;
+ case 1: /* statistics file */
+ hrp->statfile = cp;
+ break;
+ case 2: /* welcome message */
+ hrp->welcome = cp;
+ break;
+ case 3: /* login message */
+ hrp->loginmsg = cp;
+ break;
+ }
+ }
+ ++i;
+ }
+ }
+ (void) fclose(fp);
+ }
+}
+
+static void
+selecthost(a)
+ struct in_addr *a;
+{
+ struct ftphost *hrp;
+
+ hrp = thishost = firsthost; /* default */
+ while (hrp != NULL) {
+ if (memcmp(a, &hrp->hostaddr, sizeof(hrp->hostaddr)) == 0) {
+ thishost = hrp;
+ break;
+ }
+ hrp = hrp->next;
+ }
+ /* setup static variables as appropriate */
+ hostname = thishost->hostname;
+ ftpuser = thishost->anonuser;
+}
+#endif
/*
* Helper function for sgetpwnam().
@@ -416,19 +768,27 @@ user(name)
if (guest) {
reply(530, "Can't change user from guest login.");
return;
+ } else if (dochroot) {
+ reply(530, "Can't change user from chroot user.");
+ return;
}
end_login();
}
guest = 0;
if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
- if (checkuser("ftp") || checkuser("anonymous"))
+ if (checkuser(_PATH_FTPUSERS, "ftp") ||
+ checkuser(_PATH_FTPUSERS, "anonymous"))
reply(530, "User %s access denied.", name);
+#ifdef VIRTUAL_HOSTING
+ else if ((pw = sgetpwnam(thishost->anonuser)) != NULL) {
+#else
else if ((pw = sgetpwnam("ftp")) != NULL) {
+#endif
guest = 1;
askpasswd = 1;
reply(331,
- "Guest login ok, type your name as password.");
+ "Guest login ok, send your email address as password.");
} else
reply(530, "User %s unknown.", name);
if (!askpasswd && logging)
@@ -436,7 +796,12 @@ user(name)
"ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
return;
}
- if (pw = sgetpwnam(name)) {
+ if (anon_only != 0) {
+ reply(530, "Sorry, only anonymous ftp allowed.");
+ return;
+ }
+
+ if ((pw = sgetpwnam(name))) {
if ((shell = pw->pw_shell) == NULL || *shell == 0)
shell = _PATH_BSHELL;
while ((cp = getusershell()) != NULL)
@@ -444,7 +809,7 @@ user(name)
break;
endusershell();
- if (cp == NULL || checkuser(name)) {
+ if (cp == NULL || checkuser(_PATH_FTPUSERS, name)) {
reply(530, "User %s access denied.", name);
if (logging)
syslog(LOG_NOTICE,
@@ -456,7 +821,12 @@ user(name)
}
if (logging)
strncpy(curname, name, sizeof(curname)-1);
+#ifdef SKEY
+ pwok = skeyaccess(name, NULL, remotehost, addr_string);
+ reply(331, "%s", skey_challenge(name, pw, pwok));
+#else
reply(331, "Password required for %s.", name);
+#endif
askpasswd = 1;
/*
* Delay before reading passwd after first failed
@@ -467,26 +837,42 @@ user(name)
}
/*
- * Check if a user is in the file _PATH_FTPUSERS
+ * Check if a user is in the file "fname"
*/
static int
-checkuser(name)
+checkuser(fname, name)
+ char *fname;
char *name;
{
FILE *fd;
int found = 0;
char *p, line[BUFSIZ];
- if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
- while (fgets(line, sizeof(line), fd) != NULL)
+ if ((fd = fopen(fname, "r")) != NULL) {
+ while (!found && fgets(line, sizeof(line), fd) != NULL)
if ((p = strchr(line, '\n')) != NULL) {
*p = '\0';
if (line[0] == '#')
continue;
- if (strcmp(line, name) == 0) {
- found = 1;
- break;
+ /*
+ * if first chr is '@', check group membership
+ */
+ if (line[0] == '@') {
+ int i = 0;
+ struct group *grp;
+
+ if ((grp = getgrnam(line+1)) == NULL)
+ continue;
+ while (!found && grp->gr_mem[i])
+ found = strcmp(name,
+ grp->gr_mem[i++])
+ == 0;
}
+ /*
+ * Otherwise, just check for username match
+ */
+ else
+ found = strcmp(line, name) == 0;
}
(void) fclose(fd);
}
@@ -505,16 +891,25 @@ end_login()
if (logged_in)
logwtmp(ttyline, "", "");
pw = NULL;
+#ifdef LOGIN_CAP
+ setusercontext(NULL, getpwuid(0), (uid_t)0,
+ LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
+#endif
logged_in = 0;
guest = 0;
+ dochroot = 0;
}
void
pass(passwd)
char *passwd;
{
- char *salt, *xpasswd;
+ int rval;
FILE *fd;
+#ifdef LOGIN_CAP
+ login_cap_t *lc = NULL;
+#endif
+ static char homedir[MAXPATHLEN];
if (logged_in || askpasswd == 0) {
reply(503, "Login with USER first.");
@@ -522,14 +917,33 @@ pass(passwd)
}
askpasswd = 0;
if (!guest) { /* "ftp" is only account allowed no password */
- if (pw == NULL)
- salt = "xx";
- else
- salt = pw->pw_passwd;
- xpasswd = crypt(passwd, salt);
+ if (pw == NULL) {
+ rval = 1; /* failure below */
+ goto skip;
+ }
+#if defined(KERBEROS)
+ rval = klogin(pw, "", hostname, passwd);
+ if (rval == 0)
+ goto skip;
+#endif
+#ifdef SKEY
+ rval = strcmp(skey_crypt(passwd, pw->pw_passwd, pw, pwok),
+ pw->pw_passwd);
+ pwok = 0;
+#else
+ rval = strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd);
+#endif
/* The strcmp does not catch null passwords! */
- if (pw == NULL || *pw->pw_passwd == '\0' ||
- strcmp(xpasswd, pw->pw_passwd)) {
+ if (*pw->pw_passwd == '\0' ||
+ (pw->pw_expire && time(NULL) >= pw->pw_expire))
+ rval = 1; /* failure */
+skip:
+ /*
+ * If rval == 1, the user failed the authentication check
+ * above. If rval == 0, either Kerberos or local authentication
+ * succeeded.
+ */
+ if (rval) {
reply(530, "Login incorrect.");
if (logging)
syslog(LOG_NOTICE,
@@ -550,13 +964,52 @@ pass(passwd)
reply(550, "Can't set gid.");
return;
}
+ /* May be overridden by login.conf */
+ (void) umask(defumask);
+#ifdef LOGIN_CAP
+ if ((lc = login_getpwclass(pw)) != NULL) {
+ char remote_ip[MAXHOSTNAMELEN];
+
+ strncpy(remote_ip, inet_ntoa(his_addr.sin_addr),
+ sizeof(remote_ip) - 1);
+ remote_ip[sizeof(remote_ip) - 1] = 0;
+ if (!auth_hostok(lc, remotehost, remote_ip)) {
+ syslog(LOG_INFO|LOG_AUTH,
+ "FTP LOGIN FAILED (HOST) as %s: permission denied.",
+ pw->pw_name);
+ reply(530, "Permission denied.\n");
+ pw = NULL;
+ return;
+ }
+ if (!auth_timeok(lc, time(NULL))) {
+ reply(530, "Login not available right now.\n");
+ pw = NULL;
+ return;
+ }
+ }
+ setusercontext(lc, pw, (uid_t)0,
+ LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
+#else
(void) initgroups(pw->pw_name, pw->pw_gid);
+#endif
/* open wtmp before chroot */
- (void)sprintf(ttyline, "ftp%d", getpid());
logwtmp(ttyline, pw->pw_name, remotehost);
logged_in = 1;
+ if (guest && stats && statfd < 0)
+#ifdef VIRTUAL_HOSTING
+ if ((statfd = open(thishost->statfile, O_WRONLY|O_APPEND)) < 0)
+#else
+ if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
+#endif
+ stats = 0;
+
+ dochroot =
+#ifdef LOGIN_CAP /* Allow login.conf configuration as well */
+ login_getcapbool(lc, "ftp-chroot", 0) ||
+#endif
+ checkuser(_PATH_FTPCHROOT, pw->pw_name);
if (guest) {
/*
* We MUST do a chdir() after the chroot. Otherwise
@@ -567,6 +1020,11 @@ pass(passwd)
reply(550, "Can't set guest privileges.");
goto bad;
}
+ } else if (dochroot) {
+ if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
+ reply(550, "Can't change root.");
+ goto bad;
+ }
} else if (chdir(pw->pw_dir) < 0) {
if (chdir("/") < 0) {
reply(530, "User %s: can't change directory to %s.",
@@ -579,11 +1037,22 @@ pass(passwd)
reply(550, "Can't set uid.");
goto bad;
}
+
+ /*
+ * Set home directory so that use of ~ (tilde) works correctly.
+ */
+ if (getcwd(homedir, MAXPATHLEN) != NULL)
+ setenv("HOME", homedir, 1);
+
/*
* Display a login message, if it exists.
* N.B. reply(230,) must follow the message.
*/
+#ifdef VIRTUAL_HOSTING
+ if ((fd = fopen(thishost->loginmsg, "r")) != NULL) {
+#else
if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
+#endif
char *cp, line[LINE_MAX];
while (fgets(line, sizeof(line), fd) != NULL) {
@@ -595,32 +1064,56 @@ pass(passwd)
(void) fclose(fd);
}
if (guest) {
+ if (ident != NULL)
+ free(ident);
+ ident = strdup(passwd);
+ if (ident == NULL)
+ fatal("Ran out of memory.");
+
reply(230, "Guest login ok, access restrictions apply.");
#ifdef SETPROCTITLE
- snprintf(proctitle, sizeof(proctitle),
- "%s: anonymous/%.*s", remotehost,
- sizeof(proctitle) - sizeof(remotehost) -
- sizeof(": anonymous/"), passwd);
- setproctitle(proctitle);
+#ifdef VIRTUAL_HOSTING
+ if (thishost != firsthost)
+ snprintf(proctitle, sizeof(proctitle),
+ "%s: anonymous(%s)/%.*s", remotehost, hostname,
+ sizeof(proctitle) - sizeof(remotehost) -
+ sizeof(": anonymous/"), passwd);
+ else
+#endif
+ snprintf(proctitle, sizeof(proctitle),
+ "%s: anonymous/%.*s", remotehost,
+ sizeof(proctitle) - sizeof(remotehost) -
+ sizeof(": anonymous/"), passwd);
+ setproctitle("%s", proctitle);
#endif /* SETPROCTITLE */
if (logging)
syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
remotehost, passwd);
} else {
+ if (dochroot)
+ reply(230, "User %s logged in, access restrictions apply.",
+ pw->pw_name);
+ else
reply(230, "User %s logged in.", pw->pw_name);
+
#ifdef SETPROCTITLE
snprintf(proctitle, sizeof(proctitle),
- "%s: %s", remotehost, pw->pw_name);
- setproctitle(proctitle);
+ "%s: %s", remotehost, pw->pw_name);
+ setproctitle("%s", proctitle);
#endif /* SETPROCTITLE */
if (logging)
syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
remotehost, pw->pw_name);
}
- (void) umask(defumask);
+#ifdef LOGIN_CAP
+ login_close(lc);
+#endif
return;
bad:
/* Forget all about it... */
+#ifdef LOGIN_CAP
+ login_close(lc);
+#endif
end_login();
}
@@ -631,6 +1124,7 @@ retrieve(cmd, name)
FILE *fin, *dout;
struct stat st;
int (*closefunc) __P((FILE *));
+ long start;
if (cmd == 0) {
fin = fopen(name, "r"), closefunc = fclose;
@@ -680,7 +1174,11 @@ retrieve(cmd, name)
dout = dataconn(name, st.st_size, "w");
if (dout == NULL)
goto done;
- send_data(fin, dout, st.st_blksize);
+ time(&start);
+ send_data(fin, dout, st.st_blksize, st.st_size,
+ restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode));
+ if (cmd == 0 && guest && stats)
+ logxfer(name, st.st_size, start);
(void) fclose(dout);
data = -1;
pdata = -1;
@@ -699,7 +1197,7 @@ store(name, mode, unique)
struct stat st;
int (*closefunc) __P((FILE *));
- if (unique && stat(name, &st) == 0 &&
+ if ((unique || guest) && stat(name, &st) == 0 &&
(name = gunique(name)) == NULL) {
LOGCMD(*mode == 'w' ? "put" : "append", name);
return;
@@ -778,6 +1276,7 @@ getdatasock(mode)
(char *) &on, sizeof(on)) < 0)
goto bad;
/* anchor socket to avoid multi-homing problems */
+ data_source.sin_len = sizeof(struct sockaddr_in);
data_source.sin_family = AF_INET;
data_source.sin_addr = ctrl_addr.sin_addr;
for (tries = 1; ; tries++) {
@@ -794,6 +1293,23 @@ getdatasock(mode)
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
#endif
+#ifdef TCP_NOPUSH
+ /*
+ * Turn off push flag to keep sender TCP from sending short packets
+ * at the boundaries of each write(). Should probably do a SO_SNDBUF
+ * to set the send buffer size as well, but that may not be desirable
+ * in heavy-load situations.
+ */
+ on = 1;
+ if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
+ syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
+#endif
+#ifdef SO_SNDBUF
+ on = 65536;
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
+ syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
+#endif
+
return (fdopen(s, mode));
bad:
/* Return the real value of errno (close may change it) */
@@ -823,9 +1339,17 @@ dataconn(name, size, mode)
if (pdata >= 0) {
struct sockaddr_in from;
int s, fromlen = sizeof(from);
+ struct timeval timeout;
+ fd_set set;
+
+ FD_ZERO(&set);
+ FD_SET(pdata, &set);
- s = accept(pdata, (struct sockaddr *)&from, &fromlen);
- if (s < 0) {
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 120;
+
+ if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 ||
+ (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) {
reply(425, "Can't open data connection.");
(void) close(pdata);
pdata = -1;
@@ -834,7 +1358,7 @@ dataconn(name, size, mode)
(void) close(pdata);
pdata = s;
#ifdef IP_TOS
- tos = IPTOS_LOWDELAY;
+ tos = IPTOS_THROUGHPUT;
(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
sizeof(int));
#endif
@@ -878,17 +1402,20 @@ dataconn(name, size, mode)
/*
* Tranfer the contents of "instr" to "outstr" peer using the appropriate
- * encapsulation of the data subject * to Mode, Structure, and Type.
+ * encapsulation of the data subject to Mode, Structure, and Type.
*
* NB: Form isn't handled.
*/
static void
-send_data(instr, outstr, blksize)
+send_data(instr, outstr, blksize, filesize, isreg)
FILE *instr, *outstr;
off_t blksize;
+ off_t filesize;
+ int isreg;
{
int c, cnt, filefd, netfd;
- char *buf;
+ char *buf, *bp;
+ size_t len;
transflag++;
if (setjmp(urgcatch)) {
@@ -918,13 +1445,45 @@ send_data(instr, outstr, blksize)
case TYPE_I:
case TYPE_L:
+ /*
+ * isreg is only set if we are not doing restart and we
+ * are sending a regular file
+ */
+ netfd = fileno(outstr);
+ filefd = fileno(instr);
+
+ if (isreg && filesize < (off_t)16 * 1024 * 1024) {
+ buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
+ (off_t)0);
+ if (buf == MAP_FAILED) {
+ syslog(LOG_WARNING, "mmap(%lu): %m",
+ (unsigned long)filesize);
+ goto oldway;
+ }
+ bp = buf;
+ len = filesize;
+ do {
+ cnt = write(netfd, bp, len);
+ len -= cnt;
+ bp += cnt;
+ if (cnt > 0) byte_count += cnt;
+ } while(cnt > 0 && len > 0);
+
+ transflag = 0;
+ munmap(buf, (size_t)filesize);
+ if (cnt < 0)
+ goto data_err;
+ reply(226, "Transfer complete.");
+ return;
+ }
+
+oldway:
if ((buf = malloc((u_int)blksize)) == NULL) {
transflag = 0;
perror_reply(451, "Local resource failure: malloc");
return;
}
- netfd = fileno(outstr);
- filefd = fileno(instr);
+
while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
write(netfd, buf, cnt) == cnt)
byte_count += cnt;
@@ -964,7 +1523,7 @@ receive_data(instr, outstr)
FILE *instr, *outstr;
{
int c;
- int cnt, bare_lfs = 0;
+ int cnt, bare_lfs;
char buf[BUFSIZ];
transflag++;
@@ -972,6 +1531,9 @@ receive_data(instr, outstr)
transflag = 0;
return (-1);
}
+
+ bare_lfs = 0;
+
switch (type) {
case TYPE_I:
@@ -1046,7 +1608,7 @@ statfilecmd(filename)
int c;
char line[LINE_MAX];
- (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
+ (void)snprintf(line, sizeof(line), _PATH_LS " -lgA %s", filename);
fin = ftpd_popen(line, "r");
lreply(211, "status of %s:", filename);
while ((c = getc(fin)) != EOF) {
@@ -1209,7 +1771,7 @@ yyerror(s)
{
char *cp;
- if (cp = strchr(cbuf,'\n'))
+ if ((cp = strchr(cbuf,'\n')))
*cp = '\0';
reply(500, "'%s': command not understood.", cbuf);
}
@@ -1304,8 +1866,15 @@ void
renamecmd(from, to)
char *from, *to;
{
+ struct stat st;
LOGCMD2("rename", from, to);
+
+ if (guest && (stat(to, &st) == 0)) {
+ reply(550, "%s: permission denied", to);
+ return;
+ }
+
if (rename(from, to) < 0)
perror_reply(550, "rename");
else
@@ -1325,12 +1894,26 @@ dolog(sin)
(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
sizeof(remotehost));
#ifdef SETPROCTITLE
- snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
- setproctitle(proctitle);
+#ifdef VIRTUAL_HOSTING
+ if (thishost != firsthost)
+ snprintf(proctitle, sizeof(proctitle), "%s: connected (to %s)",
+ remotehost, hostname);
+ else
+#endif
+ snprintf(proctitle, sizeof(proctitle), "%s: connected",
+ remotehost);
+ setproctitle("%s", proctitle);
#endif /* SETPROCTITLE */
- if (logging)
- syslog(LOG_INFO, "connection from %s", remotehost);
+ if (logging) {
+#ifdef VIRTUAL_HOSTING
+ if (thishost != firsthost)
+ syslog(LOG_INFO, "connection from %s (to %s)",
+ remotehost, hostname);
+ else
+#endif
+ syslog(LOG_INFO, "connection from %s", remotehost);
+ }
}
/*
@@ -1341,10 +1924,19 @@ void
dologout(status)
int status;
{
+ /*
+ * Prevent reception of SIGURG from resulting in a resumption
+ * back to the main program loop.
+ */
+ transflag = 0;
if (logged_in) {
(void) seteuid((uid_t)0);
logwtmp(ttyline, "", "");
+#if defined(KERBEROS)
+ if (!notickets && krbtkfile_env)
+ unlink(krbtkfile_env);
+#endif
}
/* beware of flushing buffers after a SIGPIPE */
_exit(status);
@@ -1392,19 +1984,36 @@ passive()
int len;
char *p, *a;
+ if (pdata >= 0) /* close old port if one set */
+ close(pdata);
+
pdata = socket(AF_INET, SOCK_STREAM, 0);
if (pdata < 0) {
perror_reply(425, "Can't open passive connection");
return;
}
+
+ (void) seteuid((uid_t)0);
+
+#ifdef IP_PORTRANGE
+ {
+ int on = restricted_data_ports ? IP_PORTRANGE_HIGH
+ : IP_PORTRANGE_DEFAULT;
+
+ if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
+ (char *)&on, sizeof(on)) < 0)
+ goto pasv_error;
+ }
+#endif
+
pasv_addr = ctrl_addr;
pasv_addr.sin_port = 0;
- (void) seteuid((uid_t)0);
- if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
- (void) seteuid((uid_t)pw->pw_uid);
+ if (bind(pdata, (struct sockaddr *)&pasv_addr,
+ sizeof(pasv_addr)) < 0)
goto pasv_error;
- }
+
(void) seteuid((uid_t)pw->pw_uid);
+
len = sizeof(pasv_addr);
if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
goto pasv_error;
@@ -1420,6 +2029,7 @@ passive()
return;
pasv_error:
+ (void) seteuid((uid_t)pw->pw_uid);
(void) close(pdata);
pdata = -1;
perror_reply(425, "Can't open passive connection");
@@ -1449,7 +2059,7 @@ gunique(local)
}
if (cp)
*cp = '/';
- (void) strcpy(new, local);
+ (void) snprintf(new, sizeof(new), "%s", local);
cp = new + strlen(new);
*cp++ = '.';
for (count = 1; count < 100; count++) {
@@ -1515,7 +2125,7 @@ send_file_list(whichf)
transflag = 0;
goto out;
}
- while (dirname = *dirlist++) {
+ while ((dirname = *dirlist++)) {
if (stat(dirname, &st) < 0) {
/*
* If user typed "ls -l", etc, and the client
@@ -1523,7 +2133,7 @@ send_file_list(whichf)
*/
if (dirname[0] == '-' && *dirlist == NULL &&
transflag == 0) {
- retrieve("/bin/ls %s", dirname);
+ retrieve(_PATH_LS " %s", dirname);
goto out;
}
perror_reply(550, whichf);
@@ -1608,7 +2218,14 @@ out:
}
}
-#ifdef SETPROCTITLE
+void
+reapchild(signo)
+ int signo;
+{
+ while (wait3(NULL, WNOHANG, NULL) > 0);
+}
+
+#ifdef OLD_SETPROCTITLE
/*
* Clobber argv so ps will show what we're doing. (Stolen from sendmail.)
* Warning, since this is usually started from inetd.conf, it often doesn't
@@ -1651,4 +2268,23 @@ setproctitle(fmt, va_alist)
while (p < LastArgv)
*p++ = ' ';
}
-#endif /* SETPROCTITLE */
+#endif /* OLD_SETPROCTITLE */
+
+static void
+logxfer(name, size, start)
+ char *name;
+ long size;
+ long start;
+{
+ char buf[1024];
+ char path[MAXPATHLEN + 1];
+ long now;
+
+ if (statfd >= 0 && getwd(path) != NULL) {
+ time(&now);
+ snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%ld!%ld\n",
+ ctime(&now)+4, ident, remotehost,
+ path, name, size, now - start + (now == start));
+ write(statfd, buf, strlen(buf));
+ }
+}
diff --git a/libexec/ftpd/logwtmp.c b/libexec/ftpd/logwtmp.c
index d40840c..9562795 100644
--- a/libexec/ftpd/logwtmp.c
+++ b/libexec/ftpd/logwtmp.c
@@ -30,6 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
+ * $Id$
*/
#ifndef lint
@@ -37,10 +38,13 @@ static char sccsid[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/types.h>
-#include <sys/time.h>
#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include <fcntl.h>
+#include <time.h>
+#include <netdb.h>
#include <utmp.h>
#include <unistd.h>
#include <stdio.h>
@@ -61,6 +65,18 @@ logwtmp(line, name, host)
struct utmp ut;
struct stat buf;
+ if (strlen(host) > UT_HOSTSIZE) {
+ struct hostent *hp = gethostbyname(host);
+
+ if (hp != NULL) {
+ struct in_addr in;
+
+ memmove(&in, hp->h_addr, sizeof(in));
+ host = inet_ntoa(in);
+ } else
+ host = "invalid hostname";
+ }
+
if (fd < 0 && (fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
return;
if (fstat(fd, &buf) == 0) {
diff --git a/libexec/ftpd/pathnames.h b/libexec/ftpd/pathnames.h
index 2a50063..d2f8b73 100644
--- a/libexec/ftpd/pathnames.h
+++ b/libexec/ftpd/pathnames.h
@@ -31,10 +31,14 @@
* SUCH DAMAGE.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * $Id: pathnames.h,v 1.9 1997/04/26 12:12:10 davidn Exp $
*/
#include <paths.h>
-#define _PATH_FTPUSERS "/etc/ftpusers"
+#define _PATH_FTPCHROOT "/etc/ftpchroot"
#define _PATH_FTPWELCOME "/etc/ftpwelcome"
-#define _PATH_FTPLOGINMESG "/etc/motd"
+#define _PATH_FTPLOGINMESG "/etc/ftpmotd"
+#define _PATH_FTPHOSTS "/etc/ftphosts"
+#define _PATH_FTPDSTATFILE "/var/log/ftpd"
+#define _PATH_LS "/bin/ls"
diff --git a/libexec/ftpd/popen.c b/libexec/ftpd/popen.c
index b26732e..ac0b76a 100644
--- a/libexec/ftpd/popen.c
+++ b/libexec/ftpd/popen.c
@@ -33,11 +33,14 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
+ * $Id: popen.c,v 1.7 1997/02/22 14:21:31 peter Exp $
*/
+#if 0
#ifndef lint
static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94";
#endif /* not lint */
+#endif
#include <sys/types.h>
#include <sys/wait.h>
@@ -51,6 +54,12 @@ static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94";
#include <unistd.h>
#include "extern.h"
+#ifdef INTERNAL_LS
+#include "pathnames.h"
+#endif
+
+#define MAXUSRARGS 100
+#define MAXGLOBARGS 1000
/*
* Special version of popen which avoids call to shell. This ensures noone
@@ -67,9 +76,9 @@ ftpd_popen(program, type)
char *cp;
FILE *iop;
int argc, gargc, pdes[2], pid;
- char **pop, *argv[100], *gargv[1000];
+ char **pop, *argv[MAXUSRARGS], *gargv[MAXGLOBARGS];
- if (*type != 'r' && *type != 'w' || type[1])
+ if (((*type != 'r') && (*type != 'w')) || type[1])
return (NULL);
if (!pids) {
@@ -83,13 +92,13 @@ ftpd_popen(program, type)
return (NULL);
/* break up string into pieces */
- for (argc = 0, cp = program;; cp = NULL)
+ for (argc = 0, cp = program; argc < MAXUSRARGS; cp = NULL)
if (!(argv[argc++] = strtok(cp, " \t\n")))
break;
/* glob each piece */
gargv[0] = argv[0];
- for (gargc = argc = 1; argv[argc]; argc++) {
+ for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) {
glob_t gl;
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
@@ -97,14 +106,21 @@ ftpd_popen(program, type)
if (glob(argv[argc], flags, NULL, &gl))
gargv[gargc++] = strdup(argv[argc]);
else
- for (pop = gl.gl_pathv; *pop; pop++)
+ for (pop = gl.gl_pathv; *pop && gargc < (MAXGLOBARGS-1);
+ pop++)
gargv[gargc++] = strdup(*pop);
globfree(&gl);
}
gargv[gargc] = NULL;
iop = NULL;
- switch(pid = vfork()) {
+#ifdef INTERNAL_LS
+ fflush(NULL);
+ pid = (strcmp(gargv[0], _PATH_LS) == 0) ? fork() : vfork();
+#else
+ pid = vfork();
+#endif
+ switch(pid) {
case -1: /* error */
(void)close(pdes[0]);
(void)close(pdes[1]);
@@ -125,6 +141,14 @@ ftpd_popen(program, type)
}
(void)close(pdes[1]);
}
+#ifdef INTERNAL_LS
+ if (strcmp(gargv[0], _PATH_LS) == 0) {
+ extern int optreset;
+ /* Reset getopt for ls_main() */
+ optreset = optind = optopt = 1;
+ exit(ls_main(gargc, gargv));
+ }
+#endif
execv(gargv[0], gargv);
_exit(1);
}
diff --git a/libexec/ftpd/skey-stuff.c b/libexec/ftpd/skey-stuff.c
new file mode 100644
index 0000000..b6aba40
--- /dev/null
+++ b/libexec/ftpd/skey-stuff.c
@@ -0,0 +1,29 @@
+/* Author: Wietse Venema, Eindhoven University of Technology.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+
+#include <skey.h>
+
+/* skey_challenge - additional password prompt stuff */
+
+char *skey_challenge(name, pwd, pwok)
+char *name;
+struct passwd *pwd;
+int pwok;
+{
+ static char buf[128];
+ struct skey skey;
+
+ /* Display s/key challenge where appropriate. */
+
+ if (pwd == NULL || skeychallenge(&skey, pwd->pw_name, buf))
+ sprintf(buf, "Password required for %s.", name);
+ else if (!pwok)
+ strcat(buf, " (s/key required)");
+ return (buf);
+}
diff --git a/libexec/getNAME/Makefile b/libexec/getNAME/Makefile
index a78bc28..6600d23 100644
--- a/libexec/getNAME/Makefile
+++ b/libexec/getNAME/Makefile
@@ -1,6 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
PROG= getNAME
-NOMAN= noman
.include <bsd.prog.mk>
diff --git a/libexec/getNAME/getNAME.1 b/libexec/getNAME/getNAME.1
new file mode 100644
index 0000000..c58bbe2
--- /dev/null
+++ b/libexec/getNAME/getNAME.1
@@ -0,0 +1,65 @@
+.\" Copyright (c) July 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+
+.Dd July 8, 1996
+.Dt getNAME 1
+.Os FreeBSD 2.2
+.Sh NAME
+.Nm getNAME
+.Nd get name sections from manual pages
+.Sh SYNOPSIS
+.Nm /usr/libexec/getNAME
+.Op Fl itw
+.Ar files ...
+.Sh DESCRIPTION
+The
+.Nm
+utility
+get name sections from manual pages. Without options
+.Nm
+building
+.Xr apropos 1
+database entries.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl i
+for building intro entries.
+.It Fl t
+for building toc.
+.It Fl w
+print type of manual page (OLD, NEW, UNKNOWN).
+.El
+.\" .Sh BUGS
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr makewhatis 1 ,
+.Xr man 1
+.Sh HISTORY
+The manual page for
+.Nm
+command appeared in
+.Fx 2.2 .
diff --git a/libexec/getNAME/getNAME.c b/libexec/getNAME/getNAME.c
index 2ab64b4..2961ecf 100644
--- a/libexec/getNAME/getNAME.c
+++ b/libexec/getNAME/getNAME.c
@@ -29,6 +29,9 @@
* 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: getNAME.c,v 1.4 1997/02/22 14:21:35 peter Exp $
+ *
*/
#ifndef lint
@@ -70,7 +73,7 @@ main(argc, argv)
extern int optind;
int ch;
- while ((ch = getopt(argc, argv, "itw")) != EOF)
+ while ((ch = getopt(argc, argv, "itw")) != -1)
switch(ch) {
case 'i':
intro = 1;
@@ -81,7 +84,6 @@ main(argc, argv)
case 'w':
typeflag = 1;
break;
- case '?':
default:
usage();
}
@@ -334,6 +336,6 @@ again:
void
usage()
{
- (void)fprintf(stderr, "usage: getNAME [-it] file ...\n");
+ (void)fprintf(stderr, "usage: getNAME [-itw] file ...\n");
exit(1);
}
diff --git a/libexec/getty/Makefile b/libexec/getty/Makefile
new file mode 100644
index 0000000..f51fe24
--- /dev/null
+++ b/libexec/getty/Makefile
@@ -0,0 +1,14 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
+
+PROG= getty
+SRCS= main.c init.c subr.c chat.c
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+MAN5= gettytab.5 ttys.5
+MAN8= getty.8
+# for the paranoid:
+#CFLAGS+= -Wall -Wstrict-prototypes -Wno-unused -Wwrite-strings
+
+.include <bsd.prog.mk>
+
diff --git a/libexec/getty/chat.c b/libexec/getty/chat.c
new file mode 100644
index 0000000..2474195
--- /dev/null
+++ b/libexec/getty/chat.c
@@ -0,0 +1,515 @@
+/*-
+ * Copyright (c) 1997
+ * David L Nugent <davidn@blaze.net.au>.
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * 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. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Modem chat module - send/expect style functions for getty
+ * For semi-intelligent modem handling.
+ *
+ * $Id$
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/ttydefaults.h>
+#include <sys/utsname.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <locale.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include "extern.h"
+
+#define PAUSE_CH (unsigned char)'\xff' /* pause kludge */
+
+#define CHATDEBUG_RECEIVE 0x01
+#define CHATDEBUG_SEND 0x02
+#define CHATDEBUG_EXPECT 0x04
+#define CHATDEBUG_MISC 0x08
+
+#define CHATDEBUG_DEFAULT 0
+#define CHAT_DEFAULT_TIMEOUT 10
+
+
+static int chat_debug = CHATDEBUG_DEFAULT;
+static int chat_alarm = CHAT_DEFAULT_TIMEOUT; /* Default */
+
+static volatile int alarmed = 0;
+
+
+static void chat_alrm __P((int));
+static int chat_unalarm __P((void));
+static int getdigit __P((unsigned char **, int, int));
+static char **read_chat __P((char **));
+static char *cleanchr __P((char **, unsigned char));
+static char *cleanstr __P((const unsigned char *, int));
+static const char *result __P((int));
+static int chat_expect __P((const char *));
+static int chat_send __P((char const *));
+
+
+/*
+ * alarm signal handler
+ * handle timeouts in read/write
+ * change stdin to non-blocking mode to prevent
+ * possible hang in read().
+ */
+
+static void
+chat_alrm(signo)
+ int signo;
+{
+ int on = 1;
+
+ alarm(1);
+ alarmed = 1;
+ signal(SIGALRM, chat_alrm);
+ ioctl(STDIN_FILENO, FIONBIO, &on);
+}
+
+
+/*
+ * Turn back on blocking mode reset by chat_alrm()
+ */
+
+static int
+chat_unalarm()
+{
+ int off = 0;
+ return ioctl(STDIN_FILENO, FIONBIO, &off);
+}
+
+
+/*
+ * convert a string of a given base (octal/hex) to binary
+ */
+
+static int
+getdigit(ptr, base, max)
+ unsigned char **ptr;
+ int base, max;
+{
+ int i, val = 0;
+ char * q;
+
+ static const char xdigits[] = "0123456789abcdef";
+
+ for (i = 0, q = *ptr; i++ < max; ++q) {
+ int sval;
+ const char * s = strchr(xdigits, tolower(*q));
+
+ if (s == NULL || (sval = s - xdigits) >= base)
+ break;
+ val = (val * base) + sval;
+ }
+ *ptr = q;
+ return val;
+}
+
+
+/*
+ * read_chat()
+ * Convert a whitespace delimtied string into an array
+ * of strings, being expect/send pairs
+ */
+
+static char **
+read_chat(chatstr)
+ char **chatstr;
+{
+ char *str = *chatstr;
+ char **res = NULL;
+
+ if (str != NULL) {
+ char *tmp = NULL;
+ int l;
+
+ if ((l=strlen(str)) > 0 && (tmp=malloc(l + 1)) != NULL &&
+ (res=malloc((l / 2 + 1) * sizeof(char *))) != NULL) {
+ static char ws[] = " \t";
+ char * p;
+
+ for (l = 0, p = strtok(strcpy(tmp, str), ws);
+ p != NULL;
+ p = strtok(NULL, ws))
+ {
+ unsigned char *q, *r;
+
+ /* Read escapes */
+ for (q = r = (unsigned char *)p; *r; ++q)
+ {
+ int val;
+
+ if (*q == '\\')
+ {
+ /* handle special escapes */
+ switch (*++q)
+ {
+ case 'a': /* bell */
+ *r++ = '\a';
+ break;
+ case 'r': /* cr */
+ *r++ = '\r';
+ break;
+ case 'n': /* nl */
+ *r++ = '\n';
+ break;
+ case 'f': /* ff */
+ *r++ = '\f';
+ break;
+ case 'b': /* bs */
+ *r++ = '\b';
+ break;
+ case 'e': /* esc */
+ *r++ = 27;
+ break;
+ case 't': /* tab */
+ *r++ = '\t';
+ break;
+ case 'p': /* pause */
+ *r++ = PAUSE_CH;
+ break;
+ case 's':
+ case 'S': /* space */
+ *r++ = ' ';
+ break;
+ case 'x': /* hexdigit */
+ ++q;
+ *r++ = getdigit(&q, 16, 2);
+ --q;
+ break;
+ case '0': /* octal */
+ ++q;
+ *r++ = getdigit(&q, 8, 3);
+ --q;
+ break;
+ default: /* literal */
+ *r++ = *q;
+ break;
+ case 0: /* not past eos */
+ --q;
+ break;
+ }
+ } else {
+ /* copy standard character */
+ *r++ == *q;
+ }
+ }
+
+ /* Remove surrounding quotes, if any
+ */
+ if (*p == '"' || *p == '\'') {
+ q = strrchr(p+1, *p);
+ if (q != NULL && *q == *p && q[1] == '\0') {
+ *q = '\0';
+ strcpy(p, p+1);
+ }
+ }
+
+ res[l++] = p;
+ }
+ res[l] = NULL;
+ *chatstr = tmp;
+ return res;
+ }
+ free(tmp);
+ }
+ return res;
+}
+
+
+/*
+ * clean a character for display (ctrl/meta character)
+ */
+
+static char *
+cleanchr(buf, ch)
+ char **buf;
+ unsigned char ch;
+{
+ int l;
+ static char tmpbuf[5];
+ char * tmp = buf ? *buf : tmpbuf;
+
+ if (ch & 0x80) {
+ strcpy(tmp, "M-");
+ l = 2;
+ ch &= 0x7f;
+ } else
+ l = 0;
+
+ if (ch < 32) {
+ tmp[l++] = '^';
+ tmp[l++] = ch + '@';
+ } else if (ch == 127) {
+ tmp[l++] = '^';
+ tmp[l++] = '?';
+ } else
+ tmp[l++] = ch;
+ tmp[l] = '\0';
+
+ if (buf)
+ *buf = tmp + l;
+ return tmp;
+}
+
+
+/*
+ * clean a string for display (ctrl/meta characters)
+ */
+
+static char *
+cleanstr(s, l)
+ const unsigned char *s;
+ int l;
+{
+ static unsigned char * tmp = NULL;
+ static int tmplen = 0;
+
+ if (tmplen < l * 4 + 1)
+ tmp = realloc(tmp, tmplen = l * 4 + 1);
+
+ if (tmp == NULL) {
+ tmplen = 0;
+ return (char *)"(mem alloc error)";
+ } else {
+ int i = 0;
+ char * p = tmp;
+
+ while (i < l)
+ cleanchr(&p, s[i++]);
+ *p = '\0';
+ }
+
+ return tmp;
+}
+
+
+/*
+ * return result as an pseudo-english word
+ */
+
+static const char *
+result(r)
+ int r;
+{
+ static const char * results[] = {
+ "OK", "MEMERROR", "IOERROR", "TIMEOUT"
+ };
+ return results[r & 3];
+}
+
+
+/*
+ * chat_expect()
+ * scan input for an expected string
+ */
+
+static int
+chat_expect(str)
+ const char *str;
+{
+ int len, r = 0;
+
+ if (chat_debug & CHATDEBUG_EXPECT)
+ syslog(LOG_DEBUG, "chat_expect '%s'", cleanstr(str, strlen(str)));
+
+ if ((len = strlen(str)) > 0) {
+ int i = 0;
+ char * got;
+
+ if ((got = malloc(len + 1)) == NULL)
+ r = 1;
+ else {
+
+ memset(got, 0, len+1);
+ alarm(chat_alarm);
+ alarmed = 0;
+
+ while (r == 0 && i < len) {
+ if (alarmed)
+ r = 3;
+ else {
+ unsigned char ch;
+
+ if (read(STDIN_FILENO, &ch, 1) == 1) {
+
+ if (chat_debug & CHATDEBUG_RECEIVE)
+ syslog(LOG_DEBUG, "chat_recv '%s' m=%d",
+ cleanchr(NULL, ch), i);
+
+ if (ch == str[i])
+ got[i++] = ch;
+ else if (i > 0) {
+ int j = 1;
+
+ /* See if we can resync on a
+ * partial match in our buffer
+ */
+ while (j < i && memcmp(got + j, str, i - j) != NULL)
+ j++;
+ if (j < i)
+ memcpy(got, got + j, i - j);
+ i -= j;
+ }
+ } else
+ r = alarmed ? 3 : 2;
+ }
+ }
+ alarm(0);
+ chat_unalarm();
+ alarmed = 0;
+ free(got);
+ }
+ }
+
+ if (chat_debug & CHATDEBUG_EXPECT)
+ syslog(LOG_DEBUG, "chat_expect %s", result(r));
+
+ return r;
+}
+
+
+/*
+ * chat_send()
+ * send a chat string
+ */
+
+static int
+chat_send(str)
+ char const *str;
+{
+ int r = 0;
+
+ if (chat_debug && CHATDEBUG_SEND)
+ syslog(LOG_DEBUG, "chat_send '%s'", cleanstr(str, strlen(str)));
+
+ if (*str) {
+ alarm(chat_alarm);
+ alarmed = 0;
+ while (r == 0 && *str)
+ {
+ unsigned char ch = (unsigned char)*str++;
+
+ if (alarmed)
+ r = 3;
+ else if (ch == PAUSE_CH)
+ usleep(500000); /* 1/2 second */
+ else {
+ usleep(10000); /* be kind to modem */
+ if (write(STDOUT_FILENO, &ch, 1) != 1)
+ r = alarmed ? 3 : 2;
+ }
+ }
+ alarm(0);
+ chat_unalarm();
+ alarmed = 0;
+ }
+
+ if (chat_debug & CHATDEBUG_SEND)
+ syslog(LOG_DEBUG, "chat_send %s", result(r));
+
+ return r;
+}
+
+
+/*
+ * getty_chat()
+ *
+ * Termination codes:
+ * -1 - no script supplied
+ * 0 - script terminated correctly
+ * 1 - invalid argument, expect string too large, etc.
+ * 2 - error on an I/O operation or fatal error condition
+ * 3 - timeout waiting for a simple string
+ *
+ * Parameters:
+ * char *scrstr - unparsed chat script
+ * timeout - seconds timeout
+ * debug - debug value (bitmask)
+ */
+
+int
+getty_chat(scrstr, timeout, debug)
+ char *scrstr;
+ int timeout, debug;
+{
+ int r = -1;
+
+ chat_alarm = timeout ? timeout : CHAT_DEFAULT_TIMEOUT;
+ chat_debug = debug;
+
+ if (scrstr != NULL) {
+ char **script;
+
+ if (chat_debug & CHATDEBUG_MISC)
+ syslog(LOG_DEBUG, "getty_chat script='%s'", scrstr);
+
+ if ((script = read_chat(&scrstr)) != NULL) {
+ int i = r = 0;
+ int off = 0;
+ sig_t old_alarm;
+ struct termios tneed;
+
+ /*
+ * We need to be in raw mode for all this
+ * Rely on caller...
+ */
+
+ old_alarm = signal(SIGALRM, chat_alrm);
+ chat_unalarm(); /* Force blocking mode at start */
+
+ /*
+ * This is the send/expect loop
+ */
+ while (r == 0 && script[i] != NULL)
+ if ((r = chat_expect(script[i++])) == 0 && script[i] != NULL)
+ r = chat_send(script[i++]);
+
+ signal(SIGALRM, old_alarm);
+ free(script);
+ free(scrstr);
+
+ /*
+ * Ensure stdin is in blocking mode
+ */
+ ioctl(STDIN_FILENO, FIONBIO, &off);
+ }
+
+ if (chat_debug & CHATDEBUG_MISC)
+ syslog(LOG_DEBUG, "getty_chat %s", result(r));
+
+ }
+ return r;
+}
diff --git a/libexec/telnetd/authenc.c b/libexec/getty/extern.h
index ccb463c..bd84a13 100644
--- a/libexec/telnetd/authenc.c
+++ b/libexec/getty/extern.h
@@ -1,5 +1,5 @@
-/*-
- * Copyright (c) 1991, 1993
+/*
+ * Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,63 +29,35 @@
* 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.
+ *
+ * from: @(#)extern.h 8.1 (Berkeley) 6/4/93
+ * $Id$
*/
-#ifndef lint
-static char sccsid[] = "@(#)authenc.c 8.2 (Berkeley) 5/30/95";
-#endif /* not lint */
-
-#if defined(AUTHENTICATION) || defined(ENCRYPTION)
-#include "telnetd.h"
-#include <libtelnet/misc.h>
-
- int
-net_write(str, len)
- unsigned char *str;
- int len;
-{
- if (nfrontp + len < netobuf + BUFSIZ) {
- memmove((void *)nfrontp, (void *)str, len);
- nfrontp += len;
- return(len);
- }
- return(0);
-}
-
- void
-net_encrypt()
-{
-#ifdef ENCRYPTION
- char *s = (nclearto > nbackp) ? nclearto : nbackp;
- if (s < nfrontp && encrypt_output) {
- (*encrypt_output)((unsigned char *)s, nfrontp - s);
- }
- nclearto = nfrontp;
-#endif /* ENCRYPTION */
-}
-
- int
-telnet_spin()
-{
- ttloop();
- return(0);
-}
+struct delayval;
+struct termios;
+struct gettyflags;
+struct gettynums;
+struct gettystrs;
- char *
-telnet_getenv(val)
- char *val;
-{
- extern char *getenv();
- return(getenv(val));
-}
+extern char hostname[];
+extern int hopcount;
+extern struct termios tmode, omode;
+extern struct gettyflags gettyflags[];
+extern struct gettynums gettynums[];
+extern struct gettystrs gettystrs[];
- char *
-telnet_gets(prompt, result, length, echo)
- char *prompt;
- char *result;
- int length;
- int echo;
-{
- return((char *)0);
-}
-#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
+int adelay __P((int, struct delayval *));
+const char *autobaud __P((void));
+int delaybits __P((void));
+void edithost __P((const char *));
+void gendefaults __P((void));
+void gettable __P((const char *, char *));
+void makeenv __P((char *[]));
+const char *portselector __P((void));
+void set_ttydefaults __P((int));
+void setchars __P((void));
+void setdefaults __P((void));
+void setflags __P((int));
+int speed __P((int));
+int getty_chat __P((char *, int, int));
diff --git a/libexec/getty/getty.8 b/libexec/getty/getty.8
new file mode 100644
index 0000000..c1b1936
--- /dev/null
+++ b/libexec/getty/getty.8
@@ -0,0 +1,128 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)getty.8 8.1 (Berkeley) 6/4/93
+.\" $Id$
+.\" "
+.Dd June 4, 1993
+.Dt GETTY 8
+.Os BSD 4
+.Sh NAME
+.Nm getty
+.Nd set terminal mode
+.Sh SYNOPSIS
+.Nm getty
+.Oo
+.Ar type
+.Op Ar tty
+.Oc
+.Sh DESCRIPTION
+The
+.Nm getty
+program
+is called by
+.Xr init 8
+to open and initialize the tty line, read a login name, and invoke
+.Xr login 1 .
+.Pp
+The argument
+.Ar tty
+is the special device file in
+.Pa /dev
+to open for the terminal (for example, ``ttyh0'').
+If there is no argument or the argument is
+.Ql Fl ,
+the tty line is assumed to be open as file descriptor 0.
+.Pp
+The
+.Ar type
+argument can be used to make
+.Nm getty
+treat the terminal line specially.
+This argument is used as an index into the
+.Nm gettytab 5
+database, to determine the characteristics of the line.
+If there is no argument, or there is no such table, the
+.Em default
+table is used.
+If there is no
+.Pa /etc/gettytab
+a set of system defaults is used.
+If indicated by the table located,
+.Nm getty
+will clear the terminal screen,
+print a banner heading,
+and prompt for a login name.
+Usually either the banner or the login prompt will include
+the system hostname.
+.Pp
+Most of the default actions of
+.Nm getty
+can be circumvented, or modified, by a suitable
+.Nm gettytab
+table.
+.Pp
+The
+.Nm getty
+program
+can be set to timeout after some interval,
+which will cause dial up lines to hang up
+if the login name is not entered reasonably quickly.
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "ttyxx: No such device or address."
+.It "ttyxx: No such file or address."
+A terminal which is turned
+on in the
+.Xr ttys
+file cannot be opened, likely because the requisite
+lines are either not configured into the system, the associated device
+was not attached during boot-time system configuration,
+or the special file in
+.Pa /dev
+does not exist.
+.El
+.Sh FILES
+.Bl -tag -width /etc/gettytab -compact
+.It Pa /etc/gettytab
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr ioctl 2 ,
+.Xr tty 4 ,
+.Xr gettytab 5 ,
+.Xr ttys 5 ,
+.Xr init 8
+.Sh HISTORY
+A
+.Nm getty
+program appeared in
+.At v6 .
diff --git a/libexec/getty/gettytab.5 b/libexec/getty/gettytab.5
new file mode 100644
index 0000000..ab92e0b
--- /dev/null
+++ b/libexec/getty/gettytab.5
@@ -0,0 +1,516 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)gettytab.5 8.4 (Berkeley) 4/19/94
+.\" $Id$
+.\" "
+.Dd April 19, 1994
+.Dt GETTYTAB 5
+.Os BSD 4.2
+.Sh NAME
+.Nm gettytab
+.Nd terminal configuration data base
+.Sh SYNOPSIS
+.Nm gettytab
+.Sh DESCRIPTION
+The
+.Nm gettytab
+file
+is a simplified version of the
+.Xr termcap 5
+data base
+used to describe terminal lines.
+The initial terminal login process
+.Xr getty 8
+accesses the
+.Nm gettytab
+file each time it starts, allowing simpler
+reconfiguration of terminal characteristics.
+Each entry in the data base
+is used to describe one class of terminals.
+.Pp
+There is a default terminal class,
+.Em default ,
+that is used to set global defaults for all other classes.
+(That is, the
+.Em default
+entry is read, then the entry for the class required
+is used to override particular settings.)
+.Sh CAPABILITIES
+Refer to
+.Xr termcap 5
+for a description of the file layout.
+The
+.Em default
+column below lists defaults obtained if there is
+no entry in the table obtained, nor one in the special
+.Em default
+table.
+.Bl -column Namexx /usr/bin/login Default
+.It Sy Name Type Default Description
+.It "ac str unused expect-send chat script for modem answer"
+.It "ap bool false terminal uses any parity"
+.It "bk str 0377 alternate end of line character (input break)"
+.It "c0 num unused tty control flags to write messages"
+.It "c1 num unused tty control flags to read login name"
+.It "c2 num unused tty control flags to leave terminal as"
+.It "ce bool false use crt erase algorithm"
+.It "ck bool false use crt kill algorithm"
+.It "cl str" Ta Dv NULL Ta
+.No "screen clear sequence"
+.It "co bool false console - add"
+.Ql \en
+after login prompt
+.It "ct num 10 chat timeout for ac/ic scripts"
+.It "dc num 0 chat debug bitmask"
+.It "de num 0 delay secs and flush input before writing first prompt"
+.It "ds str" Ta So Li ^Y Sc Ta
+.No "delayed suspend character"
+.It "dx bool false set"
+.Dv DECCTLQ
+.It "ec bool false leave echo"
+.Tn OFF
+.It "ep bool false terminal uses even parity"
+.It "er str" Ta So Li ^? Sc Ta
+.No "erase character"
+.It "et str" Ta So Li ^D Sc Ta
+.No "end of text"
+.Pq Dv EOF
+character
+.It "ev str" Ta Dv NULL Ta
+.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"
+.It "fl str" Ta So Li ^O Sc Ta
+.No "output flush character"
+.It "hc bool false do"
+.Tn NOT
+hangup line on last close
+.It "he str" Ta Dv NULL Ta
+.No "hostname editing string"
+.It "hn str hostname hostname"
+.It "ht bool false terminal has real tabs"
+.It "hw bool false do cts/rts hardware flow control"
+.It "i0 num unused tty input flags to write messages"
+.It "i1 num unused tty input flags to read login name"
+.It "i2 num unused tty input flags to leave terminal as"
+.It "ic str unused expect-send chat script for modem initialization"
+.It "if str unused display named file before prompt"
+.It "ig bool false ignore garbage characters in login name"
+.It "im str" Ta Dv NULL Ta
+.No "initial (banner) message"
+.It "in str" Ta So Li ^C Sc Ta
+.No "interrupt character"
+.It "is num unused input speed"
+.It "kl str" Ta So Li ^U Sc Ta
+.No "kill character"
+.It "l0 num unused tty local flags to write messages"
+.It "l1 num unused tty local flags to read login name"
+.It "l2 num unused tty local flags to leave terminal as"
+.It "lm str login: login prompt"
+.It "ln str" Ta So Li ^V Sc Ta
+.No "``literal next'' character"
+.It "lo str" Ta Pa /usr/bin/login Ta
+.No "program to exec when name obtained"
+.It "mb bool false do flow control based on carrier"
+.It "nl bool false terminal has (or might have) a newline character"
+.It "np bool false terminal uses no parity (i.e. 8-bit characters)"
+.It "nx str default next table (for auto speed selection)"
+.It "o0 num unused tty output flags to write messages"
+.It "o1 num unused tty output flags to read login name"
+.It "o2 num unused tty output flags to leave terminal as"
+.It "op bool false terminal uses odd parity"
+.It "os num unused output speed"
+.It "pc str" Ta So Li \e0 Sc Ta
+.No "pad character"
+.It "pe bool false use printer (hard copy) erase algorithm"
+.It "pf num 0 delay"
+between first prompt and following flush (seconds)
+.It "pp str unused PPP authentication program"
+.It "ps bool false line connected to a"
+.Tn MICOM
+port selector
+.It "qu str" Ta So Li \&^\e Sc Ta
+.No "quit character"
+.It "rp str" Ta So Li ^R Sc Ta
+.No "line retype character"
+.It "rt num unused ring timeout when using ac"
+.It "rw bool false do"
+.Tn NOT
+use raw for input, use cbreak
+.It "sp num unused line speed (input and output)"
+.It "su str" Ta So Li ^Z Sc Ta
+.No "suspend character"
+.It "tc str none table continuation"
+.It "to num 0 timeout (seconds)"
+.It "tt str" Ta Dv NULL Ta
+.No "terminal type (for environment)"
+.It "ub bool false do unbuffered output (of prompts etc)"
+.It "we str" Ta So Li ^W Sc Ta
+.No "word erase character"
+.It xc bool false do
+.Tn NOT
+echo control chars as
+.Ql ^X
+.It "xf str" Ta So Li ^S Sc Ta Dv XOFF
+(stop output) character
+.It "xn str" Ta So Li ^Q Sc Ta Dv XON
+(start output) character
+.It "Lo str C the locale name used for \&%d in the banner message"
+.El
+.Pp
+The following capabilities are no longer supported by getty(8):
+.Bl -column Namexx /usr/bin/login Default
+.It "bd num 0 backspace delay"
+.It "cb bool false use crt backspace mode"
+.It "cd num 0 carriage-return delay"
+.It "fd num 0 form-feed (vertical motion) delay"
+.It "lc bool false terminal has lower case"
+.It "nd num 0 newline (line-feed) delay"
+.It "uc bool false terminal is known upper case only"
+.El
+.Pp
+If no line speed is specified, speed will not be altered
+from that which prevails when getty is entered.
+Specifying an input or output speed will override
+line speed for stated direction only.
+.Pp
+Terminal modes to be used for the output of the message,
+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 overridden
+with one of the
+.Em \&c0 ,
+.Em \&c1 ,
+.Em \&c2 ,
+.Em \&i0 ,
+.Em \&i1 ,
+.Em \&i2 ,
+.Em \&l0 ,
+.Em \&l1 ,
+.Em \&l2 ,
+.Em \&o0 ,
+.Em \&o1 ,
+or
+.Em \&o2
+numeric specifications, which can be used to specify
+(usually in octal, with a leading '0')
+the exact values of the flags.
+These flags correspond to the termios
+.Em c_cflag ,
+.Em c_iflag ,
+.Em c_lflag ,
+and
+.Em c_oflag
+fields, respectively. Each these sets must be completely specified to be
+effective.
+The
+.Em \&f0 ,
+.Em \&f1 ,
+and
+.Em \&f2
+are excepted for backwards compatibility with a previous incarnation of
+the TTY sub-system. In these flags the bottom 16 bits of the (32 bits)
+value contain the sgttyb
+.Em sg_flags
+field, while the top 16 bits represent the local mode word.
+.Pp
+Should
+.Xr getty 8
+receive a null character
+(presumed to indicate a line break)
+it will restart using the table indicated by the
+.Em nx
+entry. If there is none, it will re-use its original table.
+.Pp
+Delays are specified in milliseconds, the nearest possible
+delay available in the tty driver will be used.
+Should greater certainty be desired, delays
+with values 0, 1, 2, and 3 are interpreted as
+choosing that particular delay algorithm from the driver.
+.Pp
+The
+.Em \&cl
+screen clear string may be preceded by a (decimal) number
+of milliseconds of delay required (a la termcap).
+This delay is simulated by repeated use of the pad character
+.Em \&pc .
+.Pp
+The initial message, and login message,
+.Em \&im
+and
+.Em \&lm
+may include any of the following character sequences, which expand to
+information about the environment in which
+.Xr getty 8
+is running.
+.Pp
+.Bl -tag -offset indent -width \&%xxxxxxxxxxxxxx
+.It \&%d
+The current date and time in the locale's representation as of the
+.Em \&Lo
+string
+(the \&%+ format of
+.Xr strftime 3 ).
+.It \&%h
+The hostname of the machine, which is normally obtained from the
+system using
+.Xr gethostname 3 ,
+but may also be overridden by the
+.Em \&hn
+table entry.
+In either case it may be edited with the
+.Em \&he
+string.
+A '@' in the
+.Em \&he
+string causes one character from the real hostname to
+be copied to the final hostname.
+A '#' in the
+.Em \&he
+string causes the next character of the real hostname
+to be skipped.
+Each character that
+is neither '@' nor '#' is copied into the final hostname.
+Surplus '@' and '#' characters are ignored.
+.It \&%t
+The tty name.
+.It "\&%m, \&%r, \&%s, \&%v"
+The type of machine, release of the operating system, name of the
+operating system, and version of the kernel, respectively, as
+returned by
+.Xr uname 3 .
+.It \&%%
+A
+.Dq %
+character.
+.El
+.Pp
+When getty execs the login process, given
+in the
+.Em \&lo
+string (usually
+.Dq Pa /usr/bin/login ) ,
+it will have set
+the environment to include the terminal type, as indicated
+by the
+.Em \&tt
+string (if it exists).
+The
+.Em \&ev
+string, can be used to enter additional data into
+the environment.
+It is a list of comma separated strings, each of which
+will presumably be of the form
+.Em name=value .
+.Pp
+If a non-zero timeout is specified, with
+.Em \&to ,
+then getty will exit within the indicated
+number of seconds, either having
+received a login name and passed control
+to
+.Xr login 1 ,
+or having received an alarm signal, and exited.
+This may be useful to hangup dial in lines.
+.Pp
+Output from
+.Xr getty 8
+is even parity unless
+.Em \&op
+or
+.Em \&np
+is specified.
+The
+.Em \&op
+string
+may be specified with
+.Em \&ap
+to allow any parity on input, but generate odd parity output.
+Note: this only applies while getty is being run,
+terminal driver limitations prevent a more complete
+implementation.
+.Xr Getty 8
+does not check parity of input characters in
+.Dv RAW
+mode.
+.Pp
+If
+.Em \&pp
+string is specified and a PPP link bringup sequence is recognized,
+getty will invoke the program referenced by the pp option. This
+can be used to handle incoming PPP calls.
+.Pp
+.Nm getty
+provides some basic intelligent modem handling by providing a chat
+script feature available via two capabilities:
+.Pp
+.Bl -tag -offset indent -width \&xxxxxxxx -compact
+.It ic
+Chat script to initialize modem.
+.It ac
+Chat script to answer a call.
+.El
+.Pp
+A chat script is a set of expect/send string pairs.
+When a chat string starts,
+.Nm Getty
+will wait for the first string, and if it finds it, will send the
+second, and so on.
+Strings specified are separated by one or more tabs or spaces.
+Strings may contain standard ascii characters and special 'escapes',
+which consist of a backslash character followed by one or more
+characters which are interpreted as follows:
+.Pp
+.Bl -tag -offset indent -width \&xxxxxxxx -compact
+.It \ea
+bell character.
+.It \eb
+backspace.
+.It \en
+newline.
+.It \ee
+escape.
+.It \ef
+formfeed.
+.It \ep
+half-second pause.
+.It \er
+carriage return.
+.It \eS, \es
+space character.
+.It \et
+tab.
+.It \exNN
+hexadecimal byte value.
+.It \e0NNN
+octal byte value.
+.El
+.Pp
+Note that the
+.Ql \ep
+sequence is only valid for send strings and causes a half-second
+pause between sending the previous and next characters.
+Hexidecimal values are, at most, 2 hex digits long, and octal
+values are a maximum of 3 octal digits.
+.Pp
+The
+.Em \&ic
+chat sequence is used to initialize a modem or similar device.
+A typical example of an init chat script for a modem with a
+hayes compatible command set might look like this:
+.Pp
+.Dl :ic="" ATE0Q0V1\er OK\er ATS0=0\er OK\er:
+.Pp
+This script waits for nothing (which always succeeds), sends
+a sequence to ensure that the modem is in the correct mode
+(suppress command echo, send responses in verbose mode),
+and then disables auto-answer.
+It waits for an "OK" response before it terminates.
+The init sequence is used to check modem responses to ensure that
+the modem is functioning correctly.
+If the init script fails to complete,
+.Nm getty
+considers this to be fatal, and results in an error logged via
+.Xr syslogd 8 ,
+and exiting.
+.Pp
+Similarly, an answer chat script is used to manually answer the
+phone in response to (usually) a "RING".
+When run with an answer script,
+.Nm getty
+opens the port in non-blocking mode, clears any extraneous input
+and waits for data on the port.
+As soon as any data is available, the answer chat script is
+started and scanned for a string, and responds according to
+the answer chat script.
+With a hayes compatible modem, this would normally look something
+like:
+.Pp
+.Dl :ac=RING\er ATA\er CONNECT:
+.Pp
+This causes the modem to answer the call via the "ATA" command,
+then scans input for a "CONNECT" string.
+If this is received before a
+.Em \&ct timeout, then a normal login sequence commences.
+.Pp
+The
+.Em \&ct
+capability specifies a timeout for all send and expect strings.
+This timeout is set individually for each expect wait and send
+string and must be at least as long as the time it takes for
+a connection to be established between a remote and local
+modem (usually around 10 seconds).
+.Pp
+In most situations, you will want to flush any additional
+input after the connection has been detected, and the
+.Em \&de
+capability may be used to do that, as well as delay for a
+short time after the connection has been established during
+which all of the connection data has been sent by the modem.
+.Pp
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr gethostname 3 ,
+.Xr uname 3 ,
+.Xr termcap 5 ,
+.Xr getty 8 ,
+.Xr telnetd 8 .
+.Sh BUGS
+The special characters (erase, kill, etc.) are reset to system defaults
+by
+.Xr login 1 .
+In
+.Em all
+cases, '#' or '^H' typed in a login name will be treated as
+an erase character, and '@' will be treated as a kill character.
+.Pp
+The delay stuff is a real crock.
+Apart form its general lack of flexibility, some
+of the delay algorithms are not implemented.
+The terminal driver should support sane delay settings.
+.Pp
+The
+.Em \&he
+capability is stupid.
+.Pp
+The
+.Xr termcap
+format is horrid, something more rational should
+have been chosen.
+.Sh HISTORY
+The
+.Nm gettytab
+file format appeared in
+.Bx 4.2 .
diff --git a/libexec/getty/gettytab.h b/libexec/getty/gettytab.h
new file mode 100644
index 0000000..1321ad1
--- /dev/null
+++ b/libexec/getty/gettytab.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 1983, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)gettytab.h 8.2 (Berkeley) 3/30/94
+ * $Id$
+ */
+
+/*
+ * Getty description definitions.
+ */
+struct gettystrs {
+ const char *field; /* name to lookup in gettytab */
+ char *defalt; /* value we find by looking in defaults */
+ char *value; /* value that we find there */
+};
+
+struct gettynums {
+ const char *field; /* name to lookup */
+ long defalt; /* number we find in defaults */
+ long value; /* number we find there */
+ int set; /* we actually got this one */
+};
+
+struct gettyflags {
+ const char *field; /* name to lookup */
+ char invrt; /* name existing in gettytab --> false */
+ char defalt; /* true/false in defaults */
+ char value; /* true/false flag */
+ char set; /* we found it */
+};
+
+/*
+ * String values.
+ */
+#define NX gettystrs[0].value
+#define CL gettystrs[1].value
+#define IM gettystrs[2].value
+#define LM gettystrs[3].value
+#define ER gettystrs[4].value
+#define KL gettystrs[5].value
+#define ET gettystrs[6].value
+#define PC gettystrs[7].value
+#define TT gettystrs[8].value
+#define EV gettystrs[9].value
+#define LO gettystrs[10].value
+#define HN gettystrs[11].value
+#define HE gettystrs[12].value
+#define IN gettystrs[13].value
+#define QU gettystrs[14].value
+#define XN gettystrs[15].value
+#define XF gettystrs[16].value
+#define BK gettystrs[17].value
+#define SU gettystrs[18].value
+#define DS gettystrs[19].value
+#define RP gettystrs[20].value
+#define FL gettystrs[21].value
+#define WE gettystrs[22].value
+#define LN gettystrs[23].value
+#define Lo gettystrs[24].value
+#define PP gettystrs[25].value
+#define IF gettystrs[26].value
+#define IC gettystrs[27].value
+#define AC gettystrs[28].value
+
+/*
+ * Numeric definitions.
+ */
+#define IS gettynums[0].value
+#define OS gettynums[1].value
+#define SP gettynums[2].value
+#define ND gettynums[3].value
+#define CD gettynums[4].value
+#define TD gettynums[5].value
+#define FD gettynums[6].value
+#define BD gettynums[7].value
+#define TO gettynums[8].value
+#define F0 gettynums[9].value
+#define F0set gettynums[9].set
+#define F1 gettynums[10].value
+#define F1set gettynums[10].set
+#define F2 gettynums[11].value
+#define F2set gettynums[11].set
+#define PF gettynums[12].value
+#define C0 gettynums[13].value
+#define C0set gettynums[13].set
+#define C1 gettynums[14].value
+#define C1set gettynums[14].set
+#define C2 gettynums[15].value
+#define C2set gettynums[15].set
+#define I0 gettynums[16].value
+#define I0set gettynums[16].set
+#define I1 gettynums[17].value
+#define I1set gettynums[17].set
+#define I2 gettynums[18].value
+#define I2set gettynums[18].set
+#define L0 gettynums[19].value
+#define L0set gettynums[19].set
+#define L1 gettynums[20].value
+#define L1set gettynums[20].set
+#define L2 gettynums[21].value
+#define L2set gettynums[21].set
+#define O0 gettynums[22].value
+#define O0set gettynums[22].set
+#define O1 gettynums[23].value
+#define O1set gettynums[23].set
+#define O2 gettynums[24].value
+#define O2set gettynums[24].set
+#define DE gettynums[25].value
+#define RTset gettynums[26].set
+#define RT gettynums[26].value
+#define CT gettynums[27].value
+#define DC gettynums[28].value
+
+/*
+ * Boolean values.
+ */
+#define HT gettyflags[0].value
+#define NL gettyflags[1].value
+#define EP gettyflags[2].value
+#define EPset gettyflags[2].set
+#define OP gettyflags[3].value
+#define OPset gettyflags[3].set
+#define AP gettyflags[4].value
+#define APset gettyflags[4].set
+#define EC gettyflags[5].value
+#define CO gettyflags[6].value
+#define CB gettyflags[7].value
+#define CK gettyflags[8].value
+#define CE gettyflags[9].value
+#define PE gettyflags[10].value
+#define RW gettyflags[11].value
+#define XC gettyflags[12].value
+#define LC gettyflags[13].value
+#define UC gettyflags[14].value
+#define IG gettyflags[15].value
+#define PS gettyflags[16].value
+#define HC gettyflags[17].value
+#define UB gettyflags[18].value
+#define AB gettyflags[19].value
+#define DX gettyflags[20].value
+#define NP gettyflags[21].value
+#define MB gettyflags[22].value
+#define HW gettyflags[23].value
+
diff --git a/libexec/getty/init.c b/libexec/getty/init.c
new file mode 100644
index 0000000..9df0728
--- /dev/null
+++ b/libexec/getty/init.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)init.c 8.1 (Berkeley) 6/4/93";*/
+static char rcsid[] = "$Id$";
+#endif /* not lint */
+
+/*
+ * Getty table initializations.
+ *
+ * Melbourne getty.
+ */
+#include <termios.h>
+#include "extern.h"
+#include "gettytab.h"
+#include "pathnames.h"
+
+static char loginmsg[] = "login: ";
+static char nullstr[] = "";
+static char loginprg[] = _PATH_LOGIN;
+
+struct gettystrs gettystrs[] = {
+ { "nx" }, /* next table */
+ { "cl" }, /* screen clear characters */
+ { "im" }, /* initial message */
+ { "lm", loginmsg }, /* login message */
+ { "er", &tmode.c_cc[VERASE] }, /* erase character */
+ { "kl", &tmode.c_cc[VKILL] }, /* kill character */
+ { "et", &tmode.c_cc[VEOF] }, /* eof chatacter (eot) */
+ { "pc", nullstr }, /* pad character */
+ { "tt" }, /* terminal type */
+ { "ev" }, /* enviroment */
+ { "lo", loginprg }, /* login program */
+ { "hn", hostname }, /* host name */
+ { "he" }, /* host name edit */
+ { "in", &tmode.c_cc[VINTR] }, /* interrupt char */
+ { "qu", &tmode.c_cc[VQUIT] }, /* quit char */
+ { "xn", &tmode.c_cc[VSTART] }, /* XON (start) char */
+ { "xf", &tmode.c_cc[VSTOP] }, /* XOFF (stop) char */
+ { "bk", &tmode.c_cc[VEOL] }, /* brk char (alt \n) */
+ { "su", &tmode.c_cc[VSUSP] }, /* suspend char */
+ { "ds", &tmode.c_cc[VDSUSP] }, /* delayed suspend */
+ { "rp", &tmode.c_cc[VREPRINT] },/* reprint char */
+ { "fl", &tmode.c_cc[VDISCARD] },/* flush output */
+ { "we", &tmode.c_cc[VWERASE] }, /* word erase */
+ { "ln", &tmode.c_cc[VLNEXT] }, /* literal next */
+ { "Lo" }, /* locale for strftime() */
+ { "pp" }, /* ppp login program */
+ { "if" }, /* sysv-like 'issue' filename */
+ { "ic" }, /* modem init-chat */
+ { "ac" }, /* modem answer-chat */
+ { 0 }
+};
+
+struct gettynums gettynums[] = {
+ { "is" }, /* input speed */
+ { "os" }, /* output speed */
+ { "sp" }, /* both speeds */
+ { "nd" }, /* newline delay */
+ { "cd" }, /* carriage-return delay */
+ { "td" }, /* tab delay */
+ { "fd" }, /* form-feed delay */
+ { "bd" }, /* backspace delay */
+ { "to" }, /* timeout */
+ { "f0" }, /* output flags */
+ { "f1" }, /* input flags */
+ { "f2" }, /* user mode flags */
+ { "pf" }, /* delay before flush at 1st prompt */
+ { "c0" }, /* output c_flags */
+ { "c1" }, /* input c_flags */
+ { "c2" }, /* user mode c_flags */
+ { "i0" }, /* output i_flags */
+ { "i1" }, /* input i_flags */
+ { "i2" }, /* user mode i_flags */
+ { "l0" }, /* output l_flags */
+ { "l1" }, /* input l_flags */
+ { "l2" }, /* user mode l_flags */
+ { "o0" }, /* output o_flags */
+ { "o1" }, /* input o_flags */
+ { "o2" }, /* user mode o_flags */
+ { "de" }, /* delay before sending 1st prompt */
+ { "rt" }, /* reset timeout */
+ { "ct" }, /* chat script timeout */
+ { "dc" }, /* debug chat script value */
+ { 0 }
+};
+
+
+struct gettyflags gettyflags[] = {
+ { "ht", 0 }, /* has tabs */
+ { "nl", 1 }, /* has newline char */
+ { "ep", 0 }, /* even parity */
+ { "op", 0 }, /* odd parity */
+ { "ap", 0 }, /* any parity */
+ { "ec", 1 }, /* no echo */
+ { "co", 0 }, /* console special */
+ { "cb", 0 }, /* crt backspace */
+ { "ck", 0 }, /* crt kill */
+ { "ce", 0 }, /* crt erase */
+ { "pe", 0 }, /* printer erase */
+ { "rw", 1 }, /* don't use raw */
+ { "xc", 1 }, /* don't ^X ctl chars */
+ { "lc", 0 }, /* terminal las lower case */
+ { "uc", 0 }, /* terminal has no lower case */
+ { "ig", 0 }, /* ignore garbage */
+ { "ps", 0 }, /* do port selector speed select */
+ { "hc", 1 }, /* don't set hangup on close */
+ { "ub", 0 }, /* unbuffered output */
+ { "ab", 0 }, /* auto-baud detect with '\r' */
+ { "dx", 0 }, /* set decctlq */
+ { "np", 0 }, /* no parity at all (8bit chars) */
+ { "mb", 0 }, /* do MDMBUF flow control */
+ { "hw", 0 }, /* do CTSRTS flow control */
+ { 0 }
+};
diff --git a/libexec/getty/main.c b/libexec/getty/main.c
new file mode 100644
index 0000000..cead481
--- /dev/null
+++ b/libexec/getty/main.c
@@ -0,0 +1,763 @@
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)main.c 8.1 (Berkeley) 6/20/93";*/
+static char rcsid[] = "$Id: main.c,v 1.20 1997/06/03 12:56:47 davidn Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/ttydefaults.h>
+#include <sys/utsname.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <locale.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "gettytab.h"
+#include "pathnames.h"
+#include "extern.h"
+
+/*
+ * Set the amount of running time that getty should accumulate
+ * before deciding that something is wrong and exit.
+ */
+#define GETTY_TIMEOUT 60 /* seconds */
+
+#undef CTRL
+#define CTRL(x) (x&037)
+
+/* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
+
+#define PPP_FRAME 0x7e /* PPP Framing character */
+#define PPP_STATION 0xff /* "All Station" character */
+#define PPP_ESCAPE 0x7d /* Escape Character */
+#define PPP_CONTROL 0x03 /* PPP Control Field */
+#define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */
+#define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */
+#define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */
+
+struct termios tmode, omode;
+
+int crmod, digit, lower, upper;
+
+char hostname[MAXHOSTNAMELEN];
+char name[MAXLOGNAME*3];
+char dev[] = _PATH_DEV;
+char ttyn[32];
+
+#define OBUFSIZ 128
+#define TABBUFSIZ 512
+
+char defent[TABBUFSIZ];
+char tabent[TABBUFSIZ];
+
+char *env[128];
+
+char partab[] = {
+ 0001,0201,0201,0001,0201,0001,0001,0201,
+ 0202,0004,0003,0205,0005,0206,0201,0001,
+ 0201,0001,0001,0201,0001,0201,0201,0001,
+ 0001,0201,0201,0001,0201,0001,0001,0201,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0201
+};
+
+#define ERASE tmode.c_cc[VERASE]
+#define KILL tmode.c_cc[VKILL]
+#define EOT tmode.c_cc[VEOF]
+
+static void dingdong __P((int));
+static int getname __P((void));
+static void interrupt __P((int));
+static void oflush __P((void));
+static void prompt __P((void));
+static void putchr __P((int));
+static void putf __P((const char *));
+static void putpad __P((const char *));
+static void puts __P((const char *));
+static void timeoverrun __P((int));
+static char *getline __P((int));
+static void setttymode __P((const char *, int));
+static void setdefttymode __P((const char *));
+static int opentty __P((const char *, int));
+
+int main __P((int, char **));
+
+jmp_buf timeout;
+
+static void
+dingdong(signo)
+ int signo;
+{
+ alarm(0);
+ longjmp(timeout, 1);
+}
+
+jmp_buf intrupt;
+
+static void
+interrupt(signo)
+ int signo;
+{
+ longjmp(intrupt, 1);
+}
+
+/*
+ * Action to take when getty is running too long.
+ */
+static void
+timeoverrun(signo)
+ int signo;
+{
+
+ syslog(LOG_ERR, "getty exiting due to excessive running time\n");
+ exit(1);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern char **environ;
+ const char *tname;
+ int first_sleep = 1, first_time = 1;
+ struct rlimit limit;
+ int rval;
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+
+ openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
+ gethostname(hostname, sizeof(hostname));
+ if (hostname[0] == '\0')
+ strcpy(hostname, "Amnesiac");
+
+ /*
+ * Limit running time to deal with broken or dead lines.
+ */
+ (void)signal(SIGXCPU, timeoverrun);
+ limit.rlim_max = RLIM_INFINITY;
+ limit.rlim_cur = GETTY_TIMEOUT;
+ (void)setrlimit(RLIMIT_CPU, &limit);
+
+ gettable("default", defent);
+ gendefaults();
+ tname = "default";
+ if (argc > 1)
+ tname = argv[1];
+
+ /*
+ * The following is a work around for vhangup interactions
+ * which cause great problems getting window systems started.
+ * If the tty line is "-", we do the old style getty presuming
+ * that the file descriptors are already set up for us.
+ * J. Gettys - MIT Project Athena.
+ */
+ if (argc <= 2 || strcmp(argv[2], "-") == 0)
+ strcpy(ttyn, ttyname(STDIN_FILENO));
+ else {
+ strcpy(ttyn, dev);
+ strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
+ if (strcmp(argv[0], "+") != 0) {
+ chown(ttyn, 0, 0);
+ chmod(ttyn, 0600);
+ revoke(ttyn);
+
+ gettable(tname, tabent);
+
+ /* Init modem sequence has been specified
+ */
+ if (IC) {
+ if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
+ exit(1);
+ setdefttymode(tname);
+ if (getty_chat(IC, CT, DC) > 0) {
+ syslog(LOG_ERR, "modem init problem on %s", ttyn);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(1);
+ }
+ }
+
+ if (AC) {
+ int i, rfds;
+ struct timeval timeout;
+
+ if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
+ exit(1);
+ setdefttymode(tname);
+ rfds = 1 << 0; /* FD_SET */
+ timeout.tv_sec = RT;
+ timeout.tv_usec = 0;
+ i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
+ (fd_set*)NULL, RT ? &timeout : NULL);
+ if (i < 0) {
+ syslog(LOG_ERR, "select %s: %m", ttyn);
+ } else if (i == 0) {
+ syslog(LOG_NOTICE, "recycle tty %s", ttyn);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(0); /* recycle for init */
+ }
+ i = getty_chat(AC, CT, DC);
+ if (i > 0) {
+ syslog(LOG_ERR, "modem answer problem on %s", ttyn);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(1);
+ }
+ } else { /* blocking open */
+ if (!opentty(ttyn, O_RDWR))
+ exit(1);
+ }
+ }
+ }
+
+ /* Start with default tty settings */
+ if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
+ syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
+ exit(1);
+ }
+ /*
+ * Don't rely on the driver too much, and initialize crucial
+ * things according to <sys/ttydefaults.h>. Avoid clobbering
+ * the c_cc[] settings however, the console drivers might wish
+ * to leave their idea of the preferred VERASE key value
+ * there.
+ */
+ tmode.c_iflag = TTYDEF_IFLAG;
+ tmode.c_oflag = TTYDEF_OFLAG;
+ tmode.c_lflag = TTYDEF_LFLAG;
+ tmode.c_cflag = TTYDEF_CFLAG;
+ omode = tmode;
+
+ for (;;) {
+
+ /*
+ * if a delay was specified then sleep for that
+ * number of seconds before writing the initial prompt
+ */
+ if (first_sleep && DE) {
+ sleep(DE);
+ /* remove any noise */
+ (void)tcflush(STDIN_FILENO, TCIOFLUSH);
+ }
+ first_sleep = 0;
+
+ setttymode(tname, 0);
+ if (AB) {
+ tname = autobaud();
+ continue;
+ }
+ if (PS) {
+ tname = portselector();
+ continue;
+ }
+ if (CL && *CL)
+ putpad(CL);
+ edithost(HE);
+
+ /* if this is the first time through this, and an
+ issue file has been given, then send it */
+ if (first_time && IF) {
+ int fd;
+
+ if ((fd = open(IF, O_RDONLY)) != -1) {
+ char * cp;
+
+ while ((cp = getline(fd)) != NULL) {
+ putf(cp);
+ }
+ close(fd);
+ }
+ }
+ first_time = 0;
+
+ if (IM && *IM)
+ putf(IM);
+ if (setjmp(timeout)) {
+ cfsetispeed(&tmode, B0);
+ cfsetospeed(&tmode, B0);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(1);
+ }
+ if (TO) {
+ signal(SIGALRM, dingdong);
+ alarm(TO);
+ }
+ if ((rval = getname()) == 2) {
+ oflush();
+ alarm(0);
+ execle(PP, "ppplogin", ttyn, (char *) 0, env);
+ syslog(LOG_ERR, "%s: %m", PP);
+ exit(1);
+ } else if (rval) {
+ register int i;
+
+ oflush();
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ if (name[0] == '-') {
+ puts("user names may not start with '-'.");
+ continue;
+ }
+ if (!(upper || lower || digit))
+ continue;
+ setflags(2);
+ if (crmod) {
+ tmode.c_iflag |= ICRNL;
+ tmode.c_oflag |= ONLCR;
+ }
+#if REALLY_OLD_TTYS
+ if (upper || UC)
+ tmode.sg_flags |= LCASE;
+ if (lower || LC)
+ tmode.sg_flags &= ~LCASE;
+#endif
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
+ syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
+ exit(1);
+ }
+ signal(SIGINT, SIG_DFL);
+ for (i = 0; environ[i] != (char *)0; i++)
+ env[i] = environ[i];
+ makeenv(&env[i]);
+
+ limit.rlim_max = RLIM_INFINITY;
+ limit.rlim_cur = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &limit);
+ execle(LO, "login", "-p", name, (char *) 0, env);
+ syslog(LOG_ERR, "%s: %m", LO);
+ exit(1);
+ }
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ signal(SIGINT, SIG_IGN);
+ if (NX && *NX)
+ tname = NX;
+ }
+}
+
+static int
+opentty(const char *ttyn, int flags)
+{
+ int i, j = 0;
+ int failopenlogged = 0;
+
+ while (j < 10 && (i = open(ttyn, flags)) == -1)
+ {
+ if (((j % 10) == 0) && (errno != ENXIO || !failopenlogged)) {
+ syslog(LOG_ERR, "open %s: %m", ttyn);
+ failopenlogged = 1;
+ }
+ j++;
+ sleep(60);
+ }
+ if (i == -1) {
+ syslog(LOG_ERR, "open %s: %m", ttyn);
+ return 0;
+ }
+ else {
+ login_tty(i);
+ return 1;
+ }
+}
+
+static void
+setdefttymode(tname)
+ const char * tname;
+{
+ if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
+ syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
+ exit(1);
+ }
+ tmode.c_iflag = TTYDEF_IFLAG;
+ tmode.c_oflag = TTYDEF_OFLAG;
+ tmode.c_lflag = TTYDEF_LFLAG;
+ tmode.c_cflag = TTYDEF_CFLAG;
+ omode = tmode;
+ setttymode(tname, 1);
+}
+
+static void
+setttymode(tname, raw)
+ const char * tname;
+ int raw;
+{
+ int off = 0;
+
+ gettable(tname, tabent);
+ if (OPset || EPset || APset)
+ APset++, OPset++, EPset++;
+ setdefaults();
+ (void)tcflush(STDIN_FILENO, TCIOFLUSH); /* clear out the crap */
+ ioctl(STDIN_FILENO, FIONBIO, &off); /* turn off non-blocking mode */
+ ioctl(STDIN_FILENO, FIOASYNC, &off); /* ditto for async mode */
+
+ if (IS)
+ cfsetispeed(&tmode, speed(IS));
+ else if (SP)
+ cfsetispeed(&tmode, speed(SP));
+ if (OS)
+ cfsetospeed(&tmode, speed(OS));
+ else if (SP)
+ cfsetospeed(&tmode, speed(SP));
+ setflags(0);
+ setchars();
+ if (raw)
+ cfmakeraw(&tmode);
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
+ syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
+ exit(1);
+ }
+}
+
+
+static int
+getname()
+{
+ register int c;
+ register char *np;
+ unsigned char cs;
+ int ppp_state = 0;
+ int ppp_connection = 0;
+
+ /*
+ * Interrupt may happen if we use CBREAK mode
+ */
+ if (setjmp(intrupt)) {
+ signal(SIGINT, SIG_IGN);
+ return (0);
+ }
+ signal(SIGINT, interrupt);
+ setflags(1);
+ prompt();
+ oflush();
+ if (PF > 0) {
+ sleep(PF);
+ PF = 0;
+ }
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
+ syslog(LOG_ERR, "%s: %m", ttyn);
+ exit(1);
+ }
+ crmod = digit = lower = upper = 0;
+ np = name;
+ for (;;) {
+ oflush();
+ if (read(STDIN_FILENO, &cs, 1) <= 0)
+ exit(0);
+ if ((c = cs&0177) == 0)
+ return (0);
+
+ /* PPP detection state machine..
+ Look for sequences:
+ PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
+ PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
+ See RFC1662.
+ Derived from code from Michael Hancock, <michaelh@cet.co.jp>
+ and Erik 'PPP' Olson, <eriko@wrq.com>
+ */
+
+ if (PP && (cs == PPP_FRAME)) {
+ ppp_state = 1;
+ } else if (ppp_state == 1 && cs == PPP_STATION) {
+ ppp_state = 2;
+ } else if (ppp_state == 2 && cs == PPP_ESCAPE) {
+ ppp_state = 3;
+ } else if ((ppp_state == 2 && cs == PPP_CONTROL)
+ || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
+ ppp_state = 4;
+ } else if (ppp_state == 4 && cs == PPP_LCP_HI) {
+ ppp_state = 5;
+ } else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
+ ppp_connection = 1;
+ break;
+ } else {
+ ppp_state = 0;
+ }
+
+ if (c == EOT || c == CTRL('d'))
+ exit(1);
+ if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
+ putf("\r\n");
+ break;
+ }
+ if (islower(c))
+ lower = 1;
+ else if (isupper(c))
+ upper = 1;
+ else if (c == ERASE || c == '\b' || c == 0177) {
+ if (np > name) {
+ np--;
+ if (cfgetospeed(&tmode) >= 1200)
+ puts("\b \b");
+ else
+ putchr(cs);
+ }
+ continue;
+ } else if (c == KILL || c == CTRL('u')) {
+ putchr('\r');
+ if (cfgetospeed(&tmode) < 1200)
+ putchr('\n');
+ /* this is the way they do it down under ... */
+ else if (np > name)
+ puts(" \r");
+ prompt();
+ np = name;
+ continue;
+ } else if (isdigit(c))
+ digit++;
+ if (IG && (c <= ' ' || c > 0176))
+ continue;
+ *np++ = c;
+ putchr(cs);
+ }
+ signal(SIGINT, SIG_IGN);
+ *np = 0;
+ if (c == '\r')
+ crmod = 1;
+ if ((upper && !lower && !LC) || UC)
+ for (np = name; *np; np++)
+ if (isupper(*np))
+ *np = tolower(*np);
+ return (1 + ppp_connection);
+}
+
+static void
+putpad(s)
+ register const char *s;
+{
+ register pad = 0;
+ speed_t ospeed = cfgetospeed(&tmode);
+
+ if (isdigit(*s)) {
+ while (isdigit(*s)) {
+ pad *= 10;
+ pad += *s++ - '0';
+ }
+ pad *= 10;
+ if (*s == '.' && isdigit(s[1])) {
+ pad += s[1] - '0';
+ s += 2;
+ }
+ }
+
+ puts(s);
+ /*
+ * If no delay needed, or output speed is
+ * not comprehensible, then don't try to delay.
+ */
+ if (pad == 0 || ospeed <= 0)
+ return;
+
+ /*
+ * Round up by a half a character frame, and then do the delay.
+ * Too bad there are no user program accessible programmed delays.
+ * Transmitting pad characters slows many terminals down and also
+ * loads the system.
+ */
+ pad = (pad * ospeed + 50000) / 100000;
+ while (pad--)
+ putchr(*PC);
+}
+
+static void
+puts(s)
+ register const char *s;
+{
+ while (*s)
+ putchr(*s++);
+}
+
+char outbuf[OBUFSIZ];
+int obufcnt = 0;
+
+static void
+putchr(cc)
+ int cc;
+{
+ char c;
+
+ c = cc;
+ if (!NP) {
+ c |= partab[c&0177] & 0200;
+ if (OP)
+ c ^= 0200;
+ }
+ if (!UB) {
+ outbuf[obufcnt++] = c;
+ if (obufcnt >= OBUFSIZ)
+ oflush();
+ } else
+ write(STDOUT_FILENO, &c, 1);
+}
+
+static void
+oflush()
+{
+ if (obufcnt)
+ write(STDOUT_FILENO, outbuf, obufcnt);
+ obufcnt = 0;
+}
+
+static void
+prompt()
+{
+
+ putf(LM);
+ if (CO)
+ putchr('\n');
+}
+
+
+static char *
+getline(fd)
+ int fd;
+{
+ int i = 0;
+ static char linebuf[512];
+
+ /*
+ * This is certainly slow, but it avoids having to include
+ * stdio.h unnecessarily. Issue files should be small anyway.
+ */
+ while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
+ if (linebuf[i] == '\n') {
+ /* Don't rely on newline mode, assume raw */
+ linebuf[i++] = '\r';
+ linebuf[i++] = '\n';
+ linebuf[i] = '\0';
+ return linebuf;
+ }
+ ++i;
+ }
+ linebuf[i] = '\0';
+ return i ? linebuf : 0;
+}
+
+static void
+putf(cp)
+ register const char *cp;
+{
+ extern char editedhost[];
+ time_t t;
+ char *slash, db[100];
+
+ static struct utsname kerninfo;
+
+ if (!*kerninfo.sysname)
+ uname(&kerninfo);
+
+ while (*cp) {
+ if (*cp != '%') {
+ putchr(*cp++);
+ continue;
+ }
+ switch (*++cp) {
+
+ case 't':
+ slash = strrchr(ttyn, '/');
+ if (slash == (char *) 0)
+ puts(ttyn);
+ else
+ puts(&slash[1]);
+ break;
+
+ case 'h':
+ puts(editedhost);
+ break;
+
+ case 'd': {
+ t = (time_t)0;
+ (void)time(&t);
+ if (Lo)
+ (void)setlocale(LC_TIME, Lo);
+ (void)strftime(db, sizeof(db), "%+", localtime(&t));
+ puts(db);
+ break;
+
+ case 's':
+ puts(kerninfo.sysname);
+ break;
+
+ case 'm':
+ puts(kerninfo.machine);
+ break;
+
+ case 'r':
+ puts(kerninfo.release);
+ break;
+
+ case 'v':
+ puts(kerninfo.version);
+ break;
+ }
+
+ case '%':
+ putchr('%');
+ break;
+ }
+ cp++;
+ }
+}
diff --git a/libexec/bugfiler/pathnames.h b/libexec/getty/pathnames.h
index 7ff5ab6..fd397dd 100644
--- a/libexec/bugfiler/pathnames.h
+++ b/libexec/getty/pathnames.h
@@ -30,9 +30,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * from: @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * $Id$
*/
-#define MAIL_CMD "/usr/sbin/sendmail -i -t -F \"Bugs Bunny\" -f owner-bugs"
-#undef _PATH_TMP
-#define _PATH_TMP "/tmp/BUG_XXXXXX"
+#include <paths.h>
+
+#define _PATH_GETTYTAB "/etc/gettytab"
+#define _PATH_LOGIN "/usr/bin/login"
diff --git a/libexec/getty/subr.c b/libexec/getty/subr.c
new file mode 100644
index 0000000..84cbefb
--- /dev/null
+++ b/libexec/getty/subr.c
@@ -0,0 +1,853 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)subr.c 8.1 (Berkeley) 6/4/93";*/
+static char rcsid[] = "$Id: subr.c,v 1.9 1997/02/22 14:21:40 peter Exp $";
+#endif /* not lint */
+
+/*
+ * Melbourne getty.
+ */
+#define COMPAT_43
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <syslog.h>
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#include "gettytab.h"
+#include "pathnames.h"
+#include "extern.h"
+
+
+#ifdef COMPAT_43
+static void compatflags __P((long));
+#endif
+
+/*
+ * Get a table entry.
+ */
+void
+gettable(name, buf)
+ const char *name;
+ char *buf;
+{
+ register struct gettystrs *sp;
+ register struct gettynums *np;
+ register struct gettyflags *fp;
+ long n;
+ int l;
+ char *p;
+ char *msg = NULL;
+ const char *dba[2];
+
+ static int firsttime = 1;
+
+ dba[0] = _PATH_GETTYTAB;
+ dba[1] = 0;
+
+ if (firsttime) {
+ /*
+ * we need to strdup() anything in the strings array
+ * initially in order to simplify things later
+ */
+ for (sp = gettystrs; sp->field; sp++)
+ if (sp->value != NULL) {
+ /* handle these ones more carefully */
+ if (sp >= &gettystrs[4] && sp <= &gettystrs[6])
+ l = 2;
+ else
+ l = strlen(sp->value) + 1;
+ if ((p = malloc(l)) != NULL) {
+ strncpy(p, sp->value, l);
+ p[l-1] = '\0';
+ }
+ /*
+ * replace, even if NULL, else we'll
+ * have problems with free()ing static mem
+ */
+ sp->value = p;
+ }
+ firsttime = 0;
+ }
+
+ switch (cgetent(&buf, (char **)dba, (char *)name)) {
+ case 1:
+ msg = "%s: couldn't resolve 'tc=' in gettytab '%s'";
+ case 0:
+ break;
+ case -1:
+ msg = "%s: unknown gettytab entry '%s'";
+ break;
+ case -2:
+ msg = "%s: retrieving gettytab entry '%s': %m";
+ break;
+ case -3:
+ msg = "%s: recursive 'tc=' reference gettytab entry '%s'";
+ break;
+ default:
+ msg = "%s: unexpected cgetent() error for entry '%s'";
+ break;
+ }
+
+ if (msg != NULL) {
+ syslog(LOG_ERR, msg, "getty", name);
+ return;
+ }
+
+ for (sp = gettystrs; sp->field; sp++) {
+ if ((l = cgetstr(buf, (char*)sp->field, &p)) >= 0) {
+ if (sp->value) {
+ /* prefer existing value */
+ if (strcmp(p, sp->value) != 0)
+ free(sp->value);
+ else {
+ free(p);
+ p = sp->value;
+ }
+ }
+ sp->value = p;
+ } else if (l == -1) {
+ free(sp->value);
+ sp->value = NULL;
+ }
+ }
+
+ for (np = gettynums; np->field; np++) {
+ if (cgetnum(buf, (char*)np->field, &n) == -1)
+ np->set = 0;
+ else {
+ np->set = 1;
+ np->value = n;
+ }
+ }
+
+ for (fp = gettyflags; fp->field; fp++) {
+ if (cgetcap(buf, (char *)fp->field, ':') == NULL)
+ fp->set = 0;
+ else {
+ fp->set = 1;
+ fp->value = 1 ^ fp->invrt;
+ }
+ }
+
+#ifdef DEBUG
+ printf("name=\"%s\", buf=\"%s\"\r\n", name, buf);
+ for (sp = gettystrs; sp->field; sp++)
+ printf("cgetstr: %s=%s\r\n", sp->field, sp->value);
+ for (np = gettynums; np->field; np++)
+ printf("cgetnum: %s=%d\r\n", np->field, np->value);
+ for (fp = gettyflags; fp->field; fp++)
+ printf("cgetflags: %s='%c' set='%c'\r\n", fp->field,
+ fp->value + '0', fp->set + '0');
+#endif /* DEBUG */
+}
+
+void
+gendefaults()
+{
+ register struct gettystrs *sp;
+ register struct gettynums *np;
+ register struct gettyflags *fp;
+
+ for (sp = gettystrs; sp->field; sp++)
+ if (sp->value)
+ sp->defalt = strdup(sp->value);
+ for (np = gettynums; np->field; np++)
+ if (np->set)
+ np->defalt = np->value;
+ for (fp = gettyflags; fp->field; fp++)
+ if (fp->set)
+ fp->defalt = fp->value;
+ else
+ fp->defalt = fp->invrt;
+}
+
+void
+setdefaults()
+{
+ register struct gettystrs *sp;
+ register struct gettynums *np;
+ register struct gettyflags *fp;
+
+ for (sp = gettystrs; sp->field; sp++)
+ if (!sp->value)
+ sp->value = !sp->defalt ? sp->defalt
+ : strdup(sp->defalt);
+ for (np = gettynums; np->field; np++)
+ if (!np->set)
+ np->value = np->defalt;
+ for (fp = gettyflags; fp->field; fp++)
+ if (!fp->set)
+ fp->value = fp->defalt;
+}
+
+static char **
+charnames[] = {
+ &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
+ &SU, &DS, &RP, &FL, &WE, &LN, 0
+};
+
+static char *
+charvars[] = {
+ &tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR],
+ &tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP],
+ &tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP],
+ &tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD],
+ &tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], 0
+};
+
+void
+setchars()
+{
+ register int i;
+ register const char *p;
+
+ for (i = 0; charnames[i]; i++) {
+ p = *charnames[i];
+ if (p && *p)
+ *charvars[i] = *p;
+ else
+ *charvars[i] = _POSIX_VDISABLE;
+ }
+}
+
+/* Macros to clear/set/test flags. */
+#define SET(t, f) (t) |= (f)
+#define CLR(t, f) (t) &= ~(f)
+#define ISSET(t, f) ((t) & (f))
+
+void
+setflags(n)
+ int n;
+{
+ register tcflag_t iflag, oflag, cflag, lflag;
+
+#ifdef COMPAT_43
+ switch (n) {
+ case 0:
+ if (F0set) {
+ compatflags(F0);
+ return;
+ }
+ break;
+ case 1:
+ if (F1set) {
+ compatflags(F1);
+ return;
+ }
+ break;
+ default:
+ if (F2set) {
+ compatflags(F2);
+ return;
+ }
+ break;
+ }
+#endif
+
+ switch (n) {
+ case 0:
+ if (C0set && I0set && L0set && O0set) {
+ tmode.c_cflag = C0;
+ tmode.c_iflag = I0;
+ tmode.c_lflag = L0;
+ tmode.c_oflag = O0;
+ return;
+ }
+ break;
+ case 1:
+ if (C1set && I1set && L1set && O1set) {
+ tmode.c_cflag = C1;
+ tmode.c_iflag = I1;
+ tmode.c_lflag = L1;
+ tmode.c_oflag = O1;
+ return;
+ }
+ break;
+ default:
+ if (C2set && I2set && L2set && O2set) {
+ tmode.c_cflag = C2;
+ tmode.c_iflag = I2;
+ tmode.c_lflag = L2;
+ tmode.c_oflag = O2;
+ return;
+ }
+ break;
+ }
+
+ iflag = omode.c_iflag;
+ oflag = omode.c_oflag;
+ cflag = omode.c_cflag;
+ lflag = omode.c_lflag;
+
+ if (NP) {
+ CLR(cflag, CSIZE|PARENB);
+ SET(cflag, CS8);
+ CLR(iflag, ISTRIP|INPCK|IGNPAR);
+ } else if (AP || EP || OP) {
+ CLR(cflag, CSIZE);
+ SET(cflag, CS7|PARENB);
+ SET(iflag, ISTRIP);
+ if (OP && !EP) {
+ SET(iflag, INPCK|IGNPAR);
+ SET(cflag, PARODD);
+ if (AP)
+ CLR(iflag, INPCK);
+ } else if (EP && !OP) {
+ SET(iflag, INPCK|IGNPAR);
+ CLR(cflag, PARODD);
+ if (AP)
+ CLR(iflag, INPCK);
+ } else if (AP || (EP && OP)) {
+ CLR(iflag, INPCK|IGNPAR);
+ CLR(cflag, PARODD);
+ }
+ } /* else, leave as is */
+
+#if 0
+ if (UC)
+ f |= LCASE;
+#endif
+
+ if (HC)
+ SET(cflag, HUPCL);
+ else
+ CLR(cflag, HUPCL);
+
+ if (MB)
+ SET(cflag, MDMBUF);
+ else
+ CLR(cflag, MDMBUF);
+
+ if (HW)
+ SET(cflag, CRTSCTS);
+ else
+ CLR(cflag, CRTSCTS);
+
+ if (NL) {
+ SET(iflag, ICRNL);
+ SET(oflag, ONLCR|OPOST);
+ } else {
+ CLR(iflag, ICRNL);
+ CLR(oflag, ONLCR);
+ }
+
+ if (!HT)
+ SET(oflag, OXTABS|OPOST);
+ else
+ CLR(oflag, OXTABS);
+
+#ifdef XXX_DELAY
+ SET(f, delaybits());
+#endif
+
+ if (n == 1) { /* read mode flags */
+ if (RW) {
+ iflag = 0;
+ CLR(oflag, OPOST);
+ CLR(cflag, CSIZE|PARENB);
+ SET(cflag, CS8);
+ lflag = 0;
+ } else {
+ CLR(lflag, ICANON);
+ }
+ goto out;
+ }
+
+ if (n == 0)
+ goto out;
+
+#if 0
+ if (CB)
+ SET(f, CRTBS);
+#endif
+
+ if (CE)
+ SET(lflag, ECHOE);
+ else
+ CLR(lflag, ECHOE);
+
+ if (CK)
+ SET(lflag, ECHOKE);
+ else
+ CLR(lflag, ECHOKE);
+
+ if (PE)
+ SET(lflag, ECHOPRT);
+ else
+ CLR(lflag, ECHOPRT);
+
+ if (EC)
+ SET(lflag, ECHO);
+ else
+ CLR(lflag, ECHO);
+
+ if (XC)
+ SET(lflag, ECHOCTL);
+ else
+ CLR(lflag, ECHOCTL);
+
+ if (DX)
+ SET(lflag, IXANY);
+ else
+ CLR(lflag, IXANY);
+
+out:
+ tmode.c_iflag = iflag;
+ tmode.c_oflag = oflag;
+ tmode.c_cflag = cflag;
+ tmode.c_lflag = lflag;
+}
+
+#ifdef COMPAT_43
+/*
+ * Old TTY => termios, snatched from <sys/kern/tty_compat.c>
+ */
+void
+compatflags(flags)
+register long flags;
+{
+ register tcflag_t iflag, oflag, cflag, lflag;
+
+ iflag = BRKINT|ICRNL|IMAXBEL|IXON|IXANY;
+ oflag = OPOST|ONLCR|OXTABS;
+ cflag = CREAD;
+ lflag = ICANON|ISIG|IEXTEN;
+
+ if (ISSET(flags, TANDEM))
+ SET(iflag, IXOFF);
+ else
+ CLR(iflag, IXOFF);
+ if (ISSET(flags, ECHO))
+ SET(lflag, ECHO);
+ else
+ CLR(lflag, ECHO);
+ if (ISSET(flags, CRMOD)) {
+ SET(iflag, ICRNL);
+ SET(oflag, ONLCR);
+ } else {
+ CLR(iflag, ICRNL);
+ CLR(oflag, ONLCR);
+ }
+ if (ISSET(flags, XTABS))
+ SET(oflag, OXTABS);
+ else
+ CLR(oflag, OXTABS);
+
+
+ if (ISSET(flags, RAW)) {
+ iflag &= IXOFF;
+ CLR(lflag, ISIG|ICANON|IEXTEN);
+ CLR(cflag, PARENB);
+ } else {
+ SET(iflag, BRKINT|IXON|IMAXBEL);
+ SET(lflag, ISIG|IEXTEN);
+ if (ISSET(flags, CBREAK))
+ CLR(lflag, ICANON);
+ else
+ SET(lflag, ICANON);
+ switch (ISSET(flags, ANYP)) {
+ case 0:
+ CLR(cflag, PARENB);
+ break;
+ case ANYP:
+ SET(cflag, PARENB);
+ CLR(iflag, INPCK);
+ break;
+ case EVENP:
+ SET(cflag, PARENB);
+ SET(iflag, INPCK);
+ CLR(cflag, PARODD);
+ break;
+ case ODDP:
+ SET(cflag, PARENB);
+ SET(iflag, INPCK);
+ SET(cflag, PARODD);
+ break;
+ }
+ }
+
+ /* Nothing we can do with CRTBS. */
+ if (ISSET(flags, PRTERA))
+ SET(lflag, ECHOPRT);
+ else
+ CLR(lflag, ECHOPRT);
+ if (ISSET(flags, CRTERA))
+ SET(lflag, ECHOE);
+ else
+ CLR(lflag, ECHOE);
+ /* Nothing we can do with TILDE. */
+ if (ISSET(flags, MDMBUF))
+ SET(cflag, MDMBUF);
+ else
+ CLR(cflag, MDMBUF);
+ if (ISSET(flags, NOHANG))
+ CLR(cflag, HUPCL);
+ else
+ SET(cflag, HUPCL);
+ if (ISSET(flags, CRTKIL))
+ SET(lflag, ECHOKE);
+ else
+ CLR(lflag, ECHOKE);
+ if (ISSET(flags, CTLECH))
+ SET(lflag, ECHOCTL);
+ else
+ CLR(lflag, ECHOCTL);
+ if (!ISSET(flags, DECCTQ))
+ SET(iflag, IXANY);
+ else
+ CLR(iflag, IXANY);
+ CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH);
+ SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH));
+
+ if (ISSET(flags, RAW|LITOUT|PASS8)) {
+ CLR(cflag, CSIZE);
+ SET(cflag, CS8);
+ if (!ISSET(flags, RAW|PASS8))
+ SET(iflag, ISTRIP);
+ else
+ CLR(iflag, ISTRIP);
+ if (!ISSET(flags, RAW|LITOUT))
+ SET(oflag, OPOST);
+ else
+ CLR(oflag, OPOST);
+ } else {
+ CLR(cflag, CSIZE);
+ SET(cflag, CS7);
+ SET(iflag, ISTRIP);
+ SET(oflag, OPOST);
+ }
+
+ tmode.c_iflag = iflag;
+ tmode.c_oflag = oflag;
+ tmode.c_cflag = cflag;
+ tmode.c_lflag = lflag;
+}
+#endif
+
+#ifdef XXX_DELAY
+struct delayval {
+ unsigned delay; /* delay in ms */
+ int bits;
+};
+
+/*
+ * below are random guesses, I can't be bothered checking
+ */
+
+struct delayval crdelay[] = {
+ { 1, CR1 },
+ { 2, CR2 },
+ { 3, CR3 },
+ { 83, CR1 },
+ { 166, CR2 },
+ { 0, CR3 },
+};
+
+struct delayval nldelay[] = {
+ { 1, NL1 }, /* special, calculated */
+ { 2, NL2 },
+ { 3, NL3 },
+ { 100, NL2 },
+ { 0, NL3 },
+};
+
+struct delayval bsdelay[] = {
+ { 1, BS1 },
+ { 0, 0 },
+};
+
+struct delayval ffdelay[] = {
+ { 1, FF1 },
+ { 1750, FF1 },
+ { 0, FF1 },
+};
+
+struct delayval tbdelay[] = {
+ { 1, TAB1 },
+ { 2, TAB2 },
+ { 3, XTABS }, /* this is expand tabs */
+ { 100, TAB1 },
+ { 0, TAB2 },
+};
+
+int
+delaybits()
+{
+ register int f;
+
+ f = adelay(CD, crdelay);
+ f |= adelay(ND, nldelay);
+ f |= adelay(FD, ffdelay);
+ f |= adelay(TD, tbdelay);
+ f |= adelay(BD, bsdelay);
+ return (f);
+}
+
+int
+adelay(ms, dp)
+ register ms;
+ register struct delayval *dp;
+{
+ if (ms == 0)
+ return (0);
+ while (dp->delay && ms > dp->delay)
+ dp++;
+ return (dp->bits);
+}
+#endif
+
+char editedhost[MAXHOSTNAMELEN];
+
+void
+edithost(pat)
+ register const char *pat;
+{
+ register const char *host = HN;
+ register char *res = editedhost;
+
+ if (!pat)
+ pat = "";
+ while (*pat) {
+ switch (*pat) {
+
+ case '#':
+ if (*host)
+ host++;
+ break;
+
+ case '@':
+ if (*host)
+ *res++ = *host++;
+ break;
+
+ default:
+ *res++ = *pat;
+ break;
+
+ }
+ if (res == &editedhost[sizeof editedhost - 1]) {
+ *res = '\0';
+ return;
+ }
+ pat++;
+ }
+ if (*host)
+ strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
+ else
+ *res = '\0';
+ editedhost[sizeof editedhost - 1] = '\0';
+}
+
+static struct speedtab {
+ int speed;
+ int uxname;
+} speedtab[] = {
+ { 50, B50 },
+ { 75, B75 },
+ { 110, B110 },
+ { 134, B134 },
+ { 150, B150 },
+ { 200, B200 },
+ { 300, B300 },
+ { 600, B600 },
+ { 1200, B1200 },
+ { 1800, B1800 },
+ { 2400, B2400 },
+ { 4800, B4800 },
+ { 9600, B9600 },
+ { 19200, EXTA },
+ { 19, EXTA }, /* for people who say 19.2K */
+ { 38400, EXTB },
+ { 38, EXTB },
+ { 7200, EXTB }, /* alternative */
+ { 57600, B57600 },
+ { 115200, B115200 },
+ { 0 }
+};
+
+int
+speed(val)
+ int val;
+{
+ register struct speedtab *sp;
+
+ if (val <= B115200)
+ return (val);
+
+ for (sp = speedtab; sp->speed; sp++)
+ if (sp->speed == val)
+ return (sp->uxname);
+
+ return (B300); /* default in impossible cases */
+}
+
+void
+makeenv(env)
+ char *env[];
+{
+ static char termbuf[128] = "TERM=";
+ register char *p, *q;
+ register char **ep;
+
+ ep = env;
+ if (TT && *TT) {
+ strcat(termbuf, TT);
+ *ep++ = termbuf;
+ }
+ if ((p = EV)) {
+ q = p;
+ while ((q = strchr(q, ','))) {
+ *q++ = '\0';
+ *ep++ = p;
+ p = q;
+ }
+ if (*p)
+ *ep++ = p;
+ }
+ *ep = (char *)0;
+}
+
+/*
+ * This speed select mechanism is written for the Develcon DATASWITCH.
+ * The Develcon sends a string of the form "B{speed}\n" at a predefined
+ * baud rate. This string indicates the user's actual speed.
+ * The routine below returns the terminal type mapped from derived speed.
+ */
+struct portselect {
+ const char *ps_baud;
+ const char *ps_type;
+} portspeeds[] = {
+ { "B110", "std.110" },
+ { "B134", "std.134" },
+ { "B150", "std.150" },
+ { "B300", "std.300" },
+ { "B600", "std.600" },
+ { "B1200", "std.1200" },
+ { "B2400", "std.2400" },
+ { "B4800", "std.4800" },
+ { "B9600", "std.9600" },
+ { "B19200", "std.19200" },
+ { 0 }
+};
+
+const char *
+portselector()
+{
+ char c, baud[20];
+ const char *type = "default";
+ register struct portselect *ps;
+ int len;
+
+ alarm(5*60);
+ for (len = 0; len < sizeof (baud) - 1; len++) {
+ if (read(STDIN_FILENO, &c, 1) <= 0)
+ break;
+ c &= 0177;
+ if (c == '\n' || c == '\r')
+ break;
+ if (c == 'B')
+ len = 0; /* in case of leading garbage */
+ baud[len] = c;
+ }
+ baud[len] = '\0';
+ for (ps = portspeeds; ps->ps_baud; ps++)
+ if (strcmp(ps->ps_baud, baud) == 0) {
+ type = ps->ps_type;
+ break;
+ }
+ sleep(2); /* wait for connection to complete */
+ return (type);
+}
+
+/*
+ * This auto-baud speed select mechanism is written for the Micom 600
+ * portselector. Selection is done by looking at how the character '\r'
+ * is garbled at the different speeds.
+ */
+#include <sys/time.h>
+
+const char *
+autobaud()
+{
+ int rfds;
+ struct timeval timeout;
+ char c;
+ const char *type = "9600-baud";
+
+ (void)tcflush(0, TCIOFLUSH);
+ rfds = 1 << 0;
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
+ (fd_set *)NULL, &timeout) <= 0)
+ return (type);
+ if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
+ return (type);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 20;
+ (void) select(32, (fd_set *)NULL, (fd_set *)NULL,
+ (fd_set *)NULL, &timeout);
+ (void)tcflush(0, TCIOFLUSH);
+ switch (c & 0377) {
+
+ case 0200: /* 300-baud */
+ type = "300-baud";
+ break;
+
+ case 0346: /* 1200-baud */
+ type = "1200-baud";
+ break;
+
+ case 015: /* 2400-baud */
+ case 0215:
+ type = "2400-baud";
+ break;
+
+ default: /* 4800-baud */
+ type = "4800-baud";
+ break;
+
+ case 0377: /* 9600-baud */
+ type = "9600-baud";
+ break;
+ }
+ return (type);
+}
diff --git a/libexec/getty/ttys.5 b/libexec/getty/ttys.5
new file mode 100644
index 0000000..4130ab8
--- /dev/null
+++ b/libexec/getty/ttys.5
@@ -0,0 +1,163 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)ttys.5 8.1 (Berkeley) 6/4/93
+.\" $Id: ttys.5,v 1.7 1997/04/13 21:29:50 davidn Exp $
+.\" "
+.Dd November 17, 1996
+.Dt TTYS 5
+.Os
+.Sh NAME
+.Nm ttys
+.Nd terminal initialization information
+.Sh DESCRIPTION
+The file
+.Nm ttys
+contains information that is used by various routines to initialize
+and control the use of terminal special files.
+This information is read with the
+.Xr getttyent 3
+library routines.
+There is one line in the
+.Nm ttys
+file per special device file.
+Fields are separated by tabs and/or spaces.
+Fields comprised of more than one word should be enclosed in double
+quotes (``"'').
+Blank lines and comments may appear anywhere in the file; comments
+are delimited by hash marks (``#'') and new lines.
+Any unspecified fields will default to null.
+.Pp
+The first field is the
+name of the terminal special file as it is found in
+.Pa /dev .
+.Pp
+The second field of the file is the command to execute for the line,
+usually
+.Xr getty 8 ,
+which initializes and opens the line, setting the speed, waiting for
+a user name and executing the
+.Xr login 1
+program.
+It can be, however, any desired command, for example
+the start up for a window system terminal emulator or some other
+daemon process, and can contain multiple words if quoted.
+.Pp
+The third field is the type of terminal usually connected to that
+tty line, normally the one found in the
+.Xr termcap 5
+data base file.
+The environment variable
+.Dv TERM
+is initialized with the value by
+either
+.Xr getty 8
+or
+.Xr login 1 .
+.Pp
+The remaining fields set flags in the
+.Fa ty_status
+entry (see
+.Xr getttyent 3 ),
+specify a window system process that
+.Xr init 8
+will maintain for the terminal line, optionally determine the
+type of tty (whether dialin, network or otherwise),
+or specify a tty group
+name that allows the login class database (see
+.Xr login.conf 5 )
+to refer to many ttys as a group, to selectively allow or
+deny access or enable or disable accounting facilities for
+ttys as a group.
+.Pp
+As flag values, the strings ``on'' and ``off'' specify that
+.Xr init
+should (should not) execute the command given in the second field,
+while ``secure'' (if ``on'' is also specified) allows users with a
+uid of 0 to login on
+this line.
+The flag ``dialin'' indicates that a tty entry describes a dialin
+line, and ``network'' indicates that a tty entry provides a
+network connection.
+Either of these strings may also be specified in the terminal type
+field.
+The string ``window='' may be followed by a quoted command
+string which
+.Xr init
+will execute
+.Em before
+starting the command specified by the second field.
+.Pp
+The string ``group='' may be followed by a group name comprised of
+alphanumeric characters that can be used by
+.Xr login.conf 5
+to refer to many tty lines as a group to enable or disable access
+and accounting facilities.
+If no group is specified, then the tty becomes a member of the group
+"none".
+For backwards compatibility, the ``group='' should appear last on the
+line, immediately before the optional comment.
+.Sh EXAMPLES
+.Bd -literal
+# root login on console at 1200 baud
+console "/usr/libexec/getty std.1200" vt100 on secure
+# dialup at 1200 baud, no root logins
+ttyd0 "/usr/libexec/getty d1200" dialup on group=dialup # 555-1234
+# Mike's terminal: hp2621
+ttyh0 "/usr/libexec/getty std.9600" hp2621-nl on group=dialup # 457 Evans
+# John's terminal: vt100
+ttyh1 "/usr/libexec/getty std.9600" vt100 on group=dialup # 459 Evans
+# terminal emulate/window system
+ttyv0 "/usr/new/xterm -L :0" vs100 on window="/usr/new/Xvs100 0"
+# Network pseudo ttys -- don't enable getty
+ttyp0 none network group=pty
+ttyp1 none network off group=pty
+.Ed
+.Sh FILES
+.Bl -tag -width /etc/ttys -compact
+.It Pa /etc/ttys
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr getttyent 3 ,
+.Xr ttyslot 3 ,
+.Xr gettytab 5 ,
+.Xr login.conf 5 ,
+.Xr termcap 5 ,
+.Xr getty 8 ,
+.Xr init 8
+.\".Xr init 8 ,
+.\".Xr ttyflags 8
+.Sh HISTORY
+A
+.Nm
+file appeared in
+.At v6 .
diff --git a/libexec/kpasswdd/Makefile b/libexec/kpasswdd/Makefile
deleted file mode 100644
index a01cbf8..0000000
--- a/libexec/kpasswdd/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# @(#)Makefile 8.1 (Berkeley) 6/4/93
-
-PROG= kpasswdd
-SRCS= kpasswdd.c des_rw.c
-CFLAGS+=-DCRYPT -DKERBEROS -I${.CURDIR}/../../usr.bin/passwd
-DPADD= ${LIBKDB} ${LIBKRB} ${LIBDES}
-LDADD= -lkdb -lkrb -ldes
-.PATH: ${.CURDIR}/../../usr.bin/rlogin
-MAN8= kpasswdd.0
-
-.include <bsd.prog.mk>
diff --git a/libexec/kpasswdd/kpasswdd.c b/libexec/kpasswdd/kpasswdd.c
deleted file mode 100644
index 23ff1f8..0000000
--- a/libexec/kpasswdd/kpasswdd.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1990, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)kpasswdd.c 8.1 (Berkeley) 6/4/93";
-#endif /* not lint */
-
-/*
- * kpasswdd - update a principal's passwd field in the Kerberos
- * database. Called from inetd.
- * K. Fall
- * 12-Dec-88
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/signal.h>
-#include <netinet/in.h>
-#include <pwd.h>
-#include <syslog.h>
-#include <kerberosIV/des.h>
-#include <kerberosIV/krb.h>
-#include <kerberosIV/krb_db.h>
-#include <stdio.h>
-#include "kpasswd_proto.h"
-
-static struct kpasswd_data kpwd_data;
-static des_cblock master_key, key;
-static Key_schedule master_key_schedule,
- key_schedule, random_sched;
-long mkeyversion;
-AUTH_DAT kdata;
-static Principal principal_data;
-static struct update_data ud_data;
-
-char inst[INST_SZ];
-char version[9];
-KTEXT_ST ticket;
-
-char *progname; /* for the library */
-
-main()
-{
- struct sockaddr_in foreign;
- int foreign_len = sizeof(foreign);
- int rval, more;
- static char name[] = "kpasswdd";
-
- static struct rlimit rl = { 0, 0 };
-
- progname = name;
- openlog("kpasswdd", LOG_CONS | LOG_PID, LOG_AUTH);
-
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- signal(SIGTSTP, SIG_IGN);
- if (setrlimit(RLIMIT_CORE, &rl) < 0) {
- syslog(LOG_ERR, "setrlimit: %m");
- exit(1);
- }
-
- if (getpeername(0, &foreign, &foreign_len) < 0) {
- syslog(LOG_ERR,"getpeername: %m");
- exit(1);
- }
-
- strcpy(inst, "*");
- rval = krb_recvauth(
- 0L, /* options--!MUTUAL */
- 0, /* file desc */
- &ticket, /* client's ticket */
- SERVICE, /* expected service */
- inst, /* expected instance */
- &foreign, /* foreign addr */
- (struct sockaddr_in *) 0, /* local addr */
- &kdata, /* returned krb data */
- "", /* service keys file */
- (bit_64 *) NULL, /* returned key schedule */
- version
- );
-
-
- if (rval != KSUCCESS) {
- syslog(LOG_NOTICE, "krb_recvauth: %s", krb_err_txt[rval]);
- cleanup();
- exit(1);
- }
-
- if (*version == '\0') {
- /* indicates error on client's side (no tickets, etc.) */
- cleanup();
- exit(0);
- } else if (strcmp(version, "KPWDV0.1") != 0) {
- syslog(LOG_NOTICE,
- "kpasswdd version conflict (recv'd %s)",
- version);
- cleanup();
- exit(1);
- }
-
-
- /* get master key */
- if (kdb_get_master_key(0, master_key, master_key_schedule) != 0) {
- syslog(LOG_ERR, "couldn't get master key");
- cleanup();
- exit(1);
- }
-
- mkeyversion = kdb_get_master_key(NULL, master_key, master_key_schedule);
-
- if (mkeyversion < 0) {
- syslog(LOG_NOTICE, "couldn't verify master key");
- cleanup();
- exit(1);
- }
-
- /* get principal info */
- rval = kerb_get_principal(
- kdata.pname,
- kdata.pinst,
- &principal_data,
- 1,
- &more
- );
-
- if (rval < 0) {
- syslog(LOG_NOTICE,
- "error retrieving principal record for %s.%s",
- kdata.pname, kdata.pinst);
- cleanup();
- exit(1);
- }
-
- if (rval != 1 || (more != 0)) {
- syslog(LOG_NOTICE, "more than 1 dbase entry for %s.%s",
- kdata.pname, kdata.pinst);
- cleanup();
- exit(1);
- }
-
- /* get the user's key */
-
- bcopy(&principal_data.key_low, key, 4);
- bcopy(&principal_data.key_high, ((long *) key) + 1, 4);
- kdb_encrypt_key(key, key, master_key, master_key_schedule,
- DECRYPT);
- key_sched(key, key_schedule);
- des_set_key(key, key_schedule);
-
-
- /* get random key and send it over {random} Kperson */
-
- random_key(kpwd_data.random_key);
- strcpy(kpwd_data.secure_msg, SECURE_STRING);
- if (des_write(0, &kpwd_data, sizeof(kpwd_data)) != sizeof(kpwd_data)) {
- syslog(LOG_NOTICE, "error writing initial data");
- cleanup();
- exit(1);
- }
-
- bzero(key, sizeof(key));
- bzero(key_schedule, sizeof(key_schedule));
-
- /* now read update info: { info }Krandom */
-
- key_sched(kpwd_data.random_key, random_sched);
- des_set_key(kpwd_data.random_key, random_sched);
- if (des_read(0, &ud_data, sizeof(ud_data)) != sizeof(ud_data)) {
- syslog(LOG_NOTICE, "update aborted");
- cleanup();
- exit(1);
- }
-
- /* validate info string by looking at the embedded string */
-
- if (strcmp(ud_data.secure_msg, SECURE_STRING) != 0) {
- syslog(LOG_NOTICE, "invalid update from %s",
- inet_ntoa(foreign.sin_addr));
- cleanup();
- exit(1);
- }
-
- /* produce the new key entry in the database { key }Kmaster */
- string_to_key(ud_data.pw, key);
- kdb_encrypt_key(key, key,
- master_key, master_key_schedule,
- ENCRYPT);
- bcopy(key, &principal_data.key_low, 4);
- bcopy(((long *) key) + 1,
- &principal_data.key_high, 4);
- bzero(key, sizeof(key));
- principal_data.key_version++;
- if (kerb_put_principal(&principal_data, 1)) {
- syslog(LOG_ERR, "couldn't write new record for %s.%s",
- principal_data.name, principal_data.instance);
- cleanup();
- exit(1);
- }
-
- syslog(LOG_NOTICE,"wrote new password field for %s.%s from %s",
- principal_data.name,
- principal_data.instance,
- inet_ntoa(foreign.sin_addr)
- );
-
- send_ack(0, "Update complete.\n");
- cleanup();
- exit(0);
-}
-
-cleanup()
-{
- bzero(&kpwd_data, sizeof(kpwd_data));
- bzero(master_key, sizeof(master_key));
- bzero(master_key_schedule, sizeof(master_key_schedule));
- bzero(key, sizeof(key));
- bzero(key_schedule, sizeof(key_schedule));
- bzero(random_sched, sizeof(random_sched));
- bzero(&principal_data, sizeof(principal_data));
- bzero(&ud_data, sizeof(ud_data));
-}
-
-send_ack(remote, msg)
- int remote;
- char *msg;
-{
- int cc;
- cc = des_write(remote, msg, strlen(msg) + 1);
- if (cc <= 0) {
- syslog(LOG_NOTICE, "error writing ack");
- cleanup();
- exit(1);
- }
-}
diff --git a/libexec/lfs_cleanerd/Makefile b/libexec/lfs_cleanerd/Makefile
index 6993cf7..cda9236 100644
--- a/libexec/lfs_cleanerd/Makefile
+++ b/libexec/lfs_cleanerd/Makefile
@@ -1,10 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/5/93
+# $Id$
PROG= lfs_cleanerd
-CFLAGS+=-I/sys/ufs/lfs -I${.CURDIR} -DDIAGNOSTIC
-MAN8= lfs_cleanerd.0
+CFLAGS+=-I/sys/ufs/lfs -I${.CURDIR} ${DEBUG}
+MAN8= lfs_cleanerd.8
SRCS= cleanerd.c lfs_cksum.c library.c misc.c print.c
-.PATH: /sys/ufs/lfs
+.PATH: ${.CURDIR}/../../sys/ufs/lfs
.include <bsd.prog.mk>
diff --git a/libexec/lfs_cleanerd/clean.h b/libexec/lfs_cleanerd/clean.h
index f735ea1..b28cffe 100644
--- a/libexec/lfs_cleanerd/clean.h
+++ b/libexec/lfs_cleanerd/clean.h
@@ -30,7 +30,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)clean.h 8.2 (Berkeley) 5/4/95
+ * @(#)clean.h 8.1 (Berkeley) 6/4/93
+ * $Id$
*/
/*
@@ -63,7 +64,7 @@
#define BUSY_LIM 0.50
#define IDLE_LIM 0.90
-#define MIN_SEGS(lfsp) (3)
+#define MIN_SEGS(lfsp) (5)
#define NUM_TO_CLEAN(fsp) (1)
#define MAXLOADS 3
@@ -82,9 +83,9 @@ typedef struct fs_info {
off_t fi_ifile_length; /* length of the ifile */
} FS_INFO;
-/*
+/*
* XXX: size (in bytes) of a segment
- * should lfs_bsize be fsbtodb(fs,1), blksize(fs), or lfs_dsize?
+ * should lfs_bsize be fsbtodb(fs,1), blksize(fs), or lfs_dsize?
*/
#define seg_size(fs) ((fs)->lfs_ssize << (fs)->lfs_bshift)
@@ -106,7 +107,7 @@ typedef struct fs_info {
__BEGIN_DECLS
int dump_summary __P((struct lfs *, SEGSUM *, u_long, daddr_t **));
void err __P((const int, const char *, ...));
-int fs_getmntinfo __P((struct statfs **, char *, char *));
+int fs_getmntinfo __P((struct statfs **, char *, int));
int get __P((int, off_t, void *, size_t));
FS_INFO *get_fs_info __P((struct statfs *, int));
int lfs_segmapv __P((FS_INFO *, int, caddr_t, BLOCK_INFO **, int *));
diff --git a/libexec/lfs_cleanerd/cleanerd.c b/libexec/lfs_cleanerd/cleanerd.c
index 6d06d75..f8877a8 100644
--- a/libexec/lfs_cleanerd/cleanerd.c
+++ b/libexec/lfs_cleanerd/cleanerd.c
@@ -29,6 +29,8 @@
* 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: cleanerd.c,v 1.6 1997/02/22 14:21:44 peter Exp $
*/
#ifndef lint
@@ -38,7 +40,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)cleanerd.c 8.5 (Berkeley) 6/10/95";
+static char sccsid[] = "@(#)cleanerd.c 8.2 (Berkeley) 1/13/94";
#endif /* not lint */
#include <sys/param.h>
@@ -57,10 +59,7 @@ static char sccsid[] = "@(#)cleanerd.c 8.5 (Berkeley) 6/10/95";
char *special = "cleanerd";
int do_small = 0;
int do_mmap = 0;
-int stat_report = 0;
struct cleaner_stats {
- double util_tot;
- double util_sos;
int blocks_read;
int blocks_written;
int segs_cleaned;
@@ -68,10 +67,10 @@ struct cleaner_stats {
int segs_error;
} cleaner_stats;
-struct seglist {
+struct seglist {
int sl_id; /* segment number */
int sl_cost; /* cleaning cost */
- char sl_bytes; /* bytes in segment */
+ char sl_empty; /* is segment empty */
};
struct tossstruct {
@@ -79,8 +78,6 @@ struct tossstruct {
int seg;
};
-#define CLEAN_BYTES 0x1
-
/* function prototypes for system calls; not sure where they should go */
int lfs_segwait __P((fsid_t *, struct timeval *));
int lfs_segclean __P((fsid_t *, u_long));
@@ -89,10 +86,10 @@ int lfs_markv __P((fsid_t *, BLOCK_INFO *, int));
/* function prototypes */
int bi_tossold __P((const void *, const void *, const void *));
-int choose_segments __P((FS_INFO *, struct seglist *,
+int choose_segments __P((FS_INFO *, struct seglist *,
int (*)(FS_INFO *, SEGUSE *)));
-void clean_fs __P((FS_INFO *, int (*)(FS_INFO *, SEGUSE *), int, long));
-int clean_loop __P((FS_INFO *, int, long));
+void clean_fs __P((FS_INFO *, int (*)(FS_INFO *, SEGUSE *)));
+int clean_loop __P((FS_INFO *));
int clean_segment __P((FS_INFO *, int));
int cost_benefit __P((FS_INFO *, SEGUSE *));
int cost_compare __P((const void *, const void *));
@@ -122,14 +119,14 @@ cost_benefit(fsp, su)
gettimeofday(&t, NULL);
- live = su->su_nbytes;
+ live = su->su_nbytes;
age = t.tv_sec < su->su_lastmod ? 0 : t.tv_sec - su->su_lastmod;
-
+
lfsp = &fsp->fi_lfs;
if (live == 0)
return (t.tv_sec * lblkno(lfsp, seg_size(lfsp)));
else {
- /*
+ /*
* from lfsSegUsage.c (Mendel's code).
* priority calculation is done using INTEGER arithmetic.
* sizes are in BLOCKS (that is why we use lblkno below).
@@ -157,37 +154,22 @@ main(argc, argv)
struct statfs *lstatfsp; /* file system stats */
struct timeval timeout; /* sleep timeout */
fsid_t fsid;
- long clean_opts; /* cleaning options */
- int i, nodaemon, segs_per_clean;
+ int i, nodaemon;
int opt, cmd_err;
char *fs_name; /* name of filesystem to clean */
extern int optind;
cmd_err = nodaemon = 0;
- clean_opts = 0;
- segs_per_clean = 1;
- while ((opt = getopt(argc, argv, "bdmn:r:s")) != EOF) {
+ while ((opt = getopt(argc, argv, "smd")) != -1) {
switch (opt) {
- case 'b': /*
- * Use live bytes to determine
- * how many segs to clean.
- */
- clean_opts |= CLEAN_BYTES;
- break;
- case 'd': /* Debug mode. */
- nodaemon = 1;
+ case 's': /* small writes */
+ do_small = 1;
break;
- case 'm': /* Use mmap instead of read/write */
+ case 'm':
do_mmap = 1;
break;
- case 'n': /* How many segs to clean at once */
- segs_per_clean = atoi(optarg);
- break;
- case 'r': /* Report every stat_report segments */
- stat_report = atoi(optarg);
- break;
- case 's': /* small writes */
- do_small = 1;
+ case 'd':
+ nodaemon = 1;
break;
default:
++cmd_err;
@@ -203,7 +185,7 @@ main(argc, argv)
signal(SIGINT, sig_report);
signal(SIGUSR1, sig_report);
signal(SIGUSR2, sig_report);
- if (fs_getmntinfo(&lstatfsp, fs_name, "lfs") == 0) {
+ if (fs_getmntinfo(&lstatfsp, fs_name, MOUNT_LFS) == 0) {
/* didn't find the filesystem */
err(1, "lfs_cleanerd: filesystem %s isn't an LFS!", fs_name);
}
@@ -225,14 +207,14 @@ main(argc, argv)
* to make sure that some nasty process hasn't just
* filled the disk system up.
*/
- if (clean_loop(fsp, segs_per_clean, clean_opts))
+ if (clean_loop(fsp))
continue;
#ifdef VERBOSE
(void)printf("Cleaner going to sleep.\n");
#endif
if (lfs_segwait(&fsid, &timeout) < 0)
- err(0, "lfs_segwait: returned error\n");
+ err(0, "lfs_segwait: returned error\n");
#ifdef VERBOSE
(void)printf("Cleaner waking up.\n");
#endif
@@ -241,45 +223,33 @@ main(argc, argv)
/* return the number of segments cleaned */
int
-clean_loop(fsp, nsegs, options)
+clean_loop(fsp)
FS_INFO *fsp; /* file system information */
- int nsegs;
- long options;
{
double loadavg[MAXLOADS];
time_t now;
u_long max_free_segs;
- u_long db_per_seg;
/*
* Compute the maximum possible number of free segments, given the
* number of free blocks.
*/
- db_per_seg = fsbtodb(&fsp->fi_lfs, fsp->fi_lfs.lfs_ssize);
- max_free_segs = fsp->fi_lfs.lfs_bfree / db_per_seg;
-
- /*
+ max_free_segs = fsp->fi_statfsp->f_bfree / fsp->fi_lfs.lfs_ssize;
+
+ /*
* We will clean if there are not enough free blocks or total clean
* space is less than BUSY_LIM % of possible clean space.
*/
now = time((time_t *)NULL);
-#ifdef VERBOSE
- printf("db_er_seg = %d max_free_segs = %d, bfree = %d avail = %d ",
- db_per_seg, max_free_segs, fsp->fi_lfs.lfs_bfree,
- fsp->fi_lfs.lfs_avail);
- printf("clean = %d\n", fsp->fi_cip->clean);
-#endif
- if ((fsp->fi_lfs.lfs_bfree - fsp->fi_lfs.lfs_avail > db_per_seg &&
- fsp->fi_lfs.lfs_avail < db_per_seg) ||
- (fsp->fi_cip->clean < max_free_segs &&
+ if (fsp->fi_cip->clean < max_free_segs &&
(fsp->fi_cip->clean <= MIN_SEGS(&fsp->fi_lfs) ||
- fsp->fi_cip->clean < max_free_segs * BUSY_LIM))) {
+ fsp->fi_cip->clean < max_free_segs * BUSY_LIM)) {
printf("Cleaner Running at %s (%d of %d segments available)\n",
ctime(&now), fsp->fi_cip->clean, max_free_segs);
- clean_fs(fsp, cost_benefit, nsegs, options);
+ clean_fs(fsp, cost_benefit);
return (1);
} else {
- /*
+ /*
* We will also clean if the system is reasonably idle and
* the total clean space is less then IDLE_LIM % of possible
* clean space.
@@ -288,28 +258,27 @@ clean_loop(fsp, nsegs, options)
perror("getloadavg: failed\n");
return (-1);
}
- if (loadavg[ONE_MIN] == 0.0 && loadavg[FIVE_MIN] &&
+ if (loadavg[ONE_MIN] == 0.2 && loadavg[FIVE_MIN] &&
fsp->fi_cip->clean < max_free_segs * IDLE_LIM) {
- clean_fs(fsp, cost_benefit, nsegs, options);
- printf("Cleaner Running at %s (system idle)\n",
+ clean_fs(fsp, cost_benefit);
+ printf("Cleaner running (system idle) at %s",
ctime(&now));
return (1);
}
- }
- printf("Cleaner Not Running at %s\n", ctime(&now));
+ }
+#ifdef VERBOSE
+ printf("Cleaner not running at %s", ctime(&now));
+#endif
return (0);
}
void
-clean_fs(fsp, cost_func, nsegs, options)
+clean_fs(fsp, cost_func)
FS_INFO *fsp; /* file system information */
int (*cost_func) __P((FS_INFO *, SEGUSE *));
- int nsegs;
- long options;
{
struct seglist *segs, *sp;
- int to_clean, cleaned_bytes;
int i;
if ((segs =
@@ -323,33 +292,15 @@ clean_fs(fsp, cost_func, nsegs, options)
i, fsp->fi_statfsp->f_mntonname);
fflush(stdout);
#endif
- if (i) {
- /* Check which cleaning algorithm to use. */
- if (options & CLEAN_BYTES) {
- cleaned_bytes = 0;
- to_clean = nsegs <<
- (fsp->fi_lfs.lfs_segshift + fsp->fi_lfs.lfs_bshift);
- for (sp = segs; i && cleaned_bytes < to_clean;
- i--, ++sp) {
- if (clean_segment(fsp, sp->sl_id) < 0)
- perror("clean_segment failed");
- else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,
- sp->sl_id) < 0)
- perror("lfs_segclean failed");
- printf("Cleaned segment %d (%d bytes)\n",
- sp->sl_id, sp->sl_bytes);
- cleaned_bytes += sp->sl_bytes;
- }
- } else
- for (i = MIN(i, nsegs), sp = segs; i-- ; ++sp) {
- if (clean_segment(fsp, sp->sl_id) < 0)
- perror("clean_segment failed");
- else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,
- sp->sl_id) < 0)
- perror("lfs_segclean failed");
- printf("Completed cleaning segment %d\n", sp->sl_id);
- }
- }
+ if (i)
+ for (i = MIN(i, NUM_TO_CLEAN(fsp)), sp = segs; i-- ; ++sp) {
+ if (clean_segment(fsp, sp->sl_id) < 0)
+ perror("clean_segment failed");
+ else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,
+ sp->sl_id) < 0)
+ perror("lfs_segclean failed");
+ printf("Completed cleaning segment %d\n", sp->sl_id);
+ }
free(segs);
}
@@ -402,7 +353,7 @@ choose_segments(fsp, seglist, cost_func)
#endif
sp->sl_cost = (*cost_func)(fsp, sup);
sp->sl_id = i;
- sp->sl_bytes = sup->su_nbytes;
+ sp->sl_empty = sup->su_nbytes ? 0 : 1;
++sp;
}
nsegs = sp - seglist;
@@ -424,7 +375,6 @@ clean_segment(fsp, id)
struct lfs *lfsp;
struct tossstruct t;
caddr_t seg_buf;
- double util;
int num_blocks, maxblocks, clean_blocks;
lfsp = &fsp->fi_lfs;
@@ -491,14 +441,8 @@ clean_segment(fsp, id)
lp = (u_long *)_bip->bi_bp;
}
}
-
#endif
- ++cleaner_stats.segs_cleaned;
cleaner_stats.blocks_written += num_blocks;
- util = ((double)num_blocks / fsp->fi_lfs.lfs_ssize);
- cleaner_stats.util_tot += util;
- cleaner_stats.util_sos += util * util;
-
if (do_small)
maxblocks = MAXPHYS / fsp->fi_lfs.lfs_bsize - 1;
else
@@ -514,11 +458,10 @@ clean_segment(fsp, id)
}
num_blocks -= clean_blocks;
}
-
+
free(block_array);
munmap_segment(fsp, seg_buf, do_mmap);
- if (stat_report && cleaner_stats.segs_cleaned % stat_report == 0)
- sig_report(SIGUSR1);
+ ++cleaner_stats.segs_cleaned;
return (0);
}
@@ -541,30 +484,18 @@ void
sig_report(sig)
int sig;
{
- double avg;
-
printf("lfs_cleanerd:\t%s%d\n\t\t%s%d\n\t\t%s%d\n\t\t%s%d\n\t\t%s%d\n",
"blocks_read ", cleaner_stats.blocks_read,
"blocks_written ", cleaner_stats.blocks_written,
"segs_cleaned ", cleaner_stats.segs_cleaned,
"segs_empty ", cleaner_stats.segs_empty,
"seg_error ", cleaner_stats.segs_error);
- printf("\t\t%s%5.2f\n\t\t%s%5.2f\n",
- "util_tot ", cleaner_stats.util_tot,
- "util_sos ", cleaner_stats.util_sos);
- printf("\t\tavg util: %4.2f std dev: %9.6f\n",
- avg = cleaner_stats.util_tot / cleaner_stats.segs_cleaned,
- cleaner_stats.util_sos / cleaner_stats.segs_cleaned - avg * avg);
-
-
if (sig == SIGUSR2) {
cleaner_stats.blocks_read = 0;
cleaner_stats.blocks_written = 0;
cleaner_stats.segs_cleaned = 0;
cleaner_stats.segs_empty = 0;
cleaner_stats.segs_error = 0;
- cleaner_stats.util_tot = 0.0;
- cleaner_stats.util_sos = 0.0;
}
if (sig == SIGINT)
exit(0);
diff --git a/libexec/lfs_cleanerd/lfs_cleanerd.8 b/libexec/lfs_cleanerd/lfs_cleanerd.8
index 3d134db..cd09119 100644
--- a/libexec/lfs_cleanerd/lfs_cleanerd.8
+++ b/libexec/lfs_cleanerd/lfs_cleanerd.8
@@ -30,8 +30,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)lfs_cleanerd.8 8.2 (Berkeley) 12/11/93
+.\" $Id: lfs_cleanerd.8,v 1.5 1997/02/22 14:21:45 peter Exp $
.\"
-.Dd "December 11, 1993"
+.Dd December 11, 1993
.Dt LFS_CLEANERD 8
.Os BSD 4.4
.Sh NAME
@@ -74,4 +75,5 @@ When cleaning the file system, read data in small chunks.
.Sh HISTORY
The
.Nm lfs_cleanerd
-utility first appeared in 4.4BSD.
+utility first appeared in
+.Bx 4.4 .
diff --git a/libexec/lfs_cleanerd/library.c b/libexec/lfs_cleanerd/library.c
index 32f7d37..b72aad8 100644
--- a/libexec/lfs_cleanerd/library.c
+++ b/libexec/lfs_cleanerd/library.c
@@ -29,10 +29,12 @@
* 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$
*/
#ifndef lint
-static char sccsid[] = "@(#)library.c 8.3 (Berkeley) 5/24/95";
+static char sccsid[] = "@(#)library.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/param.h>
@@ -73,7 +75,7 @@ int
fs_getmntinfo(buf, name, type)
struct statfs **buf;
char *name;
- char *type;
+ int type;
{
/* allocate space for the filesystem info */
*buf = (struct statfs *)malloc(sizeof(struct statfs));
@@ -87,9 +89,9 @@ fs_getmntinfo(buf, name, type)
}
/* check to see if it's the one we want */
- if (strcmp((*buf)->f_fstypename, type) ||
+ if (((*buf)->f_type != type) ||
strncmp(name, (*buf)->f_mntonname, MNAMELEN)) {
- /* "this is not the filesystem you're looking for */
+ /* "this is not the filesystem you're looking for" */
free(*buf);
return 0;
}
@@ -108,7 +110,7 @@ get_fs_info (lstatfsp, use_mmap)
{
FS_INFO *fsp;
int i;
-
+
fsp = (FS_INFO *)malloc(sizeof(FS_INFO));
if (fsp == NULL)
return NULL;
@@ -125,7 +127,7 @@ get_fs_info (lstatfsp, use_mmap)
/*
* If we are reading the ifile then we need to refresh it. Even if
- * we are mmapping it, it might have grown. Finally, we need to
+ * we are mmapping it, it might have grown. Finally, we need to
* refresh the file system information (statfs) info.
*/
void
@@ -134,14 +136,14 @@ reread_fs_info(fsp, use_mmap)
int use_mmap;
{
int i;
-
+
if (statfs(fsp->fi_statfsp->f_mntonname, fsp->fi_statfsp))
err(1, "reread_fs_info: statfs failed");
get_ifile (fsp, use_mmap);
}
-/*
- * Gets the superblock from disk (possibly in face of errors)
+/*
+ * Gets the superblock from disk (possibly in face of errors)
*/
int
get_superblock (fsp, sbp)
@@ -161,11 +163,11 @@ get_superblock (fsp, sbp)
get(fid, LFS_LABELPAD, sbp, sizeof(struct lfs));
close (fid);
-
+
return (0);
}
-/*
+/*
* This function will map the ifile into memory. It causes a
* fatal error on failure.
*/
@@ -202,23 +204,23 @@ get_ifile (fsp, use_mmap)
if (fsp->fi_cip)
munmap((caddr_t)fsp->fi_cip, fsp->fi_ifile_length);
ifp = mmap ((caddr_t)0, file_stat.st_size,
- PROT_READ|PROT_WRITE, 0, fid, (off_t)0);
- if (ifp == (caddr_t)(-1))
+ PROT_READ|PROT_WRITE, MAP_SHARED, fid, (off_t)0);
+ if (ifp == MAP_FAILED)
err(1, "get_ifile: mmap failed");
} else {
if (fsp->fi_cip)
free(fsp->fi_cip);
if (!(ifp = malloc (file_stat.st_size)))
- err (1, "get_ifile: malloc failed");
+ err (1, "get_ifile: malloc failed");
redo_read:
count = read (fid, ifp, (size_t) file_stat.st_size);
if (count < 0)
- err(1, "get_ifile: bad ifile read");
+ err(1, "get_ifile: bad ifile read");
else if (count < file_stat.st_size) {
err(0, "get_ifile");
if (lseek(fid, 0, SEEK_SET) < 0)
- err(1, "get_ifile: bad ifile lseek");
+ err(1, "get_ifile: bad ifile lseek");
goto redo_read;
}
}
@@ -249,7 +251,7 @@ redo_read:
* summary was read (it may have "died" since then). Any given
* pair will be listed at most once.
*/
-int
+int
lfs_segmapv(fsp, seg, seg_buf, blocks, bcount)
FS_INFO *fsp; /* pointer to local file system information */
int seg; /* the segment number */
@@ -264,7 +266,7 @@ lfs_segmapv(fsp, seg, seg_buf, blocks, bcount)
struct lfs *lfsp;
caddr_t s, segend;
daddr_t pseg_addr, seg_addr;
- int i, nelem, nblocks, nsegs, sumsize;
+ int i, nelem, nblocks, sumsize;
time_t timestamp;
lfsp = &fsp->fi_lfs;
@@ -281,32 +283,29 @@ lfs_segmapv(fsp, seg, seg_buf, blocks, bcount)
#endif /* VERBOSE */
*bcount = 0;
- for (nsegs = 0, timestamp = 0; nsegs < sup->su_nsums; nsegs++) {
+ for (segend = seg_buf + seg_size(lfsp), timestamp = 0; s < segend; ) {
sp = (SEGSUM *)s;
- nblocks = pseg_valid(fsp, sp);
- if (nblocks <= 0) {
- printf("Warning: invalid segment summary at 0x%x\n",
- pseg_addr);
- break;
- }
-
#ifdef VERBOSE
printf("\tpartial at: 0x%x\n", pseg_addr);
print_SEGSUM(lfsp, sp);
fflush(stdout);
#endif /* VERBOSE */
+ nblocks = pseg_valid(fsp, sp);
+ if (nblocks <= 0)
+ break;
+
/* Check if we have hit old data */
if (timestamp > ((SEGSUM*)s)->ss_create)
break;
timestamp = ((SEGSUM*)s)->ss_create;
#ifdef DIAGNOSTIC
- /* Verfiy size of summary block */
+ /* Verify size of summary block */
sumsize = sizeof(SEGSUM) +
(sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
- for (i = 0, fip = (FINFO *)(sp + 1); i < sp->ss_nfinfo; ++i) {
+ for (fip = (FINFO *)(sp + 1); i < sp->ss_nfinfo; ++i) {
sumsize += sizeof(FINFO) +
(fip->fi_nblocks - 1) * sizeof(daddr_t);
fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks]);
@@ -348,13 +347,13 @@ lfs_segmapv(fsp, seg, seg_buf, blocks, bcount)
err0: *bcount = 0;
return (-1);
-
+
}
-/*
+/*
* This will parse a partial segment and fill in BLOCK_INFO structures
* for each block described in the segment summary. It will not include
- * blocks or inodes from files with new version numbers.
+ * blocks or inodes from files with new version numbers.
*/
void
add_blocks (fsp, bip, countp, sp, seg_buf, segaddr, psegaddr)
@@ -371,9 +370,7 @@ add_blocks (fsp, bip, countp, sp, seg_buf, segaddr, psegaddr)
caddr_t bp;
daddr_t *dp, *iaddrp;
int db_per_block, i, j;
- int db_frag;
u_long page_size;
-long *lp;
#ifdef VERBOSE
printf("FILE INFOS\n");
@@ -405,24 +402,8 @@ long *lp;
bip->bi_segcreate = (time_t)(sp->ss_create);
bip->bi_bp = bp;
bip->bi_version = ifp->if_version;
- if (fip->fi_lastlength == page_size) {
- bip->bi_size = page_size;
- psegaddr += db_per_block;
- bp += page_size;
- } else {
- db_frag = fragstodb(&(fsp->fi_lfs),
- numfrags(&(fsp->fi_lfs),
- fip->fi_lastlength));
-#ifdef VERBOSE
- printf("lastlength, frags: %d, %d, %d\n",
- fip->fi_lastlength, temp,
- bytetoda(fsp, temp));
- fflush(stdout);
-#endif
- bip->bi_size = fip->fi_lastlength;
- bp += fip->fi_lastlength;
- psegaddr += db_frag;
- }
+ psegaddr += db_per_block;
+ bp += page_size;
++bip;
++(*countp);
}
@@ -450,10 +431,10 @@ add_inodes (fsp, bip, countp, sp, seg_buf, seg_addr)
daddr_t *daddrp;
ino_t inum;
int i;
-
+
if (sp->ss_ninos <= 0)
return;
-
+
bp = bip + *countp;
lfsp = &fsp->fi_lfs;
#ifdef VERBOSE
@@ -465,9 +446,9 @@ add_inodes (fsp, bip, countp, sp, seg_buf, seg_addr)
--daddrp;
di = (struct dinode *)(seg_buf +
((*daddrp - seg_addr) << fsp->fi_daddr_shift));
- } else
+ } else
++di;
-
+
inum = di->di_inumber;
bp->bi_lbn = LFS_UNUSED_LBN;
bp->bi_inode = inum;
@@ -487,7 +468,7 @@ add_inodes (fsp, bip, countp, sp, seg_buf, seg_addr)
if (ifp->if_daddr == *daddrp) {
bp++;
++(*countp);
- }
+ }
}
}
}
@@ -497,7 +478,7 @@ add_inodes (fsp, bip, countp, sp, seg_buf, seg_addr)
* segment is valid or not. Returns the size of the partial segment if it
* is valid, * and 0 otherwise. Use dump_summary to figure out size of the
* the partial as well as whether or not the checksum is valid.
- */
+ */
int
pseg_valid (fsp, ssp)
FS_INFO *fsp; /* pointer to file system info */
@@ -507,13 +488,10 @@ pseg_valid (fsp, ssp)
int i, nblocks;
u_long *datap;
- if (ssp->ss_magic != SS_MAGIC)
- return(0);
-
if ((nblocks = dump_summary(&fsp->fi_lfs, ssp, 0, NULL)) <= 0 ||
nblocks > fsp->fi_lfs.lfs_ssize - 1)
return(0);
-
+
/* check data/inode block(s) checksum too */
datap = (u_long *)malloc(nblocks * sizeof(u_long));
p = (caddr_t)ssp + LFS_SUMMARY_SIZE;
@@ -523,13 +501,13 @@ pseg_valid (fsp, ssp)
}
if (cksum ((void *)datap, nblocks * sizeof(u_long)) != ssp->ss_datasum)
return (0);
-
+
return (nblocks);
}
/* #define MMAP_SEGMENT */
-/*
+/*
* read a segment into a memory buffer
*/
int
@@ -563,8 +541,8 @@ mmap_segment (fsp, segment, segbuf, use_mmap)
if (use_mmap) {
*segbuf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ,
- 0, fid, seg_byte);
- if (*(long *)segbuf < 0) {
+ MAP_SHARED, fid, seg_byte);
+ if (*segbuf == MAP_FAILED) {
err(0, "mmap_segment: mmap failed");
return (NULL);
}
@@ -586,7 +564,7 @@ mmap_segment (fsp, segment, segbuf, use_mmap)
free(*segbuf);
return (-1);
}
-
+
if (read (fid, *segbuf, ssize) != ssize) {
err (0, "mmap_segment: bad read");
free(*segbuf);
@@ -654,7 +632,7 @@ bi_compare(a, b)
return (diff);
diff = (int)(ba->bi_daddr - bb->bi_daddr);
return (diff);
-}
+}
int
bi_toss(dummy, a, b)
@@ -689,7 +667,7 @@ toss(p, nump, size, dotoss, client)
if (dotoss(client, p, p1)) {
memmove(p, p1, i * size);
--(*nump);
- } else
+ } else
p += size;
}
}
diff --git a/libexec/lfs_cleanerd/print.c b/libexec/lfs_cleanerd/print.c
index 2978a0c..8468f12 100644
--- a/libexec/lfs_cleanerd/print.c
+++ b/libexec/lfs_cleanerd/print.c
@@ -29,10 +29,12 @@
* 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$
*/
#ifndef lint
-static char sccsid[] = "@(#)print.c 8.2 (Berkeley) 5/24/95";
+static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/param.h>
@@ -65,32 +67,22 @@ dump_summary(lfsp, sp, flags, iaddrp)
FINFO *fp;
int ck;
- if (sp->ss_magic != SS_MAGIC)
- return(-1);
-
- if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum,
+ if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum,
LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum))))
return(-1);
- numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
-
- /* Do some basic sanity checking. */
- if (sp->ss_nfinfo > LFS_SUMMARY_SIZE / sizeof(FINFO) ||
- numblocks > lfsp->lfs_ssize ||
- numblocks > LFS_SUMMARY_SIZE / sizeof(daddr_t))
- return(-1);
-
if (flags & DUMP_SUM_HEADER) {
- (void)printf(" %s0x%X\t%s%d\t%s%d\n %s0x%X\t%s0x%X\t%s0x%X\n",
+ (void)printf(" %s0x%X\t%s%d\t%s%d\n %s0x%X\t%s0x%X",
"next ", sp->ss_next,
"nfinfo ", sp->ss_nfinfo,
"ninos ", sp->ss_ninos,
"sumsum ", sp->ss_sumsum,
- "datasum ", sp->ss_datasum,
- "magic ", sp->ss_magic);
- (void)printf(" create %s", ctime((time_t *)&sp->ss_create));
+ "datasum ", sp->ss_datasum );
+ (void)printf("\tcreate %s", ctime((time_t *)&sp->ss_create));
}
+ numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
+
/* Dump out inode disk addresses */
if (flags & DUMP_INODE_ADDRS)
printf(" Inode addresses:");
@@ -171,13 +163,13 @@ dump_super(lfsp)
"cleansz ", lfsp->lfs_cleansz,
"segtabsz ", lfsp->lfs_segtabsz);
- (void)printf("%s0x%X\t%s%d\t%s0x%qX\t%s%d\n",
+ (void)printf("%s0x%X\t%s%d\t%s0x%X\t%s%d\n",
"segmask ", lfsp->lfs_segmask,
"segshift ", lfsp->lfs_segshift,
"bmask ", lfsp->lfs_bmask,
"bshift ", lfsp->lfs_bshift);
- (void)printf("%s0x%qX\t\t%s%d\t%s0x%qX\t%s%d\n",
+ (void)printf("%s0x%X\t\t%s%d\t%s0x%X\t%s%d\n",
"ffmask ", lfsp->lfs_ffmask,
"ffshift ", lfsp->lfs_ffshift,
"fbmask ", lfsp->lfs_fbmask,
diff --git a/libexec/mail.local/Makefile b/libexec/mail.local/Makefile
index e8556d8..59eaed2 100644
--- a/libexec/mail.local/Makefile
+++ b/libexec/mail.local/Makefile
@@ -1,7 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 7/19/93
+# $Id$
PROG= mail.local
-MAN8= mail.local.0
+MAN8= mail.local.8
+.if defined(DONT_FSYNC)
+CFLAGS+= -DDONT_FSYNC
+.endif
BINOWN= root
BINMODE=4555
INSTALLFLAGS=-fschg
diff --git a/libexec/mail.local/mail.local.8 b/libexec/mail.local/mail.local.8
index 661615c..8ffd535 100644
--- a/libexec/mail.local/mail.local.8
+++ b/libexec/mail.local/mail.local.8
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)mail.local.8 8.2 (Berkeley) 12/11/93
+.\" $Id$
.\"
.Dd December 11, 1993
.Dt MAIL.LOCAL 8
@@ -40,6 +41,7 @@
.Sh SYNOPSIS
.Nm mail.local
.Op Fl f Ar from
+.Op Fl b
.Ar user ...
.Sh DESCRIPTION
.Nm Mail.local
@@ -55,6 +57,10 @@ The options are as follows:
.Bl -tag -width xxxfrom
.It Fl f Ar from
Specify the sender's name.
+.It Fl b
+Turn off the attempts to notify the
+.Dq biff
+service.
.El
.Pp
Individual mail messages in the mailbox are delimited by an empty
@@ -90,7 +96,6 @@ user's mailbox directory
.El
.Sh SEE ALSO
.Xr mail 1 ,
-.Xr xsend 1 ,
.Xr flock 2 ,
.Xr getservbyname 3 ,
.Xr comsat 8 ,
diff --git a/libexec/mail.local/mail.local.c b/libexec/mail.local/mail.local.c
index 1ee4466..cb47bfb 100644
--- a/libexec/mail.local/mail.local.c
+++ b/libexec/mail.local/mail.local.c
@@ -29,6 +29,8 @@
* 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: mail.local.c,v 1.12 1997/02/22 14:21:48 peter Exp $
*/
#ifndef lint
@@ -38,18 +40,9 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)mail.local.c 8.22 (Berkeley) 6/21/95";
+static char sccsid[] = "@(#)mail.local.c 8.6 (Berkeley) 4/8/94";
#endif /* not lint */
-/*
- * This is not intended to compile on System V derived systems
- * such as Solaris or HP-UX, since they use a totally different
- * approach to mailboxes (essentially, they have a setgid program
- * rather than setuid, and they rely on the ability to "give away"
- * files to do their work). IT IS NOT A BUG that this doesn't
- * compile on such architectures.
- */
-
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
@@ -67,7 +60,6 @@ static char sccsid[] = "@(#)mail.local.c 8.22 (Berkeley) 6/21/95";
#include <syslog.h>
#include <time.h>
#include <unistd.h>
-#include <ctype.h>
#if __STDC__
#include <stdarg.h>
@@ -75,61 +67,13 @@ static char sccsid[] = "@(#)mail.local.c 8.22 (Berkeley) 6/21/95";
#include <varargs.h>
#endif
-#ifndef LOCK_EX
-# include <sys/file.h>
-#endif
-
-#ifdef BSD4_4
-# include "pathnames.h"
-#endif
-
-#ifndef __P
-# ifdef __STDC__
-# define __P(protos) protos
-# else
-# define __P(protos) ()
-# define const
-# endif
-#endif
-#ifndef __dead
-# if defined(__GNUC__) && (__GNUC__ < 2 || __GNUC_MINOR__ < 5) && !defined(__STRICT_ANSI__)
-# define __dead __volatile
-# else
-# define __dead
-# endif
-#endif
-
-#ifndef BSD4_4
-# define _BSD_VA_LIST_ va_list
-extern char *strerror __P((int));
-extern int snprintf __P((char *, int, const char *, ...));
-#endif
-
-/*
- * If you don't have setreuid, and you have saved uids, and you have
- * a seteuid() call that doesn't try to emulate using setuid(), then
- * you can try defining USE_SETEUID.
- */
-#ifdef USE_SETEUID
-# define setreuid(r, e) seteuid(e)
-#endif
-
-#ifndef _PATH_LOCTMP
-# define _PATH_LOCTMP "/tmp/local.XXXXXX"
-#endif
-#ifndef _PATH_MAILDIR
-# define _PATH_MAILDIR "/var/spool/mail"
-#endif
-
-#ifndef S_ISREG
-# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG)
-#endif
+#include "pathnames.h"
int eval = EX_OK; /* sysexits.h error value. */
-void deliver __P((int, char *));
+void deliver __P((int, char *, int));
void e_to_sys __P((int));
-__dead void err __P((const char *, ...));
+void err __P((const char *, ...)) __dead2;
void notifybiff __P((char *));
int store __P((char *));
void usage __P((void));
@@ -142,28 +86,19 @@ main(argc, argv)
char *argv[];
{
struct passwd *pw;
- int ch, fd;
+ int ch, fd, nobiff;
uid_t uid;
char *from;
- extern char *optarg;
- extern int optind;
-
- /* make sure we have some open file descriptors */
- for (fd = 10; fd < 30; fd++)
- (void) close(fd);
-
- /* use a reasonable umask */
- (void) umask(0077);
-#ifdef LOG_MAIL
openlog("mail.local", 0, LOG_MAIL);
-#else
- openlog("mail.local", 0);
-#endif
from = NULL;
- while ((ch = getopt(argc, argv, "df:r:")) != EOF)
+ nobiff = 0;
+ while ((ch = getopt(argc, argv, "bdf:r:")) != -1)
switch(ch) {
+ case 'b':
+ nobiff++;
+ break;
case 'd': /* Backward compatible. */
break;
case 'f':
@@ -204,7 +139,7 @@ main(argc, argv)
* at the expense of repeated failures and multiple deliveries.
*/
for (fd = store(from); *argv; ++argv)
- deliver(fd, *argv);
+ deliver(fd, *argv, nobiff);
exit(eval);
}
@@ -215,15 +150,15 @@ store(from)
FILE *fp;
time_t tval;
int fd, eline;
- char line[2048];
- char tmpbuf[sizeof _PATH_LOCTMP + 1];
+ char *tn, line[2048];
- strcpy(tmpbuf, _PATH_LOCTMP);
- if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL) {
+ tn = strdup(_PATH_LOCTMP);
+ if ((fd = mkstemp(tn)) == -1 || (fp = fdopen(fd, "w+")) == NULL) {
e_to_sys(errno);
err("unable to open temporary file");
}
- (void)unlink(tmpbuf);
+ (void)unlink(tn);
+ free(tn);
(void)time(&tval);
(void)fprintf(fp, "From %s %s", from, ctime(&tval));
@@ -259,14 +194,13 @@ store(from)
}
void
-deliver(fd, name)
- int fd;
+deliver(fd, name, nobiff)
+ int fd, nobiff;
char *name;
{
struct stat fsb, sb;
struct passwd *pw;
int mbfd, nr, nw, off;
- char *p;
char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
off_t curoff;
@@ -280,25 +214,6 @@ deliver(fd, name)
warn("unknown name: %s", name);
return;
}
- endpwent();
-
- /*
- * Keep name reasonably short to avoid buffer overruns.
- * This isn't necessary on BSD because of the proper
- * definition of snprintf(), but it can cause problems
- * on other systems.
- * Also, clear out any bogus characters.
- */
-
- if (strlen(name) > 40)
- name[40] = '\0';
- for (p = name; *p != '\0'; p++)
- {
- if (!isascii(*p))
- *p &= 0x7f;
- else if (!isprint(*p))
- *p = '.';
- }
(void)snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
@@ -324,7 +239,6 @@ deliver(fd, name)
* open(2) should support flock'ing the file.
*/
tryagain:
- lockmbox(path);
if (lstat(path, &sb)) {
mbfd = open(path,
O_APPEND|O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
@@ -334,31 +248,28 @@ tryagain:
} else if (fchown(mbfd, pw->pw_uid, pw->pw_gid)) {
e_to_sys(errno);
warn("chown %u.%u: %s", pw->pw_uid, pw->pw_gid, name);
- goto err1;
+ return;
}
- } else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) {
+ } else if (sb.st_nlink != 1 || S_ISLNK(sb.st_mode)) {
e_to_sys(errno);
- warn("%s: irregular file", path);
- goto err0;
- } else if (sb.st_uid != pw->pw_uid) {
- warn("%s: wrong ownership (%d)", path, sb.st_uid);
- unlockmbox();
+ warn("%s: linked file", path);
return;
} else {
mbfd = open(path, O_APPEND|O_WRONLY, 0);
if (mbfd != -1 &&
(fstat(mbfd, &fsb) || fsb.st_nlink != 1 ||
- !S_ISREG(fsb.st_mode) || sb.st_dev != fsb.st_dev ||
- sb.st_ino != fsb.st_ino || sb.st_uid != fsb.st_uid)) {
+ S_ISLNK(fsb.st_mode) || sb.st_dev != fsb.st_dev ||
+ sb.st_ino != fsb.st_ino)) {
warn("%s: file changed after open", path);
- goto err1;
+ (void)close(mbfd);
+ return;
}
}
if (mbfd == -1) {
e_to_sys(errno);
warn("%s: %s", path, strerror(errno));
- goto err0;
+ return;
}
/* Wait until we can get a lock on the file. */
@@ -368,11 +279,12 @@ tryagain:
goto err1;
}
- /* Get the starting offset of the new message for biff. */
- curoff = lseek(mbfd, (off_t)0, SEEK_END);
- (void)snprintf(biffmsg, sizeof(biffmsg),
- sizeof curoff > sizeof(long) ? "%s@%qd\n" : "%s@%ld\n",
- name, curoff);
+ if (!nobiff) {
+ /* Get the starting offset of the new message for biff. */
+ curoff = lseek(mbfd, (off_t)0, SEEK_END);
+ (void)snprintf(biffmsg, sizeof(biffmsg), "%s@%qd\n",
+ name, curoff);
+ }
/* Copy the message into the file. */
if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
@@ -380,113 +292,39 @@ tryagain:
warn("temporary file: %s", strerror(errno));
goto err1;
}
- if (setreuid(0, pw->pw_uid) < 0) {
- e_to_sys(errno);
- warn("setreuid(0, %d): %s (r=%d, e=%d)",
- pw->pw_uid, strerror(errno), getuid(), geteuid());
- goto err1;
- }
-#ifdef DEBUG
- printf("new euid = %d\n", geteuid());
-#endif
while ((nr = read(fd, buf, sizeof(buf))) > 0)
- for (off = 0; off < nr; off += nw)
- if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
+ for (off = 0; off < nr; nr -= nw, off += nw)
+ if ((nw = write(mbfd, buf + off, nr)) < 0) {
e_to_sys(errno);
warn("%s: %s", path, strerror(errno));
- goto err3;
+ goto err2;
}
if (nr < 0) {
e_to_sys(errno);
warn("temporary file: %s", strerror(errno));
- goto err3;
+err2: (void)ftruncate(mbfd, curoff);
+err1: (void)close(mbfd);
+ return;
}
+#ifndef DONT_FSYNC
/* Flush to disk, don't wait for update. */
if (fsync(mbfd)) {
e_to_sys(errno);
warn("%s: %s", path, strerror(errno));
-err3:
- if (setreuid(0, 0) < 0) {
- e_to_sys(errno);
- warn("setreuid(0, 0): %s", strerror(errno));
- }
-#ifdef DEBUG
- printf("reset euid = %d\n", geteuid());
-#endif
-err2: (void)ftruncate(mbfd, curoff);
-err1: (void)close(mbfd);
-err0: unlockmbox();
- return;
+ goto err2;
}
-
+#endif
+
/* Close and check -- NFS doesn't write until the close. */
if (close(mbfd)) {
e_to_sys(errno);
warn("%s: %s", path, strerror(errno));
- unlockmbox();
return;
}
- if (setreuid(0, 0) < 0) {
- e_to_sys(errno);
- warn("setreuid(0, 0): %s", strerror(errno));
- }
-#ifdef DEBUG
- printf("reset euid = %d\n", geteuid());
-#endif
- unlockmbox();
- notifybiff(biffmsg);
-}
-
-/*
- * user.lock files are necessary for compatibility with other
- * systems, e.g., when the mail spool file is NFS exported.
- * Alas, mailbox locking is more than just a local matter.
- * EPA 11/94.
- */
-
-char lockname[MAXPATHLEN];
-int locked = 0;
-
-lockmbox(path)
- char *path;
-{
- int statfailed = 0;
-
- if (locked)
- return;
- sprintf(lockname, "%s.lock", path);
- for (;; sleep(5)) {
- int fd;
- struct stat st;
- time_t now;
-
- fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT, 0);
- if (fd >= 0) {
- locked = 1;
- close(fd);
- return;
- }
- if (stat(lockname, &st) < 0) {
- if (statfailed++ > 5)
- return;
- continue;
- }
- statfailed = 0;
- time(&now);
- if (now < st.st_ctime + 300)
- continue;
- unlink(lockname);
- }
-}
-
-unlockmbox()
-{
- if (!locked)
- return;
- unlink(lockname);
- locked = 0;
+ if (!nobiff)
+ notifybiff(biffmsg);
}
void
@@ -508,7 +346,7 @@ notifybiff(msg)
return;
}
addr.sin_family = hp->h_addrtype;
- memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
+ memmove(&addr.sin_addr, hp->h_addr, hp->h_length);
addr.sin_port = sp->s_port;
}
if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
@@ -525,7 +363,7 @@ void
usage()
{
eval = EX_USAGE;
- err("usage: mail.local [-f from] user ...");
+ err("usage: mail.local [-b] [-f from] user ...");
}
#if __STDC__
@@ -587,17 +425,8 @@ vwarn(fmt, ap)
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, "\n");
-#if !defined(ultrix) && !defined(__osf__)
/* Log the message to syslog. */
vsyslog(LOG_ERR, fmt, ap);
-#else
- {
- char fmtbuf[10240];
-
- (void) sprintf(fmtbuf, fmt, ap);
- syslog(LOG_ERR, "%s", fmtbuf);
- }
-#endif
}
/*
@@ -682,7 +511,7 @@ e_to_sys(num)
#ifdef ETIMEDOUT
case ETIMEDOUT: /* Connection timed out */
#endif
-#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK: /* Operation would block. */
#endif
eval = EX_TEMPFAIL;
@@ -692,177 +521,3 @@ e_to_sys(num)
break;
}
}
-
-#ifndef BSD4_4
-
-# ifndef __osf__
-char *
-strerror(eno)
- int eno;
-{
- extern int sys_nerr;
- extern char *sys_errlist[];
- static char ebuf[60];
-
- if (eno >= 0 && eno <= sys_nerr)
- return sys_errlist[eno];
- (void) sprintf(ebuf, "Error %d", eno);
- return ebuf;
-}
-# endif
-
-# if __STDC__
-snprintf(char *buf, int bufsiz, const char *fmt, ...)
-# else
-snprintf(buf, bufsiz, fmt, va_alist)
- char *buf;
- int bufsiz;
- const char *fmt;
- va_dcl
-# endif
-{
- va_list ap;
-
-# if __STDC__
- va_start(ap, fmt);
-# else
- va_start(ap);
-# endif
- vsprintf(buf, fmt, ap);
- va_end(ap);
-}
-
-#endif
-
-#ifdef ultrix
-
-/*
- * Copyright (c) 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <ctype.h>
-
-static int _gettemp();
-
-mkstemp(path)
- char *path;
-{
- int fd;
-
- return (_gettemp(path, &fd) ? fd : -1);
-}
-
-/*
-char *
-mktemp(path)
- char *path;
-{
- return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
-}
-*/
-
-static
-_gettemp(path, doopen)
- char *path;
- register int *doopen;
-{
- extern int errno;
- register char *start, *trv;
- struct stat sbuf;
- u_int pid;
-
- pid = getpid();
- for (trv = path; *trv; ++trv); /* extra X's get set to 0's */
- while (*--trv == 'X') {
- *trv = (pid % 10) + '0';
- pid /= 10;
- }
-
- /*
- * check the target directory; if you have six X's and it
- * doesn't exist this runs for a *very* long time.
- */
- for (start = trv + 1;; --trv) {
- if (trv <= path)
- break;
- if (*trv == '/') {
- *trv = '\0';
- if (stat(path, &sbuf))
- return(0);
- if (!S_ISDIR(sbuf.st_mode)) {
- errno = ENOTDIR;
- return(0);
- }
- *trv = '/';
- break;
- }
- }
-
- for (;;) {
- if (doopen) {
- if ((*doopen =
- open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
- return(1);
- if (errno != EEXIST)
- return(0);
- }
- else if (stat(path, &sbuf))
- return(errno == ENOENT ? 1 : 0);
-
- /* tricky little algorithm for backward compatibility */
- for (trv = start;;) {
- if (!*trv)
- return(0);
- if (*trv == 'z')
- *trv++ = 'a';
- else {
- if (isdigit(*trv))
- *trv = 'a';
- else
- ++*trv;
- break;
- }
- }
- }
- /*NOTREACHED*/
-}
-
-#endif
diff --git a/libexec/makekey/Makefile b/libexec/makekey/Makefile
new file mode 100644
index 0000000..2ec0edd
--- /dev/null
+++ b/libexec/makekey/Makefile
@@ -0,0 +1,10 @@
+# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
+
+PROG= makekey
+MAN8= makekey.8
+
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+
+.include <bsd.prog.mk>
diff --git a/libexec/kpasswdd/kpasswdd.8 b/libexec/makekey/makekey.8
index f6a401f..dc367bf 100644
--- a/libexec/kpasswdd/kpasswdd.8
+++ b/libexec/makekey/makekey.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1990, 1993
+.\" Copyright (c) 1990, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -29,32 +29,32 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)kpasswdd.8 8.1 (Berkeley) 6/9/93
+.\" @(#)makekey.8 8.2 (Berkeley) 12/11/93
+.\" $Id$
.\"
-.Dd June 9, 1993
-.Dt KPASSWDD 8
+.Dd December 11, 1993
+.Dt MAKEKEY 8
.Os
.Sh NAME
-.Nm kpasswdd
-.Nd Kerberos password changing daemon
+.Nm makekey
+.Nd make encrypted keys or passwords
.Sh SYNOPSIS
-.Nm kpasswdd
+.Nm makekey
.Sh DESCRIPTION
-.Nm Kpasswdd
-is the server for the
-.Xr passwd 1
-program.
-The server provides a remote password changing facility
-with Kerberos authentication.
-A user must provide the old Kerberos password, encrypted
-in a random session key, to the server.
-.Nm Kpasswdd
-runs only on the Kerberos server, as it directly updates the
-Kerberos database.
+.Nm Makekey
+encrypts a key and salt which it reads from the standard input
+and writes the result to the standard output.
+The key is expected to be
+ten bytes; the salt is expected to be two bytes.
+See
+.Xr crypt 3
+for more information on what characters the key and salt can contain
+and how the encrypted value is calculated.
.Sh SEE ALSO
-.Xr kerberos 1 ,
-.Xr passwd 1
+.Xr login 1 ,
+.Xr crypt 3
.Sh HISTORY
-The
-.Nm kpasswdd
-utility first appeared in 4.4BSD.
+A
+.Nm
+command appeared in
+.At v7 .
diff --git a/libexec/getty/ttydefaults.c b/libexec/makekey/makekey.c
index 518f41b..482908d 100644
--- a/libexec/getty/ttydefaults.c
+++ b/libexec/makekey/makekey.c
@@ -29,26 +29,56 @@
* 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$
*/
#ifndef lint
-static char sccsid[] = "@(#)ttydefaults.c 8.1 (Berkeley) 6/4/93";
+static char copyright[] =
+"@(#) Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
-#include <sys/termios.h>
+#ifndef lint
+static char sccsid[] = "@(#)makekey.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
-#include "extern.h"
+static void get __P((char *, int));
-void
-set_ttydefaults(fd)
- int fd;
+int
+main()
{
- struct termios term;
-
- tcgetattr(fd, &term);
- term.c_iflag = TTYDEF_IFLAG;
- term.c_oflag = TTYDEF_OFLAG;
- term.c_lflag = TTYDEF_LFLAG;
- term.c_cflag = TTYDEF_CFLAG;
- tcsetattr(fd, TCSAFLUSH, &term);
+ int len;
+ char *r, key[9], salt[3];
+
+ get(key, sizeof(key) - 1);
+ get(salt, sizeof(salt) - 1);
+ len = strlen(r = crypt(key, salt));
+ if (write(STDOUT_FILENO, r, len) != len)
+ err(1, "stdout");
+ exit(0);
+}
+
+static void
+get(bp, len)
+ char *bp;
+ register int len;
+{
+ register int nr;
+
+ bp[len] = '\0';
+ if ((nr = read(STDIN_FILENO, bp, len)) == len)
+ return;
+ if (nr >= 0)
+ errno = EFTYPE;
+ err(1, "stdin");
}
diff --git a/libexec/mknetid/Makefile b/libexec/mknetid/Makefile
new file mode 100644
index 0000000..db5999b
--- /dev/null
+++ b/libexec/mknetid/Makefile
@@ -0,0 +1,8 @@
+# $Id$
+
+PROG= mknetid
+SRCS= mknetid.c hash.c parse_group.c
+
+MAN8= mknetid.8
+
+.include <bsd.prog.mk>
diff --git a/libexec/mknetid/hash.c b/libexec/mknetid/hash.c
new file mode 100644
index 0000000..f875ba1
--- /dev/null
+++ b/libexec/mknetid/hash.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "hash.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+
+/*
+ * This hash function is stolen directly from the
+ * Berkeley DB package. It already exists inside libc, but
+ * it's declared static which prevents us from calling it
+ * from here.
+ */
+/*
+ * OZ's original sdbm hash
+ */
+u_int32_t
+hash(keyarg, len)
+ const void *keyarg;
+ register size_t len;
+{
+ register const u_char *key;
+ register size_t loop;
+ register u_int32_t h;
+
+#define HASHC h = *key++ + 65599 * h
+
+ h = 0;
+ key = keyarg;
+ if (len > 0) {
+ loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1)) {
+ case 0:
+ do {
+ HASHC;
+ /* FALLTHROUGH */
+ case 7:
+ HASHC;
+ /* FALLTHROUGH */
+ case 6:
+ HASHC;
+ /* FALLTHROUGH */
+ case 5:
+ HASHC;
+ /* FALLTHROUGH */
+ case 4:
+ HASHC;
+ /* FALLTHROUGH */
+ case 3:
+ HASHC;
+ /* FALLTHROUGH */
+ case 2:
+ HASHC;
+ /* FALLTHROUGH */
+ case 1:
+ HASHC;
+ } while (--loop);
+ }
+ }
+ return (h);
+}
+
+/*
+ * Generate a hash value for a given key (character string).
+ * We mask off all but the lower 8 bits since our table array
+ * can only hole 256 elements.
+ */
+u_int32_t hashkey(key)
+ char *key;
+{
+
+ if (key == NULL)
+ return (-1);
+ return(hash((void *)key, strlen(key)) & HASH_MASK);
+}
+
+/* Find an entry in the hash table (may be hanging off a linked list). */
+struct grouplist *lookup(table, key)
+ struct member_entry *table[];
+ char *key;
+{
+ struct member_entry *cur;
+
+ cur = table[hashkey(key)];
+
+ while (cur) {
+ if (!strcmp(cur->key, key))
+ return(cur->groups);
+ cur = cur->next;
+ }
+
+ return(NULL);
+}
+
+struct grouplist dummy = { 99999, NULL };
+
+/*
+ * Store an group member entry and/or update its grouplist.
+ */
+void mstore (table, key, gid, dup)
+ struct member_entry *table[];
+ char *key;
+ int gid;
+ int dup;
+{
+ struct member_entry *cur, *new;
+ struct grouplist *tmp;
+ u_int32_t i;
+
+ i = hashkey(key);
+ cur = table[i];
+
+ if (!dup) {
+ tmp = (struct grouplist *)malloc(sizeof(struct grouplist));
+ tmp->groupid = gid;
+ tmp->next = NULL;
+ }
+
+ /* Check if all we have to do is insert a new groupname. */
+ while (cur) {
+ if (!dup && !strcmp(cur->key, key)) {
+ tmp->next = cur->groups;
+ cur->groups = tmp;
+ return;
+ }
+ cur = cur->next;
+ }
+
+ /* Didn't find a match -- add the whole mess to the table. */
+ new = (struct member_entry *)malloc(sizeof(struct member_entry));
+ new->key = strdup(key);
+ if (!dup)
+ new->groups = tmp;
+ else
+ new->groups = (struct grouplist *)&dummy;
+ new->next = table[i];
+ table[i] = new;
+
+ return;
+}
diff --git a/libexec/mknetid/hash.h b/libexec/mknetid/hash.h
new file mode 100644
index 0000000..5f6cd2e
--- /dev/null
+++ b/libexec/mknetid/hash.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/* Groupid entry hung off a member_entry node. */
+struct grouplist {
+ gid_t groupid;
+ struct grouplist *next;
+};
+
+/* Entry in the cooked member list hash table. */
+struct member_entry {
+ char *key; /* username */
+ struct grouplist *groups;
+ struct member_entry *next;
+};
+
+/* Table size (chosen arbitrarily). Not too big, not too small. */
+#define TABLESIZE 1024
+#define HASH_MASK 0x000003FF
+
+extern void mstore __P(( struct member_entry ** , char *, int, int ));
+extern struct grouplist *lookup __P(( struct member_entry **, char * ));
+
diff --git a/libexec/mknetid/mknetid.8 b/libexec/mknetid/mknetid.8
new file mode 100644
index 0000000..5b7ff6d
--- /dev/null
+++ b/libexec/mknetid/mknetid.8
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1995, 1996
+.\" Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd June 23, 1996
+.Dt MKNETID 8
+.Os
+.Sh NAME
+.Nm mknetid
+.Nd "generate netid map data"
+.Sh SYNOPSIS
+.Nm mknetid
+.Op Fl q
+.Op Fl g Ar group_file
+.Op Fl p Ar passwd_file
+.Op Fl h Ar hosts_file
+.Op Fl n Ar netid_file
+.Op Fl d Ar domain
+.Sh DESCRIPTION
+.Nm Mknetid
+processes the contents of the
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr hosts 5 and
+.Xr netid 5
+files into the format used to generate the
+.Pa netid.byname
+NIS map. This map is used to hold credential information for both users
+and hosts in a operating system independent format.
+.Pp
+The
+.Nm mknetid
+command checks for duplicate occurances of netids and filters
+them out.
+.Pp
+The
+.Nm mknetid
+command prints its results on the standard output. It is usually called
+only by
+.Nm /var/yp/Makefile
+when rebuilding the NIS maps.
+.Pp
+.Sh OPTIONS
+The
+.Nm mknetid
+command supports the following options:
+.Bl -tag -width flag
+.It Fl q
+Normally,
+.Nm mknetid
+prints a warning message when it encounters a duplicate netid.
+This flag turns on 'quiet' mode, allowing the warnings to be
+surpressed. Other error messages may still be generated.
+.It Fl g Ar group-file
+The
+.Fl g
+flag can be used to specify the location of the group information
+file. The compiled-in default is
+.Pa /etc/group .
+.It Fl p Ar passwd-file
+The
+.Fl p
+flag can be used to specify the location of the passwd information
+file. The compiled-in default is
+.Pa /etc/passwd .
+.It Fl h Ar group-file
+The
+.Fl h
+flag can be used to specify the location of the hosts database
+file. The compiled-in default is
+.Pa /etc/hosts .
+.It Fl n Ar netid-file
+The
+.Fl n
+flag can be used to specify the location of the netid information
+file. The compiled-in default is
+.Pa /etc/netid .
+Note that no error is generated if the netid database can't be
+found. The netid database is not likely to be present on most systems
+until Secure RPC support is added to FreeBSD.
+.It Fl d Ar domain
+By default, the
+.Nm mknetid
+command uses the system domainname when generating netid records. If
+the system domainnameis not set, the domain must be specified on the
+command line with the
+.Fl d
+flag. If the domainname is set, the
+.Fl d
+flag may be used to override it.
+.El
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /var/yp/Makefile
+The Makefile that calls
+.Nm yp_mkdb
+and
+.Nm mknetid
+to build the NIS databases.
+.It Pa /etc/group
+The default group database file.
+.It Pa /etc/passwd
+The default passwd database file.
+.It Pa /etc/hosts
+The default hosts database file.
+.It Pa /etc/netid
+The default netid database file.
+.El
+.Sh SEE ALSO
+.Xr yp 4 ,
+.Xr yp_mkdb 8
+.Sh AUTHOR
+Bill Paul <wpaul@ctr.columbia.edu>
diff --git a/libexec/mknetid/mknetid.c b/libexec/mknetid/mknetid.c
new file mode 100644
index 0000000..36bbfc4
--- /dev/null
+++ b/libexec/mknetid/mknetid.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * netid map generator program
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Center for Telecommunications Research
+ * Columbia University, New York City
+ *
+ * $Id: mknetid.c,v 1.6 1997/02/22 14:21:54 peter Exp $
+ */
+
+#include <sys/types.h>
+
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <err.h>
+#include <grp.h>
+#include <pwd.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hash.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id: mknetid.c,v 1.6 1997/02/22 14:21:54 peter Exp $";
+#endif
+
+#define LINSIZ 1024
+#define OPSYS "unix"
+
+/* Default location of group file. */
+char *groupfile = _PATH_GROUP;
+/* Default location of master.passwd file. */
+char *passfile = _PATH_PASSWD;
+/* Default location of hosts file. */
+char *hostsfile = _PATH_HOSTS;
+/* Default location of netid file */
+char *netidfile = "/etc/netid";
+
+/*
+ * Stored hash table of 'reverse' group member database
+ * which we will construct.
+ */
+struct member_entry *mtable[TABLESIZE];
+
+/*
+ * Dupe table: used to keep track of entries so we don't
+ * print the same thing twice.
+ */
+struct member_entry *dtable[TABLESIZE];
+
+extern struct group *_getgrent __P(( void ));
+extern int _setgrent __P(( void ));
+extern void _endgrent __P(( void ));
+void usage(prog)
+char *prog;
+{
+ fprintf (stderr,"usage: %s [-q] [-g group file] [-p passwd file] \
+[-h hosts file]\n\t\t\t[-d netid file] [-d domain]\n",prog);
+ exit(1);
+}
+
+extern char *optarg;
+extern FILE *_gr_fp;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ FILE *gfp, *pfp, *hfp, *nfp;
+ char readbuf[LINSIZ];
+ char writebuf[LINSIZ];
+ struct group *gr;
+ struct grouplist *glist;
+ char *domain;
+ int ch;
+ gid_t i;
+ char *ptr, *pidptr, *gidptr, *hptr;
+ int quiet = 0;
+
+ while ((ch = getopt(argc, argv, "g:p:h:n:d:q")) != -1) {
+ switch(ch) {
+ case 'g':
+ groupfile = optarg;
+ break;
+ case 'p':
+ passfile = optarg;
+ break;
+ case 'h':
+ hostsfile = optarg;
+ break;
+ case 'n':
+ netidfile = optarg;
+ break;
+ case 'd':
+ domain = optarg;
+ break;
+ case 'q':
+ quiet++;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (domain == NULL) {
+ if (yp_get_default_domain(&domain))
+ errx(1, "no domain name specified and default \
+domain not set");
+ }
+
+ if ((gfp = fopen(groupfile, "r")) == NULL) {
+ err(1, "%s", groupfile);
+ }
+
+ if ((pfp = fopen(passfile, "r")) == NULL) {
+ err(1, "%s", passfile);
+ }
+
+ if ((hfp = fopen(hostsfile, "r")) == NULL) {
+ err(1, "%s", hostsfile);
+ }
+
+ if ((nfp = fopen(netidfile, "r")) == NULL) {
+ /* netid is optional -- just continue */
+ nfp = NULL;
+ }
+
+ _gr_fp = gfp;
+
+ /* Load all the group membership info into a hash table. */
+
+ _setgrent();
+ while((gr = _getgrent()) != NULL) {
+ while(*gr->gr_mem) {
+ mstore(mtable, *gr->gr_mem, gr->gr_gid, 0);
+ gr->gr_mem++;
+ }
+ }
+
+ fclose(gfp);
+ _endgrent();
+
+ /*
+ * Now parse the passwd database, spewing out the extra
+ * group information we just stored if necessary.
+ */
+ while(fgets(readbuf, LINSIZ, pfp)) {
+ if ((ptr = strchr(readbuf, ':')) == NULL)
+ warnx("bad passwd file entry: %s", readbuf);
+ *ptr = '\0';
+ ptr++;
+ if ((ptr = strchr(ptr, ':')) == NULL)
+ warnx("bad passwd file entry: %s", readbuf);
+ *ptr = '\0';
+ ptr++;
+ pidptr = ptr;
+ if ((ptr = strchr(ptr, ':')) == NULL)
+ warnx("bad passwd file entry: %s", readbuf);
+ *ptr = '\0';
+ ptr++;
+ gidptr = ptr;
+ if ((ptr = strchr(ptr, ':')) == NULL)
+ warnx("bad passwd file entry: %s", readbuf);
+ *ptr = '\0';
+ i = atol(gidptr);
+
+ snprintf(writebuf, sizeof(writebuf), "%s.%s@%s", OPSYS,
+ pidptr, domain);
+
+ if (lookup(dtable, writebuf)) {
+ if (!quiet)
+ warnx("duplicate netid '%s.%s@%s' -- skipping",
+ OPSYS, pidptr, domain);
+ continue;
+ } else {
+ mstore(dtable, writebuf, 0, 1);
+ }
+ printf("%s.%s@%s %s:%s", OPSYS, pidptr, domain, pidptr, gidptr);
+ if ((glist = lookup(mtable, (char *)&readbuf)) != NULL) {
+ while(glist) {
+ if (glist->groupid != i)
+ printf(",%lu", glist->groupid);
+ glist = glist->next;
+ }
+ }
+ printf ("\n");
+ }
+
+ fclose(pfp);
+
+ /*
+ * Now parse the hosts database (this part sucks).
+ */
+
+ while ((ptr = fgets(readbuf, LINSIZ, hfp))) {
+ if (*ptr == '#')
+ continue;
+ if (!(hptr = strpbrk(ptr, "#\n")))
+ continue;
+ *hptr = '\0';
+ if (!(hptr = strpbrk(ptr, " \t")))
+ continue;
+ *hptr++ = '\0';
+ ptr = hptr;
+ while (*ptr == ' ' || *ptr == '\t')
+ ptr++;
+ if (!(hptr = strpbrk(ptr, " \t")))
+ continue;
+ *hptr++ = '\0';
+ snprintf(writebuf, sizeof(writebuf), "%s.%s@%s", OPSYS,
+ ptr, domain);
+ if (lookup(dtable, (char *)&writebuf)) {
+ if (!quiet)
+ warnx("duplicate netid '%s' -- skipping",
+ writebuf);
+ continue;
+ } else {
+ mstore(dtable, (char *)&writebuf, 0, 1);
+ }
+ printf ("%s.%s@%s 0:%s\n", OPSYS, ptr, domain, ptr);
+ }
+
+ fclose(hfp);
+
+ /*
+ * Lastly, copy out any extra information in the netid
+ * file. If it's not open, just ignore it: it's optional anyway.
+ */
+
+ if (nfp != NULL) {
+ while(fgets(readbuf, LINSIZ, nfp)) {
+ if (readbuf[0] == '#')
+ continue;
+ if ((ptr = strpbrk((char*)&readbuf, " \t")) == NULL) {
+ warnx("bad netid entry: '%s'", readbuf);
+ continue;
+ }
+
+ writebuf[0] = *ptr;
+ *ptr = '\0';
+ if (lookup(dtable, (char *)&readbuf)) {
+ if (!quiet)
+ warnx("duplicate netid '%s' -- skipping",
+ readbuf);
+ continue;
+ } else {
+ mstore(dtable, (char *)&readbuf, 0, 1);
+ }
+ *ptr = writebuf[0];
+ printf("%s",readbuf);
+ }
+ fclose(nfp);
+ }
+
+ exit(0);
+}
diff --git a/libexec/mknetid/parse_group.c b/libexec/mknetid/parse_group.c
new file mode 100644
index 0000000..e5fd718
--- /dev/null
+++ b/libexec/mknetid/parse_group.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef lint
+static const char rcsid[] = "$Id: parse_group.c,v 1.3 1997/02/22 14:21:54 peter Exp $";
+#endif
+
+/*
+ * This is a slightly modified chunk of getgrent(3). All the YP support
+ * and unneeded functions have been stripped out.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grp.h>
+
+FILE *_gr_fp;
+static struct group _gr_group;
+static int _gr_stayopen;
+static int grscan(), start_gr();
+
+#define MAXGRP 200
+static char *members[MAXGRP];
+#define MAXLINELENGTH 1024
+static char line[MAXLINELENGTH];
+
+struct group *
+_getgrent()
+{
+ if (!_gr_fp && !start_gr()) {
+ return NULL;
+ }
+
+
+ if (!grscan(0, 0, NULL))
+ return(NULL);
+ return(&_gr_group);
+}
+
+static int
+start_gr()
+{
+ return 1;
+}
+
+int
+_setgroupent(stayopen)
+ int stayopen;
+{
+ if (!start_gr())
+ return(0);
+ _gr_stayopen = stayopen;
+ return(1);
+}
+
+int
+_setgrent()
+{
+ return(_setgroupent(0));
+}
+
+void
+_endgrent()
+{
+ if (_gr_fp) {
+ (void)fclose(_gr_fp);
+ _gr_fp = NULL;
+ }
+}
+
+static int
+grscan(search, gid, name)
+ register int search, gid;
+ register char *name;
+{
+ register char *cp, **m;
+ char *bp;
+ for (;;) {
+ if (!fgets(line, sizeof(line), _gr_fp))
+ return(0);
+ bp = line;
+ /* skip lines that are too big */
+ if (!index(line, '\n')) {
+ int ch;
+
+ while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
+ ;
+ continue;
+ }
+ if ((_gr_group.gr_name = strsep(&bp, ":\n")) == NULL)
+ break;
+ if (_gr_group.gr_name[0] == '+')
+ continue;
+
+ if (search && name) {
+ if(strcmp(_gr_group.gr_name, name)) {
+ continue;
+ }
+ }
+ if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL)
+ break;;
+ if (!(cp = strsep(&bp, ":\n")))
+ continue;
+ _gr_group.gr_gid = atoi(cp);
+ if (search && name == NULL && _gr_group.gr_gid != gid)
+ continue;
+ cp = NULL;
+ if (bp == NULL) /* !! Must check for this! */
+ break;
+ for (m = _gr_group.gr_mem = members;; bp++) {
+ if (m == &members[MAXGRP - 1])
+ break;
+ if (*bp == ',') {
+ if (cp) {
+ *bp = '\0';
+ *m++ = cp;
+ cp = NULL;
+ }
+ } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
+ if (cp) {
+ *bp = '\0';
+ *m++ = cp;
+ }
+ break;
+ } else if (cp == NULL)
+ cp = bp;
+ }
+ *m = NULL;
+ return(1);
+ }
+ /* NOTREACHED */
+ return (0);
+}
diff --git a/libexec/named-xfer/Makefile b/libexec/named-xfer/Makefile
new file mode 100644
index 0000000..a02cb03
--- /dev/null
+++ b/libexec/named-xfer/Makefile
@@ -0,0 +1,20 @@
+# $Id$
+
+.include "${.CURDIR}/../../usr.sbin/named/Makefile.inc"
+
+.PATH: ${BIND_DIR}/named
+.PATH: ${BIND_DIR}/man
+
+PROG= named-xfer
+SRCS= named-xfer.c db_glue.c storage.c version.c
+MAN8= named-xfer.8
+
+CLEANFILES+= version.c
+
+version.c: Version.c ${BIND_DIR}/Makefile
+ (u=$${USER-root} d=`pwd` h=`hostname` t=`LC_TIME=C date`; \
+ sed -e "s|%WHEN%|$${t}|" -e "s|%VERSION%|"${VER}"|" \
+ -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+ < ${BIND_DIR}/named/Version.c > version.c)
+
+.include <bsd.prog.mk>
diff --git a/libexec/rbootd/Makefile b/libexec/rbootd/Makefile
new file mode 100644
index 0000000..0cc5ac2
--- /dev/null
+++ b/libexec/rbootd/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id: Makefile,v 1.7 1997/02/22 14:21:57 peter Exp $
+
+PROG= rbootd
+SRCS= bpf.c conf.c parseconf.c rbootd.c rmpproto.c utils.c
+MAN8= rbootd.8
+
+.include <bsd.prog.mk>
diff --git a/libexec/rbootd/bpf.c b/libexec/rbootd/bpf.c
new file mode 100644
index 0000000..ddeea4f
--- /dev/null
+++ b/libexec/rbootd/bpf.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)bpf.c 8.1 (Berkeley) 6/4/93
+ * $Id: bpf.c,v 1.7 1997/06/29 19:00:01 steve Exp $
+ *
+ * From: Utah Hdr: bpf.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static const char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "defs.h"
+#include "pathnames.h"
+
+static int BpfFd = -1;
+static unsigned BpfLen = 0;
+static u_int8_t *BpfPkt = NULL;
+
+/*
+** BpfOpen -- Open and initialize a BPF device.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** File descriptor of opened BPF device (for select() etc).
+**
+** Side Effects:
+** If an error is encountered, the program terminates here.
+*/
+int
+BpfOpen()
+{
+ struct ifreq ifr;
+ char bpfdev[32];
+ int n = 0;
+
+ /*
+ * Open the first available BPF device.
+ */
+ do {
+ (void) sprintf(bpfdev, _PATH_BPF, n++);
+ BpfFd = open(bpfdev, O_RDWR);
+ } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM));
+
+ if (BpfFd < 0) {
+ syslog(LOG_ERR, "bpf: no available devices: %m");
+ Exit(0);
+ }
+
+ /*
+ * Set interface name for bpf device, get data link layer
+ * type and make sure it's type Ethernet.
+ */
+ (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name));
+ if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName);
+ Exit(0);
+ }
+
+ /*
+ * Make sure we are dealing with an Ethernet device.
+ */
+ if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m");
+ Exit(0);
+ }
+ if (n != DLT_EN10MB) {
+ syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported",
+ IntfName, n);
+ Exit(0);
+ }
+
+ /*
+ * On read(), return packets immediately (do not buffer them).
+ */
+ n = 1;
+ if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m");
+ Exit(0);
+ }
+
+ /*
+ * Try to enable the chip/driver's multicast address filter to
+ * grab our RMP address. If this fails, try promiscuous mode.
+ * If this fails, there's no way we are going to get any RMP
+ * packets so just exit here.
+ */
+#ifdef MSG_EOR
+ ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
+#endif
+ ifr.ifr_addr.sa_family = AF_UNSPEC;
+ memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN);
+ if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) {
+ syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m");
+ Exit(0);
+ }
+
+ /*
+ * Ask BPF how much buffer space it requires and allocate one.
+ */
+ if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m");
+ Exit(0);
+ }
+ if (BpfPkt == NULL)
+ BpfPkt = (u_int8_t *)malloc(BpfLen);
+
+ if (BpfPkt == NULL) {
+ syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)",
+ BpfLen);
+ Exit(0);
+ }
+
+ /*
+ * Write a little program to snarf RMP Boot packets and stuff
+ * it down BPF's throat (i.e. set up the packet filter).
+ */
+ {
+#define RMP ((struct rmp_packet *)0)
+ static struct bpf_insn bpf_insn[] = {
+ { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap },
+ { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP },
+ { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl },
+ { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP },
+ { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap },
+ { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP },
+ { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET },
+ { BPF_RET|BPF_K, 0, 0, 0x0 }
+ };
+#undef RMP
+ static struct bpf_program bpf_pgm = {
+ sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn
+ };
+
+ if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m");
+ Exit(0);
+ }
+ }
+
+ return(BpfFd);
+}
+
+/*
+** BPF GetIntfName -- Return the name of a network interface attached to
+** the system, or 0 if none can be found. The interface
+** must be configured up; the lowest unit number is
+** preferred; loopback is ignored.
+**
+** Parameters:
+** errmsg - if no network interface found, *errmsg explains why.
+**
+** Returns:
+** A (static) pointer to interface name, or NULL on error.
+**
+** Side Effects:
+** None.
+*/
+char *
+BpfGetIntfName(errmsg)
+ char **errmsg;
+{
+ struct ifreq ibuf[8], *ifrp, *ifend, *mp;
+ struct ifconf ifc;
+ int fd;
+ int minunit, n;
+ char *cp;
+ static char device[sizeof(ifrp->ifr_name)];
+ static char errbuf[128] = "No Error!";
+
+ if (errmsg != NULL)
+ *errmsg = errbuf;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ (void) strcpy(errbuf, "bpf: socket: %m");
+ return(NULL);
+ }
+ ifc.ifc_len = sizeof ibuf;
+ ifc.ifc_buf = (caddr_t)ibuf;
+
+#ifdef OSIOCGIFCONF
+ if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m");
+ return(NULL);
+ }
+#else
+ if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m");
+ return(NULL);
+ }
+#endif
+ ifrp = ibuf;
+ ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+
+ mp = 0;
+ minunit = 666;
+ for (; ifrp < ifend; ++ifrp) {
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {
+ (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m");
+ return(NULL);
+ }
+
+ /*
+ * If interface is down or this is the loopback interface,
+ * ignore it.
+ */
+ if ((ifrp->ifr_flags & IFF_UP) == 0 ||
+#ifdef IFF_LOOPBACK
+ (ifrp->ifr_flags & IFF_LOOPBACK))
+#else
+ (strcmp(ifrp->ifr_name, "lo0") == 0))
+#endif
+ continue;
+
+ for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
+ ;
+ n = atoi(cp);
+ if (n < minunit) {
+ minunit = n;
+ mp = ifrp;
+ }
+ }
+
+ (void) close(fd);
+ if (mp == 0) {
+ (void) strcpy(errbuf, "bpf: no interfaces found");
+ return(NULL);
+ }
+
+ (void) strcpy(device, mp->ifr_name);
+ return(device);
+}
+
+/*
+** BpfRead -- Read packets from a BPF device and fill in `rconn'.
+**
+** Parameters:
+** rconn - filled in with next packet.
+** doread - is True if we can issue a read() syscall.
+**
+** Returns:
+** True if `rconn' contains a new packet, False otherwise.
+**
+** Side Effects:
+** None.
+*/
+int
+BpfRead(rconn, doread)
+ RMPCONN *rconn;
+ int doread;
+{
+ int datlen, caplen, hdrlen;
+ static u_int8_t *bp = NULL, *ep = NULL;
+ int cc;
+
+ /*
+ * The read() may block, or it may return one or more packets.
+ * We let the caller decide whether or not we can issue a read().
+ */
+ if (doread) {
+ if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) {
+ syslog(LOG_ERR, "bpf: read: %m");
+ return(0);
+ } else {
+ bp = BpfPkt;
+ ep = BpfPkt + cc;
+ }
+ }
+
+#define bhp ((struct bpf_hdr *)bp)
+ /*
+ * If there is a new packet in the buffer, stuff it into `rconn'
+ * and return a success indication.
+ */
+ if (bp < ep) {
+ datlen = bhp->bh_datalen;
+ caplen = bhp->bh_caplen;
+ hdrlen = bhp->bh_hdrlen;
+
+ if (caplen != datlen)
+ syslog(LOG_ERR,
+ "bpf: short packet dropped (%d of %d bytes)",
+ caplen, datlen);
+ else if (caplen > sizeof(struct rmp_packet))
+ syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)",
+ caplen);
+ else {
+ rconn->rmplen = caplen;
+ memmove((char *)&rconn->tstamp, (char *)&bhp->bh_tstamp,
+ sizeof(struct timeval));
+ memmove((char *)&rconn->rmp, (char *)bp + hdrlen, caplen);
+ }
+ bp += BPF_WORDALIGN(caplen + hdrlen);
+ return(1);
+ }
+#undef bhp
+
+ return(0);
+}
+
+/*
+** BpfWrite -- Write packet to BPF device.
+**
+** Parameters:
+** rconn - packet to send.
+**
+** Returns:
+** True if write succeeded, False otherwise.
+**
+** Side Effects:
+** None.
+*/
+int
+BpfWrite(rconn)
+ RMPCONN *rconn;
+{
+ if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) {
+ syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn));
+ return(0);
+ }
+
+ return(1);
+}
+
+/*
+** BpfClose -- Close a BPF device.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** None.
+*/
+void
+BpfClose()
+{
+ struct ifreq ifr;
+
+ if (BpfPkt != NULL) {
+ free((char *)BpfPkt);
+ BpfPkt = NULL;
+ }
+
+ if (BpfFd == -1)
+ return;
+
+#ifdef MSG_EOR
+ ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
+#endif
+ ifr.ifr_addr.sa_family = AF_UNSPEC;
+ memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN);
+ if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)
+ (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);
+
+ (void) close(BpfFd);
+ BpfFd = -1;
+}
diff --git a/libexec/rbootd/conf.c b/libexec/rbootd/conf.c
new file mode 100644
index 0000000..58da9f0
--- /dev/null
+++ b/libexec/rbootd/conf.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)conf.c 8.1 (Berkeley) 6/4/93
+ * $Id$
+ *
+ * From: Utah Hdr: conf.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static const char sccsid[] = "@(#)conf.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include "defs.h"
+#include "pathnames.h"
+
+/*
+** Define (and possibly initialize) global variables here.
+**
+** Caveat:
+** The maximum number of bootable files (`char *BootFiles[]') is
+** limited to C_MAXFILE (i.e. the maximum number of files that
+** can be spec'd in the configuration file). This was done to
+** simplify the boot file search code.
+*/
+
+char MyHost[MAXHOSTNAMELEN+1]; /* host name */
+pid_t MyPid; /* process id */
+int DebugFlg = 0; /* set true if debugging */
+int BootAny = 0; /* set true if we boot anyone */
+
+char *ConfigFile = NULL; /* configuration file */
+char *DfltConfig = _PATH_RBOOTDCONF; /* default configuration file */
+char *PidFile = _PATH_RBOOTDPID; /* file w/pid of server */
+char *BootDir = _PATH_RBOOTDLIB; /* directory w/boot files */
+char *DbgFile = _PATH_RBOOTDDBG; /* debug output file */
+
+FILE *DbgFp = NULL; /* debug file pointer */
+char *IntfName = NULL; /* intf we are attached to */
+
+u_int16_t SessionID = 0; /* generated session ID */
+
+char *BootFiles[C_MAXFILE]; /* list of boot files */
+
+CLIENT *Clients = NULL; /* list of addrs we'll accept */
+RMPCONN *RmpConns = NULL; /* list of active connections */
+
+u_int8_t RmpMcastAddr[RMP_ADDRLEN] = RMP_ADDR; /* RMP multicast address */
diff --git a/libexec/rbootd/defs.h b/libexec/rbootd/defs.h
new file mode 100644
index 0000000..6edde9b
--- /dev/null
+++ b/libexec/rbootd/defs.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)defs.h 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: defs.h 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#include "rmp.h"
+#include "rmp_var.h"
+
+/*
+** Common #define's and external variables. All other files should
+** include this.
+*/
+
+/*
+ * This may be defined in <sys/param.h>, if not, it's defined here.
+ */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+/*
+ * SIGUSR1 and SIGUSR2 are defined in <signal.h> for 4.3BSD systems.
+ */
+#ifndef SIGUSR1
+#define SIGUSR1 SIGEMT
+#endif
+#ifndef SIGUSR2
+#define SIGUSR2 SIGFPE
+#endif
+
+/*
+ * These can be faster & more efficient than strcmp()/strncmp()...
+ */
+#define STREQN(s1,s2) ((*s1 == *s2) && (strcmp(s1,s2) == 0))
+#define STRNEQN(s1,s2,n) ((*s1 == *s2) && (strncmp(s1,s2,n) == 0))
+
+/*
+ * Configuration file limitations.
+ */
+#define C_MAXFILE 10 /* max number of boot-able files */
+#define C_LINELEN 1024 /* max length of line */
+
+/*
+ * Direction of packet (used as argument to DispPkt).
+ */
+#define DIR_RCVD 0
+#define DIR_SENT 1
+#define DIR_NONE 2
+
+/*
+ * These need not be functions, so...
+ */
+#define FreeStr(str) free(str)
+#define FreeClient(cli) free(cli)
+#define GenSessID() (++SessionID ? SessionID: ++SessionID)
+
+/*
+ * Converting an Ethernet address to a string is done in many routines.
+ * Using `rmp.hp_hdr.saddr' works because this field is *never* changed;
+ * it will *always* contain the source address of the packet.
+ */
+#define EnetStr(rptr) GetEtherAddr(&(rptr)->rmp.hp_hdr.saddr[0])
+
+/*
+ * Every machine we can boot will have one of these allocated for it
+ * (unless there are no restrictions on who we can boot).
+ */
+typedef struct client_s {
+ u_int8_t addr[RMP_ADDRLEN]; /* addr of machine */
+ char *files[C_MAXFILE]; /* boot-able files */
+ struct client_s *next; /* ptr to next */
+} CLIENT;
+
+/*
+ * Every active connection has one of these allocated for it.
+ */
+typedef struct rmpconn_s {
+ struct rmp_packet rmp; /* RMP packet */
+ int rmplen; /* length of packet */
+ struct timeval tstamp; /* last time active */
+ int bootfd; /* open boot file */
+ struct rmpconn_s *next; /* ptr to next */
+} RMPCONN;
+
+/*
+ * All these variables are defined in "conf.c".
+ */
+extern char MyHost[]; /* this hosts' name */
+extern pid_t MyPid; /* this processes' ID */
+extern int DebugFlg; /* set true if debugging */
+extern int BootAny; /* set true if we can boot anyone */
+
+extern char *ConfigFile; /* configuration file */
+extern char *DfltConfig; /* default configuration file */
+extern char *DbgFile; /* debug output file */
+extern char *PidFile; /* file containing pid of server */
+extern char *BootDir; /* directory w/boot files */
+
+extern FILE *DbgFp; /* debug file pointer */
+extern char *IntfName; /* interface we are attached to */
+
+extern u_int16_t SessionID; /* generated session ID */
+
+extern char *BootFiles[]; /* list of boot files */
+
+extern CLIENT *Clients; /* list of addrs we'll accept */
+extern RMPCONN *RmpConns; /* list of active connections */
+
+extern u_int8_t RmpMcastAddr[]; /* RMP multicast address */
+
+void AddConn __P((RMPCONN *));
+int BootDone __P((RMPCONN *));
+void BpfClose __P((void));
+char *BpfGetIntfName __P((char **));
+int BpfOpen __P((void));
+int BpfRead __P((RMPCONN *, int));
+int BpfWrite __P((RMPCONN *));
+void DebugOff __P((int));
+void DebugOn __P((int));
+void DispPkt __P((RMPCONN *, int));
+void DoTimeout __P((void));
+void DspFlnm __P((u_int, char *));
+void Exit __P((int));
+CLIENT *FindClient __P((RMPCONN *));
+RMPCONN *FindConn __P((RMPCONN *));
+void FreeClients __P((void));
+void FreeConn __P((RMPCONN *));
+void FreeConns __P((void));
+int GetBootFiles __P((void));
+char *GetEtherAddr __P((u_int8_t *));
+CLIENT *NewClient __P((u_int8_t *));
+RMPCONN *NewConn __P((RMPCONN *));
+char *NewStr __P((char *));
+u_int8_t *ParseAddr __P((char *));
+int ParseConfig __P((void));
+void ProcessPacket __P((RMPCONN *, CLIENT *));
+void ReConfig __P((int));
+void RemoveConn __P((RMPCONN *));
+int SendBootRepl __P((struct rmp_packet *, RMPCONN *, char *[]));
+int SendFileNo __P((struct rmp_packet *, RMPCONN *, char *[]));
+int SendPacket __P((RMPCONN *));
+int SendReadRepl __P((RMPCONN *));
+int SendServerID __P((RMPCONN *));
diff --git a/libexec/rbootd/parseconf.c b/libexec/rbootd/parseconf.c
new file mode 100644
index 0000000..4950e4f
--- /dev/null
+++ b/libexec/rbootd/parseconf.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)parseconf.c 8.1 (Berkeley) 6/4/93
+ * $Id: parseconf.c,v 1.6 1997/06/29 19:00:08 steve Exp $
+ *
+ * From: Utah Hdr: parseconf.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static const char sccsid[] = "@(#)parseconf.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include "defs.h"
+
+/*
+** ParseConfig -- parse the config file into linked list of clients.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** 1 on success, 0 otherwise.
+**
+** Side Effects:
+** - Linked list of clients will be (re)allocated.
+**
+** Warnings:
+** - GetBootFiles() must be called before this routine
+** to create a linked list of default boot files.
+*/
+int
+ParseConfig()
+{
+ FILE *fp;
+ CLIENT *client;
+ u_int8_t *addr;
+ char line[C_LINELEN];
+ char *cp, *bcp;
+ int i, j;
+ int omask, linecnt = 0;
+
+ if (BootAny) /* ignore config file */
+ return(1);
+
+ FreeClients(); /* delete old list of clients */
+
+ if ((fp = fopen(ConfigFile, "r")) == NULL) {
+ syslog(LOG_ERR, "ParseConfig: can't open config file (%s)",
+ ConfigFile);
+ return(0);
+ }
+
+ /*
+ * We've got to block SIGHUP to prevent reconfiguration while
+ * dealing with the linked list of Clients. This can be done
+ * when actually linking the new client into the list, but
+ * this could have unexpected results if the server was HUP'd
+ * whilst reconfiguring. Hence, it is done here.
+ */
+ omask = sigblock(sigmask(SIGHUP));
+
+ /*
+ * GETSTR positions `bcp' at the start of the current token,
+ * and null terminates it. `cp' is positioned at the start
+ * of the next token. spaces & commas are separators.
+ */
+#define GETSTR while (isspace(*cp) || *cp == ',') cp++; \
+ bcp = cp; \
+ while (*cp && *cp!=',' && !isspace(*cp)) cp++; \
+ if (*cp) *cp++ = '\0'
+
+ /*
+ * For each line, parse it into a new CLIENT struct.
+ */
+ while (fgets(line, C_LINELEN, fp) != NULL) {
+ linecnt++; /* line counter */
+
+ if (*line == '\0' || *line == '#') /* ignore comment */
+ continue;
+
+ if ((cp = strchr(line,'#')) != NULL) /* trash comments */
+ *cp = '\0';
+
+ cp = line; /* init `cp' */
+ GETSTR; /* get RMP addr */
+ if (bcp == cp) /* all delimiters */
+ continue;
+
+ /*
+ * Get an RMP address from a string. Abort on failure.
+ */
+ if ((addr = ParseAddr(bcp)) == NULL) {
+ syslog(LOG_ERR,
+ "ParseConfig: line %d: cant parse <%s>",
+ linecnt, bcp);
+ continue;
+ }
+
+ if ((client = NewClient(addr)) == NULL) /* alloc new client */
+ continue;
+
+ GETSTR; /* get first file */
+
+ /*
+ * If no boot files are spec'd, use the default list.
+ * Otherwise, validate each file (`bcp') against the
+ * list of boot-able files.
+ */
+ i = 0;
+ if (bcp == cp) /* no files spec'd */
+ for (; i < C_MAXFILE && BootFiles[i] != NULL; i++)
+ client->files[i] = BootFiles[i];
+ else {
+ do {
+ /*
+ * For each boot file spec'd, make sure it's
+ * in our list. If so, include a pointer to
+ * it in the CLIENT's list of boot files.
+ */
+ for (j = 0; ; j++) {
+ if (j==C_MAXFILE||BootFiles[j]==NULL) {
+ syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)",
+ linecnt, bcp);
+ break;
+ }
+ if (STREQN(BootFiles[j], bcp)) {
+ if (i < C_MAXFILE)
+ client->files[i++] =
+ BootFiles[j];
+ else
+ syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)",
+ linecnt, bcp);
+ break;
+ }
+ }
+ GETSTR; /* get next file */
+ } while (bcp != cp);
+
+ /*
+ * Restricted list of boot files were spec'd,
+ * however, none of them were found. Since we
+ * apparently cant let them boot "just anything",
+ * the entire record is invalidated.
+ */
+ if (i == 0) {
+ FreeClient(client);
+ continue;
+ }
+ }
+
+ /*
+ * Link this client into the linked list of clients.
+ * SIGHUP has already been blocked.
+ */
+ if (Clients)
+ client->next = Clients;
+ Clients = client;
+ }
+
+ (void) fclose(fp); /* close config file */
+
+ (void) sigsetmask(omask); /* reset signal mask */
+
+ return(1); /* return success */
+}
+
+/*
+** ParseAddr -- Parse a string containing an RMP address.
+**
+** This routine is fairly liberal at parsing an RMP address. The
+** address must contain 6 octets consisting of between 0 and 2 hex
+** chars (upper/lower case) separated by colons. If two colons are
+** together (e.g. "::", the octet between them is recorded as being
+** zero. Hence, the following addrs are all valid and parse to the
+** same thing:
+**
+** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD
+**
+** For clarity, an RMP address is really an Ethernet address, but
+** since the HP boot code uses IEEE 802.3, it's really an IEEE
+** 802.3 address. Of course, all of these are identical.
+**
+** Parameters:
+** str - string representation of an RMP address.
+**
+** Returns:
+** pointer to a static array of RMP_ADDRLEN bytes.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - The return value points to a static buffer; it must
+** be copied if it's to be saved.
+*/
+u_int8_t *
+ParseAddr(str)
+ char *str;
+{
+ static u_int8_t addr[RMP_ADDRLEN];
+ char *cp;
+ unsigned i;
+ int part, subpart;
+
+ memset((char *)&addr[0], 0, RMP_ADDRLEN); /* zero static buffer */
+
+ part = subpart = 0;
+ for (cp = str; *cp; cp++) {
+ /*
+ * A colon (`:') must be used to delimit each octet.
+ */
+ if (*cp == ':') {
+ if (++part == RMP_ADDRLEN) /* too many parts */
+ return(NULL);
+ subpart = 0;
+ continue;
+ }
+
+ /*
+ * Convert hex character to an integer.
+ */
+ if (isdigit(*cp))
+ i = *cp - '0';
+ else {
+ i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10;
+ if (i < 10 || i > 15) /* not a hex char */
+ return(NULL);
+ }
+
+ if (subpart++) {
+ if (subpart > 2) /* too many hex chars */
+ return(NULL);
+ addr[part] <<= 4;
+ }
+ addr[part] |= i;
+ }
+
+ if (part != (RMP_ADDRLEN-1)) /* too few parts */
+ return(NULL);
+
+ return(&addr[0]);
+}
+
+/*
+** GetBootFiles -- record list of files in current (boot) directory.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Number of boot files on success, 0 on failure.
+**
+** Side Effects:
+** Strings in `BootFiles' are freed/allocated.
+**
+** Warnings:
+** - After this routine is called, ParseConfig() must be
+** called to re-order it's list of boot file pointers.
+*/
+int
+GetBootFiles()
+{
+ DIR *dfd;
+ struct stat statb;
+ struct dirent *dp;
+ int i;
+
+ /*
+ * Free the current list of boot files.
+ */
+ for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) {
+ FreeStr(BootFiles[i]);
+ BootFiles[i] = NULL;
+ }
+
+ /*
+ * Open current directory to read boot file names.
+ */
+ if ((dfd = opendir(".")) == NULL) { /* open BootDir */
+ syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n",
+ BootDir);
+ return(0);
+ }
+
+ /*
+ * Read each boot file name and allocate space for it in the
+ * list of boot files (BootFiles). All boot files read after
+ * C_MAXFILE will be ignored.
+ */
+ i = 0;
+ for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) {
+ if (stat(dp->d_name, &statb) < 0 ||
+ (statb.st_mode & S_IFMT) != S_IFREG)
+ continue;
+ if (i == C_MAXFILE)
+ syslog(LOG_ERR,
+ "GetBootFiles: too many boot files (%s ignored)",
+ dp->d_name);
+ else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL)
+ i++;
+ }
+
+ (void) closedir(dfd); /* close BootDir */
+
+ if (i == 0) /* cant find any boot files */
+ syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir);
+
+ return(i);
+}
diff --git a/libexec/bugfiler/extern.h b/libexec/rbootd/pathnames.h
index b096f3d..56b9deb 100644
--- a/libexec/bugfiler/extern.h
+++ b/libexec/rbootd/pathnames.h
@@ -1,7 +1,15 @@
-/*-
- * Copyright (c) 1993
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,12 +38,14 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)extern.h 8.1 (Berkeley) 6/4/93
+ * from: @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: pathnames.h 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
*/
-void error __P((char *, char *));
-void gethead __P((int));
-int process __P((void));
-void redist __P((void));
-void reply __P((void));
-void seterr __P((void));
+#define _PATH_BPF "/dev/bpf%d"
+#define _PATH_RBOOTDCONF "/etc/rbootd.conf"
+#define _PATH_RBOOTDDBG "/tmp/rbootd.dbg"
+#define _PATH_RBOOTDLIB "/usr/mdec/rbootd"
+#define _PATH_RBOOTDPID "/var/run/rbootd.pid"
diff --git a/libexec/rbootd/rbootd.8 b/libexec/rbootd/rbootd.8
new file mode 100644
index 0000000..23c37c5
--- /dev/null
+++ b/libexec/rbootd/rbootd.8
@@ -0,0 +1,156 @@
+.\" Copyright (c) 1988, 1992 The University of Utah and the Center
+.\" for Software Science (CSS).
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Center for Software Science of the University of Utah Computer
+.\" Science Department. CSS requests users of this software to return
+.\" to css-dist@cs.utah.edu any improvements that they make and grant
+.\" CSS redistribution rights.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)rbootd.8 8.2 (Berkeley) 12/11/93
+.\" $Id: rbootd.8,v 1.6 1997/06/23 04:02:13 steve Exp $
+.\"
+.\" Utah Hdr: rbootd.man 3.1 92/07/06
+.\" Author: Jeff Forys, University of Utah CSS
+.\"
+.Dd December 11, 1993
+.Dt RBOOTD 8
+.Os
+.Sh NAME
+.Nm rbootd
+.Nd HP remote boot server
+.Sh SYNOPSIS
+.Nm rbootd
+.Op Fl ad
+.Op Fl i Ar interface
+.Op config_file
+.Sh DESCRIPTION
+The
+.Nm rbootd
+utility services boot requests from Hewlett-Packard workstations over a
+local area network.
+All boot files must reside in the boot file directory; further, if a
+client supplies path information in its boot request, it will be silently
+stripped away before processing.
+By default,
+.Nm rbootd
+only responds to requests from machines listed in its configuration file.
+.Pp
+The options are as follows:
+.Bl -tag -width Fl
+.It Fl a
+Respond to boot requests from any machine.
+The configuration file is ignored if this option is specified.
+.It Fl d
+Run
+.Nm rbootd
+in debug mode.
+Packets sent and received are displayed to the terminal.
+.It Fl i Ar interface
+Service boot requests on specified interface.
+If unspecified,
+.Nm rbootd
+searches the system interface list for the lowest numbered, configured
+``up'' interface (excluding loopback).
+Ties are broken by choosing the earliest match.
+.El
+.Pp
+Specifying
+.Ar config_file
+on the command line causes
+.Nm rbootd
+to use a different configuration file from the default.
+.Pp
+The configuration file is a text file where each line describes a particular
+machine.
+A line must start with a machine's Ethernet address followed by an optional
+list of boot file names.
+An Ethernet address is specified in hexadecimal with each of its six octets
+separated by a colon.
+The boot file names come from the boot file directory.
+The ethernet address and boot file(s) must be separated by white-space
+and/or comma characters.
+A pound sign causes the remainder of a line to be ignored.
+.Pp
+Here is a sample configuration file:
+.Bl -column 08:00:09:0:66:ad SYSHPBSD,SYSHPUX "# vandy (anything)"
+.It #
+.It # ethernet addr boot file(s) comments
+.It #
+.It 08:00:09:0:66:ad SYSHPBSD # snake (4.3BSD)
+.It 08:00:09:0:59:5b # vandy (anything)
+.It 8::9:1:C6:75 SYSHPBSD,SYSHPUX # jaguar (either)
+.El
+.Pp
+.Nm Rbootd
+logs status and error messages via
+.Xr syslog 3 .
+A startup message is always logged, and in the case of fatal errors (or
+deadly signals) a message is logged announcing the server's termination.
+In general, a non-fatal error is handled by ignoring the event that caused
+it (e.g. an invalid Ethernet address in the config file causes that line
+to be invalidated).
+.Pp
+The following signals have the specified effect when sent to the server
+process using the
+.Xr kill 1
+command:
+.Bl -tag -width SIGUSR1 -offset -compact
+.It SIGHUP
+Drop all active connections and reconfigure.
+.It SIGUSR1
+Turn on debugging, do nothing if already on.
+.It SIGUSR2
+Turn off debugging, do nothing if already off.
+.El
+.Sh "FILES"
+.Bl -tag -width /usr/libexec/rbootd -compact
+.It /dev/bpf#
+packet-filter device
+.It /etc/rbootd.conf
+configuration file
+.It /tmp/rbootd.dbg
+debug output
+.It /usr/mdec/rbootd
+directory containing boot files
+.It /var/run/rbootd.pid
+process id
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr socket 2 ,
+.Xr signal 3 ,
+.Xr syslog 3
+.Sh BUGS
+If multiple servers are started on the same interface, each will receive
+and respond to the same boot packets.
diff --git a/libexec/rbootd/rbootd.c b/libexec/rbootd/rbootd.c
new file mode 100644
index 0000000..0129c6d
--- /dev/null
+++ b/libexec/rbootd/rbootd.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)rbootd.c 8.1 (Berkeley) 6/4/93
+ * $Id: rbootd.c,v 1.7 1997/06/29 19:00:15 steve Exp $
+ *
+ * From: Utah Hdr: rbootd.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static const char sccsid[] = "@(#)rbootd.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "defs.h"
+
+extern char *__progname; /* from crt0.o */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c, fd, omask, maxfds;
+ fd_set rset;
+
+ /*
+ * Close any open file descriptors.
+ * Temporarily leave stdin & stdout open for `-d',
+ * and stderr open for any pre-syslog error messages.
+ */
+ {
+ int i, nfds = getdtablesize();
+
+ for (i = 0; i < nfds; i++)
+ if (i != fileno(stdin) && i != fileno(stdout) &&
+ i != fileno(stderr))
+ (void) close(i);
+ }
+
+ /*
+ * Parse any arguments.
+ */
+ while ((c = getopt(argc, argv, "adi:")) != -1)
+ switch(c) {
+ case 'a':
+ BootAny++;
+ break;
+ case 'd':
+ DebugFlg++;
+ break;
+ case 'i':
+ IntfName = optarg;
+ break;
+ }
+ for (; optind < argc; optind++) {
+ if (ConfigFile == NULL)
+ ConfigFile = argv[optind];
+ else {
+ warnx("too many config files (`%s' ignored)\n",
+ argv[optind]);
+ }
+ }
+
+ if (ConfigFile == NULL) /* use default config file */
+ ConfigFile = DfltConfig;
+
+ if (DebugFlg) {
+ DbgFp = stdout; /* output to stdout */
+
+ (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */
+ (void) signal(SIGUSR2, SIG_IGN);
+ (void) fclose(stderr); /* finished with it */
+ } else {
+ if (daemon(0, 0))
+ err(1, "can't detach from terminal");
+
+ (void) signal(SIGUSR1, DebugOn);
+ (void) signal(SIGUSR2, DebugOff);
+ }
+
+ openlog(__progname, LOG_PID, LOG_DAEMON);
+
+ /*
+ * If no interface was specified, get one now.
+ *
+ * This is convoluted because we want to get the default interface
+ * name for the syslog("restarted") message. If BpfGetIntfName()
+ * runs into an error, it will return a syslog-able error message
+ * (in `errmsg') which will be displayed here.
+ */
+ if (IntfName == NULL) {
+ char *errmsg;
+
+ if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) {
+ syslog(LOG_NOTICE, "restarted (??)");
+ syslog(LOG_ERR, errmsg);
+ Exit(0);
+ }
+ }
+
+ syslog(LOG_NOTICE, "restarted (%s)", IntfName);
+
+ (void) signal(SIGHUP, ReConfig);
+ (void) signal(SIGINT, Exit);
+ (void) signal(SIGTERM, Exit);
+
+ /*
+ * Grab our host name and pid.
+ */
+ if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) {
+ syslog(LOG_ERR, "gethostname: %m");
+ Exit(0);
+ }
+ MyHost[MAXHOSTNAMELEN] = '\0';
+
+ MyPid = getpid();
+
+ /*
+ * Write proc's pid to a file.
+ */
+ {
+ FILE *fp;
+
+ if ((fp = fopen(PidFile, "w")) != NULL) {
+ (void) fprintf(fp, "%d\n", (int) MyPid);
+ (void) fclose(fp);
+ } else {
+ syslog(LOG_WARNING, "fopen: failed (%s)", PidFile);
+ }
+ }
+
+ /*
+ * All boot files are relative to the boot directory, we might
+ * as well chdir() there to make life easier.
+ */
+ if (chdir(BootDir) < 0) {
+ syslog(LOG_ERR, "chdir: %m (%s)", BootDir);
+ Exit(0);
+ }
+
+ /*
+ * Initial configuration.
+ */
+ omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */
+ if (GetBootFiles() == 0) /* get list of boot files */
+ Exit(0);
+ if (ParseConfig() == 0) /* parse config file */
+ Exit(0);
+
+ /*
+ * Open and initialize a BPF device for the appropriate interface.
+ * If an error is encountered, a message is displayed and Exit()
+ * is called.
+ */
+ fd = BpfOpen();
+
+ (void) sigsetmask(omask); /* allow reconfig's */
+
+ /*
+ * Main loop: receive a packet, determine where it came from,
+ * and if we service this host, call routine to handle request.
+ */
+ maxfds = fd + 1;
+ FD_ZERO(&rset);
+ FD_SET(fd, &rset);
+ for (;;) {
+ struct timeval timeout;
+ fd_set r;
+ int nsel;
+
+ r = rset;
+
+ if (RmpConns == NULL) { /* timeout isnt necessary */
+ nsel = select(maxfds, &r, NULL, NULL, NULL);
+ } else {
+ timeout.tv_sec = RMP_TIMEOUT;
+ timeout.tv_usec = 0;
+ nsel = select(maxfds, &r, NULL, NULL, &timeout);
+ }
+
+ if (nsel < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "select: %m");
+ Exit(0);
+ } else if (nsel == 0) { /* timeout */
+ DoTimeout(); /* clear stale conns */
+ continue;
+ }
+
+ if (FD_ISSET(fd, &r)) {
+ RMPCONN rconn;
+ CLIENT *client, *FindClient();
+ int doread = 1;
+
+ while (BpfRead(&rconn, doread)) {
+ doread = 0;
+
+ if (DbgFp != NULL) /* display packet */
+ DispPkt(&rconn,DIR_RCVD);
+
+ omask = sigblock(sigmask(SIGHUP));
+
+ /*
+ * If we do not restrict service, set the
+ * client to NULL (ProcessPacket() handles
+ * this). Otherwise, check that we can
+ * service this host; if not, log a message
+ * and ignore the packet.
+ */
+ if (BootAny) {
+ client = NULL;
+ } else if ((client=FindClient(&rconn))==NULL) {
+ syslog(LOG_INFO,
+ "%s: boot packet ignored",
+ EnetStr(&rconn));
+ (void) sigsetmask(omask);
+ continue;
+ }
+
+ ProcessPacket(&rconn,client);
+
+ (void) sigsetmask(omask);
+ }
+ }
+ }
+}
+
+/*
+** DoTimeout -- Free any connections that have timed out.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Timed out connections in `RmpConns' will be freed.
+*/
+void
+DoTimeout()
+{
+ RMPCONN *rtmp;
+ struct timeval now;
+
+ (void) gettimeofday(&now, (struct timezone *)0);
+
+ /*
+ * For each active connection, if RMP_TIMEOUT seconds have passed
+ * since the last packet was sent, delete the connection.
+ */
+ for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
+ if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) {
+ syslog(LOG_WARNING, "%s: connection timed out (%u)",
+ EnetStr(rtmp), rtmp->rmp.r_type);
+ RemoveConn(rtmp);
+ }
+}
+
+/*
+** FindClient -- Find client associated with a packet.
+**
+** Parameters:
+** rconn - the new packet.
+**
+** Returns:
+** Pointer to client info if found, NULL otherwise.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked since
+** a reconfigure can invalidate the information returned.
+*/
+
+CLIENT *
+FindClient(rconn)
+ RMPCONN *rconn;
+{
+ CLIENT *ctmp;
+
+ for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next)
+ if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
+ (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0)
+ break;
+
+ return(ctmp);
+}
+
+/*
+** Exit -- Log an error message and exit.
+**
+** Parameters:
+** sig - caught signal (or zero if not dying on a signal).
+**
+** Returns:
+** Does not return.
+**
+** Side Effects:
+** - This process ceases to exist.
+*/
+void
+Exit(sig)
+ int sig;
+{
+ if (sig > 0)
+ syslog(LOG_ERR, "going down on signal %d", sig);
+ else
+ syslog(LOG_ERR, "going down with fatal error");
+ BpfClose();
+ exit(1);
+}
+
+/*
+** ReConfig -- Get new list of boot files and reread config files.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - All active connections are dropped.
+** - List of boot-able files is changed.
+** - List of clients is changed.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+ReConfig(signo)
+ int signo;
+{
+ syslog(LOG_NOTICE, "reconfiguring boot server");
+
+ FreeConns();
+
+ if (GetBootFiles() == 0)
+ Exit(0);
+
+ if (ParseConfig() == 0)
+ Exit(0);
+}
+
+/*
+** DebugOff -- Turn off debugging.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Debug file is closed.
+*/
+void
+DebugOff(signo)
+ int signo;
+{
+ if (DbgFp != NULL)
+ (void) fclose(DbgFp);
+
+ DbgFp = NULL;
+}
+
+/*
+** DebugOn -- Turn on debugging.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Debug file is opened/truncated if not already opened,
+** otherwise do nothing.
+*/
+void
+DebugOn(signo)
+ int signo;
+{
+ if (DbgFp == NULL) {
+ if ((DbgFp = fopen(DbgFile, "w")) == NULL)
+ syslog(LOG_ERR, "can't open debug file (%s)", DbgFile);
+ }
+}
diff --git a/libexec/rbootd/rmp.h b/libexec/rbootd/rmp.h
new file mode 100644
index 0000000..c4285c9
--- /dev/null
+++ b/libexec/rbootd/rmp.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)rmp.h 8.1 (Berkeley) 6/4/93
+ *
+ * From: Utah Hdr: rmp.h 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+/*
+ * Define MIN/MAX sizes of RMP (ethernet) packet.
+ * For ease of computation, the 4 octet CRC field is not included.
+ *
+ * MCLBYTES is for bpfwrite(); it is adamant about using a cluster.
+ */
+
+#define RMP_MAX_PACKET MIN(1514,MCLBYTES)
+#define RMP_MIN_PACKET 60
+
+/*
+ * Define RMP/Ethernet Multicast address (9:0:9:0:0:4) and its length.
+ */
+#define RMP_ADDR { 0x9, 0x0, 0x9, 0x0, 0x0, 0x4 }
+#define RMP_ADDRLEN 6
+
+/*
+ * Define IEEE802.2 (Logical Link Control) information.
+ */
+#define IEEE_DSAP_HP 0xF8 /* Destination Service Access Point */
+#define IEEE_SSAP_HP 0xF8 /* Source Service Access Point */
+#define IEEE_CNTL_HP 0x0300 /* Type 1 / I format control information */
+
+#define HPEXT_DXSAP 0x608 /* HP Destination Service Access Point */
+#define HPEXT_SXSAP 0x609 /* HP Source Service Access Point */
+
+/*
+ * 802.3-style "Ethernet" header.
+ */
+
+struct hp_hdr {
+ u_int8_t daddr[RMP_ADDRLEN];
+ u_int8_t saddr[RMP_ADDRLEN];
+ u_int16_t len;
+};
+
+/*
+ * HP uses 802.2 LLC with their own local extensions. This struct makes
+ * sense out of this data (encapsulated in the above 802.3 packet).
+ */
+
+struct hp_llc {
+ u_int8_t dsap; /* 802.2 DSAP */
+ u_int8_t ssap; /* 802.2 SSAP */
+ u_int16_t cntrl; /* 802.2 control field */
+ u_int16_t filler; /* HP filler (must be zero) */
+ u_int16_t dxsap; /* HP extended DSAP */
+ u_int16_t sxsap; /* HP extended SSAP */
+};
diff --git a/libexec/rbootd/rmp_var.h b/libexec/rbootd/rmp_var.h
new file mode 100644
index 0000000..3a9c7f4
--- /dev/null
+++ b/libexec/rbootd/rmp_var.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)rmp_var.h 8.1 (Berkeley) 6/4/93
+ *
+ * from: Utah Hdr: rmp_var.h 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+/*
+ * Possible values for "rmp_type" fields.
+ */
+
+#define RMP_BOOT_REQ 1 /* boot request packet */
+#define RMP_BOOT_REPL 129 /* boot reply packet */
+#define RMP_READ_REQ 2 /* read request packet */
+#define RMP_READ_REPL 130 /* read reply packet */
+#define RMP_BOOT_DONE 3 /* boot complete packet */
+
+/*
+ * Useful constants.
+ */
+
+#define RMP_VERSION 2 /* protocol version */
+#define RMP_TIMEOUT 600 /* timeout connection after ten minutes */
+#define RMP_PROBESID 0xffff /* session ID for probes */
+#define RMP_HOSTLEN 13 /* max length of server's name */
+#define RMP_MACHLEN 20 /* length of machine type field */
+
+/*
+ * RMP error codes
+ */
+
+#define RMP_E_OKAY 0
+#define RMP_E_EOF 2 /* read reply: returned end of file */
+#define RMP_E_ABORT 3 /* abort operation */
+#define RMP_E_BUSY 4 /* boot reply: server busy */
+#define RMP_E_TIMEOUT 5 /* lengthen time out (not implemented) */
+#define RMP_E_NOFILE 16 /* boot reply: file does not exist */
+#define RMP_E_OPENFILE 17 /* boot reply: file open failed */
+#define RMP_E_NODFLT 18 /* boot reply: default file does not exist */
+#define RMP_E_OPENDFLT 19 /* boot reply: default file open failed */
+#define RMP_E_BADSID 25 /* read reply: bad session ID */
+#define RMP_E_BADPACKET 27 /* Bad packet detected */
+
+/*
+ * RMPDATALEN is the maximum number of data octets that can be stuffed
+ * into an RMP packet. This excludes the 802.2 LLC w/HP extensions.
+ */
+#define RMPDATALEN (RMP_MAX_PACKET - (sizeof(struct hp_hdr) + \
+ sizeof(struct hp_llc)))
+
+/*
+ * Define sizes of packets we send. Boot and Read replies are variable
+ * in length depending on the length of `s'.
+ *
+ * Also, define how much space `restofpkt' can take up for outgoing
+ * Boot and Read replies. Boot Request packets are effectively
+ * limited to 255 bytes due to the preceding 1-byte length field.
+ */
+
+#define RMPBOOTSIZE(s) (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
+ sizeof(struct rmp_boot_repl) + s - sizeof(restofpkt))
+#define RMPREADSIZE(s) (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
+ sizeof(struct rmp_read_repl) + s - sizeof(restofpkt) \
+ - sizeof(u_int8_t))
+#define RMPDONESIZE (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
+ sizeof(struct rmp_boot_done))
+#define RMPBOOTDATA 255
+#define RMPREADDATA (RMPDATALEN - \
+ (2*sizeof(u_int8_t)+sizeof(u_int16_t)+sizeof(u_word)))
+
+/*
+ * This protocol defines some field sizes as "rest of ethernet packet".
+ * There is no easy way to specify this in C, so we use a one character
+ * field to denote it, and index past it to the end of the packet.
+ */
+
+typedef char restofpkt;
+
+/*
+ * Due to the RMP packet layout, we'll run into alignment problems
+ * on machines that can't access (or don't, by default, align) words
+ * on half-word boundaries. If you know that your machine does not suffer
+ * from this problem, add it to the vax/tahoe/m68k #define below.
+ *
+ * The following macros are used to deal with this problem:
+ * WORDZE(w) Return True if u_word `w' is zero, False otherwise.
+ * ZEROWORD(w) Set u_word `w' to zero.
+ * COPYWORD(w1,w2) Copy u_word `w1' to `w2'.
+ * GETWORD(w,i) Copy u_word `w' into int `i'.
+ * PUTWORD(i,w) Copy int `i' into u_word `w'.
+ *
+ * N.B. Endianness is handled by use of ntohl/htonl
+ */
+#if defined(__vax__) || defined(__tahoe__) || defined(__m68k__)
+
+typedef u_int32_t u_word;
+
+#define WORDZE(w) ((w) == 0)
+#define ZEROWORD(w) (w) = 0
+#define COPYWORD(w1,w2) (w2) = (w1)
+#define GETWORD(w, i) (i) = ntohl(w)
+#define PUTWORD(i, w) (w) = htonl(i)
+
+#else
+
+#define _WORD_HIGHPART 0
+#define _WORD_LOWPART 1
+
+typedef struct _uword { u_int16_t val[2]; } u_word;
+
+#define WORDZE(w) \
+ ((w.val[_WORD_HIGHPART] == 0) && (w.val[_WORD_LOWPART] == 0))
+#define ZEROWORD(w) \
+ (w).val[_WORD_HIGHPART] = (w).val[_WORD_LOWPART] = 0
+#define COPYWORD(w1, w2) \
+ { (w2).val[_WORD_HIGHPART] = (w1).val[_WORD_HIGHPART]; \
+ (w2).val[_WORD_LOWPART] = (w1).val[_WORD_LOWPART]; \
+ }
+#define GETWORD(w, i) \
+ (i) = (((u_int32_t)ntohs((w).val[_WORD_HIGHPART])) << 16) | ntohs((w).val[_WORD_LOWPART])
+#define PUTWORD(i, w) \
+ { (w).val[_WORD_HIGHPART] = htons((u_int16_t) ((i >> 16) & 0xffff)); \
+ (w).val[_WORD_LOWPART] = htons((u_int16_t) (i & 0xffff)); \
+ }
+
+#endif
+
+/*
+ * Packet structures.
+ */
+
+struct rmp_raw { /* generic RMP packet */
+ u_int8_t rmp_type; /* packet type */
+ u_int8_t rmp_rawdata[RMPDATALEN-1];
+};
+
+struct rmp_boot_req { /* boot request */
+ u_int8_t rmp_type; /* packet type (RMP_BOOT_REQ) */
+ u_int8_t rmp_retcode; /* return code (0) */
+ u_word rmp_seqno; /* sequence number (real time clock) */
+ u_int16_t rmp_session; /* session id (normally 0) */
+ u_int16_t rmp_version; /* protocol version (RMP_VERSION) */
+ char rmp_machtype[RMP_MACHLEN]; /* machine type */
+ u_int8_t rmp_flnmsize; /* length of rmp_flnm */
+ restofpkt rmp_flnm; /* name of file to be read */
+};
+
+struct rmp_boot_repl { /* boot reply */
+ u_int8_t rmp_type; /* packet type (RMP_BOOT_REPL) */
+ u_int8_t rmp_retcode; /* return code (normally 0) */
+ u_word rmp_seqno; /* sequence number (from boot req) */
+ u_int16_t rmp_session; /* session id (generated) */
+ u_int16_t rmp_version; /* protocol version (RMP_VERSION) */
+ u_int8_t rmp_flnmsize; /* length of rmp_flnm */
+ restofpkt rmp_flnm; /* name of file (from boot req) */
+};
+
+struct rmp_read_req { /* read request */
+ u_int8_t rmp_type; /* packet type (RMP_READ_REQ) */
+ u_int8_t rmp_retcode; /* return code (0) */
+ u_word rmp_offset; /* file relative byte offset */
+ u_int16_t rmp_session; /* session id (from boot repl) */
+ u_int16_t rmp_size; /* max no of bytes to send */
+};
+
+struct rmp_read_repl { /* read reply */
+ u_int8_t rmp_type; /* packet type (RMP_READ_REPL) */
+ u_int8_t rmp_retcode; /* return code (normally 0) */
+ u_word rmp_offset; /* byte offset (from read req) */
+ u_int16_t rmp_session; /* session id (from read req) */
+ restofpkt rmp_data; /* data (max size from read req) */
+ u_int8_t rmp_unused; /* padding to 16-bit boundary */
+};
+
+struct rmp_boot_done { /* boot complete */
+ u_int8_t rmp_type; /* packet type (RMP_BOOT_DONE) */
+ u_int8_t rmp_retcode; /* return code (0) */
+ u_word rmp_unused; /* not used (0) */
+ u_int16_t rmp_session; /* session id (from read repl) */
+};
+
+struct rmp_packet {
+ struct hp_hdr hp_hdr;
+ struct hp_llc hp_llc;
+ union {
+ struct rmp_boot_req rmp_brq; /* boot request */
+ struct rmp_boot_repl rmp_brpl; /* boot reply */
+ struct rmp_read_req rmp_rrq; /* read request */
+ struct rmp_read_repl rmp_rrpl; /* read reply */
+ struct rmp_boot_done rmp_done; /* boot complete */
+ struct rmp_raw rmp_raw; /* raw data */
+ } rmp_proto;
+};
+
+/*
+ * Make life easier...
+ */
+
+#define r_type rmp_proto.rmp_raw.rmp_type
+#define r_data rmp_proto.rmp_raw.rmp_rawdata
+#define r_brq rmp_proto.rmp_brq
+#define r_brpl rmp_proto.rmp_brpl
+#define r_rrq rmp_proto.rmp_rrq
+#define r_rrpl rmp_proto.rmp_rrpl
+#define r_done rmp_proto.rmp_done
diff --git a/libexec/rbootd/rmpproto.c b/libexec/rbootd/rmpproto.c
new file mode 100644
index 0000000..31102e8
--- /dev/null
+++ b/libexec/rbootd/rmpproto.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)rmpproto.c 8.1 (Berkeley) 6/4/93
+ * $Id: rmpproto.c,v 1.2 1997/06/29 19:00:24 steve Exp $
+ *
+ * From: Utah Hdr: rmpproto.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static const char sccsid[] = "@(#)rmpproto.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "defs.h"
+
+/*
+** ProcessPacket -- determine packet type and do what's required.
+**
+** An RMP BOOT packet has been received. Look at the type field
+** and process Boot Requests, Read Requests, and Boot Complete
+** packets. Any other type will be dropped with a warning msg.
+**
+** Parameters:
+** rconn - the new connection
+** client - list of files available to this host
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - If this is a valid boot request, it will be added to
+** the linked list of outstanding requests (RmpConns).
+** - If this is a valid boot complete, its associated
+** entry in RmpConns will be deleted.
+** - Also, unless we run out of memory, a reply will be
+** sent to the host that sent the packet.
+*/
+void
+ProcessPacket(rconn, client)
+ RMPCONN *rconn;
+ CLIENT *client;
+{
+ struct rmp_packet *rmp;
+ RMPCONN *rconnout;
+
+ rmp = &rconn->rmp; /* cache pointer to RMP packet */
+
+ switch(rmp->r_type) { /* do what we came here to do */
+ case RMP_BOOT_REQ: /* boot request */
+ if ((rconnout = NewConn(rconn)) == NULL)
+ return;
+
+ /*
+ * If the Session ID is 0xffff, this is a "probe"
+ * packet and we do not want to add the connection
+ * to the linked list of active connections. There
+ * are two types of probe packets, if the Sequence
+ * Number is 0 they want to know our host name, o/w
+ * they want the name of the file associated with
+ * the number spec'd by the Sequence Number.
+ *
+ * If this is an actual boot request, open the file
+ * and send a reply. If SendBootRepl() does not
+ * return 0, add the connection to the linked list
+ * of active connections, otherwise delete it since
+ * an error was encountered.
+ */
+ if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {
+ if (WORDZE(rmp->r_brq.rmp_seqno))
+ (void) SendServerID(rconnout);
+ else
+ (void) SendFileNo(rmp, rconnout,
+ client? client->files:
+ BootFiles);
+ FreeConn(rconnout);
+ } else {
+ if (SendBootRepl(rmp, rconnout,
+ client? client->files: BootFiles))
+ AddConn(rconnout);
+ else
+ FreeConn(rconnout);
+ }
+ break;
+
+ case RMP_BOOT_REPL: /* boot reply (not valid) */
+ syslog(LOG_WARNING, "%s: sent a boot reply",
+ EnetStr(rconn));
+ break;
+
+ case RMP_READ_REQ: /* read request */
+ /*
+ * Send a portion of the boot file.
+ */
+ (void) SendReadRepl(rconn);
+ break;
+
+ case RMP_READ_REPL: /* read reply (not valid) */
+ syslog(LOG_WARNING, "%s: sent a read reply",
+ EnetStr(rconn));
+ break;
+
+ case RMP_BOOT_DONE: /* boot complete */
+ /*
+ * Remove the entry from the linked list of active
+ * connections.
+ */
+ (void) BootDone(rconn);
+ break;
+
+ default: /* unknown RMP packet type */
+ syslog(LOG_WARNING, "%s: unknown packet type (%u)",
+ EnetStr(rconn), rmp->r_type);
+ }
+}
+
+/*
+** SendServerID -- send our host name to who ever requested it.
+**
+** Parameters:
+** rconn - the reply packet to be formatted.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendServerID(rconn)
+ RMPCONN *rconn;
+{
+ struct rmp_packet *rpl;
+ char *src, *dst;
+ u_int8_t *size;
+
+ rpl = &rconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
+ rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
+ ZEROWORD(rpl->r_brpl.rmp_seqno);
+ rpl->r_brpl.rmp_session = 0;
+ rpl->r_brpl.rmp_version = htons(RMP_VERSION);
+
+ size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of host name */
+
+ /*
+ * Copy our host name into the reply packet incrementing the
+ * length as we go. Stop at RMP_HOSTLEN or the first dot.
+ */
+ src = MyHost;
+ dst = (char *) &rpl->r_brpl.rmp_flnm;
+ for (*size = 0; *size < RMP_HOSTLEN; (*size)++) {
+ if (*src == '.' || *src == '\0')
+ break;
+ *dst++ = *src++;
+ }
+
+ rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */
+
+ return(SendPacket(rconn)); /* send packet */
+}
+
+/*
+** SendFileNo -- send the name of a bootable file to the requester.
+**
+** Parameters:
+** req - RMP BOOT packet containing the request.
+** rconn - the reply packet to be formatted.
+** filelist - list of files available to the requester.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendFileNo(req, rconn, filelist)
+ struct rmp_packet *req;
+ RMPCONN *rconn;
+ char *filelist[];
+{
+ struct rmp_packet *rpl;
+ char *src, *dst;
+ u_int8_t *size;
+ int i;
+
+ GETWORD(req->r_brpl.rmp_seqno, i); /* SeqNo is really FileNo */
+ rpl = &rconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
+ PUTWORD(i, rpl->r_brpl.rmp_seqno);
+ i--;
+ rpl->r_brpl.rmp_session = 0;
+ rpl->r_brpl.rmp_version = htons(RMP_VERSION);
+
+ size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of filename */
+ *size = 0; /* init length to zero */
+
+ /*
+ * Copy the file name into the reply packet incrementing the
+ * length as we go. Stop at end of string or when RMPBOOTDATA
+ * characters have been copied. Also, set return code to
+ * indicate success or "no more files".
+ */
+ if (i < C_MAXFILE && filelist[i] != NULL) {
+ src = filelist[i];
+ dst = (char *)&rpl->r_brpl.rmp_flnm;
+ for (; *src && *size < RMPBOOTDATA; (*size)++) {
+ if (*src == '\0')
+ break;
+ *dst++ = *src++;
+ }
+ rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
+ } else
+ rpl->r_brpl.rmp_retcode = RMP_E_NODFLT;
+
+ rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */
+
+ return(SendPacket(rconn)); /* send packet */
+}
+
+/*
+** SendBootRepl -- open boot file and respond to boot request.
+**
+** Parameters:
+** req - RMP BOOT packet containing the request.
+** rconn - the reply packet to be formatted.
+** filelist - list of files available to the requester.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendBootRepl(req, rconn, filelist)
+ struct rmp_packet *req;
+ RMPCONN *rconn;
+ char *filelist[];
+{
+ int retval;
+ char *filename, filepath[RMPBOOTDATA+1];
+ RMPCONN *oldconn;
+ struct rmp_packet *rpl;
+ char *src, *dst1, *dst2;
+ u_int8_t i;
+
+ /*
+ * If another connection already exists, delete it since we
+ * are obviously starting again.
+ */
+ if ((oldconn = FindConn(rconn)) != NULL) {
+ syslog(LOG_WARNING, "%s: dropping existing connection",
+ EnetStr(oldconn));
+ RemoveConn(oldconn);
+ }
+
+ rpl = &rconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
+ COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno);
+ rpl->r_brpl.rmp_session = htons(GenSessID());
+ rpl->r_brpl.rmp_version = htons(RMP_VERSION);
+ rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize;
+
+ /*
+ * Copy file name to `filepath' string, and into reply packet.
+ */
+ src = &req->r_brq.rmp_flnm;
+ dst1 = filepath;
+ dst2 = &rpl->r_brpl.rmp_flnm;
+ for (i = 0; i < req->r_brq.rmp_flnmsize; i++)
+ *dst1++ = *dst2++ = *src++;
+ *dst1 = '\0';
+
+ /*
+ * If we are booting HP-UX machines, their secondary loader will
+ * ask for files like "/hp-ux". As a security measure, we do not
+ * allow boot files to lay outside the boot directory (unless they
+ * are purposely link'd out. So, make `filename' become the path-
+ * stripped file name and spoof the client into thinking that it
+ * really got what it wanted.
+ */
+ filename = (filename = strrchr(filepath,'/'))? ++filename: filepath;
+
+ /*
+ * Check that this is a valid boot file name.
+ */
+ for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++)
+ if (STREQN(filename, filelist[i]))
+ goto match;
+
+ /*
+ * Invalid boot file name, set error and send reply packet.
+ */
+ rpl->r_brpl.rmp_retcode = RMP_E_NOFILE;
+ retval = 0;
+ goto sendpkt;
+
+match:
+ /*
+ * This is a valid boot file. Open the file and save the file
+ * descriptor associated with this connection and set success
+ * indication. If the file couldnt be opened, set error:
+ * "no such file or dir" - RMP_E_NOFILE
+ * "file table overflow" - RMP_E_BUSY
+ * "too many open files" - RMP_E_BUSY
+ * anything else - RMP_E_OPENFILE
+ */
+ if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) {
+ rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE:
+ (errno == EMFILE || errno == ENFILE)? RMP_E_BUSY:
+ RMP_E_OPENFILE;
+ retval = 0;
+ } else {
+ rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
+ retval = 1;
+ }
+
+sendpkt:
+ syslog(LOG_INFO, "%s: request to boot %s (%s)",
+ EnetStr(rconn), filename, retval? "granted": "denied");
+
+ rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize);
+
+ return (retval & SendPacket(rconn));
+}
+
+/*
+** SendReadRepl -- send a portion of the boot file to the requester.
+**
+** Parameters:
+** rconn - the reply packet to be formatted.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendReadRepl(rconn)
+ RMPCONN *rconn;
+{
+ int retval = 0;
+ RMPCONN *oldconn;
+ struct rmp_packet *rpl, *req;
+ int size = 0;
+ int madeconn = 0;
+
+ /*
+ * Find the old connection. If one doesnt exist, create one only
+ * to return the error code.
+ */
+ if ((oldconn = FindConn(rconn)) == NULL) {
+ if ((oldconn = NewConn(rconn)) == NULL)
+ return(0);
+ syslog(LOG_ERR, "SendReadRepl: no active connection (%s)",
+ EnetStr(rconn));
+ madeconn++;
+ }
+
+ req = &rconn->rmp; /* cache ptr to request packet */
+ rpl = &oldconn->rmp; /* cache ptr to reply packet */
+
+ if (madeconn) { /* no active connection above; abort */
+ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * Make sure Session ID's match.
+ */
+ if (ntohs(req->r_rrq.rmp_session) !=
+ ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
+ ntohs(rpl->r_rrpl.rmp_session))) {
+ syslog(LOG_ERR, "SendReadRepl: bad session id (%s)",
+ EnetStr(rconn));
+ rpl->r_rrpl.rmp_retcode = RMP_E_BADSID;
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * If the requester asks for more data than we can fit,
+ * silently clamp the request size down to RMPREADDATA.
+ *
+ * N.B. I do not know if this is "legal", however it seems
+ * to work. This is necessary for bpfwrite() on machines
+ * with MCLBYTES less than 1514.
+ */
+ if (ntohs(req->r_rrq.rmp_size) > RMPREADDATA)
+ req->r_rrq.rmp_size = htons(RMPREADDATA);
+
+ /*
+ * Position read head on file according to info in request packet.
+ */
+ GETWORD(req->r_rrq.rmp_offset, size);
+ if (lseek(oldconn->bootfd, (off_t)size, L_SET) < 0) {
+ syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)",
+ EnetStr(rconn));
+ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * Read data directly into reply packet.
+ */
+ if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data,
+ (int) ntohs(req->r_rrq.rmp_size))) <= 0) {
+ if (size < 0) {
+ syslog(LOG_ERR, "SendReadRepl: read: %m (%s)",
+ EnetStr(rconn));
+ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
+ } else {
+ rpl->r_rrpl.rmp_retcode = RMP_E_EOF;
+ }
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * Set success indication.
+ */
+ rpl->r_rrpl.rmp_retcode = RMP_E_OKAY;
+
+sendpkt:
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_rrpl.rmp_type = RMP_READ_REPL;
+ COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset);
+ rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session;
+
+ oldconn->rmplen = RMPREADSIZE(size); /* set size of packet */
+
+ retval &= SendPacket(oldconn); /* send packet */
+
+ if (madeconn) /* clean up after ourself */
+ FreeConn(oldconn);
+
+ return (retval);
+}
+
+/*
+** BootDone -- free up memory allocated for a connection.
+**
+** Parameters:
+** rconn - incoming boot complete packet.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+BootDone(rconn)
+ RMPCONN *rconn;
+{
+ RMPCONN *oldconn;
+ struct rmp_packet *rpl;
+
+ /*
+ * If we cant find the connection, ignore the request.
+ */
+ if ((oldconn = FindConn(rconn)) == NULL) {
+ syslog(LOG_ERR, "BootDone: no existing connection (%s)",
+ EnetStr(rconn));
+ return(0);
+ }
+
+ rpl = &oldconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Make sure Session ID's match.
+ */
+ if (ntohs(rconn->rmp.r_rrq.rmp_session) !=
+ ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
+ ntohs(rpl->r_rrpl.rmp_session))) {
+ syslog(LOG_ERR, "BootDone: bad session id (%s)",
+ EnetStr(rconn));
+ return(0);
+ }
+
+ RemoveConn(oldconn); /* remove connection */
+
+ syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn));
+
+ return(1);
+}
+
+/*
+** SendPacket -- send an RMP packet to a remote host.
+**
+** Parameters:
+** rconn - packet to be sent.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendPacket(rconn)
+ RMPCONN *rconn;
+{
+ /*
+ * Set Ethernet Destination address to Source (BPF and the enet
+ * driver will take care of getting our source address set).
+ */
+ memmove((char *)&rconn->rmp.hp_hdr.daddr[0],
+ (char *)&rconn->rmp.hp_hdr.saddr[0], RMP_ADDRLEN);
+#ifdef __FreeBSD__
+ /* BPF (incorrectly) wants this in host order. */
+ rconn->rmp.hp_hdr.len = rconn->rmplen - sizeof(struct hp_hdr);
+#else
+ rconn->rmp.hp_hdr.len = htons(rconn->rmplen - sizeof(struct hp_hdr));
+#endif
+
+ /*
+ * Reverse 802.2/HP Extended Source & Destination Access Pts.
+ */
+ rconn->rmp.hp_llc.dxsap = htons(HPEXT_SXSAP);
+ rconn->rmp.hp_llc.sxsap = htons(HPEXT_DXSAP);
+
+ /*
+ * Last time this connection was active.
+ */
+ (void) gettimeofday(&rconn->tstamp, (struct timezone *)0);
+
+ if (DbgFp != NULL) /* display packet */
+ DispPkt(rconn,DIR_SENT);
+
+ /*
+ * Send RMP packet to remote host.
+ */
+ return(BpfWrite(rconn));
+}
diff --git a/libexec/rbootd/utils.c b/libexec/rbootd/utils.c
new file mode 100644
index 0000000..aadb5a9
--- /dev/null
+++ b/libexec/rbootd/utils.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)utils.c 8.1 (Berkeley) 6/4/93
+ * $Id: utils.c,v 1.2 1997/06/29 19:00:29 steve Exp $
+ *
+ * From: Utah Hdr: utils.c 3.1 92/07/06
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static const char sccsid[] = "@(#)utils.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#include "defs.h"
+
+/*
+** DispPkt -- Display the contents of an RMPCONN packet.
+**
+** Parameters:
+** rconn - packet to be displayed.
+** direct - direction packet is going (DIR_*).
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** None.
+*/
+void
+DispPkt(rconn, direct)
+ RMPCONN *rconn;
+ int direct;
+{
+ static char BootFmt[] = "\t\tRetCode:%u SeqNo:%lx SessID:%x Vers:%u";
+ static char ReadFmt[] = "\t\tRetCode:%u Offset:%lx SessID:%x\n";
+
+ struct tm *tmp;
+ struct rmp_packet *rmp;
+ int i, omask;
+ u_int32_t t;
+
+ /*
+ * Since we will be working with RmpConns as well as DbgFp, we
+ * must block signals that can affect either.
+ */
+ omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2));
+
+ if (DbgFp == NULL) { /* sanity */
+ (void) sigsetmask(omask);
+ return;
+ }
+
+ /* display direction packet is going using '>>>' or '<<<' */
+ fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp);
+
+ /* display packet timestamp */
+ tmp = localtime((time_t *)&rconn->tstamp.tv_sec);
+ fprintf(DbgFp, "%02d:%02d:%02d.%06ld ", tmp->tm_hour, tmp->tm_min,
+ tmp->tm_sec, rconn->tstamp.tv_usec);
+
+ /* display src or dst addr and information about network interface */
+ fprintf(DbgFp, "Addr: %s Intf: %s\n", EnetStr(rconn), IntfName);
+
+ rmp = &rconn->rmp;
+
+ /* display IEEE 802.2 Logical Link Control header */
+ (void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n",
+ rmp->hp_llc.dsap, rmp->hp_llc.ssap, ntohs(rmp->hp_llc.cntrl));
+
+ /* display HP extensions to 802.2 Logical Link Control header */
+ (void) fprintf(DbgFp, "\tHP Ext: DXSAP:%x SXSAP:%x\n",
+ ntohs(rmp->hp_llc.dxsap), ntohs(rmp->hp_llc.sxsap));
+
+ /*
+ * Display information about RMP packet using type field to
+ * determine what kind of packet this is.
+ */
+ switch(rmp->r_type) {
+ case RMP_BOOT_REQ: /* boot request */
+ (void) fprintf(DbgFp, "\tBoot Request:");
+ GETWORD(rmp->r_brq.rmp_seqno, t);
+ if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {
+ if (WORDZE(rmp->r_brq.rmp_seqno))
+ fputs(" (Send Server ID)", DbgFp);
+ else
+ fprintf(DbgFp," (Send Filename #%u)",t);
+ }
+ (void) fputc('\n', DbgFp);
+ (void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode,
+ t, ntohs(rmp->r_brq.rmp_session),
+ ntohs(rmp->r_brq.rmp_version));
+ (void) fprintf(DbgFp, "\n\t\tMachine Type: ");
+ for (i = 0; i < RMP_MACHLEN; i++)
+ (void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp);
+ DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm);
+ break;
+ case RMP_BOOT_REPL: /* boot reply */
+ fprintf(DbgFp, "\tBoot Reply:\n");
+ GETWORD(rmp->r_brpl.rmp_seqno, t);
+ (void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode,
+ t, ntohs(rmp->r_brpl.rmp_session),
+ ntohs(rmp->r_brpl.rmp_version));
+ DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm);
+ break;
+ case RMP_READ_REQ: /* read request */
+ (void) fprintf(DbgFp, "\tRead Request:\n");
+ GETWORD(rmp->r_rrq.rmp_offset, t);
+ (void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode,
+ t, ntohs(rmp->r_rrq.rmp_session));
+ (void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n",
+ ntohs(rmp->r_rrq.rmp_size));
+ break;
+ case RMP_READ_REPL: /* read reply */
+ (void) fprintf(DbgFp, "\tRead Reply:\n");
+ GETWORD(rmp->r_rrpl.rmp_offset, t);
+ (void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode,
+ t, ntohs(rmp->r_rrpl.rmp_session));
+ (void) fprintf(DbgFp, "\t\tNoOfBytesSent: %d\n",
+ rconn->rmplen - RMPREADSIZE(0));
+ break;
+ case RMP_BOOT_DONE: /* boot complete */
+ (void) fprintf(DbgFp, "\tBoot Complete:\n");
+ (void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n",
+ rmp->r_done.rmp_retcode,
+ ntohs(rmp->r_done.rmp_session));
+ break;
+ default: /* ??? */
+ (void) fprintf(DbgFp, "\tUnknown Type:(%d)\n",
+ rmp->r_type);
+ }
+ (void) fputc('\n', DbgFp);
+ (void) fflush(DbgFp);
+
+ (void) sigsetmask(omask); /* reset old signal mask */
+}
+
+
+/*
+** GetEtherAddr -- convert an RMP (Ethernet) address into a string.
+**
+** An RMP BOOT packet has been received. Look at the type field
+** and process Boot Requests, Read Requests, and Boot Complete
+** packets. Any other type will be dropped with a warning msg.
+**
+** Parameters:
+** addr - array of RMP_ADDRLEN bytes.
+**
+** Returns:
+** Pointer to static string representation of `addr'.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - The return value points to a static buffer; it must
+** be copied if it's to be saved.
+*/
+char *
+GetEtherAddr(addr)
+ u_int8_t *addr;
+{
+ static char Hex[] = "0123456789abcdef";
+ static char etherstr[RMP_ADDRLEN*3];
+ int i;
+ char *cp;
+
+ /*
+ * For each byte in `addr', convert it to "<hexchar><hexchar>:".
+ * The last byte does not get a trailing `:' appended.
+ */
+ i = 0;
+ cp = etherstr;
+ for(;;) {
+ *cp++ = Hex[*addr >> 4 & 0xf];
+ *cp++ = Hex[*addr++ & 0xf];
+ if (++i == RMP_ADDRLEN)
+ break;
+ *cp++ = ':';
+ }
+ *cp = '\0';
+
+ return(etherstr);
+}
+
+
+/*
+** DispFlnm -- Print a string of bytes to DbgFp (often, a file name).
+**
+** Parameters:
+** size - number of bytes to print.
+** flnm - address of first byte.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Characters are sent to `DbgFp'.
+*/
+void
+DspFlnm(size, flnm)
+ u_int size;
+ char *flnm;
+{
+ int i;
+
+ (void) fprintf(DbgFp, "\n\t\tFile Name (%u): <", size);
+ for (i = 0; i < size; i++)
+ (void) fputc(*flnm++, DbgFp);
+ (void) fputs(">\n", DbgFp);
+}
+
+
+/*
+** NewClient -- allocate memory for a new CLIENT.
+**
+** Parameters:
+** addr - RMP (Ethernet) address of new client.
+**
+** Returns:
+** Ptr to new CLIENT or NULL if we ran out of memory.
+**
+** Side Effects:
+** - Memory will be malloc'd for the new CLIENT.
+** - If malloc() fails, a log message will be generated.
+*/
+CLIENT *
+NewClient(addr)
+ u_int8_t *addr;
+{
+ CLIENT *ctmp;
+
+ if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) {
+ syslog(LOG_ERR, "NewClient: out of memory (%s)",
+ GetEtherAddr(addr));
+ return(NULL);
+ }
+
+ memset(ctmp, 0, sizeof(CLIENT));
+ memmove(&ctmp->addr[0], addr, RMP_ADDRLEN);
+ return(ctmp);
+}
+
+/*
+** FreeClient -- free linked list of Clients.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - All malloc'd memory associated with the linked list of
+** CLIENTS will be free'd; `Clients' will be set to NULL.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+FreeClients()
+{
+ CLIENT *ctmp;
+
+ while (Clients != NULL) {
+ ctmp = Clients;
+ Clients = Clients->next;
+ FreeClient(ctmp);
+ }
+}
+
+/*
+** NewStr -- allocate memory for a character array.
+**
+** Parameters:
+** str - null terminated character array.
+**
+** Returns:
+** Ptr to new character array or NULL if we ran out of memory.
+**
+** Side Effects:
+** - Memory will be malloc'd for the new character array.
+** - If malloc() fails, a log message will be generated.
+*/
+char *
+NewStr(str)
+ char *str;
+{
+ char *stmp;
+
+ if ((stmp = (char *)malloc((unsigned) (strlen(str)+1))) == NULL) {
+ syslog(LOG_ERR, "NewStr: out of memory (%s)", str);
+ return(NULL);
+ }
+
+ (void) strcpy(stmp, str);
+ return(stmp);
+}
+
+/*
+** To save time, NewConn and FreeConn maintain a cache of one RMPCONN
+** in `LastFree' (defined below).
+*/
+
+static RMPCONN *LastFree = NULL;
+
+/*
+** NewConn -- allocate memory for a new RMPCONN connection.
+**
+** Parameters:
+** rconn - initialization template for new connection.
+**
+** Returns:
+** Ptr to new RMPCONN or NULL if we ran out of memory.
+**
+** Side Effects:
+** - Memory may be malloc'd for the new RMPCONN (if not cached).
+** - If malloc() fails, a log message will be generated.
+*/
+RMPCONN *
+NewConn(rconn)
+ RMPCONN *rconn;
+{
+ RMPCONN *rtmp;
+
+ if (LastFree == NULL) { /* nothing cached; make a new one */
+ if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) {
+ syslog(LOG_ERR, "NewConn: out of memory (%s)",
+ EnetStr(rconn));
+ return(NULL);
+ }
+ } else { /* use the cached RMPCONN */
+ rtmp = LastFree;
+ LastFree = NULL;
+ }
+
+ /*
+ * Copy template into `rtmp', init file descriptor to `-1' and
+ * set ptr to next elem NULL.
+ */
+ memmove((char *)rtmp, (char *)rconn, sizeof(RMPCONN));
+ rtmp->bootfd = -1;
+ rtmp->next = NULL;
+
+ return(rtmp);
+}
+
+/*
+** FreeConn -- Free memory associated with an RMPCONN connection.
+**
+** Parameters:
+** rtmp - ptr to RMPCONN to be free'd.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Memory associated with `rtmp' may be free'd (or cached).
+** - File desc associated with `rtmp->bootfd' will be closed.
+*/
+void
+FreeConn(rtmp)
+ RMPCONN *rtmp;
+{
+ /*
+ * If the file descriptor is in use, close the file.
+ */
+ if (rtmp->bootfd >= 0) {
+ (void) close(rtmp->bootfd);
+ rtmp->bootfd = -1;
+ }
+
+ if (LastFree == NULL) /* cache for next time */
+ rtmp = LastFree;
+ else /* already one cached; free this one */
+ free((char *)rtmp);
+}
+
+/*
+** FreeConns -- free linked list of RMPCONN connections.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - All malloc'd memory associated with the linked list of
+** connections will be free'd; `RmpConns' will be set to NULL.
+** - If LastFree is != NULL, it too will be free'd & NULL'd.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+FreeConns()
+{
+ RMPCONN *rtmp;
+
+ while (RmpConns != NULL) {
+ rtmp = RmpConns;
+ RmpConns = RmpConns->next;
+ FreeConn(rtmp);
+ }
+
+ if (LastFree != NULL) {
+ free((char *)LastFree);
+ LastFree = NULL;
+ }
+}
+
+/*
+** AddConn -- Add a connection to the linked list of connections.
+**
+** Parameters:
+** rconn - connection to be added.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - RmpConn will point to new connection.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+AddConn(rconn)
+ RMPCONN *rconn;
+{
+ if (RmpConns != NULL)
+ rconn->next = RmpConns;
+ RmpConns = rconn;
+}
+
+/*
+** FindConn -- Find a connection in the linked list of connections.
+**
+** We use the RMP (Ethernet) address as the basis for determining
+** if this is the same connection. According to the Remote Maint
+** Protocol, we can only have one connection with any machine.
+**
+** Parameters:
+** rconn - connection to be found.
+**
+** Returns:
+** Matching connection from linked list or NULL if not found.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+RMPCONN *
+FindConn(rconn)
+ RMPCONN *rconn;
+{
+ RMPCONN *rtmp;
+
+ for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
+ if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
+ (char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0)
+ break;
+
+ return(rtmp);
+}
+
+/*
+** RemoveConn -- Remove a connection from the linked list of connections.
+**
+** Parameters:
+** rconn - connection to be removed.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - If found, an RMPCONN will cease to exist and it will
+** be removed from the linked list.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+RemoveConn(rconn)
+ RMPCONN *rconn;
+{
+ RMPCONN *thisrconn, *lastrconn;
+
+ if (RmpConns == rconn) { /* easy case */
+ RmpConns = RmpConns->next;
+ FreeConn(rconn);
+ } else { /* must traverse linked list */
+ lastrconn = RmpConns; /* set back ptr */
+ thisrconn = lastrconn->next; /* set current ptr */
+ while (thisrconn != NULL) {
+ if (rconn == thisrconn) { /* found it */
+ lastrconn->next = thisrconn->next;
+ FreeConn(thisrconn);
+ break;
+ }
+ lastrconn = thisrconn;
+ thisrconn = thisrconn->next;
+ }
+ }
+}
diff --git a/libexec/revnetgroup/Makefile b/libexec/revnetgroup/Makefile
new file mode 100644
index 0000000..dec0e7b
--- /dev/null
+++ b/libexec/revnetgroup/Makefile
@@ -0,0 +1,8 @@
+# $Id$
+
+PROG= revnetgroup
+SRCS= revnetgroup.c hash.c parse_netgroup.c
+
+MAN8= revnetgroup.8
+
+.include <bsd.prog.mk>
diff --git a/libexec/revnetgroup/hash.c b/libexec/revnetgroup/hash.c
new file mode 100644
index 0000000..2c1cb16
--- /dev/null
+++ b/libexec/revnetgroup/hash.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "hash.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+/*
+ * This hash function is stolen directly from the
+ * Berkeley DB package. It already exists inside libc, but
+ * it's declared static which prevents us from calling it
+ * from here.
+ */
+/*
+ * OZ's original sdbm hash
+ */
+u_int32_t
+hash(keyarg, len)
+ const void *keyarg;
+ register size_t len;
+{
+ register const u_char *key;
+ register size_t loop;
+ register u_int32_t h;
+
+#define HASHC h = *key++ + 65599 * h
+
+ h = 0;
+ key = keyarg;
+ if (len > 0) {
+ loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1)) {
+ case 0:
+ do {
+ HASHC;
+ /* FALLTHROUGH */
+ case 7:
+ HASHC;
+ /* FALLTHROUGH */
+ case 6:
+ HASHC;
+ /* FALLTHROUGH */
+ case 5:
+ HASHC;
+ /* FALLTHROUGH */
+ case 4:
+ HASHC;
+ /* FALLTHROUGH */
+ case 3:
+ HASHC;
+ /* FALLTHROUGH */
+ case 2:
+ HASHC;
+ /* FALLTHROUGH */
+ case 1:
+ HASHC;
+ } while (--loop);
+ }
+ }
+ return (h);
+}
+
+/*
+ * Generate a hash value for a given key (character string).
+ * We mask off all but the lower 8 bits since our table array
+ * can only hold 256 elements.
+ */
+u_int32_t hashkey(key)
+ char *key;
+{
+
+ if (key == NULL)
+ return (-1);
+ return(hash((void *)key, strlen(key)) & HASH_MASK);
+}
+
+/* Find an entry in the hash table (may be hanging off a linked list). */
+char *lookup(table, key)
+ struct group_entry *table[];
+ char *key;
+{
+ struct group_entry *cur;
+
+ cur = table[hashkey(key)];
+
+ while (cur) {
+ if (!strcmp(cur->key, key))
+ return(cur->data);
+ cur = cur->next;
+ }
+
+ return(NULL);
+}
+
+/*
+ * Store an entry in the main netgroup hash table. Here's how this
+ * works: the table can only be so big when we initialize it (TABLESIZE)
+ * but the number of netgroups in the /etc/netgroup file could easily be
+ * much larger than the table. Since our hash values are adjusted to
+ * never be greater than TABLESIZE too, this means it won't be long before
+ * we find ourselves with two keys that hash to the same value.
+ *
+ * One way to deal with this is to malloc(2) a second table and start
+ * doing indirection, but this is a pain in the butt and it's not worth
+ * going to all that trouble for a dinky little program like this. Instead,
+ * we turn each table entry into a linked list and simply link keys
+ * with the same hash value together at the same index location within
+ * the table.
+ *
+ * That's a lot of comment for such a small piece of code, isn't it.
+ */
+void store (table, key, data)
+ struct group_entry *table[];
+ char *key, *data;
+{
+ struct group_entry *new;
+ u_int32_t i;
+
+ i = hashkey(key);
+
+ new = (struct group_entry *)malloc(sizeof(struct group_entry));
+ new->key = strdup(key);
+ new->data = strdup(data);
+ new->next = table[i];
+ table[i] = new;
+
+ return;
+}
+
+/*
+ * Store a group member entry and/or update its grouplist. This is
+ * a bit more complicated than the previous function since we have to
+ * maintain not only the hash table of group members, each group member
+ * structure also has a linked list of groups hung off it. If handed
+ * a member name that we haven't encountered before, we have to do
+ * two things: add that member to the table (possibly hanging them
+ * off the end of a linked list, as above), and add a group name to
+ * the member's grouplist list. If we're handed a name that already has
+ * an entry in the table, then we just have to do one thing, which is
+ * to update its grouplist.
+ */
+void mstore (table, key, data, domain)
+ struct member_entry *table[];
+ char *key, *data, *domain;
+{
+ struct member_entry *cur, *new;
+ struct grouplist *tmp;
+ u_int32_t i;
+
+ i = hashkey(key);
+ cur = table[i];
+
+ tmp = (struct grouplist *)malloc(sizeof(struct grouplist));
+ tmp->groupname = strdup(data);
+ tmp->next = NULL;
+
+ /* Check if all we have to do is insert a new groupname. */
+ while (cur) {
+ if (!strcmp(cur->key, key)) {
+ tmp->next = cur->groups;
+ cur->groups = tmp;
+ return;
+ }
+ cur = cur->next;
+ }
+
+ /* Didn't find a match -- add the whole mess to the table. */
+ new = (struct member_entry *)malloc(sizeof(struct member_entry));
+ new->key = strdup(key);
+ new->domain = domain ? strdup(domain) : "*";
+ new->groups = tmp;
+ new->next = table[i];
+ table[i] = new;
+
+ return;
+}
diff --git a/libexec/revnetgroup/hash.h b/libexec/revnetgroup/hash.h
new file mode 100644
index 0000000..7106967
--- /dev/null
+++ b/libexec/revnetgroup/hash.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/* Groupname entry hung off a member_entry node. */
+struct grouplist {
+ char *groupname;
+ struct grouplist *next;
+};
+
+/* Entry in the cooked member list hash table. */
+struct member_entry {
+ char *key;
+ char *domain;
+ struct grouplist *groups;
+ struct member_entry *next;
+};
+
+/* Entry in the raw netgroup table. */
+struct group_entry {
+ char *key;
+ char *data;
+ struct group_entry *next;
+};
+
+/* Table size (chosen arbitrarily). Not too big, not too small. */
+#define TABLESIZE 256
+#define HASH_MASK 0x000000FF
+
+#define LINSIZ 1024 * 10
+
+extern void store __P(( struct group_entry ** , char *, char * ));
+extern void mstore __P(( struct member_entry ** , char *, char *, char * ));
+extern char *lookup __P(( struct group_entry **, char * ));
+extern void __endnetgrent __P(( void ));
+extern void __setnetgrent __P(( char * ));
+extern int __getnetgrent __P(( char **, char **, char ** ));
diff --git a/libexec/revnetgroup/parse_netgroup.c b/libexec/revnetgroup/parse_netgroup.c
new file mode 100644
index 0000000..14e7e23
--- /dev/null
+++ b/libexec/revnetgroup/parse_netgroup.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * This is a specially hacked-up version of getnetgrent.c used to parse
+ * data from the stored hash table of netgroup info rather than from a
+ * file. It's used mainly for the parse_netgroup() function. All the YP
+ * stuff and file support has been stripped out since it isn't needed.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "hash.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+/*
+ * Static Variables and functions used by setnetgrent(), getnetgrent() and
+ * __endnetgrent().
+ * There are two linked lists:
+ * - linelist is just used by setnetgrent() to parse the net group file via.
+ * parse_netgrp()
+ * - netgrp is the list of entries for the current netgroup
+ */
+struct linelist {
+ struct linelist *l_next; /* Chain ptr. */
+ int l_parsed; /* Flag for cycles */
+ char *l_groupname; /* Name of netgroup */
+ char *l_line; /* Netgroup entrie(s) to be parsed */
+};
+
+struct netgrp {
+ struct netgrp *ng_next; /* Chain ptr */
+ char *ng_str[3]; /* Field pointers, see below */
+};
+#define NG_HOST 0 /* Host name */
+#define NG_USER 1 /* User name */
+#define NG_DOM 2 /* and Domain name */
+
+static struct linelist *linehead = (struct linelist *)0;
+static struct netgrp *nextgrp = (struct netgrp *)0;
+static struct {
+ struct netgrp *gr;
+ char *grname;
+} grouphead = {
+ (struct netgrp *)0,
+ (char *)0,
+};
+static int parse_netgrp();
+static struct linelist *read_for_group();
+void __setnetgrent(), __endnetgrent();
+int __getnetgrent();
+extern struct group_entry *gtable[];
+
+/*
+ * setnetgrent()
+ * Parse the netgroup file looking for the netgroup and build the list
+ * of netgrp structures. Let parse_netgrp() and read_for_group() do
+ * most of the work.
+ */
+void
+__setnetgrent(group)
+ char *group;
+{
+ /* Sanity check */
+
+ if (group == NULL || !strlen(group))
+ return;
+
+ if (grouphead.gr == (struct netgrp *)0 ||
+ strcmp(group, grouphead.grname)) {
+ __endnetgrent();
+ if (parse_netgrp(group))
+ __endnetgrent();
+ else {
+ grouphead.grname = (char *)
+ malloc(strlen(group) + 1);
+ strcpy(grouphead.grname, group);
+ }
+ }
+ nextgrp = grouphead.gr;
+}
+
+/*
+ * Get the next netgroup off the list.
+ */
+int
+__getnetgrent(hostp, userp, domp)
+ char **hostp, **userp, **domp;
+{
+ if (nextgrp) {
+ *hostp = nextgrp->ng_str[NG_HOST];
+ *userp = nextgrp->ng_str[NG_USER];
+ *domp = nextgrp->ng_str[NG_DOM];
+ nextgrp = nextgrp->ng_next;
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * __endnetgrent() - cleanup
+ */
+void
+__endnetgrent()
+{
+ register struct linelist *lp, *olp;
+ register struct netgrp *gp, *ogp;
+
+ lp = linehead;
+ while (lp) {
+ olp = lp;
+ lp = lp->l_next;
+ free(olp->l_groupname);
+ free(olp->l_line);
+ free((char *)olp);
+ }
+ linehead = (struct linelist *)0;
+ if (grouphead.grname) {
+ free(grouphead.grname);
+ grouphead.grname = (char *)0;
+ }
+ gp = grouphead.gr;
+ while (gp) {
+ ogp = gp;
+ gp = gp->ng_next;
+ if (ogp->ng_str[NG_HOST])
+ free(ogp->ng_str[NG_HOST]);
+ if (ogp->ng_str[NG_USER])
+ free(ogp->ng_str[NG_USER]);
+ if (ogp->ng_str[NG_DOM])
+ free(ogp->ng_str[NG_DOM]);
+ free((char *)ogp);
+ }
+ grouphead.gr = (struct netgrp *)0;
+}
+
+/*
+ * Parse the netgroup file setting up the linked lists.
+ */
+static int
+parse_netgrp(group)
+ char *group;
+{
+ register char *spos, *epos;
+ register int len, strpos;
+#ifdef DEBUG
+ register int fields;
+#endif
+ char *pos, *gpos;
+ struct netgrp *grp;
+ struct linelist *lp = linehead;
+
+ /*
+ * First, see if the line has already been read in.
+ */
+ while (lp) {
+ if (!strcmp(group, lp->l_groupname))
+ break;
+ lp = lp->l_next;
+ }
+ if (lp == (struct linelist *)0 &&
+ (lp = read_for_group(group)) == (struct linelist *)0)
+ return (1);
+ if (lp->l_parsed) {
+#ifdef DEBUG
+ /*
+ * This error message is largely superflous since the
+ * code handles the error condition sucessfully, and
+ * spewing it out from inside libc can actually hose
+ * certain programs.
+ */
+ fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
+#endif
+ return (1);
+ } else
+ lp->l_parsed = 1;
+ pos = lp->l_line;
+ /* Watch for null pointer dereferences, dammit! */
+ while (pos != NULL && *pos != '\0') {
+ if (*pos == '(') {
+ grp = (struct netgrp *)malloc(sizeof (struct netgrp));
+ bzero((char *)grp, sizeof (struct netgrp));
+ grp->ng_next = grouphead.gr;
+ grouphead.gr = grp;
+ pos++;
+ gpos = strsep(&pos, ")");
+#ifdef DEBUG
+ fields = 0;
+#endif
+ for (strpos = 0; strpos < 3; strpos++) {
+ if ((spos = strsep(&gpos, ","))) {
+#ifdef DEBUG
+ fields++;
+#endif
+ while (*spos == ' ' || *spos == '\t')
+ spos++;
+ if ((epos = strpbrk(spos, " \t"))) {
+ *epos = '\0';
+ len = epos - spos;
+ } else
+ len = strlen(spos);
+ if (len > 0) {
+ grp->ng_str[strpos] = (char *)
+ malloc(len + 1);
+ bcopy(spos, grp->ng_str[strpos],
+ len + 1);
+ }
+ } else {
+ /*
+ * All other systems I've tested
+ * return NULL for empty netgroup
+ * fields. It's up to user programs
+ * to handle the NULLs appropriately.
+ */
+ grp->ng_str[strpos] = NULL;
+ }
+ }
+#ifdef DEBUG
+ /*
+ * Note: on other platforms, malformed netgroup
+ * entries are not normally flagged. While we
+ * can catch bad entries and report them, we should
+ * stay silent by default for compatibility's sake.
+ */
+ if (fields < 3)
+ fprintf(stderr, "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n",
+ grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
+ grp->ng_str[NG_USER] == NULL ? "" : ",",
+ grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
+ grp->ng_str[NG_DOM] == NULL ? "" : ",",
+ grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
+ lp->l_groupname);
+#endif
+ } else {
+ spos = strsep(&pos, ", \t");
+ if (parse_netgrp(spos))
+ continue;
+ }
+ /* Watch for null pointer dereferences, dammit! */
+ if (pos != NULL)
+ while (*pos == ' ' || *pos == ',' || *pos == '\t')
+ pos++;
+ }
+ return (0);
+}
+
+/*
+ * Read the netgroup file and save lines until the line for the netgroup
+ * is found. Return 1 if eof is encountered.
+ */
+static struct linelist *
+read_for_group(group)
+ char *group;
+{
+ register char *pos, *spos, *linep = NULL, *olinep = NULL;
+ register int len, olen;
+ int cont;
+ struct linelist *lp;
+ char line[LINSIZ + 1];
+ char *data = NULL;
+
+ data = lookup (gtable, group);
+ sprintf(line, "%s %s", group, data);
+ pos = (char *)&line;
+#ifdef CANT_HAPPEN
+ if (*pos == '#')
+ continue;
+#endif
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ spos = pos;
+ while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
+ *pos != '\0')
+ pos++;
+ len = pos - spos;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos != '\n' && *pos != '\0') {
+ lp = (struct linelist *)malloc(sizeof (*lp));
+ lp->l_parsed = 0;
+ lp->l_groupname = (char *)malloc(len + 1);
+ bcopy(spos, lp->l_groupname, len);
+ *(lp->l_groupname + len) = '\0';
+ len = strlen(pos);
+ olen = 0;
+ /*
+ * Loop around handling line continuations.
+ */
+ do {
+ if (*(pos + len - 1) == '\n')
+ len--;
+ if (*(pos + len - 1) == '\\') {
+ len--;
+ cont = 1;
+ } else
+ cont = 0;
+ if (len > 0) {
+ linep = (char *)malloc(olen + len + 1);
+ if (olen > 0) {
+ bcopy(olinep, linep, olen);
+ free(olinep);
+ }
+ bcopy(pos, linep + olen, len);
+ olen += len;
+ *(linep + olen) = '\0';
+ olinep = linep;
+ }
+#ifdef CANT_HAPPEN
+ if (cont) {
+ if (fgets(line, LINSIZ, netf)) {
+ pos = line;
+ len = strlen(pos);
+ } else
+ cont = 0;
+ }
+#endif
+ } while (cont);
+ lp->l_line = linep;
+ lp->l_next = linehead;
+ linehead = lp;
+#ifdef CANT_HAPPEN
+ /*
+ * If this is the one we wanted, we are done.
+ */
+ if (!strcmp(lp->l_groupname, group))
+#endif
+ return (lp);
+ }
+ return ((struct linelist *)0);
+}
diff --git a/libexec/revnetgroup/revnetgroup.8 b/libexec/revnetgroup/revnetgroup.8
new file mode 100644
index 0000000..2d03f81
--- /dev/null
+++ b/libexec/revnetgroup/revnetgroup.8
@@ -0,0 +1,137 @@
+.\" Copyright (c) 1995
+.\" Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd October 24, 1995
+.Dt REVNETGROUP 8
+.Os
+.Sh NAME
+.Nm revnetgroup
+.Nd "generate reverse netgroup data"
+.Sh SYNOPSIS
+.Nm revnetgroup
+.Fl u
+.Fl h
+.Op Fl f Ar netgroup_file
+.Sh DESCRIPTION
+.Nm revnetgroup
+processes the contents of a file in
+.Xr netgroup 5
+format into what is called
+.Pa reverse netgroup
+form. That is, where the original file shows
+netgroup memberships in terms of which members reside in a particular
+group, the reverse netgroup format specifies what groups are associated
+with a particular member. This information is used to generate the
+.Nm netgroup.byuser
+and
+.Nm netgroup.byhosts
+NIS maps. These reverse netgroup maps are used to help speed up
+netgroup lookups, particularly for the
+.Fn innetgr
+library function.
+.Pp
+For example, the standard
+.Nm /etc/netgroup
+file may list a netgroup and a list of its members. Here, the
+netgroup is considered the
+.Pa key
+and the member names are the
+.Pa data .
+By contrast, the reverse
+.Nm netgroup.byusers
+database lists each unique
+member as the key and the netgroups to which the members belong become
+the data. Seperate databases are created to hold information pertaining
+to users and hosts; this allows netgroup username lookups
+and netgroup hostname lookups to be performed using independent keyspaces.
+.Pp
+By constructing these reverse netgroup databases (and the corresponding
+NIS maps) in advance, the
+.Xr getnetgrent 3
+library functions are spared from having to work out the dependencies
+themselves on the fly. This is important on networks with large numbers
+of users and hosts, since it can take a considerable amount of time
+to process very large netgroup databases.
+.Pp
+The
+.Nm revnetgroup
+command prints its results on the standard output. It is usually called
+only by
+.Nm /var/yp/Makefile
+when rebuilding the NIS netgroup maps.
+.Pp
+.Sh OPTIONS
+The
+.Nm revnetgroup
+command supports the following options:
+.Bl -tag -width flag
+.It Fl u
+Generate netgroup.byuser output; only username information in the
+original netgroup file is processed.
+.It Fl h
+Generate netgroup.byhost output; only hostname information in the
+original netgroup file is processed. (Note at least one of the
+.Fl u
+or
+.Fl h
+flags must be specified.)
+.It Op Fl f Ar netgroup_file
+The
+.Nm revnetgroup
+command uses
+.Nm /etc/netgroup
+as its default input file. The
+.Fl f
+flag allows the user to specify an alternate input file. Specifying ``-''
+as the input file causes
+.Nm revnetgroup
+to read from the standard input.
+.El
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /var/yp/Makefile
+The Makefile that calls
+.Nm yp_mkdb
+and
+.Nm revnetgroup
+to build the NIS databases.
+.It Pa /etc/netgroup
+The default netgroup database file. This file is most often found
+only on the NIS master server.
+.El
+.Sh SEE ALSO
+.Xr getnetgrent 3 ,
+.Xr yp 4 ,
+.Xr netgroup 5 ,
+.Xr yp_mkdb 8
+.Sh AUTHOR
+Bill Paul <wpaul@ctr.columbia.edu>
diff --git a/libexec/revnetgroup/revnetgroup.c b/libexec/revnetgroup/revnetgroup.c
new file mode 100644
index 0000000..7655480
--- /dev/null
+++ b/libexec/revnetgroup/revnetgroup.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * reverse netgroup map generator program
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Center for Telecommunications Research
+ * Columbia University, New York City
+ *
+ * $Id: revnetgroup.c,v 1.6 1997/02/22 14:22:03 peter Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include "hash.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id: revnetgroup.c,v 1.6 1997/02/22 14:22:03 peter Exp $";
+#endif
+
+/* Default location of netgroup file. */
+char *netgroup = "/etc/netgroup";
+
+/* Stored hash table version of 'forward' netgroup database. */
+struct group_entry *gtable[TABLESIZE];
+
+/*
+ * Stored hash table of 'reverse' netgroup member database
+ * which we will construct.
+ */
+struct member_entry *mtable[TABLESIZE];
+
+void usage(prog)
+char *prog;
+{
+ fprintf (stderr,"usage: %s -u|-h [-f netgroup file]\n",prog);
+ exit(1);
+}
+
+extern char *optarg;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ FILE *fp;
+ char readbuf[LINSIZ];
+ struct group_entry *gcur;
+ struct member_entry *mcur;
+ char *host, *user, *domain;
+ int ch;
+ char *key = NULL, *data = NULL;
+ int hosts = -1, i;
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ while ((ch = getopt(argc, argv, "uhf:")) != -1) {
+ switch(ch) {
+ case 'u':
+ if (hosts != -1) {
+ warnx("please use only one of -u or -h");
+ usage(argv[0]);
+ }
+ hosts = 0;
+ break;
+ case 'h':
+ if (hosts != -1) {
+ warnx("please use only one of -u or -h");
+ usage(argv[0]);
+ }
+ hosts = 1;
+ break;
+ case 'f':
+ netgroup = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (hosts == -1)
+ usage(argv[0]);
+
+ if (strcmp(netgroup, "-")) {
+ if ((fp = fopen(netgroup, "r")) == NULL) {
+ err(1,netgroup);
+ }
+ } else {
+ fp = stdin;
+ }
+
+ /* Stuff all the netgroup names and members into a hash table. */
+ while (fgets(readbuf, LINSIZ, fp)) {
+ if (readbuf[0] == '#')
+ continue;
+ /* handle backslash line continuations */
+ while(readbuf[strlen(readbuf) - 2] == '\\') {
+ fgets((char *)&readbuf[strlen(readbuf) - 2],
+ sizeof(readbuf) - strlen(readbuf), fp);
+ }
+ data = NULL;
+ if ((data = (char *)(strpbrk(readbuf, " \t") + 1)) < (char *)2)
+ continue;
+ key = (char *)&readbuf;
+ *(data - 1) = '\0';
+ store(gtable, key, data);
+ }
+
+ fclose(fp);
+
+ /*
+ * Find all members of each netgroup and keep track of which
+ * group they belong to.
+ */
+ for (i = 0; i < TABLESIZE; i++) {
+ gcur = gtable[i];
+ while(gcur) {
+ __setnetgrent(gcur->key);
+ while(__getnetgrent(&host, &user, &domain) != NULL) {
+ if (hosts ? host && strcmp(host,"-") : user && strcmp(user, "-"))
+ mstore(mtable, hosts ? host : user, gcur->key, domain);
+ }
+ gcur = gcur->next;
+ }
+ }
+
+ /* Release resources used by the netgroup parser code. */
+ __endnetgrent();
+
+ /* Spew out the results. */
+ for (i = 0; i < TABLESIZE; i++) {
+ mcur = mtable[i];
+ while(mcur) {
+ struct grouplist *tmp;
+ printf ("%s.%s\t", mcur->key, mcur->domain);
+ tmp = mcur->groups;
+ while(tmp) {
+ printf ("%s", tmp->groupname);
+ tmp = tmp->next;
+ if (tmp)
+ printf(",");
+ }
+ mcur = mcur->next;
+ printf ("\n");
+ }
+ }
+
+ /* Let the OS free all our resources. */
+ exit(0);
+}
diff --git a/libexec/rexecd/Makefile b/libexec/rexecd/Makefile
index aaedac5..ebd3d15 100644
--- a/libexec/rexecd/Makefile
+++ b/libexec/rexecd/Makefile
@@ -1,6 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
PROG= rexecd
-MAN8= rexecd.0
+MAN8= rexecd.8
+CFLAGS+= -DSKEY
+
+DPADD= ${LIBSKEY} ${LIBMD} ${LIBCRYPT}
+LDADD= -lskey -lmd -lcrypt
.include <bsd.prog.mk>
diff --git a/libexec/rexecd/rexecd.8 b/libexec/rexecd/rexecd.8
index 3035900..df89504 100644
--- a/libexec/rexecd/rexecd.8
+++ b/libexec/rexecd/rexecd.8
@@ -29,9 +29,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)rexecd.8 8.3 (Berkeley) 6/1/94
+.\" @(#)rexecd.8 8.2 (Berkeley) 12/11/93
+.\" $Id$
.\"
-.Dd June 1, 1994
+.Dd September 23, 1994
.Dt REXECD 8
.Os BSD 4.2
.Sh NAME
@@ -96,6 +97,14 @@ shell inherits the network connections established
by
.Nm rexecd .
.El
+.Sh CAVEATS
+.Nm Rexecd
+will no longer allow root logins, access for users listed in /etc/ftpusers,
+or access for users with no passwords, which were all serious security holes.
+The entire concept of rexec/rexecd is a major security hole and an example
+of how not to do things.
+.Nm Rexecd
+is disabled by default in /etc/inetd.conf.
.Sh DIAGNOSTICS
Except for the last one listed below,
all diagnostic messages are returned on the initial socket,
@@ -117,7 +126,6 @@ list (as configured into the system).
No password file entry for the user name existed.
.It Sy Password incorrect.
The wrong password was supplied.
-.ne 1i
.It Sy \&No remote directory.
The
.Xr chdir
@@ -136,10 +144,6 @@ and is not preceded by a flag byte.
.Sh SEE ALSO
.Xr rexec 3
.Sh BUGS
-Indicating ``Login incorrect'' as opposed to ``Password incorrect''
-is a security breach which allows people to probe a system for users
-with null passwords.
-.Pp
A facility to allow all data and password exchanges to be encrypted should be
present.
.Sh HISTORY
diff --git a/libexec/rexecd/rexecd.c b/libexec/rexecd/rexecd.c
index 796ad9c..119551e 100644
--- a/libexec/rexecd/rexecd.c
+++ b/libexec/rexecd/rexecd.c
@@ -29,6 +29,8 @@
* 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: rexecd.c,v 1.13 1997/02/22 14:22:06 peter Exp $
*/
#ifndef lint
@@ -47,6 +49,7 @@ static char sccsid[] = "@(#)rexecd.c 8.1 (Berkeley) 6/4/93";
#include <sys/time.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
@@ -57,10 +60,23 @@ static char sccsid[] = "@(#)rexecd.c 8.1 (Berkeley) 6/4/93";
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <syslog.h>
+#include <netdb.h>
/*VARARGS1*/
int error();
+char username[MAXLOGNAME + 5 + 1] = "USER=";
+char homedir[MAXPATHLEN + 5 + 1] = "HOME=";
+char shell[MAXPATHLEN + 6 + 1] = "SHELL=";
+char path[sizeof(_PATH_DEFPATH) + sizeof("PATH=")] = "PATH=";
+char *envinit[] =
+ {homedir, shell, path, username, 0};
+char **environ;
+char *remote;
+
+struct sockaddr_in asin = { AF_INET };
+
/*
* remote execute server:
* username\0
@@ -75,32 +91,36 @@ main(argc, argv)
{
struct sockaddr_in from;
int fromlen;
+ struct hostent *hp;
+ openlog(argv[0], LOG_PID, LOG_AUTH);
fromlen = sizeof (from);
if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
(void)fprintf(stderr,
"rexecd: getpeername: %s\n", strerror(errno));
exit(1);
}
- doit(0, &from);
-}
-char username[20] = "USER=";
-char homedir[64] = "HOME=";
-char shell[64] = "SHELL=";
-char path[sizeof(_PATH_DEFPATH) + sizeof("PATH=")] = "PATH=";
-char *envinit[] =
- {homedir, shell, path, username, 0};
-char **environ;
+ hp = gethostbyaddr((char *) &from.sin_addr, sizeof(from.sin_addr),
+ from.sin_family);
+ remote = inet_ntoa(from.sin_addr);
+ remote = (hp != NULL) ? hp->h_name : inet_ntoa(from.sin_addr);
-struct sockaddr_in asin = { AF_INET };
+ doit(0, &from);
+}
doit(f, fromp)
int f;
struct sockaddr_in *fromp;
{
+ FILE *fp;
char cmdbuf[NCARGS+1], *cp, *namep;
+#ifdef SKEY
+ char *skey_crypt();
+ char user[16], pass[100];
+#else /* SKEY */
char user[16], pass[16];
+#endif /* SKEY */
struct passwd *pwd;
int s;
u_short port;
@@ -156,16 +176,43 @@ doit(f, fromp)
}
endpwent();
if (*pwd->pw_passwd != '\0') {
+#ifdef SKEY
+ namep = skey_crypt(pass, pwd->pw_passwd, pwd,
+ skeyaccess(user, NULL, remote));
+#else /* SKEY */
namep = crypt(pass, pwd->pw_passwd);
+#endif /* SKEY */
if (strcmp(namep, pwd->pw_passwd)) {
- error("Password incorrect.\n");
+ syslog(LOG_ERR, "LOGIN FAILURE from %s, %s",
+ remote, user);
+ error("Login incorrect.\n");
exit(1);
}
}
- if (chdir(pwd->pw_dir) < 0) {
- error("No remote directory.\n");
+
+ if (pwd->pw_uid == 0 || *pwd->pw_passwd == '\0' ||
+ (pwd->pw_expire && time(NULL) >= pwd->pw_expire)) {
+ syslog(LOG_ERR, "%s LOGIN REFUSED from %s", user, remote);
+ error("Login incorrect.\n");
exit(1);
}
+
+ if ((fp = fopen(_PATH_FTPUSERS, "r")) != NULL) {
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if ((cp = index(buf, '\n')) != NULL)
+ *cp = '\0';
+ if (strcmp(buf, pwd->pw_name) == 0) {
+ syslog(LOG_ERR, "%s LOGIN REFUSED from %s",
+ user, remote);
+ error("Login incorrect.\n");
+ exit(1);
+ }
+ }
+ }
+ (void) fclose(fp);
+
+ syslog(LOG_INFO, "login from %s as %s", remote, user);
+
(void) write(2, "\0", 1);
if (port) {
(void) pipe(pv);
@@ -210,6 +257,8 @@ doit(f, fromp)
pwd->pw_shell = _PATH_BSHELL;
if (f > 2)
(void) close(f);
+ if (setlogin(pwd->pw_name) < 0)
+ syslog(LOG_ERR, "setlogin() failed: %m");
(void) setgid((gid_t)pwd->pw_gid);
initgroups(pwd->pw_name, pwd->pw_gid);
(void) setuid((uid_t)pwd->pw_uid);
@@ -223,6 +272,10 @@ doit(f, fromp)
cp++;
else
cp = pwd->pw_shell;
+ if (chdir(pwd->pw_dir) < 0) {
+ error("No remote directory.\n");
+ exit(1);
+ }
execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
perror(pwd->pw_shell);
exit(1);
@@ -236,7 +289,7 @@ error(fmt, a1, a2, a3)
char buf[BUFSIZ];
buf[0] = 1;
- (void) sprintf(buf+1, fmt, a1, a2, a3);
+ (void) snprintf(buf+1, sizeof(buf) - 1, fmt, a1, a2, a3);
(void) write(2, buf, strlen(buf));
}
diff --git a/libexec/rlogind/Makefile b/libexec/rlogind/Makefile
index 639d3f6..41136e2 100644
--- a/libexec/rlogind/Makefile
+++ b/libexec/rlogind/Makefile
@@ -1,11 +1,18 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
PROG= rlogind
+SRCS= rlogind.c
+MAN8= rlogind.8
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a) && (defined(MAKE_KERBEROS) \
+ || defined(MAKE_EBONES))
CFLAGS+=-DKERBEROS -DCRYPT
-SRCS= rlogind.c des_rw.c
-MAN8= rlogind.0
-DPADD= ${LIBUTIL} ${LIBKRB} ${LIBDES}
-LDADD= -lutil -lkrb -ldes
-.PATH: ${.CURDIR}/../../usr.bin/rlogin
+DPADD= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
+DISTRIBUTION= krb
+.endif
.include <bsd.prog.mk>
diff --git a/libexec/rlogind/rlogind.8 b/libexec/rlogind/rlogind.8
index 9c19933..7c565e3 100644
--- a/libexec/rlogind/rlogind.8
+++ b/libexec/rlogind/rlogind.8
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)rlogind.8 8.1 (Berkeley) 6/4/93
+.\" $Id$
.\"
.Dd June 4, 1993
.Dt RLOGIND 8
@@ -39,7 +40,7 @@
.Nd remote login server
.Sh SYNOPSIS
.Nm rlogind
-.Op Fl aln
+.Op Fl Daln
.Sh DESCRIPTION
.Nm Rlogind
is the server for the
@@ -50,6 +51,9 @@ with authentication based on privileged port numbers from trusted hosts.
Options supported by
.Nm rlogind :
.Bl -tag -width Ds
+.It Fl D
+Set TCP_NODELAY socket option. This improves responsiveness at the expense of
+some additional network traffic.
.It Fl a
Ask hostname for verification.
.It Fl l
@@ -60,6 +64,20 @@ file, unless the user is logging in as the superuser.
Disable keep-alive messages.
.El
.Pp
+The following options are valid only if Kerberos is in use:
+.Bl -tag -width Ds
+.It Fl k
+Enable Kerberos authentication.
+.It Fl v
+Enable vacuous mode.
+.It Fl x
+Enable
+.Tn DES
+encryption for all data passed via the rlogin
+session. This may impact response time
+and CPU utilization, but provides increased security.
+.El
+.Pp
.Nm Rlogind
listens for service requests at the port indicated in
the ``login'' service specification; see
@@ -151,7 +169,17 @@ by the server failed.
.Sh SEE ALSO
.Xr login 1 ,
.Xr ruserok 3 ,
+.Xr hosts 5 ,
+.Xr nologin 5 ,
.Xr rshd 8
+.Sh FILES
+.Bl -tag -width /etc/hostsxxxxxxxx -compact
+.It Pa /etc/hosts
+.It Pa /etc/hosts.equiv
+.It Pa $HOME/.rhosts
+.It Pa /etc/nologin
+.El
+
.Sh BUGS
The authentication procedure used here assumes the integrity
of each client machine and the connecting medium. This is
diff --git a/libexec/rlogind/rlogind.c b/libexec/rlogind/rlogind.c
index 80d53d5..97ba074 100644
--- a/libexec/rlogind/rlogind.c
+++ b/libexec/rlogind/rlogind.c
@@ -29,6 +29,8 @@
* 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: rlogind.c,v 1.16 1997/03/24 06:01:39 imp Exp $
*/
#ifndef lint
@@ -38,7 +40,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)rlogind.c 8.2 (Berkeley) 4/28/95";
+static char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
/*
@@ -61,6 +63,7 @@ static char sccsid[] = "@(#)rlogind.c 8.2 (Berkeley) 4/28/95";
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -78,7 +81,7 @@ static char sccsid[] = "@(#)rlogind.c 8.2 (Berkeley) 4/28/95";
#endif
#ifdef KERBEROS
-#include <kerberosIV/des.h>
+#include <des.h>
#include <kerberosIV/krb.h>
#define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
@@ -89,9 +92,9 @@ u_char tick_buf[sizeof(KTEXT_ST)];
Key_schedule schedule;
int doencrypt, retval, use_kerberos, vacuous;
-#define ARGSTR "alnkvx"
+#define ARGSTR "Dalnkvx"
#else
-#define ARGSTR "aln"
+#define ARGSTR "Daln"
#endif /* KERBEROS */
char *env[2];
@@ -101,6 +104,7 @@ static char term[64] = "TERM=";
#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
int keepalive = 1;
int check_all = 0;
+int no_delay;
struct passwd *pwd;
@@ -129,8 +133,11 @@ main(argc, argv)
openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
opterr = 0;
- while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
+ while ((ch = getopt(argc, argv, ARGSTR)) != -1)
switch (ch) {
+ case 'D':
+ no_delay = 1;
+ break;
case 'a':
check_all = 1;
break;
@@ -176,9 +183,13 @@ main(argc, argv)
if (keepalive &&
setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+ if (no_delay &&
+ setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
+ syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
on = IPTOS_LOWDELAY;
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+
doit(0, &from);
}
@@ -215,10 +226,12 @@ doit(f, fromp)
fromp->sin_port = ntohs((u_short)fromp->sin_port);
hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr),
fromp->sin_family);
- if (hp)
- (void)strcpy(hostname, hp->h_name);
- else
- (void)strcpy(hostname, inet_ntoa(fromp->sin_addr));
+ if (hp) {
+ (void)strncpy(hostname, hp->h_name, sizeof(hostname));
+ } else {
+ (void)strncpy(hostname, inet_ntoa(fromp->sin_addr), sizeof(hostname));
+ }
+ hostname[sizeof(hostname) - 1] = '\0';
#ifdef KERBEROS
if (use_kerberos) {
@@ -241,9 +254,8 @@ doit(f, fromp)
}
#ifdef IP_OPTIONS
{
- u_char optbuf[BUFSIZ/3], *cp;
- char lbuf[BUFSIZ], *lp;
- int optsize = sizeof(optbuf), ipproto;
+ u_char optbuf[BUFSIZ/3];
+ int optsize = sizeof(optbuf), ipproto, i;
struct protoent *ip;
if ((ip = getprotobyname("ip")) != NULL)
@@ -252,17 +264,18 @@ doit(f, fromp)
ipproto = IPPROTO_IP;
if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
&optsize) == 0 && optsize != 0) {
- lp = lbuf;
- for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
- sprintf(lp, " %2.2x", *cp);
- syslog(LOG_NOTICE,
- "Connection received using IP options (ignored):%s",
- lbuf);
- if (setsockopt(0, ipproto, IP_OPTIONS,
- (char *)NULL, optsize) != 0) {
- syslog(LOG_ERR,
- "setsockopt IP_OPTIONS NULL: %m");
- exit(1);
+ for (i = 0; i < optsize; ) {
+ u_char c = optbuf[i];
+ if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
+ syslog(LOG_NOTICE,
+ "Connection refused from %s with IP option %s",
+ inet_ntoa(fromp->sin_addr),
+ c == IPOPT_LSRR ? "LSRR" : "SSRR");
+ exit(1);
+ }
+ if (c == IPOPT_EOL)
+ break;
+ i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
}
}
}
@@ -293,6 +306,11 @@ doit(f, fromp)
if (f > 2) /* f should always be 0, but... */
(void) close(f);
setup_term(0);
+ if (*lusername=='-') {
+ syslog(LOG_ERR, "tried to pass user \"%s\" to login",
+ lusername);
+ fatal(STDERR_FILENO, "invalid user", 0);
+ }
if (authenticated) {
#ifdef KERBEROS
if (use_kerberos && (pwd->pw_uid == 0))
@@ -302,11 +320,11 @@ doit(f, fromp)
hostname);
#endif
- execle(_PATH_LOGIN, "login", "-p",
- "-h", hostname, "-f", "--", lusername, NULL, env);
+ execl(_PATH_LOGIN, "login", "-p",
+ "-h", hostname, "-f", lusername, (char *)NULL);
} else
- execle(_PATH_LOGIN, "login", "-p",
- "-h", hostname, "--", lusername, NULL, env);
+ execl(_PATH_LOGIN, "login", "-p",
+ "-h", hostname, lusername, (char *)NULL);
fatal(STDERR_FILENO, _PATH_LOGIN, 1);
/*NOTREACHED*/
}
@@ -348,7 +366,7 @@ control(pty, cp, n)
if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
return (0);
oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
- memmove(&w, cp+4, sizeof(w));
+ bcopy(cp+4, (char *)&w, sizeof(w));
w.ws_row = ntohs(w.ws_row);
w.ws_col = ntohs(w.ws_col);
w.ws_xpixel = ntohs(w.ws_xpixel);
@@ -573,10 +591,9 @@ do_rlogin(dest)
pwd = getpwnam(lusername);
if (pwd == NULL)
return (-1);
- if (pwd->pw_uid == 0)
- return (-1);
/* XXX why don't we syslog() failure? */
- return (iruserok(dest->sin_addr.s_addr, 0, rusername, lusername));
+ return (iruserok(dest->sin_addr.s_addr, pwd->pw_uid == 0,
+ rusername, lusername));
}
void
@@ -596,6 +613,8 @@ getstr(buf, cnt, errmsg)
} while (c != 0);
}
+extern char **environ;
+
void
setup_term(fd)
int fd;
@@ -634,6 +653,7 @@ setup_term(fd)
env[0] = term;
env[1] = 0;
+ environ = env;
}
#ifdef KERBEROS
@@ -673,7 +693,7 @@ do_krb_login(dest)
ticket, "rcmd",
instance, dest, &faddr,
kdata, "", schedule, version);
- des_set_key(kdata->session, schedule);
+ des_set_key_krb(&kdata->session, schedule);
} else
#endif
@@ -681,7 +701,7 @@ do_krb_login(dest)
authopts, 0,
ticket, "rcmd",
instance, dest, (struct sockaddr_in *) 0,
- kdata, "", (bit_64 *) 0, version);
+ kdata, "", NULL, version);
if (rc != KSUCCESS)
return (rc);
@@ -697,7 +717,7 @@ do_krb_login(dest)
/* returns nonzero for no access */
if (kuserok(kdata, lusername) != 0)
return (-1);
-
+
return (0);
}
@@ -707,9 +727,9 @@ void
usage()
{
#ifdef KERBEROS
- syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]");
+ syslog(LOG_ERR, "usage: rlogind [-Daln] [-k | -v]");
#else
- syslog(LOG_ERR, "usage: rlogind [-aln]");
+ syslog(LOG_ERR, "usage: rlogind [-Daln]");
#endif
}
diff --git a/libexec/rpc.rquotad/Makefile b/libexec/rpc.rquotad/Makefile
new file mode 100644
index 0000000..53ca412
--- /dev/null
+++ b/libexec/rpc.rquotad/Makefile
@@ -0,0 +1,10 @@
+# $Id$
+
+PROG = rpc.rquotad
+SRCS = rquotad.c
+MAN8 = rpc.rquotad.8
+
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
+.include <bsd.prog.mk>
diff --git a/libexec/rpc.rquotad/rpc.rquotad.8 b/libexec/rpc.rquotad/rpc.rquotad.8
new file mode 100644
index 0000000..dd8f3aa
--- /dev/null
+++ b/libexec/rpc.rquotad/rpc.rquotad.8
@@ -0,0 +1,61 @@
+.\"
+.\" Copyright (c) 1994 Theo de Raadt
+.\" 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 Theo de Raadt.
+.\" 4. The name of the author 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 ``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: rpc.rquotad.8,v 1.3 1997/02/22 14:22:10 peter Exp $
+.\"
+.Dd June 22, 1994
+.Dt RPC.RQUOTAD 8
+.Os BSD 4.3
+.Sh NAME
+.Nm rpc.rquotad
+.Nd remote quota server
+.Sh SYNOPSIS
+.Nm /usr/libexec/rpc.rquotad
+.Sh DESCRIPTION
+.Nm rpc.rquotad
+is a
+.Xr rpc 3
+server which returns quotas for a user of a local filesystem
+which is NFS-mounted onto a remote machine.
+.Xr quota 1
+uses the results to display user quotas for remote filesystems.
+.Nm rpc.rquotad
+is normally invoked by
+.Xr inetd 8 .
+.Pp
+.Nm rpc.rquotad
+uses an RPC protocol defined in
+.Pa /usr/include/rpcsvc/rquota.x .
+.Sh BUGS
+.Bx 4.4
+and
+.Tn FreeBSD
+support group quotas but the rquota protocol does not.
+.Sh SEE ALSO
+.Xr quota 1
diff --git a/libexec/rpc.rquotad/rquotad.c b/libexec/rpc.rquotad/rquotad.c
new file mode 100644
index 0000000..33fa420
--- /dev/null
+++ b/libexec/rpc.rquotad/rquotad.c
@@ -0,0 +1,331 @@
+/*
+ * by Manuel Bouyer (bouyer@ensta.fr)
+ *
+ * There is no copyright, you can use it as you want.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <signal.h>
+
+#include <stdio.h>
+#include <fstab.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+
+#include <syslog.h>
+#include <varargs.h>
+
+#include <ufs/ufs/quota.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpcsvc/rquota.h>
+#include <arpa/inet.h>
+
+void rquota_service __P((struct svc_req *request, SVCXPRT *transp));
+void sendquota __P((struct svc_req *request, SVCXPRT *transp));
+void printerr_reply __P((SVCXPRT *transp));
+void initfs __P((void));
+int getfsquota __P((long id, char *path, struct dqblk *dqblk));
+int hasquota __P((struct fstab *fs, char **qfnamep));
+
+/*
+ * structure containing informations about ufs filesystems
+ * initialised by initfs()
+ */
+struct fs_stat {
+ struct fs_stat *fs_next; /* next element */
+ char *fs_file; /* mount point of the filesystem */
+ char *qfpathname; /* pathname of the quota file */
+ dev_t st_dev; /* device of the filesystem */
+} fs_stat;
+struct fs_stat *fs_begin = NULL;
+
+int from_inetd = 1;
+
+void
+cleanup()
+{
+ (void) pmap_unset(RQUOTAPROG, RQUOTAVERS);
+ exit(0);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SVCXPRT *transp;
+ int sock = 0;
+ int proto = 0;
+ struct sockaddr_in from;
+ int fromlen;
+
+ fromlen = sizeof(from);
+ if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ from_inetd = 0;
+ sock = RPC_ANYSOCK;
+ proto = IPPROTO_UDP;
+ }
+
+ if (!from_inetd) {
+ daemon(0, 0);
+
+ (void) pmap_unset(RQUOTAPROG, RQUOTAVERS);
+
+ (void) signal(SIGINT, cleanup);
+ (void) signal(SIGTERM, cleanup);
+ (void) signal(SIGHUP, cleanup);
+ }
+
+ openlog("rpc.rquotad", LOG_CONS|LOG_PID, LOG_DAEMON);
+
+ /* create and register the service */
+ transp = svcudp_create(sock);
+ if (transp == NULL) {
+ syslog(LOG_ERR, "couldn't create udp service.");
+ exit(1);
+ }
+ if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquota_service, proto)) {
+ syslog(LOG_ERR, "unable to register (RQUOTAPROG, RQUOTAVERS, %s).", proto?"udp":"(inetd)");
+ exit(1);
+ }
+
+ initfs(); /* init the fs_stat list */
+ svc_run();
+ syslog(LOG_ERR, "svc_run returned");
+ exit(1);
+}
+
+void
+rquota_service(request, transp)
+ struct svc_req *request;
+ SVCXPRT *transp;
+{
+ switch (request->rq_proc) {
+ case NULLPROC:
+ (void)svc_sendreply(transp, xdr_void, (char *)NULL);
+ break;
+
+ case RQUOTAPROC_GETQUOTA:
+ case RQUOTAPROC_GETACTIVEQUOTA:
+ sendquota(request, transp);
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ break;
+ }
+ if (from_inetd)
+ exit(0);
+}
+
+/* read quota for the specified id, and send it */
+void
+sendquota(request, transp)
+ struct svc_req *request;
+ SVCXPRT *transp;
+{
+ struct getquota_args getq_args;
+ struct getquota_rslt getq_rslt;
+ struct dqblk dqblk;
+ struct timeval timev;
+
+ bzero((char *)&getq_args, sizeof(getq_args));
+ if (!svc_getargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
+ svcerr_decode(transp);
+ return;
+ }
+ if (request->rq_cred.oa_flavor != AUTH_UNIX) {
+ /* bad auth */
+ getq_rslt.status = Q_EPERM;
+ } else if (!getfsquota(getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
+ /* failed, return noquota */
+ getq_rslt.status = Q_NOQUOTA;
+ } else {
+ gettimeofday(&timev, NULL);
+ getq_rslt.status = Q_OK;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = DEV_BSIZE;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
+ dqblk.dqb_bhardlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
+ dqblk.dqb_bsoftlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
+ dqblk.dqb_curblocks;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
+ dqblk.dqb_ihardlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
+ dqblk.dqb_isoftlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
+ dqblk.dqb_curinodes;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
+ dqblk.dqb_btime - timev.tv_sec;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
+ dqblk.dqb_itime - timev.tv_sec;
+ }
+ if (!svc_sendreply(transp, xdr_getquota_rslt, (char *)&getq_rslt)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
+ syslog(LOG_ERR, "unable to free arguments");
+ exit(1);
+ }
+}
+
+void
+printerr_reply(transp) /* when a reply to a request failed */
+ SVCXPRT *transp;
+{
+ char *name;
+ struct sockaddr_in *caller;
+ int save_errno;
+
+ save_errno = errno;
+
+ caller = svc_getcaller(transp);
+ name = (char *)inet_ntoa(caller->sin_addr);
+ errno = save_errno;
+ if (errno == 0)
+ syslog(LOG_ERR, "couldn't send reply to %s", name);
+ else
+ syslog(LOG_ERR, "couldn't send reply to %s: %m", name);
+}
+
+/* initialise the fs_tab list from entries in /etc/fstab */
+void
+initfs()
+{
+ struct fs_stat *fs_current = NULL;
+ struct fs_stat *fs_next = NULL;
+ char *qfpathname;
+ struct fstab *fs;
+ struct stat st;
+
+ setfsent();
+ while ((fs = getfsent())) {
+ if (strcmp(fs->fs_vfstype, "ufs"))
+ continue;
+ if (!hasquota(fs, &qfpathname))
+ continue;
+
+ fs_current = (struct fs_stat *) malloc(sizeof(struct fs_stat));
+ fs_current->fs_next = fs_next; /* next element */
+
+ fs_current->fs_file = malloc(sizeof(char) * (strlen(fs->fs_file) + 1));
+ strcpy(fs_current->fs_file, fs->fs_file);
+
+ fs_current->qfpathname = malloc(sizeof(char) * (strlen(qfpathname) + 1));
+ strcpy(fs_current->qfpathname, qfpathname);
+
+ stat(qfpathname, &st);
+ fs_current->st_dev = st.st_dev;
+
+ fs_next = fs_current;
+ }
+ endfsent();
+ fs_begin = fs_current;
+}
+
+/*
+ * gets the quotas for id, filesystem path.
+ * Return 0 if fail, 1 otherwise
+ */
+int
+getfsquota(id, path, dqblk)
+ long id;
+ char *path;
+ struct dqblk *dqblk;
+{
+ struct stat st_path;
+ struct fs_stat *fs;
+ int qcmd, fd, ret = 0;
+
+ if (stat(path, &st_path) < 0)
+ return (0);
+
+ qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
+
+ for (fs = fs_begin; fs != NULL; fs = fs->fs_next) {
+ /* where the devise is the same as path */
+ if (fs->st_dev != st_path.st_dev)
+ continue;
+
+ /* find the specified filesystem. get and return quota */
+ if (quotactl(fs->fs_file, qcmd, id, dqblk) == 0)
+ return (1);
+
+ if ((fd = open(fs->qfpathname, O_RDONLY)) < 0) {
+ syslog(LOG_ERR, "open error: %s: %m", fs->qfpathname);
+ return (0);
+ }
+ if (lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET) == (off_t)-1) {
+ close(fd);
+ return (1);
+ }
+ switch (read(fd, dqblk, sizeof(struct dqblk))) {
+ case 0:
+ /*
+ * Convert implicit 0 quota (EOF)
+ * into an explicit one (zero'ed dqblk)
+ */
+ bzero((caddr_t) dqblk, sizeof(struct dqblk));
+ ret = 1;
+ break;
+ case sizeof(struct dqblk): /* OK */
+ ret = 1;
+ break;
+ default: /* ERROR */
+ syslog(LOG_ERR, "read error: %s: %m", fs->qfpathname);
+ close(fd);
+ return (0);
+ }
+ close(fd);
+ }
+ return (ret);
+}
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ * Comes from quota.c, NetBSD 0.9
+ */
+int
+hasquota(fs, qfnamep)
+ struct fstab *fs;
+ char **qfnamep;
+{
+ static char initname, usrname[100];
+ static char buf[BUFSIZ];
+ char *opt, *cp;
+ char *qfextension[] = INITQFNAMES;
+
+ if (!initname) {
+ sprintf(usrname, "%s%s", qfextension[USRQUOTA], QUOTAFILENAME);
+ initname = 1;
+ }
+ strcpy(buf, fs->fs_mntops);
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if ((cp = index(opt, '=')))
+ *cp++ = '\0';
+ if (strcmp(opt, usrname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp) {
+ *qfnamep = cp;
+ return (1);
+ }
+ sprintf(buf, "%s/%s.%s", fs->fs_file, QUOTAFILENAME, qfextension[USRQUOTA]);
+ *qfnamep = buf;
+ return (1);
+}
diff --git a/libexec/rpc.rstatd/Makefile b/libexec/rpc.rstatd/Makefile
new file mode 100644
index 0000000..026c8e0
--- /dev/null
+++ b/libexec/rpc.rstatd/Makefile
@@ -0,0 +1,10 @@
+# $Id$
+
+PROG = rpc.rstatd
+SRCS = rstatd.c rstat_proc.c
+MAN8 = rpc.rstatd.8
+
+DPADD= ${LIBRPCSVC} ${LIBUTIL} ${LIBKVM}
+LDADD= -lrpcsvc -lutil -lkvm
+
+.include <bsd.prog.mk>
diff --git a/libexec/rpc.rstatd/rpc.rstatd.8 b/libexec/rpc.rstatd/rpc.rstatd.8
new file mode 100644
index 0000000..5a54b81
--- /dev/null
+++ b/libexec/rpc.rstatd/rpc.rstatd.8
@@ -0,0 +1,61 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 1985, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd June 7, 1993
+.Dt RPC.RSTATD 8
+.Os BSD 4.3
+.Sh NAME
+.Nm rpc.rstatd
+.Nd kernel statistics server
+.Sh SYNOPSIS
+.Nm /usr/libexec/rpc.rstatd
+.Sh DESCRIPTION
+.Nm rpc.rstatd
+is a server which returns performance statistics obtained from the kernel.
+These statistics are read using the
+.Xr rup 1
+command.
+The
+.Nm rpc.rstatd
+daemon is normally invoked by
+.Xr inetd 8 .
+.Pp
+.Nm rpc.rstatd
+uses an RPC protocol defined in
+.Pa /usr/include/rpcsvc/rstat.x .
+.Sh SEE ALSO
+.Xr rup 1 ,
+.Xr inetd 8
+
diff --git a/libexec/rpc.rstatd/rstat_proc.c b/libexec/rpc.rstatd/rstat_proc.c
new file mode 100644
index 0000000..bb67bed
--- /dev/null
+++ b/libexec/rpc.rstatd/rstat_proc.c
@@ -0,0 +1,416 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#ifndef lint
+/*static char sccsid[] = "from: @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro";*/
+/*static char sccsid[] = "from: @(#)rstat_proc.c 2.2 88/08/01 4.0 RPCSRC";*/
+static char rcsid[] = "$Id$";
+#endif
+
+/*
+ * rstat service: built with rstat.x and derived from rpc.rstatd.c
+ *
+ * Copyright (c) 1984 by Sun Microsystems, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dkstat.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/vmmeter.h>
+
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <net/if.h>
+#include <net/if_mib.h>
+
+#include <rpc/rpc.h>
+
+#undef FSHIFT /* Use protocol's shift and scale values */
+#undef FSCALE
+#undef if_ipackets
+#undef if_ierrors
+#undef if_opackets
+#undef if_oerrors
+#undef if_collisions
+#include <rpcsvc/rstat.h>
+
+struct nlist nl[] = {
+#define X_CPTIME 0
+ { "_cp_time" },
+#define X_CNT 1
+ { "_cnt" },
+#define X_DKXFER 2
+ { "_dk_xfer" },
+#define X_DKNDRIVE 3
+ { "_dk_ndrive" },
+ { "" },
+};
+int stats_service();
+
+extern int from_inetd;
+int sincelastreq = 0; /* number of alarms since last request */
+extern int closedown;
+
+union {
+ struct stats s1;
+ struct statsswtch s2;
+ struct statstime s3;
+} stats_all;
+
+void updatestat();
+static stat_is_init = 0;
+static kvm_t *kd;
+extern int errno;
+
+static int cp_time_xlat[RSTAT_CPUSTATES] = { CP_USER, CP_NICE, CP_SYS,
+ CP_IDLE };
+static long bsd_cp_time[CPUSTATES];
+
+
+#ifndef FSCALE
+#define FSCALE (1 << 8)
+#endif
+
+stat_init()
+{
+ stat_is_init = 1;
+ setup();
+ updatestat();
+ (void) signal(SIGALRM, updatestat);
+ alarm(1);
+}
+
+statstime *
+rstatproc_stats_3()
+{
+ if (! stat_is_init)
+ stat_init();
+ sincelastreq = 0;
+ return(&stats_all.s3);
+}
+
+statsswtch *
+rstatproc_stats_2()
+{
+ if (! stat_is_init)
+ stat_init();
+ sincelastreq = 0;
+ return(&stats_all.s2);
+}
+
+stats *
+rstatproc_stats_1()
+{
+ if (! stat_is_init)
+ stat_init();
+ sincelastreq = 0;
+ return(&stats_all.s1);
+}
+
+u_int *
+rstatproc_havedisk_3()
+{
+ static u_int have;
+
+ if (! stat_is_init)
+ stat_init();
+ sincelastreq = 0;
+ have = havedisk();
+ return(&have);
+}
+
+u_int *
+rstatproc_havedisk_2()
+{
+ return(rstatproc_havedisk_3());
+}
+
+u_int *
+rstatproc_havedisk_1()
+{
+ return(rstatproc_havedisk_3());
+}
+
+void
+updatestat()
+{
+ int off, i, hz;
+ struct clockinfo clockrate;
+ struct vmmeter cnt;
+ struct ifmibdata ifmd;
+ double avrun[3];
+ struct timeval tm, btm;
+ int mib[6];
+ size_t len;
+ int ifcount;
+
+#ifdef DEBUG
+ fprintf(stderr, "entering updatestat\n");
+#endif
+ if (sincelastreq >= closedown) {
+#ifdef DEBUG
+ fprintf(stderr, "about to closedown\n");
+#endif
+ if (from_inetd)
+ exit(0);
+ else {
+ stat_is_init = 0;
+ return;
+ }
+ }
+ sincelastreq++;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_CLOCKRATE;
+ len = sizeof clockrate;
+ if (sysctl(mib, 2, &clockrate, &len, 0, 0) < 0) {
+ syslog(LOG_ERR, "sysctl(kern.clockrate): %m");
+ exit(1);
+ }
+ hz = clockrate.hz;
+
+ if (kvm_read(kd, (long)nl[X_CPTIME].n_value, (char *)bsd_cp_time, sizeof(bsd_cp_time))
+ != sizeof(bsd_cp_time)) {
+ syslog(LOG_ERR, "rstat: can't read cp_time from kmem\n");
+ exit(1);
+ }
+ for(i = 0; i < RSTAT_CPUSTATES ; i++)
+ stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]];
+
+ (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
+
+ stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
+ stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
+ stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
+ len = sizeof btm;
+ if (sysctl(mib, 2, &btm, &len, 0, 0) < 0) {
+ syslog(LOG_ERR, "sysctl(kern.boottime): %m");
+ exit(1);
+ }
+
+ stats_all.s2.boottime.tv_sec = btm.tv_sec;
+ stats_all.s2.boottime.tv_usec = btm.tv_usec;
+
+
+#ifdef DEBUG
+ fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0],
+ stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
+#endif
+
+ /* XXX - should use sysctl */
+ if (kvm_read(kd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) != sizeof cnt) {
+ syslog(LOG_ERR, "rstat: can't read cnt from kmem\n");
+ exit(1);
+ }
+ stats_all.s1.v_pgpgin = cnt.v_vnodepgsin;
+ stats_all.s1.v_pgpgout = cnt.v_vnodepgsout;
+ stats_all.s1.v_pswpin = cnt.v_swappgsin;
+ stats_all.s1.v_pswpout = cnt.v_swappgsout;
+ stats_all.s1.v_intr = cnt.v_intr;
+ gettimeofday(&tm, (struct timezone *) 0);
+ stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
+ hz*(tm.tv_usec - btm.tv_usec)/1000000;
+ stats_all.s2.v_swtch = cnt.v_swtch;
+
+ /* XXX - should use sysctl */
+ if (kvm_read(kd, (long)nl[X_DKXFER].n_value, (char *)stats_all.s1.dk_xfer, sizeof (stats_all.s1.dk_xfer))
+ != sizeof (stats_all.s1.dk_xfer)) {
+ syslog(LOG_ERR, "rstat: can't read dk_xfer from kmem\n");
+ exit(1);
+ }
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_LINK;
+ mib[2] = NETLINK_GENERIC;
+ mib[3] = IFMIB_SYSTEM;
+ mib[4] = IFMIB_IFCOUNT;
+ len = sizeof ifcount;
+ if (sysctl(mib, 5, &ifcount, &len, 0, 0) < 0) {
+ syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m");
+ exit(1);
+ }
+
+ stats_all.s1.if_ipackets = 0;
+ stats_all.s1.if_opackets = 0;
+ stats_all.s1.if_ierrors = 0;
+ stats_all.s1.if_oerrors = 0;
+ stats_all.s1.if_collisions = 0;
+ for (i = 1; i <= ifcount; i++) {
+ len = sizeof ifmd;
+ mib[3] = IFMIB_IFDATA;
+ mib[4] = i;
+ mib[5] = IFDATA_GENERAL;
+ if (sysctl(mib, 6, &ifmd, &len, 0, 0) < 0) {
+ syslog(LOG_ERR, "sysctl(net.link.ifdata.%d.general)"
+ ": %m", i);
+ exit(1);
+ }
+
+ stats_all.s1.if_ipackets += ifmd.ifmd_data.ifi_ipackets;
+ stats_all.s1.if_opackets += ifmd.ifmd_data.ifi_opackets;
+ stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors;
+ stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors;
+ stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions;
+ }
+ gettimeofday((struct timeval *)&stats_all.s3.curtime,
+ (struct timezone *) 0);
+ alarm(1);
+}
+
+setup()
+{
+ int off;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ int en;
+
+ if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) {
+ syslog(LOG_ERR, "rpc.rstatd, %s", errbuf);
+ exit(1);
+ }
+
+ if ((en = kvm_nlist(kd, nl)) != 0) {
+ syslog(LOG_ERR, "rstatd: Can't get namelist. %d", en);
+ exit (1);
+ }
+}
+
+/*
+ * returns true if have a disk
+ */
+havedisk()
+{
+ int i, cnt;
+ int dk_ndrive;
+
+ if (kvm_nlist(kd, nl) != 0) {
+ syslog(LOG_ERR, "rstatd: Can't get namelist.(d)");
+ exit (1);
+ }
+
+ if (kvm_read(kd, (long)nl[X_DKNDRIVE].n_value, (char *)&dk_ndrive,
+ sizeof dk_ndrive)!= sizeof dk_ndrive) {
+ syslog(LOG_ERR, "rstat: can't read kmem\n");
+ exit(1);
+ }
+ return (dk_ndrive != 0);
+}
+
+void
+rstat_service(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ union {
+ int fill;
+ } argument;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ (void)svc_sendreply(transp, xdr_void, (char *)NULL);
+ goto leave;
+
+ case RSTATPROC_STATS:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_statstime;
+ switch (rqstp->rq_vers) {
+ case RSTATVERS_ORIG:
+ local = (char *(*)()) rstatproc_stats_1;
+ break;
+ case RSTATVERS_SWTCH:
+ local = (char *(*)()) rstatproc_stats_2;
+ break;
+ case RSTATVERS_TIME:
+ local = (char *(*)()) rstatproc_stats_3;
+ break;
+ default:
+ svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
+ goto leave;
+ /*NOTREACHED*/
+ }
+ break;
+
+ case RSTATPROC_HAVEDISK:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_u_int;
+ switch (rqstp->rq_vers) {
+ case RSTATVERS_ORIG:
+ local = (char *(*)()) rstatproc_havedisk_1;
+ break;
+ case RSTATVERS_SWTCH:
+ local = (char *(*)()) rstatproc_havedisk_2;
+ break;
+ case RSTATVERS_TIME:
+ local = (char *(*)()) rstatproc_havedisk_3;
+ break;
+ default:
+ svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
+ goto leave;
+ /*NOTREACHED*/
+ }
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ goto leave;
+ }
+ bzero((char *)&argument, sizeof(argument));
+ if (!svc_getargs(transp, xdr_argument, &argument)) {
+ svcerr_decode(transp);
+ goto leave;
+ }
+ result = (*local)(&argument, rqstp);
+ if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, xdr_argument, &argument)) {
+ (void)fprintf(stderr, "unable to free arguments\n");
+ exit(1);
+ }
+leave:
+ if (from_inetd)
+ exit(0);
+}
diff --git a/libexec/rpc.rstatd/rstatd.c b/libexec/rpc.rstatd/rstatd.c
new file mode 100644
index 0000000..72c449f
--- /dev/null
+++ b/libexec/rpc.rstatd/rstatd.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 1993, John Brezak
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <signal.h>
+#include <syslog.h>
+#include <rpcsvc/rstat.h>
+
+extern void rstat_service();
+
+int from_inetd = 1; /* started from inetd ? */
+int closedown = 20; /* how long to wait before going dormant */
+
+void
+cleanup()
+{
+ (void) pmap_unset(RSTATPROG, RSTATVERS_TIME);
+ (void) pmap_unset(RSTATPROG, RSTATVERS_SWTCH);
+ (void) pmap_unset(RSTATPROG, RSTATVERS_ORIG);
+ exit(0);
+}
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SVCXPRT *transp;
+ int sock = 0;
+ int proto = 0;
+ struct sockaddr_in from;
+ int fromlen;
+
+ if (argc == 2)
+ closedown = atoi(argv[1]);
+ if (closedown <= 0)
+ closedown = 20;
+
+ /*
+ * See if inetd started us
+ */
+ fromlen = sizeof(from);
+ if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ from_inetd = 0;
+ sock = RPC_ANYSOCK;
+ proto = IPPROTO_UDP;
+ }
+
+ if (!from_inetd) {
+ daemon(0, 0);
+
+ (void)pmap_unset(RSTATPROG, RSTATVERS_TIME);
+ (void)pmap_unset(RSTATPROG, RSTATVERS_SWTCH);
+ (void)pmap_unset(RSTATPROG, RSTATVERS_ORIG);
+
+ (void) signal(SIGINT, cleanup);
+ (void) signal(SIGTERM, cleanup);
+ (void) signal(SIGHUP, cleanup);
+ }
+
+ openlog("rpc.rstatd", LOG_CONS|LOG_PID, LOG_DAEMON);
+
+ transp = svcudp_create(sock);
+ if (transp == NULL) {
+ syslog(LOG_ERR, "cannot create udp service.");
+ exit(1);
+ }
+ if (!svc_register(transp, RSTATPROG, RSTATVERS_TIME, rstat_service, proto)) {
+ syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_TIME, udp).");
+ exit(1);
+ }
+ if (!svc_register(transp, RSTATPROG, RSTATVERS_SWTCH, rstat_service, proto)) {
+ syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_SWTCH, udp).");
+ exit(1);
+ }
+ if (!svc_register(transp, RSTATPROG, RSTATVERS_ORIG, rstat_service, proto)) {
+ syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_ORIG, udp).");
+ exit(1);
+ }
+
+ svc_run();
+ syslog(LOG_ERR, "svc_run returned");
+ exit(1);
+}
diff --git a/libexec/rpc.rusersd/Makefile b/libexec/rpc.rusersd/Makefile
new file mode 100644
index 0000000..48f3853
--- /dev/null
+++ b/libexec/rpc.rusersd/Makefile
@@ -0,0 +1,16 @@
+# $Id$
+
+PROG = rpc.rusersd
+SRCS = rusersd.c rusers_proc.c
+MAN8 = rpc.rusersd.8
+
+DPADD= ${LIBRPCSVC} ${LIBUTIL}
+LDADD= -lrpcsvc -lutil
+
+#.if exists(/usr/X11R6/include/X11/extensions/xidle.h)
+#CFLAGS+= -DXIDLE
+#LDADD+= -L/usr/X11R6/lib -lXext -lX11
+#.endif
+
+
+.include <bsd.prog.mk>
diff --git a/libexec/rpc.rusersd/rpc.rusersd.8 b/libexec/rpc.rusersd/rpc.rusersd.8
new file mode 100644
index 0000000..81345f8
--- /dev/null
+++ b/libexec/rpc.rusersd/rpc.rusersd.8
@@ -0,0 +1,64 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 1985, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd June 7, 1993
+.Dt RPC.RUSERSD 8
+.Os BSD 4.3
+.Sh NAME
+.Nm rpc.rusersd
+.Nd logged in users server
+.Sh SYNOPSIS
+.Nm /usr/libexec/rpc.rusersd
+.Sh DESCRIPTION
+.Nm rpc.rusersd
+is a server which returns information about users
+currently logged in to the system.
+.Pp
+The currently logged in users are queried using the
+.Xr rusers 1
+command.
+The
+.Nm rpc.rusersd
+daemon is normally invoked by
+.Xr inetd 8 .
+.Pp
+.Nm rpc.rusersd
+uses an RPC protocol defined in
+.Pa /usr/include/rpcsvc/rnusers.x .
+.Sh SEE ALSO
+.Xr rusers 1 ,
+.Xr w 1 ,
+.Xr who 1 ,
+.Xr inetd 8
diff --git a/libexec/rpc.rusersd/rusers_proc.c b/libexec/rpc.rusersd/rusers_proc.c
new file mode 100644
index 0000000..db6288b
--- /dev/null
+++ b/libexec/rpc.rusersd/rusers_proc.c
@@ -0,0 +1,390 @@
+/*-
+ * Copyright (c) 1993, John Brezak
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif /* not lint */
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <utmp.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef XIDLE
+#include <setjmp.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/xidle.h>
+#endif
+#define utmp rutmp
+#include <rpcsvc/rnusers.h>
+#undef utmp
+
+#define IGNOREUSER "sleeper"
+
+#ifdef OSF
+#define _PATH_UTMP UTMP_FILE
+#endif
+
+#ifndef _PATH_UTMP
+#define _PATH_UTMP "/etc/utmp"
+#endif
+
+#ifndef _PATH_DEV
+#define _PATH_DEV "/dev"
+#endif
+
+#ifndef UT_LINESIZE
+#define UT_LINESIZE sizeof(((struct utmp *)0)->ut_line)
+#endif
+#ifndef UT_NAMESIZE
+#define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name)
+#endif
+#ifndef UT_HOSTSIZE
+#define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host)
+#endif
+
+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];
+ut_line_t line[MAXUSERS];
+ut_name_t name[MAXUSERS];
+ut_host_t host[MAXUSERS];
+
+extern int from_inetd;
+
+FILE *ufp;
+
+#ifdef XIDLE
+Display *dpy;
+
+static jmp_buf openAbort;
+
+static void
+abortOpen ()
+{
+ longjmp (openAbort, 1);
+}
+
+XqueryIdle(char *display)
+{
+ int first_event, first_error;
+ Time IdleTime;
+
+ (void) signal (SIGALRM, abortOpen);
+ (void) alarm ((unsigned) 10);
+ if (!setjmp (openAbort)) {
+ if (!(dpy= XOpenDisplay(display))) {
+ syslog(LOG_ERR, "Cannot open display %s", display);
+ return(-1);
+ }
+ if (XidleQueryExtension(dpy, &first_event, &first_error)) {
+ if (!XGetIdleTime(dpy, &IdleTime)) {
+ syslog(LOG_ERR, "%s: Unable to get idle time.", display);
+ return(-1);
+ }
+ }
+ else {
+ syslog(LOG_ERR, "%s: Xidle extension not loaded.", display);
+ return(-1);
+ }
+ XCloseDisplay(dpy);
+ }
+ else {
+ syslog(LOG_ERR, "%s: Server grabbed for over 10 seconds.", display);
+ return(-1);
+ }
+ (void) signal (SIGALRM, SIG_DFL);
+ (void) alarm ((unsigned) 0);
+
+ IdleTime /= 1000;
+ return((IdleTime + 30) / 60);
+}
+#endif
+
+static u_int
+getidle(char *tty, char *display)
+{
+ struct stat st;
+ char devname[PATH_MAX];
+ time_t now;
+ u_long idle;
+
+ /*
+ * If this is an X terminal or console, then try the
+ * XIdle extension
+ */
+#ifdef XIDLE
+ if (display && *display && (idle = XqueryIdle(display)) >= 0)
+ return(idle);
+#endif
+ idle = 0;
+ if (*tty == 'X') {
+ u_long kbd_idle, mouse_idle;
+#if !defined(__FreeBSD__)
+ kbd_idle = getidle("kbd", NULL);
+#else
+ kbd_idle = getidle("vga", NULL);
+#endif
+ mouse_idle = getidle("mouse", NULL);
+ idle = (kbd_idle < mouse_idle)?kbd_idle:mouse_idle;
+ }
+ else {
+ sprintf(devname, "%s/%s", _PATH_DEV, tty);
+ if (stat(devname, &st) < 0) {
+#ifdef DEBUG
+ printf("%s: %s\n", devname, strerror(errno));
+#endif
+ return(-1);
+ }
+ time(&now);
+#ifdef DEBUG
+ printf("%s: now=%d atime=%d\n", devname, now,
+ st.st_atime);
+#endif
+ idle = now - st.st_atime;
+ idle = (idle + 30) / 60; /* secs->mins */
+ }
+ if (idle < 0) idle = 0;
+
+ return(idle);
+}
+
+static utmpidlearr *
+do_names_2(int all)
+{
+ static utmpidlearr ut;
+ struct utmp usr;
+ int nusers = 0;
+
+ bzero((char *)&ut, sizeof(ut));
+ ut.utmpidlearr_val = &utmp_idle[0];
+
+ ufp = fopen(_PATH_UTMP, "r");
+ if (!ufp) {
+ syslog(LOG_ERR, "%m");
+ return(&ut);
+ }
+
+ /* only entries with both name and line fields */
+ while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1 &&
+ nusers < MAXUSERS)
+ if (*usr.ut_name && *usr.ut_line &&
+ strncmp(usr.ut_name, IGNOREUSER,
+ sizeof(usr.ut_name))
+#ifdef OSF
+ && usr.ut_type == USER_PROCESS
+#endif
+ ) {
+ utmp_idle[nusers].ui_utmp.ut_time =
+ usr.ut_time;
+ 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, UT_LINESIZE);
+ utmp_idle[nusers].ui_utmp.ut_name = 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, UT_HOSTSIZE);
+
+ /* Make sure entries are NUL terminated */
+ line[nusers][UT_LINESIZE] =
+ name[nusers][UT_NAMESIZE] =
+ host[nusers][UT_HOSTSIZE] = '\0';
+ nusers++;
+ }
+
+ ut.utmpidlearr_len = nusers;
+ fclose(ufp);
+ return(&ut);
+}
+
+int *
+rusers_num()
+{
+ static int num_users = 0;
+ struct utmp usr;
+
+ ufp = fopen(_PATH_UTMP, "r");
+ if (!ufp) {
+ syslog(LOG_ERR, "%m");
+ return(0);
+ }
+
+ /* only entries with both name and line fields */
+ while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
+ if (*usr.ut_name && *usr.ut_line &&
+ strncmp(usr.ut_name, IGNOREUSER,
+ sizeof(usr.ut_name))
+#ifdef OSF
+ && usr.ut_type == USER_PROCESS
+#endif
+ ) {
+ num_users++;
+ }
+
+ fclose(ufp);
+ return(&num_users);
+}
+
+static utmparr *
+do_names_1(int all)
+{
+ utmpidlearr *utidle;
+ static utmparr ut;
+ int i;
+
+ bzero((char *)&ut, sizeof(ut));
+
+ utidle = do_names_2(all);
+ if (utidle) {
+ ut.utmparr_len = utidle->utmpidlearr_len;
+ ut.utmparr_val = &old_utmp[0];
+ for (i = 0; i < ut.utmparr_len; i++)
+ bcopy(&utmp_idle[i].ui_utmp, &old_utmp[i],
+ sizeof(old_utmp[0]));
+
+ }
+
+ return(&ut);
+}
+
+utmpidlearr *
+rusersproc_names_2()
+{
+ return(do_names_2(0));
+}
+
+utmpidlearr *
+rusersproc_allnames_2()
+{
+ return(do_names_2(1));
+}
+
+utmparr *
+rusersproc_names_1()
+{
+ return(do_names_1(0));
+}
+
+utmparr *
+rusersproc_allnames_1()
+{
+ return(do_names_1(1));
+}
+
+void
+rusers_service(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ union {
+ int fill;
+ } argument;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ (void)svc_sendreply(transp, xdr_void, (char *)NULL);
+ goto leave;
+
+ case RUSERSPROC_NUM:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_int;
+ local = (char *(*)()) rusers_num;
+ break;
+
+ case RUSERSPROC_NAMES:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_utmpidlearr;
+ switch (rqstp->rq_vers) {
+ case RUSERSVERS_ORIG:
+ local = (char *(*)()) rusersproc_names_1;
+ break;
+ case RUSERSVERS_IDLE:
+ local = (char *(*)()) rusersproc_names_2;
+ break;
+ default:
+ svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
+ goto leave;
+ /*NOTREACHED*/
+ }
+ break;
+
+ case RUSERSPROC_ALLNAMES:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_utmpidlearr;
+ switch (rqstp->rq_vers) {
+ case RUSERSVERS_ORIG:
+ local = (char *(*)()) rusersproc_allnames_1;
+ break;
+ case RUSERSVERS_IDLE:
+ local = (char *(*)()) rusersproc_allnames_2;
+ break;
+ default:
+ svcerr_progvers(transp, RUSERSVERS_ORIG, RUSERSVERS_IDLE);
+ goto leave;
+ /*NOTREACHED*/
+ }
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ goto leave;
+ }
+ bzero((char *)&argument, sizeof(argument));
+ if (!svc_getargs(transp, xdr_argument, &argument)) {
+ svcerr_decode(transp);
+ goto leave;
+ }
+ result = (*local)(&argument, rqstp);
+ if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, xdr_argument, &argument)) {
+ (void)fprintf(stderr, "unable to free arguments\n");
+ exit(1);
+ }
+leave:
+ if (from_inetd)
+ exit(0);
+}
diff --git a/libexec/bugfiler/error.c b/libexec/rpc.rusersd/rusersd.c
index bd00b2b..8538797 100644
--- a/libexec/bugfiler/error.c
+++ b/libexec/rpc.rusersd/rusersd.c
@@ -1,6 +1,6 @@
-/*
- * Copyright (c) 1986, 1987, 1993
- * The Regents of the University of California. All rights reserved.
+/*-
+ * Copyright (c) 1993, John Brezak
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,58 +32,78 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)error.c 8.1 (Berkeley) 6/4/93";
+static char rcsid[] = "$Id$";
#endif /* not lint */
-#include <sys/param.h>
-
-#include <dirent.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <rpc/rpc.h>
+#include <signal.h>
#include <syslog.h>
+#define utmp rutmp
+#include <rpcsvc/rnusers.h>
+#undef utmp
-#include "bug.h"
-#include "extern.h"
+extern void rusers_service();
-static short err_redir; /* stderr redirected */
+int from_inetd = 1;
-/*
- * seterr --
- * redirect stderr for error processing
- */
void
-seterr()
+cleanup()
{
- if (!freopen(ERROR_FILE, "a", stderr))
- error("can't open error file %s.", ERROR_FILE);
- err_redir = YES;
+ (void) pmap_unset(RUSERSPROG, RUSERSVERS_IDLE);
+ (void) pmap_unset(RUSERSPROG, RUSERSVERS_ORIG);
+ exit(0);
}
-/*
- * error --
- * write errors to log file and die
- */
-void
-error(fmt, arg)
- register char *fmt,
- *arg;
+main(argc, argv)
+ int argc;
+ char *argv[];
{
- static char logmsg[MAXLINELEN]; /* syslog message */
+ SVCXPRT *transp;
+ int sock = 0;
+ int proto = 0;
+ struct sockaddr_in from;
+ int fromlen;
+
+ /*
+ * See if inetd started us
+ */
+ fromlen = sizeof(from);
+ if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ from_inetd = 0;
+ sock = RPC_ANYSOCK;
+ proto = IPPROTO_UDP;
+ }
+
+ if (!from_inetd) {
+ daemon(0, 0);
- if (err_redir) {
- /* don't combine these, "fmt" may not require "arg" */
- fprintf(stderr, "\t%s\n\t", tmpname);
- fprintf(stderr, fmt, arg);
- fputc('\n', stderr);
+ (void) pmap_unset(RUSERSPROG, RUSERSVERS_IDLE);
+ (void) pmap_unset(RUSERSPROG, RUSERSVERS_ORIG);
+
+ (void) signal(SIGINT, cleanup);
+ (void) signal(SIGTERM, cleanup);
+ (void) signal(SIGHUP, cleanup);
+ }
+
+ openlog("rpc.rusersd", LOG_CONS|LOG_PID, LOG_DAEMON);
+
+ transp = svcudp_create(sock);
+ if (transp == NULL) {
+ syslog(LOG_ERR, "cannot create udp service.");
+ exit(1);
}
- else {
- sprintf(logmsg, "bugfiler: %s", fmt);
- syslog(LOG_ERR, logmsg, arg);
+ if (!svc_register(transp, RUSERSPROG, RUSERSVERS_IDLE, rusers_service, proto)) {
+ syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_IDLE, %s).", proto?"udp":"(inetd)");
+ exit(1);
}
-#ifdef METOO
- exit(ERR);
-#else
- exit(OK);
-#endif
+
+ if (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG, rusers_service, proto)) {
+ syslog(LOG_ERR, "unable to register (RUSERSPROG, RUSERSVERS_ORIG, %s).", proto?"udp":"(inetd)");
+ exit(1);
+ }
+
+ svc_run();
+ syslog(LOG_ERR, "svc_run returned");
+ exit(1);
}
diff --git a/libexec/rpc.rwalld/Makefile b/libexec/rpc.rwalld/Makefile
new file mode 100644
index 0000000..f9bf277
--- /dev/null
+++ b/libexec/rpc.rwalld/Makefile
@@ -0,0 +1,10 @@
+# $Id$
+
+PROG = rpc.rwalld
+SRCS = rwalld.c
+MAN8 = rpc.rwalld.8
+
+DPADD= ${LIBRPCSVC} ${LIBUTIL}
+LDADD= -lrpcsvc -lutil
+
+.include <bsd.prog.mk>
diff --git a/libexec/rpc.rwalld/rpc.rwalld.8 b/libexec/rpc.rwalld/rpc.rwalld.8
new file mode 100644
index 0000000..cbd64a9
--- /dev/null
+++ b/libexec/rpc.rwalld/rpc.rwalld.8
@@ -0,0 +1,67 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 1985, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd June 7, 1993
+.Dt RPC.RWALLD 8
+.Os BSD 4.3
+.Sh NAME
+.Nm rpc.rwalld
+.Nd write messages to users currently logged in server
+.Sh SYNOPSIS
+.Nm /usr/libexec/rpc.rwalld
+.Sh DESCRIPTION
+.Nm rpc.rwalld
+is a server which will send a message to users
+currently logged in to the system. This server
+invokes the
+.Xr wall 1
+command to actually write the messages to the
+system.
+.Pp
+Messages are sent to this server by the
+.Xr rwall 1
+command.
+The
+.Nm rpc.rwalld
+daemon is normally invoked by
+.Xr inetd 8 .
+.Pp
+.Nm rpc.rwalld
+uses an RPC protocol defined in
+.Pa /usr/include/rpcsvc/rwall.x .
+.Sh SEE ALSO
+.Xr rwall 1 ,
+.Xr wall 1 ,
+.Xr inetd 8
diff --git a/libexec/rpc.rwalld/rwalld.c b/libexec/rpc.rwalld/rwalld.c
new file mode 100644
index 0000000..90b0ffe
--- /dev/null
+++ b/libexec/rpc.rwalld/rwalld.c
@@ -0,0 +1,210 @@
+/*
+ * 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. The name of the author 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 ``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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif /* not lint */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/rwall.h>
+
+#ifdef OSF
+#define WALL_CMD "/usr/sbin/wall"
+#else
+#define WALL_CMD "/usr/bin/wall -n"
+#endif
+
+void wallprog_1();
+void possess();
+void killkids();
+
+int nodaemon = 0;
+int from_inetd = 1;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SVCXPRT *transp;
+ int s, salen;
+ struct sockaddr_in sa;
+ int sock = 0;
+ int proto = 0;
+
+ if (argc == 2 && !strcmp(argv[1], "-n"))
+ nodaemon = 1;
+ if (argc != 1 && !nodaemon) {
+ printf("usage: %s [-n]\n", argv[0]);
+ exit(1);
+ }
+
+ if (geteuid() == 0) {
+ struct passwd *pep = getpwnam("nobody");
+ if (pep)
+ setuid(pep->pw_uid);
+ else
+ setuid(getuid());
+ }
+
+ /*
+ * See if inetd started us
+ */
+ salen = sizeof(sa);
+ if (getsockname(0, (struct sockaddr *)&sa, &salen) < 0) {
+ from_inetd = 0;
+ sock = RPC_ANYSOCK;
+ proto = IPPROTO_UDP;
+ }
+
+ if (!from_inetd) {
+ if (!nodaemon)
+ possess();
+
+ (void)pmap_unset(WALLPROG, WALLVERS);
+ if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+ bzero((char *)&sa, sizeof sa);
+ if (bind(s, (struct sockaddr *)&sa, sizeof sa) < 0) {
+ perror("bind");
+ exit(1);
+ }
+
+ salen = sizeof sa;
+ if (getsockname(s, (struct sockaddr *)&sa, &salen)) {
+ perror("getsockname");
+ exit(1);
+ }
+
+ pmap_set(WALLPROG, WALLVERS, IPPROTO_UDP, ntohs(sa.sin_port));
+ if (dup2(s, 0) < 0) {
+ perror("dup2");
+ exit(1);
+ }
+ (void)pmap_unset(WALLPROG, WALLVERS);
+ }
+
+ (void)signal(SIGCHLD, killkids);
+
+ transp = svcudp_create(sock);
+ if (transp == NULL) {
+ (void)fprintf(stderr, "cannot create udp service.\n");
+ exit(1);
+ }
+ if (!svc_register(transp, WALLPROG, WALLVERS, wallprog_1, proto)) {
+ (void)fprintf(stderr, "unable to register (WALLPROG, WALLVERS, udp).\n");
+ exit(1);
+ }
+ svc_run();
+ (void)fprintf(stderr, "svc_run returned\n");
+ exit(1);
+
+}
+
+void possess()
+{
+ daemon(0, 0);
+}
+
+void killkids()
+{
+ while(wait4(-1, NULL, WNOHANG, NULL) > 0)
+ ;
+}
+
+void *wallproc_wall_1(s)
+ char **s;
+{
+ /* fork, popen wall with special option, and send the message */
+ if (fork() == 0) {
+ FILE *pfp;
+
+ pfp = popen(WALL_CMD, "w");
+ if (pfp != NULL) {
+ fprintf(pfp, "\007\007%s", *s);
+ pclose(pfp);
+ exit(0);
+ }
+ }
+}
+
+void
+wallprog_1(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ union {
+ char *wallproc_wall_1_arg;
+ } argument;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ (void)svc_sendreply(transp, xdr_void, (char *)NULL);
+ goto leave;
+
+ case WALLPROC_WALL:
+ xdr_argument = xdr_wrapstring;
+ xdr_result = xdr_void;
+ local = (char *(*)()) wallproc_wall_1;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ goto leave;
+ }
+ bzero((char *)&argument, sizeof(argument));
+ if (!svc_getargs(transp, xdr_argument, &argument)) {
+ svcerr_decode(transp);
+ goto leave;
+ }
+ result = (*local)(&argument, rqstp);
+ if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, xdr_argument, &argument)) {
+ (void)fprintf(stderr, "unable to free arguments\n");
+ exit(1);
+ }
+leave:
+ if (from_inetd)
+ exit(0);
+}
diff --git a/libexec/rpc.sprayd/Makefile b/libexec/rpc.sprayd/Makefile
new file mode 100644
index 0000000..233c4d8
--- /dev/null
+++ b/libexec/rpc.sprayd/Makefile
@@ -0,0 +1,11 @@
+# $Id$
+
+PROG = rpc.sprayd
+SRCS = sprayd.c
+MAN8 = rpc.sprayd.8
+
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
+.include <bsd.prog.mk>
+
diff --git a/libexec/rpc.sprayd/rpc.sprayd.8 b/libexec/rpc.sprayd/rpc.sprayd.8
new file mode 100644
index 0000000..1b7b823
--- /dev/null
+++ b/libexec/rpc.sprayd/rpc.sprayd.8
@@ -0,0 +1,54 @@
+.\"
+.\" Copyright (c) 1994 Christos Zoulas
+.\" 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 Christos Zoulas.
+.\" 4. The name of the author 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 ``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$
+.\"
+.Dd June 22, 1994
+.Dt RPC.SPRAYD 8
+.Os BSD 4.3
+.Sh NAME
+.Nm rpc.sprayd
+.Nd spray server
+.Sh SYNOPSIS
+.Nm /usr/libexec/rpc.sprayd
+.Sh DESCRIPTION
+.Nm rpc.sprayd
+is a server which records packets sent by the
+.Xr spray 8
+command and sends a traffic report to the originator of the packets.
+The
+.Nm rpc.sprayd
+daemon is normally invoked by
+.Xr inetd 8 .
+.Pp
+.Nm rpc.sprayd
+uses an RPC protocol defined in
+.Pa /usr/include/rpcsvc/spray.x .
+.Sh SEE ALSO
+.Xr spray 8
diff --git a/libexec/rpc.sprayd/sprayd.c b/libexec/rpc.sprayd/sprayd.c
new file mode 100644
index 0000000..44883f4
--- /dev/null
+++ b/libexec/rpc.sprayd/sprayd.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * 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 Christos Zoulas.
+ * 4. The name of the author 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 ``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$
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <syslog.h>
+#include <rpcsvc/spray.h>
+
+static void spray_service __P((struct svc_req *, SVCXPRT *));
+
+static int from_inetd = 1;
+
+#define timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+
+#define TIMEOUT 120
+
+void
+cleanup()
+{
+ (void) pmap_unset(SPRAYPROG, SPRAYVERS);
+ exit(0);
+}
+
+void
+die()
+{
+ exit(0);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SVCXPRT *transp;
+ int sock = 0;
+ int proto = 0;
+ struct sockaddr_in from;
+ int fromlen;
+
+ /*
+ * See if inetd started us
+ */
+ fromlen = sizeof(from);
+ if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ from_inetd = 0;
+ sock = RPC_ANYSOCK;
+ proto = IPPROTO_UDP;
+ }
+
+ if (!from_inetd) {
+ daemon(0, 0);
+
+ (void) pmap_unset(SPRAYPROG, SPRAYVERS);
+
+ (void) signal(SIGINT, cleanup);
+ (void) signal(SIGTERM, cleanup);
+ (void) signal(SIGHUP, cleanup);
+ } else {
+ (void) signal(SIGALRM, die);
+ alarm(TIMEOUT);
+ }
+
+ openlog("rpc.sprayd", LOG_CONS|LOG_PID, LOG_DAEMON);
+
+ transp = svcudp_create(sock);
+ if (transp == NULL) {
+ syslog(LOG_ERR, "cannot create udp service.");
+ return 1;
+ }
+ if (!svc_register(transp, SPRAYPROG, SPRAYVERS, spray_service, proto)) {
+ syslog(LOG_ERR,
+ "unable to register (SPRAYPROG, SPRAYVERS, %s).",
+ proto ? "udp" : "(inetd)");
+ return 1;
+ }
+
+ svc_run();
+ syslog(LOG_ERR, "svc_run returned");
+ return 1;
+}
+
+
+static void
+spray_service(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ static spraycumul scum;
+ static struct timeval clear, get;
+
+ switch (rqstp->rq_proc) {
+ case SPRAYPROC_CLEAR:
+ scum.counter = 0;
+ (void) gettimeofday(&clear, 0);
+ /*FALLTHROUGH*/
+
+ case NULLPROC:
+ (void)svc_sendreply(transp, xdr_void, (char *)NULL);
+ return;
+
+ case SPRAYPROC_SPRAY:
+ scum.counter++;
+ return;
+
+ case SPRAYPROC_GET:
+ (void) gettimeofday(&get, 0);
+ timersub(&get, &clear, &get);
+ scum.clock.sec = get.tv_sec;
+ scum.clock.usec = get.tv_usec;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+
+ if (!svc_sendreply(transp, xdr_spraycumul, (caddr_t)&scum)) {
+ svcerr_systemerr(transp);
+ syslog(LOG_ERR, "bad svc_sendreply");
+ }
+}
diff --git a/libexec/rshd/Makefile b/libexec/rshd/Makefile
index 0b448aa..c94f453 100644
--- a/libexec/rshd/Makefile
+++ b/libexec/rshd/Makefile
@@ -1,11 +1,21 @@
-# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# From: @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id: Makefile,v 1.6 1997/02/22 14:22:22 peter Exp $
PROG= rshd
+SRCS= rshd.c
+MAN8= rshd.8
+
+.if exists(${DESTDIR}/usr/lib/libkrb.a) && (defined(MAKE_KERBEROS) \
+ || defined(MAKE_EBONES))
CFLAGS+=-DKERBEROS -DCRYPT
-SRCS= rshd.c des_rw.c
-MAN8= rshd.0
DPADD= ${LIBKRB} ${LIBDES}
LDADD= -lkrb -ldes
-.PATH: ${.CURDIR}/../../usr.bin/rlogin
+DISTRIBUTION= krb
+.endif
+
+# For login_cap handling
+CFLAGS+=-DLOGIN_CAP
+DPADD+= ${LIBUTIL}
+LDADD+= -lutil
.include <bsd.prog.mk>
diff --git a/libexec/rshd/rshd.8 b/libexec/rshd/rshd.8
index 82e1991..1f2ae32 100644
--- a/libexec/rshd/rshd.8
+++ b/libexec/rshd/rshd.8
@@ -30,6 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)rshd.8 8.1 (Berkeley) 6/4/93
+.\" $Id: rshd.8,v 1.8 1997/04/23 03:06:47 davidn Exp $
.\"
.Dd June 4, 1993
.Dt RSHD 8
@@ -106,7 +107,7 @@ machine.
A null terminated user name of at most 16 characters
is retrieved on the initial socket. This user name
is interpreted as a user identity to use on the
-.Sy server Ns 's
+.Em server Ns 's
machine.
.It
A null terminated command to be passed to a
@@ -132,6 +133,12 @@ If the file
.Pa /etc/nologin
exists and the user is not the superuser,
the connection is closed.
+The name of the nologin file may be overridden
+using the nologin= capability in login.conf
+according to the local user's login class,
+which may also be used to restrict rsh access by
+login time (times.allow and times.deny capabilities)
+and remote host (hosts.allow and hosts.deny capabilities).
.It
A null byte is returned on the initial socket
and the command line is passed to the normal login
@@ -173,13 +180,15 @@ longer than 16 characters.
The command line passed exceeds the size of the argument
list (as configured into the system).
.It Sy Login incorrect.
-No password file entry for the user name existed.
+No password file entry for the user name existed
+or the authentication procedure described above failed.
.It Sy Remote directory.
The
.Xr chdir
command to the home directory failed.
-.It Sy Permission denied.
-The authentication procedure described above failed.
+.It Sy Logins not available right now.
+Rsh was attempted outside the allowed hours defined in
+login.conf for the local user's login class.
.It Sy Can't make pipe.
The pipe needed for the
.Em stderr ,
@@ -195,9 +204,25 @@ on the connection associated with the
and is not preceded by a flag byte.
.El
.Sh SEE ALSO
+.Xr rlogin 1 ,
.Xr rsh 1 ,
+.Xr gethostbyaddr 3 ,
.Xr rcmd 3 ,
-.Xr ruserok 3
+.Xr ruserok 3 ,
+.Xr hosts 5 ,
+.Xr login.conf 5 ,
+.Xr nologin 5 ,
+.Xr services 5 ,
+.Xr named 8 ,
+.Xr rlogind 8 ,
+.Xr syslogd 8 .
+.Sh FILES
+.Bl -tag -width /etc/hosts -compact
+.It Pa /etc/hosts
+.It Pa /etc/hosts.equiv
+.It Pa $HOME/.rhosts
+.It Pa /etc/nologin
+.El
.Sh BUGS
The authentication procedure used here assumes the integrity
of each client machine and the connecting medium. This is
diff --git a/libexec/rshd/rshd.c b/libexec/rshd/rshd.c
index 1b9eea9..dbb1351 100644
--- a/libexec/rshd/rshd.c
+++ b/libexec/rshd/rshd.c
@@ -29,6 +29,8 @@
* 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: rshd.c,v 1.17 1997/05/10 19:02:03 davidn Exp $
*/
#ifndef lint
@@ -54,7 +56,9 @@ static char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94";
#include <sys/time.h>
#include <sys/socket.h>
+#include <netinet/in_systm.h>
#include <netinet/in.h>
+#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -68,6 +72,9 @@ static char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94";
#include <string.h>
#include <syslog.h>
#include <unistd.h>
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#endif
int keepalive = 1;
int check_all;
@@ -82,7 +89,7 @@ char *topdomain __P((char *));
void usage __P((void));
#ifdef KERBEROS
-#include <kerberosIV/des.h>
+#include <des.h>
#include <kerberosIV/krb.h>
#define VERSION_SIZE 9
#define SECURE_MESSAGE "This rsh session is using DES encryption for all transmissions.\r\n"
@@ -108,7 +115,7 @@ main(argc, argv)
openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
opterr = 0;
- while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
+ while ((ch = getopt(argc, argv, OPTIONS)) != -1)
switch (ch) {
case 'a':
check_all = 1;
@@ -200,6 +207,10 @@ doit(fromp)
char *cp, sig, buf[BUFSIZ];
char cmdbuf[NCARGS+1], locuser[16], remuser[16];
char remotehost[2 * MAXHOSTNAMELEN + 1];
+ char fromhost[2 * MAXHOSTNAMELEN + 1];
+#ifdef LOGIN_CAP
+ login_cap_t *lc;
+#endif
#ifdef KERBEROS
AUTH_DAT *kdata = (AUTH_DAT *) NULL;
@@ -233,9 +244,8 @@ doit(fromp)
}
#ifdef IP_OPTIONS
{
- u_char optbuf[BUFSIZ/3], *cp;
- char lbuf[BUFSIZ], *lp;
- int optsize = sizeof(optbuf), ipproto;
+ u_char optbuf[BUFSIZ/3];
+ int optsize = sizeof(optbuf), ipproto, i;
struct protoent *ip;
if ((ip = getprotobyname("ip")) != NULL)
@@ -244,16 +254,18 @@ doit(fromp)
ipproto = IPPROTO_IP;
if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) &&
optsize != 0) {
- lp = lbuf;
- for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
- sprintf(lp, " %2.2x", *cp);
- syslog(LOG_NOTICE,
- "Connection received from %s using IP options (ignored):%s",
- inet_ntoa(fromp->sin_addr), lbuf);
- if (setsockopt(0, ipproto, IP_OPTIONS,
- (char *)NULL, optsize) != 0) {
- syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
- exit(1);
+ for (i = 0; i < optsize; ) {
+ u_char c = optbuf[i];
+ if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
+ syslog(LOG_NOTICE,
+ "Connection refused from %s with IP option %s",
+ inet_ntoa(fromp->sin_addr),
+ c == IPOPT_LSRR ? "LSRR" : "SSRR");
+ exit(1);
+ }
+ if (c == IPOPT_EOL)
+ break;
+ i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
}
}
}
@@ -297,8 +309,12 @@ doit(fromp)
#ifdef KERBEROS
if (!use_kerberos)
#endif
- if (port >= IPPORT_RESERVED) {
- syslog(LOG_ERR, "2nd port not reserved\n");
+ if (port >= IPPORT_RESERVED ||
+ port < IPPORT_RESERVED/2) {
+ syslog(LOG_NOTICE|LOG_AUTH,
+ "2nd socket from %s on unreserved port %u",
+ inet_ntoa(fromp->sin_addr),
+ port);
exit(1);
}
fromp->sin_port = htons(port);
@@ -331,7 +347,9 @@ doit(fromp)
* in a remote net; look up the name and check that this
* address corresponds to the name.
*/
- hostname = hp->h_name;
+ strncpy(fromhost, hp->h_name, sizeof(fromhost) - 1);
+ fromhost[sizeof(fromhost) - 1] = 0;
+ hostname = fromhost;
#ifdef KERBEROS
if (!use_kerberos)
#endif
@@ -346,7 +364,10 @@ doit(fromp)
remotehost);
errorstr =
"Couldn't look up address for your host (%s)\n";
- hostname = inet_ntoa(fromp->sin_addr);
+ strncpy(fromhost, inet_ntoa(fromp->sin_addr),
+ sizeof(fromhost) - 1);
+ fromhost[sizeof(fromhost) - 1] = 0;
+ hostname = fromhost;
} else for (; ; hp->h_addr_list++) {
if (hp->h_addr_list[0] == NULL) {
syslog(LOG_NOTICE,
@@ -355,19 +376,26 @@ doit(fromp)
hp->h_name);
errorstr =
"Host address mismatch for %s\n";
- hostname = inet_ntoa(fromp->sin_addr);
+ strncpy(fromhost, inet_ntoa(fromp->sin_addr),
+ sizeof(fromhost) - 1);
+ fromhost[sizeof(fromhost) - 1] = 0;
+ hostname = fromhost;
break;
}
if (!bcmp(hp->h_addr_list[0],
(caddr_t)&fromp->sin_addr,
sizeof(fromp->sin_addr))) {
- hostname = hp->h_name;
+ hostname = remotehost;
break;
}
}
}
- } else
- errorhost = hostname = inet_ntoa(fromp->sin_addr);
+ } else {
+ strncpy(fromhost, inet_ntoa(fromp->sin_addr),
+ sizeof(fromhost) - 1);
+ fromhost[sizeof(fromhost) - 1] = 0;
+ errorhost = hostname = fromhost;
+ }
#ifdef KERBEROS
if (use_kerberos) {
@@ -391,13 +419,13 @@ doit(fromp)
"rcmd", instance, &fromaddr,
&local_addr, kdata, "", schedule,
version);
- des_set_key(kdata->session, schedule);
+ des_set_key_krb(&kdata->session, schedule);
} else
#endif
rc = krb_recvauth(authopts, 0, ticket, "rcmd",
instance, &fromaddr,
(struct sockaddr_in *) 0,
- kdata, "", (bit_64 *) 0, version);
+ kdata, "", NULL, version);
if (rc != KSUCCESS) {
error("Kerberos authentication failure: %s\n",
krb_err_txt[rc]);
@@ -419,7 +447,20 @@ doit(fromp)
errorstr = "Login incorrect.\n";
goto fail;
}
+#ifdef LOGIN_CAP
+ lc = login_getpwclass(pwd);
+#endif
if (chdir(pwd->pw_dir) < 0) {
+#ifdef LOGIN_CAP
+ if (chdir("/") < 0 ||
+ login_getcapbool(lc, "requirehome", !!pwd->pw_uid)) {
+ syslog(LOG_INFO|LOG_AUTH,
+ "%s@%s as %s: no home directory. cmd='%.80s'",
+ remuser, hostname, locuser, cmdbuf);
+ error("No remote home directory.\n");
+ exit(0);
+ }
+#else
(void) chdir("/");
#ifdef notdef
syslog(LOG_INFO|LOG_AUTH,
@@ -428,6 +469,8 @@ doit(fromp)
error("No remote directory.\n");
exit(1);
#endif
+#endif
+ pwd->pw_dir = "/";
}
#ifdef KERBEROS
@@ -437,7 +480,7 @@ doit(fromp)
syslog(LOG_INFO|LOG_AUTH,
"Kerberos rsh denied to %s.%s@%s",
kdata->pname, kdata->pinst, kdata->prealm);
- error("Permission denied.\n");
+ error("Login incorrect.\n");
exit(1);
}
}
@@ -445,9 +488,10 @@ doit(fromp)
#endif
if (errorstr ||
- pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
+ (pwd->pw_expire && time(NULL) >= pwd->pw_expire) ||
+ (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0,
- remuser, locuser) < 0) {
+ remuser, locuser) < 0)) {
if (__rcmd_errstr)
syslog(LOG_INFO|LOG_AUTH,
"%s@%s as %s: permission denied (%s). cmd='%.80s'",
@@ -459,7 +503,7 @@ doit(fromp)
remuser, hostname, locuser, cmdbuf);
fail:
if (errorstr == NULL)
- errorstr = "Permission denied.\n";
+ errorstr = "Login incorrect.\n";
error(errorstr, errorhost);
exit(1);
}
@@ -468,6 +512,32 @@ fail:
error("Logins currently disabled.\n");
exit(1);
}
+#ifdef LOGIN_CAP
+ if (lc != NULL) {
+ char remote_ip[MAXHOSTNAMELEN];
+
+ strncpy(remote_ip, inet_ntoa(fromp->sin_addr),
+ sizeof(remote_ip) - 1);
+ remote_ip[sizeof(remote_ip) - 1] = 0;
+ if (!auth_hostok(lc, fromhost, remote_ip)) {
+ syslog(LOG_INFO|LOG_AUTH,
+ "%s@%s as %s: permission denied (%s). cmd='%.80s'",
+ remuser, hostname, locuser, __rcmd_errstr,
+ cmdbuf);
+ error("Login incorrect.\n");
+ exit(1);
+ }
+ if (!auth_timeok(lc, time(NULL))) {
+ error("Logins not available right now\n");
+ exit(1);
+ }
+ }
+#endif /* !LOGIN_CAP */
+#if BSD > 43
+ /* before fork, while we're session leader */
+ if (setlogin(pwd->pw_name) < 0)
+ syslog(LOG_ERR, "setlogin() failed: %m");
+#endif
(void) write(STDERR_FILENO, "\0", 1);
sent_null = 1;
@@ -642,13 +712,6 @@ fail:
}
if (*pwd->pw_shell == '\0')
pwd->pw_shell = _PATH_BSHELL;
-#if BSD > 43
- if (setlogin(pwd->pw_name) < 0)
- syslog(LOG_ERR, "setlogin() failed: %m");
-#endif
- (void) setgid((gid_t)pwd->pw_gid);
- initgroups(pwd->pw_name, pwd->pw_gid);
- (void) setuid((uid_t)pwd->pw_uid);
environ = envinit;
strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
strcat(path, _PATH_DEFPATH);
@@ -659,6 +722,17 @@ fail:
cp++;
else
cp = pwd->pw_shell;
+#ifdef LOGIN_CAP
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) {
+ syslog(LOG_ERR, "setusercontext: %m");
+ exit(1);
+ }
+ login_close(lc);
+#else
+ (void) setgid((gid_t)pwd->pw_gid);
+ initgroups(pwd->pw_name, pwd->pw_gid);
+ (void) setuid((uid_t)pwd->pw_uid);
+#endif
endpwent();
if (log_success || pwd->pw_uid == 0) {
#ifdef KERBEROS
diff --git a/libexec/rtld-aout/Makefile b/libexec/rtld-aout/Makefile
new file mode 100644
index 0000000..4177f6b
--- /dev/null
+++ b/libexec/rtld-aout/Makefile
@@ -0,0 +1,20 @@
+# $Id: Makefile,v 1.23 1997/02/22 15:46:46 peter Exp $
+
+PROG= ld.so
+SRCS= mdprologue.S rtld.c malloc.c shlib.c md.c support.c sbrk.c
+MAN1= rtld.1
+LDDIR?= $(.CURDIR)/..
+# As there is relocation going on behind GCC's back, don't cache function addresses.
+PICFLAG=-fpic -fno-function-cse
+CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) $(PICFLAG) -DRTLD
+LDFLAGS+=-nostdlib -Wl,-Bshareable -Wl,-Bsymbolic -Wl,-assert -Wl,nosymbolic
+ASFLAGS+=-k
+DPADD+= ${LIBC:S/c.a/c_pic.a/} ${LIBC:S/c.a/gcc_pic.a/}
+LDADD+= -lc_pic -lgcc_pic
+BINDIR= /usr/libexec
+INSTALLFLAGS+= -fschg -C # -C to install as atomically as possible
+MLINKS= rtld.1 ld.so.1
+
+.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
+
+.include <bsd.prog.mk>
diff --git a/libexec/rtld-aout/dynamic.h b/libexec/rtld-aout/dynamic.h
new file mode 100644
index 0000000..c1890db
--- /dev/null
+++ b/libexec/rtld-aout/dynamic.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author 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 ``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: dynamic.h,v 1.3 1997/02/22 15:46:18 peter Exp $
+ */
+
+#ifndef __DYNAMIC_H__
+#define __DYNAMIC_H__
+
+#define SUN_COMPAT
+
+#include "md.h"
+#include "link.h"
+
+#ifndef RELOC_JMPTAB_P
+
+#define RELOC_JMPTAB_P(r) ((r)->r_jmptable)
+#define RELOC_BASEREL_P(r) ((r)->r_baserel)
+#define RELOC_RELATIVE_P(r) ((r)->r_relative)
+#define RELOC_COPY_P(r) ((r)->r_copy)
+#define RELOC_LAZY_P(r) ((r)->r_jmptable)
+
+#define CHECK_GOT_RELOC(r) ((r)->r_pcrel)
+#define RELOC_PIC_TYPE(r) ((r)->r_baserel? \
+ PIC_TYPE_LARGE:PIC_TYPE_NONE)
+#endif
+
+#ifndef RELOC_INIT_SEGMENT_RELOC
+#define RELOC_INIT_SEGMENT_RELOC(r)
+#endif
+
+#ifndef MAX_GOTOFF
+#define MAX_GOTOFF(x) (LONG_MAX)
+#endif
+
+#ifndef MIN_GOTOFF
+#define MIN_GOTOFF(x) (LONG_MIN)
+#endif
+
+/*
+ * Internal representation of relocation types
+ */
+#define RELTYPE_EXTERN 1
+#define RELTYPE_JMPSLOT 2
+#define RELTYPE_BASEREL 4
+#define RELTYPE_RELATIVE 8
+#define RELTYPE_COPY 16
+
+#define N_ISWEAK(p) (N_BIND(p) & BIND_WEAK)
+
+typedef struct localsymbol {
+ struct nzlist nzlist; /* n[z]list from file */
+ struct glosym *symbol; /* Corresponding global symbol,
+ if any */
+ struct localsymbol *next; /* List of definitions */
+ struct file_entry *entry; /* Backpointer to file */
+ long gotslot_offset; /* Position in GOT, if any */
+ int symbolnum; /* Position in output nlist */
+ int flags;
+#define LS_L_SYMBOL 1 /* Local symbol starts with an `L' */
+#define LS_WRITE 2 /* Symbol goes in output symtable */
+#define LS_RENAME 4 /* xlat name to `<file>.<name>' */
+#define LS_HASGOTSLOT 8 /* This symbol has a GOT entry */
+#define LS_WARNING 16 /* Second part of a N_WARNING duo */
+} localsymbol_t;
+
+/*
+ * Global symbol data is recorded in these structures, one for each global
+ * symbol. They are found via hashing in 'symtab', which points to a vector
+ * of buckets. Each bucket is a chain of these structures through the link
+ * field.
+ *
+ * Rewritten version to support extra info for dynamic linking.
+ */
+
+struct glosym {
+ struct glosym *link; /* Next symbol hash bucket. */
+ char *name; /* Name of this symbol. */
+ long value; /* Value of this symbol */
+ localsymbol_t *refs; /* Chain of local symbols from object
+ files pertaining to this global
+ symbol */
+ localsymbol_t *sorefs;/* Same for local symbols from shared
+ object files. */
+
+ char *warning; /* message, from N_WARNING nlists */
+ int common_size; /* Common size */
+ int symbolnum; /* Symbol index in output symbol table */
+ int rrs_symbolnum; /* Symbol index in RRS symbol table */
+
+ localsymbol_t *def_lsp; /* The local symbol that gave this
+ global symbol its definition */
+
+ char defined; /* Definition of this symbol */
+ char so_defined; /* Definition of this symbol in a shared
+ object. These go into the RRS symbol table */
+ u_char undef_refs; /* Count of number of "undefined"
+ messages printed for this symbol */
+ u_char mult_defs; /* Same for "multiply defined" symbols */
+ struct glosym *alias; /* For symbols of type N_INDR, this
+ points at the real symbol. */
+ int setv_count; /* Number of elements in N_SETV symbols */
+ int size; /* Size of this symbol (either from N_SIZE
+ symbols or a from shared object's RRS */
+ int aux; /* Auxiliary type information conveyed in
+ the `n_other' field of nlists */
+
+ /* The offset into one of the RRS tables, -1 if not used */
+ long jmpslot_offset;
+ long gotslot_offset;
+
+ long flags;
+
+#define GS_DEFINED 0x1 /* Symbol has definition (notyetused)*/
+#define GS_REFERENCED 0x2 /* Symbol is referred to by something
+ interesting */
+#define GS_TRACE 0x4 /* Symbol will be traced */
+#define GS_HASJMPSLOT 0x8 /* */
+#define GS_HASGOTSLOT 0x10 /* Some state bits concerning */
+#define GS_CPYRELOCRESERVED 0x20 /* entries in GOT and PLT tables */
+#define GS_CPYRELOCCLAIMED 0x40 /* */
+#define GS_WEAK 0x80 /* Symbol is weakly defined */
+
+};
+#ifndef __symbol_defined__
+#define __symbol_defined__
+typedef struct glosym symbol;
+#endif
+
+/* The symbol hash table: a vector of SYMTABSIZE pointers to struct glosym. */
+extern symbol *symtab[];
+#define FOR_EACH_SYMBOL(i,sp) { \
+ int i; \
+ for (i = 0; i < SYMTABSIZE; i++) { \
+ register symbol *sp; \
+ for (sp = symtab[i]; sp; sp = sp->link)
+
+#define END_EACH_SYMBOL }}
+
+extern symbol *got_symbol; /* the symbol __GLOBAL_OFFSET_TABLE_ */
+extern symbol *dynamic_symbol; /* the symbol __DYNAMIC */
+
+/*
+ * Each input file, and each library member ("subfile") being loaded, has a
+ * `file_entry' structure for it.
+ *
+ * For files specified by command args, these are contained in the vector which
+ * `file_table' points to.
+ *
+ * For library members, they are dynamically allocated, and chained through the
+ * `chain' field. The chain is found in the `subfiles' field of the
+ * `file_entry'. The `file_entry' objects for the members have `superfile'
+ * fields pointing to the one for the library.
+ *
+ * Rewritten version to support extra info for dynamic linking.
+ */
+
+struct file_entry {
+ char *filename; /* Name of this file. */
+ /*
+ * Name to use for the symbol giving address of text start Usually
+ * the same as filename, but for a file spec'd with -l this is the -l
+ * switch itself rather than the filename.
+ */
+ char *local_sym_name;
+ struct exec header; /* The file's a.out header. */
+ localsymbol_t *symbols; /* Symbol table of the file. */
+ int nsymbols; /* Number of symbols in above array. */
+ int string_size; /* Size in bytes of string table. */
+ char *strings; /* Pointer to the string table when
+ in core, NULL otherwise */
+ int strings_offset; /* Offset of string table,
+ (normally N_STROFF() + 4) */
+ /*
+ * Next two used only if `relocatable_output' or if needed for
+ * output of undefined reference line numbers.
+ */
+ struct relocation_info *textrel; /* Text relocations */
+ int ntextrel; /* # of text relocations */
+ struct relocation_info *datarel; /* Data relocations */
+ int ndatarel; /* # of data relocations */
+
+ /*
+ * Relation of this file's segments to the output file.
+ */
+ int text_start_address; /* Start of this file's text segment
+ in the output file core image. */
+ int data_start_address; /* Start of this file's data segment
+ in the output file core image. */
+ int bss_start_address; /* Start of this file's bss segment
+ in the output file core image. */
+ struct file_entry *subfiles; /* For a library, points to chain of
+ entries for the library members. */
+ struct file_entry *superfile; /* For library member, points to the
+ library's own entry. */
+ struct file_entry *chain; /* For library member, points to next
+ entry for next member. */
+ int starting_offset; /* For a library member, offset of the
+ member within the archive. Zero for
+ files that are not library members.*/
+ int total_size; /* Size of contents of this file,
+ if library member. */
+#ifdef SUN_COMPAT
+ struct file_entry *silly_archive;/* For shared libraries which have
+ a .sa companion */
+#endif
+ int lib_major, lib_minor; /* Version numbers of a shared object */
+
+ int flags;
+#define E_IS_LIBRARY 1 /* File is a an archive */
+#define E_HEADER_VALID 2 /* File's header has been read */
+#define E_SEARCH_DIRS 4 /* Search directories for file */
+#define E_SEARCH_DYNAMIC 8 /* Search for shared libs allowed */
+#define E_JUST_SYMS 0x10 /* File is used for incremental load */
+#define E_DYNAMIC 0x20 /* File is a shared object */
+#define E_SCRAPPED 0x40 /* Ignore this file */
+#define E_SYMBOLS_USED 0x80 /* Symbols from this entry were used */
+#define E_SECONDCLASS 0x100 /* Shared object is a subsidiary */
+};
+
+/*
+ * Runtime Relocation Section (RRS).
+ * This describes the data structures that go into the output text and data
+ * segments to support the run-time linker. The RRS can be empty (plain old
+ * static linking), or can just exist of GOT and PLT entries (in case of
+ * statically linked PIC code).
+ */
+extern int rrs_section_type; /* What's in the RRS section */
+#define RRS_NONE 0
+#define RRS_PARTIAL 1
+#define RRS_FULL 2
+extern int rrs_text_size; /* Size of RRS text additions */
+extern int rrs_text_start; /* Location of above */
+extern int rrs_data_size; /* Size of RRS data additions */
+extern int rrs_data_start; /* Location of above */
+extern char *rrs_search_paths; /* `-L' RT paths */
+
+/* Version number to put in __DYNAMIC (set by -V) */
+extern int soversion;
+#ifndef DEFAULT_SOVERSION
+#define DEFAULT_SOVERSION LD_VERSION_BSD
+#endif
+
+extern int pc_relocation; /* Current PC reloc value */
+
+extern int number_of_shobjs; /* # of shared objects linked in */
+
+/* Current link mode */
+extern int link_mode;
+#define DYNAMIC 1 /* Consider shared libraries */
+#define SYMBOLIC 2 /* Force symbolic resolution */
+#define FORCEARCHIVE 4 /* Force inclusion of all members
+ of archives */
+#define SHAREABLE 8 /* Build a shared object */
+#define SILLYARCHIVE 16 /* Process .sa companions, if any */
+#define FORCEDYNAMIC 32 /* Force dynamic output even if no
+ shared libraries included */
+#define WARNRRSTEXT 64 /* Warn about rrs in text */
+
+extern FILE *outstream; /* Output file. */
+extern struct exec outheader; /* Output file header. */
+extern int magic; /* Output file magic. */
+extern int oldmagic;
+extern int relocatable_output;
+extern int pic_type;
+#define PIC_TYPE_NONE 0
+#define PIC_TYPE_SMALL 1
+#define PIC_TYPE_LARGE 2
+
+void read_header __P((int, struct file_entry *));
+void read_entry_symbols __P((int, struct file_entry *));
+void read_entry_strings __P((int, struct file_entry *));
+void read_entry_relocation __P((int, struct file_entry *));
+void enter_file_symbols __P((struct file_entry *));
+void read_file_symbols __P((struct file_entry *));
+int set_element_prefixed_p __P((char *));
+int text_offset __P((struct file_entry *));
+int file_open __P((struct file_entry *));
+void each_file __P((void (*)(), void *));
+void each_full_file __P((void (*)(), void *));
+unsigned long check_each_file __P((unsigned long (*)(), void *));
+void mywrite __P((void *, int, int, FILE *));
+void padfile __P((int, FILE *));
+
+/* In warnings.c: */
+void perror_name __P((char *));
+void perror_file __P((struct file_entry *));
+void print_symbols __P((FILE *));
+char *get_file_name __P((struct file_entry *));
+void print_file_name __P((struct file_entry *, FILE *));
+void prline_file_name __P((struct file_entry *, FILE *));
+int do_warnings __P((FILE *));
+
+/* In etc.c: */
+#include "support.h"
+
+/* In symbol.c: */
+void symtab_init __P((int));
+symbol *getsym __P((char *)), *getsym_soft __P((char *));
+
+/* In lib.c: */
+void search_library __P((int, struct file_entry *));
+void read_shared_object __P((int, struct file_entry *));
+int findlib __P((struct file_entry *));
+
+/* In shlib.c: */
+#include "shlib.h"
+
+/* In rrs.c: */
+void init_rrs __P((void));
+int rrs_add_shobj __P((struct file_entry *));
+void alloc_rrs_reloc __P((struct file_entry *, symbol *));
+void alloc_rrs_segment_reloc __P((struct file_entry *, struct relocation_info *));
+void alloc_rrs_jmpslot __P((struct file_entry *, symbol *));
+void alloc_rrs_gotslot __P((struct file_entry *, struct relocation_info *, localsymbol_t *));
+void alloc_rrs_cpy_reloc __P((struct file_entry *, symbol *));
+
+int claim_rrs_reloc __P((struct file_entry *, struct relocation_info *, symbol *, long *));
+long claim_rrs_jmpslot __P((struct file_entry *, struct relocation_info *, symbol *, long));
+long claim_rrs_gotslot __P((struct file_entry *, struct relocation_info *, struct localsymbol *, long));
+long claim_rrs_internal_gotslot __P((struct file_entry *, struct relocation_info *, struct localsymbol *, long));
+void claim_rrs_cpy_reloc __P((struct file_entry *, struct relocation_info *, symbol *));
+void claim_rrs_segment_reloc __P((struct file_entry *, struct relocation_info *));
+void consider_rrs_section_lengths __P((void));
+void relocate_rrs_addresses __P((void));
+void write_rrs __P((void));
+
+/* In <md>.c */
+void md_init_header __P((struct exec *, int, int));
+long md_get_addend __P((struct relocation_info *, unsigned char *));
+void md_relocate __P((struct relocation_info *, long, unsigned char *, int));
+void md_make_jmpslot __P((jmpslot_t *, long, long));
+void md_fix_jmpslot __P((jmpslot_t *, long, u_long));
+int md_make_reloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_jmpreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_gotreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_copyreloc __P((struct relocation_info *, struct relocation_info *));
+void md_set_breakpoint __P((long, long *));
+
+#ifdef NEED_SWAP
+/* In xbits.c: */
+void swap_longs __P((long *, int));
+void swap_symbols __P((struct nlist *, int));
+void swap_zsymbols __P((struct nzlist *, int));
+void swap_ranlib_hdr __P((struct ranlib *, int));
+void swap__dynamic __P((struct link_dynamic *));
+void swap_section_dispatch_table __P((struct section_dispatch_table *));
+void swap_so_debug __P((struct so_debug *));
+void swapin_sod __P((struct sod *, int));
+void swapout_sod __P((struct sod *, int));
+void swapout_fshash __P((struct fshash *, int));
+#endif
+
+#endif /* __DYNAMIC_H__ */
diff --git a/libexec/rtld-aout/i386/md-static-funcs.c b/libexec/rtld-aout/i386/md-static-funcs.c
new file mode 100644
index 0000000..758a4b2
--- /dev/null
+++ b/libexec/rtld-aout/i386/md-static-funcs.c
@@ -0,0 +1,17 @@
+/*
+ * $Id$
+ *
+ * Called by ld.so when onanating.
+ * This *must* be a static function, so it is not called through a jmpslot.
+ */
+
+static void
+md_relocate_simple(r, relocation, addr)
+struct relocation_info *r;
+long relocation;
+char *addr;
+{
+ if (r->r_relative)
+ *(long *)addr += relocation;
+}
+
diff --git a/libexec/rtld-aout/i386/md.c b/libexec/rtld-aout/i386/md.c
new file mode 100644
index 0000000..8e945e8
--- /dev/null
+++ b/libexec/rtld-aout/i386/md.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author 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 ``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$
+ */
+
+#include <sys/param.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <err.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+
+#include "dynamic.h"
+
+#if defined(RTLD) && defined(SUN_COMPAT)
+#define REL_SIZE(r) (2) /* !!!!! Sun BUG compatible */
+#else
+#define REL_SIZE(r) ((r)->r_length)
+#endif
+
+/*
+ * Get relocation addend corresponding to relocation record RP
+ * from address ADDR
+ */
+long
+md_get_addend(rp, addr)
+struct relocation_info *rp;
+unsigned char *addr;
+{
+ switch (REL_SIZE(rp)) {
+ case 0:
+ return get_byte(addr);
+ case 1:
+ return get_short(addr);
+ case 2:
+ return get_long(addr);
+ default:
+ errx(1, "Unsupported relocation size: %x",
+ REL_SIZE(rp));
+ }
+}
+
+/*
+ * Put RELOCATION at ADDR according to relocation record RP.
+ */
+void
+md_relocate(rp, relocation, addr, relocatable_output)
+struct relocation_info *rp;
+long relocation;
+unsigned char *addr;
+int relocatable_output;
+{
+ switch (REL_SIZE(rp)) {
+ case 0:
+ put_byte(addr, relocation);
+ break;
+ case 1:
+ put_short(addr, relocation);
+ break;
+ case 2:
+ put_long(addr, relocation);
+ break;
+ default:
+ errx(1, "Unsupported relocation size: %x",
+ REL_SIZE(rp));
+ }
+}
+
+/*
+ * Machine dependent part of claim_rrs_reloc().
+ * Set RRS relocation type.
+ */
+int
+md_make_reloc(rp, r, type)
+struct relocation_info *rp, *r;
+int type;
+{
+ /* Relocation size */
+ r->r_length = rp->r_length;
+
+ if (rp->r_pcrel)
+ r->r_pcrel = 1;
+
+ if (type & RELTYPE_RELATIVE)
+ r->r_relative = 1;
+
+ if (type & RELTYPE_COPY)
+ r->r_copy = 1;
+
+ return 0;
+}
+
+/*
+ * Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
+ * to the binder slot (which is at offset 0 of the PLT).
+ */
+void
+md_make_jmpslot(sp, offset, index)
+jmpslot_t *sp;
+long offset;
+long index;
+{
+ /*
+ * i386 PC-relative "fixed point" is located right after the
+ * instruction it pertains to.
+ */
+ u_long fudge = - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
+
+ sp->opcode = CALL;
+#if 0
+ sp->addr = fudge;
+#else
+ sp->addr[0] = fudge & 0xffff;
+ sp->addr[1] = fudge >> 16;
+#endif
+ sp->reloc_index = index;
+}
+
+/*
+ * Set up a "direct" transfer (ie. not through the run-time binder) from
+ * jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
+ * and by `ld.so' after resolving the symbol.
+ * On the i386, we use the JMP instruction which is PC relative, so no
+ * further RRS relocations will be necessary for such a jmpslot.
+ */
+void
+md_fix_jmpslot(sp, offset, addr)
+jmpslot_t *sp;
+long offset;
+u_long addr;
+{
+ u_long fudge = addr - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
+
+ sp->opcode = JUMP;
+#if 0
+ sp->addr = fudge;
+#else
+ sp->addr[0] = fudge & 0xffff;
+ sp->addr[1] = fudge >> 16;
+#endif
+ sp->reloc_index = 0;
+}
+
+/*
+ * Bind a jmpslot to its target address. TARGET is where the jmpslot
+ * should jump to, and WHERE is a pointer to the jmpslot's address field.
+ * This is called by the dynamic linker when LD_BIND_NOW is set in the
+ * environment.
+ */
+void
+md_bind_jmpslot(target, where)
+u_long target;
+caddr_t where;
+{
+ jmpslot_t *sp =
+ (jmpslot_t *) (where - offsetof(jmpslot_t, addr[0]));
+
+ md_fix_jmpslot(sp, (long) sp, target);
+}
+
+/*
+ * Update the relocation record for a RRS jmpslot.
+ */
+void
+md_make_jmpreloc(rp, r, type)
+struct relocation_info *rp, *r;
+int type;
+{
+ jmpslot_t *sp;
+
+ /*
+ * Fix relocation address to point to the correct
+ * location within this jmpslot.
+ */
+ r->r_address += sizeof(sp->opcode);
+
+ /* Relocation size */
+ r->r_length = 2;
+
+ /* Set relocation type */
+ r->r_jmptable = 1;
+ if (type & RELTYPE_RELATIVE)
+ r->r_relative = 1;
+
+}
+
+/*
+ * Set relocation type for a RRS GOT relocation.
+ */
+void
+md_make_gotreloc(rp, r, type)
+struct relocation_info *rp, *r;
+int type;
+{
+ r->r_baserel = 1;
+ if (type & RELTYPE_RELATIVE)
+ r->r_relative = 1;
+
+ /* Relocation size */
+ r->r_length = 2;
+}
+
+/*
+ * Set relocation type for a RRS copy operation.
+ */
+void
+md_make_cpyreloc(rp, r)
+struct relocation_info *rp, *r;
+{
+ /* Relocation size */
+ r->r_length = 2;
+
+ r->r_copy = 1;
+}
+
+void
+md_set_breakpoint(where, savep)
+long where;
+long *savep;
+{
+ *savep = *(long *)where;
+ *(char *)where = TRAP;
+}
+
+#ifndef RTLD
+
+#ifdef __FreeBSD__
+int netzmagic;
+#endif
+
+/*
+ * Initialize (output) exec header such that useful values are
+ * obtained from subsequent N_*() macro evaluations.
+ */
+void
+md_init_header(hp, magic, flags)
+struct exec *hp;
+int magic, flags;
+{
+#ifdef NetBSD
+ if (oldmagic || magic == QMAGIC)
+ hp->a_midmag = magic;
+ else
+ N_SETMAGIC((*hp), magic, MID_I386, flags);
+#endif
+#ifdef __FreeBSD__
+ if (oldmagic)
+ hp->a_midmag = magic;
+ else if (netzmagic)
+ N_SETMAGIC_NET((*hp), magic, MID_I386, flags);
+ else
+ N_SETMAGIC((*hp), magic, MID_I386, flags);
+#endif
+
+ /* TEXT_START depends on the value of outheader.a_entry. */
+ if (!(link_mode & SHAREABLE))
+ hp->a_entry = PAGSIZ;
+}
+#endif /* RTLD */
+
+
+#ifdef NEED_SWAP
+/*
+ * Byte swap routines for cross-linking.
+ */
+
+void
+md_swapin_exec_hdr(h)
+struct exec *h;
+{
+ int skip = 0;
+
+ if (!N_BADMAG(*h))
+ skip = 1;
+
+ swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
+}
+
+void
+md_swapout_exec_hdr(h)
+struct exec *h;
+{
+ /* NetBSD: Always leave magic alone */
+ int skip = 1;
+#if 0
+ if (N_GETMAGIC(*h) == OMAGIC)
+ skip = 0;
+#endif
+
+ swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
+}
+
+
+void
+md_swapin_reloc(r, n)
+struct relocation_info *r;
+int n;
+{
+ int bits;
+
+ for (; n; n--, r++) {
+ r->r_address = md_swap_long(r->r_address);
+ bits = ((int *)r)[1];
+ r->r_symbolnum = md_swap_long(bits) & 0x00ffffff;
+ r->r_pcrel = (bits & 1);
+ r->r_length = (bits >> 1) & 3;
+ r->r_extern = (bits >> 3) & 1;
+ r->r_baserel = (bits >> 4) & 1;
+ r->r_jmptable = (bits >> 5) & 1;
+ r->r_relative = (bits >> 6) & 1;
+#ifdef N_SIZE
+ r->r_copy = (bits >> 7) & 1;
+#endif
+ }
+}
+
+void
+md_swapout_reloc(r, n)
+struct relocation_info *r;
+int n;
+{
+ int bits;
+
+ for (; n; n--, r++) {
+ r->r_address = md_swap_long(r->r_address);
+ bits = md_swap_long(r->r_symbolnum) & 0xffffff00;
+ bits |= (r->r_pcrel & 1);
+ bits |= (r->r_length & 3) << 1;
+ bits |= (r->r_extern & 1) << 3;
+ bits |= (r->r_baserel & 1) << 4;
+ bits |= (r->r_jmptable & 1) << 5;
+ bits |= (r->r_relative & 1) << 6;
+#ifdef N_SIZE
+ bits |= (r->r_copy & 1) << 7;
+#endif
+ ((int *)r)[1] = bits;
+ }
+}
+
+void
+md_swapout_jmpslot(j, n)
+jmpslot_t *j;
+int n;
+{
+ for (; n; n--, j++) {
+ j->opcode = md_swap_short(j->opcode);
+ j->addr[0] = md_swap_short(j->addr[0]);
+ j->addr[1] = md_swap_short(j->addr[1]);
+ j->reloc_index = md_swap_short(j->reloc_index);
+ }
+}
+
+#endif /* NEED_SWAP */
diff --git a/libexec/rtld-aout/i386/md.h b/libexec/rtld-aout/i386/md.h
new file mode 100644
index 0000000..84785de
--- /dev/null
+++ b/libexec/rtld-aout/i386/md.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author 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 ``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: md.h,v 1.16 1997/02/22 15:46:34 peter Exp $
+ */
+
+#ifndef __MD_H__
+#define __MD_H__
+
+#if defined(CROSS_LINKER) && defined(XHOST) && XHOST==sparc
+#define NEED_SWAP
+#endif
+
+#define MAX_ALIGNMENT (sizeof (long))
+
+#ifdef NetBSD
+#define PAGSIZ __LDPGSZ
+#else
+#define PAGSIZ 4096
+#endif
+
+#if defined(NetBSD) || defined(CROSS_LINKER)
+
+#define N_SET_FLAG(ex,f) (oldmagic || N_GETMAGIC(ex)==QMAGIC ? (0) : \
+ N_SETMAGIC(ex, \
+ N_GETMAGIC(ex), \
+ MID_MACHINE, \
+ N_GETFLAG(ex)|(f)))
+
+#define N_IS_DYNAMIC(ex) ((N_GETFLAG(ex) & EX_DYNAMIC))
+
+#define N_BADMID(ex) \
+ (N_GETMID(ex) != 0 && N_GETMID(ex) != MID_MACHINE)
+
+#endif
+
+/*
+ * FreeBSD does it differently
+ */
+#ifdef __FreeBSD__
+#define N_SET_FLAG(ex,f) (oldmagic ? (0) : \
+ (netzmagic == 0 ? \
+ N_SETMAGIC(ex, \
+ N_GETMAGIC(ex), \
+ MID_MACHINE, \
+ N_GETFLAG(ex)|(f)) : \
+ N_SETMAGIC_NET(ex, \
+ N_GETMAGIC_NET(ex), \
+ MID_MACHINE, \
+ N_GETFLAG_NET(ex)|(f)) ))
+
+#define N_IS_DYNAMIC(ex) ((N_GETMAGIC_NET(ex) == ZMAGIC) ? \
+ ((N_GETFLAG_NET(ex) & EX_DYNAMIC)) : \
+ ((N_GETFLAG(ex) & EX_DYNAMIC) ))
+#define N_BADMID(ex) 0
+#endif
+
+/*
+ * Should be handled by a.out.h ?
+ */
+#define N_ADJUST(ex) (((ex).a_entry < PAGSIZ) ? -PAGSIZ : 0)
+#define TEXT_START(ex) (N_TXTADDR(ex) + N_ADJUST(ex))
+#define DATA_START(ex) (N_DATADDR(ex) + N_ADJUST(ex))
+
+#define RELOC_STATICS_THROUGH_GOT_P(r) (0)
+#define JMPSLOT_NEEDS_RELOC (0)
+
+#define md_got_reloc(r) (0)
+
+#define md_get_rt_segment_addend(r,a) md_get_addend(r,a)
+
+#define RELOC_INIT_SEGMENT_RELOC(r) ((r)->r_length = 2)
+
+/* Width of a Global Offset Table entry */
+#define GOT_ENTRY_SIZE 4
+typedef long got_t;
+
+typedef struct jmpslot {
+ u_short opcode;
+ u_short addr[2];
+ u_short reloc_index;
+#define JMPSLOT_RELOC_MASK 0xffff
+} jmpslot_t;
+
+#define NOP 0x90
+#define CALL 0xe890 /* NOP + CALL opcode */
+#define JUMP 0xe990 /* NOP + JMP opcode */
+#define TRAP 0xcc /* INT 3 */
+
+/*
+ * Byte swap defs for cross linking
+ */
+
+#if !defined(NEED_SWAP)
+
+#define md_swapin_exec_hdr(h)
+#define md_swapout_exec_hdr(h)
+#define md_swapin_symbols(s,n)
+#define md_swapout_symbols(s,n)
+#define md_swapin_zsymbols(s,n)
+#define md_swapout_zsymbols(s,n)
+#define md_swapin_reloc(r,n)
+#define md_swapout_reloc(r,n)
+#define md_swapin__dynamic(l)
+#define md_swapout__dynamic(l)
+#define md_swapin_section_dispatch_table(l)
+#define md_swapout_section_dispatch_table(l)
+#define md_swapin_so_debug(d)
+#define md_swapout_so_debug(d)
+#define md_swapin_rrs_hash(f,n)
+#define md_swapout_rrs_hash(f,n)
+#define md_swapin_sod(l,n)
+#define md_swapout_sod(l,n)
+#define md_swapout_jmpslot(j,n)
+#define md_swapout_got(g,n)
+#define md_swapin_ranlib_hdr(h,n)
+#define md_swapout_ranlib_hdr(h,n)
+
+#endif /* NEED_SWAP */
+
+#ifdef CROSS_LINKER
+
+#define get_byte(p) ( ((unsigned char *)(p))[0] )
+
+#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \
+ ( ((unsigned char *)(p))[1] ) \
+ )
+
+#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \
+ ( ((unsigned char *)(p))[1] << 16) | \
+ ( ((unsigned char *)(p))[2] << 8 ) | \
+ ( ((unsigned char *)(p))[3] ) \
+ )
+
+#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
+
+#define put_short(p, v) { ((unsigned char *)(p))[0] = \
+ ((((unsigned long)(v)) >> 8) & 0xff); \
+ ((unsigned char *)(p))[1] = \
+ ((((unsigned long)(v)) ) & 0xff); }
+
+#define put_long(p, v) { ((unsigned char *)(p))[0] = \
+ ((((unsigned long)(v)) >> 24) & 0xff); \
+ ((unsigned char *)(p))[1] = \
+ ((((unsigned long)(v)) >> 16) & 0xff); \
+ ((unsigned char *)(p))[2] = \
+ ((((unsigned long)(v)) >> 8) & 0xff); \
+ ((unsigned char *)(p))[3] = \
+ ((((unsigned long)(v)) ) & 0xff); }
+
+#ifdef NEED_SWAP
+
+/* Define IO byte swapping routines */
+
+void md_swapin_exec_hdr __P((struct exec *));
+void md_swapout_exec_hdr __P((struct exec *));
+void md_swapin_reloc __P((struct relocation_info *, int));
+void md_swapout_reloc __P((struct relocation_info *, int));
+void md_swapout_jmpslot __P((jmpslot_t *, int));
+
+#define md_swapin_symbols(s,n) swap_symbols(s,n)
+#define md_swapout_symbols(s,n) swap_symbols(s,n)
+#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n)
+#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n)
+#define md_swapin__dynamic(l) swap__dynamic(l)
+#define md_swapout__dynamic(l) swap__dynamic(l)
+#define md_swapin_section_dispatch_table(l) swap_section_dispatch_table(l)
+#define md_swapout_section_dispatch_table(l) swap_section_dispatch_table(l)
+#define md_swapin_so_debug(d) swap_so_debug(d)
+#define md_swapout_so_debug(d) swap_so_debug(d)
+#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n)
+#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n)
+#define md_swapin_sod(l,n) swapin_sod(l,n)
+#define md_swapout_sod(l,n) swapout_sod(l,n)
+#define md_swapout_got(g,n) swap_longs((long*)(g),n)
+#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
+#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
+
+#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) )
+
+#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \
+ (((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000))
+
+#else /* We need not swap, but must pay attention to alignment: */
+
+#define md_swap_short(x) (x)
+#define md_swap_long(x) (x)
+
+#endif /* NEED_SWAP */
+
+#else /* Not a cross linker: use native */
+
+#define md_swap_short(x) (x)
+#define md_swap_long(x) (x)
+
+#define get_byte(where) (*(char *)(where))
+#define get_short(where) (*(short *)(where))
+#define get_long(where) (*(long *)(where))
+
+#define put_byte(where,what) (*(char *)(where) = (what))
+#define put_short(where,what) (*(short *)(where) = (what))
+#define put_long(where,what) (*(long *)(where) = (what))
+
+#endif /* CROSS_LINKER */
+
+void md_init_header __P((struct exec *, int, int));
+long md_get_addend __P((struct relocation_info *, unsigned char *));
+void md_relocate __P((struct relocation_info *, long, unsigned char *, int));
+void md_make_jmpslot __P((jmpslot_t *, long, long));
+void md_fix_jmpslot __P((jmpslot_t *, long, u_long));
+void md_bind_jmpslot __P((u_long, caddr_t));
+int md_make_reloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_jmpreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_gotreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_copyreloc __P((struct relocation_info *, struct relocation_info *));
+void md_set_breakpoint __P((long, long *));
+
+
+#endif /* __MD_H__ */
diff --git a/libexec/rtld-aout/i386/mdprologue.S b/libexec/rtld-aout/i386/mdprologue.S
new file mode 100644
index 0000000..091fe7f
--- /dev/null
+++ b/libexec/rtld-aout/i386/mdprologue.S
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author 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 ``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$
+ */
+
+/*
+ * i386 run-time link editor entry points.
+ */
+
+#include <sys/syscall.h>
+
+ .text
+ .globl _binder, _binder_entry
+
+/*
+ * _rtl(int version, struct crt_ldso *crtp)
+ */
+
+_rtl: # crt0 calls us here
+ pushl %ebp # Allocate stack frame
+ movl %esp,%ebp
+ pushl %ebx
+
+ call 1f # PIC function prologue
+1:
+ popl %ebx
+ addl $_GLOBAL_OFFSET_TABLE_+[.-1b],%ebx
+
+ movl 12(%ebp),%eax # Extract data from interface structure
+ movl (%eax),%eax # base address of ld.so (first field)
+ # setup arguments for rtld()
+ movl (%ebx),%ecx # 1st entry in GOT is our __DYNAMIC
+ addl %eax,%ecx # add load address
+ pushl %ecx # 3rd arg
+ pushl 12(%ebp) # 2nd arg == &crt.
+ pushl 8(%ebp) # 1st arg == version
+ addl _rtld@GOT(%ebx),%eax # relocate address of function
+ call %eax # _rtld(version, crtp, DYNAMIC)
+ addl $12,%esp # pop arguments
+
+ popl %ebx
+ leave # remove stack frame
+ ret
+
+ # First call to a procedure generally comes through here for
+ # binding.
+
+_binder_entry:
+ pushl %ebp # setup a stack frame
+ movl %esp,%ebp
+ pusha # save all regs
+
+ xorl %eax,%eax # clear
+ movl 4(%ebp),%esi # return address in PLT
+ movw (%esi),%ax # get hold of relocation number
+ subl $6,%esi # make it point to the jmpslot
+
+ pushl %eax # pushd arguments
+ pushl %esi #
+ call _binder@PLT # _binder(rpc, index)
+ addl $8,%esp # pop arguments
+ movl %eax,4(%ebp) # return value from _binder() == actual
+ # address of function
+ popa # restore regs
+ leave # remove our stack frame
+ ret
diff --git a/libexec/rtld-aout/md-prologue.c b/libexec/rtld-aout/md-prologue.c
new file mode 100644
index 0000000..dae455e
--- /dev/null
+++ b/libexec/rtld-aout/md-prologue.c
@@ -0,0 +1,39 @@
+/*
+ * rtld entry pseudo code - turn into assembler and tweak it
+ */
+
+#include <sys/types.h>
+#include <sys/types.h>
+#include <a.out.h>
+#include "link.h"
+#include "md.h"
+
+extern long _GOT_[];
+extern void (*rtld)();
+extern void (*binder())();
+
+void
+rtld_entry(version, crtp)
+int version;
+struct crt *crtp;
+{
+ register struct link_dynamic *dp;
+ register void (*f)();
+
+ /* __DYNAMIC is first entry in GOT */
+ dp = (struct link_dynamic *) (_GOT_[0]+crtp->crt_ba);
+
+ f = (void (*)())((long)rtld + crtp->crt_ba);
+ (*f)(version, crtp, dp);
+}
+
+void
+binder_entry()
+{
+ extern int PC;
+ struct jmpslot *sp;
+ void (*func)();
+
+ func = binder(PC, sp->reloc_index & 0x003fffff);
+ (*func)();
+}
diff --git a/libexec/rtld-aout/rtld.1 b/libexec/rtld-aout/rtld.1
new file mode 100644
index 0000000..dbd4dde
--- /dev/null
+++ b/libexec/rtld-aout/rtld.1
@@ -0,0 +1,224 @@
+.\" $Id: rtld.1,v 1.13 1997/02/22 15:46:47 peter Exp $
+.\"
+.\" Copyright (c) 1995 Paul Kranenburg
+.\" 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 acknowledgment:
+.\" This product includes software developed by Paul Kranenburg.
+.\" 3. The name of the author 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 ``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.
+.\"
+.Dd June 27, 1995
+.Dt RTLD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ld.so
+.Nd run-time link-editor
+.Sh DESCRIPTION
+.Nm
+is a self-contained, position independent program image providing run-time
+support for loading and link-editing shared objects into a process'
+address space. It uses the data structures
+.Po
+see
+.Xr link 5
+.Pc
+contained within dynamically linked programs to determine which shared
+libraries are needed and loads them at a convenient virtual address
+using the
+.Xr mmap 2
+system call.
+.Pp
+After all shared libraries have been successfully loaded,
+.Nm
+proceeds to resolve external references from both the main program and
+all objects loaded. A mechanism is provided for initialization routines
+to be called, on a per-object basis, giving a shared object an opportunity
+to perform any extra set-up, before execution of the program proper begins.
+This is useful for C++ libraries that contain static constructors.
+.Pp
+.Nm
+is itself a shared object that is initially loaded by the startup module
+.Em crt0 .
+Since
+.Xr a.out 5
+formats do not provide easy access to the file header from within a running
+process,
+.Em crt0
+uses the special symbol
+.Va _DYNAMIC
+to determine whether a program is in fact dynamically linked or not. Whenever
+the linker
+.Xr ld 1
+has relocated this symbol to a location other than 0,
+.Em crt0
+assumes the services of
+.Nm
+are needed
+.Po
+see
+.Xr link 5
+for details
+.Pc \&.
+.Em crt0
+passes control to
+.Nm
+\&'s entry point before the program's
+.Fn main
+routine is called. Thus,
+.Nm
+can complete the link-editing process before the dynamic program calls upon
+services of any dynamic library.
+.Pp
+To quickly locate the required shared objects in the filesystem,
+.Nm
+may use a
+.Dq hints
+file, prepared by the
+.Xr ldconfig 8
+utility, in which the full path specification of the shared objects can be
+looked up by hashing on the 3-tuple
+.Ao
+library-name, major-version-number, minor-version-number
+.Ac \&.
+.Pp
+.Nm
+recognises a number of environment variables that can be used to modify
+its behaviour as follows:
+.Pp
+.Bl -tag -width "LD_IGNORE_MISSING_OBJECTS"
+.It Ev LD_LIBRARY_PATH
+A colon separated list of directories, overriding the default search path
+for shared libraries.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_PRELOAD
+A colon separated list of shared libraries, to be linked in before any
+other shared libraries. If the directory is not specified then
+the directories specified by LD_LIBRARY_PATH will be searched first
+followed by the set of built-in standard directories.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_BIND_NOW
+When set to a nonempty string, causes
+.Nm
+to relocate all external function calls before starting execution of the
+program. Normally, function calls are bound lazily, at the first call
+of each function.
+.Ev LD_BIND_NOW
+increases the start-up time of a program, but it avoids run-time
+surprises caused by unexpectedly undefined functions.
+.It Ev LD_WARN_NON_PURE_CODE
+When set to a nonempty string, issue a warning whenever a link-editing
+operation requires modification of the text segment of some loaded
+object. This is usually indicative of an incorrectly built library.
+.It Ev LD_SUPPRESS_WARNINGS
+When set to a nonempty string, no warning messages of any kind are
+issued. Normally, a warning is given if satisfactorily versioned
+library could not be found.
+.It Ev LD_IGNORE_MISSING_OBJECTS
+When set to a nonempty string, makes it a nonfatal condition if
+one or more required shared objects cannot be loaded.
+Loading and execution proceeds using the objects that are
+available.
+A warning is produced for each missing object, unless the environment
+variable
+.Ev LD_SUPPRESS_WARNINGS
+is set to a nonempty string.
+.Pp
+This is ignored for set-user-ID and set-group-ID programs.
+.Pp
+Missing shared objects can be ignored without errors if all the
+following conditions hold:
+.Bl -bullet
+.It
+They do not supply definitions for any required data symbols.
+.It
+No functions defined by them are called during program execution.
+.It
+The environment variable
+.Ev LD_BIND_NOW
+is unset or is set to the empty string.
+.El
+.It Ev LD_TRACE_LOADED_OBJECTS
+When set to a nonempty string, causes
+.Nm
+to exit after loading the shared objects and printing a summary which includes
+the absolute pathnames of all objects, to standard output.
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT1
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT2
+When set, these variables are interpreted as format strings a la
+.Xr printf 3
+to customize the trace output and are used by
+.Xr ldd 1 's
+.Fl f
+option and allows
+.Xr ldd 1
+to be operated as a filter more conveniently.
+The following conversions can be used:
+.Bl -tag -indent "LD_TRACE_LOADED_OBJECTS_FMT1 " -width "xxxx"
+.It \&%a
+The main program's name
+.Po also known as
+.Dq __progname
+.Pc .
+.It \&%A
+The value of the environment variable
+.Ev LD_TRACE_LOADED_OBJECTS_PROGNAME
+.It \&%o
+The library name.
+.It \&%m
+The library's major version number.
+.It \&%n
+The library's minor version number.
+.It \&%p
+The full pathname as determined by
+.Nm rtld Ns 's
+library search rules.
+.It \&%x
+The library's load address.
+.El
+.Pp
+Additionally,
+.Sy \en
+and
+.Sy \et
+are recognised and have their usual meaning.
+.\" .It Ev LD_NO_INTERN_SEARCH
+.\" When set,
+.\" .Nm
+.\" does not process any internal search paths that were recorded in the
+.\" executable.
+.\" .It Ev LD_NOSTD_PATH
+.\" When set, do not include a set of built-in standard directory paths for
+.\" searching. This might be useful when running on a system with a completely
+.\" non-standard filesystem layout.
+.El
+.Pp
+.Sh FILES
+/var/run/ld.so.hints
+.Pp
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr link 5 ,
+.Xr ldconfig 8
+.Sh HISTORY
+The shared library model employed first appeared in SunOS 4.0
diff --git a/libexec/rtld-aout/rtld.1aout b/libexec/rtld-aout/rtld.1aout
new file mode 100644
index 0000000..dbd4dde
--- /dev/null
+++ b/libexec/rtld-aout/rtld.1aout
@@ -0,0 +1,224 @@
+.\" $Id: rtld.1,v 1.13 1997/02/22 15:46:47 peter Exp $
+.\"
+.\" Copyright (c) 1995 Paul Kranenburg
+.\" 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 acknowledgment:
+.\" This product includes software developed by Paul Kranenburg.
+.\" 3. The name of the author 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 ``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.
+.\"
+.Dd June 27, 1995
+.Dt RTLD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ld.so
+.Nd run-time link-editor
+.Sh DESCRIPTION
+.Nm
+is a self-contained, position independent program image providing run-time
+support for loading and link-editing shared objects into a process'
+address space. It uses the data structures
+.Po
+see
+.Xr link 5
+.Pc
+contained within dynamically linked programs to determine which shared
+libraries are needed and loads them at a convenient virtual address
+using the
+.Xr mmap 2
+system call.
+.Pp
+After all shared libraries have been successfully loaded,
+.Nm
+proceeds to resolve external references from both the main program and
+all objects loaded. A mechanism is provided for initialization routines
+to be called, on a per-object basis, giving a shared object an opportunity
+to perform any extra set-up, before execution of the program proper begins.
+This is useful for C++ libraries that contain static constructors.
+.Pp
+.Nm
+is itself a shared object that is initially loaded by the startup module
+.Em crt0 .
+Since
+.Xr a.out 5
+formats do not provide easy access to the file header from within a running
+process,
+.Em crt0
+uses the special symbol
+.Va _DYNAMIC
+to determine whether a program is in fact dynamically linked or not. Whenever
+the linker
+.Xr ld 1
+has relocated this symbol to a location other than 0,
+.Em crt0
+assumes the services of
+.Nm
+are needed
+.Po
+see
+.Xr link 5
+for details
+.Pc \&.
+.Em crt0
+passes control to
+.Nm
+\&'s entry point before the program's
+.Fn main
+routine is called. Thus,
+.Nm
+can complete the link-editing process before the dynamic program calls upon
+services of any dynamic library.
+.Pp
+To quickly locate the required shared objects in the filesystem,
+.Nm
+may use a
+.Dq hints
+file, prepared by the
+.Xr ldconfig 8
+utility, in which the full path specification of the shared objects can be
+looked up by hashing on the 3-tuple
+.Ao
+library-name, major-version-number, minor-version-number
+.Ac \&.
+.Pp
+.Nm
+recognises a number of environment variables that can be used to modify
+its behaviour as follows:
+.Pp
+.Bl -tag -width "LD_IGNORE_MISSING_OBJECTS"
+.It Ev LD_LIBRARY_PATH
+A colon separated list of directories, overriding the default search path
+for shared libraries.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_PRELOAD
+A colon separated list of shared libraries, to be linked in before any
+other shared libraries. If the directory is not specified then
+the directories specified by LD_LIBRARY_PATH will be searched first
+followed by the set of built-in standard directories.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_BIND_NOW
+When set to a nonempty string, causes
+.Nm
+to relocate all external function calls before starting execution of the
+program. Normally, function calls are bound lazily, at the first call
+of each function.
+.Ev LD_BIND_NOW
+increases the start-up time of a program, but it avoids run-time
+surprises caused by unexpectedly undefined functions.
+.It Ev LD_WARN_NON_PURE_CODE
+When set to a nonempty string, issue a warning whenever a link-editing
+operation requires modification of the text segment of some loaded
+object. This is usually indicative of an incorrectly built library.
+.It Ev LD_SUPPRESS_WARNINGS
+When set to a nonempty string, no warning messages of any kind are
+issued. Normally, a warning is given if satisfactorily versioned
+library could not be found.
+.It Ev LD_IGNORE_MISSING_OBJECTS
+When set to a nonempty string, makes it a nonfatal condition if
+one or more required shared objects cannot be loaded.
+Loading and execution proceeds using the objects that are
+available.
+A warning is produced for each missing object, unless the environment
+variable
+.Ev LD_SUPPRESS_WARNINGS
+is set to a nonempty string.
+.Pp
+This is ignored for set-user-ID and set-group-ID programs.
+.Pp
+Missing shared objects can be ignored without errors if all the
+following conditions hold:
+.Bl -bullet
+.It
+They do not supply definitions for any required data symbols.
+.It
+No functions defined by them are called during program execution.
+.It
+The environment variable
+.Ev LD_BIND_NOW
+is unset or is set to the empty string.
+.El
+.It Ev LD_TRACE_LOADED_OBJECTS
+When set to a nonempty string, causes
+.Nm
+to exit after loading the shared objects and printing a summary which includes
+the absolute pathnames of all objects, to standard output.
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT1
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT2
+When set, these variables are interpreted as format strings a la
+.Xr printf 3
+to customize the trace output and are used by
+.Xr ldd 1 's
+.Fl f
+option and allows
+.Xr ldd 1
+to be operated as a filter more conveniently.
+The following conversions can be used:
+.Bl -tag -indent "LD_TRACE_LOADED_OBJECTS_FMT1 " -width "xxxx"
+.It \&%a
+The main program's name
+.Po also known as
+.Dq __progname
+.Pc .
+.It \&%A
+The value of the environment variable
+.Ev LD_TRACE_LOADED_OBJECTS_PROGNAME
+.It \&%o
+The library name.
+.It \&%m
+The library's major version number.
+.It \&%n
+The library's minor version number.
+.It \&%p
+The full pathname as determined by
+.Nm rtld Ns 's
+library search rules.
+.It \&%x
+The library's load address.
+.El
+.Pp
+Additionally,
+.Sy \en
+and
+.Sy \et
+are recognised and have their usual meaning.
+.\" .It Ev LD_NO_INTERN_SEARCH
+.\" When set,
+.\" .Nm
+.\" does not process any internal search paths that were recorded in the
+.\" executable.
+.\" .It Ev LD_NOSTD_PATH
+.\" When set, do not include a set of built-in standard directory paths for
+.\" searching. This might be useful when running on a system with a completely
+.\" non-standard filesystem layout.
+.El
+.Pp
+.Sh FILES
+/var/run/ld.so.hints
+.Pp
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr link 5 ,
+.Xr ldconfig 8
+.Sh HISTORY
+The shared library model employed first appeared in SunOS 4.0
diff --git a/libexec/rtld-aout/rtld.c b/libexec/rtld-aout/rtld.c
new file mode 100644
index 0000000..ea33fe8
--- /dev/null
+++ b/libexec/rtld-aout/rtld.c
@@ -0,0 +1,2120 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author 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 ``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: rtld.c,v 1.46 1997/02/22 15:46:48 peter Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#ifndef MAP_COPY
+#define MAP_COPY MAP_PRIVATE
+#endif
+#include <dlfcn.h>
+#include <err.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <stab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <link.h>
+
+#include "md.h"
+#include "shlib.h"
+#include "support.h"
+#include "dynamic.h"
+
+#ifndef MAP_ANON
+#define MAP_ANON 0
+#define anon_open() do { \
+ if ((anon_fd = open("/dev/zero", O_RDWR, 0)) == -1) \
+ err("open: %s", "/dev/zero"); \
+} while (0)
+#define anon_close() do { \
+ (void)close(anon_fd); \
+ anon_fd = -1; \
+} while (0)
+#else
+#define anon_open()
+#define anon_close()
+#endif
+
+/*
+ * Structure for building a list of shared objects.
+ */
+struct so_list {
+ struct so_map *sol_map; /* Link map for shared object */
+ struct so_list *sol_next; /* Next entry in the list */
+};
+
+/*
+ * Loader private data, hung off <so_map>->som_spd
+ */
+struct somap_private {
+ int spd_version;
+ struct so_map *spd_parent;
+ struct so_list *spd_children;
+ struct so_map *spd_prev;
+ dev_t spd_dev;
+ ino_t spd_ino;
+ int spd_refcount;
+ int spd_flags;
+#define RTLD_MAIN 0x01
+#define RTLD_RTLD 0x02
+#define RTLD_DL 0x04
+#define RTLD_INIT 0x08
+ unsigned long a_text; /* text size, if known */
+ unsigned long a_data; /* initialized data size */
+ unsigned long a_bss; /* uninitialized data size */
+
+#ifdef SUN_COMPAT
+ long spd_offset; /* Correction for Sun main programs */
+#endif
+};
+
+#define LM_PRIVATE(smp) ((struct somap_private *)(smp)->som_spd)
+
+#ifdef SUN_COMPAT
+#define LM_OFFSET(smp) (LM_PRIVATE(smp)->spd_offset)
+#else
+#define LM_OFFSET(smp) (0)
+#endif
+
+/* Base address for section_dispatch_table entries */
+#define LM_LDBASE(smp) (smp->som_addr + LM_OFFSET(smp))
+
+/* Start of text segment */
+#define LM_TXTADDR(smp) (smp->som_addr == (caddr_t)0 ? PAGSIZ : 0)
+
+/* Start of run-time relocation_info */
+#define LM_REL(smp) ((struct relocation_info *) \
+ (smp->som_addr + LM_OFFSET(smp) + LD_REL((smp)->som_dynamic)))
+
+/* Start of symbols */
+#define LM_SYMBOL(smp, i) ((struct nzlist *) \
+ (smp->som_addr + LM_OFFSET(smp) + LD_SYMBOL((smp)->som_dynamic) + \
+ i * (LD_VERSION_NZLIST_P(smp->som_dynamic->d_version) ? \
+ sizeof(struct nzlist) : sizeof(struct nlist))))
+
+/* Start of hash table */
+#define LM_HASH(smp) ((struct rrs_hash *) \
+ ((smp)->som_addr + LM_OFFSET(smp) + LD_HASH((smp)->som_dynamic)))
+
+/* Start of strings */
+#define LM_STRINGS(smp) ((char *) \
+ ((smp)->som_addr + LM_OFFSET(smp) + LD_STRINGS((smp)->som_dynamic)))
+
+/* Start of search paths */
+#define LM_PATHS(smp) ((char *) \
+ ((smp)->som_addr + LM_OFFSET(smp) + LD_PATHS((smp)->som_dynamic)))
+
+/* End of text */
+#define LM_ETEXT(smp) ((char *) \
+ ((smp)->som_addr + LM_TXTADDR(smp) + LD_TEXTSZ((smp)->som_dynamic)))
+
+/* Needed shared objects */
+#define LM_NEED(smp) ((struct sod *) \
+ ((smp)->som_addr + LM_TXTADDR(smp) + LD_NEED((smp)->som_dynamic)))
+
+/* PLT is in data segment, so don't use LM_OFFSET here */
+#define LM_PLT(smp) ((jmpslot_t *) \
+ ((smp)->som_addr + LD_PLT((smp)->som_dynamic)))
+
+/* Parent of link map */
+#define LM_PARENT(smp) (LM_PRIVATE(smp)->spd_parent)
+
+#ifndef RELOC_EXTERN_P
+#define RELOC_EXTERN_P(s) ((s)->r_extern)
+#endif
+
+#ifndef RELOC_SYMBOL
+#define RELOC_SYMBOL(s) ((s)->r_symbolnum)
+#endif
+
+#ifndef RELOC_PCREL_P
+#define RELOC_PCREL_P(s) ((s)->r_pcrel)
+#endif
+
+static char __main_progname[] = "main";
+static char *main_progname = __main_progname;
+static char us[] = "/usr/libexec/ld.so";
+
+char **environ;
+char *__progname;
+int errno;
+
+static uid_t uid, euid;
+static gid_t gid, egid;
+static int careful;
+static int anon_fd = -1;
+
+static char *ld_bind_now;
+static char *ld_ignore_missing_objects;
+static char *ld_library_path;
+static char *ld_preload;
+static char *ld_tracing;
+static char *ld_suppress_warnings;
+static char *ld_warn_non_pure_code;
+
+struct so_map *link_map_head;
+struct so_map *link_map_tail;
+struct rt_symbol *rt_symbol_head;
+
+static void *__dlopen __P((char *, int));
+static int __dlclose __P((void *));
+static void *__dlsym __P((void *, char *));
+static char *__dlerror __P((void));
+static void __dlexit __P((void));
+static void *__dlsym3 __P((void *, char *, void *));
+
+static struct ld_entry ld_entry = {
+ __dlopen, __dlclose, __dlsym, __dlerror, __dlexit, __dlsym3
+};
+
+ void xprintf __P((char *, ...));
+static struct so_map *map_object __P(( char *,
+ struct sod *,
+ struct so_map *));
+static int map_preload __P((void));
+static int map_sods __P((struct so_map *));
+static int reloc_and_init __P((struct so_map *, int));
+static void unmap_object __P((struct so_map *, int));
+static struct so_map *alloc_link_map __P(( char *, struct sod *,
+ struct so_map *, caddr_t,
+ struct _dynamic *));
+static void free_link_map __P((struct so_map *));
+static inline int check_text_reloc __P(( struct relocation_info *,
+ struct so_map *,
+ caddr_t));
+static int reloc_map __P((struct so_map *, int));
+static void reloc_copy __P((struct so_map *));
+static void init_object __P((struct so_map *));
+static void init_sods __P((struct so_list *));
+static int call_map __P((struct so_map *, char *));
+static char *findhint __P((char *, int, int *));
+static char *rtfindlib __P((char *, int, int));
+static char *rtfindfile __P((char *));
+void binder_entry __P((void));
+long binder __P((jmpslot_t *));
+static struct nzlist *lookup __P((char *, struct so_map **, int));
+static inline struct rt_symbol *lookup_rts __P((char *));
+static struct rt_symbol *enter_rts __P((char *, long, int, caddr_t,
+ long, struct so_map *));
+static void die __P((void));
+static void generror __P((char *, ...));
+static int maphints __P((void));
+static void unmaphints __P((void));
+static void ld_trace __P((struct so_map *));
+static void rt_readenv __P((void));
+static int hinthash __P((char *, int));
+int rtld __P((int, struct crt_ldso *, struct _dynamic *));
+
+static inline int
+strcmp (register const char *s1, register const char *s2)
+{
+ while (*s1 == *s2++)
+ if (*s1++ == 0)
+ return (0);
+ return (*(unsigned char *)s1 - *(unsigned char *)--s2);
+}
+
+#include "md-static-funcs.c"
+
+/*
+ * Called from assembler stub that has set up crtp (passed from crt0)
+ * and dp (our __DYNAMIC).
+ */
+int
+rtld(version, crtp, dp)
+int version;
+struct crt_ldso *crtp;
+struct _dynamic *dp;
+{
+ struct relocation_info *reloc;
+ struct relocation_info *reloc_limit; /* End+1 of relocation */
+ struct so_debug *ddp;
+ struct so_map *main_map;
+ struct so_map *smp;
+ char *add_paths;
+
+ /* Check version */
+ if (version != CRT_VERSION_BSD_2 &&
+ version != CRT_VERSION_BSD_3 &&
+ version != CRT_VERSION_BSD_4 &&
+ version != CRT_VERSION_SUN)
+ return -1;
+
+ /* Fixup __DYNAMIC structure */
+ (long)dp->d_un.d_sdt += crtp->crt_ba;
+
+ /* Relocate ourselves */
+ reloc = (struct relocation_info *) (LD_REL(dp) + crtp->crt_ba);
+ reloc_limit =
+ (struct relocation_info *) ((char *) reloc + LD_RELSZ(dp));
+ while(reloc < reloc_limit) {
+ /*
+ * Objects linked with "-Bsymbolic" (in particular, ld.so
+ * itself) can end up having unused relocation entries at
+ * the end. These can be detected by the fact that they
+ * have an address of 0.
+ */
+ if(reloc->r_address == 0) /* We're done */
+ break;
+ md_relocate_simple(reloc, crtp->crt_ba,
+ reloc->r_address + crtp->crt_ba);
+ ++reloc;
+ }
+
+ if (version >= CRT_VERSION_BSD_4)
+ __progname = crtp->crt_ldso;
+ if (version >= CRT_VERSION_BSD_3)
+ main_progname = crtp->crt_prog;
+
+ /* Some buggy versions of crt0.o have crt_ldso filled in as NULL. */
+ if (__progname == NULL)
+ __progname = us;
+
+ /* Fill in some fields in _DYNAMIC or crt structure */
+ if (version >= CRT_VERSION_BSD_4)
+ crtp->crt_ldentry = &ld_entry; /* crt */
+ else
+ crtp->crt_dp->d_entry = &ld_entry; /* _DYNAMIC */
+
+ /* Setup out (private) environ variable */
+ environ = crtp->crt_ep;
+
+ /* Get user and group identifiers */
+ uid = getuid(); euid = geteuid();
+ gid = getgid(); egid = getegid();
+
+ careful = (uid != euid) || (gid != egid);
+
+ rt_readenv();
+
+ anon_open();
+
+ /* Make a link map entry for the main program */
+ main_map = alloc_link_map(main_progname,
+ (struct sod *) NULL, (struct so_map *) NULL,
+ (caddr_t) 0, crtp->crt_dp);
+ LM_PRIVATE(main_map)->spd_refcount++;
+ LM_PRIVATE(main_map)->spd_flags |= RTLD_MAIN;
+
+ /* Make a link map entry for ourselves */
+ smp = alloc_link_map(us,
+ (struct sod *) NULL, (struct so_map *) NULL,
+ (caddr_t) crtp->crt_ba, dp);
+ LM_PRIVATE(smp)->spd_refcount++;
+ LM_PRIVATE(smp)->spd_flags |= RTLD_RTLD;
+
+ /*
+ * Setup the executable's run path
+ */
+ if (version >= CRT_VERSION_BSD_4) {
+ add_paths = LM_PATHS(main_map);
+ if (add_paths)
+ add_search_path(add_paths);
+ }
+
+ /*
+ * Setup the directory search list for findshlib. We use only
+ * the standard search path. Any extra directories from
+ * LD_LIBRARY_PATH are searched explicitly, in rtfindlib.
+ */
+ std_search_path();
+
+ /* Map in LD_PRELOADs before the main program's shared objects so we
+ can intercept those calls */
+ if (ld_preload != NULL) {
+ if(map_preload() == -1) /* Failed */
+ die();
+ }
+
+ /* Map all the shared objects that the main program depends upon */
+ if(map_sods(main_map) == -1)
+ die();
+
+ if(ld_tracing) { /* We're done */
+ ld_trace(link_map_head);
+ exit(0);
+ }
+
+ crtp->crt_dp->d_un.d_sdt->sdt_loaded = link_map_head->som_next;
+
+ /* Relocate and initialize all mapped objects */
+ if(reloc_and_init(main_map, ld_bind_now != NULL) == -1) /* Failed */
+ die();
+
+ ddp = crtp->crt_dp->d_debug;
+ ddp->dd_cc = rt_symbol_head;
+ if (ddp->dd_in_debugger) {
+ caddr_t addr = (caddr_t)((long)crtp->crt_bp & (~(PAGSIZ - 1)));
+
+ /* Set breakpoint for the benefit of debuggers */
+ if (mprotect(addr, PAGSIZ,
+ PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
+ err(1, "Cannot set breakpoint (%s)", main_progname);
+ }
+ md_set_breakpoint((long)crtp->crt_bp, (long *)&ddp->dd_bpt_shadow);
+ if (mprotect(addr, PAGSIZ, PROT_READ|PROT_EXEC) == -1) {
+ err(1, "Cannot re-protect breakpoint (%s)",
+ main_progname);
+ }
+
+ ddp->dd_bpt_addr = crtp->crt_bp;
+ if (link_map_head)
+ ddp->dd_sym_loaded = 1;
+ }
+
+ /* Close the hints file */
+ unmaphints();
+
+ /* Close our file descriptor */
+ (void)close(crtp->crt_ldfd);
+ anon_close();
+
+ return LDSO_VERSION_HAS_DLSYM3;
+}
+
+void
+ld_trace(smp)
+ struct so_map *smp;
+{
+ char *fmt1, *fmt2, *fmt, *main_local;
+ int c;
+
+ if ((main_local = getenv("LD_TRACE_LOADED_OBJECTS_PROGNAME")) == NULL)
+ main_local = "";
+
+ if ((fmt1 = getenv("LD_TRACE_LOADED_OBJECTS_FMT1")) == NULL)
+ fmt1 = "\t-l%o.%m => %p (%x)\n";
+
+ if ((fmt2 = getenv("LD_TRACE_LOADED_OBJECTS_FMT2")) == NULL)
+ fmt2 = "\t%o (%x)\n";
+
+ for (; smp; smp = smp->som_next) {
+ struct sod *sodp;
+ char *name, *path;
+
+ if ((sodp = smp->som_sod) == NULL)
+ continue;
+
+ name = (char *)sodp->sod_name;
+ if (LM_PARENT(smp))
+ name += (long)LM_LDBASE(LM_PARENT(smp));
+
+ if ((path = smp->som_path) == NULL)
+ path = "not found";
+
+ fmt = sodp->sod_library ? fmt1 : fmt2;
+ while ((c = *fmt++) != '\0') {
+ switch (c) {
+ default:
+ putchar(c);
+ continue;
+ case '\\':
+ switch (c = *fmt) {
+ case '\0':
+ continue;
+ case 'n':
+ putchar('\n');
+ break;
+ case 't':
+ putchar('\t');
+ break;
+ }
+ break;
+ case '%':
+ switch (c = *fmt) {
+ case '\0':
+ continue;
+ case '%':
+ default:
+ putchar(c);
+ break;
+ case 'A':
+ printf("%s", main_local);
+ break;
+ case 'a':
+ printf("%s", main_progname);
+ break;
+ case 'o':
+ printf("%s", name);
+ break;
+ case 'm':
+ printf("%d", sodp->sod_major);
+ break;
+ case 'n':
+ printf("%d", sodp->sod_minor);
+ break;
+ case 'p':
+ printf("%s", path);
+ break;
+ case 'x':
+ printf("%p", smp->som_addr);
+ break;
+ }
+ break;
+ }
+ ++fmt;
+ }
+ }
+}
+
+/*
+ * Allocate a new link map and return a pointer to it.
+ *
+ * PATH is the pathname of the shared object.
+ *
+ * SODP is a pointer to the shared object dependency structure responsible
+ * for causing the new object to be loaded. PARENT is the shared object
+ * into which SODP points. Both can be NULL if the new object is not
+ * being loaded as a result of a shared object dependency.
+ *
+ * ADDR is the address at which the object has been mapped. DP is a pointer
+ * to its _dynamic structure.
+ */
+ static struct so_map *
+alloc_link_map(path, sodp, parent, addr, dp)
+ char *path;
+ struct sod *sodp;
+ struct so_map *parent;
+ caddr_t addr;
+ struct _dynamic *dp;
+{
+ struct so_map *smp;
+ struct somap_private *smpp;
+ size_t smp_size;
+
+#ifdef DEBUG /* { */
+ xprintf("alloc_link_map: \"%s\" at %p\n", path, addr);
+#endif /* } */
+
+ /*
+ * Allocate so_map and private area with a single malloc. Round
+ * up the size of so_map so the private area is aligned.
+ */
+ smp_size = ((((sizeof(struct so_map)) + sizeof (void *) - 1) /
+ sizeof (void *)) * sizeof (void *));
+
+ smp = (struct so_map *)xmalloc(smp_size +
+ sizeof (struct somap_private));
+ smpp = (struct somap_private *) (((caddr_t) smp) + smp_size);
+
+ /* Link the new entry into the list of link maps */
+ smp->som_next = NULL;
+ smpp->spd_prev = link_map_tail;
+ if(link_map_tail == NULL) /* First link map entered into list */
+ link_map_head = link_map_tail = smp;
+ else { /* Append to end of list */
+ link_map_tail->som_next = smp;
+ link_map_tail = smp;
+ }
+
+ smp->som_addr = addr;
+ smp->som_path = path ? strdup(path) : NULL;
+ smp->som_sod = sodp;
+ smp->som_dynamic = dp;
+ smp->som_spd = (caddr_t)smpp;
+
+ smpp->spd_refcount = 0;
+ smpp->spd_flags = 0;
+ smpp->spd_parent = parent;
+ smpp->spd_children = NULL;
+ smpp->a_text = 0;
+ smpp->a_data = 0;
+ smpp->a_bss = 0;
+#ifdef SUN_COMPAT
+ smpp->spd_offset =
+ (addr==0 && dp && dp->d_version==LD_VERSION_SUN) ? PAGSIZ : 0;
+#endif
+ return smp;
+}
+
+/*
+ * Remove the specified link map entry from the list of link maps, and free
+ * the associated storage.
+ */
+ static void
+free_link_map(smp)
+ struct so_map *smp;
+{
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+#ifdef DEBUG /* { */
+ xprintf("free_link_map: \"%s\"\n", smp->som_path);
+#endif /* } */
+
+ if(smpp->spd_prev == NULL) /* Removing first entry in list */
+ link_map_head = smp->som_next;
+ else /* Update link of previous entry */
+ smpp->spd_prev->som_next = smp->som_next;
+
+ if(smp->som_next == NULL) /* Removing last entry in list */
+ link_map_tail = smpp->spd_prev;
+ else /* Update back link of next entry */
+ LM_PRIVATE(smp->som_next)->spd_prev = smpp->spd_prev;
+
+ free(smp->som_path);
+ free(smp);
+}
+
+/*
+ * Map the shared object specified by PATH into memory, if it is not
+ * already mapped. Increment the object's reference count, and return a
+ * pointer to its link map.
+ *
+ * As a special case, if PATH is NULL, it is taken to refer to the main
+ * program.
+ *
+ * SODP is a pointer to the shared object dependency structure that caused
+ * this object to be requested. PARENT is a pointer to the link map of
+ * the shared object containing that structure. For a shared object not
+ * being mapped as a result of a shared object dependency, these pointers
+ * should be NULL. An example of this is a shared object that is explicitly
+ * loaded via dlopen().
+ *
+ * The return value is a pointer to the link map for the requested object.
+ * If the operation failed, the return value is NULL. In that case, an
+ * error message can be retrieved by calling dlerror().
+ */
+ static struct so_map *
+map_object(path, sodp, parent)
+ char *path;
+ struct sod *sodp;
+ struct so_map *parent;
+{
+ struct so_map *smp;
+ struct stat statbuf;
+
+ if(path == NULL) /* Special case for the main program itself */
+ smp = link_map_head;
+ else {
+ /*
+ * Check whether the shared object is already mapped.
+ * We check first for an exact match by pathname. That
+ * will detect the usual case. If no match is found by
+ * pathname, then stat the file, and check for a match by
+ * device and inode. That will detect the less common case
+ * involving multiple links to the same library.
+ */
+ for(smp = link_map_head; smp != NULL; smp = smp->som_next) {
+ if(!(LM_PRIVATE(smp)->spd_flags & (RTLD_MAIN|RTLD_RTLD))
+ && smp->som_path != NULL
+ && strcmp(smp->som_path, path) == 0)
+ break;
+ }
+ if(smp == NULL) { /* Check for a match by device and inode */
+ if (stat(path, &statbuf) == -1) {
+ generror ("cannot stat \"%s\" : %s",
+ path, strerror(errno));
+ return NULL;
+ }
+ for (smp = link_map_head; smp != NULL;
+ smp = smp->som_next) {
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+ if (!(smpp->spd_flags & (RTLD_MAIN | RTLD_RTLD))
+ && smpp->spd_ino == statbuf.st_ino
+ && smpp->spd_dev == statbuf.st_dev)
+ break;
+ }
+ }
+ }
+
+ if (smp == NULL) { /* We must map the object */
+ struct _dynamic *dp;
+ int fd;
+ caddr_t addr;
+ struct exec hdr;
+ struct somap_private *smpp;
+
+ if ((fd = open(path, O_RDONLY, 0)) == -1) {
+ generror ("open failed for \"%s\" : %s",
+ path, strerror (errno));
+ return NULL;
+ }
+
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ generror ("header read failed for \"%s\"", path);
+ (void)close(fd);
+ return NULL;
+ }
+
+ if (N_BADMAG(hdr)) {
+ generror ("bad magic number in \"%s\"", path);
+ (void)close(fd);
+ return NULL;
+ }
+
+ /*
+ * Map the entire address space of the object. It is
+ * tempting to map just the text segment at first, in
+ * order to avoid having to use mprotect to change the
+ * protections of the data segment. But that would not
+ * be correct. Mmap might find a group of free pages
+ * large enough to hold the text segment, but not large
+ * enough for the entire object. When we then mapped
+ * in the data and BSS segments, they would either be
+ * non-contiguous with the text segment (if we didn't
+ * specify MAP_FIXED), or they would map over some
+ * previously mapped region (if we did use MAP_FIXED).
+ * The only way we can be sure of getting a contigous
+ * region that is large enough is to map the entire
+ * region at once.
+ */
+ if ((addr = mmap(0, hdr.a_text + hdr.a_data + hdr.a_bss,
+ PROT_READ|PROT_EXEC,
+ MAP_COPY, fd, 0)) == (caddr_t)-1) {
+ generror ("mmap failed for \"%s\" : %s",
+ path, strerror (errno));
+ (void)close(fd);
+ return NULL;
+ }
+
+ (void)close(fd);
+
+ /* Change the data segment to writable */
+ if (mprotect(addr + hdr.a_text, hdr.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
+ generror ("mprotect failed for \"%s\" : %s",
+ path, strerror (errno));
+ (void)munmap(addr, hdr.a_text + hdr.a_data + hdr.a_bss);
+ return NULL;
+ }
+
+ /* Map in pages of zeros for the BSS segment */
+ if (mmap(addr + hdr.a_text + hdr.a_data, hdr.a_bss,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_ANON|MAP_COPY|MAP_FIXED,
+ anon_fd, 0) == (caddr_t)-1) {
+ generror ("mmap failed for \"%s\" : %s",
+ path, strerror (errno));
+ (void)munmap(addr, hdr.a_text + hdr.a_data + hdr.a_bss);
+ return NULL;
+ }
+
+ /* Assume _DYNAMIC is the first data item */
+ dp = (struct _dynamic *)(addr+hdr.a_text);
+
+ /* Fixup __DYNAMIC structure */
+ (long)dp->d_un.d_sdt += (long)addr;
+
+ smp = alloc_link_map(path, sodp, parent, addr, dp);
+
+ /* save segment sizes for unmap. */
+ smpp = LM_PRIVATE(smp);
+ smpp->a_text = hdr.a_text;
+ smpp->a_data = hdr.a_data;
+ smpp->a_bss = hdr.a_bss;
+
+ /*
+ * Save the device and inode, so we can detect multiple links
+ * to the same library. Note, if we reach this point, then
+ * statbuf is guaranteed to have been filled in.
+ */
+ smpp->spd_dev = statbuf.st_dev;
+ smpp->spd_ino = statbuf.st_ino;
+ }
+
+ LM_PRIVATE(smp)->spd_refcount++;
+ if(LM_PRIVATE(smp)->spd_refcount == 1) { /* First use of object */
+ /*
+ * Recursively map all of the shared objects that this
+ * one depends upon.
+ */
+ if(map_sods(smp) == -1) { /* Failed */
+ unmap_object(smp, 0); /* Clean up */
+ return NULL;
+ }
+ }
+
+ return smp;
+}
+
+/*
+ * Map all the shared libraries named in the LD_PRELOAD environment
+ * variable.
+ *
+ * Returns 0 on success, -1 on failure. On failure, an error message can
+ * be gotten via dlerror().
+ */
+ static int
+map_preload __P((void)) {
+ char *ld_name = ld_preload;
+ char *name;
+
+ while ((name = strsep(&ld_name, ":")) != NULL) {
+ char *path = NULL;
+ struct so_map *smp = NULL;
+
+ if (*name != '\0') {
+ path = (strchr(name, '/') != NULL) ? strdup(name) :
+ rtfindfile(name);
+ }
+ if (path == NULL) {
+ generror("Can't find LD_PRELOAD shared"
+ " library \"%s\"", name);
+ } else {
+ smp = map_object(path, (struct sod *) NULL,
+ (struct so_map *) NULL);
+ free(path);
+ }
+ if (ld_name != NULL)
+ *(ld_name - 1) = ':';
+ if (smp == NULL) {
+ /*
+ * We don't bother to unmap already-loaded libraries
+ * on failure, because in that case the program is
+ * about to die anyway.
+ */
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Map all of the shared objects that a given object depends upon. PARENT is
+ * a pointer to the link map for the shared object whose dependencies are
+ * to be mapped.
+ *
+ * Returns 0 on success. Returns -1 on failure. In that case, an error
+ * message can be retrieved by calling dlerror().
+ */
+ static int
+map_sods(parent)
+ struct so_map *parent;
+{
+ struct somap_private *parpp = LM_PRIVATE(parent);
+ struct so_list **soltail = &parpp->spd_children;
+ long next = LD_NEED(parent->som_dynamic);
+
+ while(next != 0) {
+ struct sod *sodp =
+ (struct sod *) (LM_LDBASE(parent) + next);
+ char *name =
+ (char *) (LM_LDBASE(parent) + sodp->sod_name);
+ char *path = NULL;
+ struct so_map *smp = NULL;
+
+ if(sodp->sod_library) {
+ path = rtfindlib(name, sodp->sod_major,
+ sodp->sod_minor);
+ if(path == NULL && !ld_tracing) {
+ generror ("Can't find shared library"
+ " \"lib%s.so.%d.%d\"", name,
+ sodp->sod_major, sodp->sod_minor);
+ }
+ } else {
+ if(careful && name[0] != '/') {
+ generror("Shared library path must start"
+ " with \"/\" for \"%s\"", name);
+ } else
+ path = strdup(name);
+ }
+
+ if(path != NULL) {
+ smp = map_object(path, sodp, parent);
+ free(path);
+ }
+
+ if(smp != NULL) {
+ struct so_list *solp = (struct so_list *)
+ xmalloc(sizeof(struct so_list));
+ solp->sol_map = smp;
+ solp->sol_next = NULL;
+ *soltail = solp;
+ soltail = &solp->sol_next;
+ } else if(ld_tracing) {
+ /*
+ * Allocate a dummy map entry so that we will get the
+ * "not found" message.
+ */
+ (void)alloc_link_map(NULL, sodp, parent, 0, 0);
+ } else if (ld_ignore_missing_objects) {
+ char *msg;
+ /*
+ * Call __dlerror() even it we're not going to use
+ * the message, in order to clear the saved message.
+ */
+ msg = __dlerror(); /* Should never be NULL */
+ if (!ld_suppress_warnings)
+ warnx("warning: %s", msg);
+ } else /* Give up */
+ break;
+
+ next = sodp->sod_next;
+ }
+
+ if(next != 0) {
+ /*
+ * Oh drat, we have to clean up a mess.
+ *
+ * We failed to load a shared object that we depend upon.
+ * So now we have to unload any dependencies that we had
+ * already successfully loaded prior to the error.
+ *
+ * Cleaning up doesn't matter so much for the initial
+ * loading of the program, since any failure is going to
+ * terminate the program anyway. But it is very important
+ * to clean up properly when something is being loaded
+ * via dlopen().
+ */
+ struct so_list *solp;
+
+ while((solp = parpp->spd_children) != NULL) {
+ unmap_object(solp->sol_map, 0);
+ parpp->spd_children = solp->sol_next;
+ free(solp);
+ }
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Relocate and initialize the tree of shared objects rooted at the given
+ * link map entry. Returns 0 on success, or -1 on failure. On failure,
+ * an error message can be retrieved via dlerror().
+ */
+ static int
+reloc_and_init(root, bind_now)
+ struct so_map *root;
+ int bind_now;
+{
+ struct so_map *smp;
+
+ /*
+ * Relocate all newly-loaded objects. We avoid recursion for this
+ * step by taking advantage of a few facts. This function is called
+ * only when there are in fact some newly-loaded objects to process.
+ * Furthermore, all newly-loaded objects will have their link map
+ * entries at the end of the link map list. And, the root of the
+ * tree of objects just loaded will have been the first to be loaded
+ * and therefore the first new object in the link map list. Finally,
+ * we take advantage of the fact that we can relocate the newly-loaded
+ * objects in any order.
+ *
+ * All these facts conspire to let us simply loop over the tail
+ * portion of the link map list, relocating each object so
+ * encountered.
+ */
+ for(smp = root; smp != NULL; smp = smp->som_next) {
+ if(!(LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)) {
+ if(reloc_map(smp, bind_now) < 0)
+ return -1;
+ }
+ }
+
+ /*
+ * Copy any relocated initialized data. Again, we can just loop
+ * over the appropriate portion of the link map list.
+ */
+ for(smp = root; smp != NULL; smp = smp->som_next) {
+ if(!(LM_PRIVATE(smp)->spd_flags & RTLD_RTLD))
+ reloc_copy(smp);
+ }
+
+ /*
+ * Call any object initialization routines.
+ *
+ * Here, the order is very important, and we cannot simply loop
+ * over the newly-loaded objects as we did before. Rather, we
+ * have to initialize the tree of new objects depth-first, and
+ * process the sibling objects at each level in reverse order
+ * relative to the dependency list.
+ *
+ * Here is the reason we initialize depth-first. If an object
+ * depends on one or more other objects, then the objects it
+ * depends on should be initialized first, before the parent
+ * object itself. For it is possible that the parent's
+ * initialization routine will need the services provided by the
+ * objects it depends on -- and those objects had better already
+ * be initialized.
+ *
+ * We initialize the objects at each level of the tree in reverse
+ * order for a similar reason. When an object is linked with
+ * several libraries, it is common for routines in the earlier
+ * libraries to call routines in the later libraries. So, again,
+ * the later libraries need to be initialized first.
+ *
+ * The upshot of these rules is that we have to use recursion to
+ * get the libraries initialized in the best order. But the
+ * recursion is never likely to be very deep.
+ */
+ init_object(root);
+
+ return 0;
+}
+
+/*
+ * Remove a reference to the shared object specified by SMP. If no
+ * references remain, unmap the object and, recursively, its descendents.
+ * This function also takes care of calling the finalization routines for
+ * objects that are removed.
+ *
+ * If KEEP is true, then the actual calls to munmap() are skipped,
+ * and the object is kept in memory. That is used only for finalization,
+ * from dlexit(), when the program is exiting. There are two reasons
+ * for it. First, the program is exiting and there is no point in
+ * spending the time to explicitly unmap its shared objects. Second,
+ * even after dlexit() has been called, there are still a couple of
+ * calls that are made to functions in libc. (This is really a bug
+ * in crt0.) So libc and the main program, at least, must remain
+ * mapped in that situation.
+ *
+ * Under no reasonable circumstances should this function fail. If
+ * anything goes wrong, we consider it an internal error, and report
+ * it with err().
+ */
+ static void
+unmap_object(smp, keep)
+ struct so_map *smp;
+ int keep;
+{
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+ smpp->spd_refcount--;
+ if(smpp->spd_refcount == 0) { /* Finished with this object */
+ struct so_list *solp;
+
+ if(smpp->spd_flags & RTLD_INIT) { /* Was initialized */
+ /*
+ * Call the object's finalization routine. For
+ * backward compatibility, we first try to call
+ * ".fini". If that does not exist, we call
+ * "__fini".
+ */
+ if(call_map(smp, ".fini") == -1)
+ call_map(smp, "__fini");
+ }
+
+ /* Recursively unreference the object's descendents */
+ while((solp = smpp->spd_children) != NULL) {
+ unmap_object(solp->sol_map, keep);
+ smpp->spd_children = solp->sol_next;
+ free(solp);
+ }
+
+ if(!keep) { /* Unmap the object from memory */
+ if(munmap(smp->som_addr,
+ smpp->a_text + smpp->a_data + smpp->a_bss) < 0)
+ err(1, "internal error 1: munmap failed");
+
+ /* Unlink and free the object's link map entry */
+ free_link_map(smp);
+ }
+ }
+}
+
+static inline int
+check_text_reloc(r, smp, addr)
+struct relocation_info *r;
+struct so_map *smp;
+caddr_t addr;
+{
+ char *sym;
+
+ if (addr >= LM_ETEXT(smp))
+ return 0;
+
+ if (RELOC_EXTERN_P(r))
+ sym = LM_STRINGS(smp) +
+ LM_SYMBOL(smp, RELOC_SYMBOL(r))->nz_strx;
+ else
+ sym = "";
+
+ if (!ld_suppress_warnings && ld_warn_non_pure_code)
+ warnx("warning: non pure code in %s at %x (%s)",
+ smp->som_path, r->r_address, sym);
+
+ if (smp->som_write == 0 &&
+ mprotect(smp->som_addr + LM_TXTADDR(smp),
+ LD_TEXTSZ(smp->som_dynamic),
+ PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
+ generror ("mprotect failed for \"%s\" : %s",
+ smp->som_path, strerror (errno));
+ return -1;
+ }
+
+ smp->som_write = 1;
+ return 0;
+}
+
+static int
+reloc_map(smp, bind_now)
+ struct so_map *smp;
+ int bind_now;
+{
+ /*
+ * Caching structure for reducing the number of calls to
+ * lookup() during relocation.
+ *
+ * While relocating a given shared object, the dynamic linker
+ * maintains a caching vector that is directly indexed by
+ * the symbol number in the relocation entry. The first time
+ * a given symbol is looked up, the caching vector is
+ * filled in with a pointer to the symbol table entry, and
+ * a pointer to the so_map of the shared object in which the
+ * symbol was defined. On subsequent uses of the same symbol,
+ * that information is retrieved directly from the caching
+ * vector, without calling lookup() again.
+ *
+ * A symbol that is referenced in a relocation entry is
+ * typically referenced in many relocation entries, so this
+ * caching reduces the number of calls to lookup()
+ * dramatically. The overall improvement in the speed of
+ * dynamic linking is also dramatic -- as much as a factor
+ * of three for programs that use many shared libaries.
+ */
+ struct cacheent {
+ struct nzlist *np; /* Pointer to symbol entry */
+ struct so_map *src_map; /* Shared object that defined symbol */
+ };
+
+ struct _dynamic *dp = smp->som_dynamic;
+ struct relocation_info *r = LM_REL(smp);
+ struct relocation_info *rend = r + LD_RELSZ(dp)/sizeof(*r);
+ long symbolbase = (long)LM_SYMBOL(smp, 0);
+ char *stringbase = LM_STRINGS(smp);
+ int symsize = LD_VERSION_NZLIST_P(dp->d_version) ?
+ sizeof(struct nzlist) :
+ sizeof(struct nlist);
+ long numsyms = LD_STABSZ(dp) / symsize;
+ size_t cachebytes = numsyms * sizeof(struct cacheent);
+ struct cacheent *symcache =
+ (struct cacheent *) alloca(cachebytes);
+
+ if(symcache == NULL) {
+ generror("Cannot allocate symbol caching vector for %s",
+ smp->som_path);
+ return -1;
+ }
+ bzero(symcache, cachebytes);
+
+ if (LD_PLTSZ(dp))
+ md_fix_jmpslot(LM_PLT(smp),
+ (long)LM_PLT(smp), (long)binder_entry);
+
+ for (; r < rend; r++) {
+ char *sym;
+ caddr_t addr;
+
+ /*
+ * Objects linked with "-Bsymbolic" can end up having unused
+ * relocation entries at the end. These can be detected by
+ * the fact that they have an address of 0.
+ */
+ if(r->r_address == 0) /* Finished relocating this object */
+ break;
+
+ addr = smp->som_addr + r->r_address;
+ if (check_text_reloc(r, smp, addr) < 0)
+ return -1;
+
+ if (RELOC_EXTERN_P(r)) {
+ struct so_map *src_map = NULL;
+ struct nzlist *p, *np;
+ long relocation;
+
+ if (RELOC_JMPTAB_P(r) && !bind_now)
+ continue;
+
+ p = (struct nzlist *)
+ (symbolbase + symsize * RELOC_SYMBOL(r));
+
+ if (p->nz_type == (N_SETV + N_EXT))
+ src_map = smp;
+
+ sym = stringbase + p->nz_strx;
+
+ /*
+ * Look up the symbol, checking the caching
+ * vector first.
+ */
+ np = symcache[RELOC_SYMBOL(r)].np;
+ if(np != NULL) /* Symbol already cached */
+ src_map = symcache[RELOC_SYMBOL(r)].src_map;
+ else { /* Symbol not cached yet */
+ np = lookup(sym, &src_map, RELOC_JMPTAB_P(r));
+ /*
+ * Record the needed information about
+ * the symbol in the caching vector,
+ * so that we won't have to call
+ * lookup the next time we encounter
+ * the symbol.
+ */
+ symcache[RELOC_SYMBOL(r)].np = np;
+ symcache[RELOC_SYMBOL(r)].src_map = src_map;
+ }
+
+ if (np == NULL) {
+ generror ("Undefined symbol \"%s\" in %s:%s",
+ sym, main_progname, smp->som_path);
+ return -1;
+ }
+
+ /*
+ * Found symbol definition.
+ * If it's in a link map, adjust value
+ * according to the load address of that map.
+ * Otherwise it's a run-time allocated common
+ * whose value is already up-to-date.
+ */
+ relocation = np->nz_value;
+ if (src_map)
+ relocation += (long)src_map->som_addr;
+
+ if (RELOC_JMPTAB_P(r)) {
+ md_bind_jmpslot(relocation, addr);
+ continue;
+ }
+
+ relocation += md_get_addend(r, addr);
+
+ if (RELOC_PCREL_P(r))
+ relocation -= (long)smp->som_addr;
+
+ if (RELOC_COPY_P(r) && src_map) {
+ (void)enter_rts(sym,
+ (long)addr,
+ N_DATA + N_EXT,
+ src_map->som_addr + np->nz_value,
+ np->nz_size, src_map);
+ continue;
+ }
+
+ md_relocate(r, relocation, addr, 0);
+ } else {
+ md_relocate(r,
+#ifdef SUN_COMPAT
+ md_get_rt_segment_addend(r, addr)
+#else
+ md_get_addend(r, addr)
+#endif
+ + (long)smp->som_addr, addr, 0);
+ }
+
+ }
+
+ if (smp->som_write) {
+ if (mprotect(smp->som_addr + LM_TXTADDR(smp),
+ LD_TEXTSZ(smp->som_dynamic),
+ PROT_READ|PROT_EXEC) == -1) {
+ generror ("mprotect failed for \"%s\" : %s",
+ smp->som_path, strerror (errno));
+ return -1;
+ }
+ smp->som_write = 0;
+ }
+ return 0;
+}
+
+ static void
+reloc_copy(smp)
+ struct so_map *smp;
+{
+ struct rt_symbol *rtsp;
+
+ for (rtsp = rt_symbol_head; rtsp; rtsp = rtsp->rt_next)
+ if ((rtsp->rt_smp == NULL || rtsp->rt_smp == smp) &&
+ rtsp->rt_sp->nz_type == N_DATA + N_EXT) {
+ bcopy(rtsp->rt_srcaddr, (caddr_t)rtsp->rt_sp->nz_value,
+ rtsp->rt_sp->nz_size);
+ }
+}
+
+ static void
+init_object(smp)
+ struct so_map *smp;
+{
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+ if(!(smpp->spd_flags & RTLD_INIT)) { /* Not initialized yet */
+ smpp->spd_flags |= RTLD_INIT;
+
+ /* Make sure all the children are initialized */
+ if(smpp->spd_children != NULL)
+ init_sods(smpp->spd_children);
+
+ if(call_map(smp, ".init") == -1)
+ call_map(smp, "__init");
+ }
+}
+
+ static void
+init_sods(solp)
+ struct so_list *solp;
+{
+ /* Recursively initialize the rest of the list */
+ if(solp->sol_next != NULL)
+ init_sods(solp->sol_next);
+
+ /* Initialize the first element of the list */
+ init_object(solp->sol_map);
+}
+
+
+/*
+ * Call a function in a given shared object. SMP is the shared object, and
+ * SYM is the name of the function.
+ *
+ * Returns 0 on success, or -1 if the symbol was not found. Failure is not
+ * necessarily an error condition, so no error message is generated.
+ */
+ static int
+call_map(smp, sym)
+ struct so_map *smp;
+ char *sym;
+{
+ struct so_map *src_map = smp;
+ struct nzlist *np;
+
+ np = lookup(sym, &src_map, 1);
+ if (np) {
+ (*(void (*)())(src_map->som_addr + np->nz_value))();
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Run-time common symbol table.
+ */
+
+#define RTC_TABSIZE 57
+static struct rt_symbol *rt_symtab[RTC_TABSIZE];
+
+/*
+ * Compute hash value for run-time symbol table
+ */
+ static inline int
+hash_string(key)
+ char *key;
+{
+ register char *cp;
+ register int k;
+
+ cp = key;
+ k = 0;
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ return k;
+}
+
+/*
+ * Lookup KEY in the run-time common symbol table.
+ */
+
+ static inline struct rt_symbol *
+lookup_rts(key)
+ char *key;
+{
+ register int hashval;
+ register struct rt_symbol *rtsp;
+
+ /* Determine which bucket. */
+
+ hashval = hash_string(key) % RTC_TABSIZE;
+
+ /* Search the bucket. */
+
+ for (rtsp = rt_symtab[hashval]; rtsp; rtsp = rtsp->rt_link)
+ if (strcmp(key, rtsp->rt_sp->nz_name) == 0)
+ return rtsp;
+
+ return NULL;
+}
+
+ static struct rt_symbol *
+enter_rts(name, value, type, srcaddr, size, smp)
+ char *name;
+ long value;
+ int type;
+ caddr_t srcaddr;
+ long size;
+ struct so_map *smp;
+{
+ register int hashval;
+ register struct rt_symbol *rtsp, **rpp;
+
+ /* Determine which bucket */
+ hashval = hash_string(name) % RTC_TABSIZE;
+
+ /* Find end of bucket */
+ for (rpp = &rt_symtab[hashval]; *rpp; rpp = &(*rpp)->rt_link)
+ continue;
+
+ /* Allocate new common symbol */
+ rtsp = (struct rt_symbol *)malloc(sizeof(struct rt_symbol));
+ rtsp->rt_sp = (struct nzlist *)malloc(sizeof(struct nzlist));
+ rtsp->rt_sp->nz_name = strdup(name);
+ rtsp->rt_sp->nz_value = value;
+ rtsp->rt_sp->nz_type = type;
+ rtsp->rt_sp->nz_size = size;
+ rtsp->rt_srcaddr = srcaddr;
+ rtsp->rt_smp = smp;
+ rtsp->rt_link = NULL;
+
+ /* Link onto linear list as well */
+ rtsp->rt_next = rt_symbol_head;
+ rt_symbol_head = rtsp;
+
+ *rpp = rtsp;
+
+ return rtsp;
+}
+
+
+/*
+ * Lookup NAME in the link maps. The link map producing a definition
+ * is returned in SRC_MAP. If SRC_MAP is not NULL on entry the search is
+ * confined to that map. If STRONG is set, the symbol returned must
+ * have a proper type (used by binder()).
+ */
+ static struct nzlist *
+lookup(name, src_map, strong)
+ char *name;
+ struct so_map **src_map; /* IN/OUT */
+ int strong;
+{
+ long common_size = 0;
+ struct so_map *smp;
+ struct rt_symbol *rtsp;
+
+ if ((rtsp = lookup_rts(name)) != NULL)
+ return rtsp->rt_sp;
+
+ /*
+ * Search all maps for a definition of NAME
+ */
+ for (smp = link_map_head; smp; smp = smp->som_next) {
+ int buckets;
+ long hashval;
+ struct rrs_hash *hp;
+ char *cp;
+ struct nzlist *np;
+
+ /* Some local caching */
+ long symbolbase;
+ struct rrs_hash *hashbase;
+ char *stringbase;
+ int symsize;
+
+ if (*src_map && smp != *src_map)
+ continue;
+
+ if ((buckets = LD_BUCKETS(smp->som_dynamic)) == 0)
+ continue;
+
+ if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ continue;
+
+restart:
+ /*
+ * Compute bucket in which the symbol might be found.
+ */
+ for (hashval = 0, cp = name; *cp; cp++)
+ hashval = (hashval << 1) + *cp;
+
+ hashval = (hashval & 0x7fffffff) % buckets;
+
+ hashbase = LM_HASH(smp);
+ hp = hashbase + hashval;
+ if (hp->rh_symbolnum == -1)
+ /* Nothing in this bucket */
+ continue;
+
+ symbolbase = (long)LM_SYMBOL(smp, 0);
+ stringbase = LM_STRINGS(smp);
+ symsize = LD_VERSION_NZLIST_P(smp->som_dynamic->d_version)?
+ sizeof(struct nzlist) :
+ sizeof(struct nlist);
+ while (hp) {
+ np = (struct nzlist *)
+ (symbolbase + hp->rh_symbolnum * symsize);
+ cp = stringbase + np->nz_strx;
+ if (strcmp(cp, name) == 0)
+ break;
+ if (hp->rh_next == 0)
+ hp = NULL;
+ else
+ hp = hashbase + hp->rh_next;
+ }
+ if (hp == NULL)
+ /* Nothing in this bucket */
+ continue;
+
+ /*
+ * We have a symbol with the name we're looking for.
+ */
+ if (np->nz_type == N_INDR+N_EXT) {
+ /*
+ * Next symbol gives the aliased name. Restart
+ * search with new name and confine to this map.
+ */
+ name = stringbase + (++np)->nz_strx;
+ *src_map = smp;
+ goto restart;
+ }
+
+ if (np->nz_value == 0)
+ /* It's not a definition */
+ continue;
+
+ if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
+ if (np->nz_other == AUX_FUNC) {
+ /* It's a weak function definition */
+ if (strong)
+ continue;
+ } else {
+ /* It's a common, note value and continue search */
+ if (common_size < np->nz_value)
+ common_size = np->nz_value;
+ continue;
+ }
+ }
+
+ *src_map = smp;
+ return np;
+ }
+
+ if (common_size == 0)
+ /* Not found */
+ return NULL;
+
+ /*
+ * It's a common, enter into run-time common symbol table.
+ */
+ rtsp = enter_rts(name, (long)calloc(1, common_size),
+ N_UNDF + N_EXT, 0, common_size, NULL);
+
+#if DEBUG
+ xprintf("Allocating common: %s size %d at %#x\n", name, common_size,
+ rtsp->rt_sp->nz_value);
+#endif
+
+ return rtsp->rt_sp;
+}
+
+/*
+ * This routine is called from the jumptable to resolve
+ * procedure calls to shared objects.
+ */
+ long
+binder(jsp)
+ jmpslot_t *jsp;
+{
+ struct so_map *smp, *src_map = NULL;
+ long addr;
+ char *sym;
+ struct nzlist *np;
+ int index;
+
+ /*
+ * Find the PLT map that contains JSP.
+ */
+ for (smp = link_map_head; smp; smp = smp->som_next) {
+ if (LM_PLT(smp) < jsp &&
+ jsp < LM_PLT(smp) + LD_PLTSZ(smp->som_dynamic)/sizeof(*jsp))
+ break;
+ }
+
+ if (smp == NULL)
+ errx(1, "Call to binder from unknown location: %#x\n", jsp);
+
+ index = jsp->reloc_index & JMPSLOT_RELOC_MASK;
+
+ /* Get the local symbol this jmpslot refers to */
+ sym = LM_STRINGS(smp) +
+ LM_SYMBOL(smp,RELOC_SYMBOL(&LM_REL(smp)[index]))->nz_strx;
+
+ np = lookup(sym, &src_map, 1);
+ if (np == NULL)
+ errx(1, "Undefined symbol \"%s\" called from %s:%s at %#x",
+ sym, main_progname, smp->som_path, jsp);
+
+ /* Fixup jmpslot so future calls transfer directly to target */
+ addr = np->nz_value;
+ if (src_map)
+ addr += (long)src_map->som_addr;
+
+ md_fix_jmpslot(jsp, (long)jsp, addr);
+
+#if DEBUG
+ xprintf(" BINDER: %s located at = %#x in %s\n", sym, addr,
+ src_map->som_path);
+#endif
+ return addr;
+}
+
+static struct hints_header *hheader; /* NULL means not mapped */
+static struct hints_bucket *hbuckets;
+static char *hstrtab;
+
+/*
+ * Map the hints file into memory, if it is not already mapped. Returns
+ * 0 on success, or -1 on failure.
+ */
+ static int
+maphints __P((void))
+{
+ static int hints_bad; /* TRUE if hints are unusable */
+ static int paths_added;
+ int hfd;
+ struct hints_header hdr;
+ caddr_t addr;
+
+ if (hheader != NULL) /* Already mapped */
+ return 0;
+
+ if (hints_bad) /* Known to be corrupt or unavailable */
+ return -1;
+
+ if ((hfd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
+ hints_bad = 1;
+ return -1;
+ }
+
+ /* Read the header and check it */
+
+ if (read(hfd, &hdr, sizeof hdr) != sizeof hdr ||
+ HH_BADMAG(hdr) ||
+ (hdr.hh_version != LD_HINTS_VERSION_1 &&
+ hdr.hh_version != LD_HINTS_VERSION_2)) {
+ close(hfd);
+ hints_bad = 1;
+ return -1;
+ }
+
+ /* Map the hints into memory */
+
+ addr = mmap(0, hdr.hh_ehints, PROT_READ, MAP_SHARED, hfd, 0);
+ if (addr == (caddr_t)-1) {
+ close(hfd);
+ hints_bad = 1;
+ return -1;
+ }
+
+ close(hfd);
+
+ hheader = (struct hints_header *)addr;
+ hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab);
+ hstrtab = (char *)(addr + hheader->hh_strtab);
+ /* pluck out the system ldconfig path */
+ if (hheader->hh_version >= LD_HINTS_VERSION_2 && !paths_added) {
+ add_search_path(hstrtab + hheader->hh_dirlist);
+ paths_added = 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Unmap the hints file, if it is currently mapped.
+ */
+ static void
+unmaphints()
+{
+ if (hheader != NULL) {
+ munmap((caddr_t)hheader, hheader->hh_ehints);
+ hheader = NULL;
+ }
+}
+
+ int
+hinthash(cp, vmajor)
+ char *cp;
+ int vmajor;
+{
+ int k = 0;
+
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
+
+ return k;
+}
+
+#undef major
+#undef minor
+
+/*
+ * Search for a library in the hints generated by ldconfig. On success,
+ * returns the full pathname of the matching library. This string is
+ * always dynamically allocated on the heap.
+ *
+ * Returns the minor number of the matching library via the pointer
+ * argument MINORP.
+ *
+ * Returns NULL if the library cannot be found.
+ */
+ static char *
+findhint(name, major, minorp)
+ char *name;
+ int major;
+ int *minorp;
+{
+ struct hints_bucket *bp =
+ hbuckets + (hinthash(name, major) % hheader->hh_nbucket);
+
+ while (1) {
+ /* Sanity check */
+ if (bp->hi_namex >= hheader->hh_strtab_sz) {
+ warnx("Bad name index: %#x\n", bp->hi_namex);
+ break;
+ }
+ if (bp->hi_pathx >= hheader->hh_strtab_sz) {
+ warnx("Bad path index: %#x\n", bp->hi_pathx);
+ break;
+ }
+
+ /*
+ * We accept the current hints entry if its name matches
+ * and its major number matches. We don't have to search
+ * for the best minor number, because that was already
+ * done by "ldconfig" when it built the hints file.
+ */
+ if (strcmp(name, hstrtab + bp->hi_namex) == 0 &&
+ bp->hi_major == major) {
+ struct stat s;
+
+ if (stat(hstrtab + bp->hi_pathx, &s) == -1)
+ return NULL; /* Doesn't actually exist */
+ *minorp = bp->hi_ndewey >= 2 ? bp->hi_minor : -1;
+ return strdup(hstrtab + bp->hi_pathx);
+ }
+
+ if (bp->hi_next == -1)
+ break;
+
+ /* Move on to next in bucket */
+ bp = &hbuckets[bp->hi_next];
+ }
+
+ /* No hints available for name */
+ return NULL;
+}
+
+/*
+ * Search for the given shared library. On success, returns a string
+ * containing the full pathname for the library. This string is always
+ * dynamically allocated on the heap.
+ *
+ * Returns NULL if the library cannot be found.
+ */
+ static char *
+rtfindlib(name, major, minor)
+ char *name;
+ int major, minor;
+{
+ char *ld_path = ld_library_path;
+ char *path = NULL;
+ int realminor = -1;
+
+ if (ld_path != NULL) { /* First, search the directories in ld_path */
+ /*
+ * There is no point in trying to use the hints file for this.
+ */
+ char *dir;
+
+ while (path == NULL && (dir = strsep(&ld_path, ":")) != NULL) {
+ path = search_lib_dir(dir, name, &major, &realminor, 0);
+ if (ld_path != NULL)
+ *(ld_path - 1) = ':';
+ }
+ }
+
+ if (path == NULL && maphints() == 0) /* Search the hints file */
+ path = findhint(name, major, &realminor);
+
+ if (path == NULL) /* Search the standard directories */
+ path = findshlib(name, &major, &realminor, 0);
+
+ if (path != NULL && realminor < minor && !ld_suppress_warnings) {
+ warnx("warning: %s: minor version %d"
+ " older than expected %d, using it anyway",
+ path, realminor, minor);
+ }
+
+ return path;
+}
+
+/*
+ * Search for the given shared library file. This is similar to rtfindlib,
+ * except that the argument is the actual name of the desired library file.
+ * Thus there is no need to worry about version numbers. The return value
+ * is a string containing the full pathname for the library. This string
+ * is always dynamically allocated on the heap.
+ *
+ * Returns NULL if the library cannot be found.
+ */
+ static char *
+rtfindfile(name)
+ char *name;
+{
+ char *ld_path = ld_library_path;
+ char *path = NULL;
+
+ if (ld_path != NULL) { /* First, search the directories in ld_path */
+ char *dir;
+
+ while (path == NULL && (dir = strsep(&ld_path, ":")) != NULL) {
+ struct stat sb;
+
+ path = concat(dir, "/", name);
+ if (lstat(path, &sb) == -1) { /* Does not exist */
+ free(path);
+ path = NULL;
+ }
+ if (ld_path != NULL)
+ *(ld_path - 1) = ':';
+ }
+ }
+
+ /*
+ * We don't search the hints file. It is organized around major
+ * and minor version numbers, so it is not suitable for finding
+ * a specific file name.
+ */
+
+ if (path == NULL) /* Search the standard directories */
+ path = find_lib_file(name);
+
+ return path;
+}
+
+/*
+ * Buffer for error messages and a pointer that is set to point to the buffer
+ * when a error occurs. It acts as a last error flag, being set to NULL
+ * after an error is returned.
+ */
+#define DLERROR_BUF_SIZE 512
+static char dlerror_buf [DLERROR_BUF_SIZE];
+static char *dlerror_msg = NULL;
+
+
+ static void *
+__dlopen(path, mode)
+ char *path;
+ int mode;
+{
+ struct so_map *old_tail = link_map_tail;
+ struct so_map *smp;
+ int bind_now = mode == RTLD_NOW;
+
+ /*
+ * path == NULL is handled by map_object()
+ */
+
+ anon_open();
+
+ /* Map the object, and the objects on which it depends */
+ smp = map_object(path, (struct sod *) NULL, (struct so_map *) NULL);
+ if(smp == NULL) /* Failed */
+ return NULL;
+ LM_PRIVATE(smp)->spd_flags |= RTLD_DL;
+
+ /* Relocate and initialize all newly-mapped objects */
+ if(link_map_tail != old_tail) { /* We have mapped some new objects */
+ if(reloc_and_init(smp, bind_now) == -1) /* Failed */
+ return NULL;
+ }
+
+ unmaphints();
+ anon_close();
+
+ return smp;
+}
+
+ static int
+__dlclose(fd)
+ void *fd;
+{
+ struct so_map *smp = (struct so_map *)fd;
+ struct so_map *scanp;
+
+#ifdef DEBUG
+ xprintf("dlclose(%s): refcount = %d\n", smp->som_path,
+ LM_PRIVATE(smp)->spd_refcount);
+#endif
+ /* Check the argument for validity */
+ for(scanp = link_map_head; scanp != NULL; scanp = scanp->som_next)
+ if(scanp == smp) /* We found the map in the list */
+ break;
+ if(scanp == NULL || !(LM_PRIVATE(smp)->spd_flags & RTLD_DL)) {
+ generror("Invalid argument to dlclose");
+ return -1;
+ }
+
+ unmap_object(smp, 0);
+
+ return 0;
+}
+
+/*
+ * This form of dlsym is obsolete. Current versions of crt0 don't call
+ * it. It can still be called by old executables that were linked with
+ * old versions of crt0.
+ */
+ static void *
+__dlsym(fd, sym)
+ void *fd;
+ char *sym;
+{
+ if (fd == RTLD_NEXT) {
+ generror("RTLD_NEXT not supported by this version of"
+ " /usr/lib/crt0.o");
+ return NULL;
+ }
+ return __dlsym3(fd, sym, NULL);
+}
+
+ static void *
+__dlsym3(fd, sym, retaddr)
+ void *fd;
+ char *sym;
+ void *retaddr;
+{
+ struct so_map *smp;
+ struct so_map *src_map;
+ struct nzlist *np;
+ long addr;
+
+ if (fd == RTLD_NEXT) {
+ /* Find the shared object that contains the caller. */
+ for (smp = link_map_head; smp != NULL; smp = smp->som_next) {
+ void *textbase = smp->som_addr + LM_TXTADDR(smp);
+ void *textlimit = LM_ETEXT(smp);
+
+ if (textbase <= retaddr && retaddr < textlimit)
+ break;
+ }
+ if (smp == NULL) {
+ generror("Cannot determine caller's shared object");
+ return NULL;
+ }
+ smp = smp->som_next;
+ if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ smp = smp->som_next;
+ if (smp == NULL) {
+ generror("No next shared object for RTLD_NEXT");
+ return NULL;
+ }
+ do {
+ src_map = smp;
+ np = lookup(sym, &src_map, 1);
+ } while (np == NULL && (smp = smp->som_next) != NULL);
+ } else {
+ smp = (struct so_map *)fd;
+ src_map = NULL;
+
+ /*
+ * Restrict search to passed map if dlopen()ed.
+ */
+ if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_DL)
+ src_map = smp;
+
+ np = lookup(sym, &src_map, 1);
+ }
+
+ if (np == NULL) {
+ generror("Undefined symbol");
+ return NULL;
+ }
+
+ addr = np->nz_value;
+ if (src_map)
+ addr += (long)src_map->som_addr;
+
+ return (void *)addr;
+}
+
+ static char *
+__dlerror __P((void))
+{
+ char *err;
+
+ err = dlerror_msg;
+ dlerror_msg = NULL; /* Next call will return NULL */
+
+ return err;
+}
+
+ static void
+__dlexit __P((void))
+{
+#ifdef DEBUG
+xprintf("__dlexit called\n");
+#endif
+
+ unmap_object(link_map_head, 1);
+}
+
+/*
+ * Print the current error message and exit with failure status.
+ */
+static void
+die __P((void))
+{
+ char *msg;
+
+ fprintf(stderr, "ld.so failed");
+ if ((msg = __dlerror()) != NULL)
+ fprintf(stderr, ": %s", msg);
+ putc('\n', stderr);
+ _exit(1);
+}
+
+
+/*
+ * Generate an error message that can be later be retrieved via dlerror.
+ */
+static void
+#if __STDC__
+generror(char *fmt, ...)
+#else
+generror(fmt, va_alist)
+char *fmt;
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vsnprintf (dlerror_buf, DLERROR_BUF_SIZE, fmt, ap);
+ dlerror_msg = dlerror_buf;
+
+ va_end(ap);
+}
+
+void
+#if __STDC__
+xprintf(char *fmt, ...)
+#else
+xprintf(fmt, va_alist)
+char *fmt;
+#endif
+{
+ char buf[256];
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ (void)write(1, buf, strlen(buf));
+ va_end(ap);
+}
+
+/*
+ * rt_readenv() etc.
+ *
+ * Do a sweep over the environment once only, pick up what
+ * looks interesting.
+ *
+ * This is pretty obscure, but is relatively simple. Simply
+ * look at each environment variable, if it starts with "LD_" then
+ * look closer at it. If it's in our table, set the variable
+ * listed. effectively, this is like:
+ * ld_preload = careful ? NULL : getenv("LD_PRELOAD");
+ * except that the environment is scanned once only to pick up all
+ * known variables, rather than scanned multiple times for each
+ * variable.
+ *
+ * If an environment variable of interest is set to the empty string, we
+ * treat it as if it were unset.
+ */
+
+#define L(n, u, v) { n, sizeof(n) - 1, u, v },
+struct env_scan_tab {
+ char *name;
+ int len;
+ int unsafe;
+ char **value;
+} scan_tab[] = {
+ L("LD_LIBRARY_PATH=", 1, &ld_library_path)
+ L("LD_PRELOAD=", 1, &ld_preload)
+ L("LD_IGNORE_MISSING_OBJECTS=", 1, &ld_ignore_missing_objects)
+ L("LD_TRACE_LOADED_OBJECTS=", 0, &ld_tracing)
+ L("LD_BIND_NOW=", 0, &ld_bind_now)
+ L("LD_SUPPRESS_WARNINGS=", 0, &ld_suppress_warnings)
+ L("LD_WARN_NON_PURE_CODE=", 0, &ld_warn_non_pure_code)
+ { NULL, 0, NULL }
+};
+#undef L
+
+static void
+rt_readenv()
+{
+ char **p = environ;
+ char *v;
+ struct env_scan_tab *t;
+
+ /* for each string in the environment... */
+ while ((v = *p++)) {
+
+ /* check for LD_xxx */
+ if (v[0] != 'L' || v[1] != 'D' || v[2] != '_')
+ continue;
+
+ for (t = scan_tab; t->name; t++) {
+ if (careful && t->unsafe)
+ continue; /* skip for set[ug]id */
+ if (strncmp(t->name, v, t->len) == 0) {
+ if (*(v + t->len) != '\0') /* Not empty */
+ *t->value = v + t->len;
+ break;
+ }
+ }
+ }
+}
diff --git a/libexec/rtld-aout/shlib.c b/libexec/rtld-aout/shlib.c
new file mode 100644
index 0000000..efb0bb6
--- /dev/null
+++ b/libexec/rtld-aout/shlib.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author 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 ``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$
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <a.out.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <link.h>
+#include "shlib.h"
+#include "support.h"
+
+/*
+ * Standard directories to search for files specified by -l.
+ */
+#ifndef STANDARD_SEARCH_DIRS
+#define STANDARD_SEARCH_DIRS "/usr/lib"
+#endif
+
+/*
+ * Actual vector of library search directories,
+ * including `-L'ed and LD_LIBRARY_PATH spec'd ones.
+ */
+char **search_dirs;
+int n_search_dirs;
+
+char *standard_search_dirs[] = {
+ STANDARD_SEARCH_DIRS
+};
+
+
+void
+add_search_dir(name)
+ char *name;
+{
+ int n;
+
+ for (n = 0; n < n_search_dirs; n++)
+ if (strcmp(search_dirs[n], name) == 0)
+ return;
+ n_search_dirs++;
+ search_dirs = (char **)
+ xrealloc(search_dirs, n_search_dirs * sizeof search_dirs[0]);
+ search_dirs[n_search_dirs - 1] = strdup(name);
+}
+
+void
+add_search_path(path)
+char *path;
+{
+ register char *cp, *dup;
+
+ if (path == NULL)
+ return;
+
+ /* Add search directories from `path' */
+ path = dup = strdup(path);
+ while ((cp = strsep(&path, ":")) != NULL)
+ add_search_dir(cp);
+ free(dup);
+}
+
+void
+std_search_path()
+{
+ int i, n;
+
+ /* Append standard search directories */
+ n = sizeof standard_search_dirs / sizeof standard_search_dirs[0];
+ for (i = 0; i < n; i++)
+ add_search_dir(standard_search_dirs[i]);
+}
+
+/*
+ * Return true if CP points to a valid dewey number.
+ * Decode and leave the result in the array DEWEY.
+ * Return the number of decoded entries in DEWEY.
+ */
+
+int
+getdewey(dewey, cp)
+int dewey[];
+char *cp;
+{
+ int i, n;
+
+ for (n = 0, i = 0; i < MAXDEWEY; i++) {
+ if (*cp == '\0')
+ break;
+
+ if (*cp == '.') cp++;
+ if (!isdigit(*cp))
+ return 0;
+
+ dewey[n++] = strtol(cp, &cp, 10);
+ }
+
+ return n;
+}
+
+/*
+ * Compare two dewey arrays.
+ * Return -1 if `d1' represents a smaller value than `d2'.
+ * Return 1 if `d1' represents a greater value than `d2'.
+ * Return 0 if equal.
+ */
+int
+cmpndewey(d1, n1, d2, n2)
+int d1[], d2[];
+int n1, n2;
+{
+ register int i;
+
+ for (i = 0; i < n1 && i < n2; i++) {
+ if (d1[i] < d2[i])
+ return -1;
+ if (d1[i] > d2[i])
+ return 1;
+ }
+
+ if (n1 == n2)
+ return 0;
+
+ if (i == n1)
+ return -1;
+
+ if (i == n2)
+ return 1;
+
+ errx(1, "cmpndewey: cant happen");
+ return 0;
+}
+
+/*
+ * Search directories for a shared library matching the given
+ * major and minor version numbers. See search_lib_dir() below for
+ * the detailed matching rules.
+ *
+ * As soon as a directory with an acceptable match is found, the search
+ * terminates. Subsequent directories are not searched for a better
+ * match. This is in conformance with the SunOS searching rules. Also,
+ * it avoids a lot of directory searches that are virtually guaranteed to
+ * be fruitless.
+ *
+ * The return value is a full pathname to the matching library. The
+ * string is dynamically allocated. If no matching library is found, the
+ * function returns NULL.
+ */
+
+char *
+findshlib(name, majorp, minorp, do_dot_a)
+char *name;
+int *majorp, *minorp;
+int do_dot_a;
+{
+ int i;
+
+ for (i = 0; i < n_search_dirs; i++) {
+ char *path;
+
+ path = search_lib_dir(search_dirs[i], name, majorp, minorp,
+ do_dot_a);
+ if(path != NULL)
+ return path;
+ }
+
+ return NULL;
+}
+
+/*
+ * Search library directories for a file with the given name. The
+ * return value is a full pathname to the matching file. The string
+ * is dynamically allocated. If no matching file is found, the function
+ * returns NULL.
+ */
+
+char *
+find_lib_file(name)
+ char *name;
+{
+ int i;
+
+ for (i = 0; i < n_search_dirs; i++) {
+ char *path = concat(search_dirs[i], "/", name);
+ struct stat sb;
+
+ if (lstat(path, &sb) != -1) /* We found it */
+ return path;
+
+ free(path);
+ }
+
+ return NULL;
+}
+
+/*
+ * Search a given directory for a library (preferably shared) satisfying
+ * the given criteria.
+ *
+ * The matching rules are as follows:
+ *
+ * if(*majorp == -1)
+ * find the library with the highest major version;
+ * else
+ * insist on a major version identical to *majorp;
+ *
+ * Always find the library with the highest minor version;
+ * if(*minorp != -1)
+ * insist on a minor version >= *minorp;
+ *
+ * It is invalid to specify a specific minor number while wildcarding
+ * the major number.
+ *
+ * The actual major and minor numbers found are returned via the pointer
+ * arguments.
+ *
+ * A suitable shared library is always preferred over a static (.a) library.
+ * If do_dot_a is false, then a static library will not be accepted in
+ * any case.
+ *
+ * The return value is a full pathname to the matching library. The
+ * string is dynamically allocated. If no matching library is found, the
+ * function returns NULL.
+ */
+
+char *
+search_lib_dir(dir, name, majorp, minorp, do_dot_a)
+ char *dir;
+ char *name;
+ int *majorp;
+ int *minorp;
+ int do_dot_a;
+{
+ int namelen;
+ DIR *dd;
+ struct dirent *dp;
+ int best_dewey[MAXDEWEY];
+ int best_ndewey;
+ char dot_a_name[MAXNAMLEN+1];
+ char dot_so_name[MAXNAMLEN+1];
+
+ if((dd = opendir(dir)) == NULL)
+ return NULL;
+
+ namelen = strlen(name);
+ best_ndewey = 0;
+ dot_a_name[0] = '\0';
+ dot_so_name[0] = '\0';
+
+ while((dp = readdir(dd)) != NULL) {
+ char *extension;
+
+ if(strlen(dp->d_name) < 3 + namelen + 2 || /* lib+xxx+.a */
+ strncmp(dp->d_name, "lib", 3) != 0 ||
+ strncmp(dp->d_name + 3, name, namelen) != 0 ||
+ dp->d_name[3+namelen] != '.')
+ continue;
+
+ extension = dp->d_name + 3 + namelen + 1; /* a or so.* */
+
+ if(strncmp(extension, "so.", 3) == 0) {
+ int cur_dewey[MAXDEWEY];
+ int cur_ndewey;
+
+ cur_ndewey = getdewey(cur_dewey, extension+3);
+ if(cur_ndewey == 0) /* No version number */
+ continue;
+
+ if(*majorp != -1) { /* Need exact match on major */
+ if(cur_dewey[0] != *majorp)
+ continue;
+ if(*minorp != -1) { /* Need minor >= minimum */
+ if(cur_ndewey < 2 ||
+ cur_dewey[1] < *minorp)
+ continue;
+ }
+ }
+
+ if(cmpndewey(cur_dewey, cur_ndewey, best_dewey,
+ best_ndewey) <= 0) /* No better than prior match */
+ continue;
+
+ /* We found a better match */
+ strcpy(dot_so_name, dp->d_name);
+ bcopy(cur_dewey, best_dewey,
+ cur_ndewey * sizeof best_dewey[0]);
+ best_ndewey = cur_ndewey;
+ } else if(do_dot_a && strcmp(extension, "a") == 0)
+ strcpy(dot_a_name, dp->d_name);
+ }
+ closedir(dd);
+
+ if(dot_so_name[0] != '\0') {
+ *majorp = best_dewey[0];
+ if(best_ndewey >= 2)
+ *minorp = best_dewey[1];
+ return concat(dir, "/", dot_so_name);
+ }
+
+ if(dot_a_name[0] != '\0')
+ return concat(dir, "/", dot_a_name);
+
+ return NULL;
+}
diff --git a/libexec/rtld-aout/shlib.h b/libexec/rtld-aout/shlib.h
new file mode 100644
index 0000000..796d37e
--- /dev/null
+++ b/libexec/rtld-aout/shlib.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (C) 1996
+ * Peter Wemm. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *-
+ * $Id$
+ */
+
+/*
+ * prototypes for shlib.c. Big deal.
+ */
+
+extern char **search_dirs;
+extern int n_search_dirs;
+
+void add_search_dir __P((char *));
+void add_search_path __P((char *));
+void std_search_path __P((void));
+int getdewey __P((int[], char *));
+int cmpndewey __P((int[], int, int[], int));
+char *findshlib __P((char *, int *, int *, int));
+char *find_lib_file __P((char *));
+char *search_lib_dir __P((char *, char *, int *, int *, int));
diff --git a/libexec/rtld-aout/support.c b/libexec/rtld-aout/support.c
new file mode 100644
index 0000000..0d9df2a
--- /dev/null
+++ b/libexec/rtld-aout/support.c
@@ -0,0 +1,86 @@
+/*
+ * Generic "support" routines to replace those obtained from libiberty for ld.
+ *
+ * I've collected these from random bits of (published) code I've written
+ * over the years, not that they are a big deal. peter@freebsd.org
+ *-
+ * Copyright (C) 1996
+ * Peter Wemm. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *-
+ * $Id$
+ */
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <err.h>
+
+#include "support.h"
+
+char *
+concat(s1, s2, s3)
+ const char *s1, *s2, *s3;
+{
+ int len = 1;
+ char *s;
+ if (s1)
+ len += strlen(s1);
+ if (s2)
+ len += strlen(s2);
+ if (s3)
+ len += strlen(s3);
+ s = xmalloc(len);
+ s[0] = '\0';
+ if (s1)
+ strcat(s, s1);
+ if (s2)
+ strcat(s, s2);
+ if (s3)
+ strcat(s, s3);
+ return s;
+}
+
+void *
+xmalloc(n)
+ size_t n;
+{
+ char *p = malloc(n);
+
+ if (p == NULL)
+ errx(1, "Could not allocate memory");
+
+ return p;
+}
+
+void *
+xrealloc(p, n)
+ void *p;
+ size_t n;
+{
+ p = realloc(p, n);
+
+ if (p == NULL)
+ errx(1, "Could not allocate memory");
+
+ return p;
+}
diff --git a/libexec/rtld-aout/support.h b/libexec/rtld-aout/support.h
new file mode 100644
index 0000000..5be1e31
--- /dev/null
+++ b/libexec/rtld-aout/support.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (C) 1996
+ * Peter Wemm. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *-
+ * $Id$
+ */
+
+/*
+ * prototypes for support.c. Big deal.
+ */
+
+void *xmalloc __P((size_t));
+void *xrealloc __P((void *, size_t));
+char *concat __P((const char *, const char *, const char *));
diff --git a/libexec/rtld-elf/rtld.1 b/libexec/rtld-elf/rtld.1
new file mode 100644
index 0000000..dbd4dde
--- /dev/null
+++ b/libexec/rtld-elf/rtld.1
@@ -0,0 +1,224 @@
+.\" $Id: rtld.1,v 1.13 1997/02/22 15:46:47 peter Exp $
+.\"
+.\" Copyright (c) 1995 Paul Kranenburg
+.\" 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 acknowledgment:
+.\" This product includes software developed by Paul Kranenburg.
+.\" 3. The name of the author 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 ``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.
+.\"
+.Dd June 27, 1995
+.Dt RTLD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ld.so
+.Nd run-time link-editor
+.Sh DESCRIPTION
+.Nm
+is a self-contained, position independent program image providing run-time
+support for loading and link-editing shared objects into a process'
+address space. It uses the data structures
+.Po
+see
+.Xr link 5
+.Pc
+contained within dynamically linked programs to determine which shared
+libraries are needed and loads them at a convenient virtual address
+using the
+.Xr mmap 2
+system call.
+.Pp
+After all shared libraries have been successfully loaded,
+.Nm
+proceeds to resolve external references from both the main program and
+all objects loaded. A mechanism is provided for initialization routines
+to be called, on a per-object basis, giving a shared object an opportunity
+to perform any extra set-up, before execution of the program proper begins.
+This is useful for C++ libraries that contain static constructors.
+.Pp
+.Nm
+is itself a shared object that is initially loaded by the startup module
+.Em crt0 .
+Since
+.Xr a.out 5
+formats do not provide easy access to the file header from within a running
+process,
+.Em crt0
+uses the special symbol
+.Va _DYNAMIC
+to determine whether a program is in fact dynamically linked or not. Whenever
+the linker
+.Xr ld 1
+has relocated this symbol to a location other than 0,
+.Em crt0
+assumes the services of
+.Nm
+are needed
+.Po
+see
+.Xr link 5
+for details
+.Pc \&.
+.Em crt0
+passes control to
+.Nm
+\&'s entry point before the program's
+.Fn main
+routine is called. Thus,
+.Nm
+can complete the link-editing process before the dynamic program calls upon
+services of any dynamic library.
+.Pp
+To quickly locate the required shared objects in the filesystem,
+.Nm
+may use a
+.Dq hints
+file, prepared by the
+.Xr ldconfig 8
+utility, in which the full path specification of the shared objects can be
+looked up by hashing on the 3-tuple
+.Ao
+library-name, major-version-number, minor-version-number
+.Ac \&.
+.Pp
+.Nm
+recognises a number of environment variables that can be used to modify
+its behaviour as follows:
+.Pp
+.Bl -tag -width "LD_IGNORE_MISSING_OBJECTS"
+.It Ev LD_LIBRARY_PATH
+A colon separated list of directories, overriding the default search path
+for shared libraries.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_PRELOAD
+A colon separated list of shared libraries, to be linked in before any
+other shared libraries. If the directory is not specified then
+the directories specified by LD_LIBRARY_PATH will be searched first
+followed by the set of built-in standard directories.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_BIND_NOW
+When set to a nonempty string, causes
+.Nm
+to relocate all external function calls before starting execution of the
+program. Normally, function calls are bound lazily, at the first call
+of each function.
+.Ev LD_BIND_NOW
+increases the start-up time of a program, but it avoids run-time
+surprises caused by unexpectedly undefined functions.
+.It Ev LD_WARN_NON_PURE_CODE
+When set to a nonempty string, issue a warning whenever a link-editing
+operation requires modification of the text segment of some loaded
+object. This is usually indicative of an incorrectly built library.
+.It Ev LD_SUPPRESS_WARNINGS
+When set to a nonempty string, no warning messages of any kind are
+issued. Normally, a warning is given if satisfactorily versioned
+library could not be found.
+.It Ev LD_IGNORE_MISSING_OBJECTS
+When set to a nonempty string, makes it a nonfatal condition if
+one or more required shared objects cannot be loaded.
+Loading and execution proceeds using the objects that are
+available.
+A warning is produced for each missing object, unless the environment
+variable
+.Ev LD_SUPPRESS_WARNINGS
+is set to a nonempty string.
+.Pp
+This is ignored for set-user-ID and set-group-ID programs.
+.Pp
+Missing shared objects can be ignored without errors if all the
+following conditions hold:
+.Bl -bullet
+.It
+They do not supply definitions for any required data symbols.
+.It
+No functions defined by them are called during program execution.
+.It
+The environment variable
+.Ev LD_BIND_NOW
+is unset or is set to the empty string.
+.El
+.It Ev LD_TRACE_LOADED_OBJECTS
+When set to a nonempty string, causes
+.Nm
+to exit after loading the shared objects and printing a summary which includes
+the absolute pathnames of all objects, to standard output.
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT1
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT2
+When set, these variables are interpreted as format strings a la
+.Xr printf 3
+to customize the trace output and are used by
+.Xr ldd 1 's
+.Fl f
+option and allows
+.Xr ldd 1
+to be operated as a filter more conveniently.
+The following conversions can be used:
+.Bl -tag -indent "LD_TRACE_LOADED_OBJECTS_FMT1 " -width "xxxx"
+.It \&%a
+The main program's name
+.Po also known as
+.Dq __progname
+.Pc .
+.It \&%A
+The value of the environment variable
+.Ev LD_TRACE_LOADED_OBJECTS_PROGNAME
+.It \&%o
+The library name.
+.It \&%m
+The library's major version number.
+.It \&%n
+The library's minor version number.
+.It \&%p
+The full pathname as determined by
+.Nm rtld Ns 's
+library search rules.
+.It \&%x
+The library's load address.
+.El
+.Pp
+Additionally,
+.Sy \en
+and
+.Sy \et
+are recognised and have their usual meaning.
+.\" .It Ev LD_NO_INTERN_SEARCH
+.\" When set,
+.\" .Nm
+.\" does not process any internal search paths that were recorded in the
+.\" executable.
+.\" .It Ev LD_NOSTD_PATH
+.\" When set, do not include a set of built-in standard directory paths for
+.\" searching. This might be useful when running on a system with a completely
+.\" non-standard filesystem layout.
+.El
+.Pp
+.Sh FILES
+/var/run/ld.so.hints
+.Pp
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr link 5 ,
+.Xr ldconfig 8
+.Sh HISTORY
+The shared library model employed first appeared in SunOS 4.0
diff --git a/libexec/talkd/Makefile b/libexec/talkd/Makefile
index 51f6806..1754066 100644
--- a/libexec/talkd/Makefile
+++ b/libexec/talkd/Makefile
@@ -1,8 +1,9 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
PROG= ntalkd
SRCS= talkd.c announce.c process.c table.c print.c ttymsg.c
.PATH: ${.CURDIR}/../../usr.bin/wall
-MAN8= talkd.0
+MAN8= talkd.8
.include <bsd.prog.mk>
diff --git a/libexec/talkd/announce.c b/libexec/talkd/announce.c
index 7c99ea4..2ce6e53 100644
--- a/libexec/talkd/announce.c
+++ b/libexec/talkd/announce.c
@@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@@ -41,24 +43,26 @@ static char sccsid[] = "@(#)announce.c 8.3 (Berkeley) 4/28/95";
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/socket.h>
+
#include <protocols/talkd.h>
-#include <sgtty.h>
+
#include <errno.h>
-#include <syslog.h>
-#include <unistd.h>
+#include <paths.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
#include <vis.h>
-#include <paths.h>
extern char hostname[];
/*
* Announce an invitation to talk.
*/
-
+
/*
- * See if the user is accepting messages. If so, announce that
+ * See if the user is accepting messages. If so, announce that
* a talk is requested.
*/
announce(request, remote_machine)
@@ -81,7 +85,7 @@ announce(request, remote_machine)
#define N_CHARS 256
/*
- * Build a block of characters containing the message.
+ * Build a block of characters containing the message.
* It is sent blank filled and in a single block to
* try to keep the message in one piece if the recipient
* in in vi at the time
@@ -107,33 +111,35 @@ print_mesg(tty, tf, request, remote_machine)
max_size = 0;
gettimeofday(&clock, &zone);
localclock = localtime( &clock.tv_sec );
- (void)sprintf(line_buf[i], " ");
+ (void)snprintf(line_buf[i], N_CHARS, " ");
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
- (void)sprintf(line_buf[i], "Message from Talk_Daemon@%s at %d:%02d ...",
- hostname, localclock->tm_hour , localclock->tm_min );
+ (void)snprintf(line_buf[i], N_CHARS,
+ "Message from Talk_Daemon@%s at %d:%02d ...",
+ hostname, localclock->tm_hour , localclock->tm_min );
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
- vis_user = (char *) malloc(strlen(request->l_name) * 4 + 1);
+
+ vis_user = malloc(strlen(request->l_name) * 4 + 1);
strvis(vis_user, request->l_name, VIS_CSTYLE);
- (void)sprintf(line_buf[i], "talk: connection requested by %s@%s",
- vis_user, remote_machine);
+ (void)snprintf(line_buf[i], N_CHARS,
+ "talk: connection requested by %s@%s", vis_user, remote_machine);
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
- (void)sprintf(line_buf[i], "talk: respond with: talk %s@%s",
- vis_user, remote_machine);
+ (void)snprintf(line_buf[i], N_CHARS, "talk: respond with: talk %s@%s",
+ vis_user, remote_machine);
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
- (void)sprintf(line_buf[i], " ");
+ (void)snprintf(line_buf[i], N_CHARS, " ");
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
bptr = big_buf;
- *bptr++ = ''; /* send something to wake them up */
+ *bptr++ = '\007'; /* send something to wake them up */
*bptr++ = '\r'; /* add a \r in case of raw mode */
*bptr++ = '\n';
for (i = 0; i < N_LINES; i++) {
diff --git a/libexec/talkd/print.c b/libexec/talkd/print.c
index 9c0085b..af9e119 100644
--- a/libexec/talkd/print.c
+++ b/libexec/talkd/print.c
@@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@@ -46,7 +48,7 @@ static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 6/4/93";
static char *types[] =
{ "leave_invite", "look_up", "delete", "announce" };
#define NTYPES (sizeof (types) / sizeof (types[0]))
-static char *answers[] =
+static char *answers[] =
{ "success", "not_here", "failed", "machine_unknown", "permission_denied",
"unknown_request", "badversion", "badaddr", "badctladdr" };
#define NANSWERS (sizeof (answers) / sizeof (answers[0]))
@@ -56,7 +58,7 @@ print_request(cp, mp)
register CTL_MSG *mp;
{
char tbuf[80], *tp;
-
+
if (mp->type > NTYPES) {
(void)sprintf(tbuf, "type %d", mp->type);
tp = tbuf;
@@ -71,7 +73,7 @@ print_response(cp, rp)
register CTL_RESPONSE *rp;
{
char tbuf[80], *tp, abuf[80], *ap;
-
+
if (rp->type > NTYPES) {
(void)sprintf(tbuf, "type %d", rp->type);
tp = tbuf;
diff --git a/libexec/talkd/process.c b/libexec/talkd/process.c
index dd05e6b..df087e3 100644
--- a/libexec/talkd/process.c
+++ b/libexec/talkd/process.c
@@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@@ -52,6 +54,7 @@ static char sccsid[] = "@(#)process.c 8.2 (Berkeley) 11/16/93";
#include <syslog.h>
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
#include <paths.h>
CTL_MSG *find_request();
@@ -63,6 +66,7 @@ process_request(mp, rp)
{
register CTL_MSG *ptr;
extern int debug;
+ char *s;
rp->vers = TALK_VERSION;
rp->type = mp->type;
@@ -87,6 +91,12 @@ process_request(mp, rp)
rp->answer = BADCTLADDR;
return;
}
+ for (s = mp->l_name; *s; s++)
+ if (!isprint(*s)) {
+ syslog(LOG_NOTICE, "Illegal user name. Aborting");
+ rp->answer = FAILED;
+ return;
+ }
mp->pid = ntohl(mp->pid);
if (debug)
print_request("process_request", mp);
@@ -182,6 +192,7 @@ find_user(name, tty)
int status;
FILE *fd;
struct stat statb;
+ time_t best = 0;
char line[sizeof(ubuf.ut_line) + 1];
char ftty[sizeof(_PATH_DEV) - 1 + sizeof(line)];
@@ -196,17 +207,21 @@ find_user(name, tty)
if (SCMPN(ubuf.ut_name, name) == 0) {
strncpy(line, ubuf.ut_line, sizeof(ubuf.ut_line));
line[sizeof(ubuf.ut_line)] = '\0';
- if (*tty == '\0') {
- status = PERMISSION_DENIED;
+ if (*tty == '\0' || best != 0) {
+ if (best == 0)
+ status = PERMISSION_DENIED;
/* no particular tty was requested */
(void) strcpy(ftty + sizeof(_PATH_DEV) - 1,
line);
if (stat(ftty, &statb) == 0) {
if (!(statb.st_mode & 020))
continue;
- (void) strcpy(tty, line);
- status = SUCCESS;
- break;
+ if (statb.st_atime > best) {
+ best = statb.st_atime;
+ (void) strcpy(tty, line);
+ status = SUCCESS;
+ continue;
+ }
}
}
if (strcmp(line, tty) == 0) {
diff --git a/libexec/talkd/table.c b/libexec/talkd/table.c
index cc8cb66..a31c611 100644
--- a/libexec/talkd/table.c
+++ b/libexec/talkd/table.c
@@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@@ -38,7 +40,7 @@ static char sccsid[] = "@(#)table.c 8.1 (Berkeley) 6/4/93";
/*
* Routines to handle insertion, deletion, etc on the table
* of requests kept by the daemon. Nothing fancy here, linear
- * search on a double-linked list. A time is kept with each
+ * search on a double-linked list. A time is kept with each
* entry so that overly old invitations can be eliminated.
*
* Consider this a mis-guided attempt at modularity
@@ -110,7 +112,7 @@ find_match(request)
/*
* Look for an identical request, as opposed to a complimentary
- * one as find_match does
+ * one as find_match does
*/
CTL_MSG *
find_request(request)
diff --git a/libexec/talkd/talkd.c b/libexec/talkd/talkd.c
index 669931b..acaa888 100644
--- a/libexec/talkd/talkd.c
+++ b/libexec/talkd/talkd.c
@@ -29,6 +29,8 @@
* 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$
*/
#ifndef lint
@@ -43,12 +45,13 @@ static char sccsid[] = "@(#)talkd.c 8.1 (Berkeley) 6/4/93";
/*
* The top level of the daemon, the format is heavily borrowed
- * from rwhod.c. Basically: find out who and where you are;
+ * from rwhod.c. Basically: find out who and where you are;
* disconnect all descriptors and ttys, and then endless
* loop on waiting for and processing requests
*/
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/param.h>
#include <protocols/talkd.h>
#include <signal.h>
#include <syslog.h>
@@ -68,7 +71,7 @@ int debug = 0;
void timeout();
long lastmsgtime;
-char hostname[32];
+char hostname[MAXHOSTNAMELEN + 1];
#define TIMEOUT 30
#define MAXIDLE 120
@@ -109,6 +112,7 @@ main(argc, argv)
lastmsgtime = time(0);
process_request(mp, &response);
/* can block here, is this what I want? */
+ mp->ctl_addr.sa_family = htons(mp->ctl_addr.sa_family);
cc = sendto(sockt, (char *)&response,
sizeof (response), 0, (struct sockaddr *)&mp->ctl_addr,
sizeof (mp->ctl_addr));
diff --git a/libexec/telnetd/Makefile b/libexec/telnetd/Makefile
index 4b1d530..7c9919e 100644
--- a/libexec/telnetd/Makefile
+++ b/libexec/telnetd/Makefile
@@ -1,36 +1,19 @@
# @(#)Makefile 8.2 (Berkeley) 12/15/93
+# $Id$
PROG= telnetd
-CFLAGS+=-DLINEMODE -DKLUDGELINEMODE -DUSE_TERMIO -DDIAGNOSTICS
+CFLAGS+=-DLINEMODE -DUSE_TERMIO -DDIAGNOSTICS
+#CFLAGS+=-DKLUDGELINEMODE
CFLAGS+=-DOLD_ENVIRON -DENV_HACK
-CFLAGS+=-DAUTHENTICATION -DENCRYPTION -I${.CURDIR}/../../lib
-SRCS= authenc.c global.c slc.c state.c sys_term.c telnetd.c \
+CFLAGS+=-I${.CURDIR}/../../lib
+#CFLAGS+=-DAUTHENTICATION -DENCRYPTION
+SRCS= global.c slc.c state.c sys_term.c telnetd.c \
termstat.c utility.c
-DPADD= ${LIBUTIL} ${LIBTERM}
+#SRCS+= authenc.c
+DPADD= ${LIBUTIL} ${LIBTERMCAP} ${LIBTELNET}
LDADD= -lutil -ltermcap -ltelnet
-LDADD+= -lkrb -ldes
-MAN8= telnetd.0
-
-# These are the sources that have encryption stuff in them.
-CRYPT_SRC= authenc.c ext.h state.c telnetd.c termstat.c
-CRYPT_SRC+= utility.c Makefile
-NOCRYPT_DIR=${.CURDIR}/Nocrypt
+#DPADD+= $LIBKRB} ${LIBDES}
+#LDADD+= -lkrb -ldes
+MAN8= telnetd.8
.include <bsd.prog.mk>
-
-nocrypt:
-#ifdef ENCRYPTION
- @for i in ${CRYPT_SRC}; do \
- if [ ! -d ${NOCRYPT_DIR} ]; then \
- echo Creating subdirectory ${NOCRYPT_DIR}; \
- mkdir ${NOCRYPT_DIR}; \
- fi; \
- echo ${NOCRYPT_DIR}/$$i; \
- unifdef -UENCRYPTION ${.CURDIR}/$$i | \
- sed "s/ || defined(ENCRYPTION)//" > ${NOCRYPT_DIR}/$$i; \
- done
-
-placeholder:
-#else /* ENCRYPTION */
- @echo "Encryption code already removed."
-#endif /* ENCRYPTION */
diff --git a/libexec/telnetd/ext.h b/libexec/telnetd/ext.h
index 19bc0d6..05898fb 100644
--- a/libexec/telnetd/ext.h
+++ b/libexec/telnetd/ext.h
@@ -31,6 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ext.h 8.2 (Berkeley) 12/15/93
+ * $Id$
*/
/*
@@ -191,11 +192,6 @@ extern void
wontoption P((int)),
writenet P((unsigned char *, int));
-#ifdef ENCRYPTION
-extern void (*encrypt_output) P((unsigned char *, int));
-extern int (*decrypt_input) P((int));
-extern char *nclearto;
-#endif /* ENCRYPTION */
/*
@@ -233,7 +229,7 @@ extern int needtermstat;
# ifdef ultrix
# define DEFAULT_IM "\r\n\r\nULTRIX (%h) (%t)\r\n\r\r\n\r"
# else
-# define DEFAULT_IM "\r\n\r\n4.4 BSD UNIX (%h) (%t)\r\n\r\r\n\r"
+# define DEFAULT_IM "\r\n\r\nFreeBSD (%h) (%t)\r\n\r\r\n\r"
# endif
# endif
# endif
diff --git a/libexec/telnetd/pathnames.h b/libexec/telnetd/pathnames.h
index c8b0806..979f4d0 100644
--- a/libexec/telnetd/pathnames.h
+++ b/libexec/telnetd/pathnames.h
@@ -31,6 +31,7 @@
* SUCH DAMAGE.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * $Id$
*/
#if BSD > 43
@@ -42,7 +43,7 @@
# endif
#else
-
+
# define _PATH_TTY "/dev/tty"
# ifndef _PATH_LOGIN
# define _PATH_LOGIN "/bin/login"
diff --git a/libexec/telnetd/slc.c b/libexec/telnetd/slc.c
index 6cbb7ab..a3799f3 100644
--- a/libexec/telnetd/slc.c
+++ b/libexec/telnetd/slc.c
@@ -29,10 +29,12 @@
* 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$
*/
#ifndef lint
-static char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)slc.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include "telnetd.h"
@@ -372,6 +374,7 @@ change_slc(func, flag, val)
slctab[func].defset.val;
val = slctab[func].current.val;
}
+
}
add_slc(func, flag, val);
}
@@ -422,6 +425,7 @@ check_slc()
slctab[i].current.val);
}
}
+
} /* check_slc */
/*
@@ -463,7 +467,7 @@ do_opt_slc(ptr, len)
def_slcbuf = (unsigned char *)malloc((unsigned)len);
if (def_slcbuf == (unsigned char *)0)
return; /* too bad */
- memmove(def_slcbuf, ptr, len);
+ bcopy(ptr, def_slcbuf, len);
}
}
diff --git a/libexec/telnetd/state.c b/libexec/telnetd/state.c
index 4ee8bea..4e72666 100644
--- a/libexec/telnetd/state.c
+++ b/libexec/telnetd/state.c
@@ -29,10 +29,12 @@
* 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$
*/
#ifndef lint
-static char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)state.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
#include "telnetd.h"
@@ -94,10 +96,6 @@ telrcv()
if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
break;
c = *netip++ & 0377, ncc--;
-#ifdef ENCRYPTION
- if (decrypt_input)
- c = (*decrypt_input)(c);
-#endif /* ENCRYPTION */
switch (state) {
case TS_CR:
@@ -126,10 +124,6 @@ telrcv()
*/
if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
int nc = *netip;
-#ifdef ENCRYPTION
- if (decrypt_input)
- nc = (*decrypt_input)(nc & 0xff);
-#endif /* ENCRYPTION */
#ifdef LINEMODE
/*
* If we are operating in linemode,
@@ -142,10 +136,6 @@ telrcv()
} else
#endif
{
-#ifdef ENCRYPTION
- if (decrypt_input)
- (void)(*decrypt_input)(-1);
-#endif /* ENCRYPTION */
state = TS_CR;
}
}
@@ -366,7 +356,7 @@ gotiac: switch (c) {
char xbuf2[BUFSIZ];
register char *cp;
int n = pfrontp - opfrontp, oc;
- memmove(xptyobuf, opfrontp, n);
+ bcopy(opfrontp, xptyobuf, n);
pfrontp = opfrontp;
pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
xbuf2, &oc, BUFSIZ);
@@ -464,9 +454,6 @@ extern void auth_request();
#ifdef LINEMODE
extern void doclientstat();
#endif
-#ifdef ENCRYPTION
-extern void encrypt_send_support();
-#endif /* ENCRYPTION */
void
willoption(option)
@@ -580,12 +567,6 @@ willoption(option)
break;
#endif
-#ifdef ENCRYPTION
- case TELOPT_ENCRYPT:
- func = encrypt_send_support;
- changeok++;
- break;
-#endif /* ENCRYPTION */
default:
break;
@@ -645,11 +626,6 @@ willoption(option)
break;
#endif
-#ifdef ENCRYPTION
- case TELOPT_ENCRYPT:
- func = encrypt_send_support;
- break;
-#endif /* ENCRYPTION */
case TELOPT_LFLOW:
func = flowstat;
break;
@@ -716,6 +692,7 @@ wontoption(option)
*/
if (lmodetype != REAL_LINEMODE)
break;
+ lmodetype = KLUDGE_LINEMODE;
# endif /* KLUDGELINEMODE */
clientstat(TELOPT_LINEMODE, WONT, 0);
break;
@@ -939,11 +916,6 @@ dooption(option)
/* NOT REACHED */
break;
-#ifdef ENCRYPTION
- case TELOPT_ENCRYPT:
- changeok++;
- break;
-#endif /* ENCRYPTION */
case TELOPT_LINEMODE:
case TELOPT_TTYPE:
case TELOPT_NAWS:
@@ -1463,49 +1435,6 @@ suboption()
}
break;
#endif
-#ifdef ENCRYPTION
- case TELOPT_ENCRYPT:
- if (SB_EOF())
- break;
- switch(SB_GET()) {
- case ENCRYPT_SUPPORT:
- encrypt_support(subpointer, SB_LEN());
- break;
- case ENCRYPT_IS:
- encrypt_is(subpointer, SB_LEN());
- break;
- case ENCRYPT_REPLY:
- encrypt_reply(subpointer, SB_LEN());
- break;
- case ENCRYPT_START:
- encrypt_start(subpointer, SB_LEN());
- break;
- case ENCRYPT_END:
- encrypt_end();
- break;
- case ENCRYPT_REQSTART:
- encrypt_request_start(subpointer, SB_LEN());
- break;
- case ENCRYPT_REQEND:
- /*
- * We can always send an REQEND so that we cannot
- * get stuck encrypting. We should only get this
- * if we have been able to get in the correct mode
- * anyhow.
- */
- encrypt_request_end();
- break;
- case ENCRYPT_ENC_KEYID:
- encrypt_enc_keyid(subpointer, SB_LEN());
- break;
- case ENCRYPT_DEC_KEYID:
- encrypt_dec_keyid(subpointer, SB_LEN());
- break;
- default:
- break;
- }
- break;
-#endif /* ENCRYPTION */
default:
break;
@@ -1519,8 +1448,8 @@ doclientstat()
clientstat(TELOPT_LINEMODE, WILL, 0);
}
-#define ADD(c) *ncp++ = c
-#define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
+#define ADD(c) *ncp++ = c;
+#define ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
void
send_status()
{
@@ -1549,10 +1478,14 @@ send_status()
if (my_want_state_is_will(i)) {
ADD(WILL);
ADD_DATA(i);
+ if (i == IAC)
+ ADD(IAC);
}
if (his_want_state_is_will(i)) {
ADD(DO);
ADD_DATA(i);
+ if (i == IAC)
+ ADD(IAC);
}
}
@@ -1567,14 +1500,15 @@ send_status()
ADD(SE);
if (restartany >= 0) {
- ADD(SB);
+ ADD(SB)
ADD(TELOPT_LFLOW);
if (restartany) {
ADD(LFLOW_RESTART_ANY);
} else {
ADD(LFLOW_RESTART_XON);
}
- ADD(SE);
+ ADD(SE)
+ ADD(SB);
}
}
@@ -1587,6 +1521,8 @@ send_status()
ADD(TELOPT_LINEMODE);
ADD(LM_MODE);
ADD_DATA(editmode);
+ if (editmode == IAC)
+ ADD(IAC);
ADD(SE);
ADD(SB);
diff --git a/libexec/telnetd/sys_term.c b/libexec/telnetd/sys_term.c
index 58d2e98..1881e32 100644
--- a/libexec/telnetd/sys_term.c
+++ b/libexec/telnetd/sys_term.c
@@ -29,10 +29,12 @@
* 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$
*/
#ifndef lint
-static char sccsid[] = "@(#)sys_term.c 8.4 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)sys_term.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
#include "telnetd.h"
@@ -42,13 +44,15 @@ static char sccsid[] = "@(#)sys_term.c 8.4 (Berkeley) 5/30/95";
#include <libtelnet/auth.h>
#endif
+extern char *altlogin;
+
#if defined(CRAY) || defined(__hpux)
# define PARENT_DOES_UTMP
#endif
+int utmp_len = MAXHOSTNAMELEN;
#ifdef NEWINIT
#include <initreq.h>
-int utmp_len = MAXHOSTNAMELEN; /* sizeof(init_request.host) */
#else /* NEWINIT*/
# ifdef UTMPX
# include <utmpx.h>
@@ -58,10 +62,17 @@ struct utmpx wtmp;
struct utmp wtmp;
# endif /* UTMPX */
-int utmp_len = sizeof(wtmp.ut_host);
# ifndef PARENT_DOES_UTMP
+#ifdef _PATH_WTMP
+char wtmpf[] = _PATH_WTMP;
+#else
char wtmpf[] = "/usr/adm/wtmp";
+#endif
+#ifdef _PATH_UTMP
+char utmpf[] = _PATH_UTMP;
+#else
char utmpf[] = "/etc/utmp";
+#endif
# else /* PARENT_DOES_UTMP */
char wtmpf[] = "/etc/wtmp";
# endif /* PARENT_DOES_UTMP */
@@ -69,16 +80,21 @@ char wtmpf[] = "/etc/wtmp";
# ifdef CRAY
#include <tmpdir.h>
#include <sys/wait.h>
-# if (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1')
-# define UNICOS7x
+# if defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
+ /*
+ * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
+ * use it to tell us to turn off all the socket security code,
+ * since that is only used in UNICOS 7.0 and later.
+ */
+# undef _SC_CRAY_SECURE_SYS
# endif
-# ifdef UNICOS7x
+# if defined(_SC_CRAY_SECURE_SYS)
#include <sys/sysv.h>
#include <sys/secstat.h>
extern int secflag;
extern struct sysv sysv;
-# endif /* UNICOS7x */
+# endif /* _SC_CRAY_SECURE_SYS */
# endif /* CRAY */
#endif /* NEWINIT */
@@ -210,7 +226,7 @@ copy_termbuf(cp, len)
{
if (len > sizeof(termbuf))
len = sizeof(termbuf);
- memmove((char *)&termbuf, cp, len);
+ bcopy(cp, (char *)&termbuf, len);
termbuf2 = termbuf;
}
#endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
@@ -222,19 +238,17 @@ set_termbuf()
* Only make the necessary changes.
*/
#ifndef USE_TERMIO
- if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg,
- sizeof(termbuf.sg)))
+ if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
(void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
- if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc,
- sizeof(termbuf.tc)))
+ if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
(void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
- if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
+ if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
sizeof(termbuf.ltc)))
(void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
if (termbuf.lflags != termbuf2.lflags)
(void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
#else /* USE_TERMIO */
- if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
+ if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
# ifdef STREAMSPTY
(void) tcsetattr(ttyfd, TCSANOW, &termbuf);
# else
@@ -504,7 +518,7 @@ int *ptynum;
p2 = &line[14];
#endif
- for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
+ for (cp = "pqrsPQRS"; *cp; cp++) {
struct stat stb;
*p1 = *cp;
@@ -516,8 +530,8 @@ int *ptynum;
*/
if (stat(line, &stb) < 0)
break;
- for (i = 0; i < 16; i++) {
- *p2 = "0123456789abcdef"[i];
+ for (i = 0; i < 32; i++) {
+ *p2 = "0123456789abcdefghijklmnopqrstuv"[i];
p = open(line, 2);
if (p > 0) {
#ifndef __hpux
@@ -947,7 +961,6 @@ tty_iscrnl()
#endif
#ifdef DECODE_BAUD
-
/*
* A table of available terminal speeds
*/
@@ -955,39 +968,14 @@ struct termspeeds {
int speed;
int value;
} termspeeds[] = {
- { 0, B0 }, { 50, B50 }, { 75, B75 },
- { 110, B110 }, { 134, B134 }, { 150, B150 },
- { 200, B200 }, { 300, B300 }, { 600, B600 },
- { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
- { 4800, B4800 },
-#ifdef B7200
- { 7200, B7200 },
-#endif
- { 9600, B9600 },
-#ifdef B14400
- { 14400, B14400 },
-#endif
-#ifdef B19200
- { 19200, B19200 },
-#endif
-#ifdef B28800
- { 28800, B28800 },
-#endif
-#ifdef B38400
- { 38400, B38400 },
-#endif
-#ifdef B57600
- { 57600, B57600 },
-#endif
-#ifdef B115200
- { 115200, B115200 },
-#endif
-#ifdef B230400
- { 230400, B230400 },
-#endif
- { -1, 0 }
+ { 0, B0 }, { 50, B50 }, { 75, B75 },
+ { 110, B110 }, { 134, B134 }, { 150, B150 },
+ { 200, B200 }, { 300, B300 }, { 600, B600 },
+ { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
+ { 4800, B4800 }, { 9600, B9600 }, { 19200, B9600 },
+ { 38400, B9600 }, { -1, B9600 }
};
-#endif /* DECODE_BUAD */
+#endif /* DECODE_BAUD */
void
tty_tspeed(val)
@@ -998,12 +986,10 @@ tty_tspeed(val)
for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
;
- if (tp->speed == -1) /* back up to last valid value */
- --tp;
cfsetospeed(&termbuf, tp->value);
-#else /* DECODE_BUAD */
+#else /* DECODE_BAUD */
cfsetospeed(&termbuf, val);
-#endif /* DECODE_BUAD */
+#endif /* DECODE_BAUD */
}
void
@@ -1015,8 +1001,6 @@ tty_rspeed(val)
for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
;
- if (tp->speed == -1) /* back up to last valid value */
- --tp;
cfsetispeed(&termbuf, tp->value);
#else /* DECODE_BAUD */
cfsetispeed(&termbuf, val);
@@ -1069,6 +1053,7 @@ extern void utmp_sig_notify P((int));
getptyslave()
{
register int t = -1;
+ char erase;
#if !defined(CRAY) || !defined(NEWINIT)
# ifdef LINEMODE
@@ -1085,12 +1070,13 @@ getptyslave()
* if linemode was turned on
* terminal window size
* terminal speed
+ * erase character
* so that we can re-set them if we need to.
*/
# ifdef LINEMODE
waslm = tty_linemode();
# endif
-
+ erase = termbuf.c_cc[VERASE];
/*
* Make sure that we don't have a controlling tty, and
@@ -1136,7 +1122,7 @@ getptyslave()
init_termbuf();
# ifdef TIOCGWINSZ
if (def_row || def_col) {
- memset((char *)&ws, 0, sizeof(ws));
+ bzero((char *)&ws, sizeof(ws));
ws.ws_col = def_col;
ws.ws_row = def_row;
(void)ioctl(t, TIOCSWINSZ, (char *)&ws);
@@ -1176,6 +1162,8 @@ getptyslave()
# endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
+ if (erase)
+ termbuf.c_cc[VERASE] = erase;
# ifdef LINEMODE
if (waslm)
tty_setlinemode(1);
@@ -1216,9 +1204,9 @@ cleanopen(line)
char *line;
{
register int t;
-#ifdef UNICOS7x
+#if defined(_SC_CRAY_SECURE_SYS)
struct secstat secbuf;
-#endif /* UNICOS7x */
+#endif /* _SC_CRAY_SECURE_SYS */
#ifndef STREAMSPTY
/*
@@ -1232,7 +1220,7 @@ cleanopen(line)
# if !defined(CRAY) && (BSD > 43)
(void) revoke(line);
# endif
-#ifdef UNICOS7x
+#if defined(_SC_CRAY_SECURE_SYS)
if (secflag) {
if (secstat(line, &secbuf) < 0)
return(-1);
@@ -1241,18 +1229,18 @@ cleanopen(line)
if (setucmp(secbuf.st_compart) < 0)
return(-1);
}
-#endif /* UNICOS7x */
+#endif /* _SC_CRAY_SECURE_SYS */
t = open(line, O_RDWR|O_NOCTTY);
-#ifdef UNICOS7x
+#if defined(_SC_CRAY_SECURE_SYS)
if (secflag) {
if (setulvl(sysv.sy_minlvl) < 0)
return(-1);
if (setucmp(0) < 0)
return(-1);
}
-#endif /* UNICOS7x */
+#endif /* _SC_CRAY_SECURE_SYS */
if (t < 0)
return(-1);
@@ -1275,8 +1263,9 @@ cleanopen(line)
(void) signal(SIGHUP, SIG_IGN);
(void) ioctl(t, TCVHUP, (char *)0);
(void) signal(SIGHUP, SIG_DFL);
+ setpgrp();
-#ifdef UNICOS7x
+#if defined(_SC_CRAY_SECURE_SYS)
if (secflag) {
if (secstat(line, &secbuf) < 0)
return(-1);
@@ -1285,18 +1274,18 @@ cleanopen(line)
if (setucmp(secbuf.st_compart) < 0)
return(-1);
}
-#endif /* UNICOS7x */
+#endif /* _SC_CRAY_SECURE_SYS */
i = open(line, O_RDWR);
-#ifdef UNICOS7x
+#if defined(_SC_CRAY_SECURE_SYS)
if (secflag) {
if (setulvl(sysv.sy_minlvl) < 0)
return(-1);
if (setucmp(0) < 0)
return(-1);
}
-#endif /* UNICOS7x */
+#endif /* _SC_CRAY_SECURE_SYS */
if (i < 0)
return(-1);
@@ -1345,11 +1334,7 @@ login_tty(t)
* setsid() call above may have set our pgrp, so clear
* it out before opening the tty...
*/
-# ifndef SOLARIS
(void) setpgrp(0, 0);
-# else
- (void) setpgrp();
-# endif
close(open(line, O_RDWR));
# endif
if (t != 0)
@@ -1544,7 +1529,7 @@ start_login(host, autologin, name)
{
register char *cp;
register char **argv;
- char **addarg();
+ char **addarg(), *user;
extern char *getenv();
#ifdef UTMPX
register int pid = getpid();
@@ -1560,7 +1545,7 @@ start_login(host, autologin, name)
* Create utmp entry for child
*/
- memset(&utmpx, 0, sizeof(utmpx));
+ bzero(&utmpx, sizeof(utmpx));
SCPYN(utmpx.ut_user, ".telnet");
SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
utmpx.ut_pid = pid;
@@ -1570,10 +1555,12 @@ start_login(host, autologin, name)
utmpx.ut_id[3] = SC_WILDC;
utmpx.ut_type = LOGIN_PROCESS;
(void) time(&utmpx.ut_tv.tv_sec);
- if (pututxline(&utmpx) == NULL)
- fatal(net, "pututxline failed");
+ if (makeutx(&utmpx) == NULL)
+ fatal(net, "makeutx failed");
#endif
+ scrub_env();
+
/*
* -h : pass on name of host.
* WARNING: -h is accepted by login if and only if
@@ -1615,19 +1602,6 @@ start_login(host, autologin, name)
#if !defined(NO_LOGIN_P)
argv = addarg(argv, "-p");
#endif
-#ifdef LINEMODE
- /*
- * Set the environment variable "LINEMODE" to either
- * "real" or "kludge" if we are operating in either
- * real or kludge linemode.
- */
- if (lmodetype == REAL_LINEMODE)
- setenv("LINEMODE", "real", 1);
-# ifdef KLUDGELINEMODE
- else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
- setenv("LINEMODE", "kludge", 1);
-# endif
-#endif
#ifdef BFTPDAEMON
/*
* Are we working as the bftp daemon? If so, then ask login
@@ -1650,6 +1624,7 @@ start_login(host, autologin, name)
if (auth_level >= 0 && autologin == AUTH_VALID) {
# if !defined(NO_LOGIN_F)
argv = addarg(argv, "-f");
+ argv = addarg(argv, "--");
argv = addarg(argv, name);
# else
# if defined(LOGIN_R)
@@ -1722,12 +1697,14 @@ start_login(host, autologin, name)
pty = xpty;
}
# else
+ argv = addarg(argv, "--");
argv = addarg(argv, name);
# endif
# endif
} else
#endif
if (getenv("USER")) {
+ argv = addarg(argv, "--");
argv = addarg(argv, getenv("USER"));
#if defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
{
@@ -1748,31 +1725,19 @@ start_login(host, autologin, name)
*/
unsetenv("USER");
}
-#ifdef SOLARIS
- else {
- char **p;
-
- argv = addarg(argv, ""); /* no login name */
- for (p = environ; *p; p++) {
- argv = addarg(argv, *p);
- }
- }
-#endif /* SOLARIS */
#if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
if (pty > 2)
close(pty);
#endif
closelog();
- /*
- * This sleep(1) is in here so that telnetd can
- * finish up with the tty. There's a race condition
- * the login banner message gets lost...
- */
- sleep(1);
- execv(_PATH_LOGIN, argv);
- syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
- fatalperror(net, _PATH_LOGIN);
+ if (altlogin == NULL) {
+ altlogin = _PATH_LOGIN;
+ }
+ execv(altlogin, argv);
+
+ syslog(LOG_ERR, "%s: %m\n", altlogin);
+ fatalperror(net, altlogin);
/*NOTREACHED*/
}
@@ -1798,7 +1763,7 @@ addarg(argv, val)
if (cpp == &argv[(int)argv[-1]]) {
--argv;
*argv = (char *)((int)(*argv) + 10);
- argv = (char **)realloc(argv, sizeof(*argv)*((int)(*argv) + 2));
+ argv = (char **)realloc(argv, (int)(*argv) + 2);
if (argv == NULL)
return(NULL);
argv++;
@@ -1811,6 +1776,31 @@ addarg(argv, val)
#endif /* NEWINIT */
/*
+ * scrub_env()
+ *
+ * Remove a few things from the environment that
+ * don't need to be there.
+ */
+scrub_env()
+{
+ register char **cpp, **cpp2;
+
+ for (cpp2 = cpp = environ; *cpp; cpp++) {
+#ifdef __FreeBSD__
+ if (strncmp(*cpp, "LD_LIBRARY_PATH=", 16) &&
+ strncmp(*cpp, "LD_PRELOAD=", 11) &&
+#else
+ if (strncmp(*cpp, "LD_", 3) &&
+ strncmp(*cpp, "_RLD_", 5) &&
+ strncmp(*cpp, "LIBPATH=", 8) &&
+#endif
+ strncmp(*cpp, "IFS=", 4))
+ *cpp2++ = *cpp;
+ }
+ *cpp2 = 0;
+}
+
+/*
* cleanup()
*
* This is the routine to call when we are all through, to
@@ -1851,8 +1841,6 @@ cleanup(sig)
# ifdef CRAY
static int incleanup = 0;
register int t;
- int child_status; /* status of child process as returned by waitpid */
- int flags = WNOHANG|WUNTRACED;
/*
* 1: Pick up the zombie, if we are being called
@@ -1863,17 +1851,9 @@ cleanup(sig)
* 5: Close down the network and pty connections.
* 6: Finish up the TMPDIR cleanup, if needed.
*/
- if (sig == SIGCHLD) {
- while (waitpid(-1, &child_status, flags) > 0)
+ if (sig == SIGCHLD)
+ while (waitpid(-1, 0, WNOHANG) > 0)
; /* VOID */
- /* Check if the child process was stopped
- * rather than exited. We want cleanup only if
- * the child has died.
- */
- if (WIFSTOPPED(child_status)) {
- return;
- }
- }
t = sigblock(sigmask(SIGCHLD));
if (incleanup) {
sigsetmask(t);
@@ -1881,7 +1861,6 @@ cleanup(sig)
}
incleanup = 1;
sigsetmask(t);
-#ifdef UNICOS7x
if (secflag) {
/*
* We need to set ourselves back to a null
@@ -1891,7 +1870,6 @@ cleanup(sig)
setulvl(sysv.sy_minlvl);
setucmp((long)0);
}
-#endif /* UNICOS7x */
t = cleantmp(&wtmp);
setutent(); /* just to make sure */
@@ -1992,28 +1970,6 @@ sigjob(sig)
}
/*
- * jid_getutid:
- * called by jobend() before calling cleantmp()
- * to find the correct $TMPDIR to cleanup.
- */
-
- struct utmp *
-jid_getutid(jid)
- int jid;
-{
- struct utmp *cur = NULL;
-
- setutent(); /* just to make sure */
- while (cur = getutent()) {
- if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
- return(cur);
- }
- }
-
- return(0);
-}
-
-/*
* Clean up the TMPDIR that login created.
* The first time this is called we pick up the info
* from the utmp. If the job has already gone away,
@@ -2069,27 +2025,9 @@ jobend(jid, path, user)
register char *user;
{
static int saved_jid = 0;
- static int pty_saved_jid = 0;
static char saved_path[sizeof(wtmp.ut_tpath)+1];
static char saved_user[sizeof(wtmp.ut_user)+1];
- /*
- * this little piece of code comes into play
- * only when ptyreconnect is used to reconnect
- * to an previous session.
- *
- * this is the only time when the
- * "saved_jid != jid" code is executed.
- */
-
- if ( saved_jid && saved_jid != jid ) {
- if (!path) { /* called from signal handler */
- pty_saved_jid = jid;
- } else {
- pty_saved_jid = saved_jid;
- }
- }
-
if (path) {
strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
strncpy(saved_user, user, sizeof(wtmp.ut_user));
@@ -2100,24 +2038,6 @@ jobend(jid, path, user)
saved_jid = jid;
return(0);
}
-
- /* if the jid has changed, get the correct entry from the utmp file */
-
- if ( saved_jid != jid ) {
- struct utmp *utp = NULL;
- struct utmp *jid_getutid();
-
- utp = jid_getutid(pty_saved_jid);
-
- if (utp == 0) {
- syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
- return(-1);
- }
-
- cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
- return(1);
- }
-
cleantmpdir(jid, saved_path, saved_user);
return(1);
}
diff --git a/libexec/telnetd/telnetd.8 b/libexec/telnetd/telnetd.8
index f618385..cb3c743 100644
--- a/libexec/telnetd/telnetd.8
+++ b/libexec/telnetd/telnetd.8
@@ -29,9 +29,10 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)telnetd.8 8.4 (Berkeley) 6/1/94
+.\" @(#)telnetd.8 8.3 (Berkeley) 3/1/94
+.\" $Id$
.\"
-.Dd June 1, 1994
+.Dd March 1, 1994
.Dt TELNETD 8
.Os BSD 4.2
.Sh NAME
@@ -48,6 +49,7 @@ protocol server
.Op Fl X Ar authtype
.Op Fl a Ar authmode
.Op Fl edebug
+.Op Fl P Ar loginprog
.Op Fl r Ns Ar lowpty-highpty
.Op Fl u Ar len
.Op Fl debug Op Ar port
@@ -187,6 +189,11 @@ If
has been compiled with support for data encryption, then the
.Fl edebug
option may be used to enable encryption debugging code.
+.It Fl P Ar loginprog
+Specifies an alternate
+.Xr login 1
+command to run to complete the login. The alternate command must
+understand the same command arguments as the standard login.
.It Fl h
Disables the printing of host-specific information before
login has been completed.
@@ -217,7 +224,7 @@ will operate in character at a time mode.
It will still support kludge linemode, but will only
go into kludge linemode if the remote client requests
it.
-(This is done by by the client sending
+(This is done by the client sending
.Dv DONT SUPPRESS-GO-AHEAD
and
.Dv DONT ECHO . )
@@ -308,7 +315,6 @@ indicates that only dotted decimal addresses
should be put into the
.Pa utmp
file.
-.ne 1i
.It Fl U
This option causes
.Nm telnetd
@@ -425,7 +431,6 @@ Whenever a
command is received, it is always responded
to with a
.Dv WILL TIMING-MARK
-.ne 1i
.It "WILL LOGOUT"
When a
.Dv DO LOGOUT
@@ -481,7 +486,7 @@ about the speed of the serial line to which
the client is attached.
.It "DO XDISPLOC"
Indicates a desire to be able to request the name
-of the X windows display that is associated with
+of the X Window System display that is associated with
the telnet client.
.It "DO NEW-ENVIRON"
Indicates a desire to be able to request environment
@@ -532,9 +537,9 @@ the data stream.
.Pa /usr/ucb/bftp
(if supported)
.Sh "SEE ALSO"
-.Xr telnet 1 ,
+.Xr bftp 1 ,
.Xr login 1 ,
-.Xr bftp 1
+.Xr telnet 1
(if supported)
.Sh STANDARDS
.Bl -tag -compact -width RFC-1572
diff --git a/libexec/telnetd/telnetd.c b/libexec/telnetd/telnetd.c
index 70c0fc0..8aafdbd 100644
--- a/libexec/telnetd/telnetd.c
+++ b/libexec/telnetd/telnetd.c
@@ -29,6 +29,8 @@
* 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: telnetd.c,v 1.10 1997/02/22 14:22:31 peter Exp $
*/
#ifndef lint
@@ -38,7 +40,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)telnetd.c 8.4 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)telnetd.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
#include "telnetd.h"
@@ -124,6 +126,7 @@ int lowpty = 0, highpty; /* low, high pty numbers */
int debug = 0;
int keepalive = 1;
char *progname;
+char *altlogin;
extern void usage P((void));
@@ -133,7 +136,7 @@ extern void usage P((void));
* passed off to getopt().
*/
char valid_opts[] = {
- 'd', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U',
+ 'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
#ifdef AUTHENTICATION
'a', ':', 'X', ':',
#endif
@@ -143,9 +146,6 @@ char valid_opts[] = {
#ifdef DIAGNOSTICS
'D', ':',
#endif
-#ifdef ENCRYPTION
- 'e', ':',
-#endif
#if defined(CRAY) && defined(NEWINIT)
'I', ':',
#endif
@@ -176,9 +176,6 @@ main(argc, argv)
pfrontp = pbackp = ptyobuf;
netip = netibuf;
nfrontp = nbackp = netobuf;
-#ifdef ENCRYPTION
- nclearto = 0;
-#endif /* ENCRYPTION */
progname = *argv;
@@ -190,7 +187,7 @@ main(argc, argv)
highpty = getnpty();
#endif /* CRAY */
- while ((ch = getopt(argc, argv, valid_opts)) != EOF) {
+ while ((ch = getopt(argc, argv, valid_opts)) != -1) {
switch(ch) {
#ifdef AUTHENTICATION
@@ -258,17 +255,6 @@ main(argc, argv)
break;
#endif /* DIAGNOSTICS */
-#ifdef ENCRYPTION
- case 'e':
- if (strcmp(optarg, "debug") == 0) {
- extern int encrypt_debug_mode;
- encrypt_debug_mode = 1;
- break;
- }
- usage();
- /* NOTREACHED */
- break;
-#endif /* ENCRYPTION */
case 'h':
hostinfo = 0;
@@ -301,6 +287,10 @@ main(argc, argv)
keepalive = 0;
break;
+ case 'p':
+ altlogin = optarg;
+ break;
+
#ifdef CRAY
case 'r':
{
@@ -451,7 +441,7 @@ main(argc, argv)
int szi = sizeof(int);
#endif /* SO_SEC_MULTI */
- memset((char *)&dv, 0, sizeof(dv));
+ bzero((char *)&dv, sizeof(dv));
if (getsysv(&sysv, sizeof(struct sysv)) != 0) {
perror("getsysv");
@@ -605,18 +595,12 @@ getterminaltype(name)
}
#endif
-#ifdef ENCRYPTION
- send_will(TELOPT_ENCRYPT, 1);
-#endif /* ENCRYPTION */
send_do(TELOPT_TTYPE, 1);
send_do(TELOPT_TSPEED, 1);
send_do(TELOPT_XDISPLOC, 1);
send_do(TELOPT_NEW_ENVIRON, 1);
send_do(TELOPT_OLD_ENVIRON, 1);
while (
-#ifdef ENCRYPTION
- his_do_dont_is_changing(TELOPT_ENCRYPT) ||
-#endif /* ENCRYPTION */
his_will_wont_is_changing(TELOPT_TTYPE) ||
his_will_wont_is_changing(TELOPT_TSPEED) ||
his_will_wont_is_changing(TELOPT_XDISPLOC) ||
@@ -624,53 +608,38 @@ getterminaltype(name)
his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
ttloop();
}
-#ifdef ENCRYPTION
- /*
- * Wait for the negotiation of what type of encryption we can
- * send with. If autoencrypt is not set, this will just return.
- */
- if (his_state_is_will(TELOPT_ENCRYPT)) {
- encrypt_wait();
- }
-#endif /* ENCRYPTION */
if (his_state_is_will(TELOPT_TSPEED)) {
static unsigned char sb[] =
{ IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
- memmove(nfrontp, sb, sizeof sb);
+ bcopy(sb, nfrontp, sizeof sb);
nfrontp += sizeof sb;
- DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
}
if (his_state_is_will(TELOPT_XDISPLOC)) {
static unsigned char sb[] =
{ IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
- memmove(nfrontp, sb, sizeof sb);
+ bcopy(sb, nfrontp, sizeof sb);
nfrontp += sizeof sb;
- DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
}
if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
static unsigned char sb[] =
{ IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
- memmove(nfrontp, sb, sizeof sb);
+ bcopy(sb, nfrontp, sizeof sb);
nfrontp += sizeof sb;
- DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
}
else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
static unsigned char sb[] =
{ IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
- memmove(nfrontp, sb, sizeof sb);
+ bcopy(sb, nfrontp, sizeof sb);
nfrontp += sizeof sb;
- DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
}
if (his_state_is_will(TELOPT_TTYPE)) {
- memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf);
+ bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
nfrontp += sizeof ttytype_sbbuf;
- DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
- sizeof ttytype_sbbuf - 2););
}
if (his_state_is_will(TELOPT_TSPEED)) {
while (sequenceIs(tspeedsubopt, baseline))
@@ -699,12 +668,14 @@ getterminaltype(name)
* we have to just go with what we (might) have already gotten.
*/
if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
- (void) strncpy(first, terminaltype, sizeof(first));
+ (void) strncpy(first, terminaltype, sizeof(first)-1);
+ first[sizeof(first)-1] = '\0';
for(;;) {
/*
* Save the unknown name, and request the next name.
*/
- (void) strncpy(last, terminaltype, sizeof(last));
+ (void) strncpy(last, terminaltype, sizeof(last)-1);
+ last[sizeof(last)-1] = '\0';
_gettermname();
if (terminaltypeok(terminaltype))
break;
@@ -722,8 +693,10 @@ getterminaltype(name)
* the start of the list.
*/
_gettermname();
- if (strncmp(first, terminaltype, sizeof(first)) != 0)
- (void) strncpy(terminaltype, first, sizeof(first));
+ if (strncmp(first, terminaltype, sizeof(first)) != 0) {
+ (void) strncpy(terminaltype, first, sizeof(terminaltype)-1);
+ terminaltype[sizeof(terminaltype)-1] = '\0';
+ }
break;
}
}
@@ -743,10 +716,8 @@ _gettermname()
if (his_state_is_wont(TELOPT_TTYPE))
return;
settimer(baseline);
- memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf);
+ bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
nfrontp += sizeof ttytype_sbbuf;
- DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
- sizeof ttytype_sbbuf - 2););
while (sequenceIs(ttypesubopt, baseline))
ttloop();
}
@@ -780,12 +751,10 @@ char *hostname;
char host_name[MAXHOSTNAMELEN];
char remote_host_name[MAXHOSTNAMELEN];
-#ifndef convex
-extern void telnet P((int, int));
-#else
extern void telnet P((int, int, char *));
-#endif
+int level;
+char user_name[256];
/*
* Get a pty, scan input lines.
*/
@@ -795,9 +764,7 @@ doit(who)
char *host, *inet_ntoa();
int t;
struct hostent *hp;
- int level;
int ptynum;
- char user_name[256];
/*
* Find an available pty to use.
@@ -844,10 +811,9 @@ doit(who)
if (hp == NULL && registerd_host_only) {
fatal(net, "Couldn't resolve your address into a host name.\r\n\
- Please contact your net administrator");
+ Please contact your net administrator");
} else if (hp &&
- (strlen(hp->h_name) <= (unsigned int)((utmp_len < 0) ? -utmp_len
- : utmp_len))) {
+ (strlen(hp->h_name) <= ((utmp_len < 0) ? -utmp_len : utmp_len))) {
host = hp->h_name;
} else {
host = inet_ntoa(who->sin_addr);
@@ -863,7 +829,7 @@ doit(who)
(void) gethostname(host_name, sizeof (host_name));
hostname = host_name;
-#if defined(AUTHENTICATION) || defined(ENCRYPTION)
+#if defined(AUTHENTICATION)
auth_encrypt_init(hostname, host, "TELNETD", 1);
#endif
@@ -875,12 +841,6 @@ doit(who)
level = getterminaltype(user_name);
setenv("TERM", terminaltype ? terminaltype : "network", 1);
- /*
- * Start up the login process on the slave side of the terminal
- */
-#ifndef convex
- startslave(host, level, user_name);
-
#if defined(_SC_CRAY_SECURE_SYS)
if (secflag) {
if (setulvl(dv.dv_actlvl) < 0)
@@ -890,10 +850,8 @@ doit(who)
}
#endif /* _SC_CRAY_SECURE_SYS */
- telnet(net, pty); /* begin server processing */
-#else
- telnet(net, pty, host);
-#endif
+ telnet(net, pty, host); /* begin server process */
+
/*NOTREACHED*/
} /* end of doit */
@@ -917,15 +875,9 @@ Xterm_output(ibufp, obuf, icountp, ocount)
* hand data to telnet receiver finite state machine.
*/
void
-#ifndef convex
-telnet(f, p)
-#else
telnet(f, p, host)
-#endif
int f, p;
-#ifdef convex
char *host;
-#endif
{
int on = 1;
#define TABBUFSIZ 512
@@ -936,7 +888,6 @@ telnet(f, p, host)
char *HN;
char *IM;
void netflush();
- int nfd;
/*
* Initialize the slc mapping table.
@@ -1162,11 +1113,13 @@ telnet(f, p, host)
{sprintf(nfrontp, "td: Entering processing loop\r\n");
nfrontp += strlen(nfrontp);});
-#ifdef convex
- startslave(host);
-#endif
+ /*
+ * Startup the login process on the slave side of the terminal
+ * now. We delay this until here to insure option negotiation
+ * is complete.
+ */
+ startslave(host, level, user_name);
- nfd = ((f > p) ? f : p) + 1;
for (;;) {
fd_set ibits, obits, xbits;
register int c;
@@ -1198,7 +1151,7 @@ telnet(f, p, host)
if (!SYNCHing) {
FD_SET(f, &xbits);
}
- if ((c = select(nfd, &ibits, &obits, &xbits,
+ if ((c = select(16, &ibits, &obits, &xbits,
(struct timeval *)0)) < 1) {
if (c == -1) {
if (errno == EINTR) {
@@ -1337,9 +1290,6 @@ telnet(f, p, host)
*nfrontp++ = IAC;
*nfrontp++ = DM;
neturg = nfrontp-1; /* off by one XXX */
- DIAG(TD_OPTIONS,
- printoption("td: send IAC", DM));
-
#endif
}
if (his_state_is_will(TELOPT_LFLOW) &&
@@ -1356,9 +1306,6 @@ telnet(f, p, host)
: LFLOW_OFF,
IAC, SE);
nfrontp += 6;
- DIAG(TD_OPTIONS, printsub('>',
- (unsigned char *)nfrontp-4,
- 4););
}
}
pcc--;
@@ -1524,14 +1471,6 @@ interrupt()
{
ptyflush(); /* half-hearted */
-#if defined(STREAMSPTY) && defined(TIOCSIGNAL)
- /* Streams PTY style ioctl to post a signal */
- {
- int sig = SIGINT;
- (void) ioctl(pty, TIOCSIGNAL, &sig);
- (void) ioctl(pty, I_FLUSH, FLUSHR);
- }
-#else
#ifdef TCSIG
(void) ioctl(pty, TCSIG, (char *)SIGINT);
#else /* TCSIG */
@@ -1539,7 +1478,6 @@ interrupt()
*pfrontp++ = slctab[SLC_IP].sptr ?
(unsigned char)*slctab[SLC_IP].sptr : '\177';
#endif /* TCSIG */
-#endif
}
/*
diff --git a/libexec/telnetd/termstat.c b/libexec/telnetd/termstat.c
index ebc843a..9cb2b63 100644
--- a/libexec/telnetd/termstat.c
+++ b/libexec/telnetd/termstat.c
@@ -29,10 +29,12 @@
* 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$
*/
#ifndef lint
-static char sccsid[] = "@(#)termstat.c 8.2 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)termstat.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include "telnetd.h"
@@ -144,25 +146,6 @@ localstat()
#endif /* defined(CRAY2) && defined(UNICOS5) */
/*
- * Check for state of BINARY options.
- */
- if (tty_isbinaryin()) {
- if (his_want_state_is_wont(TELOPT_BINARY))
- send_do(TELOPT_BINARY, 1);
- } else {
- if (his_want_state_is_will(TELOPT_BINARY))
- send_dont(TELOPT_BINARY, 1);
- }
-
- if (tty_isbinaryout()) {
- if (my_want_state_is_wont(TELOPT_BINARY))
- send_will(TELOPT_BINARY, 1);
- } else {
- if (my_want_state_is_will(TELOPT_BINARY))
- send_wont(TELOPT_BINARY, 1);
- }
-
- /*
* Check for changes to flow control if client supports it.
*/
flowstat();
@@ -181,25 +164,34 @@ localstat()
tty_setlinemode(uselinemode);
}
-#ifdef ENCRYPTION
- /*
- * If the terminal is not echoing, but editing is enabled,
- * something like password input is going to happen, so
- * if we the other side is not currently sending encrypted
- * data, ask the other side to start encrypting.
- */
- if (his_state_is_will(TELOPT_ENCRYPT)) {
- static int enc_passwd = 0;
- if (uselinemode && !tty_isecho() && tty_isediting()
- && (enc_passwd == 0) && !decrypt_input) {
- encrypt_send_request_start();
- enc_passwd = 1;
- } else if (enc_passwd) {
- encrypt_send_request_end();
- enc_passwd = 0;
- }
- }
-#endif /* ENCRYPTION */
+ if (uselinemode) {
+
+ /*
+ * Check for state of BINARY options.
+ *
+ * We only need to do the binary dance if we are actually going
+ * to use linemode. As this confuses some telnet clients that dont
+ * support linemode, and doesnt gain us anything, we dont do it
+ * unless we're doing linemode. -Crh (henrich@msu.edu)
+ */
+
+ if (tty_isbinaryin()) {
+ if (his_want_state_is_wont(TELOPT_BINARY))
+ send_do(TELOPT_BINARY, 1);
+ } else {
+ if (his_want_state_is_will(TELOPT_BINARY))
+ send_dont(TELOPT_BINARY, 1);
+ }
+
+ if (tty_isbinaryout()) {
+ if (my_want_state_is_wont(TELOPT_BINARY))
+ send_will(TELOPT_BINARY, 1);
+ } else {
+ if (my_want_state_is_will(TELOPT_BINARY))
+ send_wont(TELOPT_BINARY, 1);
+ }
+
+ }
/*
* Do echo mode handling as soon as we know what the
@@ -632,7 +624,7 @@ defer_terminit()
if (def_col || def_row) {
struct winsize ws;
- memset((char *)&ws, 0, sizeof(ws));
+ bzero((char *)&ws, sizeof(ws));
ws.ws_col = def_col;
ws.ws_row = def_row;
(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
diff --git a/libexec/telnetd/utility.c b/libexec/telnetd/utility.c
index 9553d58..2ee0d21 100644
--- a/libexec/telnetd/utility.c
+++ b/libexec/telnetd/utility.c
@@ -29,12 +29,18 @@
* 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$
*/
#ifndef lint
-static char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95";
+static char sccsid[] = "@(#)utility.c 8.2 (Berkeley) 12/15/93";
#endif /* not lint */
+#ifdef __FreeBSD__
+#include <locale.h>
+#include <sys/utsname.h>
+#endif
#define PRINTOPTIONS
#include "telnetd.h"
@@ -93,6 +99,7 @@ stilloob(s)
do {
FD_ZERO(&excepts);
FD_SET(s, &excepts);
+ memset((char *)&timeout, 0, sizeof timeout);
value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
} while ((value == -1) && (errno == EINTR));
@@ -193,11 +200,7 @@ netclear()
#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
-#ifdef ENCRYPTION
- thisitem = nclearto > netobuf ? nclearto : netobuf;
-#else /* ENCRYPTION */
thisitem = netobuf;
-#endif /* ENCRYPTION */
while ((next = nextitem(thisitem)) <= nbackp) {
thisitem = next;
@@ -205,11 +208,7 @@ netclear()
/* Now, thisitem is first before/at boundary. */
-#ifdef ENCRYPTION
- good = nclearto > netobuf ? nclearto : netobuf;
-#else /* ENCRYPTION */
good = netobuf; /* where the good bytes go */
-#endif /* ENCRYPTION */
while (nfrontp > thisitem) {
if (wewant(thisitem)) {
@@ -220,7 +219,7 @@ netclear()
next = nextitem(next);
} while (wewant(next) && (nfrontp > next));
length = next-thisitem;
- memmove(good, thisitem, length);
+ bcopy(thisitem, good, length);
good += length;
thisitem = next;
} else {
@@ -250,15 +249,6 @@ netflush()
n += strlen(nfrontp); /* get count first */
nfrontp += strlen(nfrontp); /* then move pointer */
});
-#ifdef ENCRYPTION
- if (encrypt_output) {
- char *s = nclearto ? nclearto : nbackp;
- if (nfrontp - s > 0) {
- (*encrypt_output)((unsigned char *)s, nfrontp-s);
- nclearto = nfrontp;
- }
- }
-#endif /* ENCRYPTION */
/*
* if no urgent data, or if the other side appears to be an
* old 4.2 client (and thus unable to survive TCP urgent data),
@@ -289,18 +279,11 @@ netflush()
cleanup(0);
}
nbackp += n;
-#ifdef ENCRYPTION
- if (nbackp > nclearto)
- nclearto = 0;
-#endif /* ENCRYPTION */
if (nbackp >= neturg) {
neturg = 0;
}
if (nbackp == nfrontp) {
nbackp = nfrontp = netobuf;
-#ifdef ENCRYPTION
- nclearto = 0;
-#endif /* ENCRYPTION */
}
return;
} /* end of netflush */
@@ -327,7 +310,7 @@ writenet(ptr, len)
netflush();
}
- memmove(nfrontp, ptr, len);
+ bcopy(ptr, nfrontp, len);
nfrontp += len;
} /* end of writenet */
@@ -346,16 +329,6 @@ fatal(f, msg)
char buf[BUFSIZ];
(void) sprintf(buf, "telnetd: %s.\r\n", msg);
-#ifdef ENCRYPTION
- if (encrypt_output) {
- /*
- * Better turn off encryption first....
- * Hope it flushes...
- */
- encrypt_send_end();
- netflush();
- }
-#endif /* ENCRYPTION */
(void) write(f, buf, (int)strlen(buf));
sleep(1); /*XXX*/
exit(1);
@@ -368,7 +341,7 @@ fatalperror(f, msg)
{
char buf[BUFSIZ], *strerror();
- (void) sprintf(buf, "%s: %s", msg, strerror(errno));
+ (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
fatal(f, buf);
}
@@ -433,12 +406,16 @@ putchr(cc)
*putlocation++ = cc;
}
+#ifdef __FreeBSD__
+static char fmtstr[] = { "%+" };
+#else
/*
* This is split on two lines so that SCCS will not see the M
* between two % signs and expand it...
*/
static char fmtstr[] = { "%l:%M\
%P on %A, %d %B %Y" };
+#endif
void
putf(cp, where)
@@ -449,9 +426,15 @@ putf(cp, where)
time_t t;
char db[100];
#ifdef STREAMSPTY
- extern char *strchr();
+ extern char *index();
#else
- extern char *strrchr();
+ extern char *rindex();
+#endif
+#ifdef __FreeBSD__
+ static struct utsname kerninfo;
+
+ if (!*kerninfo.sysname)
+ uname(&kerninfo);
#endif
putlocation = where;
@@ -466,9 +449,9 @@ putf(cp, where)
case 't':
#ifdef STREAMSPTY
/* names are like /dev/pts/2 -- we want pts/2 */
- slash = strchr(line+1, '/');
+ slash = index(line+1, '/');
#else
- slash = strrchr(line, '/');
+ slash = rindex(line, '/');
#endif
if (slash == (char *) 0)
putstr(line);
@@ -481,11 +464,32 @@ putf(cp, where)
break;
case 'd':
+#ifdef __FreeBSD__
+ setlocale(LC_TIME, "");
+#endif
(void)time(&t);
(void)strftime(db, sizeof(db), fmtstr, localtime(&t));
putstr(db);
break;
+#ifdef __FreeBSD__
+ case 's':
+ putstr(kerninfo.sysname);
+ break;
+
+ case 'm':
+ putstr(kerninfo.machine);
+ break;
+
+ case 'r':
+ putstr(kerninfo.release);
+ break;
+
+ case 'v':
+ putstr(kerninfo.version);
+ break;
+#endif
+
case '%':
putchr('%');
break;
@@ -522,7 +526,7 @@ printsub(direction, pointer, length)
register int i;
char buf[512];
- if (!(diagnostic & TD_OPTIONS))
+ if (!(diagnostic & TD_OPTIONS))
return;
if (direction) {
@@ -1044,99 +1048,12 @@ printsub(direction, pointer, length)
break;
#endif
-#ifdef ENCRYPTION
- case TELOPT_ENCRYPT:
- sprintf(nfrontp, "ENCRYPT");
- nfrontp += strlen(nfrontp);
- if (length < 2) {
- sprintf(nfrontp, " (empty suboption??\?)");
- nfrontp += strlen(nfrontp);
- break;
- }
- switch (pointer[1]) {
- case ENCRYPT_START:
- sprintf(nfrontp, " START");
- nfrontp += strlen(nfrontp);
- break;
-
- case ENCRYPT_END:
- sprintf(nfrontp, " END");
- nfrontp += strlen(nfrontp);
- break;
-
- case ENCRYPT_REQSTART:
- sprintf(nfrontp, " REQUEST-START");
- nfrontp += strlen(nfrontp);
- break;
-
- case ENCRYPT_REQEND:
- sprintf(nfrontp, " REQUEST-END");
- nfrontp += strlen(nfrontp);
- break;
-
- case ENCRYPT_IS:
- case ENCRYPT_REPLY:
- sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ?
- "IS" : "REPLY");
- nfrontp += strlen(nfrontp);
- if (length < 3) {
- sprintf(nfrontp, " (partial suboption??\?)");
- nfrontp += strlen(nfrontp);
- break;
- }
- if (ENCTYPE_NAME_OK(pointer[2]))
- sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2]));
- else
- sprintf(nfrontp, " %d (unknown)", pointer[2]);
- nfrontp += strlen(nfrontp);
-
- encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
- sprintf(nfrontp, "%s", buf);
- nfrontp += strlen(nfrontp);
- break;
-
- case ENCRYPT_SUPPORT:
- i = 2;
- sprintf(nfrontp, " SUPPORT ");
- nfrontp += strlen(nfrontp);
- while (i < length) {
- if (ENCTYPE_NAME_OK(pointer[i]))
- sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i]));
- else
- sprintf(nfrontp, "%d ", pointer[i]);
- nfrontp += strlen(nfrontp);
- i++;
- }
- break;
-
- case ENCRYPT_ENC_KEYID:
- sprintf(nfrontp, " ENC_KEYID", pointer[1]);
- nfrontp += strlen(nfrontp);
- goto encommon;
-
- case ENCRYPT_DEC_KEYID:
- sprintf(nfrontp, " DEC_KEYID", pointer[1]);
- nfrontp += strlen(nfrontp);
- goto encommon;
-
- default:
- sprintf(nfrontp, " %d (unknown)", pointer[1]);
- nfrontp += strlen(nfrontp);
- encommon:
- for (i = 2; i < length; i++) {
- sprintf(nfrontp, " %d", pointer[i]);
- nfrontp += strlen(nfrontp);
- }
- break;
- }
- break;
-#endif /* ENCRYPTION */
default:
if (TELOPT_OK(pointer[0]))
- sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));
+ sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));
else
- sprintf(nfrontp, "%d (unknown)", pointer[i]);
+ sprintf(nfrontp, "%d (unknown)", pointer[i]);
nfrontp += strlen(nfrontp);
for (i = 1; i < length; i++) {
sprintf(nfrontp, " %d", pointer[i]);
diff --git a/libexec/tftpd/Makefile b/libexec/tftpd/Makefile
index f94acc0..b7c600c 100644
--- a/libexec/tftpd/Makefile
+++ b/libexec/tftpd/Makefile
@@ -1,8 +1,9 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
PROG= tftpd
SRCS= tftpd.c tftpsubs.c
-MAN8= tftpd.0
+MAN8= tftpd.8
CFLAGS+=-I${.CURDIR}/../../usr.bin/tftp
.PATH: ${.CURDIR}/../../usr.bin/tftp
diff --git a/libexec/tftpd/tftpd.8 b/libexec/tftpd/tftpd.8
index 430c1c4..4a9004d 100644
--- a/libexec/tftpd/tftpd.8
+++ b/libexec/tftpd/tftpd.8
@@ -42,6 +42,7 @@ Internet Trivial File Transfer Protocol server
.Nm tftpd
.Op Fl l
.Op Fl n
+.Op Fl s Ar directory
.Op Ar directory ...
.Sh DESCRIPTION
.Nm Tftpd
@@ -87,6 +88,15 @@ names are prefixed by the one of the given directories.
The given directories are also treated as a search path for
relative filename requests.
.Pp
+The chroot option provides additional security by restricting access
+of tftpd to only a chroot'd file system. This is useful when moving
+from an OS that supported
+.Nm -s
+as a boot server. Because chroot is restricted to root, you must run
+tftpd as root. However, if you chroot, then
+.Nm tftpd
+will set its user id to nobody.
+.Pp
The options are:
.Bl -tag -width Ds
.It Fl l
@@ -95,6 +105,11 @@ Logs all requests using
.It Fl n
Suppresses negative acknowledgement of requests for nonexistent
relative filenames.
+.It Fl s Ar directory
+Causes tftpd to chroot to
+.Pa directory
+before accepting commands. In addition, the user id is set to
+nobody.
.El
.Sh SEE ALSO
.Xr tftp 1 ,
diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c
index 2c74e3d..199ec2b 100644
--- a/libexec/tftpd/tftpd.c
+++ b/libexec/tftpd/tftpd.c
@@ -29,6 +29,8 @@
* 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: tftpd.c,v 1.8 1997/03/24 06:04:08 imp Exp $
*/
#ifndef lint
@@ -52,6 +54,7 @@ static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/tftp.h>
@@ -68,6 +71,7 @@ static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
#include <string.h>
#include <syslog.h>
#include <unistd.h>
+#include <pwd.h>
#include "tftpsubs.h"
@@ -113,9 +117,11 @@ main(argc, argv)
register int n;
int ch, on;
struct sockaddr_in sin;
+ char *chroot_dir = NULL;
+ struct passwd *nobody;
openlog("tftpd", LOG_PID, LOG_FTP);
- while ((ch = getopt(argc, argv, "ln")) != EOF) {
+ while ((ch = getopt(argc, argv, "lns:")) != -1) {
switch (ch) {
case 'l':
logging = 1;
@@ -123,6 +129,9 @@ main(argc, argv)
case 'n':
suppress_naks = 1;
break;
+ case 's':
+ chroot_dir = optarg;
+ break;
default:
syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
}
@@ -140,6 +149,10 @@ main(argc, argv)
}
}
}
+ else if (chroot_dir) {
+ dirs->name = "/";
+ dirs->len = 1;
+ }
on = 1;
if (ioctl(0, FIONBIO, &on) < 0) {
@@ -203,6 +216,26 @@ main(argc, argv)
exit(0);
}
}
+
+ /*
+ * Since we exit here, we should do that only after the above
+ * recvfrom to keep inetd from constantly forking should there
+ * be a problem. See the above comment about system clogging.
+ */
+ if (chroot_dir) {
+ /* Must get this before chroot because /etc might go away */
+ if ((nobody = getpwnam("nobody")) == NULL) {
+ syslog(LOG_ERR, "nobody: no such user");
+ exit(1);
+ }
+ if (chroot(chroot_dir)) {
+ syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
+ exit(1);
+ }
+ chdir( "/" );
+ setuid(nobody->pw_uid);
+ }
+
from.sin_family = AF_INET;
alarm(0);
close(0);
@@ -375,11 +408,11 @@ validate_access(filep, mode)
/*
* Relative file name: search the approved locations for it.
- * Don't allow write requests or ones that avoid directory
+ * Don't allow write requests that avoid directory
* restrictions.
*/
- if (mode != RRQ || !strncmp(filename, "../", 3))
+ if (!strncmp(filename, "../", 3))
return (EACCESS);
/*
@@ -389,7 +422,8 @@ validate_access(filep, mode)
*/
err = ENOTFOUND;
for (dirp = dirs; dirp->name != NULL; dirp++) {
- sprintf(pathname, "%s/%s", dirp->name, filename);
+ snprintf(pathname, sizeof(pathname), "%s/%s",
+ dirp->name, filename);
if (stat(pathname, &stbuf) == 0 &&
(stbuf.st_mode & S_IFMT) == S_IFREG) {
if ((stbuf.st_mode & S_IROTH) != 0) {
@@ -402,7 +436,7 @@ validate_access(filep, mode)
return (err);
*filep = filename = pathname;
}
- fd = open(filename, mode == RRQ ? 0 : 1);
+ fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC);
if (fd < 0)
return (errno + 100);
file = fdopen(fd, (mode == RRQ)? "r":"w");
@@ -599,7 +633,7 @@ errtomsg(error)
for (pe = errmsgs; pe->e_code >= 0; pe++)
if (pe->e_code == error)
return pe->e_msg;
- sprintf(buf, "error %d", error);
+ snprintf(buf, sizeof(buf), "error %d", error);
return buf;
}
diff --git a/libexec/uucpd/Makefile b/libexec/uucpd/Makefile
index 45df1cd..9a296c9 100644
--- a/libexec/uucpd/Makefile
+++ b/libexec/uucpd/Makefile
@@ -1,6 +1,8 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
+# $Id$
PROG= uucpd
-NOMAN= noman
-
+MAN8= uucpd.8
+LDADD= -lcrypt -lutil
+DPADD= ${LIBCRYPT} ${LIBUTIL}
.include <bsd.prog.mk>
diff --git a/libexec/uucpd/pathnames.h b/libexec/uucpd/pathnames.h
index e9823ee..782f23e 100644
--- a/libexec/uucpd/pathnames.h
+++ b/libexec/uucpd/pathnames.h
@@ -31,8 +31,10 @@
* SUCH DAMAGE.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ *
+ * $Id$
*/
#include <paths.h>
-#define _PATH_UUCICO "/usr/lib/uucp/uucico"
+#define _PATH_UUCICO "/usr/libexec/uucp/uucico"
diff --git a/libexec/bugfiler/sendbug.1 b/libexec/uucpd/uucpd.8
index 31ca802..654f65e 100644
--- a/libexec/bugfiler/sendbug.1
+++ b/libexec/uucpd/uucpd.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1983, 1990, 1993
+.\" Copyright (c) 1983, 1989, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -29,57 +29,40 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)sendbug.1 8.1 (Berkeley) 6/4/93
+.\" @(#)rshd.8 8.1 (Berkeley) 6/4/93
+.\" $Id$
.\"
-.Dd June 4, 1993
-.Dt SENDBUG 1
-.Os BSD 4.2
+.Dd Feb 18, 1996
+.Dt UUCPD 8
+.Os BSD 4.4
.Sh NAME
-.Nm sendbug
-.Nd mail a system bug report to 4bsd-bugs
+.Nm uucpd
+.Nd uucp network server
.Sh SYNOPSIS
-.Nm sendbug
-.Op Ar address
+.Nm uucpd
.Sh DESCRIPTION
-Bug reports sent to `4bsd-bugs@Berkeley.EDU' are intercepted
-by a program which expects bug reports to conform to a standard format.
-.Nm Sendbug
-is a shell script to help the user compose and mail bug reports
-in the correct format.
-.Nm Sendbug
-works by invoking the editor specified by the environment variable
-.Ev EDITOR
-on a temporary copy of the bug report format outline. The user must fill in the
-appropriate fields and exit the editor.
-.Nm Sendbug
-then mails the completed report to `4bsd-bugs@Berkeley.EDU' or the
-.Ar address
-specified on the command line.
-.Sh ENVIRONMENT
-.Nm Sendbug
-will utilize the following environment variable if it exists:
-.Bl -tag -width EDITOR
-.It Ev EDITOR
-Specifies the preferred editor. If
-.Ev EDITOR
-is not set,
-.Nm
-defaults to
-.Xr vi 1 .
-.El
+.Nm Uucpd
+is the server for supporting uucp connections over networks.
+.Nm Uucpd
+listens for service requests at the port indicated in the ``uucp'' service
+specification; see
+.Xr services 5 .
+The server provides login name and password authentication before starting
+up
+.Nm uucico
+for the rest of the transaction.
+.Sh SEE ALSO
+.Xr inetd.conf 5 ,
+.Xr services 5 ,
+.Xr inetd 8 ,
+.Xr uucico 8 .
.Sh FILES
-.Bl -tag -width /usr/share/misc/bugformat -compact
-.It Pa /usr/share/misc/bugformat
-Contains the bug report outline.
+.Bl -tag -width /etc/hosts -compact
+.It Pa /etc/services
+.It Pa /etc/inetd.conf
.El
-.Sh SEE ALSO
-.Xr vi 1 ,
-.Xr environ 7 ,
-.Xr bugfiler 8 ,
-.Xr sendmail 8
.Sh HISTORY
The
-.Nm sendbug
-command
-appeared in
-.Bx 4.2 .
+.Nm uucpd
+utility first appeared in
+.Bx 4.3 .
diff --git a/libexec/uucpd/uucpd.c b/libexec/uucpd/uucpd.c
index 5b958ce..f95b388 100644
--- a/libexec/uucpd/uucpd.c
+++ b/libexec/uucpd/uucpd.c
@@ -32,6 +32,8 @@
* 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: uucpd.c,v 1.12 1997/04/08 12:32:17 davidn Exp $
*/
#ifndef lint
@@ -53,6 +55,7 @@ static char sccsid[] = "@(#)uucpd.c 8.1 (Berkeley) 6/4/93";
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -65,207 +68,186 @@ static char sccsid[] = "@(#)uucpd.c 8.1 (Berkeley) 6/4/93";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <utmp.h>
+#include <syslog.h>
+#include <sys/param.h>
#include "pathnames.h"
+#if (MAXLOGNAME-1) > UT_NAMESIZE
+#define LOGNAMESIZE UT_NAMESIZE
+#else
+#define LOGNAMESIZE (MAXLOGNAME-1)
+#endif
+
+#define SCPYN(a, b) strncpy(a, b, sizeof (a))
+
struct sockaddr_in hisctladdr;
int hisaddrlen = sizeof hisctladdr;
struct sockaddr_in myctladdr;
int mypid;
-char Username[64];
+char Username[64], Logname[64];
char *nenv[] = {
Username,
+ Logname,
NULL,
};
extern char **environ;
+extern void logwtmp(char *line, char *name, char *host);
-main(argc, argv)
-int argc;
-char **argv;
-{
-#ifndef BSDINETD
- register int s, tcp_socket;
- struct servent *sp;
-#endif !BSDINETD
- extern int errno;
- int dologout();
+void doit(struct sockaddr_in *sinp);
+void dologout(void);
+int readline(char start[], int num, int passw);
+void dologin(struct passwd *pw, struct sockaddr_in *sin);
+void main(int argc, char **argv)
+{
environ = nenv;
-#ifdef BSDINETD
close(1); close(2);
dup(0); dup(0);
hisaddrlen = sizeof (hisctladdr);
- if (getpeername(0, &hisctladdr, &hisaddrlen) < 0) {
- fprintf(stderr, "%s: ", argv[0]);
- perror("getpeername");
+ openlog("uucpd", LOG_PID, LOG_DAEMON);
+ if (getpeername(0, (struct sockaddr *)&hisctladdr, &hisaddrlen) < 0) {
+ syslog(LOG_ERR, "getpeername: %m");
_exit(1);
}
- if (fork() == 0)
- doit(&hisctladdr);
+ doit(&hisctladdr);
dologout();
- exit(1);
-#else !BSDINETD
- sp = getservbyname("uucp", "tcp");
- if (sp == NULL){
- perror("uucpd: getservbyname");
- exit(1);
- }
- if (fork())
- exit(0);
- if ((s=open(_PATH_TTY, 2)) >= 0){
- ioctl(s, TIOCNOTTY, (char *)0);
- close(s);
- }
+ exit(0);
+}
- bzero((char *)&myctladdr, sizeof (myctladdr));
- myctladdr.sin_family = AF_INET;
- myctladdr.sin_port = sp->s_port;
-#ifdef BSD4_2
- tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
- if (tcp_socket < 0) {
- perror("uucpd: socket");
- exit(1);
- }
- if (bind(tcp_socket, (char *)&myctladdr, sizeof (myctladdr)) < 0) {
- perror("uucpd: bind");
- exit(1);
- }
- listen(tcp_socket, 3); /* at most 3 simultaneuos uucp connections */
- signal(SIGCHLD, dologout);
+void badlogin(char *name, struct sockaddr_in *sin)
+{
+ char remotehost[MAXHOSTNAMELEN];
+ struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
+ sizeof (struct in_addr), AF_INET);
- for(;;) {
- s = accept(tcp_socket, &hisctladdr, &hisaddrlen);
- if (s < 0){
- if (errno == EINTR)
- continue;
- perror("uucpd: accept");
- exit(1);
- }
- if (fork() == 0) {
- close(0); close(1); close(2);
- dup(s); dup(s); dup(s);
- close(tcp_socket); close(s);
- doit(&hisctladdr);
- exit(1);
- }
- close(s);
- }
-#endif BSD4_2
+ if (hp) {
+ strncpy(remotehost, hp->h_name, sizeof (remotehost));
+ endhostent();
+ } else
+ strncpy(remotehost, inet_ntoa(sin->sin_addr),
+ sizeof (remotehost));
-#endif !BSDINETD
+ remotehost[sizeof remotehost - 1] = '\0';
+
+ syslog(LOG_NOTICE, "LOGIN FAILURE FROM %s", remotehost);
+ syslog(LOG_AUTHPRIV|LOG_NOTICE,
+ "LOGIN FAILURE FROM %s, %s", remotehost, name);
+
+ fprintf(stderr, "Login incorrect.\n");
+ exit(1);
}
-doit(sinp)
-struct sockaddr_in *sinp;
+void doit(struct sockaddr_in *sinp)
{
char user[64], passwd[64];
char *xpasswd, *crypt();
- struct passwd *pw, *getpwnam();
+ struct passwd *pw;
+ pid_t s;
+ int pwdok =0;
alarm(60);
printf("login: "); fflush(stdout);
- if (readline(user, sizeof user) < 0) {
- fprintf(stderr, "user read\n");
- return;
+ if (readline(user, sizeof user, 0) < 0) {
+ syslog(LOG_WARNING, "login read: %m");
+ _exit(1);
}
- /* truncate username to 8 characters */
- user[8] = '\0';
+ /* truncate username to LOGNAMESIZE characters */
+ user[LOGNAMESIZE] = '\0';
pw = getpwnam(user);
- if (pw == NULL) {
- fprintf(stderr, "user unknown\n");
- return;
- }
- if (strcmp(pw->pw_shell, _PATH_UUCICO)) {
- fprintf(stderr, "Login incorrect.");
- return;
- }
- if (pw->pw_passwd && *pw->pw_passwd != '\0') {
+ /*
+ * Fail after password if:
+ * 1. Invalid user
+ * 2. Shell is not uucico
+ * 3. Account has expired
+ * 4. Password is incorrect
+ */
+ if (pw != NULL && strcmp(pw->pw_shell, _PATH_UUCICO) == 0 &&
+ (!pw->pw_expire || time(NULL) >= pw->pw_expire))
+ pwdok = 1;
+ /* always ask for passwords to deter account guessing */
+ if (!pwdok || (pw->pw_passwd && *pw->pw_passwd != '\0')) {
printf("Password: "); fflush(stdout);
- if (readline(passwd, sizeof passwd) < 0) {
- fprintf(stderr, "passwd read\n");
- return;
+ if (readline(passwd, sizeof passwd, 1) < 0) {
+ syslog(LOG_WARNING, "passwd read: %m");
+ _exit(1);
}
- xpasswd = crypt(passwd, pw->pw_passwd);
- if (strcmp(xpasswd, pw->pw_passwd)) {
- fprintf(stderr, "Login incorrect.");
- return;
+ if (pwdok) {
+ xpasswd = crypt(passwd, pw->pw_passwd);
+ if (strcmp(xpasswd, pw->pw_passwd))
+ pwdok = 0;
}
+ if (!pwdok)
+ badlogin(user, sinp);
}
alarm(0);
- sprintf(Username, "USER=%s", user);
- dologin(pw, sinp);
- setgid(pw->pw_gid);
-#ifdef BSD4_2
- initgroups(pw->pw_name, pw->pw_gid);
-#endif BSD4_2
- chdir(pw->pw_dir);
- setuid(pw->pw_uid);
-#ifdef BSD4_2
- execl(UUCICO, "uucico", (char *)0);
-#endif BSD4_2
- perror("uucico server: execl");
+ sprintf(Username, "USER=%s", pw->pw_name);
+ sprintf(Logname, "LOGNAME=%s", pw->pw_name);
+ if ((s = fork()) < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ _exit(1);
+ } else if (s == 0) {
+ dologin(pw, sinp);
+ setgid(pw->pw_gid);
+ initgroups(pw->pw_name, pw->pw_gid);
+ chdir(pw->pw_dir);
+ setuid(pw->pw_uid);
+ execl(pw->pw_shell, "uucico", NULL);
+ syslog(LOG_ERR, "execl: %m");
+ _exit(1);
+ }
}
-readline(p, n)
-register char *p;
-register int n;
+int readline(char start[], int num, int passw)
{
char c;
+ register char *p = start;
+ register int n = num;
while (n-- > 0) {
if (read(0, &c, 1) <= 0)
return(-1);
c &= 0177;
- if (c == '\n' || c == '\r') {
+ if (c == '\n' || c == '\r' || c == '\0') {
+ if (p == start && passw) {
+ n++;
+ continue;
+ }
*p = '\0';
return(0);
}
+ if (c == 025) {
+ n = num;
+ p = start;
+ continue;
+ }
*p++ = c;
}
return(-1);
}
-#include <utmp.h>
-#ifdef BSD4_2
-#include <fcntl.h>
-#endif BSD4_2
-
-#define SCPYN(a, b) strncpy(a, b, sizeof (a))
-
-struct utmp utmp;
-
-dologout()
+void dologout(void)
{
union wait status;
- int pid, wtmp;
+ pid_t pid;
+ char line[32];
-#ifdef BSDINETD
while ((pid=wait((int *)&status)) > 0) {
-#else !BSDINETD
- while ((pid=wait3((int *)&status,WNOHANG,0)) > 0) {
-#endif !BSDINETD
- wtmp = open(_PATH_WTMP, O_WRONLY|O_APPEND);
- if (wtmp >= 0) {
- sprintf(utmp.ut_line, "uucp%.4d", pid);
- SCPYN(utmp.ut_name, "");
- SCPYN(utmp.ut_host, "");
- (void) time(&utmp.ut_time);
- (void) write(wtmp, (char *)&utmp, sizeof (utmp));
- (void) close(wtmp);
- }
+ sprintf(line, "uucp%ld", pid);
+ logwtmp(line, "", "");
}
}
/*
* Record login in wtmp file.
*/
-dologin(pw, sin)
-struct passwd *pw;
-struct sockaddr_in *sin;
+void dologin(struct passwd *pw, struct sockaddr_in *sin)
{
char line[32];
- char remotehost[32];
- int wtmp, f;
+ char remotehost[MAXHOSTNAMELEN];
+ int f;
+ time_t cur_time;
struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
sizeof (struct in_addr), AF_INET);
@@ -275,26 +257,19 @@ struct sockaddr_in *sin;
} else
strncpy(remotehost, inet_ntoa(sin->sin_addr),
sizeof (remotehost));
- wtmp = open(_PATH_WTMP, O_WRONLY|O_APPEND);
- if (wtmp >= 0) {
- /* hack, but must be unique and no tty line */
- sprintf(line, "uucp%.4d", getpid());
- SCPYN(utmp.ut_line, line);
- SCPYN(utmp.ut_name, pw->pw_name);
- SCPYN(utmp.ut_host, remotehost);
- time(&utmp.ut_time);
- (void) write(wtmp, (char *)&utmp, sizeof (utmp));
- (void) close(wtmp);
- }
+ remotehost[sizeof remotehost - 1] = '\0';
+ /* hack, but must be unique and no tty line */
+ sprintf(line, "uucp%ld", getpid());
+ time(&cur_time);
if ((f = open(_PATH_LASTLOG, O_RDWR)) >= 0) {
struct lastlog ll;
- time(&ll.ll_time);
- lseek(f, (long)pw->pw_uid * sizeof(struct lastlog), 0);
- strcpy(line, remotehost);
+ ll.ll_time = cur_time;
+ lseek(f, (off_t)pw->pw_uid * sizeof(struct lastlog), L_SET);
SCPYN(ll.ll_line, line);
SCPYN(ll.ll_host, remotehost);
(void) write(f, (char *) &ll, sizeof ll);
(void) close(f);
}
+ logwtmp(line, pw->pw_name, remotehost);
}
diff --git a/libexec/xtend/Makefile b/libexec/xtend/Makefile
new file mode 100644
index 0000000..d89e079
--- /dev/null
+++ b/libexec/xtend/Makefile
@@ -0,0 +1,14 @@
+# Makefile for xtend (Stark) 10/30/93
+# $Id$
+
+BINMODE= 555
+
+PROG= xtend
+SRCS= xtend.c status.c packet.c user.c
+CFLAGS+= -DXTENUNAME=\"xten\" -DXTENGNAME=\"xten\"
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+MAN8= xtend.8
+
+.include <bsd.prog.mk>
diff --git a/libexec/xtend/packet.c b/libexec/xtend/packet.c
new file mode 100644
index 0000000..ec67c94
--- /dev/null
+++ b/libexec/xtend/packet.c
@@ -0,0 +1,319 @@
+/*-
+ * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (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$
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include "xtend.h"
+#include "xten.h"
+
+char *X10housenames[] = {
+ "A", "B", "C", "D", "E", "F", "G", "H",
+ "I", "J", "K", "L", "M", "N", "O", "P",
+ NULL
+};
+
+char *X10cmdnames[] = {
+ "1", "2", "3", "4", "5", "6", "7", "8",
+ "9", "10", "11", "12", "13", "14", "15", "16",
+ "AllUnitsOff", "AllLightsOn", "On", "Off", "Dim", "Bright", "AllLightsOff",
+ "ExtendedCode", "HailRequest", "HailAcknowledge", "PreSetDim0", "PreSetDim1",
+ "ExtendedData", "StatusOn", "StatusOff", "StatusRequest",
+ NULL
+};
+
+/*
+ * Log a packet and update device status accordingly
+ */
+
+logpacket(p)
+unsigned char *p;
+{
+ fprintf(Log, "%s: %s %s ", thedate(),
+ X10housenames[p[1]], X10cmdnames[p[2]]);
+ if(p[0] & TW_RCV_LOCAL) fprintf(Log, "(loc,");
+ else fprintf(Log, "(rem,");
+ if(p[0] & TW_RCV_ERROR) fprintf(Log, "err)");
+ else fprintf(Log, " ok)");
+ fprintf(Log, "\n");
+}
+
+/*
+ * Process a received packet p, updating device status information both
+ * in core and on disk.
+ */
+
+processpacket(p)
+unsigned char *p;
+{
+ int i, j, h, k;
+ STATUS *s;
+
+ /*
+ * If the packet had the error flag set, there is no other useful info.
+ */
+ if(p[0] & TW_RCV_ERROR) return;
+ /*
+ * First update in-core status information for the device.
+ */
+ h = p[1]; k = p[2];
+ if(k < 16) { /* We received a unit code, to select a particular device */
+ s = &Status[h][k];
+ s->selected = SELECTED;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ } else { /* We received a key code, to execute some function */
+ /*
+ * Change in status depends on the key code received
+ */
+ if(k == DIM) {
+ /*
+ * We can't really track DIM/BRIGHT properly the way things are right
+ * now. The TW523 reports the first, fourth, seventh, etc. Dim packet.
+ * We don't really have any way to tell when gaps occur, to cancel
+ * selection. For now, we'll assume that successive sequences of
+ * Dim/Bright commands are never transmitted without some other
+ * intervening command, and we make a good guess about how many units of
+ * dim/bright are represented by each packet actually reported by the
+ * TW523.
+ */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ switch(s->selected) {
+ case SELECTED: /* Selected, but not being dimmed or brightened */
+ if(s->onoff == 0) {
+ s->onoff = 1;
+ s->brightness = 15;
+ }
+ s->brightness -= 2;
+ if(s->brightness < 0) s->brightness = 0;
+ s->selected = DIMMING;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case DIMMING: /* Selected and being dimmed */
+ s->brightness -=3;
+ if(s->brightness < 0) s->brightness = 0;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case BRIGHTENING: /* Selected and being brightened (an error) */
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if(k == BRIGHT) {
+ /*
+ * Same problem here...
+ */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ switch(s->selected) {
+ case SELECTED: /* Selected, but not being dimmed or brightened */
+ if(s->onoff == 0) {
+ s->onoff = 1;
+ s->brightness = 15;
+ }
+ s->brightness += 2;
+ if(s->brightness > 15) s->brightness = 15;
+ s->selected = BRIGHTENING;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case DIMMING: /* Selected and being dimmed (an error) */
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case BRIGHTENING: /* Selected and being brightened */
+ s->brightness +=3;
+ if(s->brightness > 15) s->brightness = 15;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ } else { /* Other key codes besides Bright and Dim */
+ /*
+ * We cancel brightening and dimming on ALL units on ALL house codes,
+ * because the arrival of a different packet indicates a gap that
+ * terminates any prior sequence of brightening and dimming
+ */
+ for(j = 0; j < 16; j++) {
+ for(i = 0; i < 16; i++) {
+ s = &Status[j][i];
+ if(s->selected == BRIGHTENING || s->selected == DIMMING) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ }
+ switch(k) {
+ case ALLUNITSOFF:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->brightness = 0;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ break;
+ case ALLLIGHTSON:
+ /* Does AllLightsOn cancel selectedness of non-lights? */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->devcap & ISLIGHT) {
+ s->onoff = 1;
+ s->selected = IDLE;
+ s->brightness = 15;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case UNITON:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->onoff = 1;
+ s->selected = IDLE;
+ s->brightness = 15;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case UNITOFF:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case ALLLIGHTSOFF:
+ /* Does AllLightsOff cancel selectedness of non-lights? */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->devcap & ISLIGHT) {
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case EXTENDEDCODE:
+ break;
+ case HAILREQUEST:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->selected = HAILED;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case HAILACKNOWLEDGE:
+ /* Do these commands cancel selection of devices not affected? */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == HAILED) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case PRESETDIM0:
+ case PRESETDIM1:
+ /* I don't really understand these */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case EXTENDEDDATA:
+ /* Who knows? The TW523 can't receive these anyway. */
+ break;
+ case STATUSON:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == REQUESTED) {
+ s->onoff = 1;
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case STATUSOFF:
+ for(i = 0; i < 16; i++) {
+ if(s->selected == REQUESTED) {
+ s = &Status[h][i];
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->brightness = 0;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ case STATUSREQUEST:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected) {
+ s->selected = REQUESTED;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/libexec/xtend/paths.h b/libexec/xtend/paths.h
new file mode 100644
index 0000000..e41d214
--- /dev/null
+++ b/libexec/xtend/paths.h
@@ -0,0 +1,13 @@
+/*
+ * Pathnames for files used by xtend
+ *
+ * $Id$
+ */
+
+#define X10DIR "/var/spool/xten"
+#define X10LOGNAME "Log"
+#define X10STATNAME "Status"
+#define X10DUMPNAME "status.out"
+#define TWPATH "/dev/tw0"
+#define SOCKPATH "/var/run/tw523"
+#define PIDPATH "/var/run/xtend.pid"
diff --git a/libexec/xtend/status.c b/libexec/xtend/status.c
new file mode 100644
index 0000000..e527f55
--- /dev/null
+++ b/libexec/xtend/status.c
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (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$
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+/*
+ * Initialize the status table from the status files
+ */
+
+initstatus()
+{
+ int h, i;
+
+ if(lseek(status, 0, SEEK_SET) != 0) {
+ fprintf(Log, "%s: Seek error on status file\n", thedate());
+ return;
+ }
+ if(read(status, Status, 16*16*sizeof(STATUS)) != 16*16*sizeof(STATUS)) {
+ fprintf(Log, "%s: Read error on status file\n", thedate());
+ return;
+ }
+}
+
+/*
+ * Checkpoint status of any devices whose status has changed
+ * and notify anyone monitoring those devices.
+ */
+
+checkpoint_status()
+{
+ int h, i, k, offset;
+
+ offset = 0;
+ for(h = 0; h < 16; h++) {
+ for(i = 0; i < 16; i++) {
+ if(Status[h][i].changed) {
+ if(lseek(status, offset, SEEK_SET) != offset) {
+ fprintf(Log, "%s: Seek error on status file\n", thedate());
+ } else {
+ if(write(status, &Status[h][i], sizeof(STATUS)) != sizeof(STATUS)) {
+ fprintf(Log, "%s: Write error on status file\n", thedate());
+ }
+ }
+ Status[h][i].changed = 0;
+ for(k = 0; k < MAXMON; k++) {
+ if(Monitor[k].inuse
+ && Monitor[k].house == h && Monitor[k].unit == i) {
+ /*
+ * Arrange to catch SIGPIPE in case client has gone away.
+ */
+ extern int client;
+ extern void clientgone();
+ void (*prev)();
+
+ client = k;
+ prev = signal(SIGPIPE, clientgone);
+ printstatus(Monitor[k].user, &Status[h][i]);
+ fflush(Monitor[k].user);
+ signal(SIGPIPE, prev);
+ }
+ }
+ }
+ offset += sizeof(STATUS);
+ }
+ }
+}
+
+int client;
+
+void clientgone()
+{
+ fprintf(Log, "%s: Deleting monitor table entry %d, client gone\n", thedate(), client);
+ fclose(Monitor[client].user);
+ Monitor[client].inuse = 0;
+}
diff --git a/libexec/xtend/user.c b/libexec/xtend/user.c
new file mode 100644
index 0000000..1a863af
--- /dev/null
+++ b/libexec/xtend/user.c
@@ -0,0 +1,175 @@
+/*-
+ * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (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: user.c,v 1.5 1997/02/22 14:22:42 peter Exp $
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+MONENTRY Monitor[MAXMON];
+
+/*
+ * Process a user command
+ */
+
+user_command()
+{
+ char h;
+ char *m;
+ int i, k, c, n, error;
+ char cmd[512], dumppath[MAXPATHLEN+1], pkt[3];
+ FILE *dumpf;
+
+ error = 0;
+ if(fgets(cmd, 512, User) != NULL) {
+ m = cmd;
+ while ( *m != '\0' ) {
+ if(isupper(*m))
+ *m = tolower(*m);
+ m++;
+ }
+ if(sscanf(cmd, "status %c %d", &h, &i) == 2
+ && h >= 'a' && h <= 'p' && i >= 1 && i <= 16) {
+ h -= 'a';
+ i--;
+ printstatus(User, &Status[h][i]);
+ } else if(sscanf(cmd, "send %c %s %d", &h, cmd, &n) == 3
+ && h >= 'a' && h <= 'p' && (i = find(cmd, X10cmdnames)) >= 0) {
+ h -= 'a';
+ pkt[0] = h;
+ pkt[1] = i;
+ pkt[2] = n;
+ if(write(tw523, pkt, 3) != 3) {
+ fprintf(Log, "%s: Transmission error (packet [%s %s]:%d).\n",
+ thedate(), X10housenames[h], X10cmdnames[i], n);
+ error++;
+ } else {
+ fprintf(User, "OK\n");
+ }
+ } else if(!strcmp("dump\n", cmd)) {
+ strcpy(dumppath, X10DIR);
+ strcat(dumppath, X10DUMPNAME);
+ if((dumpf = fopen(dumppath, "w")) != NULL) {
+ for(h = 0; h < 16; h++) {
+ for(i = 0; i < 16; i++) {
+ if(Status[h][i].lastchange) {
+ fprintf(dumpf, "%s%d\t", X10housenames[h], i+1);
+ printstatus(dumpf, &Status[h][i]);
+ }
+ }
+ }
+ fclose(dumpf);
+ fprintf(User, "OK\n");
+ } else {
+ error++;
+ }
+ } else if(sscanf(cmd, "monitor %c %d", &h, &i) == 2
+ && h >= 'a' && h <= 'p' && i >= 1 && i <= 16) {
+ h -= 'a';
+ i--;
+ for(k = 0; k < MAXMON; k++) {
+ if(!Monitor[k].inuse) break;
+ }
+ if(k == MAXMON) {
+ error++;
+ } else {
+ Monitor[k].house = h;
+ Monitor[k].unit = i;
+ Monitor[k].user = User;
+ Monitor[k].inuse = 1;
+ fprintf(Log, "%s: Adding %c %d to monitor list (entry %d)\n",
+ thedate(), h+'A', i+1, k);
+ fprintf(User, "OK\n");
+ fflush(User);
+ User = NULL;
+ return(0); /* We don't want caller to close stream */
+ }
+ } else if(!strcmp("done\n", cmd)) {
+ fprintf(User, "OK\n");
+ fflush(User);
+ return(1);
+ } else {
+ if(feof(User)) {
+ return(1);
+ } else {
+ error++;
+ }
+ }
+ } else {
+ error++;
+ }
+ if(error) {
+ fprintf(User, "ERROR\n");
+ }
+ fflush(User);
+ return(0);
+}
+
+find(s, tab)
+char *s;
+char *tab[];
+{
+ int i;
+
+ for(i = 0; tab[i] != NULL; i++) {
+ if(strcasecmp(s, tab[i]) == 0) return(i);
+ }
+ return(-1);
+}
+
+printstatus(f, s)
+FILE *f;
+STATUS *s;
+{
+ fprintf(f, "%s:%d", s->onoff ? "On" : "Off", s->brightness);
+ switch(s->selected) {
+ case IDLE:
+ fprintf(f, " (normal) "); break;
+ case SELECTED:
+ fprintf(f, " (selected) "); break;
+ case DIMMING:
+ fprintf(f, " (dimming) "); break;
+ case BRIGHTENING:
+ fprintf(f, " (brightening) "); break;
+ case REQUESTED:
+ fprintf(f, " (requested) "); break;
+ case HAILED:
+ fprintf(f, " (hailed) "); break;
+ default:
+ fprintf(f, " (bogus) "); break;
+ }
+ fprintf(f, "%s", ctime(&s->lastchange));
+}
+
diff --git a/libexec/xtend/xten.h b/libexec/xtend/xten.h
new file mode 100644
index 0000000..23e8c6b
--- /dev/null
+++ b/libexec/xtend/xten.h
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (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$
+ */
+
+extern char *X10housenames[];
+extern char *X10cmdnames[];
+
+#define ALLUNITSOFF 16
+#define ALLLIGHTSON 17
+#define UNITON 18
+#define UNITOFF 19
+#define DIM 20
+#define BRIGHT 21
+#define ALLLIGHTSOFF 22
+#define EXTENDEDCODE 23
+#define HAILREQUEST 24
+#define HAILACKNOWLEDGE 25
+#define PRESETDIM0 26
+#define PRESETDIM1 27
+#define EXTENDEDDATA 28
+#define STATUSON 29
+#define STATUSOFF 30
+#define STATUSREQUEST 31
+
+/*
+ * Flags for first byte of received packet
+ */
+
+#define TW_RCV_LOCAL 1 /* The packet arrived during a local transmission */
+#define TW_RCV_ERROR 2 /* An invalid/corrupted packet was received */
+
diff --git a/libexec/xtend/xtend.8 b/libexec/xtend/xtend.8
new file mode 100644
index 0000000..fe6209b
--- /dev/null
+++ b/libexec/xtend/xtend.8
@@ -0,0 +1,176 @@
+.\" Copyright (c) 1992, 1993 Eugene W. Stark
+.\" 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 Eugene W. Stark.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (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: xtend.8,v 1.6 1997/02/22 14:22:43 peter Exp $
+.\"
+.Th XTEND 8 "30 Oct 1993"
+.Dd Oct 30, 1993
+.Dt XTEND 8
+.Os BSD FreeBSD
+.Sh NAME
+xtend \- X-10 daemon
+.Sh SYNOPSIS
+.Nm xtend
+.Sh DESCRIPTION
+.Nm Xtend
+interfaces between user-level programs and the TW523 X-10 controller.
+It logs all packets received from the TW523, attempts to track the
+status of all X-10 devices, and accepts socket connections from user-level
+client programs that need to manipulate X-10 devices.
+.Pp
+When
+.Nm xtend
+is started, it forks, releases the controlling terminal, then opens
+its log file, where it subsequently records all X-10 activity and
+diagnostic messages. It then begins processing packets received from
+the TW523 and accepting connections one at a time from clients
+wishing to issue X-10 commands. The usual place to start xtend would
+be from the
+.Pa /etc/rc.local
+startup script.
+.Pp
+Sending
+.Nm xtend
+a SIGHUP causes it to close and reopen its log file. This is useful
+in shell scripts that rotate the log files to keep them from growing
+indefinitely.
+If
+.Nm xtend
+receives a SIGTERM, it shuts down gracefully and exits.
+A SIGPIPE causes
+.Nm xtend
+to abort the current client connection.
+.Pp
+.Nm Xtend
+communicates with client processes by a simple protocol in which a one-line
+command is sent by the client, and is acknowledged by a one-line response
+from the daemon.
+.Pp
+.Nm Xtend
+understands four types of commands. The command
+.Bl -tag
+.It status H U
+.El
+.Pp
+where H is a single letter house code, and U is a numeric unit code,
+causes
+.Nm xtend
+to respond with one line of status information about the specified device.
+The command
+.Bl -tag
+.It send H U N
+.El
+.Pp
+where H is a single-letter house code, U is either a numeric unit code
+or a function code (see source file
+.Pa xtend/packet.c
+) for a list, and N is a number indicating the number of times (usually 2)
+the packet is to be transmitted without gaps,
+causes
+.Nm xtend
+to perform the specified X-10 transmission. If the transmission was apparently
+successful, a single-line response containing
+.B
+OK
+is issued, otherwise a single-line response containing
+.B
+ERROR
+is produced.
+The command
+.Bl -tag
+.It dump
+.El
+.Pp
+causes
+.Nm xtend
+to dump the current status of all devices to an ASCII file in the spool
+directory. The response
+.B
+OK
+is issued, regardless of whether the status dump was successful.
+The command
+.Bl -tag
+.It monitor H U
+.El
+.Pp
+causes
+.Nm xtend
+to add the current client socket connection to a list of clients that are to
+be notified about activity concerning the specified X-10 device.
+The single-line acknowledgement
+.B
+OK
+is returned if the maximum (currently 5) number of such clients was not
+exceeded, otherwise
+.B
+ERROR
+is returned.
+.Nm Xtend
+then returns to its normal mode of accepting connections from clients.
+However, each subsequent change in the status of the specified device will
+cause
+.Nm xtend
+to write one line of status information for the device (in the same
+format as produced by the
+.B
+status
+command) to the saved socket. This feature is useful for writing programs
+that need to monitor the activity of devices, like motion detectors, that can
+perform X-10 transmissions.
+.Sh OPTIONS
+None.
+.Sh SEE ALSO
+.Xr xten 1 ,
+.Xr tw 4
+.Sh FILES
+.Bl -tag -width /var/spool/xten/Status -compact
+.It Pa /dev/tw0
+the TW523 special file
+.It Pa /var/run/tw523
+socket for client connections
+.It Pa /var/run/xtend.pid
+pid file
+.It Pa /var/spool/xten/Log
+log file
+.It Pa /var/spool/xten/Status
+device status file (binary)
+.It Pa /var/spool/xten/status.out
+ASCII dump of device status
+.El
+.Sh BUGS
+There is currently no timeout on client socket connections, so a hung
+client program can prevent other clients from accessing the daemon.
+.Pp
+.Nm Xtend
+does the best it can at trying to track device status, but there is
+usually no way it can tell when a device has been operated manually.
+This is due to the fact that most X-10 devices are not able to
+respond to queries about their status.
+.Sh AUTHOR
+Eugene W. Stark (stark@cs.sunysb.edu)
diff --git a/libexec/xtend/xtend.c b/libexec/xtend/xtend.c
new file mode 100644
index 0000000..dd32129
--- /dev/null
+++ b/libexec/xtend/xtend.c
@@ -0,0 +1,370 @@
+/*-
+ * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (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$
+ */
+
+/*
+ * xtend - X-10 daemon
+ * Eugene W. Stark (stark@cs.sunysb.edu)
+ * January 14, 1993
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+FILE *Log; /* Log file */
+FILE *User; /* User connection */
+STATUS Status[16][16]; /* Device status table */
+int status; /* Status file descriptor */
+int tw523; /* tw523 controller */
+int sock; /* socket for user */
+jmp_buf mainloop; /* longjmp point after SIGHUP */
+void onhup(); /* SIGHUP handler */
+void onterm(); /* SIGTERM handler */
+void onpipe(); /* SIGPIPE handler */
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char *twpath = TWPATH;
+ char *sockpath = SOCKPATH;
+ char logpath[MAXPATHLEN+1];
+ char statpath[MAXPATHLEN+1];
+ struct sockaddr_un sa;
+ struct timeval tv;
+ struct passwd *pw;
+ struct group *gr;
+ struct stat sb;
+ int user;
+ int fd;
+ FILE *pidf;
+
+ /*
+ * Make sure we start out running as root
+ */
+ if(geteuid() != 0) {
+ fprintf(stderr, "You must be root to run %s\n", argv[0]);
+ exit(1);
+ }
+
+ /*
+ * Find out what UID/GID we are to run as
+ */
+ if((pw = getpwnam(XTENUNAME)) == NULL) {
+ fprintf(stderr, "%s: No such user '%s'\n", argv[0], XTENUNAME);
+ exit(1);
+ }
+ if((gr = getgrnam(XTENGNAME)) == NULL) {
+ fprintf(stderr, "%s: No such group '%s'\n", argv[0], XTENGNAME);
+ exit(1);
+ }
+
+ /*
+ * Open the log file before doing anything else
+ */
+ strcpy(logpath, X10DIR);
+ if(stat(logpath, &sb) == -1 && errno == ENOENT) {
+ if(mkdir(logpath, 0755) != -1) {
+ chown(logpath, pw->pw_uid, gr->gr_gid);
+ } else {
+ fprintf(stderr, "%s: Can't create directory '%s'\n", argv[0], logpath);
+ exit(1);
+ }
+ }
+ strcat(logpath, "/");
+ strcat(logpath, X10LOGNAME);
+ if((Log = fopen(logpath, "a")) == NULL) {
+ fprintf(stderr, "Can't open log file %s\n", logpath);
+ exit(1);
+ }
+ chown(logpath, pw->pw_uid, gr->gr_gid);
+
+ /*
+ * Become a daemon
+ */
+ if(daemon(0, 0) == -1) {
+ fprintf(Log, "%s: Unable to become a daemon\n", thedate());
+ fclose(Log);
+ exit(1);
+ }
+ fprintf(Log, "%s: %s [%d] started\n", thedate(), argv[0], getpid());
+
+ /*
+ * Get ahold of the TW523 device
+ */
+ if((tw523 = open(twpath, O_RDWR)) < 0) {
+ fprintf(Log, "%s: Can't open %s\n", thedate(), twpath);
+ fclose(Log);
+ exit(1);
+ }
+ fprintf(Log, "%s: %s successfully opened\n", thedate(), twpath);
+
+ /*
+ * Put our pid in a file so we can be signalled by shell scripts
+ */
+ if((pidf = fopen(PIDPATH, "w")) == NULL) {
+ fprintf(Log, "%s: Error writing pid file: %s\n", thedate(), PIDPATH);
+ fclose(Log);
+ exit(1);
+ }
+ fprintf(pidf, "%d\n", getpid());
+ fclose(pidf);
+
+ /*
+ * Set up socket to accept user commands
+ */
+ if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ fprintf(Log, "%s: Can't create socket\n", thedate());
+ fclose(Log);
+ exit(1);
+ }
+ strcpy(sa.sun_path, sockpath);
+ sa.sun_family = AF_UNIX;
+ unlink(sockpath);
+ if(bind(sock, (struct sockaddr *)(&sa), strlen(sa.sun_path) + 2) < 0) {
+ fprintf(Log, "%s: Can't bind socket to %s\n", thedate(), sockpath);
+ fclose(Log);
+ exit(1);
+ }
+ if(listen(sock, 5) < 0) {
+ fprintf(Log, "%s: Can't listen on socket\n", thedate());
+ fclose(Log);
+ exit(1);
+ }
+
+ /*
+ * Set proper ownership and permissions on the socket
+ */
+ if(chown(sockpath, pw->pw_uid, gr->gr_gid) == -1 ||
+ chmod(sockpath, 0660) == -1) {
+ fprintf(Log, "%s: Can't set owner/permissions on socket\n", thedate());
+ fclose(Log);
+ exit(1);
+ }
+
+ /*
+ * Give up root privileges
+ */
+ setgid(pw->pw_gid);
+ setuid(pw->pw_uid);
+
+ /*
+ * Initialize the status table
+ */
+ strcpy(statpath, X10DIR);
+ strcat(statpath, "/");
+ strcat(statpath, X10STATNAME);
+ if((status = open(statpath, O_RDWR)) < 0) {
+ if((status = open(statpath, O_RDWR | O_CREAT, 0666)) < 0) {
+ fprintf(Log, "%s: Can't open %s\n", thedate(), statpath);
+ fclose(Log);
+ exit(1);
+ }
+ if(write(status, Status, 16 * 16 * sizeof(STATUS))
+ != 16 * 16 * sizeof(STATUS)) {
+ fprintf(Log, "%s: Error initializing status file\n", thedate());
+ fclose(Log);
+ exit(1);
+ }
+ }
+ initstatus();
+
+ /*
+ * Return here on SIGHUP after closing and reopening log file.
+ * Also on SIGPIPE after closing user connection.
+ */
+ signal(SIGTERM, onterm);
+ signal(SIGHUP, onhup);
+ signal(SIGPIPE, onpipe);
+ setjmp(mainloop);
+
+ /*
+ * Now start the main processing loop.
+ */
+ tv.tv_sec = 0;
+ tv.tv_usec = 250000;
+ while(1) {
+ fd_set fs;
+ unsigned char rpkt[3];
+ int sel, h, k;
+ STATUS *s;
+
+ FD_ZERO(&fs);
+ FD_SET(tw523, &fs);
+ if(User != NULL) FD_SET(user, &fs);
+ else FD_SET(sock, &fs);
+ sel = select(FD_SETSIZE, &fs, 0, 0, &tv);
+ if(sel == 0) {
+ /*
+ * Cancel brightening and dimming on ALL units on ALL house codes,
+ * because the fact that we haven't gotten a packet for awhile means
+ * that there was a gap in transmission.
+ */
+ for(h = 0; h < 16; h++) {
+ for(k = 0; k < 16; k++) {
+ s = &Status[h][k];
+ if(s->selected == BRIGHTENING || s->selected == DIMMING) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ }
+ fflush(Log);
+ checkpoint_status();
+ /*
+ * Now that we've done this stuff, we'll set the timeout a little
+ * longer, so we don't keep looping too frequently.
+ */
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ continue;
+ }
+ /*
+ * While there is stuff happening, we keep a short timeout, so we
+ * don't get stuck for some unknown reason, and so we can keep the
+ * brightening and dimming data up-to-date.
+ */
+ tv.tv_sec = 0;
+ tv.tv_usec = 250000;
+ if(FD_ISSET(tw523, &fs)) { /* X10 data arriving from TW523 */
+ if(read(tw523, rpkt, 3) < 3) {
+ fprintf(Log, "%s: Error reading from TW523\n", thedate());
+ } else {
+ logpacket(rpkt);
+ processpacket(rpkt);
+ }
+ } else if(FD_ISSET(user, &fs)) {
+ if(User != NULL) {
+ if(user_command()) {
+ fprintf(Log, "%s: Closing user connection\n", thedate());
+ fclose(User);
+ User = NULL;
+ }
+ } else {
+ /* "Can't" happen */
+ }
+ } else if(FD_ISSET(sock, &fs)) { /* Accept a connection */
+ if (User == NULL) {
+ int len = sizeof(struct sockaddr_un);
+ if((user = accept(sock, (struct sockaddr *)(&sa), &len)) >= 0) {
+ fprintf(Log, "%s: Accepting user connection\n", thedate());
+ if((User = fdopen(user, "w+")) == NULL) {
+ fprintf(Log, "%s: Can't attach socket to stream\n", thedate());
+ }
+ } else {
+ fprintf(Log, "%s: Failure in attempt to accept connection\n", thedate());
+ }
+ } else {
+ /* "Can't happen */
+ }
+ }
+ }
+ /* Not reached */
+}
+
+char *thedate()
+{
+ char *cp, *cp1;
+ time_t tod;
+
+ tod = time(NULL);
+ cp = cp1 = ctime(&tod);
+ while(*cp1 != '\n') cp1++;
+ *cp1 = '\0';
+ return(cp);
+}
+
+/*
+ * When SIGHUP received, close and reopen the Log file
+ */
+
+void onhup()
+{
+ char logpath[MAXPATHLEN+1];
+
+ fprintf(Log, "%s: SIGHUP received, reopening Log\n", thedate());
+ fclose(Log);
+ strcpy(logpath, X10DIR);
+ strcat(logpath, "/");
+ strcat(logpath, X10LOGNAME);
+ if((Log = fopen(logpath, "a")) == NULL) {
+ fprintf(stderr, "Can't open log file %s\n", logpath);
+ exit(1);
+ }
+ longjmp(mainloop, 1);
+ /* No return */
+}
+
+/*
+ * When SIGTERM received, just exit normally
+ */
+
+void onterm()
+{
+ fprintf(Log, "%s: SIGTERM received, shutting down\n", thedate());
+ fclose(Log);
+ exit(0);
+}
+
+/*
+ * When SIGPIPE received, reset user connection
+ */
+
+void onpipe()
+{
+ fprintf(Log, "%s: SIGPIPE received, resetting user connection\n",
+ thedate());
+ if(User != NULL) {
+ fclose(User);
+ User = NULL;
+ }
+ longjmp(mainloop, 1);
+ /* No return */
+}
diff --git a/libexec/xtend/xtend.h b/libexec/xtend/xtend.h
new file mode 100644
index 0000000..9d70444
--- /dev/null
+++ b/libexec/xtend/xtend.h
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (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$
+ */
+
+/*
+ * Device capabilities
+ */
+
+#define ISLIGHT 1 /* Is device a light? */
+#define CANQUERY 2 /* Responds to status query */
+
+/*
+ * Device status
+ */
+
+typedef enum {
+ IDLE,
+ SELECTED,
+ DIMMING,
+ BRIGHTENING,
+ REQUESTED,
+ HAILED
+ } SELECT;
+
+typedef struct {
+ unsigned int devcap; /* device capabilities */
+ unsigned int changed; /* status changed since last checkpoint? */
+ time_t lastchange; /* time status last changed */
+ SELECT selected; /* select status of device */
+ unsigned int onoff; /* nonzero if on */
+ unsigned int brightness; /* value in range 0-15 */
+} STATUS;
+
+typedef struct {
+ int inuse; /* Is entry in use? */
+ FILE *user; /* Socket to notify user */
+ int house; /* House code of device to monitor */
+ int unit; /* Unit code of device to monitor */
+} MONENTRY;
+
+#define MAXMON 5 /* Maximum number of monitor entries */
+
+extern FILE *Log; /* Log file */
+extern FILE *User; /* User connection */
+extern STATUS Status[16][16]; /* Device status table */
+extern int status; /* Status file descriptor */
+extern int tw523; /* tw523 controller */
+extern MONENTRY Monitor[MAXMON];/* Monitor table */
+
+extern char *thedate();
diff --git a/libexec/ypxfr/Makefile b/libexec/ypxfr/Makefile
new file mode 100644
index 0000000..61a59c7
--- /dev/null
+++ b/libexec/ypxfr/Makefile
@@ -0,0 +1,41 @@
+# $Id$
+
+PROG= ypxfr
+SRCS= ypxfr_clnt.c yp_clnt.c ypxfr_getmap.c yp_dblookup.c \
+ yp_error.c ypxfr_misc.c ypxfr_main.c yp_dbwrite.c \
+ ypxfrd_getmap.c
+
+.PATH: ${.CURDIR}/../../usr.sbin/ypserv
+
+MAN8= ypxfr.8
+
+CFLAGS+= -I.
+DPADD= ${LIBRPCSVC}
+LDADD= -lrpcsvc
+
+CLEANFILES= yp.h yp_clnt.c ypxfr_clnt.c
+
+RPCDIR= ${.CURDIR}/../../include/rpcsvc
+RPCGEN= rpcgen -I -C
+
+ypxfr_clnt.c: ${RPCDIR}/yp.x yp.h
+ rm -f ${.TARGET}
+ ${RPCGEN} -DYPPUSH_ONLY -l -o ${.TARGET} ${RPCDIR}/yp.x
+
+yp_clnt.c: ${RPCDIR}/yp.x yp.h
+ rm -f ${.TARGET}
+ ${RPCGEN} -DYPSERV_ONLY -l -o ${.TARGET} ${RPCDIR}/yp.x
+
+yp.h: ${RPCDIR}/yp.x
+ rm -f ${.TARGET}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCDIR}/yp.x
+
+# ypxfrd_xdr.c: ${RPCDIR}/ypxfrd.x ypxfrd.h
+# rm -f ${.TARGET}
+# ${RPCGEN} -c -o ${.TARGET} ${RPCDIR}/ypxfrd.x
+
+ypxfrd.h: ${RPCDIR}/ypxfrd.x
+ rm -f ${.TARGET}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCDIR}/ypxfrd.x
+
+.include <bsd.prog.mk>
diff --git a/libexec/ypxfr/yp_dbwrite.c b/libexec/ypxfr/yp_dbwrite.c
new file mode 100644
index 0000000..e5ad7fd
--- /dev/null
+++ b/libexec/ypxfr/yp_dbwrite.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <db.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <paths.h>
+#include <rpcsvc/yp.h>
+#include "ypxfr_extern.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#define PERM_SECURE (S_IRUSR|S_IWUSR)
+
+/*
+ * Open a DB database read/write
+ */
+DB *yp_open_db_rw(domain, map, flags)
+ const char *domain;
+ const char *map;
+ const int flags;
+{
+ DB *dbp;
+ char buf[1025];
+
+
+ yp_errno = YP_TRUE;
+
+ if (map[0] == '.' || strchr(map, '/')) {
+ yp_errno = YP_BADARGS;
+ return (NULL);
+ }
+
+#define FLAGS O_RDWR|O_EXLOCK|O_EXCL|O_CREAT
+
+ snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, domain, map);
+ dbp = dbopen(buf,flags ? flags : FLAGS,PERM_SECURE,DB_HASH,&openinfo);
+
+ if (dbp == NULL) {
+ switch(errno) {
+ case ENOENT:
+ yp_errno = YP_NOMAP;
+ break;
+ case EFTYPE:
+ yp_errno = YP_BADDB;
+ break;
+ default:
+ yp_errno = YP_YPERR;
+ break;
+ }
+ }
+
+ return (dbp);
+}
+
+int yp_put_record(dbp,key,data,allow_overwrite)
+ DB *dbp;
+ DBT *key;
+ DBT *data;
+ int allow_overwrite;
+{
+ int rval;
+
+ if ((rval = (dbp->put)(dbp,key,data, allow_overwrite ? 0 :
+ R_NOOVERWRITE))) {
+ switch(rval) {
+ case 1:
+ return(YP_FALSE);
+ break;
+ case -1:
+ default:
+ (void)(dbp->close)(dbp);
+ return(YP_BADDB);
+ break;
+ }
+ }
+
+ return(YP_TRUE);
+}
diff --git a/libexec/ypxfr/ypxfr.8 b/libexec/ypxfr/ypxfr.8
new file mode 100644
index 0000000..3dd4a0f
--- /dev/null
+++ b/libexec/ypxfr/ypxfr.8
@@ -0,0 +1,231 @@
+.\" Copyright (c) 1995
+.\" Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd February 5, 1995
+.Dt YPXFR 8
+.Os
+.Sh NAME
+.Nm ypxfr
+.Nd "transfer NIS database from remote server to local host"
+.Sh SYNOPSIS
+.Nm ypxfr
+.Op Fl f
+.Op Fl c
+.Op Fl d Ar target domain
+.Op Fl h Ar source host
+.Op Fl s Ar source domain
+.Op Fl p Ar path
+.Op Fl C Ar taskid program-number ipaddr port
+.Ar mapname
+.Sh DESCRIPTION
+.Nm ypxfr
+copies an NIS database (or
+.Pa map )
+from one NIS server to another using NIS services. In FreeBSD,
+.Nm ypxfr
+is generally invoked by
+.Xr ypserv 8
+when it receives a map transfer request from
+.Xr yppush 8 .
+.Nm ypxfr
+is used primarily in environments where several NIS servers
+are in use in a single domain. One server, the NIS master, maintains
+the canonical copies of all NIS maps, and all the other servers,
+the NIS slaves, copy new versions of the maps from the master whenever
+any updates are made (i.e. when a user updates their password via
+.Xr yppasswd 1
+).
+.Pp
+When run,
+.Nm ypxfr
+creates a temporary database file in
+.Pa /var/yp/[domainmame] ,
+and fills it with the contents of
+.Ar mapname
+as supplied by the specified
+.Ar source host .
+When the entire map has been transfered,
+.Nm ypxfr
+deletes the original copy of
+.Ar mapname
+and moves the temporary copy into its place. When the transfer is
+complete,
+.Nm ypxfr
+will attempt to send a 'clear current map' request to the local
+.Xr ypserv 8
+process to clear any possible references it may still have to the
+stale map.
+.Pp
+Note that all files created by
+.Nm ypxfr
+are owner readable and writable only for security reasons. Since the
+NIS maps and the directory in which they reside are normally owned by
+root, this prevents non-privleged users from making unauthorized
+modifications.
+.Pp
+In order to maintain consistency across all NIS servers,
+.Nm ypxfr
+can be run periodically in a
+.Xr cron 8
+job. Maps which change infrequently
+need only be updated once a day (preferably late at night when system
+usage is lowest), whereas those that are subject to frequent changes
+(such a
+.Pa passwd.byname
+and
+.Pa passwd.byuid )
+should be updated perhaps once every hour. Using
+.Xr cron 8
+to automatically
+update the NIS maps is not strictly mandatory since all updates should
+be propagated by
+.Xr yppush 8
+when
+.Pa /var/yp/Makefile
+is run on the NIS master server, however it is good practice
+on large networks where possible outages could cause NIS servers to
+fall out of sync with each other.
+.Pp
+When
+.Nm ypxfr
+is invoked without a controlling terminal, e.g. from inside
+.Xr ypserv 8 ,
+it logs all its output using the
+.Xr syslog 3
+facility.
+.Sh NOTES
+The FreeBSD version of
+.Nm ypxfr
+has support for a special map transfer protocol which works in
+conjunction with the FreeBSD
+.Xr rpc.ypxfrd 8
+server. This protocol allows it to transfer raw map database files from
+the NIS master server and can be many times faster than the standard
+transfer method, particularly for very large NIS maps. The
+.Nm ypxfr
+command will check to see if the
+.Xr rpc.ypxfrd 8
+server is registered on the NIS master server and attempt to use
+it if it is present. If it isn't it will fall back to the standard
+transfer method, copying the map contents from
+.Xr ypserv 8
+and creating new maps instead.
+.Pp
+Note that while the FreeBSD ypxfrd protocol is conceptually similar
+to the SunOS ypxfrd protocol, FreeBSD's protocol is not compatible with
+Sun's, therefore it will not work with Sun's ypxfrd server. FreeBSD
+slave systems can still transfer maps from any non-FreeBSD NIS server,
+however they will only be able to take advantage of the faster protocol
+if the master server is also running FreeBSD.
+.Sh OPTIONS
+The following options and flags are supported by
+.Nm ypxfr :
+.Bl -tag -width flag
+.It Fl f
+Force a map transfer. Normally,
+.Nm ypxfr
+will not transfer a map if it determines that the NIS master's copy
+is not newer than the existing copy already on the local host: the
+.Fl f
+flag forces a transfer regardless of which server's version is more recent.
+.It Fl c
+Do not send a 'clear current map' request to the
+.Xr ypserv 8
+process running on the local host. This flag is normally used when
+invoking
+.Nm ypxfr
+manually on a machine that is not yet running
+.Xr ypserv 8 .
+Without this flag, failure to contact the local NIS server will cause
+.Nm ypxfr
+to abort the transfer.
+.It Fl d Ar target domain
+Specify a target domain other than the current NIS domain.
+.It Fl h Ar source host
+Specify the name of the host from which to copy the NIS maps. This option
+is used to insure that
+.Nm ypxfr
+only copies maps from the NIS master server.
+.It Fl s Ar source domain
+Specify the domain from which to transfer a map, in the event that
+the transfer is being done across two different NIS domains.
+.It Fl p Ar path
+Specify the top level directory containing the NIS maps. By
+default, this path is
+.Pa /var/yp .
+The
+.Fl p
+flag allows you to specify an alternate path should you wish to
+store your NIS maps in a different part of the filesystem. The
+NIS server,
+.Xr ypserv 8 ,
+passes this flag to
+.Nm ypxfr
+if it too has been told to use an alternate path.
+.It Fl C Ar taskid program-number ipaddr port
+These options are used only when
+.Nm ypxfr
+is invoked by
+.Xr ypserv 8
+in response to a map transfer request initiated by
+.Xr yppush 8 .
+In this instance,
+.Nm ypxfr
+needs to 'callback' to the
+.Xr yppush 8
+process and interact with it, so
+.Xr yppush 8
+passes to it an IP address
+.Ar ipaddr ,
+port number
+.Ar port ,
+registered program number
+.Ar program-number
+and a transaction ID
+.Ar taskid
+that it can use to contact the waiting
+.Xr yppush 8
+process on the master server.
+.It Ar mapname
+The name of the map to transfer.
+.El
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /var/yp/[domainname]/[maps]
+The NIS maps for a particular NIS domain.
+.El
+.Sh SEE ALSO
+.Xr yp 4 ,
+.Xr yppush 8 ,
+.Xr ypserv 8
+.Sh AUTHOR
+Bill Paul <wpaul@ctr.columbia.edu>
diff --git a/libexec/ypxfr/ypxfr_extern.h b/libexec/ypxfr/ypxfr_extern.h
new file mode 100644
index 0000000..5ca370c
--- /dev/null
+++ b/libexec/ypxfr/ypxfr_extern.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+#include <sys/types.h>
+#include <limits.h>
+#include <paths.h>
+#include <db.h>
+#include <rpcsvc/yp.h>
+
+extern HASHINFO openinfo;
+extern BTREEINFO openinfo_b;
+
+#ifndef _PATH_YP
+#define _PATH_YP "/var/yp/"
+#endif
+
+extern char *yp_dir;
+extern int debug;
+extern enum ypstat yp_errno;
+extern void yp_error __P(( const char *, ... ));
+extern int _yp_check __P(( char ** ));
+extern char *ypxfrerr_string __P(( ypxfrstat ));
+extern DB *yp_open_db_rw __P(( const char *, const char *, const int));
+extern void yp_init_dbs __P(( void ));
+extern int yp_put_record __P(( DB *, DBT *, DBT * , int ));
+extern int yp_get_record __P(( const char *, const char *, const DBT *, DBT *, int ));
+extern int ypxfr_get_map __P(( char *, char *, char *, int (*)() ));
+extern char *ypxfr_get_master __P(( char *, char *, char *, const int ));
+extern unsigned long ypxfr_get_order __P(( char *, char *, char *, const int ));
+extern int ypxfr_match __P(( char *, char *, char *, char *, unsigned long ));
+extern char *ypxfxerr_string __P(( ypxfrstat ));
+extern int ypxfrd_get_map __P(( char *, char *, char *, char *));
+extern int callrpc __P(( char *, int, int, int, xdrproc_t, char *, xdrproc_t, char *));
diff --git a/libexec/ypxfr/ypxfr_getmap.c b/libexec/ypxfr/ypxfr_getmap.c
new file mode 100644
index 0000000..14939ae
--- /dev/null
+++ b/libexec/ypxfr/ypxfr_getmap.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp.h>
+#include "ypxfr_extern.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+extern bool_t xdr_ypresp_all_seq __P(( XDR *, unsigned long * ));
+
+int (*ypresp_allfn)();
+void *ypresp_data;
+extern DB *specdbp;
+extern int yp_errno;
+
+/*
+ * This is largely the same as yp_all() except we do the transfer
+ * from a specific server without the aid of ypbind(8). We need to
+ * be able to specify the source host explicitly since ypxfr may
+ * only transfer maps from the NIS master server for any given domain.
+ * However, if we use the libc version of yp_all(), we could end up
+ * talking to one of the slaves instead. We do need to dig into libc
+ * a little though, since it contains the magic XDR function we need.
+ */
+int ypxfr_get_map(map, domain, host, callback)
+ char *map;
+ char *domain;
+ char *host;
+ int (*callback)();
+{
+ CLIENT *clnt;
+ ypreq_nokey req;
+ unsigned long status;
+ struct timeval timeout;
+
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 10;
+
+ /* YPPROC_ALL is a TCP service */
+ if ((clnt = clnt_create(host, YPPROG, YPVERS, "tcp")) == NULL) {
+ yp_error("%s", clnt_spcreateerror("failed to \
+create tcp handle"));
+ yp_errno = YPXFR_YPERR;
+ return(1);
+ }
+
+ req.domain = domain;
+ req.map = map;
+ ypresp_allfn = callback;
+ ypresp_data = NULL;
+
+ (void)clnt_call(clnt, YPPROC_ALL, xdr_ypreq_nokey, &req,
+ xdr_ypresp_all_seq, &status, timeout);
+
+ clnt_destroy(clnt);
+
+ if (status == YP_NOMORE)
+ return(0);
+
+ if (status != YP_TRUE) {
+ yp_errno = YPXFR_YPERR;
+ return(1);
+ }
+
+ return(0);
+}
diff --git a/libexec/ypxfr/ypxfr_main.c b/libexec/ypxfr/ypxfr_main.c
new file mode 100644
index 0000000..6e42c05
--- /dev/null
+++ b/libexec/ypxfr/ypxfr_main.c
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: ypxfr_main.c,v 1.8 1997/02/22 14:22:48 peter Exp $
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <rpc/clnt.h>
+#include <rpcsvc/yp.h>
+struct dom_binding {};
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/ypxfrd.h>
+#include "ypxfr_extern.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id: ypxfr_main.c,v 1.8 1997/02/22 14:22:48 peter Exp $";
+#endif
+
+char *progname = "ypxfr";
+char *yp_dir = _PATH_YP;
+int _rpcpmstart = 0;
+int ypxfr_use_yplib = 0; /* Assume the worst. */
+int ypxfr_clear = 1;
+int ypxfr_prognum = 0;
+struct sockaddr_in ypxfr_callback_addr;
+struct yppushresp_xfr ypxfr_resp;
+DB *dbp;
+
+static void ypxfr_exit(retval, temp)
+ ypxfrstat retval;
+ char *temp;
+{
+ CLIENT *clnt;
+ int sock = RPC_ANYSOCK;
+ struct timeval timeout;
+
+ /* Clean up no matter what happened previously. */
+ if (temp != NULL) {
+ if (dbp != NULL)
+ (void)(dbp->close)(dbp);
+ if (unlink(temp) == -1) {
+ yp_error("failed to unlink %s",strerror(errno));
+ }
+ }
+
+ if (_rpcpmstart) {
+ timeout.tv_sec = 20;
+ timeout.tv_usec = 0;
+
+ if ((clnt = clntudp_create(&ypxfr_callback_addr, ypxfr_prognum,
+ 1, timeout, &sock)) == NULL) {
+ yp_error("%s", clnt_spcreateerror("failed to \
+establish callback handle"));
+ exit(1);
+ }
+
+ ypxfr_resp.status = retval;
+
+ if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
+ yp_error("%s", clnt_sperror(clnt, "callback failed"));
+ clnt_destroy(clnt);
+ exit(1);
+ }
+ clnt_destroy(clnt);
+ } else {
+ yp_error("Exiting: %s", ypxfrerr_string(retval));
+ }
+
+ exit(0);
+}
+
+static void usage()
+{
+ if (_rpcpmstart) {
+ ypxfr_exit(YPXFR_BADARGS,NULL);
+ } else {
+ fprintf(stderr,"usage: %s [-f] [-c] [-d target domain] \
+[-h source host] [-s source domain]\n", progname);
+ fprintf(stderr,"\t [-p path] [-C taskid program-number \
+ipaddr port] mapname\n");
+ exit(1);
+ }
+}
+
+int ypxfr_foreach(status, key, keylen, val, vallen, data)
+ int status;
+ char *key;
+ int keylen;
+ char *val;
+ int vallen;
+ char *data;
+{
+ DBT dbkey, dbval;
+
+ if (status != YP_TRUE)
+ return (status);
+
+ dbkey.data = key;
+ dbkey.size = keylen;
+ dbval.data = val;
+ dbval.size = vallen;
+
+ if (yp_put_record(dbp, &dbkey, &dbval, 0) != YP_TRUE)
+ return(yp_errno);
+
+ return (0);
+}
+
+main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ int ch;
+ int ypxfr_force = 0;
+ char *ypxfr_dest_domain = NULL;
+ char *ypxfr_source_host = NULL;
+ char *ypxfr_source_domain = NULL;
+ char *ypxfr_local_domain = NULL;
+ char *ypxfr_master = NULL;
+ unsigned long ypxfr_order = -1, ypxfr_skew_check = -1;
+ char *ypxfr_mapname = NULL;
+ int ypxfr_args = 0;
+ char ypxfr_temp_map[MAXPATHLEN + 2];
+ char tempmap[MAXPATHLEN + 2];
+ char buf[MAXPATHLEN + 2];
+ DBT key, data;
+ int remoteport;
+ int interdom = 0;
+ int secure = 0;
+
+ debug = 1;
+
+ if (!isatty(fileno(stderr))) {
+ openlog(progname, LOG_PID, LOG_DAEMON);
+ _rpcpmstart = 1;
+ }
+
+ if (argc < 2)
+ usage();
+
+ while ((ch = getopt(argc, argv, "fcd:h:s:p:C:")) != -1) {
+ int my_optind;
+ switch(ch) {
+ case 'f':
+ ypxfr_force++;
+ ypxfr_args++;
+ break;
+ case 'c':
+ ypxfr_clear = 0;
+ ypxfr_args++;
+ break;
+ case 'd':
+ ypxfr_dest_domain = optarg;
+ ypxfr_args += 2;
+ break;
+ case 'h':
+ ypxfr_source_host = optarg;
+ ypxfr_args += 2;
+ break;
+ case 's':
+ ypxfr_source_domain = optarg;
+ ypxfr_args += 2;
+ break;
+ case 'p':
+ yp_dir = optarg;
+ ypxfr_args += 2;
+ break;
+ case 'C':
+ /*
+ * Whoever decided that the -C flag should take
+ * four arguments is a twit.
+ */
+ my_optind = optind - 1;
+ if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
+ yp_error("transaction ID not specified");
+ usage();
+ }
+ ypxfr_resp.transid = atol(argv[my_optind]);
+ my_optind++;
+ if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
+ yp_error("RPC program number not specified");
+ usage();
+ }
+ ypxfr_prognum = atol(argv[my_optind]);
+ my_optind++;
+ if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
+ yp_error("address not specified");
+ usage();
+ }
+ if (!inet_aton(argv[my_optind], &ypxfr_callback_addr.sin_addr)) {
+ yp_error("failed to convert '%s' to IP addr",
+ argv[my_optind]);
+ exit(1);
+ }
+ my_optind++;
+ if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
+ yp_error("port not specified");
+ usage();
+ }
+ ypxfr_callback_addr.sin_port = htons((u_short)atoi(argv[my_optind]));
+ ypxfr_args += 5;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ ypxfr_mapname = argv[ypxfr_args + 1];
+
+ if (ypxfr_mapname == NULL) {
+ yp_error("no map name specified");
+ usage();
+ }
+
+ /* Always the case. */
+ ypxfr_callback_addr.sin_family = AF_INET;
+
+ /* Determine if local NIS client facilities are turned on. */
+ if (!yp_get_default_domain(&ypxfr_local_domain) &&
+ _yp_check(&ypxfr_local_domain))
+ ypxfr_use_yplib = 1;
+
+ /*
+ * If no destination domain is specified, assume that the
+ * local default domain is to be used and try to obtain it.
+ * Fails if NIS client facilities are turned off.
+ */
+ if (ypxfr_dest_domain == NULL) {
+ if (ypxfr_use_yplib) {
+ yp_get_default_domain(&ypxfr_dest_domain);
+ } else {
+ yp_error("no destination domain specified and \
+the local domain name isn't set");
+ ypxfr_exit(YPXFR_BADARGS,NULL);
+ }
+ }
+
+ /*
+ * If a source domain is not specified, assume it to
+ * be the same as the destination domain.
+ */
+ if (ypxfr_source_domain == NULL) {
+ ypxfr_source_domain = ypxfr_dest_domain;
+ }
+
+ /*
+ * If the source host is not specified, assume it to be the
+ * master for the specified map. If local NIS client facilities
+ * are turned on, we can figure this out using yp_master().
+ * If not, we have to see if a local copy of the map exists
+ * and extract its YP_MASTER_NAME record. If _that_ fails,
+ * we are stuck and must ask the user for more information.
+ */
+ if (ypxfr_source_host == NULL) {
+ if (!ypxfr_use_yplib) {
+ /*
+ * Double whammy: NIS isn't turned on and the user
+ * didn't specify a source host.
+ */
+ char *dptr;
+ key.data = "YP_MASTER_NAME";
+ key.size = sizeof("YP_MASTER_NAME") - 1;
+
+ if (yp_get_record(ypxfr_dest_domain, ypxfr_mapname,
+ &key, &data, 1) != YP_TRUE) {
+ yp_error("no source host specified");
+ ypxfr_exit(YPXFR_BADARGS,NULL);
+ }
+ dptr = data.data;
+ dptr[data.size] = '\0';
+ ypxfr_master = ypxfr_source_host = strdup(dptr);
+ }
+ } else {
+ if (ypxfr_use_yplib)
+ ypxfr_use_yplib = 0;
+ }
+
+ if (ypxfr_master == NULL) {
+ if ((ypxfr_master = ypxfr_get_master(ypxfr_source_domain,
+ ypxfr_mapname,
+ ypxfr_source_host,
+ ypxfr_use_yplib)) == NULL) {
+ yp_error("failed to find master of %s in domain %s: %s",
+ ypxfr_mapname, ypxfr_source_domain,
+ ypxfrerr_string(yp_errno));
+ ypxfr_exit(YPXFR_MADDR,NULL);
+ }
+ }
+
+ /*
+ * If we got here and ypxfr_source_host is still undefined,
+ * it means we had to resort to using yp_master() to find the
+ * master server for the map. The source host and master should
+ * be identical.
+ */
+ if (ypxfr_source_host == NULL)
+ ypxfr_source_host = ypxfr_master;
+
+ /*
+ * Don't talk to ypservs on unprivileged ports.
+ */
+ remoteport = getrpcport(ypxfr_source_host, YPPROG, YPVERS, IPPROTO_UDP);
+ if (remoteport >= IPPORT_RESERVED) {
+ yp_error("ypserv on %s not running on reserved port",
+ ypxfr_source_host);
+ ypxfr_exit(YPXFR_REFUSED, NULL);
+ }
+
+ if ((ypxfr_order = ypxfr_get_order(ypxfr_source_domain,
+ ypxfr_mapname,
+ ypxfr_master, 0)) == 0) {
+ yp_error("failed to get order number of %s: %s",
+ ypxfr_mapname, yp_errno == YPXFR_SUCC ?
+ "map has order 0" : ypxfrerr_string(yp_errno));
+ ypxfr_exit(YPXFR_YPERR,NULL);
+ }
+
+ if (ypxfr_match(ypxfr_master, ypxfr_source_domain, ypxfr_mapname,
+ "YP_INTERDOMAIN", sizeof("YP_INTERDOMAIN") - 1))
+ interdom++;
+
+ if (ypxfr_match(ypxfr_master, ypxfr_source_domain, ypxfr_mapname,
+ "YP_SECURE", sizeof("YP_SECURE") - 1))
+ secure++;
+
+ key.data = "YP_LAST_MODIFIED";
+ key.size = sizeof("YP_LAST_MODIFIED") - 1;
+
+ /* The order number is immaterial when the 'force' flag is set. */
+
+ if (!ypxfr_force) {
+ int ignore = 0;
+ if (yp_get_record(ypxfr_dest_domain,ypxfr_mapname,&key,&data,1) != YP_TRUE) {
+ switch(yp_errno) {
+ case YP_NOKEY:
+ ypxfr_exit(YPXFR_FORCE,NULL);
+ break;
+ case YP_NOMAP:
+ /*
+ * If the map doesn't exist, we're
+ * creating it. Ignore the error.
+ */
+ ignore++;
+ break;
+ case YP_BADDB:
+ default:
+ ypxfr_exit(YPXFR_DBM,NULL);
+ break;
+ }
+ }
+ if (!ignore && ypxfr_order <= atoi(data.data))
+ ypxfr_exit(YPXFR_AGE, NULL);
+
+ }
+
+ /* Construct a temporary map file name */
+ snprintf(tempmap, sizeof(tempmap), "%s.%d",ypxfr_mapname, getpid());
+ snprintf(ypxfr_temp_map, sizeof(ypxfr_temp_map), "%s/%s/%s", yp_dir,
+ ypxfr_dest_domain, tempmap);
+
+ if ((remoteport = getrpcport(ypxfr_source_host, YPXFRD_FREEBSD_PROG,
+ YPXFRD_FREEBSD_VERS, IPPROTO_TCP))) {
+
+ /* Don't talk to rpc.ypxfrds on unprovileged ports. */
+ if (remoteport >= IPPORT_RESERVED) {
+ yp_error("rpc.ypxfrd on %s not using privileged port",
+ ypxfr_source_host);
+ ypxfr_exit(YPXFR_REFUSED, NULL);
+ }
+
+ /* Try to send using ypxfrd. If it fails, use old method. */
+ if (!ypxfrd_get_map(ypxfr_source_host, ypxfr_mapname,
+ ypxfr_source_domain, ypxfr_temp_map))
+ goto leave;
+ }
+
+ /* Open the temporary map read/write. */
+ if ((dbp = yp_open_db_rw(ypxfr_dest_domain, tempmap, 0)) == NULL) {
+ yp_error("failed to open temporary map file");
+ ypxfr_exit(YPXFR_DBM,NULL);
+ }
+
+ /*
+ * Fill in the keys we already know, such as the order number,
+ * master name, input file name (we actually make up a bogus
+ * name for that) and output file name.
+ */
+ snprintf(buf, sizeof(buf), "%d", ypxfr_order);
+ data.data = buf;
+ data.size = strlen(buf);
+
+ if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
+ yp_error("failed to write order number to database");
+ ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
+ }
+
+ key.data = "YP_MASTER_NAME";
+ key.size = sizeof("YP_MASTER_NAME") - 1;
+ data.data = ypxfr_master;
+ data.size = strlen(ypxfr_master);
+
+ if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
+ yp_error("failed to write master name to database");
+ ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
+ }
+
+ key.data = "YP_DOMAIN_NAME";
+ key.size = sizeof("YP_DOMAIN_NAME") - 1;
+ data.data = ypxfr_dest_domain;
+ data.size = strlen(ypxfr_dest_domain);
+
+ if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
+ yp_error("failed to write domain name to database");
+ ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
+ }
+
+ snprintf (buf, sizeof(buf), "%s:%s", ypxfr_source_host, ypxfr_mapname);
+
+ key.data = "YP_INPUT_NAME";
+ key.size = sizeof("YP_INPUT_NAME") - 1;
+ data.data = &buf;
+ data.size = strlen(buf);
+
+ if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
+ yp_error("failed to write input name to database");
+ ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
+
+ }
+
+ snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, ypxfr_dest_domain,
+ ypxfr_mapname);
+
+ key.data = "YP_OUTPUT_NAME";
+ key.size = sizeof("YP_OUTPUT_NAME") - 1;
+ data.data = &buf;
+ data.size = strlen(buf);
+
+ if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
+ yp_error("failed to write output name to database");
+ ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
+ }
+
+ if (interdom) {
+ key.data = "YP_INTERDOMAIN";
+ key.size = sizeof("YP_INTERDOMAIN") - 1;
+ data.data = "";
+ data.size = 0;
+
+ if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
+ yp_error("failed to add interdomain flag to database");
+ ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
+ }
+ }
+
+ if (secure) {
+ key.data = "YP_SECURE";
+ key.size = sizeof("YP_SECURE") - 1;
+ data.data = "";
+ data.size = 0;
+
+ if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
+ yp_error("failed to add secure flag to database");
+ ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
+ }
+ }
+
+ /* Now suck over the contents of the map from the master. */
+
+ if (ypxfr_get_map(ypxfr_mapname,ypxfr_source_domain,
+ ypxfr_source_host, ypxfr_foreach)){
+ yp_error("failed to retrieve map from source host");
+ ypxfr_exit(YPXFR_YPERR,&ypxfr_temp_map);
+ }
+
+ (void)(dbp->close)(dbp);
+ dbp = NULL; /* <- yes, it seems this is necessary. */
+
+leave:
+
+ snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, ypxfr_dest_domain,
+ ypxfr_mapname);
+
+ /* Peek at the order number again and check for skew. */
+ if ((ypxfr_skew_check = ypxfr_get_order(ypxfr_source_domain,
+ ypxfr_mapname,
+ ypxfr_master, 0)) == 0) {
+ yp_error("failed to get order number of %s: %s",
+ ypxfr_mapname, yp_errno == YPXFR_SUCC ?
+ "map has order 0" : ypxfrerr_string(yp_errno));
+ ypxfr_exit(YPXFR_YPERR,&ypxfr_temp_map);
+ }
+
+ if (ypxfr_order != ypxfr_skew_check)
+ ypxfr_exit(YPXFR_SKEW,&ypxfr_temp_map);
+
+ /*
+ * Send a YPPROC_CLEAR to the local ypserv.
+ */
+ if (ypxfr_clear) {
+ char in = 0;
+ char *out = NULL;
+ int stat;
+ if ((stat = callrpc("localhost",YPPROG,YPVERS,YPPROC_CLEAR,
+ xdr_void, (void *)&in,
+ xdr_void, (void *)out)) != RPC_SUCCESS) {
+ yp_error("failed to send 'clear' to local ypserv: %s",
+ clnt_sperrno((enum clnt_stat) stat));
+ ypxfr_exit(YPXFR_CLEAR, &ypxfr_temp_map);
+ }
+ }
+
+ /*
+ * Put the new map in place immediately. I'm not sure if the
+ * kernel does an unlink() and rename() atomically in the event
+ * that we move a new copy of a map over the top of an existing
+ * one, but there's less chance of a race condition happening
+ * than if we were to do the unlink() ourselves.
+ */
+ if (rename(ypxfr_temp_map, buf) == -1) {
+ yp_error("rename(%s,%s) failed: %s", ypxfr_temp_map, buf,
+ strerror(errno));
+ ypxfr_exit(YPXFR_FILE,NULL);
+ }
+
+ ypxfr_exit(YPXFR_SUCC,NULL);
+
+ return(1);
+}
diff --git a/libexec/ypxfr/ypxfr_misc.c b/libexec/ypxfr/ypxfr_misc.c
new file mode 100644
index 0000000..aaaff67
--- /dev/null
+++ b/libexec/ypxfr/ypxfr_misc.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+struct dom_binding {};
+#include <rpcsvc/ypclnt.h>
+#include "ypxfr_extern.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+char *ypxfrerr_string(code)
+ ypxfrstat code;
+{
+ switch(code) {
+ case YPXFR_SUCC:
+ return ("Map successfully transfered");
+ break;
+ case YPXFR_AGE:
+ return ("Master's version not newer");
+ break;
+ case YPXFR_NOMAP:
+ return ("No such map in server's domain");
+ break;
+ case YPXFR_NODOM:
+ return ("Domain not supported by server");
+ break;
+ case YPXFR_RSRC:
+ return ("Local resource allocation failure");
+ break;
+ case YPXFR_RPC:
+ return ("RPC failure talking to server");
+ break;
+ case YPXFR_MADDR:
+ return ("Could not get master server address");
+ break;
+ case YPXFR_YPERR:
+ return ("NIS server/map database error");
+ break;
+ case YPXFR_BADARGS:
+ return ("Request arguments bad");
+ break;
+ case YPXFR_DBM:
+ return ("Local database operation failed");
+ break;
+ case YPXFR_FILE:
+ return ("Local file I/O operation failed");
+ break;
+ case YPXFR_SKEW:
+ return ("Map version skew during transfer");
+ break;
+ case YPXFR_CLEAR:
+ return ("Couldn't send \"clear\" request to local ypserv");
+ break;
+ case YPXFR_FORCE:
+ return ("No local order number in map -- use -f flag");
+ break;
+ case YPXFR_XFRERR:
+ return ("General ypxfr error");
+ break;
+ case YPXFR_REFUSED:
+ return ("Transfer request refused by ypserv");
+ break;
+ default:
+ return ("Unknown error code");
+ break;
+ }
+}
+
+/*
+ * These are wrappers for the usual yp_master() and yp_order() functions.
+ * They can use either local yplib functions (the real yp_master() and
+ * yp_order()) or do direct RPCs to a specified server. The latter is
+ * necessary if ypxfr is run on a machine that isn't configured as an
+ * NIS client (this can happen very easily: a given machine need not be
+ * an NIS client in order to be an NIS server).
+ */
+
+/*
+ * Careful: yp_master() returns a pointer to a dynamically allocated
+ * buffer. Calling ypproc_master_2() ourselves also returns a pointer
+ * to dynamically allocated memory, though this time it's memory
+ * allocated by the XDR routines. We have to rememver to free() or
+ * xdr_free() the memory as required to avoid leaking memory.
+ */
+char *ypxfr_get_master(domain,map,source,yplib)
+ char *domain;
+ char *map;
+ char *source;
+ const int yplib;
+{
+ static char mastername[MAXPATHLEN + 2];
+
+ bzero((char *)&mastername, sizeof(mastername));
+
+ if (yplib) {
+ int res;
+ char *master;
+ if ((res = yp_master(domain, map, &master))) {
+ switch (res) {
+ case YPERR_DOMAIN:
+ yp_errno = YPXFR_NODOM;
+ break;
+ case YPERR_MAP:
+ yp_errno = YPXFR_NOMAP;
+ break;
+ case YPERR_YPERR:
+ default:
+ yp_errno = YPXFR_YPERR;
+ break;
+ }
+ return(NULL);
+ } else {
+ snprintf(mastername, sizeof(mastername), "%s", master);
+ free(master);
+ return((char *)&mastername);
+ }
+ } else {
+ CLIENT *clnt;
+ ypresp_master *resp;
+ ypreq_nokey req;
+
+ if ((clnt = clnt_create(source,YPPROG,YPVERS,"udp")) == NULL) {
+ yp_error("%s",clnt_spcreateerror("failed to \
+create udp handle to ypserv"));
+ yp_errno = YPXFR_RPC;
+ return(NULL);
+ }
+
+ req.map = map;
+ req.domain = domain;
+ if ((resp = ypproc_master_2(&req, clnt)) == NULL) {
+ yp_error("%s",clnt_sperror(clnt,"YPPROC_MASTER \
+failed"));
+ clnt_destroy(clnt);
+ yp_errno = YPXFR_RPC;
+ return(NULL);
+ }
+ clnt_destroy(clnt);
+ if (resp->stat != YP_TRUE) {
+ switch (resp->stat) {
+ case YP_NODOM:
+ yp_errno = YPXFR_NODOM;
+ break;
+ case YP_NOMAP:
+ yp_errno = YPXFR_NOMAP;
+ break;
+ case YP_YPERR:
+ default:
+ yp_errno = YPXFR_YPERR;
+ break;
+ }
+ return(NULL);
+ }
+ snprintf(mastername, sizeof(mastername), "%s", resp->peer);
+/* xdr_free(xdr_ypresp_master, (char *)&resp); */
+ return((char *)&mastername);
+ }
+}
+
+unsigned long ypxfr_get_order(domain, map, source, yplib)
+ char *domain;
+ char *map;
+ char *source;
+ const int yplib;
+{
+ if (yplib) {
+ unsigned long order;
+ int res;
+ if ((res = yp_order(domain, map, (int *)&order))) {
+ switch (res) {
+ case YPERR_DOMAIN:
+ yp_errno = YPXFR_NODOM;
+ break;
+ case YPERR_MAP:
+ yp_errno = YPXFR_NOMAP;
+ break;
+ case YPERR_YPERR:
+ default:
+ yp_errno = YPXFR_YPERR;
+ break;
+ }
+ return(0);
+ } else
+ return(order);
+ } else {
+ CLIENT *clnt;
+ ypresp_order *resp;
+ ypreq_nokey req;
+
+ if ((clnt = clnt_create(source,YPPROG,YPVERS,"udp")) == NULL) {
+ yp_error("%s",clnt_spcreateerror("couldn't create \
+udp handle to ypserv"));
+ yp_errno = YPXFR_RPC;
+ return(0);
+ }
+ req.map = map;
+ req.domain = domain;
+ if ((resp = ypproc_order_2(&req, clnt)) == NULL) {
+ yp_error("%s", clnt_sperror(clnt, "YPPROC_ORDER \
+failed"));
+ clnt_destroy(clnt);
+ yp_errno = YPXFR_RPC;
+ return(0);
+ }
+ clnt_destroy(clnt);
+ if (resp->stat != YP_TRUE) {
+ switch (resp->stat) {
+ case YP_NODOM:
+ yp_errno = YPXFR_NODOM;
+ break;
+ case YP_NOMAP:
+ yp_errno = YPXFR_NOMAP;
+ break;
+ case YP_YPERR:
+ default:
+ yp_errno = YPXFR_YPERR;
+ break;
+ }
+ return(0);
+ }
+ return(resp->ordernum);
+ }
+}
+
+int ypxfr_match(server, domain, map, key, keylen)
+ char *server;
+ char *domain;
+ char *map;
+ char *key;
+ unsigned long keylen;
+{
+ ypreq_key ypkey;
+ ypresp_val *ypval;
+ CLIENT *clnt;
+ static char buf[YPMAXRECORD + 2];
+
+ bzero((char *)buf, sizeof(buf));
+
+ if ((clnt = clnt_create(server, YPPROG,YPVERS,"udp")) == NULL) {
+ yp_error("failed to create UDP handle: %s",
+ clnt_spcreateerror(server));
+ return(0);
+ }
+
+ ypkey.domain = domain;
+ ypkey.map = map;
+ ypkey.key.keydat_len = keylen;
+ ypkey.key.keydat_val = key;
+
+ if ((ypval = ypproc_match_2(&ypkey, clnt)) == NULL) {
+ clnt_destroy(clnt);
+ yp_error("%s: %s", server,
+ clnt_sperror(clnt,"YPPROC_MATCH failed"));
+ return(0);
+ }
+
+ clnt_destroy(clnt);
+
+ if (ypval->stat != YP_TRUE) {
+ xdr_free(xdr_ypresp_val, (char *)ypval);
+ return(0);
+ }
+
+ xdr_free(xdr_ypresp_val, (char *)ypval);
+
+ return(1);
+}
diff --git a/libexec/ypxfr/ypxfrd_getmap.c b/libexec/ypxfr/ypxfrd_getmap.c
new file mode 100644
index 0000000..3844beb
--- /dev/null
+++ b/libexec/ypxfr/ypxfrd_getmap.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <rpcsvc/ypxfrd.h>
+#include <rpcsvc/yp.h>
+#include <rpc/rpc.h>
+#include <sys/uio.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "ypxfr_extern.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+int fp = 0;
+
+static bool_t xdr_my_xfr(register XDR *xdrs, xfr *objp)
+{
+ while(1) {
+ if (!xdr_xfr(xdrs, objp))
+ return(FALSE);
+ if (objp->ok == TRUE) {
+ if (write(fp, objp->xfr_u.xfrblock_buf.xfrblock_buf_val,
+ objp->xfr_u.xfrblock_buf.xfrblock_buf_len) == -1) {
+ yp_error("write failed: %s", strerror(errno));
+ return(FALSE);
+ }
+ }
+ xdr_free(xdr_xfr, (char *)objp);
+ if (objp->ok == FALSE) {
+ switch(objp->xfr_u.xfrstat) {
+ case(XFR_DONE):
+ return(TRUE);
+ break;
+ case(XFR_READ_ERR):
+ yp_error("got read error from rpc.ypxfrd");
+ return(FALSE);
+ break;
+ case(XFR_ACCESS):
+ yp_error("rpc.ypxfrd couldn't access the map");
+ return(FALSE);
+ break;
+ case(XFR_DENIED):
+ yp_error("access to map denied by rpc.ypxfrd");
+ return(FALSE);
+ break;
+ case(XFR_DB_TYPE_MISMATCH):
+ yp_error("client/server DB type mismatch");
+ return(FALSE);
+ break;
+ case(XFR_DB_ENDIAN_MISMATCH):
+ yp_error("client/server byte order mismatch");
+ return(FALSE);
+ break;
+ default:
+ yp_error("got unknown status from rpc.ypxfrd");
+ return(FALSE);
+ break;
+ }
+ }
+ }
+}
+
+#define PERM_SECURE (S_IRUSR|S_IWUSR)
+
+int ypxfrd_get_map(host, map, domain, tmpname)
+ char *host;
+ char *map;
+ char *domain;
+ char *tmpname;
+{
+ CLIENT *clnt;
+ struct ypxfr_mapname req;
+ struct xfr resp;
+ struct timeval timeout = { 0, 25 };
+ int status = 0;
+
+ req.xfrmap = map;
+ req.xfrdomain = domain;
+ req.xfrmap_filename = "";
+ req.xfr_db_type = XFR_DB_BSD_HASH; /*
+ req.xfr_byte_order = XFR_ENDIAN_ANY; * Berkeley DB isn't
+ * byte-order sensitive.
+ */
+
+ bzero((char *)&resp, sizeof(resp));
+
+ if ((clnt = clnt_create(host, YPXFRD_FREEBSD_PROG,
+ YPXFRD_FREEBSD_VERS, "tcp")) == NULL) {
+ return(1);
+ }
+
+ if ((fp = open(tmpname, O_RDWR|O_CREAT, PERM_SECURE)) == -1) {
+ clnt_destroy(clnt);
+ yp_error("couldn't open %s: %s", tmpname, strerror(errno));
+ return(1);
+ }
+
+ if (clnt_call(clnt,YPXFRD_GETMAP,xdr_ypxfr_mapname,(char *)&req,
+ xdr_my_xfr, (char *)&resp, timeout) != RPC_SUCCESS) {
+ yp_error("%s", clnt_sperror(clnt,"call to rpc.ypxfrd failed"));
+ status++;
+ unlink(tmpname);
+ }
+
+ clnt_destroy(clnt);
+ close(fp);
+ return(status);
+}
OpenPOWER on IntegriCloud