BSD 4.4 Lite Libexec Sources

This commit is contained in:
Rodney W. Grimes 1994-05-27 12:39:25 +00:00
parent 9b50d90275
commit ea022d1687
107 changed files with 27749 additions and 0 deletions

12
libexec/Makefile Normal file
View file

@ -0,0 +1,12 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
SUBDIR= bugfiler comsat fingerd ftpd getNAME getty kpasswdd lfs_cleanerd \
mail.local makekey rexecd rlogind rshd talkd telnetd tftpd uucpd
.if ${MACHINE} == "hp300"
SUBDIR+=rbootd
.elif ${MACHINE} == "luna68k"
SUBDIR+=rbootd
.endif
.include <bsd.subdir.mk>

3
libexec/Makefile.inc Normal file
View file

@ -0,0 +1,3 @@
# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
BINDIR?= /usr/libexec

17
libexec/bugfiler/Makefile Normal file
View file

@ -0,0 +1,17 @@
# @(#)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>

92
libexec/bugfiler/bug.h Normal file
View file

@ -0,0 +1,92 @@
/*
* 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 */

290
libexec/bugfiler/bugfiler.8 Normal file
View file

@ -0,0 +1,290 @@
.\" 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 .

167
libexec/bugfiler/bugfiler.c Normal file
View file

@ -0,0 +1,167 @@
/*
* 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);
}

View file

@ -0,0 +1,32 @@
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.

89
libexec/bugfiler/error.c Normal file
View file

@ -0,0 +1,89 @@
/*
* 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[] = "@(#)error.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/param.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "bug.h"
#include "extern.h"
static short err_redir; /* stderr redirected */
/*
* seterr --
* redirect stderr for error processing
*/
void
seterr()
{
if (!freopen(ERROR_FILE, "a", stderr))
error("can't open error file %s.", ERROR_FILE);
err_redir = YES;
}
/*
* error --
* write errors to log file and die
*/
void
error(fmt, arg)
register char *fmt,
*arg;
{
static char logmsg[MAXLINELEN]; /* syslog message */
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);
}
else {
sprintf(logmsg, "bugfiler: %s", fmt);
syslog(LOG_ERR, logmsg, arg);
}
#ifdef METOO
exit(ERR);
#else
exit(OK);
#endif
}

41
libexec/bugfiler/extern.h Normal file
View file

@ -0,0 +1,41 @@
/*-
* Copyright (c) 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.
*
* @(#)extern.h 8.1 (Berkeley) 6/4/93
*/
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));

165
libexec/bugfiler/gethead.c Normal file
View file

@ -0,0 +1,165 @@
/*
* 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);
}

View file

@ -0,0 +1,38 @@
/*
* 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
*/
#define MAIL_CMD "/usr/sbin/sendmail -i -t -F \"Bugs Bunny\" -f owner-bugs"
#undef _PATH_TMP
#define _PATH_TMP "/tmp/BUG_XXXXXX"

115
libexec/bugfiler/process.c Normal file
View file

@ -0,0 +1,115 @@
/*
* 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);
}

131
libexec/bugfiler/redist.c Normal file
View file

@ -0,0 +1,131 @@
/*
* 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);
}

118
libexec/bugfiler/reply.c Normal file
View file

@ -0,0 +1,118 @@
/*
* 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);
}

View file

@ -0,0 +1,85 @@
.\" Copyright (c) 1983, 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.
.\"
.\" @(#)sendbug.1 8.1 (Berkeley) 6/4/93
.\"
.Dd June 4, 1993
.Dt SENDBUG 1
.Os BSD 4.2
.Sh NAME
.Nm sendbug
.Nd mail a system bug report to 4bsd-bugs
.Sh SYNOPSIS
.Nm sendbug
.Op Ar address
.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
.Sh FILES
.Bl -tag -width /usr/share/misc/bugformat -compact
.It Pa /usr/share/misc/bugformat
Contains the bug report outline.
.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 .

View file

@ -0,0 +1,66 @@
#!/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

6
libexec/comsat/Makefile Normal file
View file

@ -0,0 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
PROG= comsat
MAN8= comsat.0
.include <bsd.prog.mk>

96
libexec/comsat/comsat.8 Normal file
View file

@ -0,0 +1,96 @@
.\" 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.
.\"
.\" @(#)comsat.8 8.1 (Berkeley) 6/4/93
.\"
.Dd June 4, 1993
.Dt COMSAT 8
.Os BSD 4.2
.Sh NAME
.Nm comsat
.Nd biff server
.Sh SYNOPSIS
.Nm comsat
.Sh DESCRIPTION
.Nm Comsat
is the server process which receives reports of incoming mail
and notifies users if they have requested this service.
.Nm Comsat
receives messages on a datagram port associated with the
.Dq biff
service
specification (see
.Xr services 5
and
.Xr inetd 8 ) .
The one line messages are of the form:
.Pp
.Dl user@mailbox-offset
.Pp
If the
.Em user
specified is logged in to the system and the associated terminal has
the owner execute bit turned on (by a
.Dq Li biff y ) ,
the
.Em offset
is used as a seek offset into the appropriate mailbox file and
the first 7 lines or 560 characters of the message are printed
on the user's terminal. Lines which appear to be part of
the message header other than the
.Dq From ,
.Dq \&To ,
.Dq Date ,
or
.Dq Subject
lines are not included in the displayed message.
.Sh FILES
.Bl -tag -width /var/run/utmp -compact
.It Pa /var/run/utmp
to find out who's logged on and on what terminals
.El
.Sh SEE ALSO
.Xr biff 1 ,
.Xr inetd 8
.Sh BUGS
The message header filtering is prone to error.
The density of the information presented is near the theoretical minimum.
.Pp
Users should be notified of mail which arrives on other
machines than the one to which they are currently logged in.
.Pp
The notification should appear in a separate window so it
does not mess up the screen.
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .

284
libexec/comsat/comsat.c Normal file
View file

@ -0,0 +1,284 @@
/*
* 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[] = "@(#)comsat.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <paths.h>
#include <pwd.h>
#include <sgtty.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <utmp.h>
int debug = 0;
#define dsyslog if (debug) syslog
#define MAXIDLE 120
char hostname[MAXHOSTNAMELEN];
struct utmp *utmp = NULL;
time_t lastmsgtime;
int nutmp, uf;
void jkfprintf __P((FILE *, char[], off_t));
void mailfor __P((char *));
void notify __P((struct utmp *, off_t));
void onalrm __P((int));
void reapchildren __P((int));
int
main(argc, argv)
int argc;
char *argv[];
{
struct sockaddr_in from;
register int cc;
int fromlen;
char msgbuf[100];
/* verify proper invocation */
fromlen = sizeof(from);
if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
(void)fprintf(stderr,
"comsat: getsockname: %s.\n", strerror(errno));
exit(1);
}
openlog("comsat", LOG_PID, LOG_DAEMON);
if (chdir(_PATH_MAILDIR)) {
syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR);
(void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
exit(1);
}
if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
syslog(LOG_ERR, "open: %s: %m", _PATH_UTMP);
(void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
exit(1);
}
(void)time(&lastmsgtime);
(void)gethostname(hostname, sizeof(hostname));
onalrm(0);
(void)signal(SIGALRM, onalrm);
(void)signal(SIGTTOU, SIG_IGN);
(void)signal(SIGCHLD, reapchildren);
for (;;) {
cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
if (cc <= 0) {
if (errno != EINTR)
sleep(1);
errno = 0;
continue;
}
if (!nutmp) /* no one has logged in yet */
continue;
sigblock(sigmask(SIGALRM));
msgbuf[cc] = '\0';
(void)time(&lastmsgtime);
mailfor(msgbuf);
sigsetmask(0L);
}
}
void
reapchildren(signo)
int signo;
{
while (wait3(NULL, WNOHANG, NULL) > 0);
}
void
onalrm(signo)
int signo;
{
static u_int utmpsize; /* last malloced size for utmp */
static u_int utmpmtime; /* last modification time for utmp */
struct stat statbf;
if (time(NULL) - lastmsgtime >= MAXIDLE)
exit(0);
(void)alarm((u_int)15);
(void)fstat(uf, &statbf);
if (statbf.st_mtime > utmpmtime) {
utmpmtime = statbf.st_mtime;
if (statbf.st_size > utmpsize) {
utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
if ((utmp = realloc(utmp, utmpsize)) == NULL) {
syslog(LOG_ERR, "%s", strerror(errno));
exit(1);
}
}
(void)lseek(uf, (off_t)0, L_SET);
nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp);
}
}
void
mailfor(name)
char *name;
{
register struct utmp *utp = &utmp[nutmp];
register char *cp;
off_t offset;
if (!(cp = strchr(name, '@')))
return;
*cp = '\0';
offset = atoi(cp + 1);
while (--utp >= utmp)
if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name)))
notify(utp, offset);
}
static char *cr;
void
notify(utp, offset)
register struct utmp *utp;
off_t offset;
{
FILE *tp;
struct stat stb;
struct sgttyb gttybuf;
char tty[20], name[sizeof(utmp[0].ut_name) + 1];
(void)snprintf(tty, sizeof(tty), "%s%.*s",
_PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line);
if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) {
/* A slash is an attempt to break security... */
syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty);
return;
}
if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) {
dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty);
return;
}
dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty);
if (fork())
return;
(void)signal(SIGALRM, SIG_DFL);
(void)alarm((u_int)30);
if ((tp = fopen(tty, "w")) == NULL) {
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)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)fclose(tp);
_exit(0);
}
void
jkfprintf(tp, name, offset)
register FILE *tp;
char name[];
off_t offset;
{
register char *cp, ch;
register FILE *fi;
register int linecnt, charcnt, inheader;
register struct passwd *p;
char line[BUFSIZ];
/* Set effective uid to user in case mail drop is on nfs */
if ((p = getpwnam(name)) != NULL)
(void) setuid(p->pw_uid);
if ((fi = fopen(name, "r")) == NULL)
return;
(void)fseek(fi, offset, L_SET);
/*
* Print the first 7 lines or 560 characters of the new mail
* (whichever comes first). Skip header crap other than
* From, Subject, To, and Date.
*/
linecnt = 7;
charcnt = 560;
inheader = 1;
while (fgets(line, sizeof(line), fi) != NULL) {
if (inheader) {
if (line[0] == '\n') {
inheader = 0;
continue;
}
if (line[0] == ' ' || line[0] == '\t' ||
strncmp(line, "From:", 5) &&
strncmp(line, "Subject:", 8))
continue;
}
if (linecnt <= 0 || charcnt <= 0) {
(void)fprintf(tp, "...more...%s", cr);
(void)fclose(fi);
return;
}
/* strip weird stuff so can't trojan horse stupid terminals */
for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) {
ch = toascii(ch);
if (!isprint(ch) && !isspace(ch))
ch |= 0x40;
(void)fputc(ch, tp);
}
(void)fputs(cr, tp);
--linecnt;
}
(void)fprintf(tp, "----%s\n", cr);
(void)fclose(fi);
}

6
libexec/fingerd/Makefile Normal file
View file

@ -0,0 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
PROG= fingerd
MAN8= fingerd.0
.include <bsd.prog.mk>

139
libexec/fingerd/fingerd.8 Normal file
View file

@ -0,0 +1,139 @@
.\" 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.
.\"
.\" @(#)fingerd.8 8.1 (Berkeley) 6/4/93
.\"
.Dd June 4, 1993
.Dt FINGERD 8
.Os BSD 4.3
.Sh NAME
.Nm fingerd
.Nd remote user information server
.Sh SYNOPSIS
.Nm fingerd
.Op Fl s
.Op Fl l
.Op Fl p Ar filename
.Sh DESCRIPTION
.Nm Fingerd
is a simple protocol based on
.%T RFC1196
that provides an interface to the
Name and Finger programs at several network sites.
The program is supposed to return a friendly,
human-oriented status report on either the system at the moment
or a particular person in depth.
There is no required format and the
protocol consists mostly of specifying a single
.Dq command line .
.Pp
.Nm Fingerd
listens for
.Tn TCP
requests at port 79.
Once connected it reads a single command line
terminated by a
.Aq Tn CRLF
which is passed to
.Xr finger 1 .
.Nm Fingerd
closes its connections as soon as the output is finished.
.Pp
If the line is null (i.e. just a
.Aq Tn CRLF
is sent) then
.Xr finger
returns a
.Dq default
report that lists all people logged into
the system at that moment.
.Pp
If a user name is specified (e.g.
.Pf eric Aq Tn CRLF )
then the
response lists more extended information for only that particular user,
whether logged in or not.
Allowable
.Dq names
in the command line include both
.Dq login names
and
.Dq user names .
If a name is ambiguous, all possible derivations are returned.
.Pp
The following options may be passed to
.Nm fingerd
as server program arguments in
.Pa /etc/inetd.conf :
.Bl -tag -width Ds
.It Fl s
Enable secure mode.
Queries without a user name are rejected and
forwarding of queries to other remote hosts is denied.
.It Fl l
Enable logging.
The name of the host originating the query is reported via
.Xr syslog 3
at LOG_NOTICE priority.
.It Fl p
Use an alternate program as the local information provider.
The default local program
executed by
.Nm fingerd
is
.Xr finger 1 .
By specifying a customized local server,
this option allows a system manager
to have more control over what information is
provided to remote sites.
.El
.Sh SEE ALSO
.Xr finger 1
.Sh BUGS
Connecting directly to the server from a
.Tn TIP
or an equally narrow-minded
.Tn TELNET Ns \-protocol
user program can result
in meaningless attempts at option negotiation being sent to the
server, which will foul up the command line interpretation.
.Nm Fingerd
should be taught to filter out
.Tn IAC Ns \'s
and perhaps even respond
negatively
.Pq Tn IAC WON'T
to all option commands received.
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.3 .

190
libexec/fingerd/fingerd.c Normal file
View file

@ -0,0 +1,190 @@
/*
* 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 copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)fingerd.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "pathnames.h"
void err __P((const char *, ...));
int
main(argc, argv)
int argc;
char *argv[];
{
register FILE *fp;
register int ch;
register char *lp;
struct hostent *hp;
struct sockaddr_in sin;
int p[2], logging, secure, sval;
#define ENTRIES 50
char **ap, *av[ENTRIES + 1], **comp, line[1024], *prog;
prog = _PATH_FINGER;
logging = secure = 0;
openlog("fingerd", LOG_PID | LOG_CONS, LOG_DAEMON);
opterr = 0;
while ((ch = getopt(argc, argv, "slp:")) != EOF)
switch (ch) {
case 'l':
logging = 1;
break;
case 'p':
prog = optarg;
break;
case 's':
secure = 1;
break;
case '?':
default:
err("illegal option -- %c", ch);
}
if (logging) {
sval = sizeof(sin);
if (getpeername(0, (struct sockaddr *)&sin, &sval) < 0)
err("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;
else
lp = inet_ntoa(sin.sin_addr);
syslog(LOG_NOTICE, "query from %s", lp);
}
if (!fgets(line, sizeof(line), stdin))
exit(1);
comp = &av[1];
for (lp = line, ap = &av[2];;) {
*ap = strtok(lp, " \t\r\n");
if (!*ap) {
if (secure && ap == &av[2]) {
puts("must provide username\r\n");
exit(1);
}
break;
}
if (secure && strchr(*ap, '@')) {
puts("fowarding service denied\r\n");
exit(1);
}
/* RFC742: "/[Ww]" == "-l" */
if ((*ap)[0] == '/' && ((*ap)[1] == 'W' || (*ap)[1] == 'w')) {
av[1] = "-l";
comp = &av[0];
}
else if (++ap == av + ENTRIES)
break;
lp = NULL;
}
if (lp = strrchr(prog, '/'))
*comp = ++lp;
else
*comp = prog;
if (pipe(p) < 0)
err("pipe: %s", strerror(errno));
switch(vfork()) {
case 0:
(void)close(p[0]);
if (p[1] != 1) {
(void)dup2(p[1], 1);
(void)close(p[1]);
}
execv(prog, comp);
err("execv: %s: %s", prog, strerror(errno));
_exit(1);
case -1:
err("fork: %s", strerror(errno));
}
(void)close(p[1]);
if (!(fp = fdopen(p[0], "r")))
err("fdopen: %s", strerror(errno));
while ((ch = getc(fp)) != EOF) {
if (ch == '\n')
putchar('\r');
putchar(ch);
}
exit(0);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)vsyslog(LOG_ERR, fmt, ap);
va_end(ap);
exit(1);
/* NOTREACHED */
}

View file

@ -0,0 +1,36 @@
/*
* 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
*/
#define _PATH_FINGER "/usr/bin/finger"

9
libexec/ftpd/Makefile Normal file
View file

@ -0,0 +1,9 @@
# @(#)Makefile 8.2 (Berkeley) 4/4/94
PROG= ftpd
CFLAGS+=-DSETPROCTITLE
SRCS= ftpd.c ftpcmd.c logwtmp.c popen.c
MAN8= ftpd.0
CLEANFILES+=ftpcmd.c y.tab.h
.include <bsd.prog.mk>

65
libexec/ftpd/extern.h Normal file
View file

@ -0,0 +1,65 @@
/*-
* Copyright (c) 1992, 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.
*
* @(#)extern.h 8.2 (Berkeley) 4/4/94
*/
void blkfree __P((char **));
char **copyblk __P((char **));
void cwd __P((char *));
void delete __P((char *));
void dologout __P((int));
void fatal __P((char *));
int ftpd_pclose __P((FILE *));
FILE *ftpd_popen __P((char *, char *));
char *getline __P((char *, int, FILE *));
void logwtmp __P((char *, char *, char *));
void lreply __P((int, const char *, ...));
void makedir __P((char *));
void nack __P((char *));
void pass __P((char *));
void passive __P((void));
void perror_reply __P((int, char *));
void pwd __P((void));
void removedir __P((char *));
void renamecmd __P((char *, char *));
char *renamefrom __P((char *));
void reply __P((int, const char *, ...));
void retrieve __P((char *, char *));
void send_file_list __P((char *));
void setproctitle __P((const char *, ...));
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 *));

1266
libexec/ftpd/ftpcmd.y Normal file

File diff suppressed because it is too large Load diff

290
libexec/ftpd/ftpd.8 Normal file
View file

@ -0,0 +1,290 @@
.\" Copyright (c) 1985, 1988, 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.
.\"
.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
.\"
.Dd April 19, 1994
.Dt FTPD 8
.Os BSD 4.2
.Sh NAME
.Nm ftpd
.Nd
Internet File Transfer Protocol server
.Sh SYNOPSIS
.Nm ftpd
.Op Fl dl
.Op Fl T Ar maxtimeout
.Op Fl t Ar timeout
.Sh DESCRIPTION
.Nm Ftpd
is the
Internet File Transfer Protocol
server process. The server uses the
.Tn TCP
protocol
and listens at the port specified in the
.Dq ftp
service specification; see
.Xr services 5 .
.Pp
Available options:
.Bl -tag -width Ds
.It Fl d
Debugging information is written to the syslog using LOG_FTP.
.It Fl l
Each successful and failed
.Xr ftp 1
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.
.It Fl T
A client may also request a different timeout period;
the maximum period allowed may be set to
.Ar timeout
seconds with the
.Fl T
option.
The default limit is 2 hours.
.It Fl t
The inactivity timeout period is set to
.Ar timeout
seconds (the default is 15 minutes).
.El
.Pp
The file
.Pa /etc/nologin
can be used to disable ftp access.
If the file exists,
.Nm
displays it and exits.
If the file
.Pa /etc/ftpwelcome
exists,
.Nm
prints it before issuing the
.Dq ready
message.
If the file
.Pa /etc/motd
exists,
.Nm
prints it after a successful login.
.Pp
The ftp server currently supports the following ftp requests.
The case of the requests is ignored.
.Bl -column "Request" -offset indent
.It Request Ta "Description"
.It ABOR Ta "abort previous command"
.It ACCT Ta "specify account (ignored)"
.It ALLO Ta "allocate storage (vacuously)"
.It APPE Ta "append to a file"
.It CDUP Ta "change to parent of current working directory"
.It CWD Ta "change working directory"
.It DELE Ta "delete a file"
.It HELP Ta "give help information"
.It LIST Ta "give list files in a directory" Pq Dq Li "ls -lgA"
.It MKD Ta "make a directory"
.It MDTM Ta "show last modification time of file"
.It MODE Ta "specify data transfer" Em mode
.It NLST Ta "give name list of files in directory"
.It NOOP Ta "do nothing"
.It PASS Ta "specify password"
.It PASV Ta "prepare for server-to-server transfer"
.It PORT Ta "specify data connection port"
.It PWD Ta "print the current working directory"
.It QUIT Ta "terminate session"
.It REST Ta "restart incomplete transfer"
.It RETR Ta "retrieve a file"
.It RMD Ta "remove a directory"
.It RNFR Ta "specify rename-from file name"
.It RNTO Ta "specify rename-to file name"
.It SITE Ta "non-standard commands (see next section)"
.It SIZE Ta "return size of file"
.It STAT Ta "return status of server"
.It STOR Ta "store a file"
.It STOU Ta "store a file with a unique name"
.It STRU Ta "specify data transfer" Em structure
.It SYST Ta "show operating system type of server system"
.It TYPE Ta "specify data transfer" Em type
.It USER Ta "specify user name"
.It XCUP Ta "change to parent of current working directory (deprecated)"
.It XCWD Ta "change working directory (deprecated)"
.It XMKD Ta "make a directory (deprecated)"
.It XPWD Ta "print the current working directory (deprecated)"
.It XRMD Ta "remove a directory (deprecated)"
.El
.Pp
The following non-standard or
.Tn UNIX
specific commands are supported
by the
SITE request.
.Pp
.Bl -column Request -offset indent
.It Sy Request Ta Sy Description
.It UMASK Ta change umask, e.g. ``SITE UMASK 002''
.It IDLE Ta set idle-timer, e.g. ``SITE IDLE 60''
.It CHMOD Ta change mode of a file, e.g. ``SITE CHMOD 755 filename''
.It HELP Ta give help information.
.El
.Pp
The remaining ftp requests specified in Internet RFC 959
are
recognized, but not implemented.
MDTM and SIZE are not specified in RFC 959, but will appear in the
next updated FTP RFC.
.Pp
The ftp server will abort an active file transfer only when the
ABOR
command is preceded by a Telnet "Interrupt Process" (IP)
signal and a Telnet "Synch" signal in the command Telnet stream,
as described in Internet RFC 959.
If a
STAT
command is received during a data transfer, preceded by a Telnet IP
and Synch, transfer status will be returned.
.Pp
.Nm Ftpd
interprets file names according to the
.Dq globbing
conventions used by
.Xr csh 1 .
This allows users to utilize the metacharacters
.Dq Li \&*?[]{}~ .
.Pp
.Nm Ftpd
authenticates users according to three rules.
.Pp
.Bl -enum -offset indent
.It
The login name must be in the password data base,
.Pa /etc/passwd ,
and not have a null password.
In this case a password must be provided by the client before any
file operations may be performed.
.It
The login name must not appear in the file
.Pa /etc/ftpusers .
.It
The user must have a standard shell returned by
.Xr getusershell 3 .
.It
If the user name is
.Dq anonymous
or
.Dq ftp ,
an
anonymous ftp account must be present in the password
file (user
.Dq ftp ) .
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).
.El
.Pp
In the last case,
.Nm ftpd
takes special measures to restrict the client's access privileges.
The server performs a
.Xr chroot 2
to the home directory of the
.Dq ftp
user.
In order that system security is not breached, it is recommended
that the
.Dq ftp
subtree be constructed with care, following these rules:
.Bl -tag -width "~ftp/pub" -offset indent
.It Pa ~ftp
Make the home directory owned by
.Dq root
and unwritable by anyone.
.It Pa ~ftp/bin
Make this directory owned by
.Dq root
and unwritable by anyone (mode 555).
The program
.Xr ls 1
must be present to support the list command.
This program should be mode 111.
.It Pa ~ftp/etc
Make this directory owned by
.Dq root
and unwritable by anyone (mode 555).
The files
.Xr passwd 5
and
.Xr group 5
must be present for the
.Xr ls
command to be able to produce owner names rather than numbers.
The password field in
.Xr passwd
is not used, and should not contain real passwords.
The file
.Pa motd ,
if present, will be printed after a successful login.
These files should be mode 444.
.It Pa ~ftp/pub
Make this directory mode 777 and owned by
.Dq ftp .
Guests
can then place files which are to be accessible via the anonymous
account in this directory.
.El
.Sh FILES
.Bl -tag -width /etc/ftpwelcome -compact
.It Pa /etc/ftpusers
List of unwelcome/restricted users.
.It Pa /etc/ftpwelcome
Welcome notice.
.It Pa /etc/motd
Welcome notice after login.
.It Pa /etc/nologin
Displayed and access refused.
.El
.Sh SEE ALSO
.Xr ftp 1 ,
.Xr getusershell 3 ,
.Xr syslogd 8
.Sh BUGS
The server must run as the super-user
to create sockets with privileged port numbers. It maintains
an effective user id of the logged in user, reverting to
the super-user only when binding addresses to sockets. The
possible security holes have been extensively
scrutinized, but are possibly incomplete.
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .

1654
libexec/ftpd/ftpd.c Normal file

File diff suppressed because it is too large Load diff

