mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-04 12:52:15 +00:00
Import Lite2's src/libexec, except for makekey (which was spammed
by a repository copy from 1.1.5 and patched back to Lite1) and rbootd/bootdir/SYSHPBSD (which is binary). All changed files have already left the vendor branch.
This commit is contained in:
parent
fb044857e6
commit
9c60775004
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/CSRG/dist/; revision=27847
92
libexec/bugfiler/bug.h
Normal file
92
libexec/bugfiler/bug.h
Normal 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
290
libexec/bugfiler/bugfiler.8
Normal 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
167
libexec/bugfiler/bugfiler.c
Normal 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);
|
||||
}
|
32
libexec/bugfiler/bugformat
Normal file
32
libexec/bugfiler/bugformat
Normal 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
89
libexec/bugfiler/error.c
Normal 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
41
libexec/bugfiler/extern.h
Normal 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
165
libexec/bugfiler/gethead.c
Normal 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);
|
||||
}
|
38
libexec/bugfiler/pathnames.h
Normal file
38
libexec/bugfiler/pathnames.h
Normal 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
115
libexec/bugfiler/process.c
Normal 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
131
libexec/bugfiler/redist.c
Normal 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
118
libexec/bugfiler/reply.c
Normal 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);
|
||||
}
|
85
libexec/bugfiler/sendbug.1
Normal file
85
libexec/bugfiler/sendbug.1
Normal 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 .
|
66
libexec/bugfiler/sendbug.sh
Normal file
66
libexec/bugfiler/sendbug.sh
Normal 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
|
291
libexec/ftpd/ftpd.8
Normal file
291
libexec/ftpd/ftpd.8
Normal file
@ -0,0 +1,291 @@
|
||||
.\" 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.3 (Berkeley) 6/1/94
|
||||
.\"
|
||||
.Dd June 1, 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.
|
||||
.ne 1i
|
||||
.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
1654
libexec/ftpd/ftpd.c
Normal file
File diff suppressed because it is too large
Load Diff
60
libexec/kpasswdd/kpasswdd.8
Normal file
60
libexec/kpasswdd/kpasswdd.8
Normal 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
271
libexec/kpasswdd/kpasswdd.c
Normal 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);
|
||||
}
|
||||
}
|
168
libexec/lfs_cleanerd/clean.h
Normal file
168
libexec/lfs_cleanerd/clean.h
Normal 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.2 (Berkeley) 5/4/95
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 *, char *));
|
||||
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
|
571
libexec/lfs_cleanerd/cleanerd.c
Normal file
571
libexec/lfs_cleanerd/cleanerd.c
Normal file
@ -0,0 +1,571 @@
|
||||
/*-
|
||||
* 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.5 (Berkeley) 6/10/95";
|
||||
#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;
|
||||
int stat_report = 0;
|
||||
struct cleaner_stats {
|
||||
double util_tot;
|
||||
double util_sos;
|
||||
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_bytes; /* bytes in segment */
|
||||
};
|
||||
|
||||
struct tossstruct {
|
||||
struct lfs *lfs;
|
||||
int seg;
|
||||
};
|
||||
|
||||
#define CLEAN_BYTES 0x1
|
||||
|
||||
/* function prototypes for system calls; not sure where they should go */
|
||||
int lfs_segwait __P((fsid_t *, struct timeval *));
|
||||
int lfs_segclean __P((fsid_t *, u_long));
|
||||
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, long));
|
||||
int clean_loop __P((FS_INFO *, int, long));
|
||||
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;
|
||||
long clean_opts; /* cleaning options */
|
||||
int i, nodaemon, segs_per_clean;
|
||||
int opt, cmd_err;
|
||||
char *fs_name; /* name of filesystem to clean */
|
||||
extern int optind;
|
||||
|
||||
cmd_err = nodaemon = 0;
|
||||
clean_opts = 0;
|
||||
segs_per_clean = 1;
|
||||
while ((opt = getopt(argc, argv, "bdmn:r:s")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'b': /*
|
||||
* Use live bytes to determine
|
||||
* how many segs to clean.
|
||||
*/
|
||||
clean_opts |= CLEAN_BYTES;
|
||||
break;
|
||||
case 'd': /* Debug mode. */
|
||||
nodaemon = 1;
|
||||
break;
|
||||
case 'm': /* Use mmap instead of read/write */
|
||||
do_mmap = 1;
|
||||
break;
|
||||
case 'n': /* How many segs to clean at once */
|
||||
segs_per_clean = atoi(optarg);
|
||||
break;
|
||||
case 'r': /* Report every stat_report segments */
|
||||
stat_report = atoi(optarg);
|
||||
break;
|
||||
case 's': /* small writes */
|
||||
do_small = 1;
|
||||
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, "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, segs_per_clean, clean_opts))
|
||||
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, nsegs, options)
|
||||
FS_INFO *fsp; /* file system information */
|
||||
int nsegs;
|
||||
long options;
|
||||
{
|
||||
double loadavg[MAXLOADS];
|
||||
time_t now;
|
||||
u_long max_free_segs;
|
||||
u_long db_per_seg;
|
||||
|
||||
/*
|
||||
* Compute the maximum possible number of free segments, given the
|
||||
* number of free blocks.
|
||||
*/
|
||||
db_per_seg = fsbtodb(&fsp->fi_lfs, fsp->fi_lfs.lfs_ssize);
|
||||
max_free_segs = fsp->fi_lfs.lfs_bfree / db_per_seg;
|
||||
|
||||
/*
|
||||
* We will clean if there are not enough free blocks or total clean
|
||||
* space is less than BUSY_LIM % of possible clean space.
|
||||
*/
|
||||
now = time((time_t *)NULL);
|
||||
#ifdef VERBOSE
|
||||
printf("db_er_seg = %d max_free_segs = %d, bfree = %d avail = %d ",
|
||||
db_per_seg, max_free_segs, fsp->fi_lfs.lfs_bfree,
|
||||
fsp->fi_lfs.lfs_avail);
|
||||
printf("clean = %d\n", fsp->fi_cip->clean);
|
||||
#endif
|
||||
if ((fsp->fi_lfs.lfs_bfree - fsp->fi_lfs.lfs_avail > db_per_seg &&
|
||||
fsp->fi_lfs.lfs_avail < db_per_seg) ||
|
||||
(fsp->fi_cip->clean < max_free_segs &&
|
||||
(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, nsegs, options);
|
||||
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, nsegs, options);
|
||||
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, nsegs, options)
|
||||
FS_INFO *fsp; /* file system information */
|
||||
int (*cost_func) __P((FS_INFO *, SEGUSE *));
|
||||
int nsegs;
|
||||
long options;
|
||||
{
|
||||
struct seglist *segs, *sp;
|
||||
int to_clean, cleaned_bytes;
|
||||
int i;
|
||||
|
||||
if ((segs =
|
||||
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) {
|
||||
/* Check which cleaning algorithm to use. */
|
||||
if (options & CLEAN_BYTES) {
|
||||
cleaned_bytes = 0;
|
||||
to_clean = nsegs <<
|
||||
(fsp->fi_lfs.lfs_segshift + fsp->fi_lfs.lfs_bshift);
|
||||
for (sp = segs; i && cleaned_bytes < to_clean;
|
||||
i--, ++sp) {
|
||||
if (clean_segment(fsp, sp->sl_id) < 0)
|
||||
perror("clean_segment failed");
|
||||
else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,
|
||||
sp->sl_id) < 0)
|
||||
perror("lfs_segclean failed");
|
||||
printf("Cleaned segment %d (%d bytes)\n",
|
||||
sp->sl_id, sp->sl_bytes);
|
||||
cleaned_bytes += sp->sl_bytes;
|
||||
}
|
||||
} else
|
||||
for (i = MIN(i, nsegs), sp = segs; i-- ; ++sp) {
|
||||
if (clean_segment(fsp, sp->sl_id) < 0)
|
||||
perror("clean_segment failed");
|
||||
else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,
|
||||
sp->sl_id) < 0)
|
||||
perror("lfs_segclean failed");
|
||||
printf("Completed cleaning segment %d\n", sp->sl_id);
|
||||
}
|
||||
}
|
||||
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_bytes = sup->su_nbytes;
|
||||
++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;
|
||||
double util;
|
||||
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.segs_cleaned;
|
||||
cleaner_stats.blocks_written += num_blocks;
|
||||
util = ((double)num_blocks / fsp->fi_lfs.lfs_ssize);
|
||||
cleaner_stats.util_tot += util;
|
||||
cleaner_stats.util_sos += util * util;
|
||||
|
||||
if (do_small)
|
||||
maxblocks = MAXPHYS / fsp->fi_lfs.lfs_bsize - 1;
|
||||
else
|
||||
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);
|
||||
if (stat_report && cleaner_stats.segs_cleaned % stat_report == 0)
|
||||
sig_report(SIGUSR1);
|
||||
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;
|
||||
{
|
||||
double avg;
|
||||
|
||||
printf("lfs_cleanerd:\t%s%d\n\t\t%s%d\n\t\t%s%d\n\t\t%s%d\n\t\t%s%d\n",
|
||||
"blocks_read ", cleaner_stats.blocks_read,
|
||||
"blocks_written ", cleaner_stats.blocks_written,
|
||||
"segs_cleaned ", cleaner_stats.segs_cleaned,
|
||||
"segs_empty ", cleaner_stats.segs_empty,
|
||||
"seg_error ", cleaner_stats.segs_error);
|
||||
printf("\t\t%s%5.2f\n\t\t%s%5.2f\n",
|
||||
"util_tot ", cleaner_stats.util_tot,
|
||||
"util_sos ", cleaner_stats.util_sos);
|
||||
printf("\t\tavg util: %4.2f std dev: %9.6f\n",
|
||||
avg = cleaner_stats.util_tot / cleaner_stats.segs_cleaned,
|
||||
cleaner_stats.util_sos / cleaner_stats.segs_cleaned - avg * avg);
|
||||
|
||||
|
||||
if (sig == SIGUSR2) {
|
||||
cleaner_stats.blocks_read = 0;
|
||||
cleaner_stats.blocks_written = 0;
|
||||
cleaner_stats.segs_cleaned = 0;
|
||||
cleaner_stats.segs_empty = 0;
|
||||
cleaner_stats.segs_error = 0;
|
||||
cleaner_stats.util_tot = 0.0;
|
||||
cleaner_stats.util_sos = 0.0;
|
||||
}
|
||||
if (sig == SIGINT)
|
||||
exit(0);
|
||||
}
|
695
libexec/lfs_cleanerd/library.c
Normal file
695
libexec/lfs_cleanerd/library.c
Normal file
@ -0,0 +1,695 @@
|
||||
/*-
|
||||
* 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.3 (Berkeley) 5/24/95";
|
||||
#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;
|
||||
char *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 (strcmp((*buf)->f_fstypename, 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, nsegs, 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 (nsegs = 0, timestamp = 0; nsegs < sup->su_nsums; nsegs++) {
|
||||
sp = (SEGSUM *)s;
|
||||
|
||||
nblocks = pseg_valid(fsp, sp);
|
||||
if (nblocks <= 0) {
|
||||
printf("Warning: invalid segment summary at 0x%x\n",
|
||||
pseg_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE
|
||||
printf("\tpartial at: 0x%x\n", pseg_addr);
|
||||
print_SEGSUM(lfsp, sp);
|
||||
fflush(stdout);
|
||||
#endif /* VERBOSE */
|
||||
|
||||
/* 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 (i = 0, 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;
|
||||
int db_frag;
|
||||
u_long page_size;
|
||||
long *lp;
|
||||
|
||||
#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;
|
||||
if (fip->fi_lastlength == page_size) {
|
||||
bip->bi_size = page_size;
|
||||
psegaddr += db_per_block;
|
||||
bp += page_size;
|
||||
} else {
|
||||
db_frag = fragstodb(&(fsp->fi_lfs),
|
||||
numfrags(&(fsp->fi_lfs),
|
||||
fip->fi_lastlength));
|
||||
#ifdef VERBOSE
|
||||
printf("lastlength, frags: %d, %d, %d\n",
|
||||
fip->fi_lastlength, temp,
|
||||
bytetoda(fsp, temp));
|
||||
fflush(stdout);
|
||||
#endif
|
||||
bip->bi_size = fip->fi_lastlength;
|
||||
bp += fip->fi_lastlength;
|
||||
psegaddr += db_frag;
|
||||
}
|
||||
++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 (ssp->ss_magic != SS_MAGIC)
|
||||
return(0);
|
||||
|
||||
if ((nblocks = dump_summary(&fsp->fi_lfs, ssp, 0, NULL)) <= 0 ||
|
||||
nblocks > fsp->fi_lfs.lfs_ssize - 1)
|
||||
return(0);
|
||||
|
||||
/* check data/inode block(s) checksum too */
|
||||
datap = (u_long *)malloc(nblocks * sizeof(u_long));
|
||||
p = (caddr_t)ssp + LFS_SUMMARY_SIZE;
|
||||
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;
|
||||
}
|
||||
}
|
228
libexec/lfs_cleanerd/print.c
Normal file
228
libexec/lfs_cleanerd/print.c
Normal file
@ -0,0 +1,228 @@
|
||||
/*-
|
||||
* 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.2 (Berkeley) 5/24/95";
|
||||
#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_magic != SS_MAGIC)
|
||||
return(-1);
|
||||
|
||||
if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum,
|
||||
LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum))))
|
||||
return(-1);
|
||||
|
||||
numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
|
||||
|
||||
/* Do some basic sanity checking. */
|
||||
if (sp->ss_nfinfo > LFS_SUMMARY_SIZE / sizeof(FINFO) ||
|
||||
numblocks > lfsp->lfs_ssize ||
|
||||
numblocks > LFS_SUMMARY_SIZE / sizeof(daddr_t))
|
||||
return(-1);
|
||||
|
||||
if (flags & DUMP_SUM_HEADER) {
|
||||
(void)printf(" %s0x%X\t%s%d\t%s%d\n %s0x%X\t%s0x%X\t%s0x%X\n",
|
||||
"next ", sp->ss_next,
|
||||
"nfinfo ", sp->ss_nfinfo,
|
||||
"ninos ", sp->ss_ninos,
|
||||
"sumsum ", sp->ss_sumsum,
|
||||
"datasum ", sp->ss_datasum,
|
||||
"magic ", sp->ss_magic);
|
||||
(void)printf(" create %s", ctime((time_t *)&sp->ss_create));
|
||||
}
|
||||
|
||||
/* 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%qX\t%s%d\n",
|
||||
"segmask ", lfsp->lfs_segmask,
|
||||
"segshift ", lfsp->lfs_segshift,
|
||||
"bmask ", lfsp->lfs_bmask,
|
||||
"bshift ", lfsp->lfs_bshift);
|
||||
|
||||
(void)printf("%s0x%qX\t\t%s%d\t%s0x%qX\t%s%d\n",
|
||||
"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 */
|
14
libexec/mail.local/Makefile.dist
Normal file
14
libexec/mail.local/Makefile.dist
Normal file
@ -0,0 +1,14 @@
|
||||
# @(#)Makefile.dist 8.1 (Berkeley) 10/17/94
|
||||
|
||||
BINDIR= ${DESTDIR}/usr/lib
|
||||
BINOWN= root
|
||||
BINMODE=4555
|
||||
|
||||
mail.local: mail.local.c
|
||||
${CC} -O -o mail.local mail.local.c
|
||||
|
||||
install: mail.local
|
||||
install -s -o ${BINOWN} -m ${BINMODE} mail.local ${BINDIR}
|
||||
|
||||
clean:
|
||||
rm -f mail.local core a.out
|
868
libexec/mail.local/mail.local.c
Normal file
868
libexec/mail.local/mail.local.c
Normal file
@ -0,0 +1,868 @@
|
||||
/*-
|
||||
* 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.22 (Berkeley) 6/21/95";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* This is not intended to compile on System V derived systems
|
||||
* such as Solaris or HP-UX, since they use a totally different
|
||||
* approach to mailboxes (essentially, they have a setgid program
|
||||
* rather than setuid, and they rely on the ability to "give away"
|
||||
* files to do their work). IT IS NOT A BUG that this doesn't
|
||||
* compile on such architectures.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#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>
|
||||
#include <ctype.h>
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
#ifndef LOCK_EX
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#ifdef BSD4_4
|
||||
# include "pathnames.h"
|
||||
#endif
|
||||
|
||||
#ifndef __P
|
||||
# ifdef __STDC__
|
||||
# define __P(protos) protos
|
||||
# else
|
||||
# define __P(protos) ()
|
||||
# define const
|
||||
# endif
|
||||
#endif
|
||||
#ifndef __dead
|
||||
# if defined(__GNUC__) && (__GNUC__ < 2 || __GNUC_MINOR__ < 5) && !defined(__STRICT_ANSI__)
|
||||
# define __dead __volatile
|
||||
# else
|
||||
# define __dead
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BSD4_4
|
||||
# define _BSD_VA_LIST_ va_list
|
||||
extern char *strerror __P((int));
|
||||
extern int snprintf __P((char *, int, const char *, ...));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If you don't have setreuid, and you have saved uids, and you have
|
||||
* a seteuid() call that doesn't try to emulate using setuid(), then
|
||||
* you can try defining USE_SETEUID.
|
||||
*/
|
||||
#ifdef USE_SETEUID
|
||||
# define setreuid(r, e) seteuid(e)
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_LOCTMP
|
||||
# define _PATH_LOCTMP "/tmp/local.XXXXXX"
|
||||
#endif
|
||||
#ifndef _PATH_MAILDIR
|
||||
# define _PATH_MAILDIR "/var/spool/mail"
|
||||
#endif
|
||||
|
||||
#ifndef S_ISREG
|
||||
# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
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;
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
/* make sure we have some open file descriptors */
|
||||
for (fd = 10; fd < 30; fd++)
|
||||
(void) close(fd);
|
||||
|
||||
/* use a reasonable umask */
|
||||
(void) umask(0077);
|
||||
|
||||
#ifdef LOG_MAIL
|
||||
openlog("mail.local", 0, LOG_MAIL);
|
||||
#else
|
||||
openlog("mail.local", 0);
|
||||
#endif
|
||||
|
||||
from = NULL;
|
||||
while ((ch = getopt(argc, argv, "df:r:")) != EOF)
|
||||
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 line[2048];
|
||||
char tmpbuf[sizeof _PATH_LOCTMP + 1];
|
||||
|
||||
strcpy(tmpbuf, _PATH_LOCTMP);
|
||||
if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL) {
|
||||
e_to_sys(errno);
|
||||
err("unable to open temporary file");
|
||||
}
|
||||
(void)unlink(tmpbuf);
|
||||
|
||||
(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 *p;
|
||||
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;
|
||||
}
|
||||
endpwent();
|
||||
|
||||
/*
|
||||
* Keep name reasonably short to avoid buffer overruns.
|
||||
* This isn't necessary on BSD because of the proper
|
||||
* definition of snprintf(), but it can cause problems
|
||||
* on other systems.
|
||||
* Also, clear out any bogus characters.
|
||||
*/
|
||||
|
||||
if (strlen(name) > 40)
|
||||
name[40] = '\0';
|
||||
for (p = name; *p != '\0'; p++)
|
||||
{
|
||||
if (!isascii(*p))
|
||||
*p &= 0x7f;
|
||||
else if (!isprint(*p))
|
||||
*p = '.';
|
||||
}
|
||||
|
||||
(void)snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
|
||||
|
||||
/*
|
||||
* 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:
|
||||
lockmbox(path);
|
||||
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);
|
||||
goto err1;
|
||||
}
|
||||
} else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) {
|
||||
e_to_sys(errno);
|
||||
warn("%s: irregular file", path);
|
||||
goto err0;
|
||||
} else if (sb.st_uid != pw->pw_uid) {
|
||||
warn("%s: wrong ownership (%d)", path, sb.st_uid);
|
||||
unlockmbox();
|
||||
return;
|
||||
} else {
|
||||
mbfd = open(path, O_APPEND|O_WRONLY, 0);
|
||||
if (mbfd != -1 &&
|
||||
(fstat(mbfd, &fsb) || fsb.st_nlink != 1 ||
|
||||
!S_ISREG(fsb.st_mode) || sb.st_dev != fsb.st_dev ||
|
||||
sb.st_ino != fsb.st_ino || sb.st_uid != fsb.st_uid)) {
|
||||
warn("%s: file changed after open", path);
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
if (mbfd == -1) {
|
||||
e_to_sys(errno);
|
||||
warn("%s: %s", path, strerror(errno));
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* 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),
|
||||
sizeof curoff > sizeof(long) ? "%s@%qd\n" : "%s@%ld\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;
|
||||
}
|
||||
if (setreuid(0, pw->pw_uid) < 0) {
|
||||
e_to_sys(errno);
|
||||
warn("setreuid(0, %d): %s (r=%d, e=%d)",
|
||||
pw->pw_uid, strerror(errno), getuid(), geteuid());
|
||||
goto err1;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("new euid = %d\n", geteuid());
|
||||
#endif
|
||||
while ((nr = read(fd, buf, sizeof(buf))) > 0)
|
||||
for (off = 0; off < nr; off += nw)
|
||||
if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
|
||||
e_to_sys(errno);
|
||||
warn("%s: %s", path, strerror(errno));
|
||||
goto err3;
|
||||
}
|
||||
if (nr < 0) {
|
||||
e_to_sys(errno);
|
||||
warn("temporary file: %s", strerror(errno));
|
||||
goto err3;
|
||||
}
|
||||
|
||||
/* Flush to disk, don't wait for update. */
|
||||
if (fsync(mbfd)) {
|
||||
e_to_sys(errno);
|
||||
warn("%s: %s", path, strerror(errno));
|
||||
err3:
|
||||
if (setreuid(0, 0) < 0) {
|
||||
e_to_sys(errno);
|
||||
warn("setreuid(0, 0): %s", strerror(errno));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("reset euid = %d\n", geteuid());
|
||||
#endif
|
||||
err2: (void)ftruncate(mbfd, curoff);
|
||||
err1: (void)close(mbfd);
|
||||
err0: unlockmbox();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Close and check -- NFS doesn't write until the close. */
|
||||
if (close(mbfd)) {
|
||||
e_to_sys(errno);
|
||||
warn("%s: %s", path, strerror(errno));
|
||||
unlockmbox();
|
||||
return;
|
||||
}
|
||||
|
||||
if (setreuid(0, 0) < 0) {
|
||||
e_to_sys(errno);
|
||||
warn("setreuid(0, 0): %s", strerror(errno));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("reset euid = %d\n", geteuid());
|
||||
#endif
|
||||
unlockmbox();
|
||||
notifybiff(biffmsg);
|
||||
}
|
||||
|
||||
/*
|
||||
* user.lock files are necessary for compatibility with other
|
||||
* systems, e.g., when the mail spool file is NFS exported.
|
||||
* Alas, mailbox locking is more than just a local matter.
|
||||
* EPA 11/94.
|
||||
*/
|
||||
|
||||
char lockname[MAXPATHLEN];
|
||||
int locked = 0;
|
||||
|
||||
lockmbox(path)
|
||||
char *path;
|
||||
{
|
||||
int statfailed = 0;
|
||||
|
||||
if (locked)
|
||||
return;
|
||||
sprintf(lockname, "%s.lock", path);
|
||||
for (;; sleep(5)) {
|
||||
int fd;
|
||||
struct stat st;
|
||||
time_t now;
|
||||
|
||||
fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT, 0);
|
||||
if (fd >= 0) {
|
||||
locked = 1;
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if (stat(lockname, &st) < 0) {
|
||||
if (statfailed++ > 5)
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
statfailed = 0;
|
||||
time(&now);
|
||||
if (now < st.st_ctime + 300)
|
||||
continue;
|
||||
unlink(lockname);
|
||||
}
|
||||
}
|
||||
|
||||
unlockmbox()
|
||||
{
|
||||
if (!locked)
|
||||
return;
|
||||
unlink(lockname);
|
||||
locked = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
memcpy(&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");
|
||||
|
||||
#if !defined(ultrix) && !defined(__osf__)
|
||||
/* Log the message to syslog. */
|
||||
vsyslog(LOG_ERR, fmt, ap);
|
||||
#else
|
||||
{
|
||||
char fmtbuf[10240];
|
||||
|
||||
(void) sprintf(fmtbuf, fmt, ap);
|
||||
syslog(LOG_ERR, "%s", fmtbuf);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 && EWOULDBLOCK != EDEADLK
|
||||
case EWOULDBLOCK: /* Operation would block. */
|
||||
#endif
|
||||
eval = EX_TEMPFAIL;
|
||||
break;
|
||||
default:
|
||||
eval = EX_UNAVAILABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BSD4_4
|
||||
|
||||
# ifndef __osf__
|
||||
char *
|
||||
strerror(eno)
|
||||
int eno;
|
||||
{
|
||||
extern int sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
static char ebuf[60];
|
||||
|
||||
if (eno >= 0 && eno <= sys_nerr)
|
||||
return sys_errlist[eno];
|
||||
(void) sprintf(ebuf, "Error %d", eno);
|
||||
return ebuf;
|
||||
}
|
||||
# endif
|
||||
|
||||
# if __STDC__
|
||||
snprintf(char *buf, int bufsiz, const char *fmt, ...)
|
||||
# else
|
||||
snprintf(buf, bufsiz, fmt, va_alist)
|
||||
char *buf;
|
||||
int bufsiz;
|
||||
const char *fmt;
|
||||
va_dcl
|
||||
# endif
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
# if __STDC__
|
||||
va_start(ap, fmt);
|
||||
# else
|
||||
va_start(ap);
|
||||
# endif
|
||||
vsprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ultrix
|
||||
|
||||
/*
|
||||
* Copyright (c) 1987, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static int _gettemp();
|
||||
|
||||
mkstemp(path)
|
||||
char *path;
|
||||
{
|
||||
int fd;
|
||||
|
||||
return (_gettemp(path, &fd) ? fd : -1);
|
||||
}
|
||||
|
||||
/*
|
||||
char *
|
||||
mktemp(path)
|
||||
char *path;
|
||||
{
|
||||
return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
|
||||
}
|
||||
*/
|
||||
|
||||
static
|
||||
_gettemp(path, doopen)
|
||||
char *path;
|
||||
register int *doopen;
|
||||
{
|
||||
extern int errno;
|
||||
register char *start, *trv;
|
||||
struct stat sbuf;
|
||||
u_int pid;
|
||||
|
||||
pid = getpid();
|
||||
for (trv = path; *trv; ++trv); /* extra X's get set to 0's */
|
||||
while (*--trv == 'X') {
|
||||
*trv = (pid % 10) + '0';
|
||||
pid /= 10;
|
||||
}
|
||||
|
||||
/*
|
||||
* check the target directory; if you have six X's and it
|
||||
* doesn't exist this runs for a *very* long time.
|
||||
*/
|
||||
for (start = trv + 1;; --trv) {
|
||||
if (trv <= path)
|
||||
break;
|
||||
if (*trv == '/') {
|
||||
*trv = '\0';
|
||||
if (stat(path, &sbuf))
|
||||
return(0);
|
||||
if (!S_ISDIR(sbuf.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
return(0);
|
||||
}
|
||||
*trv = '/';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (doopen) {
|
||||
if ((*doopen =
|
||||
open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
|
||||
return(1);
|
||||
if (errno != EEXIST)
|
||||
return(0);
|
||||
}
|
||||
else if (stat(path, &sbuf))
|
||||
return(errno == ENOENT ? 1 : 0);
|
||||
|
||||
/* tricky little algorithm for backward compatibility */
|
||||
for (trv = start;;) {
|
||||
if (!*trv)
|
||||
return(0);
|
||||
if (*trv == 'z')
|
||||
*trv++ = 'a';
|
||||
else {
|
||||
if (isdigit(*trv))
|
||||
*trv = 'a';
|
||||
else
|
||||
++*trv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
#endif
|
149
libexec/rexecd/rexecd.8
Normal file
149
libexec/rexecd/rexecd.8
Normal file
@ -0,0 +1,149 @@
|
||||
.\" 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.3 (Berkeley) 6/1/94
|
||||
.\"
|
||||
.Dd June 1, 1994
|
||||
.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.
|
||||
.ne 1i
|
||||
.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 .
|
756
libexec/rlogind/rlogind.c
Normal file
756
libexec/rlogind/rlogind.c
Normal file
@ -0,0 +1,756 @@
|
||||
/*-
|
||||
* 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.2 (Berkeley) 4/28/95";
|
||||
#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
|
||||
|
||||
execle(_PATH_LOGIN, "login", "-p",
|
||||
"-h", hostname, "-f", "--", lusername, NULL, env);
|
||||
} else
|
||||
execle(_PATH_LOGIN, "login", "-p",
|
||||
"-h", hostname, "--", lusername, NULL, env);
|
||||
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 */
|
||||
memmove(&w, cp+4, 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
162
libexec/talkd/announce.c
Normal file
162
libexec/talkd/announce.c
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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.3 (Berkeley) 4/28/95";
|
||||
#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 <vis.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 256
|
||||
|
||||
/*
|
||||
* 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, *vis_user;
|
||||
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++;
|
||||
vis_user = (char *) malloc(strlen(request->l_name) * 4 + 1);
|
||||
strvis(vis_user, request->l_name, VIS_CSTYLE);
|
||||
(void)sprintf(line_buf[i], "talk: connection requested by %s@%s",
|
||||
vis_user, remote_machine);
|
||||
sizes[i] = strlen(line_buf[i]);
|
||||
max_size = max(max_size, sizes[i]);
|
||||
i++;
|
||||
(void)sprintf(line_buf[i], "talk: respond with: talk %s@%s",
|
||||
vis_user, remote_machine);
|
||||
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);
|
||||
}
|
91
libexec/telnetd/authenc.c
Normal file
91
libexec/telnetd/authenc.c
Normal 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.2 (Berkeley) 5/30/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#if defined(AUTHENTICATION) || defined(ENCRYPTION)
|
||||
#include "telnetd.h"
|
||||
#include <libtelnet/misc.h>
|
||||
|
||||
int
|
||||
net_write(str, len)
|
||||
unsigned char *str;
|
||||
int len;
|
||||
{
|
||||
if (nfrontp + len < netobuf + BUFSIZ) {
|
||||
memmove((void *)nfrontp, (void *)str, len);
|
||||
nfrontp += len;
|
||||
return(len);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
net_encrypt()
|
||||
{
|
||||
#ifdef ENCRYPTION
|
||||
char *s = (nclearto > nbackp) ? nclearto : nbackp;
|
||||
if (s < nfrontp && encrypt_output) {
|
||||
(*encrypt_output)((unsigned char *)s, nfrontp - s);
|
||||
}
|
||||
nclearto = nfrontp;
|
||||
#endif /* ENCRYPTION */
|
||||
}
|
||||
|
||||
int
|
||||
telnet_spin()
|
||||
{
|
||||
ttloop();
|
||||
return(0);
|
||||
}
|
||||
|
||||
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) */
|
491
libexec/telnetd/slc.c
Normal file
491
libexec/telnetd/slc.c
Normal file
@ -0,0 +1,491 @@
|
||||
/*
|
||||
* 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.2 (Berkeley) 5/30/95";
|
||||
#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 */
|
||||
memmove(def_slcbuf, ptr, 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 */
|
1612
libexec/telnetd/state.c
Normal file
1612
libexec/telnetd/state.c
Normal file
File diff suppressed because it is too large
Load Diff
2281
libexec/telnetd/sys_term.c
Normal file
2281
libexec/telnetd/sys_term.c
Normal file
File diff suppressed because it is too large
Load Diff
607
libexec/telnetd/telnetd.8
Normal file
607
libexec/telnetd/telnetd.8
Normal file
@ -0,0 +1,607 @@
|
||||
.\" 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.4 (Berkeley) 6/1/94
|
||||
.\"
|
||||
.Dd June 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.
|
||||
.ne 1i
|
||||
.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
|
||||
.ne 1i
|
||||
.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.
|
1608
libexec/telnetd/telnetd.c
Normal file
1608
libexec/telnetd/telnetd.c
Normal file
File diff suppressed because it is too large
Load Diff
660
libexec/telnetd/termstat.c
Normal file
660
libexec/telnetd/termstat.c
Normal 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.2 (Berkeley) 5/30/95";
|
||||
#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;
|
||||
|
||||
memset((char *)&ws, 0, 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 */
|
1192
libexec/telnetd/utility.c
Normal file
1192
libexec/telnetd/utility.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user