75
libexec/ftpd/logwtmp.c Normal file
View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 1988, 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[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <utmp.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include "extern.h"
static int fd = -1;
/*
* Modified version of logwtmp that holds wtmp file open
* after first call, for use with ftp (which may chroot
* after login, but before logout).
*/
void
logwtmp(line, name, host)
char *line, *name, *host;
{
struct utmp ut;
struct stat buf;
if (fd < 0 && (fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
return;
if (fstat(fd, &buf) == 0) {
(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
(void)time(&ut.ut_time);
if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
sizeof(struct utmp))
(void)ftruncate(fd, buf.st_size);
}
}

40
libexec/ftpd/pathnames.h Normal file
View file

@ -0,0 +1,40 @@
/*
* 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
*/
#include <paths.h>
#define _PATH_FTPUSERS "/etc/ftpusers"
#define _PATH_FTPWELCOME "/etc/ftpwelcome"
#define _PATH_FTPLOGINMESG "/etc/motd"

171
libexec/ftpd/popen.c Normal file
View file

@ -0,0 +1,171 @@
/*
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software written by Ken Arnold and
* published in UNIX Review, Vol. 6, No. 8.
*
* 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[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <glob.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
/*
* Special version of popen which avoids call to shell. This ensures noone
* may create a pipe to a hidden program as a side effect of a list or dir
* command.
*/
static int *pids;
static int fds;
FILE *
ftpd_popen(program, type)
char *program, *type;
{
char *cp;
FILE *iop;
int argc, gargc, pdes[2], pid;
char **pop, *argv[100], *gargv[1000];
if (*type != 'r' && *type != 'w' || type[1])
return (NULL);
if (!pids) {
if ((fds = getdtablesize()) <= 0)
return (NULL);
if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
return (NULL);
memset(pids, 0, fds * sizeof(int));
}
if (pipe(pdes) < 0)
return (NULL);
/* break up string into pieces */
for (argc = 0, cp = program;; cp = NULL)
if (!(argv[argc++] = strtok(cp, " \t\n")))
break;
/* glob each piece */
gargv[0] = argv[0];
for (gargc = argc = 1; argv[argc]; argc++) {
glob_t gl;
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
memset(&gl, 0, sizeof(gl));
if (glob(argv[argc], flags, NULL, &gl))
gargv[gargc++] = strdup(argv[argc]);
else
for (pop = gl.gl_pathv; *pop; pop++)
gargv[gargc++] = strdup(*pop);
globfree(&gl);
}
gargv[gargc] = NULL;
iop = NULL;
switch(pid = vfork()) {
case -1: /* error */
(void)close(pdes[0]);
(void)close(pdes[1]);
goto pfree;
/* NOTREACHED */
case 0: /* child */
if (*type == 'r') {
if (pdes[1] != STDOUT_FILENO) {
dup2(pdes[1], STDOUT_FILENO);
(void)close(pdes[1]);
}
dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */
(void)close(pdes[0]);
} else {
if (pdes[0] != STDIN_FILENO) {
dup2(pdes[0], STDIN_FILENO);
(void)close(pdes[0]);
}
(void)close(pdes[1]);
}
execv(gargv[0], gargv);
_exit(1);
}
/* parent; assume fdopen can't fail... */
if (*type == 'r') {
iop = fdopen(pdes[0], type);
(void)close(pdes[1]);
} else {
iop = fdopen(pdes[1], type);
(void)close(pdes[0]);
}
pids[fileno(iop)] = pid;
pfree: for (argc = 1; gargv[argc] != NULL; argc++)
free(gargv[argc]);
return (iop);
}
int
ftpd_pclose(iop)
FILE *iop;
{
int fdes, omask, status;
pid_t pid;
/*
* pclose returns -1 if stream is not associated with a
* `popened' command, or, if already `pclosed'.
*/
if (pids == 0 || pids[fdes = fileno(iop)] == 0)
return (-1);
(void)fclose(iop);
omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
continue;
(void)sigsetmask(omask);
pids[fdes] = 0;
if (pid < 0)
return (pid);
if (WIFEXITED(status))
return (WEXITSTATUS(status));
return (1);
}

6
libexec/getNAME/Makefile Normal file
View file

@ -0,0 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
PROG= getNAME
NOMAN= noman
.include <bsd.prog.mk>

339
libexec/getNAME/getNAME.c Normal file
View file

@ -0,0 +1,339 @@
/*-
* 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[] = "@(#)getNAME.c 8.1 (Berkeley) 6/30/93";
#endif /* not lint */
/*
* Get name sections from manual pages.
* -t for building toc
* -i for building intro entries
* other apropos database
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int tocrc;
int intro;
int typeflag;
void doname __P((char *));
void dorefname __P((char *));
void getfrom __P((char *));
void split __P((char *, char *));
void trimln __P((char *));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
int ch;
while ((ch = getopt(argc, argv, "itw")) != EOF)
switch(ch) {
case 'i':
intro = 1;
break;
case 't':
tocrc = 1;
break;
case 'w':
typeflag = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (!*argv)
usage();
for (; *argv; ++argv)
getfrom(*argv);
exit(0);
}
void
getfrom(pathname)
char *pathname;
{
int i = 0;
char *name, *loc;
char headbuf[BUFSIZ];
char linbuf[BUFSIZ];
if (freopen(pathname, "r", stdin) == 0) {
perror(pathname);
return;
}
if (name = strrchr(pathname, '/'))
name++;
else
name = pathname;
for (;;) {
if (fgets(headbuf, sizeof headbuf, stdin) == NULL) {
if (typeflag)
printf("%-60s UNKNOWN\n", pathname);
return;
}
if (headbuf[0] != '.')
continue;
if ((headbuf[1] == 'T' && headbuf[2] == 'H') ||
(headbuf[1] == 't' && headbuf[2] == 'h'))
break;
if (headbuf[1] == 'D' && headbuf[2] == 't') {
if (typeflag) {
printf("%-60s NEW\n", pathname);
return;
}
goto newman;
}
}
if (typeflag) {
printf("%-60s OLD\n", pathname);
return;
}
for (;;) {
if (fgets(linbuf, sizeof linbuf, stdin) == NULL)
return;
if (linbuf[0] != '.')
continue;
if (linbuf[1] == 'S' && linbuf[2] == 'H')
break;
if (linbuf[1] == 's' && linbuf[2] == 'h')
break;
}
trimln(headbuf);
if (tocrc)
doname(name);
if (!tocrc && !intro)
printf("%s\t", headbuf);
linbuf[0] = '\0';
for (;;) {
if (fgets(headbuf, sizeof headbuf, stdin) == NULL)
break;
if (headbuf[0] == '.') {
if (headbuf[1] == 'S' && headbuf[2] == 'H')
break;
if (headbuf[1] == 's' && headbuf[2] == 'h')
break;
}
if (i != 0)
strcat(linbuf, " ");
i++;
trimln(headbuf);
strcat(linbuf, headbuf);
}
if (intro)
split(linbuf, name);
else
printf("%s\n", linbuf);
return;
newman:
for (;;) {
if (fgets(linbuf, sizeof linbuf, stdin) == NULL)
return;
if (linbuf[0] != '.')
continue;
if (linbuf[1] == 'S' && linbuf[2] == 'h')
break;
}
trimln(headbuf);
if (tocrc)
doname(name);
if (!tocrc && !intro)
printf(".TH%s\t", &headbuf[3]);
linbuf[0] = '\0';
for (;;) {
if (fgets(headbuf, sizeof headbuf, stdin) == NULL)
break;
if (headbuf[0] == '.') {
if (headbuf[1] == 'S' && headbuf[2] == 'h')
break;
}
if (i != 0)
strcat(linbuf, " ");
i++;
trimln(headbuf);
for (loc = strchr(headbuf, ' '); loc; loc = strchr(loc, ' '))
if (loc[1] == ',')
strcpy(loc, &loc[1]);
else
loc++;
if (headbuf[0] != '.') {
strcat(linbuf, headbuf);
} else {
/*
* Get rid of quotes in macros.
*/
for (loc = strchr(&headbuf[4], '"'); loc; ) {
strcpy(loc, &loc[1]);
loc = strchr(loc, '"');
}
/*
* Handle cross references
*/
if (headbuf[1] == 'X' && headbuf[2] == 'r') {
for (loc = &headbuf[4]; *loc != ' '; loc++)
continue;
loc[0] = '(';
loc[2] = ')';
loc[3] = '\0';
}
/*
* Put dash between names and description.
*/
if (headbuf[1] == 'N' && headbuf[2] == 'd')
strcat(linbuf, "\\- ");
/*
* Skip over macro names.
*/
strcat(linbuf, &headbuf[4]);
}
}
if (intro)
split(linbuf, name);
else
printf("%s\n", linbuf);
}
void
trimln(cp)
register char *cp;
{
while (*cp)
cp++;
if (*--cp == '\n')
*cp = 0;
}
void
doname(name)
char *name;
{
register char *dp = name, *ep;
again:
while (*dp && *dp != '.')
putchar(*dp++);
if (*dp)
for (ep = dp+1; *ep; ep++)
if (*ep == '.') {
putchar(*dp++);
goto again;
}
putchar('(');
if (*dp)
dp++;
while (*dp)
putchar (*dp++);
putchar(')');
putchar(' ');
}
void
split(line, name)
char *line, *name;
{
register char *cp, *dp;
char *sp, *sep;
cp = strchr(line, '-');
if (cp == 0)
return;
sp = cp + 1;
for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--)
;
*++cp = '\0';
while (*sp && (*sp == ' ' || *sp == '\t'))
sp++;
for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") {
cp = strchr(dp, ',');
if (cp) {
register char *tp;
for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--)
;
*++tp = '\0';
for (++cp; *cp == ' ' || *cp == '\t'; cp++)
;
}
printf("%s%s\t", sep, dp);
dorefname(name);
printf("\t%s", sp);
}
}
void
dorefname(name)
char *name;
{
register char *dp = name, *ep;
again:
while (*dp && *dp != '.')
putchar(*dp++);
if (*dp)
for (ep = dp+1; *ep; ep++)
if (*ep == '.') {
putchar(*dp++);
goto again;
}
putchar('.');
if (*dp)
dp++;
while (*dp)
putchar (*dp++);
}
void
usage()
{
(void)fprintf(stderr, "usage: getNAME [-it] file ...\n");
exit(1);
}

10
libexec/getty/Makefile Normal file
View file

@ -0,0 +1,10 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
PROG= getty
SRCS= main.c init.c subr.c ttydefaults.c
DPADD= ${LIBUTIL}
LDADD= -lutil
MAN5= gettytab.0 ttys.0
MAN8= getty.0
.include <bsd.prog.mk>

56
libexec/getty/extern.h Normal file
View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 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.
*
* @(#)extern.h 8.1 (Berkeley) 6/4/93
*/
struct delayval;
int adelay __P((int, struct delayval *));
char *autobaud __P((void));
int delaybits __P((void));
void edithost __P((char *));
void gendefaults __P((void));
int getent __P((char *, char *));
int getflag __P((char *));
long getnum __P((char *));
char *getstr __P((char *, char **));
void gettable __P((char *, char *));
void makeenv __P((char *[]));
char *portselector __P((void));
void set_ttydefaults __P((int));
void setchars __P((void));
void setdefaults __P((void));
long setflags __P((int));
int speed __P((int));
int login_tty __P((int)); /* From libutil. */

127
libexec/getty/getty.8 Normal file
View file

@ -0,0 +1,127 @@
.\" 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.
.\"
.\" @(#)getty.8 8.1 (Berkeley) 6/4/93
.\"
.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 gettytab 5 ,
.Xr init 8 ,
.Xr login 1 ,
.Xr ioctl 2 ,
.Xr tty 4 ,
.Xr ttys 5
.Sh HISTORY
A
.Nm getty
program appeared in
.At v6 .

324
libexec/getty/gettytab.5 Normal file
View file

@ -0,0 +1,324 @@
.\" 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.
.\"
.\" @(#)gettytab.5 8.4 (Berkeley) 4/19/94
.\"
.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 "ap bool false terminal uses any parity"
.It "bd num 0 backspace delay"
.It "bk str 0377 alternate end of line character (input break)"
.It "cb bool false use crt backspace mode"
.It "cd num 0 carriage-return delay"
.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 "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 "fd num 0 form-feed (vertical motion) delay"
.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 "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 "lc bool false terminal has lower case"
.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 "nd num 0 newline (line-feed) delay"
.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 "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 "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 "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 "uc bool false terminal is known upper case only"
.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
.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 \&f0 ,
.Em \&f1 ,
or
.Em \&f2
numeric specifications, which can be used to specify
(usually in octal, with a leading '0')
the exact values of the flags.
Local (new tty) flags are set in the top 16 bits
of this (32 bit) value.
.Pp
Should
.Xr getty
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 the character sequence
.Em \&%h
or
.Em \&%t
to obtain
the hostname or tty name respectively.
.Pf ( Em %%
obtains a single '%' character.)
The hostname is normally obtained from the system,
but may be set by the
.Em \&hn
table entry.
In either case it may be edited with
.Em \&he .
The
.Em \&he
string is a sequence of characters, each character that
is neither '@' nor '#' is copied into the final hostname.
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.
Surplus '@' and '#' characters are ignored.
.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 ,
or having received an alarm signal, and exited.
This may be useful to hangup dial in lines.
.Pp
Output from
.Xr getty
is even parity unless
.Em \&op
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
does not check parity of input characters in
.Dv RAW
mode.
.Sh SEE ALSO
.Xr login 1 ,
.Xr termcap 5 ,
.Xr getty 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 4.2BSD.

145
libexec/getty/gettytab.h Normal file
View file

@ -0,0 +1,145 @@
/*
* 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.
*
* @(#)gettytab.h 8.2 (Berkeley) 3/30/94
*/
/*
* Getty description definitions.
*/
struct gettystrs {
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 {
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 {
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
/*
* 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
/*
* 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
int getent __P((char *, char *));
long getnum __P((char *));
int getflag __P((char *));
char *getstr __P((char *, char **));
extern struct gettyflags gettyflags[];
extern struct gettynums gettynums[];
extern struct gettystrs gettystrs[];
extern int hopcount;

121
libexec/getty/init.c Normal file
View file

@ -0,0 +1,121 @@
/*
* 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[] = "@(#)init.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
/*
* Getty table initializations.
*
* Melbourne getty.
*/
#include <sgtty.h>
#include "gettytab.h"
#include "pathnames.h"
extern struct sgttyb tmode;
extern struct tchars tc;
extern struct ltchars ltc;
extern char hostname[];
struct gettystrs gettystrs[] = {
{ "nx" }, /* next table */
{ "cl" }, /* screen clear characters */
{ "im" }, /* initial message */
{ "lm", "login: " }, /* login message */
{ "er", &tmode.sg_erase }, /* erase character */
{ "kl", &tmode.sg_kill }, /* kill character */
{ "et", &tc.t_eofc }, /* eof chatacter (eot) */
{ "pc", "" }, /* pad character */
{ "tt" }, /* terminal type */
{ "ev" }, /* enviroment */
{ "lo", _PATH_LOGIN }, /* login program */
{ "hn", hostname }, /* host name */
{ "he" }, /* host name edit */
{ "in", &tc.t_intrc }, /* interrupt char */
{ "qu", &tc.t_quitc }, /* quit char */
{ "xn", &tc.t_startc }, /* XON (start) char */
{ "xf", &tc.t_stopc }, /* XOFF (stop) char */
{ "bk", &tc.t_brkc }, /* brk char (alt \n) */
{ "su", &ltc.t_suspc }, /* suspend char */
{ "ds", &ltc.t_dsuspc }, /* delayed suspend */
{ "rp", &ltc.t_rprntc }, /* reprint char */
{ "fl", &ltc.t_flushc }, /* flush output */
{ "we", &ltc.t_werasc }, /* word erase */
{ "ln", &ltc.t_lnextc }, /* literal next */
{ 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 */
{ 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) */
{ 0 }
};

549
libexec/getty/main.c Normal file
View file

@ -0,0 +1,549 @@
/*-
* 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[] = "@(#)main.c 8.1 (Berkeley) 6/20/93";
#endif /* not lint */
#define USE_OLD_TTY
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <ctype.h>
#include <ctype.h>
#include <fcntl.h>
#include <setjmp.h>
#include <sgtty.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.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 */
struct sgttyb tmode = {
0, 0, CERASE, CKILL, 0
};
struct tchars tc = {
CINTR, CQUIT, CSTART,
CSTOP, CEOF, CBRK,
};
struct ltchars ltc = {
CSUSP, CDSUSP, CRPRNT,
CFLUSH, CWERASE, CLNEXT
};
int crmod, digit, lower, upper;
char hostname[MAXHOSTNAMELEN];
char name[16];
char dev[] = _PATH_DEV;
char ttyn[32];
char *portselector();
char *ttyname();
#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.sg_erase
#define KILL tmode.sg_kill
#define EOT tc.t_eofc
jmp_buf timeout;
static void
dingdong()
{
alarm(0);
signal(SIGALRM, SIG_DFL);
longjmp(timeout, 1);
}
jmp_buf intrupt;
static void
interrupt()
{
signal(SIGINT, interrupt);
longjmp(intrupt, 1);
}
/*
* Action to take when getty is running too long.
*/
void
timeoverrun(signo)
int signo;
{
syslog(LOG_ERR, "getty exiting due to excessive running time\n");
exit(1);
}
static int getname __P((void));
static void oflush __P((void));
static void prompt __P((void));
static void putchr __P((int));
static void putf __P((char *));
static void putpad __P((char *));
static void puts __P((char *));
int
main(argc, argv)
int argc;
char *argv[];
{
extern char **environ;
char *tname;
long allflags;
int repcnt = 0;
struct rlimit limit;
signal(SIGINT, SIG_IGN);
/*
signal(SIGQUIT, SIG_DFL);
*/
openlog("getty", LOG_ODELAY|LOG_CONS, 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);
/*
* 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(0));
else {
int i;
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);
/*
* Delay the open so DTR stays down long enough to be detected.
*/
sleep(2);
while ((i = open(ttyn, O_RDWR)) == -1) {
if (repcnt % 10 == 0) {
syslog(LOG_ERR, "%s: %m", ttyn);
closelog();
}
repcnt++;
sleep(60);
}
login_tty(i);
}
}
gettable("default", defent);
gendefaults();
tname = "default";
if (argc > 1)
tname = argv[1];
for (;;) {
int off;
gettable(tname, tabent);
if (OPset || EPset || APset)
APset++, OPset++, EPset++;
setdefaults();
off = 0;
ioctl(0, TIOCFLUSH, &off); /* clear out the crap */
ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */
ioctl(0, FIOASYNC, &off); /* ditto for async mode */
if (IS)
tmode.sg_ispeed = speed(IS);
else if (SP)
tmode.sg_ispeed = speed(SP);
if (OS)
tmode.sg_ospeed = speed(OS);
else if (SP)
tmode.sg_ospeed = speed(SP);
tmode.sg_flags = setflags(0);
ioctl(0, TIOCSETP, &tmode);
setchars();
ioctl(0, TIOCSETC, &tc);
if (HC)
ioctl(0, TIOCHPCL, 0);
if (AB) {
extern char *autobaud();
tname = autobaud();
continue;
}
if (PS) {
tname = portselector();
continue;
}
if (CL && *CL)
putpad(CL);
edithost(HE);
if (IM && *IM)
putf(IM);
if (setjmp(timeout)) {
tmode.sg_ispeed = tmode.sg_ospeed = 0;
ioctl(0, TIOCSETP, &tmode);
exit(1);
}
if (TO) {
signal(SIGALRM, dingdong);
alarm(TO);
}
if (getname()) {
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;
allflags = setflags(2);
tmode.sg_flags = allflags & 0xffff;
allflags >>= 16;
if (crmod || NL)
tmode.sg_flags |= CRMOD;
if (upper || UC)
tmode.sg_flags |= LCASE;
if (lower || LC)
tmode.sg_flags &= ~LCASE;
ioctl(0, TIOCSETP, &tmode);
ioctl(0, TIOCSLTC, &ltc);
ioctl(0, TIOCLSET, &allflags);
signal(SIGINT, SIG_DFL);
for (i = 0; environ[i] != (char *)0; i++)
env[i] = environ[i];
makeenv(&env[i]);
/*
* this is what login was doing anyway.
* soon we rewrite getty completely.
*/
set_ttydefaults(0);
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
getname()
{
register int c;
register char *np;
char cs;
/*
* Interrupt may happen if we use CBREAK mode
*/
if (setjmp(intrupt)) {
signal(SIGINT, SIG_IGN);
return (0);
}
signal(SIGINT, interrupt);
tmode.sg_flags = setflags(0);
ioctl(0, TIOCSETP, &tmode);
tmode.sg_flags = setflags(1);
prompt();
if (PF > 0) {
oflush();
sleep(PF);
PF = 0;
}
ioctl(0, TIOCSETP, &tmode);
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);
if (c == EOT)
exit(1);
if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
putf("\r\n");
break;
}
if (islower(c))
lower = 1;
else if (isupper(c))
upper = 1;
else if (c == ERASE || c == '#' || c == '\b') {
if (np > name) {
np--;
if (tmode.sg_ospeed >= B1200)
puts("\b \b");
else
putchr(cs);
}
continue;
} else if (c == KILL || c == '@') {
putchr(cs);
putchr('\r');
if (tmode.sg_ospeed < B1200)
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);
}
static
short tmspc10[] = {
0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
};
static void
putpad(s)
register char *s;
{
register pad = 0;
register mspc10;
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)
return;
if (tmode.sg_ospeed <= 0 ||
tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[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.
*/
mspc10 = tmspc10[tmode.sg_ospeed];
pad += mspc10 / 2;
for (pad /= mspc10; pad > 0; pad--)
putchr(*PC);
}
static void
puts(s)
register 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 void
putf(cp)
register char *cp;
{
extern char editedhost[];
time_t t;
char *slash, db[100];
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': {
static char fmt[] = "%l:% %P on %A, %d %B %Y";
fmt[4] = 'M'; /* I *hate* SCCS... */
(void)time(&t);
(void)strftime(db, sizeof(db), fmt, localtime(&t));
puts(db);
break;
}
case '%':
putchr('%');
break;
}
cp++;
}
}

39
libexec/getty/pathnames.h Normal file
View file

@ -0,0 +1,39 @@
/*
* 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
*/
#include <paths.h>
#define _PATH_GETTYTAB "/etc/gettytab"
#define _PATH_LOGIN "/usr/bin/login"

531
libexec/getty/subr.c Normal file
View file

@ -0,0 +1,531 @@
/*
* 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[] = "@(#)subr.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
/*
* Melbourne getty.
*/
#define USE_OLD_TTY
#include <stdlib.h>
#include <sgtty.h>
#include <string.h>
#include <unistd.h>
#include "gettytab.h"
#include "extern.h"
#include "pathnames.h"
extern struct sgttyb tmode;
extern struct tchars tc;
extern struct ltchars ltc;
/*
* Get a table entry.
*/
void
gettable(name, buf)
char *name, *buf;
{
register struct gettystrs *sp;
register struct gettynums *np;
register struct gettyflags *fp;
long n;
char *dba[2];
dba[0] = _PATH_GETTYTAB;
dba[1] = 0;
if (cgetent(&buf, dba, name) != 0)
return;
for (sp = gettystrs; sp->field; sp++)
cgetstr(buf, sp->field, &sp->value);
for (np = gettynums; np->field; np++) {
if (cgetnum(buf, np->field, &n) == -1)
np->set = 0;
else {
np->set = 1;
np->value = n;
}
}
for (fp = gettyflags; fp->field; fp++) {
if (cgetcap(buf, fp->field, ':') == NULL)
fp->set = 0;
else {
fp->set = 1;
fp->value = 1 ^ fp->invrt;
}
}
#ifdef DEBUG
printf("name=\"%s\", buf=\"%s\"\n", name, buf);
for (sp = gettystrs; sp->field; sp++)
printf("cgetstr: %s=%s\n", sp->field, sp->value);
for (np = gettynums; np->field; np++)
printf("cgetnum: %s=%d\n", np->field, np->value);
for (fp = gettyflags; fp->field; fp++)
printf("cgetflags: %s='%c' set='%c'\n", fp->field,
fp->value + '0', fp->set + '0');
exit(1);
#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 = 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;
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.sg_erase, &tmode.sg_kill, &tc.t_intrc,
&tc.t_quitc, &tc.t_startc, &tc.t_stopc,
&tc.t_eofc, &tc.t_brkc, &ltc.t_suspc,
&ltc.t_dsuspc, &ltc.t_rprntc, &ltc.t_flushc,
&ltc.t_werasc, &ltc.t_lnextc, 0
};
void
setchars()
{
register int i;
register char *p;
for (i = 0; charnames[i]; i++) {
p = *charnames[i];
if (p && *p)
*charvars[i] = *p;
else
*charvars[i] = '\377';
}
}
long
setflags(n)
int n;
{
register long f;
switch (n) {
case 0:
if (F0set)
return(F0);
break;
case 1:
if (F1set)
return(F1);
break;
default:
if (F2set)
return(F2);
break;
}
f = 0;
if (AP)
f |= ANYP;
else if (OP)
f |= ODDP;
else if (EP)
f |= EVENP;
if (UC)
f |= LCASE;
if (NL)
f |= CRMOD;
f |= delaybits();
if (n == 1) { /* read mode flags */
if (RW)
f |= RAW;
else
f |= CBREAK;
return (f);
}
if (!HT)
f |= XTABS;
if (n == 0)
return (f);
if (CB)
f |= CRTBS;
if (CE)
f |= CRTERA;
if (CK)
f |= CRTKIL;
if (PE)
f |= PRTERA;
if (EC)
f |= ECHO;
if (XC)
f |= CTLECH;
if (DX)
f |= DECCTQ;
return (f);
}
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);
}
char editedhost[32];
void
edithost(pat)
register char *pat;
{
register 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';
}
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 */
{ 0 }
};
int
speed(val)
int val;
{
register struct speedtab *sp;
if (val <= 15)
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 {
char *ps_baud;
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 }
};
char *
portselector()
{
char c, baud[20], *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>
char *
autobaud()
{
int rfds;
struct timeval timeout;
char c, *type = "9600-baud";
int null = 0;
ioctl(0, TIOCFLUSH, &null);
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);
ioctl(0, TIOCFLUSH, &null);
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);
}

View file

@ -0,0 +1,54 @@
/*-
* 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 sccsid[] = "@(#)ttydefaults.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/termios.h>
#include "extern.h"
void
set_ttydefaults(fd)
int fd;
{
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);
}

139
libexec/getty/ttys.5 Normal file
View file

@ -0,0 +1,139 @@
.\" 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.
.\"
.\" @(#)ttys.5 8.1 (Berkeley) 6/4/93
.\"
.Dd June 4, 1993
.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 )
or specify a window system process that
.Xr init 8
will maintain for the terminal line.
.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.
These flag fields should not be quoted.
.Pp
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.
.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 # 555-1234
# Mike's terminal: hp2621
ttyh0 "/usr/libexec/getty std.9600" hp2621-nl on # 457 Evans
# John's terminal: vt100
ttyh1 "/usr/libexec/getty std.9600" vt100 on # 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
ttyp1 none network off
.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 termcap 5 ,
.Xr getty 8 ,
.Xr init 8
.Sh HISTORY
A
.Nm
file appeared in
.At v6 .

11
libexec/kpasswdd/Makefile Normal file
View file

@ -0,0 +1,11 @@
# @(#)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>

View file

@ -0,0 +1,60 @@
.\" 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.
.\"
.\" @(#)kpasswdd.8 8.1 (Berkeley) 6/9/93
.\"
.Dd June 9, 1993
.Dt KPASSWDD 8
.Os
.Sh NAME
.Nm kpasswdd
.Nd Kerberos password changing daemon
.Sh SYNOPSIS
.Nm kpasswdd
.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.
.Sh SEE ALSO
.Xr kerberos 1 ,
.Xr passwd 1
.Sh HISTORY
The
.Nm kpasswdd
utility first appeared in 4.4BSD.

271
libexec/kpasswdd/kpasswdd.c Normal file
View file

@ -0,0 +1,271 @@
/*-
* 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);
}
}

View file

@ -0,0 +1,10 @@
# @(#)Makefile 8.1 (Berkeley) 6/5/93
PROG= lfs_cleanerd
CFLAGS+=-I/sys/ufs/lfs -I${.CURDIR} -DDIAGNOSTIC
MAN8= lfs_cleanerd.0
SRCS= cleanerd.c lfs_cksum.c library.c misc.c print.c
.PATH: /sys/ufs/lfs
.include <bsd.prog.mk>

View file

@ -0,0 +1,168 @@
/*-
* Copyright (c) 1992, 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.
*
* @(#)clean.h 8.1 (Berkeley) 6/4/93
*/
/*
* The LFS user-level library will be used when writing cleaners and
* checkers for LFS file systems. It will have facilities for finding
* and parsing LFS segments.
*/
#define DUMP_SUM_HEADER 0x0001
#define DUMP_INODE_ADDRS 0x0002
#define DUMP_FINFOS 0x0004
#define DUMP_ALL 0xFFFF
#define IFILE_NAME "ifile"
/*
* Cleaner parameters
* BUSY_LIM: lower bound of the number of segments currently available
* as a percentage of the total number of free segments possibly
* available.
* IDLE_LIM: Same as BUSY_LIM but used when the system is idle.
* MIN_SEGS: Minimum number of segments you should always have.
* I have no idea what this should be, but it should probably
* be a function of lfsp.
* NUM_TO_CLEAN: Number of segments to clean at once. Again, this
* should probably be based on the file system size and how
* full or empty the segments being cleaned are.
*/
#define BUSY_LIM 0.50
#define IDLE_LIM 0.90
#define MIN_SEGS(lfsp) (3)
#define NUM_TO_CLEAN(fsp) (1)
#define MAXLOADS 3
#define ONE_MIN 0
#define FIVE_MIN 1
#define FIFTEEN_MIN 2
typedef struct fs_info {
struct statfs *fi_statfsp; /* fsstat info from getfsstat */
struct lfs fi_lfs; /* superblock */
CLEANERINFO *fi_cip; /* Cleaner info from ifile */
SEGUSE *fi_segusep; /* segment usage table (from ifile) */
IFILE *fi_ifilep; /* ifile table (from ifile) */
u_long fi_daddr_shift; /* shift to get byte offset of daddr */
u_long fi_ifile_count; /* # entries in the ifile table */
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?
*/
#define seg_size(fs) ((fs)->lfs_ssize << (fs)->lfs_bshift)
/* daddr -> byte offset */
#define datobyte(fs, da) ((da) << (fs)->fi_daddr_shift)
#define bytetoda(fs, byte) ((byte) >> (fs)->fi_daddr_shift)
#define CLEANSIZE(fsp) (fsp->fi_lfs.lfs_cleansz << fsp->fi_lfs.lfs_bshift)
#define SEGTABSIZE(fsp) (fsp->fi_lfs.lfs_segtabsz << fsp->fi_lfs.lfs_bshift)
#define IFILE_ENTRY(fs, if, i) \
((IFILE *)((caddr_t)(if) + ((i) / (fs)->lfs_ifpb << (fs)->lfs_bshift)) \
+ (i) % (fs)->lfs_ifpb)
#define SEGUSE_ENTRY(fs, su, i) \
((SEGUSE *)((caddr_t)(su) + (fs)->lfs_bsize * ((i) / (fs)->lfs_sepb)) +\
(i) % (fs)->lfs_sepb)
__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 *, 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 *));
int mmap_segment __P((FS_INFO *, int, caddr_t *, int));
void munmap_segment __P((FS_INFO *, caddr_t, int));
void reread_fs_info __P((FS_INFO *, int));
void toss __P((void *, int *, size_t,
int (*)(const void *, const void *, const void *), void *));
/*
* USEFUL DEBUGGING FUNCTIONS:
*/
#ifdef VERBOSE
#define PRINT_FINFO(fp, ip) { \
(void)printf(" %s %s%d version %d nblocks %d\n", \
(ip)->if_version > (fp)->fi_version ? "TOSSING" : "KEEPING", \
"FINFO for inode: ", (fp)->fi_ino, \
(fp)->fi_version, (fp)->fi_nblocks); \
fflush(stdout); \
}
#define PRINT_INODE(b, bip) { \
(void) printf("\t%s inode: %d daddr: 0x%lx create: %s\n", \
b ? "KEEPING" : "TOSSING", (bip)->bi_inode, (bip)->bi_daddr, \
ctime((time_t *)&(bip)->bi_segcreate)); \
fflush(stdout); \
}
#define PRINT_BINFO(bip) { \
(void)printf("\tinode: %d lbn: %d daddr: 0x%lx create: %s\n", \
(bip)->bi_inode, (bip)->bi_lbn, (bip)->bi_daddr, \
ctime((time_t *)&(bip)->bi_segcreate)); \
fflush(stdout); \
}
#define PRINT_SEGUSE(sup, n) { \
(void)printf("Segment %d nbytes=%lu\tflags=%c%c%c ninos=%d nsums=%d lastmod: %s\n", \
n, (sup)->su_nbytes, \
(sup)->su_flags & SEGUSE_DIRTY ? 'D' : 'C', \
(sup)->su_flags & SEGUSE_ACTIVE ? 'A' : ' ', \
(sup)->su_flags & SEGUSE_SUPERBLOCK ? 'S' : ' ', \
(sup)->su_ninos, (sup)->su_nsums, \
ctime((time_t *)&(sup)->su_lastmod)); \
fflush(stdout); \
}
void dump_super __P((struct lfs *));
void dump_cleaner_info __P((void *));
void print_SEGSUM __P(( struct lfs *, SEGSUM *));
void print_CLEANERINFO __P((CLEANERINFO *));
#else
#define PRINT_FINFO(fp, ip)
#define PRINT_INODE(b, bip)
#define PRINT_BINFO(bip)
#define PRINT_SEGUSE(sup, n)
#define dump_cleaner_info(cip)
#define dump_super(lfsp)
#endif
__END_DECLS

View file

@ -0,0 +1,498 @@
/*-
* Copyright (c) 1992, 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) 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)cleanerd.c 8.2 (Berkeley) 1/13/94";
#endif /* not lint */
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/lfs/lfs.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "clean.h"
char *special = "cleanerd";
int do_small = 0;
int do_mmap = 0;
struct cleaner_stats {
int blocks_read;
int blocks_written;
int segs_cleaned;
int segs_empty;
int segs_error;
} cleaner_stats;
struct seglist {
int sl_id; /* segment number */
int sl_cost; /* cleaning cost */
char sl_empty; /* is segment empty */
};
struct tossstruct {
struct lfs *lfs;
int seg;
};
/* 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));
int lfs_bmapv __P((fsid_t *, BLOCK_INFO *, int));
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 (*)(FS_INFO *, SEGUSE *)));
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 *));
void sig_report __P((int));
/*
* Cleaning Cost Functions:
*
* These return the cost of cleaning a segment. The higher the cost value
* the better it is to clean the segment, so empty segments have the highest
* cost. (It is probably better to think of this as a priority value
* instead).
*
* This is the cost-benefit policy simulated and described in Rosenblum's
* 1991 SOSP paper.
*/
int
cost_benefit(fsp, su)
FS_INFO *fsp; /* file system information */
SEGUSE *su;
{
struct lfs *lfsp;
struct timeval t;
int age;
int live;
gettimeofday(&t, NULL);
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).
* age is in seconds.
*
* priority = ((seg_size - live) * age) / (seg_size + live)
*/
#ifdef VERBOSE
if (live < 0 || live > seg_size(lfsp)) {
err(0, "Bad segusage count: %d", live);
live = 0;
}
#endif
return (lblkno(lfsp, seg_size(lfsp) - live) * age)
/ lblkno(lfsp, seg_size(lfsp) + live);
}
}
int
main(argc, argv)
int argc;
char *argv[];
{
FS_INFO *fsp;
struct statfs *lstatfsp; /* file system stats */
struct timeval timeout; /* sleep timeout */
fsid_t fsid;
int i, nodaemon;
int opt, cmd_err;
char *fs_name; /* name of filesystem to clean */
extern int optind;
cmd_err = nodaemon = 0;
while ((opt = getopt(argc, argv, "smd")) != EOF) {
switch (opt) {
case 's': /* small writes */
do_small = 1;
break;
case 'm':
do_mmap = 1;
break;
case 'd':
nodaemon = 1;
break;
default:
++cmd_err;
}
}
argc -= optind;
argv += optind;
if (cmd_err || (argc != 1))
err(1, "usage: lfs_cleanerd [-smd] fs_name");
fs_name = argv[0];
signal(SIGINT, sig_report);
signal(SIGUSR1, sig_report);
signal(SIGUSR2, sig_report);
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);
}
if (!nodaemon) /* should we become a daemon, chdir to / & close fd's */
if (daemon(0, 0) == -1)
err(1, "lfs_cleanerd: couldn't become a daemon!");
timeout.tv_sec = 5*60; /* five minutes */
timeout.tv_usec = 0;
fsid.val[0] = 0;
fsid.val[1] = 0;
for (fsp = get_fs_info(lstatfsp, do_mmap); ;
reread_fs_info(fsp, do_mmap)) {
/*
* clean the filesystem, and, if it needed cleaning
* (i.e. it returned nonzero) try it again
* to make sure that some nasty process hasn't just
* filled the disk system up.
*/
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");
#ifdef VERBOSE
(void)printf("Cleaner waking up.\n");
#endif
}
}
/* return the number of segments cleaned */
int
clean_loop(fsp)
FS_INFO *fsp; /* file system information */
{
double loadavg[MAXLOADS];
time_t now;
u_long max_free_segs;
/*
* Compute the maximum possible number of free segments, given the
* number of free blocks.
*/
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);
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)) {
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);
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.
*/
if (getloadavg(loadavg, MAXLOADS) == -1) {
perror("getloadavg: failed\n");
return (-1);
}
if (loadavg[ONE_MIN] == 0.0 && loadavg[FIVE_MIN] &&
fsp->fi_cip->clean < max_free_segs * IDLE_LIM) {
clean_fs(fsp, cost_benefit);
printf("Cleaner Running at %s (system idle)\n",
ctime(&now));
return (1);
}
}
printf("Cleaner Not Running at %s\n", ctime(&now));
return (0);
}
void
clean_fs(fsp, cost_func)
FS_INFO *fsp; /* file system information */
int (*cost_func) __P((FS_INFO *, SEGUSE *));
{
struct seglist *segs, *sp;
int i;
if ((segs =
malloc(fsp->fi_lfs.lfs_nseg * sizeof(struct seglist))) == NULL) {
err(0, "malloc failed");
return;
}
i = choose_segments(fsp, segs, cost_func);
#ifdef VERBOSE
printf("clean_fs: found %d segments to clean in file system %s\n",
i, fsp->fi_statfsp->f_mntonname);
fflush(stdout);
#endif
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);
}
/*
* Segment with the highest priority get sorted to the beginning of the
* list. This sort assumes that empty segments always have a higher
* cost/benefit than any utilized segment.
*/
int
cost_compare(a, b)
const void *a;
const void *b;
{
return (((struct seglist *)b)->sl_cost -
((struct seglist *)a)->sl_cost);
}
/*
* Returns the number of segments to be cleaned with the elements of seglist
* filled in.
*/
int
choose_segments(fsp, seglist, cost_func)
FS_INFO *fsp;
struct seglist *seglist;
int (*cost_func) __P((FS_INFO *, SEGUSE *));
{
struct lfs *lfsp;
struct seglist *sp;
SEGUSE *sup;
int i, nsegs;
lfsp = &fsp->fi_lfs;
#ifdef VERBOSE
(void)printf("Entering choose_segments\n");
#endif
dump_super(lfsp);
dump_cleaner_info(fsp->fi_cip);
for (sp = seglist, i = 0; i < lfsp->lfs_nseg; ++i) {
sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, i);
PRINT_SEGUSE(sup, i);
if (!(sup->su_flags & SEGUSE_DIRTY) ||
sup->su_flags & SEGUSE_ACTIVE)
continue;
#ifdef VERBOSE
(void)printf("\tchoosing segment %d\n", i);
#endif
sp->sl_cost = (*cost_func)(fsp, sup);
sp->sl_id = i;
sp->sl_empty = sup->su_nbytes ? 0 : 1;
++sp;
}
nsegs = sp - seglist;
qsort(seglist, nsegs, sizeof(struct seglist), cost_compare);
#ifdef VERBOSE
(void)printf("Returning %d segments\n", nsegs);
#endif
return (nsegs);
}
int
clean_segment(fsp, id)
FS_INFO *fsp; /* file system information */
int id; /* segment number */
{
BLOCK_INFO *block_array, *bp;
SEGUSE *sp;
struct lfs *lfsp;
struct tossstruct t;
caddr_t seg_buf;
int num_blocks, maxblocks, clean_blocks;
lfsp = &fsp->fi_lfs;
sp = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, id);
#ifdef VERBOSE
(void)printf("cleaning segment %d: contains %lu bytes\n", id,
sp->su_nbytes);
fflush(stdout);
#endif
/* XXX could add debugging to verify that segment is really empty */
if (sp->su_nbytes == sp->su_nsums * LFS_SUMMARY_SIZE) {
++cleaner_stats.segs_empty;
return (0);
}
/* map the segment into a buffer */
if (mmap_segment(fsp, id, &seg_buf, do_mmap) < 0) {
err(0, "mmap_segment failed");
++cleaner_stats.segs_error;
return (-1);
}
/* get a list of blocks that are contained by the segment */
if (lfs_segmapv(fsp, id, seg_buf, &block_array, &num_blocks) < 0) {
err(0, "clean_segment: lfs_segmapv failed");
++cleaner_stats.segs_error;
return (-1);
}
cleaner_stats.blocks_read += fsp->fi_lfs.lfs_ssize;
#ifdef VERBOSE
(void)printf("lfs_segmapv returned %d blocks\n", num_blocks);
fflush(stdout);
#endif
/* get the current disk address of blocks contained by the segment */
if (lfs_bmapv(&fsp->fi_statfsp->f_fsid, block_array, num_blocks) < 0) {
perror("clean_segment: lfs_bmapv failed\n");
++cleaner_stats.segs_error;
return -1;
}
/* Now toss any blocks not in the current segment */
t.lfs = lfsp;
t.seg = id;
toss(block_array, &num_blocks, sizeof(BLOCK_INFO), bi_tossold, &t);
/* Check if last element should be tossed */
if (num_blocks && bi_tossold(&t, block_array + num_blocks - 1, NULL))
--num_blocks;
#ifdef VERBOSE
{
BLOCK_INFO *_bip;
u_long *lp;
int i;
(void)printf("after bmapv still have %d blocks\n", num_blocks);
fflush(stdout);
if (num_blocks)
printf("BLOCK INFOS\n");
for (_bip = block_array, i=0; i < num_blocks; ++_bip, ++i) {
PRINT_BINFO(_bip);
lp = (u_long *)_bip->bi_bp;
}
}
#endif
cleaner_stats.blocks_written += num_blocks;
if (do_small)
maxblocks = MAXPHYS / fsp->fi_lfs.lfs_bsize - 1;
else
maxblocks = num_blocks;
for (bp = block_array; num_blocks > 0; bp += clean_blocks) {
clean_blocks = maxblocks < num_blocks ? maxblocks : num_blocks;
if (lfs_markv(&fsp->fi_statfsp->f_fsid,
bp, clean_blocks) < 0) {
err(0, "clean_segment: lfs_markv failed");
++cleaner_stats.segs_error;
return (-1);
}
num_blocks -= clean_blocks;
}
free(block_array);
munmap_segment(fsp, seg_buf, do_mmap);
++cleaner_stats.segs_cleaned;
return (0);
}
int
bi_tossold(client, a, b)
const void *client;
const void *a;
const void *b;
{
const struct tossstruct *t;
t = (struct tossstruct *)client;
return (((BLOCK_INFO *)a)->bi_daddr == LFS_UNUSED_DADDR ||
datosn(t->lfs, ((BLOCK_INFO *)a)->bi_daddr) != t->seg);
}
void
sig_report(sig)
int sig;
{
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);
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;
}
if (sig == SIGINT)
exit(0);
}

View file

@ -0,0 +1,77 @@
.\" Copyright (c) 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.
.\"
.\" @(#)lfs_cleanerd.8 8.2 (Berkeley) 12/11/93
.\"
.Dd "December 11, 1993"
.Dt LFS_CLEANERD 8
.Os BSD 4.4
.Sh NAME
.Nm lfs_cleanerd
.Nd garbage collect a log-structured file system
.Sh SYNOPSIS
.Nm lfs_cleanerd
.Op Fl ds
.Pa node
.Sh DESCRIPTION
The
.Nm lfs_cleanerd
command starts a daemon process which garbage-collects
the log-structured file system residing at the point named by
.Ar node
in the global file system namespace.
This command is normally executed by
.Xr mount_lfs 8
when the log-structured file system is mounted.
The daemon will exit within a few minutes
of when the file system it was cleaning is unmounted.
.Pp
Garbage collection on a log-structured file system is done by scanning
the file system's segments for active, i.e. referenced, data and copying
it to new segments.
When all of the active data in a given segment has been copied to a new
segment that segment can be marked as empty, thus reclaiming the space
taken by the inactive data which was in it.
.Pp
The following options are available:
.Bl -tag -width indent
.It Fl d
Run in debug mode.
Do not become a daemon process, and print debugging information.
.It Fl s
When cleaning the file system, read data in small chunks.
.El
.Sh SEE ALSO
.Xr mount_lfs 8
.Sh HISTORY
The
.Nm lfs_cleanerd
utility first appeared in 4.4BSD.

View file

@ -0,0 +1,671 @@
/*-
* Copyright (c) 1992, 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[] = "@(#)library.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <ufs/ufs/dinode.h>
#include <ufs/lfs/lfs.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "clean.h"
void add_blocks __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
daddr_t, daddr_t));
void add_inodes __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
daddr_t));
int bi_compare __P((const void *, const void *));
int bi_toss __P((const void *, const void *, const void *));
void get_ifile __P((FS_INFO *, int));
int get_superblock __P((FS_INFO *, struct lfs *));
int pseg_valid __P((FS_INFO *, SEGSUM *));
/*
* This function will get information on a a filesystem which matches
* the name and type given. If a "name" is in a filesystem of the given
* type, then buf is filled with that filesystem's info, and the
* a non-zero value is returned.
*/
int
fs_getmntinfo(buf, name, type)
struct statfs **buf;
char *name;
int type;
{
/* allocate space for the filesystem info */
*buf = (struct statfs *)malloc(sizeof(struct statfs));
if (*buf == NULL)
return 0;
/* grab the filesystem info */
if (statfs(name, *buf) < 0) {
free(*buf);
return 0;
}
/* check to see if it's the one we want */
if (((*buf)->f_type != type) ||
strncmp(name, (*buf)->f_mntonname, MNAMELEN)) {
/* "this is not the filesystem you're looking for */
free(*buf);
return 0;
}
return 1;
}
/*
* Get all the information available on an LFS file system.
* Returns an pointer to an FS_INFO structure, NULL on error.
*/
FS_INFO *
get_fs_info (lstatfsp, use_mmap)
struct statfs *lstatfsp; /* IN: pointer to statfs struct */
int use_mmap; /* IN: mmap or read */
{
FS_INFO *fsp;
int i;
fsp = (FS_INFO *)malloc(sizeof(FS_INFO));
if (fsp == NULL)
return NULL;
bzero(fsp, sizeof(FS_INFO));
fsp->fi_statfsp = lstatfsp;
if (get_superblock (fsp, &fsp->fi_lfs))
err(1, "get_fs_info: get_superblock failed");
fsp->fi_daddr_shift =
fsp->fi_lfs.lfs_bshift - fsp->fi_lfs.lfs_fsbtodb;
get_ifile (fsp, use_mmap);
return (fsp);
}
/*
* 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
* refresh the file system information (statfs) info.
*/
void
reread_fs_info(fsp, use_mmap)
FS_INFO *fsp; /* IN: prointer fs_infos to reread */
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)
*/
int
get_superblock (fsp, sbp)
FS_INFO *fsp; /* local file system info structure */
struct lfs *sbp;
{
char mntfromname[MNAMELEN+1];
int fid;
strcpy(mntfromname, "/dev/r");
strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
err(0, "get_superblock: bad open");
return (-1);
}
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.
*/
void
get_ifile (fsp, use_mmap)
FS_INFO *fsp;
int use_mmap;
{
struct stat file_stat;
caddr_t ifp;
char *ifile_name;
int count, fid;
ifp = NULL;
ifile_name = malloc(strlen(fsp->fi_statfsp->f_mntonname) +
strlen(IFILE_NAME)+2);
strcat(strcat(strcpy(ifile_name, fsp->fi_statfsp->f_mntonname), "/"),
IFILE_NAME);
if ((fid = open(ifile_name, O_RDWR, (mode_t)0)) < 0)
err(1, "get_ifile: bad open");
if (fstat (fid, &file_stat))
err(1, "get_ifile: fstat failed");
if (use_mmap && file_stat.st_size == fsp->fi_ifile_length) {
(void) close(fid);
return;
}
/* get the ifile */
if (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))
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");
redo_read:
count = read (fid, ifp, (size_t) file_stat.st_size);
if (count < 0)
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");
goto redo_read;
}
}
fsp->fi_ifile_length = file_stat.st_size;
close (fid);
fsp->fi_cip = (CLEANERINFO *)ifp;
fsp->fi_segusep = (SEGUSE *)(ifp + CLEANSIZE(fsp));
fsp->fi_ifilep = (IFILE *)((caddr_t)fsp->fi_segusep + SEGTABSIZE(fsp));
/*
* The number of ifile entries is equal to the number of blocks
* blocks in the ifile minus the ones allocated to cleaner info
* and segment usage table multiplied by the number of ifile
* entries per page.
*/
fsp->fi_ifile_count = (fsp->fi_ifile_length >> fsp->fi_lfs.lfs_bshift -
fsp->fi_lfs.lfs_cleansz - fsp->fi_lfs.lfs_segtabsz) *
fsp->fi_lfs.lfs_ifpb;
free (ifile_name);
}
/*
* This function will scan a segment and return a list of
* <inode, blocknum> pairs which indicate which blocks were
* contained as live data within the segment when the segment
* summary was read (it may have "died" since then). Any given
* pair will be listed at most once.
*/
int
lfs_segmapv(fsp, seg, seg_buf, blocks, bcount)
FS_INFO *fsp; /* pointer to local file system information */
int seg; /* the segment number */
caddr_t seg_buf; /* the buffer containing the segment's data */
BLOCK_INFO **blocks; /* OUT: array of block_info for live blocks */
int *bcount; /* OUT: number of active blocks in segment */
{
BLOCK_INFO *bip;
SEGSUM *sp;
SEGUSE *sup;
FINFO *fip;
struct lfs *lfsp;
caddr_t s, segend;
daddr_t pseg_addr, seg_addr;
int i, nelem, nblocks, sumsize;
time_t timestamp;
lfsp = &fsp->fi_lfs;
nelem = 2 * lfsp->lfs_ssize;
if (!(bip = malloc(nelem * sizeof(BLOCK_INFO))))
goto err0;
sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, seg);
s = seg_buf + (sup->su_flags & SEGUSE_SUPERBLOCK ? LFS_SBPAD : 0);
seg_addr = sntoda(lfsp, seg);
pseg_addr = seg_addr + (sup->su_flags & SEGUSE_SUPERBLOCK ? btodb(LFS_SBPAD) : 0);
#ifdef VERBOSE
printf("\tsegment buffer at: 0x%x\tseg_addr 0x%x\n", s, seg_addr);
#endif /* VERBOSE */
*bcount = 0;
for (segend = seg_buf + seg_size(lfsp), timestamp = 0; s < segend; ) {
sp = (SEGSUM *)s;
#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 */
sumsize = sizeof(SEGSUM) +
(sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
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]);
}
if (sumsize > LFS_SUMMARY_SIZE) {
fprintf(stderr,
"Segment %d summary block too big: %d\n",
seg, sumsize);
exit(1);
}
#endif
if (*bcount + nblocks + sp->ss_ninos > nelem) {
nelem = *bcount + nblocks + sp->ss_ninos;
bip = realloc (bip, nelem * sizeof(BLOCK_INFO));
if (!bip)
goto err0;
}
add_blocks(fsp, bip, bcount, sp, seg_buf, seg_addr, pseg_addr);
add_inodes(fsp, bip, bcount, sp, seg_buf, seg_addr);
pseg_addr += fsbtodb(lfsp, nblocks) +
bytetoda(fsp, LFS_SUMMARY_SIZE);
s += (nblocks << lfsp->lfs_bshift) + LFS_SUMMARY_SIZE;
}
qsort(bip, *bcount, sizeof(BLOCK_INFO), bi_compare);
toss(bip, bcount, sizeof(BLOCK_INFO), bi_toss, NULL);
#ifdef VERBOSE
{
BLOCK_INFO *_bip;
int i;
printf("BLOCK INFOS\n");
for (_bip = bip, i=0; i < *bcount; ++_bip, ++i)
PRINT_BINFO(_bip);
}
#endif
*blocks = bip;
return (0);
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.
*/
void
add_blocks (fsp, bip, countp, sp, seg_buf, segaddr, psegaddr)
FS_INFO *fsp; /* pointer to super block */
BLOCK_INFO *bip; /* Block info array */
int *countp; /* IN/OUT: number of blocks in array */
SEGSUM *sp; /* segment summmary pointer */
caddr_t seg_buf; /* buffer containing segment */
daddr_t segaddr; /* address of this segment */
daddr_t psegaddr; /* address of this partial segment */
{
IFILE *ifp;
FINFO *fip;
caddr_t bp;
daddr_t *dp, *iaddrp;
int db_per_block, i, j;
u_long page_size;
#ifdef VERBOSE
printf("FILE INFOS\n");
#endif
db_per_block = fsbtodb(&fsp->fi_lfs, 1);
page_size = fsp->fi_lfs.lfs_bsize;
bp = seg_buf + datobyte(fsp, psegaddr - segaddr) + LFS_SUMMARY_SIZE;
bip += *countp;
psegaddr += bytetoda(fsp, LFS_SUMMARY_SIZE);
iaddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
--iaddrp;
for (fip = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo;
++i, fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks])) {
ifp = IFILE_ENTRY(&fsp->fi_lfs, fsp->fi_ifilep, fip->fi_ino);
PRINT_FINFO(fip, ifp);
if (ifp->if_version > fip->fi_version)
continue;
dp = &(fip->fi_blocks[0]);
for (j = 0; j < fip->fi_nblocks; j++, dp++) {
while (psegaddr == *iaddrp) {
psegaddr += db_per_block;
bp += page_size;
--iaddrp;
}
bip->bi_inode = fip->fi_ino;
bip->bi_lbn = *dp;
bip->bi_daddr = psegaddr;
bip->bi_segcreate = (time_t)(sp->ss_create);
bip->bi_bp = bp;
bip->bi_version = ifp->if_version;
psegaddr += db_per_block;
bp += page_size;
++bip;
++(*countp);
}
}
}
/*
* For a particular segment summary, reads the inode blocks and adds
* INODE_INFO structures to the array. Returns the number of inodes
* actually added.
*/
void
add_inodes (fsp, bip, countp, sp, seg_buf, seg_addr)
FS_INFO *fsp; /* pointer to super block */
BLOCK_INFO *bip; /* block info array */
int *countp; /* pointer to current number of inodes */
SEGSUM *sp; /* segsum pointer */
caddr_t seg_buf; /* the buffer containing the segment's data */
daddr_t seg_addr; /* disk address of seg_buf */
{
struct dinode *di;
struct lfs *lfsp;
IFILE *ifp;
BLOCK_INFO *bp;
daddr_t *daddrp;
ino_t inum;
int i;
if (sp->ss_ninos <= 0)
return;
bp = bip + *countp;
lfsp = &fsp->fi_lfs;
#ifdef VERBOSE
(void) printf("INODES:\n");
#endif
daddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
for (i = 0; i < sp->ss_ninos; ++i) {
if (i % INOPB(lfsp) == 0) {
--daddrp;
di = (struct dinode *)(seg_buf +
((*daddrp - seg_addr) << fsp->fi_daddr_shift));
} else
++di;
inum = di->di_inumber;
bp->bi_lbn = LFS_UNUSED_LBN;
bp->bi_inode = inum;
bp->bi_daddr = *daddrp;
bp->bi_bp = di;
bp->bi_segcreate = sp->ss_create;
if (inum == LFS_IFILE_INUM) {
bp->bi_version = 1; /* Ifile version should be 1 */
bp++;
++(*countp);
PRINT_INODE(1, bp);
} else {
ifp = IFILE_ENTRY(lfsp, fsp->fi_ifilep, inum);
PRINT_INODE(ifp->if_daddr == *daddrp, bp);
bp->bi_version = ifp->if_version;
if (ifp->if_daddr == *daddrp) {
bp++;
++(*countp);
}
}
}
}
/*
* Checks the summary checksum and the data checksum to determine if the
* 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 */
SEGSUM *ssp; /* pointer to segment summary block */
{
caddr_t p;
int i, nblocks;
u_long *datap;
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;
for (i = 0; i < nblocks; ++i) {
datap[i] = *((u_long *)p);
p += fsp->fi_lfs.lfs_bsize;
}
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
mmap_segment (fsp, segment, segbuf, use_mmap)
FS_INFO *fsp; /* file system information */
int segment; /* segment number */
caddr_t *segbuf; /* pointer to buffer area */
int use_mmap; /* mmap instead of read */
{
struct lfs *lfsp;
int fid; /* fildes for file system device */
daddr_t seg_daddr; /* base disk address of segment */
off_t seg_byte;
size_t ssize;
char mntfromname[MNAMELEN+2];
lfsp = &fsp->fi_lfs;
/* get the disk address of the beginning of the segment */
seg_daddr = sntoda(lfsp, segment);
seg_byte = datobyte(fsp, seg_daddr);
ssize = seg_size(lfsp);
strcpy(mntfromname, "/dev/r");
strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
err(0, "mmap_segment: bad open");
return (-1);
}
if (use_mmap) {
*segbuf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ,
0, fid, seg_byte);
if (*(long *)segbuf < 0) {
err(0, "mmap_segment: mmap failed");
return (NULL);
}
} else {
#ifdef VERBOSE
printf("mmap_segment\tseg_daddr: %lu\tseg_size: %lu\tseg_offset: %qu\n",
seg_daddr, ssize, seg_byte);
#endif
/* malloc the space for the buffer */
*segbuf = malloc(ssize);
if (!*segbuf) {
err(0, "mmap_segment: malloc failed");
return(NULL);
}
/* read the segment data into the buffer */
if (lseek (fid, seg_byte, SEEK_SET) != seg_byte) {
err (0, "mmap_segment: bad lseek");
free(*segbuf);
return (-1);
}
if (read (fid, *segbuf, ssize) != ssize) {
err (0, "mmap_segment: bad read");
free(*segbuf);
return (-1);
}
}
close (fid);
return (0);
}
void
munmap_segment (fsp, seg_buf, use_mmap)
FS_INFO *fsp; /* file system information */
caddr_t seg_buf; /* pointer to buffer area */
int use_mmap; /* mmap instead of read/write */
{
if (use_mmap)
munmap (seg_buf, seg_size(&fsp->fi_lfs));
else
free (seg_buf);
}
/*
* USEFUL DEBUGGING TOOLS:
*/
void
print_SEGSUM (lfsp, p)
struct lfs *lfsp;
SEGSUM *p;
{
if (p)
(void) dump_summary(lfsp, p, DUMP_ALL, NULL);
else printf("0x0");
fflush(stdout);
}
int
bi_compare(a, b)
const void *a;
const void *b;
{
const BLOCK_INFO *ba, *bb;
int diff;
ba = a;
bb = b;
if (diff = (int)(ba->bi_inode - bb->bi_inode))
return (diff);
if (diff = (int)(ba->bi_lbn - bb->bi_lbn)) {
if (ba->bi_lbn == LFS_UNUSED_LBN)
return(-1);
else if (bb->bi_lbn == LFS_UNUSED_LBN)
return(1);
else if (ba->bi_lbn < 0 && bb->bi_lbn >= 0)
return(1);
else if (bb->bi_lbn < 0 && ba->bi_lbn >= 0)
return(-1);
else
return (diff);
}
if (diff = (int)(ba->bi_segcreate - bb->bi_segcreate))
return (diff);
diff = (int)(ba->bi_daddr - bb->bi_daddr);
return (diff);
}
int
bi_toss(dummy, a, b)
const void *dummy;
const void *a;
const void *b;
{
const BLOCK_INFO *ba, *bb;
ba = a;
bb = b;
return(ba->bi_inode == bb->bi_inode && ba->bi_lbn == bb->bi_lbn);
}
void
toss(p, nump, size, dotoss, client)
void *p;
int *nump;
size_t size;
int (*dotoss) __P((const void *, const void *, const void *));
void *client;
{
int i;
void *p1;
if (*nump == 0)
return;
for (i = *nump; --i > 0;) {
p1 = p + size;
if (dotoss(client, p, p1)) {
memmove(p, p1, i * size);
--(*nump);
} else
p += size;
}
}

View file

@ -0,0 +1,94 @@
/*-
* Copyright (c) 1992, 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[] = "@(#)misc.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern char *special;
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(const int fatal, const char *fmt, ...)
#else
err(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "%s: ", special);
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
if (errno)
(void)fprintf(stderr, " %s", strerror(errno));
(void)fprintf(stderr, "\n");
if (fatal)
exit(1);
}
void
get(fd, off, p, len)
int fd;
off_t off;
void *p;
size_t len;
{
int rbytes;
if (lseek(fd, off, SEEK_SET) < 0)
err(1, "%s: %s", special, strerror(errno));
if ((rbytes = read(fd, p, len)) < 0)
err(1, "%s: %s", special, strerror(errno));
if (rbytes != len)
err(1, "%s: short read (%d, not %d)", special, rbytes, len);
}

View file

@ -0,0 +1,218 @@
/*-
* Copyright (c) 1992, 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[] = "@(#)print.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/lfs/lfs.h>
#include <stdlib.h>
#include <stdio.h>
#include "clean.h"
/*
* Print out a summary block; return number of blocks in segment; 0
* for empty segment or corrupt segment.
* Returns a pointer to the array of inode addresses.
*/
int
dump_summary(lfsp, sp, flags, iaddrp)
struct lfs *lfsp;
SEGSUM *sp;
u_long flags;
daddr_t **iaddrp;
{
int i, j, numblocks;
daddr_t *dp;
FINFO *fp;
int ck;
if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum,
LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum))))
return(-1);
if (flags & DUMP_SUM_HEADER) {
(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 );
(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:");
dp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
for (--dp, i = 0; i < sp->ss_ninos; --dp)
if (flags & DUMP_INODE_ADDRS) {
(void)printf("\t0x%lx", *dp);
if (++i % 7 == 0)
(void)printf("\n");
} else
++i;
if (iaddrp)
*iaddrp = ++dp;
if (flags & DUMP_INODE_ADDRS)
printf("\n");
for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; ++i) {
numblocks += fp->fi_nblocks;
if (flags & DUMP_FINFOS) {
(void)printf(" %s%d version %d nblocks %d\n",
"FINFO for inode: ", fp->fi_ino,
fp->fi_version, fp->fi_nblocks);
dp = &(fp->fi_blocks[0]);
for (j = 0; j < fp->fi_nblocks; j++, dp++) {
(void)printf("\t%d", *dp);
if ((j % 8) == 7)
(void)printf("\n");
}
if ((j % 8) != 0)
(void)printf("\n");
fp = (FINFO *)dp;
} else {
fp = (FINFO *)(&fp->fi_blocks[fp->fi_nblocks]);
}
}
return (numblocks);
}
#ifdef VERBOSE
void
dump_cleaner_info(ipage)
void *ipage;
{
CLEANERINFO *cip;
cip = (CLEANERINFO *)ipage;
(void)printf("segments clean\t%d\tsegments dirty\t%d\n\n",
cip->clean, cip->dirty);
}
void
dump_super(lfsp)
struct lfs *lfsp;
{
int i;
(void)printf("%s0x%X\t%s0x%X\t%s%d\t%s%d\n",
"magic ", lfsp->lfs_magic,
"version ", lfsp->lfs_version,
"size ", lfsp->lfs_size,
"ssize ", lfsp->lfs_ssize);
(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
"dsize ", lfsp->lfs_dsize,
"bsize ", lfsp->lfs_bsize,
"fsize ", lfsp->lfs_fsize,
"frag ", lfsp->lfs_frag);
(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
"minfree ", lfsp->lfs_minfree,
"inopb ", lfsp->lfs_inopb,
"ifpb ", lfsp->lfs_ifpb,
"nindir ", lfsp->lfs_nindir);
(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
"nseg ", lfsp->lfs_nseg,
"nspf ", lfsp->lfs_nspf,
"cleansz ", lfsp->lfs_cleansz,
"segtabsz ", lfsp->lfs_segtabsz);
(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%X\t\t%s%d\t%s0x%X\t%s%d\n",
"ffmask ", lfsp->lfs_ffmask,
"ffshift ", lfsp->lfs_ffshift,
"fbmask ", lfsp->lfs_fbmask,
"fbshift ", lfsp->lfs_fbshift);
(void)printf("%s%d\t\t%s0x%X\t%s0x%qx\n",
"fsbtodb ", lfsp->lfs_fsbtodb,
"cksum ", lfsp->lfs_cksum,
"maxfilesize ", lfsp->lfs_maxfilesize);
(void)printf("Superblock disk addresses:\t");
for (i = 0; i < LFS_MAXNUMSB; i++) {
(void)printf(" 0x%X", lfsp->lfs_sboffs[i]);
if ( i == (LFS_MAXNUMSB >> 1))
(void)printf("\n\t\t\t\t");
}
(void)printf("\n");
(void)printf("Checkpoint Info\n");
(void)printf("%s%d\t%s0x%X\t%s%d\n",
"free ", lfsp->lfs_free,
"idaddr ", lfsp->lfs_idaddr,
"ifile ", lfsp->lfs_ifile);
(void)printf("%s%d\t%s%d\t%s%d\n",
"bfree ", lfsp->lfs_bfree,
"avail ", lfsp->lfs_avail,
"uinodes ", lfsp->lfs_uinodes);
(void)printf("%s%d\t%s0x%X\t%s0x%X\n%s0x%X\t%s0x%X\t",
"nfiles ", lfsp->lfs_nfiles,
"lastseg ", lfsp->lfs_lastseg,
"nextseg ", lfsp->lfs_nextseg,
"curseg ", lfsp->lfs_curseg,
"offset ", lfsp->lfs_offset);
(void)printf("tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp));
(void)printf("\nIn-Memory Information\n");
(void)printf("%s%d\t%s0x%X\t%s%d\t%s%d\t%s%d\n",
"seglock ", lfsp->lfs_seglock,
"iocount ", lfsp->lfs_iocount,
"writer ", lfsp->lfs_writer,
"dirops ", lfsp->lfs_dirops,
"doifile ", lfsp->lfs_doifile );
(void)printf("%s%d\t%s%d\t%s0x%X\t%s%d\n",
"nactive ", lfsp->lfs_nactive,
"fmod ", lfsp->lfs_fmod,
"clean ", lfsp->lfs_clean,
"ronly ", lfsp->lfs_ronly);
}
#endif /* VERBOSE */

View file

@ -0,0 +1,9 @@
# @(#)Makefile 8.1 (Berkeley) 7/19/93
PROG= mail.local
MAN8= mail.local.0
BINOWN= root
BINMODE=4555
INSTALLFLAGS=-fschg
.include <bsd.prog.mk>

View file

@ -0,0 +1,105 @@
.\" 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.
.\"
.\" @(#)mail.local.8 8.2 (Berkeley) 12/11/93
.\"
.Dd December 11, 1993
.Dt MAIL.LOCAL 8
.Os
.Sh NAME
.Nm mail.local
.Nd store mail in a mailbox
.Sh SYNOPSIS
.Nm mail.local
.Op Fl f Ar from
.Ar user ...
.Sh DESCRIPTION
.Nm Mail.local
reads the standard input up to an end-of-file and appends it to each
.Ar user's
.Pa mail
file.
The
.Ar user
must be a valid user name.
.Pp
The options are as follows:
.Bl -tag -width xxxfrom
.It Fl f Ar from
Specify the sender's name.
.El
.Pp
Individual mail messages in the mailbox are delimited by an empty
line followed by a line beginning with the string ``From ''.
A line containing the string ``From '', the sender's name and a time stamp
is prepended to each delivered mail message.
A blank line is appended to each message.
A greater-than character (``>'') is prepended to any line in the message
which could be mistaken for a ``From '' delimiter line.
.Pp
The mail files are exclusively locked with
.Xr flock 2
while mail is appended.
.Pp
If the ``biff'' service is returned by
.Xr getservbyname 3 ,
the biff server is notified of delivered mail.
.Pp
The
.Nm mail.local
utility exits 0 on success, and >0 if an error occurs.
.Sh ENVIRONMENT
.Bl -tag -width indent
.It Ev TZ
Used to set the appropriate time zone on the timestamp.
.El
.Sh FILES
.Bl -tag -width /tmp/local.XXXXXX -compact
.It Pa /tmp/local.XXXXXX
temporary files
.It Pa /var/mail/user
user's mailbox directory
.El
.Sh SEE ALSO
.Xr mail 1 ,
.Xr xsend 1 ,
.Xr flock 2 ,
.Xr getservbyname 3 ,
.Xr comsat 8 ,
.Xr sendmail 8
.Sh HISTORY
A superset of
.Nm mail.local
(handling mailbox reading as well as mail delivery)
appeared in
.At v7 .
as the program
.Nm mail .

View file

@ -0,0 +1,511 @@
/*-
* Copyright (c) 1990, 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1990, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)mail.local.c 8.6 (Berkeley) 4/8/94";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "pathnames.h"
int eval = EX_OK; /* sysexits.h error value. */
void deliver __P((int, char *));
void e_to_sys __P((int));
__dead void err __P((const char *, ...));
void notifybiff __P((char *));
int store __P((char *));
void usage __P((void));
void vwarn __P((const char *, _BSD_VA_LIST_));
void warn __P((const char *, ...));
int
main(argc, argv)
int argc;
char *argv[];
{
struct passwd *pw;
int ch, fd;
uid_t uid;
char *from;
openlog("mail.local", 0, LOG_MAIL);
from = NULL;
while ((ch = getopt(argc, argv, "df:r:")) != EOF)
switch(ch) {
case 'd': /* Backward compatible. */
break;
case 'f':
case 'r': /* Backward compatible. */
if (from != NULL) {
warn("multiple -f options");
usage();
}
from = optarg;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (!*argv)
usage();
/*
* If from not specified, use the name from getlogin() if the
* uid matches, otherwise, use the name from the password file
* corresponding to the uid.
*/
uid = getuid();
if (!from && (!(from = getlogin()) ||
!(pw = getpwnam(from)) || pw->pw_uid != uid))
from = (pw = getpwuid(uid)) ? pw->pw_name : "???";
/*
* There is no way to distinguish the error status of one delivery
* from the rest of the deliveries. So, if we failed hard on one
* or more deliveries, but had no failures on any of the others, we
* return a hard failure. If we failed temporarily on one or more
* deliveries, we return a temporary failure regardless of the other
* failures. This results in the delivery being reattempted later
* at the expense of repeated failures and multiple deliveries.
*/
for (fd = store(from); *argv; ++argv)
deliver(fd, *argv);
exit(eval);
}
int
store(from)
char *from;
{
FILE *fp;
time_t tval;
int fd, eline;
char *tn, line[2048];
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(tn);
free(tn);
(void)time(&tval);
(void)fprintf(fp, "From %s %s", from, ctime(&tval));
line[0] = '\0';
for (eline = 1; fgets(line, sizeof(line), stdin);) {
if (line[0] == '\n')
eline = 1;
else {
if (eline && line[0] == 'F' &&
!memcmp(line, "From ", 5))
(void)putc('>', fp);
eline = 0;
}
(void)fprintf(fp, "%s", line);
if (ferror(fp)) {
e_to_sys(errno);
err("temporary file write error");
}
}
/* If message not newline terminated, need an extra. */
if (!strchr(line, '\n'))
(void)putc('\n', fp);
/* Output a newline; note, empty messages are allowed. */
(void)putc('\n', fp);
if (fflush(fp) == EOF || ferror(fp)) {
e_to_sys(errno);
err("temporary file write error");
}
return (fd);
}
void
deliver(fd, name)
int fd;
char *name;
{
struct stat fsb, sb;
struct passwd *pw;
int mbfd, nr, nw, off;
char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
off_t curoff;
/*
* Disallow delivery to unknown names -- special mailboxes can be
* handled in the sendmail aliases file.
*/
if (!(pw = getpwnam(name))) {
if (eval != EX_TEMPFAIL)
eval = EX_UNAVAILABLE;
warn("unknown name: %s", name);
return;
}
(void)snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
/*
* If the mailbox is linked or a symlink, fail. There's an obvious
* race here, that the file was replaced with a symbolic link after
* the lstat returned, but before the open. We attempt to detect
* this by comparing the original stat information and information
* returned by an fstat of the file descriptor returned by the open.
*
* NB: this is a symptom of a larger problem, that the mail spooling
* directory is writeable by the wrong users. If that directory is
* writeable, system security is compromised for other reasons, and
* it cannot be fixed here.
*
* If we created the mailbox, set the owner/group. If that fails,
* just return. Another process may have already opened it, so we
* can't unlink it. Historically, binmail set the owner/group at
* each mail delivery. We no longer do this, assuming that if the
* ownership or permissions were changed there was a reason.
*
* XXX
* open(2) should support flock'ing the file.
*/
tryagain:
if (lstat(path, &sb)) {
mbfd = open(path,
O_APPEND|O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
if (mbfd == -1) {
if (errno == EEXIST)
goto 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);
return;
}
} else if (sb.st_nlink != 1 || S_ISLNK(sb.st_mode)) {
e_to_sys(errno);
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_ISLNK(fsb.st_mode) || sb.st_dev != fsb.st_dev ||
sb.st_ino != fsb.st_ino)) {
warn("%s: file changed after open", path);
(void)close(mbfd);
return;
}
}
if (mbfd == -1) {
e_to_sys(errno);
warn("%s: %s", path, strerror(errno));
return;
}
/* Wait until we can get a lock on the file. */
if (flock(mbfd, LOCK_EX)) {
e_to_sys(errno);
warn("%s: %s", path, strerror(errno));
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), "%s@%qd\n", name, curoff);
/* Copy the message into the file. */
if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
e_to_sys(errno);
warn("temporary file: %s", strerror(errno));
goto err1;
}
while ((nr = read(fd, buf, sizeof(buf))) > 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 err2;;
}
if (nr < 0) {
e_to_sys(errno);
warn("temporary file: %s", strerror(errno));
goto err2;;
}
/* Flush to disk, don't wait for update. */
if (fsync(mbfd)) {
e_to_sys(errno);
warn("%s: %s", path, strerror(errno));
err2: (void)ftruncate(mbfd, curoff);
err1: (void)close(mbfd);
return;
}
/* Close and check -- NFS doesn't write until the close. */
if (close(mbfd)) {
e_to_sys(errno);
warn("%s: %s", path, strerror(errno));
return;
}
notifybiff(biffmsg);
}
void
notifybiff(msg)
char *msg;
{
static struct sockaddr_in addr;
static int f = -1;
struct hostent *hp;
struct servent *sp;
int len;
if (!addr.sin_family) {
/* Be silent if biff service not available. */
if (!(sp = getservbyname("biff", "udp")))
return;
if (!(hp = gethostbyname("localhost"))) {
warn("localhost: %s", strerror(errno));
return;
}
addr.sin_family = hp->h_addrtype;
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) {
warn("socket: %s", strerror(errno));
return;
}
len = strlen(msg) + 1;
if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr))
!= len)
warn("sendto biff: %s", strerror(errno));
}
void
usage()
{
eval = EX_USAGE;
err("usage: mail.local [-f from] user ...");
}
#if __STDC__
void
err(const char *fmt, ...)
#else
void
err(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
vwarn(fmt, ap);
va_end(ap);
exit(eval);
}
void
#if __STDC__
warn(const char *fmt, ...)
#else
warn(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
vwarn(fmt, ap);
va_end(ap);
}
void
vwarn(fmt, ap)
const char *fmt;
_BSD_VA_LIST_ ap;
{
/*
* Log the message to stderr.
*
* Don't use LOG_PERROR as an openlog() flag to do this,
* it's not portable enough.
*/
if (eval != EX_USAGE)
(void)fprintf(stderr, "mail.local: ");
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, "\n");
/* Log the message to syslog. */
vsyslog(LOG_ERR, fmt, ap);
}
/*
* e_to_sys --
* Guess which errno's are temporary. Gag me.
*/
void
e_to_sys(num)
int num;
{
/* Temporary failures override hard errors. */
if (eval == EX_TEMPFAIL)
return;
switch(num) { /* Hopefully temporary errors. */
#ifdef EAGAIN
case EAGAIN: /* Resource temporarily unavailable */
#endif
#ifdef EDQUOT
case EDQUOT: /* Disc quota exceeded */
#endif
#ifdef EBUSY
case EBUSY: /* Device busy */
#endif
#ifdef EPROCLIM
case EPROCLIM: /* Too many processes */
#endif
#ifdef EUSERS
case EUSERS: /* Too many users */
#endif
#ifdef ECONNABORTED
case ECONNABORTED: /* Software caused connection abort */
#endif
#ifdef ECONNREFUSED
case ECONNREFUSED: /* Connection refused */
#endif
#ifdef ECONNRESET
case ECONNRESET: /* Connection reset by peer */
#endif
#ifdef EDEADLK
case EDEADLK: /* Resource deadlock avoided */
#endif
#ifdef EFBIG
case EFBIG: /* File too large */
#endif
#ifdef EHOSTDOWN
case EHOSTDOWN: /* Host is down */
#endif
#ifdef EHOSTUNREACH
case EHOSTUNREACH: /* No route to host */
#endif
#ifdef EMFILE
case EMFILE: /* Too many open files */
#endif
#ifdef ENETDOWN
case ENETDOWN: /* Network is down */
#endif
#ifdef ENETRESET
case ENETRESET: /* Network dropped connection on reset */
#endif
#ifdef ENETUNREACH
case ENETUNREACH: /* Network is unreachable */
#endif
#ifdef ENFILE
case ENFILE: /* Too many open files in system */
#endif
#ifdef ENOBUFS
case ENOBUFS: /* No buffer space available */
#endif
#ifdef ENOMEM
case ENOMEM: /* Cannot allocate memory */
#endif
#ifdef ENOSPC
case ENOSPC: /* No space left on device */
#endif
#ifdef EROFS
case EROFS: /* Read-only file system */
#endif
#ifdef ESTALE
case ESTALE: /* Stale NFS file handle */
#endif
#ifdef ETIMEDOUT
case ETIMEDOUT: /* Connection timed out */
#endif
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK: /* Operation would block. */
#endif
eval = EX_TEMPFAIL;
break;
default:
eval = EX_UNAVAILABLE;
break;
}
}

View file

@ -0,0 +1,37 @@
/*-
* 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
*/
#include <paths.h>
#define _PATH_LOCTMP "/tmp/local.XXXXXX"

11
libexec/rbootd/Makefile Normal file
View file

@ -0,0 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
PROG= rbootd
SRCS= bpf.c conf.c parseconf.c rbootd.c rmpproto.c utils.c
MAN8= rbootd.0
afterinstall:
(cd ${.CURDIR}/bootdir && install -c -o ${BINOWN} -g ${BINGRP} \
-m 444 * ${DESTDIR}/usr/mdec/)
.include <bsd.prog.mk>

422
libexec/rbootd/bpf.c Normal file
View file

@ -0,0 +1,422 @@
/*
* 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.
*
* @(#)bpf.c 8.1 (Berkeley) 6/4/93
*
* Utah $Hdr: bpf.c 3.1 92/07/06$
* Author: Jeff Forys, University of Utah CSS
*/
#ifndef lint
static 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 <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_char *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;
bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
if (ioctl(BpfFd, SIOCADDMULTI, (caddr_t)&ifr) < 0) {
syslog(LOG_WARNING,
"bpf: can't add mcast addr (%m), setting promiscuous mode");
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_char *)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;
{
register int datlen, caplen, hdrlen;
static u_char *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;
bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp,
sizeof(struct timeval));
bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, 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;
bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)
(void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);
(void) close(BpfFd);
BpfFd = -1;
}

90
libexec/rbootd/conf.c Normal file
View file

@ -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.
*
* @(#)conf.c 8.1 (Berkeley) 6/4/93
*
* Utah $Hdr: conf.c 3.1 92/07/06$
* Author: Jeff Forys, University of Utah CSS
*/
#ifndef lint
static 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 *ProgName; /* path-stripped argv[0] */
char MyHost[MAXHOSTNAMELEN+1]; /* host name */
int 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_short 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 */
char RmpMcastAddr[RMP_ADDRLEN] = RMP_ADDR; /* RMP multicast address */

185
libexec/rbootd/defs.h Normal file
View file

@ -0,0 +1,185 @@
/*
* 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.
*
* @(#)defs.h 8.1 (Berkeley) 6/4/93
*
* 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_char 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 *ProgName; /* path-stripped argv[0] */
extern char MyHost[]; /* this hosts' name */
extern int 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_short 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 char 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_char *));
CLIENT *NewClient __P((u_char *));
RMPCONN *NewConn __P((RMPCONN *));
char *NewStr __P((char *));
u_char *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 *));

359
libexec/rbootd/parseconf.c Normal file
View file

@ -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.
*
* @(#)parseconf.c 8.1 (Berkeley) 6/4/93
*
* Utah $Hdr: parseconf.c 3.1 92/07/06$
* Author: Jeff Forys, University of Utah CSS
*/
#ifndef lint
static 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_char *addr;
char line[C_LINELEN];
register char *cp, *bcp;
register 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 = index(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.
** - For speed, we assume a u_char consists of 8 bits.
*/
u_char *
ParseAddr(str)
char *str;
{
static u_char addr[RMP_ADDRLEN];
register char *cp;
register unsigned i;
register int part, subpart;
bzero((char *)&addr[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;
register struct dirent *dp;
register 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);
}

View file

@ -0,0 +1,51 @@
/*
* 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
*
* Utah $Hdr: pathnames.h 3.1 92/07/06$
* Author: Jeff Forys, University of Utah CSS
*/
#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"

156
libexec/rbootd/rbootd.8 Normal file
View file

@ -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.
.\"
.\" @(#)rbootd.8 8.2 (Berkeley) 12/11/93
.\"
.\" 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 ,
.Xr rmp 4
.Sh BUGS
If multiple servers are started on the same interface, each will receive
and respond to the same boot packets.

508
libexec/rbootd/rbootd.c Normal file
View file

@ -0,0 +1,508 @@
/*
* 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.
*
* @(#)rbootd.c 8.2 (Berkeley) 2/22/94
*
* Utah $Hdr: rbootd.c 3.1 92/07/06$
* Author: Jeff Forys, University of Utah CSS
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)rbootd.c 8.2 (Berkeley) 2/22/94";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <ctype.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"
/* fd mask macros (backward compatibility with 4.2BSD) */
#ifndef FD_SET
#ifdef notdef
typedef struct fd_set { /* this should already be in 4.2 */
int fds_bits[1];
} fd_set;
#endif
#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
#define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << (n)))
#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1 << (n)))
#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n)))
#endif
int
main(argc, argv)
int argc;
char *argv[];
{
int c, fd, omask, maxfds;
fd_set rset;
/*
* Find what name we are running under.
*/
ProgName = (ProgName = rindex(argv[0],'/')) ? ++ProgName : *argv;
/*
* 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:")) != EOF)
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 {
fprintf(stderr,
"%s: too many config files (`%s' ignored)\n",
ProgName, 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);
} else {
(void) fclose(stdin); /* dont need these */
(void) fclose(stdout);
/*
* Fork off a child to do the work & exit.
*/
switch(fork()) {
case -1: /* fork failed */
fprintf(stderr, "%s: ", ProgName);
perror("fork");
Exit(0);
case 0: /* this is the CHILD */
break;
default: /* this is the PARENT */
_exit(0);
}
/*
* Try to disassociate from the current tty.
*/
{
char *devtty = "/dev/tty";
int i;
if ((i = open(devtty, O_RDWR)) < 0) {
/* probably already disassociated */
if (setpgrp(0, 0) < 0) {
fprintf(stderr, "%s: ", ProgName);
perror("setpgrp");
}
} else {
if (ioctl(i, (u_long)TIOCNOTTY, (char *)0) < 0){
fprintf(stderr, "%s: ", ProgName);
perror("ioctl");
}
(void) close(i);
}
}
(void) signal(SIGUSR1, DebugOn);
(void) signal(SIGUSR2, DebugOff);
}
(void) fclose(stderr); /* finished with it */
#ifdef SYSLOG4_2
openlog(ProgName, LOG_PID);
#else
openlog(ProgName, LOG_PID, LOG_DAEMON);
#endif
/*
* 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", 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, (fd_set *)0, (fd_set *)0,
(struct timeval *)0);
} else {
timeout.tv_sec = RMP_TIMEOUT;
timeout.tv_usec = 0;
nsel = select(maxfds, &r, (fd_set *)0, (fd_set *)0,
&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()
{
register 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)
register RMPCONN *rconn;
{
register 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);
}
}

95
libexec/rbootd/rmp.h Normal file
View file

@ -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.
*
* @(#)rmp.h 8.1 (Berkeley) 6/4/93
*
* 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_char daddr[RMP_ADDRLEN];
u_char saddr[RMP_ADDRLEN];
u_short len;
};
/*
* HP uses 802.2 LLC with their own local extensions. This struct makes
* sence out of this data (encapsulated in the above 802.3 packet).
*/
struct hp_llc {
u_char dsap; /* 802.2 DSAP */
u_char ssap; /* 802.2 SSAP */
u_short cntrl; /* 802.2 control field */
u_short filler; /* HP filler (must be zero) */
u_short dxsap; /* HP extended DSAP */
u_short sxsap; /* HP extended SSAP */
};

244
libexec/rbootd/rmp_var.h Normal file
View file

@ -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.
*
* @(#)rmp_var.h 8.1 (Berkeley) 6/4/93
*
* 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_char))
#define RMPDONESIZE (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
sizeof(struct rmp_boot_done))
#define RMPBOOTDATA 255
#define RMPREADDATA (RMPDATALEN - \
(2*sizeof(u_char)+sizeof(u_short)+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 cant access words on half-word boundaries. If
* you know that your machine does not suffer from this problem,
* add it to the hp300 #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. We do not support little endian alignment-challenged machines.
*/
#if defined(vax) || defined(tahoe) || defined(hp300)
typedef u_int u_word;
#define WORDZE(w) ((w) == 0)
#define ZEROWORD(w) (w) = 0
#define COPYWORD(w1,w2) (w2) = (w1)
#define GETWORD(w, i) (i) = (w)
#define PUTWORD(i, w) (w) = (i)
#else
#define _WORD_HIGHPART 0 /* XXX: assume Big Endian for now */
#define _WORD_LOWPART 1
typedef struct _uword { u_short 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_int)(w).val[_WORD_HIGHPART]) << 16) | (w).val[_WORD_LOWPART]
#define PUTWORD(i, w) \
{ (w).val[_WORD_HIGHPART] = (u_short) (((i) >> 16) & 0xffff); \
(w).val[_WORD_LOWPART] = (u_short) (i & 0xffff); \
}
#endif
/*
* Packet structures.
*/
struct rmp_raw { /* generic RMP packet */
u_char rmp_type; /* packet type */
u_char rmp_rawdata[RMPDATALEN-1];
};
struct rmp_boot_req { /* boot request */
u_char rmp_type; /* packet type (RMP_BOOT_REQ) */
u_char rmp_retcode; /* return code (0) */
u_word rmp_seqno; /* sequence number (real time clock) */
u_short rmp_session; /* session id (normally 0) */
u_short rmp_version; /* protocol version (RMP_VERSION) */
char rmp_machtype[RMP_MACHLEN]; /* machine type */
u_char rmp_flnmsize; /* length of rmp_flnm */
restofpkt rmp_flnm; /* name of file to be read */
};
struct rmp_boot_repl { /* boot reply */
u_char rmp_type; /* packet type (RMP_BOOT_REPL) */
u_char rmp_retcode; /* return code (normally 0) */
u_word rmp_seqno; /* sequence number (from boot req) */
u_short rmp_session; /* session id (generated) */
u_short rmp_version; /* protocol version (RMP_VERSION) */
u_char rmp_flnmsize; /* length of rmp_flnm */
restofpkt rmp_flnm; /* name of file (from boot req) */
};
struct rmp_read_req { /* read request */
u_char rmp_type; /* packet type (RMP_READ_REQ) */
u_char rmp_retcode; /* return code (0) */
u_word rmp_offset; /* file relative byte offset */
u_short rmp_session; /* session id (from boot repl) */
u_short rmp_size; /* max no of bytes to send */
};
struct rmp_read_repl { /* read reply */
u_char rmp_type; /* packet type (RMP_READ_REPL) */
u_char rmp_retcode; /* return code (normally 0) */
u_word rmp_offset; /* byte offset (from read req) */
u_short rmp_session; /* session id (from read req) */
restofpkt rmp_data; /* data (max size from read req) */
u_char rmp_unused; /* padding to 16-bit boundary */
};
struct rmp_boot_done { /* boot complete */
u_char rmp_type; /* packet type (RMP_BOOT_DONE) */
u_char rmp_retcode; /* return code (0) */
u_word rmp_unused; /* not used (0) */
u_short 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_data
#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

593
libexec/rbootd/rmpproto.c Normal file
View file

@ -0,0 +1,593 @@
/*
* 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.
*
* @(#)rmpproto.c 8.1 (Berkeley) 6/4/93
*
* Utah $Hdr: rmpproto.c 3.1 92/07/06$
* Author: Jeff Forys, University of Utah CSS
*/
#ifndef lint
static 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 (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;
{
register struct rmp_packet *rpl;
register char *src, *dst;
register u_char *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 = 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[];
{
register struct rmp_packet *rpl;
register char *src, *dst;
register u_char *size, 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 = 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;
register struct rmp_packet *rpl;
register char *src, *dst1, *dst2;
register u_char 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 = GenSessID();
rpl->r_brpl.rmp_version = 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 = rindex(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;
RMPCONN *oldconn;
register struct rmp_packet *rpl, *req;
register 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 (req->r_rrq.rmp_session !=
((rpl->r_type == RMP_BOOT_REPL)? rpl->r_brpl.rmp_session:
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 (req->r_rrq.rmp_size > RMPREADDATA)
req->r_rrq.rmp_size = 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) 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 (rconn->rmp.r_rrq.rmp_session !=
((rpl->r_type == RMP_BOOT_REPL)? rpl->r_brpl.rmp_session:
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)
register RMPCONN *rconn;
{
/*
* Set Ethernet Destination address to Source (BPF and the enet
* driver will take care of getting our source address set).
*/
bcopy((char *)&rconn->rmp.hp_hdr.saddr[0],
(char *)&rconn->rmp.hp_hdr.daddr[0], RMP_ADDRLEN);
rconn->rmp.hp_hdr.len = rconn->rmplen - sizeof(struct hp_hdr);
/*
* Reverse 802.2/HP Extended Source & Destination Access Pts.
*/
rconn->rmp.hp_llc.dxsap = HPEXT_SXSAP;
rconn->rmp.hp_llc.sxsap = 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));
}

557
libexec/rbootd/utils.c Normal file
View file

@ -0,0 +1,557 @@
/*
* 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.
*
* @(#)utils.c 8.2 (Berkeley) 2/22/94
*
* Utah $Hdr: utils.c 3.1 92/07/06$
* Author: Jeff Forys, University of Utah CSS
*/
#ifndef lint
static char sccsid[] = "@(#)utils.c 8.2 (Berkeley) 2/22/94";
#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;
register struct rmp_packet *rmp;
int i, omask;
u_int 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, rmp->hp_llc.cntrl);
/* display HP extensions to 802.2 Logical Link Control header */
(void) fprintf(DbgFp, "\tHP Ext: DXSAP:%x SXSAP:%x\n",
rmp->hp_llc.dxsap, 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 (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, rmp->r_brq.rmp_session,
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, rmp->r_brpl.rmp_session,
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, rmp->r_rrq.rmp_session);
(void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n",
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, 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,
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.
** - For speed, we assume a u_char consists of 8 bits.
*/
char *
GetEtherAddr(addr)
u_char *addr;
{
static char Hex[] = "0123456789abcdef";
static char etherstr[RMP_ADDRLEN*3];
register int i;
register char *cp1, *cp2;
/*
* For each byte in `addr', convert it to "<hexchar><hexchar>:".
* The last byte does not get a trailing `:' appended.
*/
i = 0;
cp1 = (char *)addr;
cp2 = etherstr;
for(;;) {
*cp2++ = Hex[*cp1 >> 4 & 0xf];
*cp2++ = Hex[*cp1++ & 0xf];
if (++i == RMP_ADDRLEN)
break;
*cp2++ = ':';
}
*cp2 = '\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)
register u_int size;
register char *flnm;
{
register int i;
(void) fprintf(DbgFp, "\n\t\tFile Name (%d): <", 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_char *addr;
{
CLIENT *ctmp;
if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) {
syslog(LOG_ERR, "NewClient: out of memory (%s)",
GetEtherAddr(addr));
return(NULL);
}
bzero(ctmp, sizeof(CLIENT));
bcopy(addr, &ctmp->addr[0], 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()
{
register 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.
*/
bcopy((char *)rconn, (char *)rtmp, 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)
register 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()
{
register 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)
register 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)
register RMPCONN *rconn;
{
register 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)
register RMPCONN *rconn;
{
register 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;
}
}
}

6
libexec/rexecd/Makefile Normal file
View file

@ -0,0 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
PROG= rexecd
MAN8= rexecd.0
.include <bsd.prog.mk>

148
libexec/rexecd/rexecd.8 Normal file
View file

@ -0,0 +1,148 @@
.\" 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.
.\"
.\" @(#)rexecd.8 8.2 (Berkeley) 12/11/93
.\"
.Dd December 11, 1993
.Dt REXECD 8
.Os BSD 4.2
.Sh NAME
.Nm rexecd
.Nd remote execution server
.Sh SYNOPSIS
.Nm rexecd
.Sh DESCRIPTION
.Nm Rexecd
is the server for the
.Xr rexec 3
routine. The server provides remote execution facilities
with authentication based on user names and
passwords.
.Pp
.Nm Rexecd
listens for service requests at the port indicated in
the ``exec'' service specification; see
.Xr services 5 .
When a service request is received the following protocol
is initiated:
.Bl -enum
.It
The server reads characters from the socket up
to a NUL
.Pq Ql \e0
byte. The resultant string is
interpreted as an
.Tn ASCII
number, base 10.
.It
If the number received in step 1 is non-zero,
it is interpreted as the port number of a secondary
stream to be used for the
.Em stderr .
A second connection is then created to the specified
port on the client's machine.
.It
A NUL terminated user name of at most 16 characters
is retrieved on the initial socket.
.It
A NUL terminated, unencrypted password of at most
16 characters is retrieved on the initial socket.
.It
A NUL terminated command to be passed to a
shell is retrieved on the initial socket. The length of
the command is limited by the upper bound on the size of
the system's argument list.
.It
.Nm Rexecd
then validates the user as is done at login time
and, if the authentication was successful, changes
to the user's home directory, and establishes the user
and group protections of the user.
If any of these steps fail the connection is
aborted with a diagnostic message returned.
.It
A NUL byte is returned on the initial socket
and the command line is passed to the normal login
shell of the user. The
shell inherits the network connections established
by
.Nm rexecd .
.El
.Sh DIAGNOSTICS
Except for the last one listed below,
all diagnostic messages are returned on the initial socket,
after which any network connections are closed.
An error is indicated by a leading byte with a value of
1 (0 is returned in step 7 above upon successful completion
of all the steps prior to the command execution).
.Pp
.Bl -tag -width Ds
.It Sy username too long
The name is
longer than 16 characters.
.It Sy password too long
The password is longer than 16 characters.
.It Sy command too long
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.
.It Sy Password incorrect.
The wrong password was supplied.
.It Sy \&No remote directory.
The
.Xr chdir
command to the home directory failed.
.It Sy Try again.
A
.Xr fork
by the server failed.
.It Sy <shellname>: ...
The user's login shell could not be started.
This message is returned
on the connection associated with the
.Em stderr ,
and is not preceded by a flag byte.
.El
.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
The
.Nm
command appeared in
.Bx 4.2 .

259
libexec/rexecd/rexecd.c Normal file
View file

@ -0,0 +1,259 @@
/*
* 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 copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)rexecd.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 <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*VARARGS1*/
int error();
/*
* remote execute server:
* username\0
* password\0
* command\0
* data
*/
/*ARGSUSED*/
main(argc, argv)
int argc;
char **argv;
{
struct sockaddr_in from;
int fromlen;
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;
struct sockaddr_in asin = { AF_INET };
doit(f, fromp)
int f;
struct sockaddr_in *fromp;
{
char cmdbuf[NCARGS+1], *cp, *namep;
char user[16], pass[16];
struct passwd *pwd;
int s;
u_short port;
int pv[2], pid, ready, readfrom, cc;
char buf[BUFSIZ], sig;
int one = 1;
(void) signal(SIGINT, SIG_DFL);
(void) signal(SIGQUIT, SIG_DFL);
(void) signal(SIGTERM, SIG_DFL);
#ifdef DEBUG
{ int t = open(_PATH_TTY, 2);
if (t >= 0) {
ioctl(t, TIOCNOTTY, (char *)0);
(void) close(t);
}
}
#endif
dup2(f, 0);
dup2(f, 1);
dup2(f, 2);
(void) alarm(60);
port = 0;
for (;;) {
char c;
if (read(f, &c, 1) != 1)
exit(1);
if (c == 0)
break;
port = port * 10 + c - '0';
}
(void) alarm(0);
if (port != 0) {
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
exit(1);
if (bind(s, (struct sockaddr *)&asin, sizeof (asin)) < 0)
exit(1);
(void) alarm(60);
fromp->sin_port = htons(port);
if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0)
exit(1);
(void) alarm(0);
}
getstr(user, sizeof(user), "username");
getstr(pass, sizeof(pass), "password");
getstr(cmdbuf, sizeof(cmdbuf), "command");
setpwent();
pwd = getpwnam(user);
if (pwd == NULL) {
error("Login incorrect.\n");
exit(1);
}
endpwent();
if (*pwd->pw_passwd != '\0') {
namep = crypt(pass, pwd->pw_passwd);
if (strcmp(namep, pwd->pw_passwd)) {
error("Password incorrect.\n");
exit(1);
}
}
if (chdir(pwd->pw_dir) < 0) {
error("No remote directory.\n");
exit(1);
}
(void) write(2, "\0", 1);
if (port) {
(void) pipe(pv);
pid = fork();
if (pid == -1) {
error("Try again.\n");
exit(1);
}
if (pid) {
(void) close(0); (void) close(1); (void) close(2);
(void) close(f); (void) close(pv[1]);
readfrom = (1<<s) | (1<<pv[0]);
ioctl(pv[1], FIONBIO, (char *)&one);
/* should set s nbio! */
do {
ready = readfrom;
(void) select(16, (fd_set *)&ready,
(fd_set *)NULL, (fd_set *)NULL,
(struct timeval *)NULL);
if (ready & (1<<s)) {
if (read(s, &sig, 1) <= 0)
readfrom &= ~(1<<s);
else
killpg(pid, sig);
}
if (ready & (1<<pv[0])) {
cc = read(pv[0], buf, sizeof (buf));
if (cc <= 0) {
shutdown(s, 1+1);
readfrom &= ~(1<<pv[0]);
} else
(void) write(s, buf, cc);
}
} while (readfrom);
exit(0);
}
setpgrp(0, getpid());
(void) close(s); (void)close(pv[0]);
dup2(pv[1], 2);
}
if (*pwd->pw_shell == '\0')
pwd->pw_shell = _PATH_BSHELL;
if (f > 2)
(void) close(f);
(void) setgid((gid_t)pwd->pw_gid);
initgroups(pwd->pw_name, pwd->pw_gid);
(void) setuid((uid_t)pwd->pw_uid);
(void)strcat(path, _PATH_DEFPATH);
environ = envinit;
strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
strncat(shell, pwd->pw_shell, sizeof(shell)-7);
strncat(username, pwd->pw_name, sizeof(username)-6);
cp = strrchr(pwd->pw_shell, '/');
if (cp)
cp++;
else
cp = pwd->pw_shell;
execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
perror(pwd->pw_shell);
exit(1);
}
/*VARARGS1*/
error(fmt, a1, a2, a3)
char *fmt;
int a1, a2, a3;
{
char buf[BUFSIZ];
buf[0] = 1;
(void) sprintf(buf+1, fmt, a1, a2, a3);
(void) write(2, buf, strlen(buf));
}
getstr(buf, cnt, err)
char *buf;
int cnt;
char *err;
{
char c;
do {
if (read(0, &c, 1) != 1)
exit(1);
*buf++ = c;
if (--cnt == 0) {
error("%s too long\n", err);
exit(1);
}
} while (c != 0);
}

11
libexec/rlogind/Makefile Normal file
View file

@ -0,0 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
PROG= rlogind
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
.include <bsd.prog.mk>

View file

@ -0,0 +1,38 @@
/*
* 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
*/
#include <paths.h>
#define _PATH_LOGIN "/usr/bin/login"

168
libexec/rlogind/rlogind.8 Normal file
View file

@ -0,0 +1,168 @@
.\" 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
.\" 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.
.\"
.\" @(#)rlogind.8 8.1 (Berkeley) 6/4/93
.\"
.Dd June 4, 1993
.Dt RLOGIND 8
.Os BSD 4.2
.Sh NAME
.Nm rlogind
.Nd remote login server
.Sh SYNOPSIS
.Nm rlogind
.Op Fl aln
.Sh DESCRIPTION
.Nm Rlogind
is the server for the
.Xr rlogin 1
program. The server provides a remote login facility
with authentication based on privileged port numbers from trusted hosts.
.Pp
Options supported by
.Nm rlogind :
.Bl -tag -width Ds
.It Fl a
Ask hostname for verification.
.It Fl l
Prevent any authentication based on the user's
.Dq Pa .rhosts
file, unless the user is logging in as the superuser.
.It Fl n
Disable keep-alive messages.
.El
.Pp
.Nm Rlogind
listens for service requests at the port indicated in
the ``login'' service specification; see
.Xr services 5 .
When a service request is received the following protocol
is initiated:
.Bl -enum
.It
The server checks the client's source port.
If the port is not in the range 512-1023, the server
aborts the connection.
.It
The server checks the client's source address
and requests the corresponding host name (see
.Xr gethostbyaddr 3 ,
.Xr hosts 5
and
.Xr named 8 ) .
If the hostname cannot be determined,
the dot-notation representation of the host address is used.
If the hostname is in the same domain as the server (according to
the last two components of the domain name),
or if the
.Fl a
option is given,
the addresses for the hostname are requested,
verifying that the name and address correspond.
Normal authentication is bypassed if the address verification fails.
.El
.Pp
Once the source port and address have been checked,
.Nm rlogind
proceeds with the authentication process described in
.Xr rshd 8 .
It then allocates a pseudo terminal (see
.Xr pty 4 ) ,
and manipulates file descriptors so that the slave
half of the pseudo terminal becomes the
.Em stdin ,
.Em stdout ,
and
.Em stderr
for a login process.
The login process is an instance of the
.Xr login 1
program, invoked with the
.Fl f
option if authentication has succeeded.
If automatic authentication fails, the user is
prompted to log in as if on a standard terminal line.
.Pp
The parent of the login process manipulates the master side of
the pseudo terminal, operating as an intermediary
between the login process and the client instance of the
.Xr rlogin
program. In normal operation, the packet protocol described
in
.Xr pty 4
is invoked to provide
.Ql ^S/^Q
type facilities and propagate
interrupt signals to the remote programs. The login process
propagates the client terminal's baud rate and terminal type,
as found in the environment variable,
.Ql Ev TERM ;
see
.Xr environ 7 .
The screen or window size of the terminal is requested from the client,
and window size changes from the client are propagated to the pseudo terminal.
.Pp
Transport-level keepalive messages are enabled unless the
.Fl n
option is present.
The use of keepalive messages allows sessions to be timed out
if the client crashes or becomes unreachable.
.Sh DIAGNOSTICS
All initial diagnostic messages are indicated
by a leading byte with a value of 1,
after which any network connections are closed.
If there are no errors before
.Xr login
is invoked, a null byte is returned as in indication of success.
.Bl -tag -width Ds
.It Sy Try again.
A
.Xr fork
by the server failed.
.El
.Sh SEE ALSO
.Xr login 1 ,
.Xr ruserok 3 ,
.Xr rshd 8
.Sh BUGS
The authentication procedure used here assumes the integrity
of each client machine and the connecting medium. This is
insecure, but is useful in an ``open'' environment.
.Pp
A facility to allow all data exchanges to be encrypted should be
present.
.Pp
A more extensible protocol should be used.
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .

759
libexec/rlogind/rlogind.c Normal file
View file

@ -0,0 +1,759 @@
/*-
* Copyright (c) 1983, 1988, 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
/*
* remote login server:
* \0
* remuser\0
* locuser\0
* terminal_type/speed\0
* data
*/
#define FD_SETSIZE 16 /* don't need many bits for select */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <termios.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pwd.h>
#include <syslog.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "pathnames.h"
#ifndef TIOCPKT_WINDOW
#define TIOCPKT_WINDOW 0x80
#endif
#ifdef KERBEROS
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
#define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
AUTH_DAT *kdata;
KTEXT ticket;
u_char auth_buf[sizeof(AUTH_DAT)];
u_char tick_buf[sizeof(KTEXT_ST)];
Key_schedule schedule;
int doencrypt, retval, use_kerberos, vacuous;
#define ARGSTR "alnkvx"
#else
#define ARGSTR "aln"
#endif /* KERBEROS */
char *env[2];
#define NMAX 30
char lusername[NMAX+1], rusername[NMAX+1];
static char term[64] = "TERM=";
#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
int keepalive = 1;
int check_all = 0;
struct passwd *pwd;
void doit __P((int, struct sockaddr_in *));
int control __P((int, char *, int));
void protocol __P((int, int));
void cleanup __P((int));
void fatal __P((int, char *, int));
int do_rlogin __P((struct sockaddr_in *));
void getstr __P((char *, int, char *));
void setup_term __P((int));
int do_krb_login __P((struct sockaddr_in *));
void usage __P((void));
int local_domain __P((char *));
char *topdomain __P((char *));
int
main(argc, argv)
int argc;
char *argv[];
{
extern int __check_rhosts_file;
struct sockaddr_in from;
int ch, fromlen, on;
openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
opterr = 0;
while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
switch (ch) {
case 'a':
check_all = 1;
break;
case 'l':
__check_rhosts_file = 0;
break;
case 'n':
keepalive = 0;
break;
#ifdef KERBEROS
case 'k':
use_kerberos = 1;
break;
case 'v':
vacuous = 1;
break;
#ifdef CRYPT
case 'x':
doencrypt = 1;
break;
#endif
#endif
case '?':
default:
usage();
break;
}
argc -= optind;
argv += optind;
#ifdef KERBEROS
if (use_kerberos && vacuous) {
usage();
fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
}
#endif
fromlen = sizeof (from);
if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
syslog(LOG_ERR,"Can't get peer name of remote host: %m");
fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
}
on = 1;
if (keepalive &&
setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %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);
}
int child;
int netf;
char line[MAXPATHLEN];
int confirmed;
struct winsize win = { 0, 0, 0, 0 };
void
doit(f, fromp)
int f;
struct sockaddr_in *fromp;
{
int master, pid, on = 1;
int authenticated = 0;
register struct hostent *hp;
char hostname[2 * MAXHOSTNAMELEN + 1];
char c;
alarm(60);
read(f, &c, 1);
if (c != 0)
exit(1);
#ifdef KERBEROS
if (vacuous)
fatal(f, "Remote host requires Kerberos authentication", 0);
#endif
alarm(0);
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));
#ifdef KERBEROS
if (use_kerberos) {
retval = do_krb_login(fromp);
if (retval == 0)
authenticated++;
else if (retval > 0)
fatal(f, krb_err_txt[retval], 0);
write(f, &c, 1);
confirmed = 1; /* we sent the null! */
} else
#endif
{
if (fromp->sin_family != AF_INET ||
fromp->sin_port >= IPPORT_RESERVED ||
fromp->sin_port < IPPORT_RESERVED/2) {
syslog(LOG_NOTICE, "Connection from %s on illegal port",
inet_ntoa(fromp->sin_addr));
fatal(f, "Permission denied", 0);
}
#ifdef IP_OPTIONS
{
u_char optbuf[BUFSIZ/3], *cp;
char lbuf[BUFSIZ], *lp;
int optsize = sizeof(optbuf), ipproto;
struct protoent *ip;
if ((ip = getprotobyname("ip")) != NULL)
ipproto = ip->p_proto;
else
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);
}
}
}
#endif
if (do_rlogin(fromp) == 0)
authenticated++;
}
if (confirmed == 0) {
write(f, "", 1);
confirmed = 1; /* we sent the null! */
}
#ifdef KERBEROS
#ifdef CRYPT
if (doencrypt)
(void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE) - 1);
#endif
#endif
netf = f;
pid = forkpty(&master, line, NULL, &win);
if (pid < 0) {
if (errno == ENOENT)
fatal(f, "Out of ptys", 0);
else
fatal(f, "Forkpty", 1);
}
if (pid == 0) {
if (f > 2) /* f should always be 0, but... */
(void) close(f);
setup_term(0);
if (authenticated) {
#ifdef KERBEROS
if (use_kerberos && (pwd->pw_uid == 0))
syslog(LOG_INFO|LOG_AUTH,
"ROOT Kerberos login from %s.%s@%s on %s\n",
kdata->pname, kdata->pinst, kdata->prealm,
hostname);
#endif
execl(_PATH_LOGIN, "login", "-p",
"-h", hostname, "-f", lusername, (char *)NULL);
} else
execl(_PATH_LOGIN, "login", "-p",
"-h", hostname, lusername, (char *)NULL);
fatal(STDERR_FILENO, _PATH_LOGIN, 1);
/*NOTREACHED*/
}
#ifdef CRYPT
#ifdef KERBEROS
/*
* If encrypted, don't turn on NBIO or the des read/write
* routines will croak.
*/
if (!doencrypt)
#endif
#endif
ioctl(f, FIONBIO, &on);
ioctl(master, FIONBIO, &on);
ioctl(master, TIOCPKT, &on);
signal(SIGCHLD, cleanup);
protocol(f, master);
signal(SIGCHLD, SIG_IGN);
cleanup(0);
}
char magic[2] = { 0377, 0377 };
char oobdata[] = {TIOCPKT_WINDOW};
/*
* Handle a "control" request (signaled by magic being present)
* in the data stream. For now, we are only willing to handle
* window size changes.
*/
int
control(pty, cp, n)
int pty;
char *cp;
int n;
{
struct winsize w;
if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
return (0);
oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
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);
w.ws_ypixel = ntohs(w.ws_ypixel);
(void)ioctl(pty, TIOCSWINSZ, &w);
return (4+sizeof (w));
}
/*
* rlogin "protocol" machine.
*/
void
protocol(f, p)
register int f, p;
{
char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
register pcc = 0, fcc = 0;
int cc, nfd, n;
char cntl;
/*
* Must ignore SIGTTOU, otherwise we'll stop
* when we try and set slave pty's window shape
* (our controlling tty is the master pty).
*/
(void) signal(SIGTTOU, SIG_IGN);
send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
if (f > p)
nfd = f + 1;
else
nfd = p + 1;
if (nfd > FD_SETSIZE) {
syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
fatal(f, "internal error (select mask too small)", 0);
}
for (;;) {
fd_set ibits, obits, ebits, *omask;
FD_ZERO(&ebits);
FD_ZERO(&ibits);
FD_ZERO(&obits);
omask = (fd_set *)NULL;
if (fcc) {
FD_SET(p, &obits);
omask = &obits;
} else
FD_SET(f, &ibits);
if (pcc >= 0)
if (pcc) {
FD_SET(f, &obits);
omask = &obits;
} else
FD_SET(p, &ibits);
FD_SET(p, &ebits);
if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
if (errno == EINTR)
continue;
fatal(f, "select", 1);
}
if (n == 0) {
/* shouldn't happen... */
sleep(5);
continue;
}
#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
if (FD_ISSET(p, &ebits)) {
cc = read(p, &cntl, 1);
if (cc == 1 && pkcontrol(cntl)) {
cntl |= oobdata[0];
send(f, &cntl, 1, MSG_OOB);
if (cntl & TIOCPKT_FLUSHWRITE) {
pcc = 0;
FD_CLR(p, &ibits);
}
}
}
if (FD_ISSET(f, &ibits)) {
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt)
fcc = des_read(f, fibuf, sizeof(fibuf));
else
#endif
#endif
fcc = read(f, fibuf, sizeof(fibuf));
if (fcc < 0 && errno == EWOULDBLOCK)
fcc = 0;
else {
register char *cp;
int left, n;
if (fcc <= 0)
break;
fbp = fibuf;
top:
for (cp = fibuf; cp < fibuf+fcc-1; cp++)
if (cp[0] == magic[0] &&
cp[1] == magic[1]) {
left = fcc - (cp-fibuf);
n = control(p, cp, left);
if (n) {
left -= n;
if (left > 0)
bcopy(cp+n, cp, left);
fcc -= n;
goto top; /* n^2 */
}
}
FD_SET(p, &obits); /* try write */
}
}
if (FD_ISSET(p, &obits) && fcc > 0) {
cc = write(p, fbp, fcc);
if (cc > 0) {
fcc -= cc;
fbp += cc;
}
}
if (FD_ISSET(p, &ibits)) {
pcc = read(p, pibuf, sizeof (pibuf));
pbp = pibuf;
if (pcc < 0 && errno == EWOULDBLOCK)
pcc = 0;
else if (pcc <= 0)
break;
else if (pibuf[0] == 0) {
pbp++, pcc--;
#ifdef CRYPT
#ifdef KERBEROS
if (!doencrypt)
#endif
#endif
FD_SET(f, &obits); /* try write */
} else {
if (pkcontrol(pibuf[0])) {
pibuf[0] |= oobdata[0];
send(f, &pibuf[0], 1, MSG_OOB);
}
pcc = 0;
}
}
if ((FD_ISSET(f, &obits)) && pcc > 0) {
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt)
cc = des_write(f, pbp, pcc);
else
#endif
#endif
cc = write(f, pbp, pcc);
if (cc < 0 && errno == EWOULDBLOCK) {
/*
* This happens when we try write after read
* from p, but some old kernels balk at large
* writes even when select returns true.
*/
if (!FD_ISSET(p, &ibits))
sleep(5);
continue;
}
if (cc > 0) {
pcc -= cc;
pbp += cc;
}
}
}
}
void
cleanup(signo)
int signo;
{
char *p;
p = line + sizeof(_PATH_DEV) - 1;
if (logout(p))
logwtmp(p, "", "");
(void)chmod(line, 0666);
(void)chown(line, 0, 0);
*p = 'p';
(void)chmod(line, 0666);
(void)chown(line, 0, 0);
shutdown(netf, 2);
exit(1);
}
void
fatal(f, msg, syserr)
int f;
char *msg;
int syserr;
{
int len;
char buf[BUFSIZ], *bp = buf;
/*
* Prepend binary one to message if we haven't sent
* the magic null as confirmation.
*/
if (!confirmed)
*bp++ = '\01'; /* error indicator */
if (syserr)
len = sprintf(bp, "rlogind: %s: %s.\r\n",
msg, strerror(errno));
else
len = sprintf(bp, "rlogind: %s.\r\n", msg);
(void) write(f, buf, bp + len - buf);
exit(1);
}
int
do_rlogin(dest)
struct sockaddr_in *dest;
{
getstr(rusername, sizeof(rusername), "remuser too long");
getstr(lusername, sizeof(lusername), "locuser too long");
getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
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));
}
void
getstr(buf, cnt, errmsg)
char *buf;
int cnt;
char *errmsg;
{
char c;
do {
if (read(0, &c, 1) != 1)
exit(1);
if (--cnt < 0)
fatal(STDOUT_FILENO, errmsg, 0);
*buf++ = c;
} while (c != 0);
}
extern char **environ;
void
setup_term(fd)
int fd;
{
register char *cp = index(term+ENVSIZE, '/');
char *speed;
struct termios tt;
#ifndef notyet
tcgetattr(fd, &tt);
if (cp) {
*cp++ = '\0';
speed = cp;
cp = index(speed, '/');
if (cp)
*cp++ = '\0';
cfsetspeed(&tt, atoi(speed));
}
tt.c_iflag = TTYDEF_IFLAG;
tt.c_oflag = TTYDEF_OFLAG;
tt.c_lflag = TTYDEF_LFLAG;
tcsetattr(fd, TCSAFLUSH, &tt);
#else
if (cp) {
*cp++ = '\0';
speed = cp;
cp = index(speed, '/');
if (cp)
*cp++ = '\0';
tcgetattr(fd, &tt);
cfsetspeed(&tt, atoi(speed));
tcsetattr(fd, TCSAFLUSH, &tt);
}
#endif
env[0] = term;
env[1] = 0;
environ = env;
}
#ifdef KERBEROS
#define VERSION_SIZE 9
/*
* Do the remote kerberos login to the named host with the
* given inet address
*
* Return 0 on valid authorization
* Return -1 on valid authentication, no authorization
* Return >0 for error conditions
*/
int
do_krb_login(dest)
struct sockaddr_in *dest;
{
int rc;
char instance[INST_SZ], version[VERSION_SIZE];
long authopts = 0L; /* !mutual */
struct sockaddr_in faddr;
kdata = (AUTH_DAT *) auth_buf;
ticket = (KTEXT) tick_buf;
instance[0] = '*';
instance[1] = '\0';
#ifdef CRYPT
if (doencrypt) {
rc = sizeof(faddr);
if (getsockname(0, (struct sockaddr *)&faddr, &rc))
return (-1);
authopts = KOPT_DO_MUTUAL;
rc = krb_recvauth(
authopts, 0,
ticket, "rcmd",
instance, dest, &faddr,
kdata, "", schedule, version);
des_set_key(kdata->session, schedule);
} else
#endif
rc = krb_recvauth(
authopts, 0,
ticket, "rcmd",
instance, dest, (struct sockaddr_in *) 0,
kdata, "", (bit_64 *) 0, version);
if (rc != KSUCCESS)
return (rc);
getstr(lusername, sizeof(lusername), "locuser");
/* get the "cmd" in the rcmd protocol */
getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
pwd = getpwnam(lusername);
if (pwd == NULL)
return (-1);
/* returns nonzero for no access */
if (kuserok(kdata, lusername) != 0)
return (-1);
return (0);
}
#endif /* KERBEROS */
void
usage()
{
#ifdef KERBEROS
syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]");
#else
syslog(LOG_ERR, "usage: rlogind [-aln]");
#endif
}
/*
* Check whether host h is in our local domain,
* defined as sharing the last two components of the domain part,
* or the entire domain part if the local domain has only one component.
* If either name is unqualified (contains no '.'),
* assume that the host is local, as it will be
* interpreted as such.
*/
int
local_domain(h)
char *h;
{
char localhost[MAXHOSTNAMELEN];
char *p1, *p2;
localhost[0] = 0;
(void) gethostname(localhost, sizeof(localhost));
p1 = topdomain(localhost);
p2 = topdomain(h);
if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
return (1);
return (0);
}
char *
topdomain(h)
char *h;
{
register char *p;
char *maybe = NULL;
int dots = 0;
for (p = h + strlen(h); p >= h; p--) {
if (*p == '.') {
if (++dots == 2)
return (p);
maybe = p;
}
}
return (maybe);
}

11
libexec/rshd/Makefile Normal file
View file

@ -0,0 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
PROG= rshd
CFLAGS+=-DKERBEROS -DCRYPT
SRCS= rshd.c des_rw.c
MAN8= rshd.0
DPADD= ${LIBKRB} ${LIBDES}
LDADD= -lkrb -ldes
.PATH: ${.CURDIR}/../../usr.bin/rlogin
.include <bsd.prog.mk>

209
libexec/rshd/rshd.8 Normal file
View file

@ -0,0 +1,209 @@
.\" 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
.\" 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.
.\"
.\" @(#)rshd.8 8.1 (Berkeley) 6/4/93
.\"
.Dd June 4, 1993
.Dt RSHD 8
.Os BSD 4.2
.Sh NAME
.Nm rshd
.Nd remote shell server
.Sh SYNOPSIS
.Nm rshd
.Op Fl alnL
.Sh DESCRIPTION
The
.Nm rshd
server
is the server for the
.Xr rcmd 3
routine and, consequently, for the
.Xr rsh 1
program. The server provides remote execution facilities
with authentication based on privileged port numbers from trusted hosts.
.Pp
The
.Nm rshd
server
listens for service requests at the port indicated in
the ``cmd'' service specification; see
.Xr services 5 .
When a service request is received the following protocol
is initiated:
.Bl -enum
.It
The server checks the client's source port.
If the port is not in the range 512-1023, the server
aborts the connection.
.It
The server reads characters from the socket up
to a null (`\e0') byte. The resultant string is
interpreted as an
.Tn ASCII
number, base 10.
.It
If the number received in step 2 is non-zero,
it is interpreted as the port number of a secondary
stream to be used for the
.Em stderr .
A second connection is then created to the specified
port on the client's machine. The source port of this
second connection is also in the range 512-1023.
.It
The server checks the client's source address
and requests the corresponding host name (see
.Xr gethostbyaddr 3 ,
.Xr hosts 5
and
.Xr named 8 ) .
If the hostname cannot be determined,
the dot-notation representation of the host address is used.
If the hostname is in the same domain as the server (according to
the last two components of the domain name),
or if the
.Fl a
option is given,
the addresses for the hostname are requested,
verifying that the name and address correspond.
If address verification fails, the connection is aborted
with the message, ``Host address mismatch.''
.It
A null terminated user name of at most 16 characters
is retrieved on the initial socket. This user name
is interpreted as the user identity on the
.Em client Ns 's
machine.
.It
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
machine.
.It
A null terminated command to be passed to a
shell is retrieved on the initial socket. The length of
the command is limited by the upper bound on the size of
the system's argument list.
.It
.Nm Rshd
then validates the user using
.Xr ruserok 3 ,
which uses the file
.Pa /etc/hosts.equiv
and the
.Pa .rhosts
file found in the user's home directory. The
.Fl l
option prevents
.Xr ruserok 3
from doing any validation based on the user's ``.rhosts'' file,
unless the user is the superuser.
.It
If the file
.Pa /etc/nologin
exists and the user is not the superuser,
the connection is closed.
.It
A null byte is returned on the initial socket
and the command line is passed to the normal login
shell of the user. The
shell inherits the network connections established
by
.Nm rshd .
.El
.Pp
Transport-level keepalive messages are enabled unless the
.Fl n
option is present.
The use of keepalive messages allows sessions to be timed out
if the client crashes or becomes unreachable.
.Pp
The
.Fl L
option causes all successful accesses to be logged to
.Xr syslogd 8
as
.Li auth.info
messages.
.Sh DIAGNOSTICS
Except for the last one listed below,
all diagnostic messages
are returned on the initial socket,
after which any network connections are closed.
An error is indicated by a leading byte with a value of
1 (0 is returned in step 10 above upon successful completion
of all the steps prior to the execution of the login shell).
.Bl -tag -width indent
.It Sy Locuser too long.
The name of the user on the client's machine is
longer than 16 characters.
.It Sy Ruser too long.
The name of the user on the remote machine is
longer than 16 characters.
.It Sy Command too long .
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.
.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 Can't make pipe.
The pipe needed for the
.Em stderr ,
wasn't created.
.It Sy Can't fork; try again.
A
.Xr fork
by the server failed.
.It Sy <shellname>: ...
The user's login shell could not be started. This message is returned
on the connection associated with the
.Em stderr ,
and is not preceded by a flag byte.
.El
.Sh SEE ALSO
.Xr rsh 1 ,
.Xr rcmd 3 ,
.Xr ruserok 3
.Sh BUGS
The authentication procedure used here assumes the integrity
of each client machine and the connecting medium. This is
insecure, but is useful in an ``open'' environment.
.Pp
A facility to allow all data exchanges to be encrypted should be
present.
.Pp
A more extensible protocol (such as Telnet) should be used.

783
libexec/rshd/rshd.c Normal file
View file

@ -0,0 +1,783 @@
/*-
* Copyright (c) 1988, 1989, 1992, 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94";
#endif /* not lint */
/*
* remote shell server:
* [port]\0
* remuser\0
* locuser\0
* command\0
* data
*/
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
int keepalive = 1;
int check_all;
int log_success; /* If TRUE, log all successful accesses */
int sent_null;
void doit __P((struct sockaddr_in *));
void error __P((const char *, ...));
void getstr __P((char *, int, char *));
int local_domain __P((char *));
char *topdomain __P((char *));
void usage __P((void));
#ifdef KERBEROS
#include <kerberosIV/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"
#define OPTIONS "alnkvxL"
char authbuf[sizeof(AUTH_DAT)];
char tickbuf[sizeof(KTEXT_ST)];
int doencrypt, use_kerberos, vacuous;
Key_schedule schedule;
#else
#define OPTIONS "alnL"
#endif
int
main(argc, argv)
int argc;
char *argv[];
{
extern int __check_rhosts_file;
struct linger linger;
int ch, on = 1, fromlen;
struct sockaddr_in from;
openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
opterr = 0;
while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
switch (ch) {
case 'a':
check_all = 1;
break;
case 'l':
__check_rhosts_file = 0;
break;
case 'n':
keepalive = 0;
break;
#ifdef KERBEROS
case 'k':
use_kerberos = 1;
break;
case 'v':
vacuous = 1;
break;
#ifdef CRYPT
case 'x':
doencrypt = 1;
break;
#endif
#endif
case 'L':
log_success = 1;
break;
case '?':
default:
usage();
break;
}
argc -= optind;
argv += optind;
#ifdef KERBEROS
if (use_kerberos && vacuous) {
syslog(LOG_ERR, "only one of -k and -v allowed");
exit(2);
}
#ifdef CRYPT
if (doencrypt && !use_kerberos) {
syslog(LOG_ERR, "-k is required for -x");
exit(2);
}
#endif
#endif
fromlen = sizeof (from);
if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
syslog(LOG_ERR, "getpeername: %m");
_exit(1);
}
if (keepalive &&
setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
sizeof(on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
linger.l_onoff = 1;
linger.l_linger = 60; /* XXX */
if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
sizeof (linger)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
doit(&from);
/* NOTREACHED */
}
char username[20] = "USER=";
char homedir[64] = "HOME=";
char shell[64] = "SHELL=";
char path[100] = "PATH=";
char *envinit[] =
{homedir, shell, path, username, 0};
char **environ;
void
doit(fromp)
struct sockaddr_in *fromp;
{
extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */
struct hostent *hp;
struct passwd *pwd;
u_short port;
fd_set ready, readfrom;
int cc, nfd, pv[2], pid, s;
int one = 1;
char *hostname, *errorstr, *errorhost;
char *cp, sig, buf[BUFSIZ];
char cmdbuf[NCARGS+1], locuser[16], remuser[16];
char remotehost[2 * MAXHOSTNAMELEN + 1];
#ifdef KERBEROS
AUTH_DAT *kdata = (AUTH_DAT *) NULL;
KTEXT ticket = (KTEXT) NULL;
char instance[INST_SZ], version[VERSION_SIZE];
struct sockaddr_in fromaddr;
int rc;
long authopts;
int pv1[2], pv2[2];
fd_set wready, writeto;
fromaddr = *fromp;
#endif
(void) signal(SIGINT, SIG_DFL);
(void) signal(SIGQUIT, SIG_DFL);
(void) signal(SIGTERM, SIG_DFL);
#ifdef DEBUG
{ int t = open(_PATH_TTY, 2);
if (t >= 0) {
ioctl(t, TIOCNOTTY, (char *)0);
(void) close(t);
}
}
#endif
fromp->sin_port = ntohs((u_short)fromp->sin_port);
if (fromp->sin_family != AF_INET) {
syslog(LOG_ERR, "malformed \"from\" address (af %d)\n",
fromp->sin_family);
exit(1);
}
#ifdef IP_OPTIONS
{
u_char optbuf[BUFSIZ/3], *cp;
char lbuf[BUFSIZ], *lp;
int optsize = sizeof(optbuf), ipproto;
struct protoent *ip;
if ((ip = getprotobyname("ip")) != NULL)
ipproto = ip->p_proto;
else
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);
}
}
}
#endif
#ifdef KERBEROS
if (!use_kerberos)
#endif
if (fromp->sin_port >= IPPORT_RESERVED ||
fromp->sin_port < IPPORT_RESERVED/2) {
syslog(LOG_NOTICE|LOG_AUTH,
"Connection from %s on illegal port %u",
inet_ntoa(fromp->sin_addr),
fromp->sin_port);
exit(1);
}
(void) alarm(60);
port = 0;
for (;;) {
char c;
if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
if (cc < 0)
syslog(LOG_NOTICE, "read: %m");
shutdown(0, 1+1);
exit(1);
}
if (c== 0)
break;
port = port * 10 + c - '0';
}
(void) alarm(0);
if (port != 0) {
int lport = IPPORT_RESERVED - 1;
s = rresvport(&lport);
if (s < 0) {
syslog(LOG_ERR, "can't get stderr port: %m");
exit(1);
}
#ifdef KERBEROS
if (!use_kerberos)
#endif
if (port >= IPPORT_RESERVED) {
syslog(LOG_ERR, "2nd port not reserved\n");
exit(1);
}
fromp->sin_port = htons(port);
if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
syslog(LOG_INFO, "connect second port %d: %m", port);
exit(1);
}
}
#ifdef KERBEROS
if (vacuous) {
error("rshd: remote host requires Kerberos authentication\n");
exit(1);
}
#endif
#ifdef notdef
/* from inetd, socket is already on 0, 1, 2 */
dup2(f, 0);
dup2(f, 1);
dup2(f, 2);
#endif
errorstr = NULL;
hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
fromp->sin_family);
if (hp) {
/*
* If name returned by gethostbyaddr is in our domain,
* attempt to verify that we haven't been fooled by someone
* in a remote net; look up the name and check that this
* address corresponds to the name.
*/
hostname = hp->h_name;
#ifdef KERBEROS
if (!use_kerberos)
#endif
if (check_all || local_domain(hp->h_name)) {
strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
remotehost[sizeof(remotehost) - 1] = 0;
errorhost = remotehost;
hp = gethostbyname(remotehost);
if (hp == NULL) {
syslog(LOG_INFO,
"Couldn't look up address for %s",
remotehost);
errorstr =
"Couldn't look up address for your host (%s)\n";
hostname = inet_ntoa(fromp->sin_addr);
} else for (; ; hp->h_addr_list++) {
if (hp->h_addr_list[0] == NULL) {
syslog(LOG_NOTICE,
"Host addr %s not listed for host %s",
inet_ntoa(fromp->sin_addr),
hp->h_name);
errorstr =
"Host address mismatch for %s\n";
hostname = inet_ntoa(fromp->sin_addr);
break;
}
if (!bcmp(hp->h_addr_list[0],
(caddr_t)&fromp->sin_addr,
sizeof(fromp->sin_addr))) {
hostname = hp->h_name;
break;
}
}
}
} else
errorhost = hostname = inet_ntoa(fromp->sin_addr);
#ifdef KERBEROS
if (use_kerberos) {
kdata = (AUTH_DAT *) authbuf;
ticket = (KTEXT) tickbuf;
authopts = 0L;
strcpy(instance, "*");
version[VERSION_SIZE - 1] = '\0';
#ifdef CRYPT
if (doencrypt) {
struct sockaddr_in local_addr;
rc = sizeof(local_addr);
if (getsockname(0, (struct sockaddr *)&local_addr,
&rc) < 0) {
syslog(LOG_ERR, "getsockname: %m");
error("rlogind: getsockname: %m");
exit(1);
}
authopts = KOPT_DO_MUTUAL;
rc = krb_recvauth(authopts, 0, ticket,
"rcmd", instance, &fromaddr,
&local_addr, kdata, "", schedule,
version);
des_set_key(kdata->session, schedule);
} else
#endif
rc = krb_recvauth(authopts, 0, ticket, "rcmd",
instance, &fromaddr,
(struct sockaddr_in *) 0,
kdata, "", (bit_64 *) 0, version);
if (rc != KSUCCESS) {
error("Kerberos authentication failure: %s\n",
krb_err_txt[rc]);
exit(1);
}
} else
#endif
getstr(remuser, sizeof(remuser), "remuser");
getstr(locuser, sizeof(locuser), "locuser");
getstr(cmdbuf, sizeof(cmdbuf), "command");
setpwent();
pwd = getpwnam(locuser);
if (pwd == NULL) {
syslog(LOG_INFO|LOG_AUTH,
"%s@%s as %s: unknown login. cmd='%.80s'",
remuser, hostname, locuser, cmdbuf);
if (errorstr == NULL)
errorstr = "Login incorrect.\n";
goto fail;
}
if (chdir(pwd->pw_dir) < 0) {
(void) chdir("/");
#ifdef notdef
syslog(LOG_INFO|LOG_AUTH,
"%s@%s as %s: no home directory. cmd='%.80s'",
remuser, hostname, locuser, cmdbuf);
error("No remote directory.\n");
exit(1);
#endif
}
#ifdef KERBEROS
if (use_kerberos) {
if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') {
if (kuserok(kdata, locuser) != 0) {
syslog(LOG_INFO|LOG_AUTH,
"Kerberos rsh denied to %s.%s@%s",
kdata->pname, kdata->pinst, kdata->prealm);
error("Permission denied.\n");
exit(1);
}
}
} else
#endif
if (errorstr ||
pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0,
remuser, locuser) < 0) {
if (__rcmd_errstr)
syslog(LOG_INFO|LOG_AUTH,
"%s@%s as %s: permission denied (%s). cmd='%.80s'",
remuser, hostname, locuser, __rcmd_errstr,
cmdbuf);
else
syslog(LOG_INFO|LOG_AUTH,
"%s@%s as %s: permission denied. cmd='%.80s'",
remuser, hostname, locuser, cmdbuf);
fail:
if (errorstr == NULL)
errorstr = "Permission denied.\n";
error(errorstr, errorhost);
exit(1);
}
if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) {
error("Logins currently disabled.\n");
exit(1);
}
(void) write(STDERR_FILENO, "\0", 1);
sent_null = 1;
if (port) {
if (pipe(pv) < 0) {
error("Can't make pipe.\n");
exit(1);
}
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt) {
if (pipe(pv1) < 0) {
error("Can't make 2nd pipe.\n");
exit(1);
}
if (pipe(pv2) < 0) {
error("Can't make 3rd pipe.\n");
exit(1);
}
}
#endif
#endif
pid = fork();
if (pid == -1) {
error("Can't fork; try again.\n");
exit(1);
}
if (pid) {
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt) {
static char msg[] = SECURE_MESSAGE;
(void) close(pv1[1]);
(void) close(pv2[1]);
des_write(s, msg, sizeof(msg) - 1);
} else
#endif
#endif
{
(void) close(0);
(void) close(1);
}
(void) close(2);
(void) close(pv[1]);
FD_ZERO(&readfrom);
FD_SET(s, &readfrom);
FD_SET(pv[0], &readfrom);
if (pv[0] > s)
nfd = pv[0];
else
nfd = s;
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt) {
FD_ZERO(&writeto);
FD_SET(pv2[0], &writeto);
FD_SET(pv1[0], &readfrom);
nfd = MAX(nfd, pv2[0]);
nfd = MAX(nfd, pv1[0]);
} else
#endif
#endif
ioctl(pv[0], FIONBIO, (char *)&one);
/* should set s nbio! */
nfd++;
do {
ready = readfrom;
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt) {
wready = writeto;
if (select(nfd, &ready,
&wready, (fd_set *) 0,
(struct timeval *) 0) < 0)
break;
} else
#endif
#endif
if (select(nfd, &ready, (fd_set *)0,
(fd_set *)0, (struct timeval *)0) < 0)
break;
if (FD_ISSET(s, &ready)) {
int ret;
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt)
ret = des_read(s, &sig, 1);
else
#endif
#endif
ret = read(s, &sig, 1);
if (ret <= 0)
FD_CLR(s, &readfrom);
else
killpg(pid, sig);
}
if (FD_ISSET(pv[0], &ready)) {
errno = 0;
cc = read(pv[0], buf, sizeof(buf));
if (cc <= 0) {
shutdown(s, 1+1);
FD_CLR(pv[0], &readfrom);
} else {
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt)
(void)
des_write(s, buf, cc);
else
#endif
#endif
(void)
write(s, buf, cc);
}
}
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt && FD_ISSET(pv1[0], &ready)) {
errno = 0;
cc = read(pv1[0], buf, sizeof(buf));
if (cc <= 0) {
shutdown(pv1[0], 1+1);
FD_CLR(pv1[0], &readfrom);
} else
(void) des_write(STDOUT_FILENO,
buf, cc);
}
if (doencrypt && FD_ISSET(pv2[0], &wready)) {
errno = 0;
cc = des_read(STDIN_FILENO,
buf, sizeof(buf));
if (cc <= 0) {
shutdown(pv2[0], 1+1);
FD_CLR(pv2[0], &writeto);
} else
(void) write(pv2[0], buf, cc);
}
#endif
#endif
} while (FD_ISSET(s, &readfrom) ||
#ifdef CRYPT
#ifdef KERBEROS
(doencrypt && FD_ISSET(pv1[0], &readfrom)) ||
#endif
#endif
FD_ISSET(pv[0], &readfrom));
exit(0);
}
setpgrp(0, getpid());
(void) close(s);
(void) close(pv[0]);
#ifdef CRYPT
#ifdef KERBEROS
if (doencrypt) {
close(pv1[0]); close(pv2[0]);
dup2(pv1[1], 1);
dup2(pv2[1], 0);
close(pv1[1]);
close(pv2[1]);
}
#endif
#endif
dup2(pv[1], 2);
close(pv[1]);
}
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);
strncat(shell, pwd->pw_shell, sizeof(shell)-7);
strncat(username, pwd->pw_name, sizeof(username)-6);
cp = strrchr(pwd->pw_shell, '/');
if (cp)
cp++;
else
cp = pwd->pw_shell;
endpwent();
if (log_success || pwd->pw_uid == 0) {
#ifdef KERBEROS
if (use_kerberos)
syslog(LOG_INFO|LOG_AUTH,
"Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'",
kdata->pname, kdata->pinst, kdata->prealm,
hostname, locuser, cmdbuf);
else
#endif
syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
remuser, hostname, locuser, cmdbuf);
}
execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
perror(pwd->pw_shell);
exit(1);
}
/*
* Report error to client. Note: can't be used until second socket has
* connected to client, or older clients will hang waiting for that
* connection first.
*/
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
error(const char *fmt, ...)
#else
error(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
int len;
char *bp, buf[BUFSIZ];
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
bp = buf;
if (sent_null == 0) {
*bp++ = 1;
len = 1;
} else
len = 0;
(void)vsnprintf(bp, sizeof(buf) - 1, fmt, ap);
(void)write(STDERR_FILENO, buf, len + strlen(bp));
}
void
getstr(buf, cnt, err)
char *buf, *err;
int cnt;
{
char c;
do {
if (read(STDIN_FILENO, &c, 1) != 1)
exit(1);
*buf++ = c;
if (--cnt == 0) {
error("%s too long\n", err);
exit(1);
}
} while (c != 0);
}
/*
* Check whether host h is in our local domain,
* defined as sharing the last two components of the domain part,
* or the entire domain part if the local domain has only one component.
* If either name is unqualified (contains no '.'),
* assume that the host is local, as it will be
* interpreted as such.
*/
int
local_domain(h)
char *h;
{
char localhost[MAXHOSTNAMELEN];
char *p1, *p2;
localhost[0] = 0;
(void) gethostname(localhost, sizeof(localhost));
p1 = topdomain(localhost);
p2 = topdomain(h);
if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
return (1);
return (0);
}
char *
topdomain(h)
char *h;
{
char *p, *maybe = NULL;
int dots = 0;
for (p = h + strlen(h); p >= h; p--) {
if (*p == '.') {
if (++dots == 2)
return (p);
maybe = p;
}
}
return (maybe);
}
void
usage()
{
syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS);
exit(2);
}

8
libexec/talkd/Makefile Normal file
View file

@ -0,0 +1,8 @@
# @(#)Makefile 8.1 (Berkeley) 6/4/93
PROG= ntalkd
SRCS= talkd.c announce.c process.c table.c print.c ttymsg.c
.PATH: ${.CURDIR}/../../usr.bin/wall
MAN8= talkd.0
.include <bsd.prog.mk>

159
libexec/talkd/announce.c Normal file
View file

@ -0,0 +1,159 @@
/*
* 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[] = "@(#)announce.c 8.2 (Berkeley) 1/7/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/stat.h>
#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 <stdio.h>
#include <string.h>
#include <paths.h>
extern char hostname[];
/*
* Announce an invitation to talk.
*/
/*
* See if the user is accepting messages. If so, announce that
* a talk is requested.
*/
announce(request, remote_machine)
CTL_MSG *request;
char *remote_machine;
{
char full_tty[32];
FILE *tf;
struct stat stbuf;
(void)snprintf(full_tty, sizeof(full_tty),
"%s%s", _PATH_DEV, request->r_tty);
if (stat(full_tty, &stbuf) < 0 || (stbuf.st_mode&020) == 0)
return (PERMISSION_DENIED);
return (print_mesg(request->r_tty, tf, request, remote_machine));
}
#define max(a,b) ( (a) > (b) ? (a) : (b) )
#define N_LINES 5
#define N_CHARS 120
/*
* 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
*/
print_mesg(tty, tf, request, remote_machine)
char *tty;
FILE *tf;
CTL_MSG *request;
char *remote_machine;
{
struct timeval clock;
struct timezone zone;
struct tm *localtime();
struct tm *localclock;
struct iovec iovec;
char line_buf[N_LINES][N_CHARS];
int sizes[N_LINES];
char big_buf[N_LINES*N_CHARS];
char *bptr, *lptr, *ttymsg();
int i, j, max_size;
i = 0;
max_size = 0;
gettimeofday(&clock, &zone);
localclock = localtime( &clock.tv_sec );
(void)sprintf(line_buf[i], " ");
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 );
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
(void)sprintf(line_buf[i], "talk: connection requested by %s@%s",
request->l_name, 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",
request->l_name, remote_machine);
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
(void)sprintf(line_buf[i], " ");
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++ = '\r'; /* add a \r in case of raw mode */
*bptr++ = '\n';
for (i = 0; i < N_LINES; i++) {
/* copy the line into the big buffer */
lptr = line_buf[i];
while (*lptr != '\0')
*(bptr++) = *(lptr++);
/* pad out the rest of the lines with blanks */
for (j = sizes[i]; j < max_size + 2; j++)
*(bptr++) = ' ';
*(bptr++) = '\r'; /* add a \r in case of raw mode */
*(bptr++) = '\n';
}
*bptr = '\0';
iovec.iov_base = big_buf;
iovec.iov_len = bptr - big_buf;
/*
* we choose a timeout of RING_WAIT-5 seconds so that we don't
* stack up processes trying to write messages to a tty
* that is permanently blocked.
*/
if (ttymsg(&iovec, 1, tty, RING_WAIT - 5) != NULL)
return (FAILED);
return (SUCCESS);
}

86
libexec/talkd/print.c Normal file
View file

@ -0,0 +1,86 @@
/*
* 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[] = "@(#)print.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
/* debug print routines */
#include <sys/types.h>
#include <sys/socket.h>
#include <protocols/talkd.h>
#include <syslog.h>
#include <stdio.h>
static char *types[] =
{ "leave_invite", "look_up", "delete", "announce" };
#define NTYPES (sizeof (types) / sizeof (types[0]))
static char *answers[] =
{ "success", "not_here", "failed", "machine_unknown", "permission_denied",
"unknown_request", "badversion", "badaddr", "badctladdr" };
#define NANSWERS (sizeof (answers) / sizeof (answers[0]))
print_request(cp, mp)
char *cp;
register CTL_MSG *mp;
{
char tbuf[80], *tp;
if (mp->type > NTYPES) {
(void)sprintf(tbuf, "type %d", mp->type);
tp = tbuf;
} else
tp = types[mp->type];
syslog(LOG_DEBUG, "%s: %s: id %d, l_user %s, r_user %s, r_tty %s",
cp, tp, mp->id_num, mp->l_name, mp->r_name, mp->r_tty);
}
print_response(cp, rp)
char *cp;
register CTL_RESPONSE *rp;
{
char tbuf[80], *tp, abuf[80], *ap;
if (rp->type > NTYPES) {
(void)sprintf(tbuf, "type %d", rp->type);
tp = tbuf;
} else
tp = types[rp->type];
if (rp->answer > NANSWERS) {
(void)sprintf(abuf, "answer %d", rp->answer);
ap = abuf;
} else
ap = answers[rp->answer];
syslog(LOG_DEBUG, "%s: %s: %s, id %d", cp, tp, ap, ntohl(rp->id_num));
}

219
libexec/talkd/process.c Normal file
View file

@ -0,0 +1,219 @@
/*
* 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[] = "@(#)process.c 8.2 (Berkeley) 11/16/93";
#endif /* not lint */
/*
* process.c handles the requests, which can be of three types:
* ANNOUNCE - announce to a user that a talk is wanted
* LEAVE_INVITE - insert the request into the table
* LOOK_UP - look up to see if a request is waiting in
* in the table for the local user
* DELETE - delete invitation
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <protocols/talkd.h>
#include <netdb.h>
#include <syslog.h>
#include <stdio.h>
#include <string.h>
#include <paths.h>
CTL_MSG *find_request();
CTL_MSG *find_match();
process_request(mp, rp)
register CTL_MSG *mp;
register CTL_RESPONSE *rp;
{
register CTL_MSG *ptr;
extern int debug;
rp->vers = TALK_VERSION;
rp->type = mp->type;
rp->id_num = htonl(0);
if (mp->vers != TALK_VERSION) {
syslog(LOG_WARNING, "Bad protocol version %d", mp->vers);
rp->answer = BADVERSION;
return;
}
mp->id_num = ntohl(mp->id_num);
mp->addr.sa_family = ntohs(mp->addr.sa_family);
if (mp->addr.sa_family != AF_INET) {
syslog(LOG_WARNING, "Bad address, family %d",
mp->addr.sa_family);
rp->answer = BADADDR;
return;
}
mp->ctl_addr.sa_family = ntohs(mp->ctl_addr.sa_family);
if (mp->ctl_addr.sa_family != AF_INET) {
syslog(LOG_WARNING, "Bad control address, family %d",
mp->ctl_addr.sa_family);
rp->answer = BADCTLADDR;
return;
}
mp->pid = ntohl(mp->pid);
if (debug)
print_request("process_request", mp);
switch (mp->type) {
case ANNOUNCE:
do_announce(mp, rp);
break;
case LEAVE_INVITE:
ptr = find_request(mp);
if (ptr != (CTL_MSG *)0) {
rp->id_num = htonl(ptr->id_num);
rp->answer = SUCCESS;
} else
insert_table(mp, rp);
break;
case LOOK_UP:
ptr = find_match(mp);
if (ptr != (CTL_MSG *)0) {
rp->id_num = htonl(ptr->id_num);
rp->addr = ptr->addr;
rp->addr.sa_family = htons(ptr->addr.sa_family);
rp->answer = SUCCESS;
} else
rp->answer = NOT_HERE;
break;
case DELETE:
rp->answer = delete_invite(mp->id_num);
break;
default:
rp->answer = UNKNOWN_REQUEST;
break;
}
if (debug)
print_response("process_request", rp);
}
do_announce(mp, rp)
register CTL_MSG *mp;
CTL_RESPONSE *rp;
{
struct hostent *hp;
CTL_MSG *ptr;
int result;
/* see if the user is logged */
result = find_user(mp->r_name, mp->r_tty);
if (result != SUCCESS) {
rp->answer = result;
return;
}
#define satosin(sa) ((struct sockaddr_in *)(sa))
hp = gethostbyaddr((char *)&satosin(&mp->ctl_addr)->sin_addr,
sizeof (struct in_addr), AF_INET);
if (hp == (struct hostent *)0) {
rp->answer = MACHINE_UNKNOWN;
return;
}
ptr = find_request(mp);
if (ptr == (CTL_MSG *) 0) {
insert_table(mp, rp);
rp->answer = announce(mp, hp->h_name);
return;
}
if (mp->id_num > ptr->id_num) {
/*
* This is an explicit re-announce, so update the id_num
* field to avoid duplicates and re-announce the talk.
*/
ptr->id_num = new_id();
rp->id_num = htonl(ptr->id_num);
rp->answer = announce(mp, hp->h_name);
} else {
/* a duplicated request, so ignore it */
rp->id_num = htonl(ptr->id_num);
rp->answer = SUCCESS;
}
}
#include <utmp.h>
/*
* Search utmp for the local user
*/
find_user(name, tty)
char *name, *tty;
{
struct utmp ubuf;
int status;
FILE *fd;
struct stat statb;
char line[sizeof(ubuf.ut_line) + 1];
char ftty[sizeof(_PATH_DEV) - 1 + sizeof(line)];
if ((fd = fopen(_PATH_UTMP, "r")) == NULL) {
fprintf(stderr, "talkd: can't read %s.\n", _PATH_UTMP);
return (FAILED);
}
#define SCMPN(a, b) strncmp(a, b, sizeof (a))
status = NOT_HERE;
(void) strcpy(ftty, _PATH_DEV);
while (fread((char *) &ubuf, sizeof ubuf, 1, fd) == 1)
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;
/* 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 (strcmp(line, tty) == 0) {
status = SUCCESS;
break;
}
}
fclose(fd);
return (status);
}

233
libexec/talkd/table.c Normal file
View file

@ -0,0 +1,233 @@
/*
* 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[] = "@(#)table.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
/*
* 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
* entry so that overly old invitations can be eliminated.
*
* Consider this a mis-guided attempt at modularity
*/
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <protocols/talkd.h>
#include <syslog.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ID 16000 /* << 2^15 so I don't have sign troubles */
#define NIL ((TABLE_ENTRY *)0)
extern int debug;
struct timeval tp;
struct timezone txp;
typedef struct table_entry TABLE_ENTRY;
struct table_entry {
CTL_MSG request;
long time;
TABLE_ENTRY *next;
TABLE_ENTRY *last;
};
TABLE_ENTRY *table = NIL;
CTL_MSG *find_request();
CTL_MSG *find_match();
/*
* Look in the table for an invitation that matches the current
* request looking for an invitation
*/
CTL_MSG *
find_match(request)
register CTL_MSG *request;
{
register TABLE_ENTRY *ptr;
time_t current_time;
gettimeofday(&tp, &txp);
current_time = tp.tv_sec;
if (debug)
print_request("find_match", request);
for (ptr = table; ptr != NIL; ptr = ptr->next) {
if ((ptr->time - current_time) > MAX_LIFE) {
/* the entry is too old */
if (debug)
print_request("deleting expired entry",
&ptr->request);
delete(ptr);
continue;
}
if (debug)
print_request("", &ptr->request);
if (strcmp(request->l_name, ptr->request.r_name) == 0 &&
strcmp(request->r_name, ptr->request.l_name) == 0 &&
ptr->request.type == LEAVE_INVITE)
return (&ptr->request);
}
return ((CTL_MSG *)0);
}
/*
* Look for an identical request, as opposed to a complimentary
* one as find_match does
*/
CTL_MSG *
find_request(request)
register CTL_MSG *request;
{
register TABLE_ENTRY *ptr;
time_t current_time;
gettimeofday(&tp, &txp);
current_time = tp.tv_sec;
/*
* See if this is a repeated message, and check for
* out of date entries in the table while we are it.
*/
if (debug)
print_request("find_request", request);
for (ptr = table; ptr != NIL; ptr = ptr->next) {
if ((ptr->time - current_time) > MAX_LIFE) {
/* the entry is too old */
if (debug)
print_request("deleting expired entry",
&ptr->request);
delete(ptr);
continue;
}
if (debug)
print_request("", &ptr->request);
if (strcmp(request->r_name, ptr->request.r_name) == 0 &&
strcmp(request->l_name, ptr->request.l_name) == 0 &&
request->type == ptr->request.type &&
request->pid == ptr->request.pid) {
/* update the time if we 'touch' it */
ptr->time = current_time;
return (&ptr->request);
}
}
return ((CTL_MSG *)0);
}
insert_table(request, response)
CTL_MSG *request;
CTL_RESPONSE *response;
{
register TABLE_ENTRY *ptr;
time_t current_time;
gettimeofday(&tp, &txp);
current_time = tp.tv_sec;
request->id_num = new_id();
response->id_num = htonl(request->id_num);
/* insert a new entry into the top of the list */
ptr = (TABLE_ENTRY *)malloc(sizeof(TABLE_ENTRY));
if (ptr == NIL) {
syslog(LOG_ERR, "insert_table: Out of memory");
_exit(1);
}
ptr->time = current_time;
ptr->request = *request;
ptr->next = table;
if (ptr->next != NIL)
ptr->next->last = ptr;
ptr->last = NIL;
table = ptr;
}
/*
* Generate a unique non-zero sequence number
*/
new_id()
{
static int current_id = 0;
current_id = (current_id + 1) % MAX_ID;
/* 0 is reserved, helps to pick up bugs */
if (current_id == 0)
current_id = 1;
return (current_id);
}
/*
* Delete the invitation with id 'id_num'
*/
delete_invite(id_num)
int id_num;
{
register TABLE_ENTRY *ptr;
ptr = table;
if (debug)
syslog(LOG_DEBUG, "delete_invite(%d)", id_num);
for (ptr = table; ptr != NIL; ptr = ptr->next) {
if (ptr->request.id_num == id_num)
break;
if (debug)
print_request("", &ptr->request);
}
if (ptr != NIL) {
delete(ptr);
return (SUCCESS);
}
return (NOT_HERE);
}
/*
* Classic delete from a double-linked list
*/
delete(ptr)
register TABLE_ENTRY *ptr;
{
if (debug)
print_request("delete", &ptr->request);
if (table == ptr)
table = ptr->next;
else if (ptr->last != NIL)
ptr->last->next = ptr->next;
if (ptr->next != NIL)
ptr->next->last = ptr->last;
free((char *)ptr);
}

75
libexec/talkd/talkd.8 Normal file
View file

@ -0,0 +1,75 @@
.\" 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.
.\"
.\" @(#)talkd.8 8.2 (Berkeley) 12/11/93
.\"
.Dd December 11, 1993
.Dt TALKD 8
.Os BSD 4.3
.Sh NAME
.Nm talkd
.Nd remote user communication server
.Sh SYNOPSIS
.Nm talkd
.Sh DESCRIPTION
.Nm Talkd
is the server that notifies a user that someone else wants to
initiate a conversation.
It acts as a repository of invitations, responding to requests
by clients wishing to rendezvous to hold a conversation.
In normal operation, a client, the caller,
initiates a rendezvous by sending a
.Tn CTL_MSG
to the server of
type
.Tn LOOK_UP
(see
.Aq Pa protocols/talkd.h ) .
This causes the server to search its invitation
tables to check if an invitation currently exists for the caller
(to speak to the callee specified in the message).
If the lookup fails,
the caller then sends an
.Tn ANNOUNCE
message causing the server to
broadcast an announcement on the callee's login ports requesting contact.
When the callee responds, the local server uses the
recorded invitation to respond with the appropriate rendezvous
address and the caller and callee client programs establish a
stream connection through which the conversation takes place.
.Sh SEE ALSO
.Xr talk 1 ,
.Xr write 1
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.3 .

127
libexec/talkd/talkd.c Normal file
View file

@ -0,0 +1,127 @@
/*
* 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 copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)talkd.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
/*
* The top level of the daemon, the format is heavily borrowed
* 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 <protocols/talkd.h>
#include <signal.h>
#include <syslog.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <paths.h>
CTL_MSG request;
CTL_RESPONSE response;
int sockt;
int debug = 0;
void timeout();
long lastmsgtime;
char hostname[32];
#define TIMEOUT 30
#define MAXIDLE 120
main(argc, argv)
int argc;
char *argv[];
{
register CTL_MSG *mp = &request;
int cc;
if (getuid()) {
fprintf(stderr, "%s: getuid: not super-user\n", argv[0]);
exit(1);
}
openlog("talkd", LOG_PID, LOG_DAEMON);
if (gethostname(hostname, sizeof (hostname) - 1) < 0) {
syslog(LOG_ERR, "gethostname: %m");
_exit(1);
}
if (chdir(_PATH_DEV) < 0) {
syslog(LOG_ERR, "chdir: %s: %m", _PATH_DEV);
_exit(1);
}
if (argc > 1 && strcmp(argv[1], "-d") == 0)
debug = 1;
signal(SIGALRM, timeout);
alarm(TIMEOUT);
for (;;) {
extern int errno;
cc = recv(0, (char *)mp, sizeof (*mp), 0);
if (cc != sizeof (*mp)) {
if (cc < 0 && errno != EINTR)
syslog(LOG_WARNING, "recv: %m");
continue;
}
lastmsgtime = time(0);
process_request(mp, &response);
/* can block here, is this what I want? */
cc = sendto(sockt, (char *)&response,
sizeof (response), 0, (struct sockaddr *)&mp->ctl_addr,
sizeof (mp->ctl_addr));
if (cc != sizeof (response))
syslog(LOG_WARNING, "sendto: %m");
}
}
void
timeout()
{
if (time(0) - lastmsgtime >= MAXIDLE)
_exit(0);
alarm(TIMEOUT);
}

36
libexec/telnetd/Makefile Normal file
View file

@ -0,0 +1,36 @@
# @(#)Makefile 8.2 (Berkeley) 12/15/93
PROG= telnetd
CFLAGS+=-DLINEMODE -DKLUDGELINEMODE -DUSE_TERMIO -DDIAGNOSTICS
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 \
termstat.c utility.c
DPADD= ${LIBUTIL} ${LIBTERM}
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
.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 */

91
libexec/telnetd/authenc.c Normal file
View file

@ -0,0 +1,91 @@
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/4/93";
#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) {
bcopy((void *)str, (void *)nfrontp, 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);
}
char *
telnet_getenv(val)
char *val;
{
extern char *getenv();
return(getenv(val));
}
char *
telnet_gets(prompt, result, length, echo)
char *prompt;
char *result;
int length;
int echo;
{
return((char *)0);
}
#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */

296
libexec/telnetd/defs.h Normal file
View file

@ -0,0 +1,296 @@
/*
* 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.
*
* @(#)defs.h 8.1 (Berkeley) 6/4/93
*/
/*
* Telnet server defines
*/
#include <sys/types.h>
#include <sys/param.h>
#ifndef BSD
# define BSD 43
#endif
#if defined(CRAY) && !defined(LINEMODE)
# define SYSV_TERMIO
# define LINEMODE
# define KLUDGELINEMODE
# define DIAGNOSTICS
# if defined(UNICOS50) && !defined(UNICOS5)
# define UNICOS5
# endif
# if !defined(UNICOS5)
# define BFTPDAEMON
# define HAS_IP_TOS
# endif
#endif /* CRAY */
#if defined(UNICOS5) && !defined(NO_SETSID)
# define NO_SETSID
#endif
#if defined(PRINTOPTIONS) && defined(DIAGNOSTICS)
#define TELOPTS
#define TELCMDS
#define SLC_NAMES
#endif
#if defined(SYSV_TERMIO) && !defined(USE_TERMIO)
# define USE_TERMIO
#endif
#include <sys/socket.h>
#ifndef CRAY
#include <sys/wait.h>
#endif /* CRAY */
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifndef FILIO_H
#include <sys/ioctl.h>
#else
#include <sys/filio.h>
#endif
#include <netinet/in.h>
#include <arpa/telnet.h>
#include <stdio.h>
#ifdef __STDC__
#include <stdlib.h>
#endif
#include <signal.h>
#include <errno.h>
#include <netdb.h>
#include <syslog.h>
#ifndef LOG_DAEMON
#define LOG_DAEMON 0
#endif
#ifndef LOG_ODELAY
#define LOG_ODELAY 0
#endif
#include <ctype.h>
#ifndef NO_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#ifndef USE_TERMIO
#include <sgtty.h>
#else
# ifdef SYSV_TERMIO
# include <termio.h>
# else
# include <termios.h>
# endif
#endif
#if !defined(USE_TERMIO) || defined(NO_CC_T)
typedef unsigned char cc_t;
#endif
#ifdef __STDC__
#include <unistd.h>
#endif
#ifndef _POSIX_VDISABLE
# ifdef VDISABLE
# define _POSIX_VDISABLE VDISABLE
# else
# define _POSIX_VDISABLE ((unsigned char)'\377')
# endif
#endif
#ifdef CRAY
# ifdef CRAY1
# include <sys/pty.h>
# ifndef FD_ZERO
# include <sys/select.h>
# endif /* FD_ZERO */
# endif /* CRAY1 */
#include <memory.h>
#endif /* CRAY */
#ifdef __hpux
#include <sys/ptyio.h>
#endif
#if !defined(TIOCSCTTY) && defined(TCSETCTTY)
# define TIOCSCTTY TCSETCTTY
#endif
#ifndef FD_SET
#ifndef HAVE_fd_set
typedef struct fd_set { int fds_bits[1]; } fd_set;
#endif
#define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n)))
#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n)))
#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
#endif /* FD_SET */
/*
* I/O data buffers defines
*/
#define NETSLOP 64
#ifdef CRAY
#undef BUFSIZ
#define BUFSIZ 2048
#endif
#define NIACCUM(c) { *netip++ = c; \
ncc++; \
}
/* clock manipulations */
#define settimer(x) (clocks.x = ++clocks.system)
#define sequenceIs(x,y) (clocks.x < clocks.y)
/*
* Linemode support states, in decreasing order of importance
*/
#define REAL_LINEMODE 0x04
#define KLUDGE_OK 0x03
#define NO_AUTOKLUDGE 0x02
#define KLUDGE_LINEMODE 0x01
#define NO_LINEMODE 0x00
/*
* Structures of information for each special character function.
*/
typedef struct {
unsigned char flag; /* the flags for this function */
cc_t val; /* the value of the special character */
} slcent, *Slcent;
typedef struct {
slcent defset; /* the default settings */
slcent current; /* the current settings */
cc_t *sptr; /* a pointer to the char in */
/* system data structures */
} slcfun, *Slcfun;
#ifdef DIAGNOSTICS
/*
* Diagnostics capabilities
*/
#define TD_REPORT 0x01 /* Report operations to client */
#define TD_EXERCISE 0x02 /* Exercise client's implementation */
#define TD_NETDATA 0x04 /* Display received data stream */
#define TD_PTYDATA 0x08 /* Display data passed to pty */
#define TD_OPTIONS 0x10 /* Report just telnet options */
#endif /* DIAGNOSTICS */
/*
* We keep track of each side of the option negotiation.
*/
#define MY_STATE_WILL 0x01
#define MY_WANT_STATE_WILL 0x02
#define MY_STATE_DO 0x04
#define MY_WANT_STATE_DO 0x08
/*
* Macros to check the current state of things
*/
#define my_state_is_do(opt) (options[opt]&MY_STATE_DO)
#define my_state_is_will(opt) (options[opt]&MY_STATE_WILL)
#define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO)
#define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL)
#define my_state_is_dont(opt) (!my_state_is_do(opt))
#define my_state_is_wont(opt) (!my_state_is_will(opt))
#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt))
#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt))
#define set_my_state_do(opt) (options[opt] |= MY_STATE_DO)
#define set_my_state_will(opt) (options[opt] |= MY_STATE_WILL)
#define set_my_want_state_do(opt) (options[opt] |= MY_WANT_STATE_DO)
#define set_my_want_state_will(opt) (options[opt] |= MY_WANT_STATE_WILL)
#define set_my_state_dont(opt) (options[opt] &= ~MY_STATE_DO)
#define set_my_state_wont(opt) (options[opt] &= ~MY_STATE_WILL)
#define set_my_want_state_dont(opt) (options[opt] &= ~MY_WANT_STATE_DO)
#define set_my_want_state_wont(opt) (options[opt] &= ~MY_WANT_STATE_WILL)
/*
* Tricky code here. What we want to know is if the MY_STATE_WILL
* and MY_WANT_STATE_WILL bits have the same value. Since the two
* bits are adjacent, a little arithmatic will show that by adding
* in the lower bit, the upper bit will be set if the two bits were
* different, and clear if they were the same.
*/
#define my_will_wont_is_changing(opt) \
((options[opt]+MY_STATE_WILL) & MY_WANT_STATE_WILL)
#define my_do_dont_is_changing(opt) \
((options[opt]+MY_STATE_DO) & MY_WANT_STATE_DO)
/*
* Make everything symetrical
*/
#define HIS_STATE_WILL MY_STATE_DO
#define HIS_WANT_STATE_WILL MY_WANT_STATE_DO
#define HIS_STATE_DO MY_STATE_WILL
#define HIS_WANT_STATE_DO MY_WANT_STATE_WILL
#define his_state_is_do my_state_is_will
#define his_state_is_will my_state_is_do
#define his_want_state_is_do my_want_state_is_will
#define his_want_state_is_will my_want_state_is_do
#define his_state_is_dont my_state_is_wont
#define his_state_is_wont my_state_is_dont
#define his_want_state_is_dont my_want_state_is_wont
#define his_want_state_is_wont my_want_state_is_dont
#define set_his_state_do set_my_state_will
#define set_his_state_will set_my_state_do
#define set_his_want_state_do set_my_want_state_will
#define set_his_want_state_will set_my_want_state_do
#define set_his_state_dont set_my_state_wont
#define set_his_state_wont set_my_state_dont
#define set_his_want_state_dont set_my_want_state_wont
#define set_his_want_state_wont set_my_want_state_dont
#define his_will_wont_is_changing my_do_dont_is_changing
#define his_do_dont_is_changing my_will_wont_is_changing

240
libexec/telnetd/ext.h Normal file
View file

@ -0,0 +1,240 @@
/*
* 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.
*
* @(#)ext.h 8.2 (Berkeley) 12/15/93
*/
/*
* Telnet server variable declarations
*/
extern char options[256];
extern char do_dont_resp[256];
extern char will_wont_resp[256];
extern int linemode; /* linemode on/off */
#ifdef LINEMODE
extern int uselinemode; /* what linemode to use (on/off) */
extern int editmode; /* edit modes in use */
extern int useeditmode; /* edit modes to use */
extern int alwayslinemode; /* command line option */
# ifdef KLUDGELINEMODE
extern int lmodetype; /* Client support for linemode */
# endif /* KLUDGELINEMODE */
#endif /* LINEMODE */
extern int flowmode; /* current flow control state */
extern int restartany; /* restart output on any character state */
#ifdef DIAGNOSTICS
extern int diagnostic; /* telnet diagnostic capabilities */
#endif /* DIAGNOSTICS */
#ifdef BFTPDAEMON
extern int bftpd; /* behave as bftp daemon */
#endif /* BFTPDAEMON */
#if defined(SecurID)
extern int require_SecurID;
#endif
#if defined(AUTHENTICATION)
extern int auth_level;
#endif
extern slcfun slctab[NSLC + 1]; /* slc mapping table */
char *terminaltype;
/*
* I/O data buffers, pointers, and counters.
*/
extern char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp;
extern char netibuf[BUFSIZ], *netip;
extern char netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp;
extern char *neturg; /* one past last bye of urgent data */
extern int pcc, ncc;
#if defined(CRAY2) && defined(UNICOS5)
extern int unpcc; /* characters left unprocessed by CRAY-2 terminal routine */
extern char *unptyip; /* pointer to remaining characters in buffer */
#endif
extern int pty, net;
extern char *line;
extern int SYNCHing; /* we are in TELNET SYNCH mode */
#ifndef P
# ifdef __STDC__
# define P(x) x
# else
# define P(x) ()
# endif
#endif
extern void
_termstat P((void)),
add_slc P((int, int, int)),
check_slc P((void)),
change_slc P((int, int, int)),
cleanup P((int)),
clientstat P((int, int, int)),
copy_termbuf P((char *, int)),
deferslc P((void)),
defer_terminit P((void)),
do_opt_slc P((unsigned char *, int)),
doeof P((void)),
dooption P((int)),
dontoption P((int)),
edithost P((char *, char *)),
fatal P((int, char *)),
fatalperror P((int, char *)),
get_slc_defaults P((void)),
init_env P((void)),
init_termbuf P((void)),
interrupt P((void)),
localstat P((void)),
flowstat P((void)),
netclear P((void)),
netflush P((void)),
#ifdef DIAGNOSTICS
printoption P((char *, int)),
printdata P((char *, char *, int)),
printsub P((int, unsigned char *, int)),
#endif
ptyflush P((void)),
putchr P((int)),
putf P((char *, char *)),
recv_ayt P((void)),
send_do P((int, int)),
send_dont P((int, int)),
send_slc P((void)),
send_status P((void)),
send_will P((int, int)),
send_wont P((int, int)),
sendbrk P((void)),
sendsusp P((void)),
set_termbuf P((void)),
start_login P((char *, int, char *)),
start_slc P((int)),
#if defined(AUTHENTICATION)
start_slave P((char *)),
#else
start_slave P((char *, int, char *)),
#endif
suboption P((void)),
telrcv P((void)),
ttloop P((void)),
tty_binaryin P((int)),
tty_binaryout P((int));
extern int
end_slc P((unsigned char **)),
getnpty P((void)),
#ifndef convex
getpty P((int *)),
#endif
login_tty P((int)),
spcset P((int, cc_t *, cc_t **)),
stilloob P((int)),
terminit P((void)),
termstat P((void)),
tty_flowmode P((void)),
tty_restartany P((void)),
tty_isbinaryin P((void)),
tty_isbinaryout P((void)),
tty_iscrnl P((void)),
tty_isecho P((void)),
tty_isediting P((void)),
tty_islitecho P((void)),
tty_isnewmap P((void)),
tty_israw P((void)),
tty_issofttab P((void)),
tty_istrapsig P((void)),
tty_linemode P((void));
extern void
tty_rspeed P((int)),
tty_setecho P((int)),
tty_setedit P((int)),
tty_setlinemode P((int)),
tty_setlitecho P((int)),
tty_setsig P((int)),
tty_setsofttab P((int)),
tty_tspeed P((int)),
willoption P((int)),
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 */
/*
* The following are some clocks used to decide how to interpret
* the relationship between various variables.
*/
extern struct {
int
system, /* what the current time is */
echotoggle, /* last time user entered echo character */
modenegotiated, /* last time operating mode negotiated */
didnetreceive, /* last time we read data from network */
ttypesubopt, /* ttype subopt is received */
tspeedsubopt, /* tspeed subopt is received */
environsubopt, /* environ subopt is received */
oenvironsubopt, /* old environ subopt is received */
xdisplocsubopt, /* xdisploc subopt is received */
baseline, /* time started to do timed action */
gotDM; /* when did we last see a data mark */
} clocks;
#if defined(CRAY2) && defined(UNICOS5)
extern int needtermstat;
#endif
#ifndef DEFAULT_IM
# ifdef CRAY
# define DEFAULT_IM "\r\n\r\nCray UNICOS (%h) (%t)\r\n\r\r\n\r"
# else
# ifdef sun
# define DEFAULT_IM "\r\n\r\nSunOS UNIX (%h) (%t)\r\n\r\r\n\r"
# else
# 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"
# endif
# endif
# endif
#endif

48
libexec/telnetd/global.c Normal file
View file

@ -0,0 +1,48 @@
/*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)global.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
/*
* Allocate global variables. We do this
* by including the header file that defines
* them all as externs, but first we define
* the keyword "extern" to be nothing, so that
* we will actually allocate the space.
*/
#include "defs.h"
#define extern
#include "ext.h"

View file

@ -0,0 +1,55 @@
/*
* 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
*/
#if BSD > 43
# include <paths.h>
# ifndef _PATH_LOGIN
# define _PATH_LOGIN "/usr/bin/login"
# endif
#else
# define _PATH_TTY "/dev/tty"
# ifndef _PATH_LOGIN
# define _PATH_LOGIN "/bin/login"
# endif
#endif
#ifdef BFTPDAEMON
#define BFTPPATH "/usr/ucb/bftp"
#endif /* BFTPDAEMON */

493
libexec/telnetd/slc.c Normal file
View file

@ -0,0 +1,493 @@
/*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)slc.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include "telnetd.h"
#ifdef LINEMODE
/*
* local varibles
*/
static unsigned char *def_slcbuf = (unsigned char *)0;
static int def_slclen = 0;
static int slcchange; /* change to slc is requested */
static unsigned char *slcptr; /* pointer into slc buffer */
static unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */
/*
* send_slc
*
* Write out the current special characters to the client.
*/
void
send_slc()
{
register int i;
/*
* Send out list of triplets of special characters
* to client. We only send info on the characters
* that are currently supported.
*/
for (i = 1; i <= NSLC; i++) {
if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT)
continue;
add_slc((unsigned char)i, slctab[i].current.flag,
slctab[i].current.val);
}
} /* end of send_slc */
/*
* default_slc
*
* Set pty special characters to all the defaults.
*/
void
default_slc()
{
register int i;
for (i = 1; i <= NSLC; i++) {
slctab[i].current.val = slctab[i].defset.val;
if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE))
slctab[i].current.flag = SLC_NOSUPPORT;
else
slctab[i].current.flag = slctab[i].defset.flag;
if (slctab[i].sptr) {
*(slctab[i].sptr) = slctab[i].defset.val;
}
}
slcchange = 1;
} /* end of default_slc */
#endif /* LINEMODE */
/*
* get_slc_defaults
*
* Initialize the slc mapping table.
*/
void
get_slc_defaults()
{
register int i;
init_termbuf();
for (i = 1; i <= NSLC; i++) {
slctab[i].defset.flag =
spcset(i, &slctab[i].defset.val, &slctab[i].sptr);
slctab[i].current.flag = SLC_NOSUPPORT;
slctab[i].current.val = 0;
}
} /* end of get_slc_defaults */
#ifdef LINEMODE
/*
* add_slc
*
* Add an slc triplet to the slc buffer.
*/
void
add_slc(func, flag, val)
register char func, flag;
register cc_t val;
{
if ((*slcptr++ = (unsigned char)func) == 0xff)
*slcptr++ = 0xff;
if ((*slcptr++ = (unsigned char)flag) == 0xff)
*slcptr++ = 0xff;
if ((*slcptr++ = (unsigned char)val) == 0xff)
*slcptr++ = 0xff;
} /* end of add_slc */
/*
* start_slc
*
* Get ready to process incoming slc's and respond to them.
*
* The parameter getit is non-zero if it is necessary to grab a copy
* of the terminal control structures.
*/
void
start_slc(getit)
register int getit;
{
slcchange = 0;
if (getit)
init_termbuf();
(void) sprintf((char *)slcbuf, "%c%c%c%c",
IAC, SB, TELOPT_LINEMODE, LM_SLC);
slcptr = slcbuf + 4;
} /* end of start_slc */
/*
* end_slc
*
* Finish up the slc negotiation. If something to send, then send it.
*/
int
end_slc(bufp)
register unsigned char **bufp;
{
register int len;
void netflush();
/*
* If a change has occured, store the new terminal control
* structures back to the terminal driver.
*/
if (slcchange) {
set_termbuf();
}
/*
* If the pty state has not yet been fully processed and there is a
* deferred slc request from the client, then do not send any
* sort of slc negotiation now. We will respond to the client's
* request very soon.
*/
if (def_slcbuf && (terminit() == 0)) {
return(0);
}
if (slcptr > (slcbuf + 4)) {
if (bufp) {
*bufp = &slcbuf[4];
return(slcptr - slcbuf - 4);
} else {
(void) sprintf((char *)slcptr, "%c%c", IAC, SE);
slcptr += 2;
len = slcptr - slcbuf;
writenet(slcbuf, len);
netflush(); /* force it out immediately */
DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2););
}
}
return (0);
} /* end of end_slc */
/*
* process_slc
*
* Figure out what to do about the client's slc
*/
void
process_slc(func, flag, val)
register unsigned char func, flag;
register cc_t val;
{
register int hislevel, mylevel, ack;
/*
* Ensure that we know something about this function
*/
if (func > NSLC) {
add_slc(func, SLC_NOSUPPORT, 0);
return;
}
/*
* Process the special case requests of 0 SLC_DEFAULT 0
* and 0 SLC_VARIABLE 0. Be a little forgiving here, don't
* worry about whether the value is actually 0 or not.
*/
if (func == 0) {
if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) {
default_slc();
send_slc();
} else if (flag == SLC_VARIABLE) {
send_slc();
}
return;
}
/*
* Appears to be a function that we know something about. So
* get on with it and see what we know.
*/
hislevel = flag & SLC_LEVELBITS;
mylevel = slctab[func].current.flag & SLC_LEVELBITS;
ack = flag & SLC_ACK;
/*
* ignore the command if:
* the function value and level are the same as what we already have;
* or the level is the same and the ack bit is set
*/
if (hislevel == mylevel && (val == slctab[func].current.val || ack)) {
return;
} else if (ack) {
/*
* If we get here, we got an ack, but the levels don't match.
* This shouldn't happen. If it does, it is probably because
* we have sent two requests to set a variable without getting
* a response between them, and this is the first response.
* So, ignore it, and wait for the next response.
*/
return;
} else {
change_slc(func, flag, val);
}
} /* end of process_slc */
/*
* change_slc
*
* Process a request to change one of our special characters.
* Compare client's request with what we are capable of supporting.
*/
void
change_slc(func, flag, val)
register char func, flag;
register cc_t val;
{
register int hislevel, mylevel;
hislevel = flag & SLC_LEVELBITS;
mylevel = slctab[func].defset.flag & SLC_LEVELBITS;
/*
* If client is setting a function to NOSUPPORT
* or DEFAULT, then we can easily and directly
* accomodate the request.
*/
if (hislevel == SLC_NOSUPPORT) {
slctab[func].current.flag = flag;
slctab[func].current.val = (cc_t)_POSIX_VDISABLE;
flag |= SLC_ACK;
add_slc(func, flag, val);
return;
}
if (hislevel == SLC_DEFAULT) {
/*
* Special case here. If client tells us to use
* the default on a function we don't support, then
* return NOSUPPORT instead of what we may have as a
* default level of DEFAULT.
*/
if (mylevel == SLC_DEFAULT) {
slctab[func].current.flag = SLC_NOSUPPORT;
} else {
slctab[func].current.flag = slctab[func].defset.flag;
}
slctab[func].current.val = slctab[func].defset.val;
add_slc(func, slctab[func].current.flag,
slctab[func].current.val);
return;
}
/*
* Client wants us to change to a new value or he
* is telling us that he can't change to our value.
* Some of the slc's we support and can change,
* some we do support but can't change,
* and others we don't support at all.
* If we can change it then we have a pointer to
* the place to put the new value, so change it,
* otherwise, continue the negotiation.
*/
if (slctab[func].sptr) {
/*
* We can change this one.
*/
slctab[func].current.val = val;
*(slctab[func].sptr) = val;
slctab[func].current.flag = flag;
flag |= SLC_ACK;
slcchange = 1;
add_slc(func, flag, val);
} else {
/*
* It is not possible for us to support this
* request as he asks.
*
* If our level is DEFAULT, then just ack whatever was
* sent.
*
* If he can't change and we can't change,
* then degenerate to NOSUPPORT.
*
* Otherwise we send our level back to him, (CANTCHANGE
* or NOSUPPORT) and if CANTCHANGE, send
* our value as well.
*/
if (mylevel == SLC_DEFAULT) {
slctab[func].current.flag = flag;
slctab[func].current.val = val;
flag |= SLC_ACK;
} else if (hislevel == SLC_CANTCHANGE &&
mylevel == SLC_CANTCHANGE) {
flag &= ~SLC_LEVELBITS;
flag |= SLC_NOSUPPORT;
slctab[func].current.flag = flag;
} else {
flag &= ~SLC_LEVELBITS;
flag |= mylevel;
slctab[func].current.flag = flag;
if (mylevel == SLC_CANTCHANGE) {
slctab[func].current.val =
slctab[func].defset.val;
val = slctab[func].current.val;
}
}
add_slc(func, flag, val);
}
} /* end of change_slc */
#if defined(USE_TERMIO) && (VEOF == VMIN)
cc_t oldeofc = '\004';
#endif
/*
* check_slc
*
* Check the special characters in use and notify the client if any have
* changed. Only those characters that are capable of being changed are
* likely to have changed. If a local change occurs, kick the support level
* and flags up to the defaults.
*/
void
check_slc()
{
register int i;
for (i = 1; i <= NSLC; i++) {
#if defined(USE_TERMIO) && (VEOF == VMIN)
/*
* In a perfect world this would be a neat little
* function. But in this world, we should not notify
* client of changes to the VEOF char when
* ICANON is off, because it is not representing
* a special character.
*/
if (i == SLC_EOF) {
if (!tty_isediting())
continue;
else if (slctab[i].sptr)
oldeofc = *(slctab[i].sptr);
}
#endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */
if (slctab[i].sptr &&
(*(slctab[i].sptr) != slctab[i].current.val)) {
slctab[i].current.val = *(slctab[i].sptr);
if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE)
slctab[i].current.flag = SLC_NOSUPPORT;
else
slctab[i].current.flag = slctab[i].defset.flag;
add_slc((unsigned char)i, slctab[i].current.flag,
slctab[i].current.val);
}
}
} /* check_slc */
/*
* do_opt_slc
*
* Process an slc option buffer. Defer processing of incoming slc's
* until after the terminal state has been processed. Save the first slc
* request that comes along, but discard all others.
*
* ptr points to the beginning of the buffer, len is the length.
*/
void
do_opt_slc(ptr, len)
register unsigned char *ptr;
register int len;
{
register unsigned char func, flag;
cc_t val;
register unsigned char *end = ptr + len;
if (terminit()) { /* go ahead */
while (ptr < end) {
func = *ptr++;
if (ptr >= end) break;
flag = *ptr++;
if (ptr >= end) break;
val = (cc_t)*ptr++;
process_slc(func, flag, val);
}
} else {
/*
* save this slc buffer if it is the first, otherwise dump
* it.
*/
if (def_slcbuf == (unsigned char *)0) {
def_slclen = len;
def_slcbuf = (unsigned char *)malloc((unsigned)len);
if (def_slcbuf == (unsigned char *)0)
return; /* too bad */
bcopy(ptr, def_slcbuf, len);
}
}
} /* end of do_opt_slc */
/*
* deferslc
*
* Do slc stuff that was deferred.
*/
void
deferslc()
{
if (def_slcbuf) {
start_slc(1);
do_opt_slc(def_slcbuf, def_slclen);
(void) end_slc(0);
free(def_slcbuf);
def_slcbuf = (unsigned char *)0;
def_slclen = 0;
}
} /* end of deferslc */
#endif /* LINEMODE */

1620
libexec/telnetd/state.c Normal file

File diff suppressed because it is too large Load diff

2135
libexec/telnetd/sys_term.c Normal file

File diff suppressed because it is too large Load diff

605
libexec/telnetd/telnetd.8 Normal file
View file

@ -0,0 +1,605 @@
.\" 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.
.\"
.\" @(#)telnetd.8 8.3 (Berkeley) 3/1/94
.\"
.Dd March 1, 1994
.Dt TELNETD 8
.Os BSD 4.2
.Sh NAME
.Nm telnetd
.Nd DARPA
.Tn TELNET
protocol server
.Sh SYNOPSIS
.Nm /usr/libexec/telnetd
.Op Fl BUhlkns
.Op Fl D Ar debugmode
.Op Fl I Ns Ar initid
.Op Fl S Ar tos
.Op Fl X Ar authtype
.Op Fl a Ar authmode
.Op Fl edebug
.Op Fl r Ns Ar lowpty-highpty
.Op Fl u Ar len
.Op Fl debug Op Ar port
.Sh DESCRIPTION
The
.Nm telnetd
command is a server which supports the
.Tn DARPA
standard
.Tn TELNET
virtual terminal protocol.
.Nm Telnetd
is normally invoked by the internet server (see
.Xr inetd 8 )
for requests to connect to the
.Tn TELNET
port as indicated by the
.Pa /etc/services
file (see
.Xr services 5 ) .
The
.Fl debug
option may be used to start up
.Nm telnetd
manually, instead of through
.Xr inetd 8 .
If started up this way,
.Ar port
may be specified to run
.Nm telnetd
on an alternate
.Tn TCP
port number.
.Pp
The
.Nm telnetd
command accepts the following options:
.Bl -tag -width "-a authmode"
.It Fl a Ar authmode
This option may be used for specifying what mode should
be used for authentication.
Note that this option is only useful if
.Nm telnetd
has been compiled with support for the
.Dv AUTHENTICATION
option.
There are several valid values for
.Ar authmode:
.Bl -tag -width debug
.It debug
Turns on authentication debugging code.
.It user
Only allow connections when the remote user
can provide valid authentication information
to identify the remote user,
and is allowed access to the specified account
without providing a password.
.It valid
Only allow connections when the remote user
can provide valid authentication information
to identify the remote user.
The
.Xr login 1
command will provide any additional user verification
needed if the remote user is not allowed automatic
access to the specified account.
.It other
Only allow connections that supply some authentication information.
This option is currently not supported
by any of the existing authentication mechanisms,
and is thus the same as specifying
.Fl a
.Cm valid .
.It none
This is the default state.
Authentication information is not required.
If no or insufficient authentication information
is provided, then the
.Xr login 1
program will provide the necessary user
verification.
.It off
This disables the authentication code.
All user verification will happen through the
.Xr login 1
program.
.El
.It Fl B
Specifies bftp server mode. In this mode,
.Nm telnetd
causes login to start a
.Xr bftp 1
session rather than the user's
normal shell. In bftp daemon mode normal
logins are not supported, and it must be used
on a port other than the normal
.Tn TELNET
port.
.It Fl D Ar debugmode
This option may be used for debugging purposes.
This allows
.Nm telnetd
to print out debugging information
to the connection, allowing the user to see what
.Nm telnetd
is doing.
There are several possible values for
.Ar debugmode:
.Bl -tag -width exercise
.It Cm options
Prints information about the negotiation of
.Tn TELNET
options.
.It Cm report
Prints the
.Cm options
information, plus some additional information
about what processing is going on.
.It Cm netdata
Displays the data stream received by
.Nm telnetd.
.It Cm ptydata
Displays data written to the pty.
.It Cm exercise
Has not been implemented yet.
.El
.It Fl debug
Enables debugging on each socket created by
.Nm telnetd
(see
.Dv SO_DEBUG
in
.Xr socket 2 ) .
.It Fl edebug
If
.Nm telnetd
has been compiled with support for data encryption, then the
.Fl edebug
option may be used to enable encryption debugging code.
.It Fl h
Disables the printing of host-specific information before
login has been completed.
.It Fl I Ar initid
This option is only applicable to
.Tn UNICOS
systems prior to 7.0.
It specifies the
.Dv ID
from
.Pa /etc/inittab
to use when init starts login sessions. The default
.Dv ID
is
.Dv fe.
.It Fl k
This option is only useful if
.Nm telnetd
has been compiled with both linemode and kludge linemode
support. If the
.Fl k
option is specified, then if the remote client does not
support the
.Dv LINEMODE
option, then
.Nm telnetd
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
.Dv DONT SUPPRESS-GO-AHEAD
and
.Dv DONT ECHO . )
The
.Fl k
option is most useful when there are remote clients
that do not support kludge linemode, but pass the heuristic
(if they respond with
.Dv WILL TIMING-MARK
in response to a
.Dv DO TIMING-MARK)
for kludge linemode support.
.It Fl l
Specifies line mode. Tries to force clients to use line-
at-a-time mode.
If the
.Dv LINEMODE
option is not supported, it will go
into kludge linemode.
.It Fl n
Disable
.Dv TCP
keep-alives. Normally
.Nm telnetd
enables the
.Tn TCP
keep-alive mechanism to probe connections that
have been idle for some period of time to determine
if the client is still there, so that idle connections
from machines that have crashed or can no longer
be reached may be cleaned up.
.It Fl r Ar lowpty-highpty
This option is only enabled when
.Nm telnetd
is compiled for
.Dv UNICOS.
It specifies an inclusive range of pseudo-terminal devices to
use. If the system has sysconf variable
.Dv _SC_CRAY_NPTY
configured, the default pty search range is 0 to
.Dv _SC_CRAY_NPTY;
otherwise, the default range is 0 to 128. Either
.Ar lowpty
or
.Ar highpty
may be omitted to allow changing
either end of the search range. If
.Ar lowpty
is omitted, the - character is still required so that
.Nm telnetd
can differentiate
.Ar highpty
from
.Ar lowpty .
.It Fl s
This option is only enabled if
.Nm telnetd
is compiled with support for
.Tn SecurID
cards.
It causes the
.Fl s
option to be passed on to
.Xr login 1 ,
and thus is only useful if
.Xr login 1
supports the
.Fl s
flag to indicate that only
.Tn SecurID
validated logins are allowed, and is
usually useful for controlling remote logins
from outside of a firewall.
.It Fl S Ar tos
.It Fl u Ar len
This option is used to specify the size of the field
in the
.Dv utmp
structure that holds the remote host name.
If the resolved host name is longer than
.Ar len ,
the dotted decimal value will be used instead.
This allows hosts with very long host names that
overflow this field to still be uniquely identified.
Specifying
.Fl u0
indicates that only dotted decimal addresses
should be put into the
.Pa utmp
file.
.It Fl U
This option causes
.Nm telnetd
to refuse connections from addresses that
cannot be mapped back into a symbolic name
via the
.Xr gethostbyaddr 3
routine.
.It Fl X Ar authtype
This option is only valid if
.Nm telnetd
has been built with support for the authentication option.
It disables the use of
.Ar authtype
authentication, and
can be used to temporarily disable
a specific authentication type without having to recompile
.Nm telnetd .
.El
.Pp
.Nm Telnetd
operates by allocating a pseudo-terminal device (see
.Xr pty 4 )
for a client, then creating a login process which has
the slave side of the pseudo-terminal as
.Dv stdin ,
.Dv stdout
and
.Dv stderr .
.Nm Telnetd
manipulates the master side of the pseudo-terminal,
implementing the
.Tn TELNET
protocol and passing characters
between the remote client and the login process.
.Pp
When a
.Tn TELNET
session is started up,
.Nm telnetd
sends
.Tn TELNET
options to the client side indicating
a willingness to do the
following
.Tn TELNET
options, which are described in more detail below:
.Bd -literal -offset indent
DO AUTHENTICATION
WILL ENCRYPT
DO TERMINAL TYPE
DO TSPEED
DO XDISPLOC
DO NEW-ENVIRON
DO ENVIRON
WILL SUPPRESS GO AHEAD
DO ECHO
DO LINEMODE
DO NAWS
WILL STATUS
DO LFLOW
DO TIMING-MARK
.Ed
.Pp
The pseudo-terminal allocated to the client is configured
to operate in \*(lqcooked\*(rq mode, and with
.Dv XTABS and
.Dv CRMOD
enabled (see
.Xr tty 4 ) .
.Pp
.Nm Telnetd
has support for enabling locally the following
.Tn TELNET
options:
.Bl -tag -width "DO AUTHENTICATION"
.It "WILL ECHO"
When the
.Dv LINEMODE
option is enabled, a
.Dv WILL ECHO
or
.Dv WONT ECHO
will be sent to the client to indicate the
current state of terminal echoing.
When terminal echo is not desired, a
.Dv WILL ECHO
is sent to indicate that
.Tn telnetd
will take care of echoing any data that needs to be
echoed to the terminal, and then nothing is echoed.
When terminal echo is desired, a
.Dv WONT ECHO
is sent to indicate that
.Tn telnetd
will not be doing any terminal echoing, so the
client should do any terminal echoing that is needed.
.It "WILL BINARY"
Indicates that the client is willing to send a
8 bits of data, rather than the normal 7 bits
of the Network Virtual Terminal.
.It "WILL SGA"
Indicates that it will not be sending
.Dv IAC GA,
go ahead, commands.
.It "WILL STATUS"
Indicates a willingness to send the client, upon
request, of the current status of all
.Tn TELNET
options.
.It "WILL TIMING-MARK"
Whenever a
.Dv DO TIMING-MARK
command is received, it is always responded
to with a
.Dv WILL TIMING-MARK
.It "WILL LOGOUT"
When a
.Dv DO LOGOUT
is received, a
.Dv WILL LOGOUT
is sent in response, and the
.Tn TELNET
session is shut down.
.It "WILL ENCRYPT"
Only sent if
.Nm telnetd
is compiled with support for data encryption, and
indicates a willingness to decrypt
the data stream.
.El
.Pp
.Nm Telnetd
has support for enabling remotely the following
.Tn TELNET
options:
.Bl -tag -width "DO AUTHENTICATION"
.It "DO BINARY"
Sent to indicate that
.Tn telnetd
is willing to receive an 8 bit data stream.
.It "DO LFLOW"
Requests that the client handle flow control
characters remotely.
.It "DO ECHO"
This is not really supported, but is sent to identify a 4.2BSD
.Xr telnet 1
client, which will improperly respond with
.Dv WILL ECHO.
If a
.Dv WILL ECHO
is received, a
.Dv DONT ECHO
will be sent in response.
.It "DO TERMINAL-TYPE"
Indicates a desire to be able to request the
name of the type of terminal that is attached
to the client side of the connection.
.It "DO SGA"
Indicates that it does not need to receive
.Dv IAC GA,
the go ahead command.
.It "DO NAWS"
Requests that the client inform the server when
the window (display) size changes.
.It "DO TERMINAL-SPEED"
Indicates a desire to be able to request information
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
the telnet client.
.It "DO NEW-ENVIRON"
Indicates a desire to be able to request environment
variable information, as described in RFC 1572.
.It "DO ENVIRON"
Indicates a desire to be able to request environment
variable information, as described in RFC 1408.
.It "DO LINEMODE"
Only sent if
.Nm telnetd
is compiled with support for linemode, and
requests that the client do line by line processing.
.It "DO TIMING-MARK"
Only sent if
.Nm telnetd
is compiled with support for both linemode and
kludge linemode, and the client responded with
.Dv WONT LINEMODE.
If the client responds with
.Dv WILL TM,
the it is assumed that the client supports
kludge linemode.
Note that the
.Op Fl k
option can be used to disable this.
.It "DO AUTHENTICATION"
Only sent if
.Nm telnetd
is compiled with support for authentication, and
indicates a willingness to receive authentication
information for automatic login.
.It "DO ENCRYPT"
Only sent if
.Nm telnetd
is compiled with support for data encryption, and
indicates a willingness to decrypt
the data stream.
.Sh ENVIRONMENT
.Sh FILES
.Pa /etc/services
.br
.Pa /etc/inittab
(UNICOS systems only)
.br
.Pa /etc/iptos
(if supported)
.br
.Pa /usr/ucb/bftp
(if supported)
.Sh "SEE ALSO"
.Xr telnet 1 ,
.Xr login 1 ,
.Xr bftp 1
(if supported)
.Sh STANDARDS
.Bl -tag -compact -width RFC-1572
.It Cm RFC-854
.Tn TELNET
PROTOCOL SPECIFICATION
.It Cm RFC-855
TELNET OPTION SPECIFICATIONS
.It Cm RFC-856
TELNET BINARY TRANSMISSION
.It Cm RFC-857
TELNET ECHO OPTION
.It Cm RFC-858
TELNET SUPPRESS GO AHEAD OPTION
.It Cm RFC-859
TELNET STATUS OPTION
.It Cm RFC-860
TELNET TIMING MARK OPTION
.It Cm RFC-861
TELNET EXTENDED OPTIONS - LIST OPTION
.It Cm RFC-885
TELNET END OF RECORD OPTION
.It Cm RFC-1073
Telnet Window Size Option
.It Cm RFC-1079
Telnet Terminal Speed Option
.It Cm RFC-1091
Telnet Terminal-Type Option
.It Cm RFC-1096
Telnet X Display Location Option
.It Cm RFC-1123
Requirements for Internet Hosts -- Application and Support
.It Cm RFC-1184
Telnet Linemode Option
.It Cm RFC-1372
Telnet Remote Flow Control Option
.It Cm RFC-1416
Telnet Authentication Option
.It Cm RFC-1411
Telnet Authentication: Kerberos Version 4
.It Cm RFC-1412
Telnet Authentication: SPX
.It Cm RFC-1571
Telnet Environment Option Interoperability Issues
.It Cm RFC-1572
Telnet Environment Option
.Sh BUGS
Some
.Tn TELNET
commands are only partially implemented.
.Pp
Because of bugs in the original 4.2 BSD
.Xr telnet 1 ,
.Nm telnetd
performs some dubious protocol exchanges to try to discover if the remote
client is, in fact, a 4.2 BSD
.Xr telnet 1 .
.Pp
Binary mode
has no common interpretation except between similar operating systems
(Unix in this case).
.Pp
The terminal type name received from the remote client is converted to
lower case.
.Pp
.Nm Telnetd
never sends
.Tn TELNET
.Dv IAC GA
(go ahead) commands.

1582
libexec/telnetd/telnetd.c Normal file

File diff suppressed because it is too large Load diff

49
libexec/telnetd/telnetd.h Normal file
View file

@ -0,0 +1,49 @@
/*
* 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.
*
* @(#)telnetd.h 8.1 (Berkeley) 6/4/93
*/
#include "defs.h"
#include "ext.h"
#ifdef DIAGNOSTICS
#define DIAG(a,b) if (diagnostic & (a)) b
#else
#define DIAG(a,b)
#endif
/* other external variables */
extern char **environ;
extern int errno;

660
libexec/telnetd/termstat.c Normal file
View file

@ -0,0 +1,660 @@
/*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)termstat.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include "telnetd.h"
/*
* local variables
*/
int def_tspeed = -1, def_rspeed = -1;
#ifdef TIOCSWINSZ
int def_row = 0, def_col = 0;
#endif
#ifdef LINEMODE
static int _terminit = 0;
#endif /* LINEMODE */
#if defined(CRAY2) && defined(UNICOS5)
int newmap = 1; /* nonzero if \n maps to ^M^J */
#endif
#ifdef LINEMODE
/*
* localstat
*
* This function handles all management of linemode.
*
* Linemode allows the client to do the local editing of data
* and send only complete lines to the server. Linemode state is
* based on the state of the pty driver. If the pty is set for
* external processing, then we can use linemode. Further, if we
* can use real linemode, then we can look at the edit control bits
* in the pty to determine what editing the client should do.
*
* Linemode support uses the following state flags to keep track of
* current and desired linemode state.
* alwayslinemode : true if -l was specified on the telnetd
* command line. It means to have linemode on as much as
* possible.
*
* lmodetype: signifies whether the client can
* handle real linemode, or if use of kludgeomatic linemode
* is preferred. It will be set to one of the following:
* REAL_LINEMODE : use linemode option
* NO_KLUDGE : don't initiate kludge linemode.
* KLUDGE_LINEMODE : use kludge linemode
* NO_LINEMODE : client is ignorant of linemode
*
* linemode, uselinemode : linemode is true if linemode
* is currently on, uselinemode is the state that we wish
* to be in. If another function wishes to turn linemode
* on or off, it sets or clears uselinemode.
*
* editmode, useeditmode : like linemode/uselinemode, but
* these contain the edit mode states (edit and trapsig).
*
* The state variables correspond to some of the state information
* in the pty.
* linemode:
* In real linemode, this corresponds to whether the pty
* expects external processing of incoming data.
* In kludge linemode, this more closely corresponds to the
* whether normal processing is on or not. (ICANON in
* system V, or COOKED mode in BSD.)
* If the -l option was specified (alwayslinemode), then
* an attempt is made to force external processing on at
* all times.
*
* The following heuristics are applied to determine linemode
* handling within the server.
* 1) Early on in starting up the server, an attempt is made
* to negotiate the linemode option. If this succeeds
* then lmodetype is set to REAL_LINEMODE and all linemode
* processing occurs in the context of the linemode option.
* 2) If the attempt to negotiate the linemode option failed,
* and the "-k" (don't initiate kludge linemode) isn't set,
* then we try to use kludge linemode. We test for this
* capability by sending "do Timing Mark". If a positive
* response comes back, then we assume that the client
* understands kludge linemode (ech!) and the
* lmodetype flag is set to KLUDGE_LINEMODE.
* 3) Otherwise, linemode is not supported at all and
* lmodetype remains set to NO_LINEMODE (which happens
* to be 0 for convenience).
* 4) At any time a command arrives that implies a higher
* state of linemode support in the client, we move to that
* linemode support.
*
* A short explanation of kludge linemode is in order here.
* 1) The heuristic to determine support for kludge linemode
* is to send a do timing mark. We assume that a client
* that supports timing marks also supports kludge linemode.
* A risky proposition at best.
* 2) Further negotiation of linemode is done by changing the
* the server's state regarding SGA. If server will SGA,
* then linemode is off, if server won't SGA, then linemode
* is on.
*/
void
localstat()
{
void netflush();
int need_will_echo = 0;
#if defined(CRAY2) && defined(UNICOS5)
/*
* Keep track of that ol' CR/NL mapping while we're in the
* neighborhood.
*/
newmap = tty_isnewmap();
#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();
/*
* Check linemode on/off state
*/
uselinemode = tty_linemode();
/*
* If alwayslinemode is on, and pty is changing to turn it off, then
* force linemode back on.
*/
if (alwayslinemode && linemode && !uselinemode) {
uselinemode = 1;
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 */
/*
* Do echo mode handling as soon as we know what the
* linemode is going to be.
* If the pty has echo turned off, then tell the client that
* the server will echo. If echo is on, then the server
* will echo if in character mode, but in linemode the
* client should do local echoing. The state machine will
* not send anything if it is unnecessary, so don't worry
* about that here.
*
* If we need to send the WILL ECHO (because echo is off),
* then delay that until after we have changed the MODE.
* This way, when the user is turning off both editing
* and echo, the client will get editing turned off first.
* This keeps the client from going into encryption mode
* and then right back out if it is doing auto-encryption
* when passwords are being typed.
*/
if (uselinemode) {
if (tty_isecho())
send_wont(TELOPT_ECHO, 1);
else
need_will_echo = 1;
#ifdef KLUDGELINEMODE
if (lmodetype == KLUDGE_OK)
lmodetype = KLUDGE_LINEMODE;
#endif
}
/*
* If linemode is being turned off, send appropriate
* command and then we're all done.
*/
if (!uselinemode && linemode) {
# ifdef KLUDGELINEMODE
if (lmodetype == REAL_LINEMODE) {
# endif /* KLUDGELINEMODE */
send_dont(TELOPT_LINEMODE, 1);
# ifdef KLUDGELINEMODE
} else if (lmodetype == KLUDGE_LINEMODE)
send_will(TELOPT_SGA, 1);
# endif /* KLUDGELINEMODE */
send_will(TELOPT_ECHO, 1);
linemode = uselinemode;
goto done;
}
# ifdef KLUDGELINEMODE
/*
* If using real linemode check edit modes for possible later use.
* If we are in kludge linemode, do the SGA negotiation.
*/
if (lmodetype == REAL_LINEMODE) {
# endif /* KLUDGELINEMODE */
useeditmode = 0;
if (tty_isediting())
useeditmode |= MODE_EDIT;
if (tty_istrapsig())
useeditmode |= MODE_TRAPSIG;
if (tty_issofttab())
useeditmode |= MODE_SOFT_TAB;
if (tty_islitecho())
useeditmode |= MODE_LIT_ECHO;
# ifdef KLUDGELINEMODE
} else if (lmodetype == KLUDGE_LINEMODE) {
if (tty_isediting() && uselinemode)
send_wont(TELOPT_SGA, 1);
else
send_will(TELOPT_SGA, 1);
}
# endif /* KLUDGELINEMODE */
/*
* Negotiate linemode on if pty state has changed to turn it on.
* Send appropriate command and send along edit mode, then all done.
*/
if (uselinemode && !linemode) {
# ifdef KLUDGELINEMODE
if (lmodetype == KLUDGE_LINEMODE) {
send_wont(TELOPT_SGA, 1);
} else if (lmodetype == REAL_LINEMODE) {
# endif /* KLUDGELINEMODE */
send_do(TELOPT_LINEMODE, 1);
/* send along edit modes */
(void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
TELOPT_LINEMODE, LM_MODE, useeditmode,
IAC, SE);
nfrontp += 7;
editmode = useeditmode;
# ifdef KLUDGELINEMODE
}
# endif /* KLUDGELINEMODE */
linemode = uselinemode;
goto done;
}
# ifdef KLUDGELINEMODE
/*
* None of what follows is of any value if not using
* real linemode.
*/
if (lmodetype < REAL_LINEMODE)
goto done;
# endif /* KLUDGELINEMODE */
if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
/*
* If edit mode changed, send edit mode.
*/
if (useeditmode != editmode) {
/*
* Send along appropriate edit mode mask.
*/
(void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
TELOPT_LINEMODE, LM_MODE, useeditmode,
IAC, SE);
nfrontp += 7;
editmode = useeditmode;
}
/*
* Check for changes to special characters in use.
*/
start_slc(0);
check_slc();
(void) end_slc(0);
}
done:
if (need_will_echo)
send_will(TELOPT_ECHO, 1);
/*
* Some things should be deferred until after the pty state has
* been set by the local process. Do those things that have been
* deferred now. This only happens once.
*/
if (_terminit == 0) {
_terminit = 1;
defer_terminit();
}
netflush();
set_termbuf();
return;
} /* end of localstat */
#endif /* LINEMODE */
/*
* flowstat
*
* Check for changes to flow control
*/
void
flowstat()
{
if (his_state_is_will(TELOPT_LFLOW)) {
if (tty_flowmode() != flowmode) {
flowmode = tty_flowmode();
(void) sprintf(nfrontp, "%c%c%c%c%c%c",
IAC, SB, TELOPT_LFLOW,
flowmode ? LFLOW_ON : LFLOW_OFF,
IAC, SE);
nfrontp += 6;
}
if (tty_restartany() != restartany) {
restartany = tty_restartany();
(void) sprintf(nfrontp, "%c%c%c%c%c%c",
IAC, SB, TELOPT_LFLOW,
restartany ? LFLOW_RESTART_ANY
: LFLOW_RESTART_XON,
IAC, SE);
nfrontp += 6;
}
}
}
/*
* clientstat
*
* Process linemode related requests from the client.
* Client can request a change to only one of linemode, editmode or slc's
* at a time, and if using kludge linemode, then only linemode may be
* affected.
*/
void
clientstat(code, parm1, parm2)
register int code, parm1, parm2;
{
void netflush();
/*
* Get a copy of terminal characteristics.
*/
init_termbuf();
/*
* Process request from client. code tells what it is.
*/
switch (code) {
#ifdef LINEMODE
case TELOPT_LINEMODE:
/*
* Don't do anything unless client is asking us to change
* modes.
*/
uselinemode = (parm1 == WILL);
if (uselinemode != linemode) {
# ifdef KLUDGELINEMODE
/*
* If using kludge linemode, make sure that
* we can do what the client asks.
* We can not turn off linemode if alwayslinemode
* and the ICANON bit is set.
*/
if (lmodetype == KLUDGE_LINEMODE) {
if (alwayslinemode && tty_isediting()) {
uselinemode = 1;
}
}
/*
* Quit now if we can't do it.
*/
if (uselinemode == linemode)
return;
/*
* If using real linemode and linemode is being
* turned on, send along the edit mode mask.
*/
if (lmodetype == REAL_LINEMODE && uselinemode)
# else /* KLUDGELINEMODE */
if (uselinemode)
# endif /* KLUDGELINEMODE */
{
useeditmode = 0;
if (tty_isediting())
useeditmode |= MODE_EDIT;
if (tty_istrapsig)
useeditmode |= MODE_TRAPSIG;
if (tty_issofttab())
useeditmode |= MODE_SOFT_TAB;
if (tty_islitecho())
useeditmode |= MODE_LIT_ECHO;
(void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
SB, TELOPT_LINEMODE, LM_MODE,
useeditmode, IAC, SE);
nfrontp += 7;
editmode = useeditmode;
}
tty_setlinemode(uselinemode);
linemode = uselinemode;
if (!linemode)
send_will(TELOPT_ECHO, 1);
}
break;
case LM_MODE:
{
register int ack, changed;
/*
* Client has sent along a mode mask. If it agrees with
* what we are currently doing, ignore it; if not, it could
* be viewed as a request to change. Note that the server
* will change to the modes in an ack if it is different from
* what we currently have, but we will not ack the ack.
*/
useeditmode &= MODE_MASK;
ack = (useeditmode & MODE_ACK);
useeditmode &= ~MODE_ACK;
if (changed = (useeditmode ^ editmode)) {
/*
* This check is for a timing problem. If the
* state of the tty has changed (due to the user
* application) we need to process that info
* before we write in the state contained in the
* ack!!! This gets out the new MODE request,
* and when the ack to that command comes back
* we'll set it and be in the right mode.
*/
if (ack)
localstat();
if (changed & MODE_EDIT)
tty_setedit(useeditmode & MODE_EDIT);
if (changed & MODE_TRAPSIG)
tty_setsig(useeditmode & MODE_TRAPSIG);
if (changed & MODE_SOFT_TAB)
tty_setsofttab(useeditmode & MODE_SOFT_TAB);
if (changed & MODE_LIT_ECHO)
tty_setlitecho(useeditmode & MODE_LIT_ECHO);
set_termbuf();
if (!ack) {
(void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
SB, TELOPT_LINEMODE, LM_MODE,
useeditmode|MODE_ACK,
IAC, SE);
nfrontp += 7;
}
editmode = useeditmode;
}
break;
} /* end of case LM_MODE */
#endif /* LINEMODE */
case TELOPT_NAWS:
#ifdef TIOCSWINSZ
{
struct winsize ws;
def_col = parm1;
def_row = parm2;
#ifdef LINEMODE
/*
* Defer changing window size until after terminal is
* initialized.
*/
if (terminit() == 0)
return;
#endif /* LINEMODE */
/*
* Change window size as requested by client.
*/
ws.ws_col = parm1;
ws.ws_row = parm2;
(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
}
#endif /* TIOCSWINSZ */
break;
case TELOPT_TSPEED:
{
def_tspeed = parm1;
def_rspeed = parm2;
#ifdef LINEMODE
/*
* Defer changing the terminal speed.
*/
if (terminit() == 0)
return;
#endif /* LINEMODE */
/*
* Change terminal speed as requested by client.
* We set the receive speed first, so that if we can't
* store seperate receive and transmit speeds, the transmit
* speed will take precedence.
*/
tty_rspeed(parm2);
tty_tspeed(parm1);
set_termbuf();
break;
} /* end of case TELOPT_TSPEED */
default:
/* What? */
break;
} /* end of switch */
#if defined(CRAY2) && defined(UNICOS5)
/*
* Just in case of the likely event that we changed the pty state.
*/
rcv_ioctl();
#endif /* defined(CRAY2) && defined(UNICOS5) */
netflush();
} /* end of clientstat */
#if defined(CRAY2) && defined(UNICOS5)
void
termstat()
{
needtermstat = 1;
}
void
_termstat()
{
needtermstat = 0;
init_termbuf();
localstat();
rcv_ioctl();
}
#endif /* defined(CRAY2) && defined(UNICOS5) */
#ifdef LINEMODE
/*
* defer_terminit
*
* Some things should not be done until after the login process has started
* and all the pty modes are set to what they are supposed to be. This
* function is called when the pty state has been processed for the first time.
* It calls other functions that do things that were deferred in each module.
*/
void
defer_terminit()
{
/*
* local stuff that got deferred.
*/
if (def_tspeed != -1) {
clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
def_tspeed = def_rspeed = 0;
}
#ifdef TIOCSWINSZ
if (def_col || def_row) {
struct winsize ws;
bzero((char *)&ws, sizeof(ws));
ws.ws_col = def_col;
ws.ws_row = def_row;
(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
}
#endif
/*
* The only other module that currently defers anything.
*/
deferslc();
} /* end of defer_terminit */
/*
* terminit
*
* Returns true if the pty state has been processed yet.
*/
int
terminit()
{
return(_terminit);
} /* end of terminit */
#endif /* LINEMODE */

Some files were not shown because too many files have changed in this diff Show more