summaryrefslogtreecommitdiffstats
path: root/login-utils
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:34 +0100
committerKarel Zak2006-12-07 00:25:34 +0100
commitfd6b7a7ffc50400704beb41d5a23af5f9edb1eed (patch)
tree997c0ca2abc018369babd7da59bcd0afe492068e /login-utils
parentImported from util-linux-2.5 tarball. (diff)
downloadkernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.tar.gz
kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.tar.xz
kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.zip
Imported from util-linux-2.7.1 tarball.
Diffstat (limited to 'login-utils')
-rw-r--r--login-utils/Makefile54
-rw-r--r--login-utils/README.admutil43
-rw-r--r--login-utils/README.modems-with-agetty76
-rw-r--r--login-utils/README.poeigl76
-rw-r--r--login-utils/agetty.8143
-rw-r--r--login-utils/agetty.c239
-rw-r--r--login-utils/checktty.c158
-rw-r--r--login-utils/chfn.c85
-rw-r--r--login-utils/chsh.c101
-rw-r--r--login-utils/cryptocard.c222
-rw-r--r--login-utils/islocal.c19
-rw-r--r--login-utils/last.c136
-rw-r--r--login-utils/login.1160
-rw-r--r--login-utils/login.c1679
-rw-r--r--login-utils/mesg.c6
-rw-r--r--login-utils/newgrp.c1
-rw-r--r--login-utils/passwd.1113
-rw-r--r--login-utils/passwd.c466
-rw-r--r--login-utils/setpwnam.c266
-rw-r--r--login-utils/setpwnam.h38
-rw-r--r--login-utils/shutdown.816
-rw-r--r--login-utils/shutdown.c25
-rw-r--r--login-utils/simpleinit.810
-rw-r--r--login-utils/simpleinit.c35
-rw-r--r--login-utils/ttymsg.c25
-rw-r--r--login-utils/vigr.81
-rw-r--r--login-utils/vipw.824
-rw-r--r--login-utils/vipw.c135
-rw-r--r--login-utils/wall.c18
29 files changed, 2825 insertions, 1545 deletions
diff --git a/login-utils/Makefile b/login-utils/Makefile
index 35c8125a2..9f41fcd19 100644
--- a/login-utils/Makefile
+++ b/login-utils/Makefile
@@ -1,6 +1,6 @@
# Makefile -- Makefile for util-linux Linux utilities
# Created: Sat Dec 26 20:09:40 1992
-# Revised: Thu Oct 12 10:10:32 1995 by r.faith@ieee.org
+# Revised: Sun Nov 10 20:28:43 1996 by faith@cs.unc.edu
# Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu)
#
# Suggested changed from Bauke Jan Douma <bjdouma@xs4all.nl> have been
@@ -19,7 +19,7 @@ MAN8.GETTY= agetty.8
MAN8.INIT= fastboot.8 fasthalt.8 halt.8 reboot.8 simpleinit.8 shutdown.8
-MAN8.PUTILS= vipw.8
+MAN8.PUTILS= vipw.8 vigr.8
# Where to put binaries?
# See the "install" rule for the links. . .
@@ -37,10 +37,21 @@ USRBIN.PASSWD= passwd
USRSBIN.PUTILS= vipw
+ifeq "$(HAVE_LIBCRYPT)" "yes"
+CRYPT=-lcrypt
+endif
+
+ifeq "$(HAVE_PAM)" "yes"
+PAM=-lpam -ldl -lpam_misc
+PAMFL=-DUSE_PAM=1
+endif
+
ifeq "$(HAVE_SHADOW)" "no"
+ifeq "$(HAVE_PAM)" "no"
ifeq "$(HAVE_PASSWD)" "no"
WHAT_TO_BUILD:=$(WHAT_TO_BUILD) all-passwd all-putils
WHAT_TO_INSTALL:=$(WHAT_TO_INSTALL) install-passwd install-putils
+endif
else
WHAT_TO_BUILD:=$(WHAT_TO_BUILD) all-putils
WHAT_TO_INSTALL:=$(WHAT_TO_INSTALL) install-putils
@@ -73,36 +84,52 @@ all-misc: $(USRBIN.MISC)
agetty.o: $(BSD)/pathnames.h
agetty: agetty.o
-chfn: chfn.o setpwnam.o
-chsh: chsh.o setpwnam.o
+chfn: chfn.o islocal.o setpwnam.o
+ $(CC) -o $@ $^ $(CRYPT) $(PAM)
+chsh: chsh.o islocal.o setpwnam.o
+ $(CC) -o $@ $^ $(CRYPT) $(PAM)
+islocal.o: $(BSD)/pathnames.h
last.o: $(BSD)/pathnames.h
last: last.o $(BSD)/getopt.o
-login: login.o checktty.o
+
+ifeq "$(HAVE_PAM)" "yes"
+login: login.o
+ $(CC) -o $@ $^ $(CRYPT) $(PAM)
+else
+login: login.o checktty.o
+ $(CC) -o $@ $^ $(CRYPT)
+endif
+
mesg: mesg.o $(BSD)/getopt.o $(BSD)/err.o
-newgrp.o: $(BSD)/pathnames.h
-newgrp: newgrp.o
+newgrp: newgrp.o
+ $(CC) -o $@ $^ $(CRYPT) $(PAM)
setpwnam.o: $(BSD)/pathnames.h
shutdown.o: $(BSD)/pathnames.h
shutdown: shutdown.o
simpleinit.o: $(BSD)/pathnames.h
-simpleinit: simpleinit.o
+simpleinit: simpleinit.o $(CRYPT)
vipw.o: $(BSD)/pathnames.h
vipw: vipw.o
+
+newgrp.o: $(BSD)/pathnames.h
+ $(CC) -c $(CFLAGS) $(PAMFL) newgrp.c
+
wall: wall.o ttymsg.o
ifeq "$(USE_TTY_GROUP)" "yes"
login.o: login.c $(BSD)/pathnames.h
- $(CC) -c $(CFLAGS) -DUSE_TTY_GROUP login.c
+ $(CC) -c $(CFLAGS) $(PAMFL) -DUSE_TTY_GROUP login.c
mesg.o: mesg.c $(BSD)/err.h
$(CC) -c $(CFLAGS) -DUSE_TTY_GROUP mesg.c
else
login.o: $(BSD)/pathnames.h
+ $(CC) -c $(CFLAGS) $(PAMFL) login.c
mesg.o: $(BSD)/err.h
endif
-passwd: passwd.o islocal.o setpwnam.o
+passwd: passwd.o islocal.o setpwnam.o $(CRYPT)
passwd.o: passwd.c
- $(CC) -c $(CFLAGS) -DUSE_SETPWNAM passwd.c
+ $(CC) -c $(CFLAGS) passwd.c
ifeq "$(REQUIRE_PASSWORD)" "yes"
CHSH_FLAGS:=$(CHSH_FLAGS) -DREQUIRE_PASSWORD
@@ -113,10 +140,10 @@ CHSH_FLAGS:=$(CHSH_FLAGS) -DONLY_LISTED_SHELLS
endif
chsh.o: chsh.c
- $(CC) -c $(CFLAGS) $(CHSH_FLAGS) chsh.c
+ $(CC) -c $(CFLAGS) $(PAMFL) $(CHSH_FLAGS) chsh.c
chfn.o: chfn.c
- $(CC) -c $(CFLAGS) $(CHSH_FLAGS) chfn.c
+ $(CC) -c $(CFLAGS) $(PAMFL) $(CHSH_FLAGS) chfn.c
install: all $(WHAT_TO_INSTALL)
@@ -125,6 +152,7 @@ install-putils: $(BIN.PUTILS) $(USRBIN.PUTILS) $(USRSBIN.PUTILS)
$(INSTALLSUID) $(BIN.PUTILS) $(BINDIR)
$(INSTALLSUID) $(USRBIN.PUTILS) $(USRBINDIR)
$(INSTALLBIN) $(USRSBIN.PUTILS) $(USRSBINDIR)
+ (cd $(USRSBINDIR); ln -sf vipw vigr)
$(INSTALLDIR) $(MAN1DIR) $(MAN8DIR)
$(INSTALLMAN) $(MAN1.PUTILS) $(MAN1DIR)
$(INSTALLMAN) $(MAN8.PUTILS) $(MAN8DIR)
diff --git a/login-utils/README.admutil b/login-utils/README.admutil
index 3e25e84e7..448f99f09 100644
--- a/login-utils/README.admutil
+++ b/login-utils/README.admutil
@@ -1,12 +1,51 @@
-README file for the admutils V1.16 for Linux.
+README file for the admutils V1.23 for Linux.
See installation instructions at the bottom. Currently the latest versions
-of this software is maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/
+of this software are maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/
LICENSE:
This software is distributed as is without any warranty what so ever.
With respect to copyrights it is covered by the GNU Public License.
+Version 1.24 (20-Jun-97)
+ Small patches for glibc compat.
+
+Version 1.23 (6-Jun-97):
+ Patch by Christophe Thaelemans <thaele@chick.vub.ac.be> to last.c,
+ no longer considers all users logged out in case of a run-level
+ change.
+
+Version 1.22 (28-Jan-97):
+ Clean-up release.
+
+Version 1.21c (27-Jan-97):
+ Updated setpwnam.[hc] to be in sync with util-linux 2.6, this
+ also prevents passwd from copying the entire passwd YP/NIS map
+ into the local /etc/passwd. Edited setpwnam.c somewhat to
+ improve error checking, beautify the code, and remove output
+ to stderr.
+ Fixed a couple of buffer overrun nits in passwd.c, patches from
+ David Holland.
+
+Version 1.21b (23-Jan-97):
+ Shutdown now supports a message on the command line, a'la
+ "shutdown -f +5 'for some reason'"
+
+Version 1.20 (2-Nov-96):
+ Fix by Steffen Zahn <zahn@berlin.snafu.de> for shutdown.c so it
+ prints its final message.
+
+Version 1.19 (8-Jul-96):
+ Fix by faith@cs.unc.edu to allow C-A-D after halting in shutdown.c
+
+Version 1.18 (19-Nov-95):
+ passwd almost completely rewritten by Martin Schulze
+ <joey@infodrom.north.de> to use setpwnam() and support
+ more long options. There's a new man-page as well.
+ Hacked some more on Martins passwd.c to support -s and -f options.
+ The old passwd.c is in the Attic/ sub-directory.
+ Bugfix in shutdown.c to fix file modes.
+
Version 1.17 (7-Oct-95):
Added setrlimit() calls to passwd.c and chsh.c to fix security hole
caused by resource limitations. Inspired by Zefram
diff --git a/login-utils/README.modems-with-agetty b/login-utils/README.modems-with-agetty
new file mode 100644
index 000000000..44a611e2a
--- /dev/null
+++ b/login-utils/README.modems-with-agetty
@@ -0,0 +1,76 @@
+25/10/95 Peter Orbaek <poe@daimi.aau.dk>
+
+Some notes for using agetty with modems
+
+Using a comms program to initialize the modem
+---------------------------------------------
+
+* Use kermit or minicom to initialize the modem to
+
+ - be entirely quiet.
+ - don't do local echo in command mode.
+ - turn on DCD (carrier detect) only when there is a connection going.
+ - enable auto-answer.
+ - keep a constant computer/modem bitrate at all times.
+ - optionally save this setup as the modem startup configuration.
+
+* Run agetty on the appropriate ttySn port with the arguments:
+ * -w to wait for a CR or LF before writing the /etc/issue message
+ * computer/modem bitrate
+ * the tty name.
+
+Example from my modem setup, an old 2400 bps SupraModem using Hayes standard
+AT commands.
+
+Initialize modem using kermit with the commands
+
+ AT E0 Q1 &D2 &C1 S0=1 &W0
+
+to
+ - turn off local echo from modem when in command mode (E0).
+ - disable all result codes from modem (Q1).
+ - make an on/off transition on the DTR line make the modem
+ disconnect and go into command mode (&D2).
+ - make the computer/modem DCD line track the modem/modem
+ carrier detect signal, i.e. no connection means no
+ carrier detect signal to the computer (&C1).
+ - enable auto-answer after the first ring (S0=1).
+ - store the configuration as the start configuration (&W0).
+
+The commands on your modem to achieve the same setup may vary, especially
+the &D2 and &C1 commands may not be entirely standard.
+
+Exit kermit/minicom.
+
+Put the command
+
+ /sbin/agetty -w 2400 ttyS1
+
+in the command field of the appropriate line in /etc/inittab to start
+agetty on /dev/ttyS1 with a 2400 bps speed between modem and computer.
+
+Initializing the modem with agetty
+----------------------------------
+
+Use the agetty -I command line option to specify a modem init string, like
+for the same setup as above, use the following agetty command in your
+/etc/inittab.
+
+ /sbin/agetty -w -I 'ATE0Q1&D2&C1S0=1\015' 2400 ttyS1
+
+The final \015 is an octal coding of the carriage return character
+ending the command string.
+
+If you're using simpleinit (part of this package) instead of the SYSV
+compatible init (you're most likely using the SYSV one!) then you must
+remove the single quotes from the command line above.
+
+Note that the &W0 command was not used here since the modem will be
+initialized each time agetty starts.
+
+With a V.34 (28.8 kbps) modem try starting with a command like:
+
+ /sbin/agetty -w -I 'ATE0Q1&D2&C1S0=1\015' 115200 ttyS1
+
+Note that agetty supports the higher (>9600 bps) serial speeds
+directly, there's no need to use setserial to use the higher speeds.
diff --git a/login-utils/README.poeigl b/login-utils/README.poeigl
index 5b6fac3f4..5d30ec581 100644
--- a/login-utils/README.poeigl
+++ b/login-utils/README.poeigl
@@ -15,7 +15,81 @@ is different.
If you are uncertain whether you got the latest version, check out
- ftp://ftp.daimi.aau.dk:/pub/linux/poe/
+ ftp://ftp.daimi.aau.dk/pub/linux/poe/
+
+Version 1.49 (20-Jun-97)
+ Small patches for new util-linux distribution and glibc compat.
+ PAM support in login.c by Erik Troan.
+
+Version 1.48 (6-Jun-97)
+ Now changes mode and owner of /dev/vcs devices for console logins.
+ After idea by Andries Brouwer.
+
+Version 1.47 (2-Apr-97)
+ Got new version of hostid.c and hostid.1 from
+ Sander van Malssen <svm@kozmix.ow.nl>.
+ Removed premature endutent() call in login.c, simpleinit.c and
+ agetty.c to be compatible with the changed semantics of gnu libc2.
+ Fix by Jesse Thilo <Jesse.Thilo@pobox.com>.
+
+Version 1.46 (28-Jan-97)
+ Several security fixes for login by David Holland (buffer overruns)
+ <dholland@hcs.harvard.edu>
+ Fixed write.c, to handle a terminating period correctly.
+ Re-indented login.c, it was getting too messy.
+
+Version 1.45a (16-Dec-96)
+ Better support in login for shadow passwords. Compile with
+ -DSHADOW_PWD if you have <shadow.h>. This is on by default.
+ By Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>.
+ Changed the wtmp locking scheme in login.c,agetty.c,simpleinit.c
+ to flock() /etc/wtmplock instead of the wtmp file directly.
+ This avoids a denial of service attack.
+ Some support for the RB-1 Cryptocard token for challenge/response
+ authentication. This needs a DES library, either Eric Young's
+ libdes, or the Koontz implementation, see cryptocard.c.
+ Initial support patch by Randolph Bentson,
+ <bentson@grieg.seaslug.org>
+ Changed getpass() to use fputs() instead of fprintf().
+
+Version 1.44 (13-Nov-96):
+ Made isapty() in checktty.c more resilient to 2.0 systems
+ that haven't re-MAKEDEV'ed their pty devices.
+
+Version 1.43 (8-Nov-96):
+ Fix to checktty.c: PTY's are numbered differently after 1.3,
+ blush! Fix by Gerhard Schneider <gs@ilfb.tuwien.ac.at>
+
+Version 1.42c (6-Nov-96):
+ Small fix by Gabriel M. Schuyler <schuyler@easiest.com>, to get
+ better syslog messages (1 LOGIN FAILURE instead of 2 LOGIN FAILURES).
+ Patch butchered by me.
+
+Version 1.42b (30-Sep-96):
+ Got patch for checktty.c from Christoph Lameter
+ <clameter@miriam.fuller.edu> so it doesn't traverse the groupfile
+ "manually" but uses the getgroups() call, this is more efficient
+ with large groupfiles and NIS/YP.
+
+Version 1.42a (24-Sep-96):
+ Added extra syslog() call to login.c to log all good logins.
+ Patch from Steve Philp.
+
+Version 1.41 (20-Jul-96):
+ Added security fix to checktty.c by JDS to clear certain lists.
+ Patches butchered and ANSI'fied by me.
+ Added -n option to agetty to avoid the login prompt.
+
+Version 1.40a (29-Dec-95):
+ Added -f <issue_file> option to agetty. Patches from Eric Rasmussen
+ <ear@usfirst.org>, but somewhat butchered by me.
+
+Version 1.39 (25-Oct-95):
+ Lots of testing and bugfixes in agetty. Now the modem init stuff
+ should finally work (for me). Also wrote modem.agetty as an example
+ on how to use agetty with a modem.
+ Agetty now also supports baud rates of 38400, 57600, 115200 and
+ 230400 bps.
Version 1.37 (15-Sep-95):
Added -I <initstring> and -w options to agetty.c for those that
diff --git a/login-utils/agetty.8 b/login-utils/agetty.8
index f6a59909c..ebbc27588 100644
--- a/login-utils/agetty.8
+++ b/login-utils/agetty.8
@@ -1,20 +1,33 @@
.TH AGETTY 8
-.ad
-.fi
.SH NAME
agetty \- alternative Linux getty
+
.SH SYNOPSIS
-.na
-.nf
-agetty [-ihLmw] [-l login_program] [-I init] [-t timeout] port baud_rate,... [term]
-agetty [-ihLmw] [-l login_program] [-I init] [-t timeout] baud_rate,... port [term]
+.BR "agetty " [\-ihLmnw]
+.RI "[-f " issue_file ]
+.RI "[-l " login_program ]
+.RI "[-I " init ]
+.RI "[-t " timeout ]
+.I port
+.I baud_rate,...
+.RI [ term ]
+.br
+.BR "agetty " [\-ihLmnw]
+.RI "[-f " issue_file ]
+.RI "[-l " login_program ]
+.RI "[-I " init ]
+.RI "[-t " timeout ]
+.I baud_rate,...
+.I port
+.RI [ term ]
+
.SH DESCRIPTION
.ad
.fi
-\fIagetty\fP opens a tty port, prompts for a login name and invokes
+\fBagetty\fP opens a tty port, prompts for a login name and invokes
the /bin/login command. It is normally invoked by \fIinit(8)\fP.
-\fIagetty\fP has several \fInon-standard\fP features that are useful
+\fBagetty\fP has several \fInon-standard\fP features that are useful
for hard-wired and for dial-in lines:
.IP o
Adapts the tty settings to parity bits and to erase, kill,
@@ -30,8 +43,11 @@ Hayes(tm)-compatible modems.
Optionally does not hang up when it is given an already opened line
(useful for call-back applications).
.IP o
-Optionally does not display the contents of the \fI/etc/issue\fP file
-(System V only).
+Optionally does not display the contents of the \fI/etc/issue\fP file.
+.IP o
+Optionally displays an alternative issue file instead of \fI/etc/issue\fP.
+.IP o
+Optionally does not ask for a login name.
.IP o
Optionally invokes a non-standard login program instead of
\fI/bin/login\fP.
@@ -50,7 +66,7 @@ This program does not use the \fI/etc/gettydefs\fP (System V) or
.TP
port
A path name relative to the \fI/dev\fP directory. If a "-" is
-specified, \fIagetty\fP assumes that its standard input is
+specified, \fBagetty\fP assumes that its standard input is
already connected to a tty port and that a connection to a
remote user has already been established.
.sp
@@ -59,7 +75,7 @@ by a "--".
.TP
baud_rate,...
A comma-separated list of one or more baud rates. Each time
-\fIagetty\fP receives a BREAK character it advances through
+\fBagetty\fP receives a BREAK character it advances through
the list, which is treated as if it were circular.
.sp
Baud rates should be specified in descending order, so that the
@@ -74,18 +90,23 @@ whatever init(8) may have set, and is inherited by login and the shell.
.fi
.ad
.TP
--h
+\-h
Enable hardware (RTS/CTS) flow control. It is left up to the
application to disable software (XON/XOFF) flow protocol where
appropriate.
.TP
--i
-Do not display the contents of \fI/etc/issue\fP before writing the
+\-i
+Do not display the contents of \fI/etc/issue\fP (or other) before writing the
login prompt. Terminals or communications hardware may become confused
when receiving lots of text at the wrong baud rate; dial-up scripts
may fail if the login prompt is preceded by too much text.
.TP
--I initstring
+\-f \fIissue_file\fP
+Display the contents of \fIissue_file\fP instead of \fI/etc/issue\fP.
+This allows custom messages to be displayed on different terminals.
+The \-i option will override this option.
+.TP
+\-I \fIinitstring\fP
Set an initial string to be sent to the tty or modem before sending
anything else. This may be used to initialize a modem. Non printable
characters may be sent by writing their octal code preceded by a
@@ -93,59 +114,80 @@ backslash (\\). For example to send a linefeed character (ASCII 10,
octal 012) write \\012.
.PP
.TP
--l login_program
+\-l \fIlogin_program\fP
Invoke the specified \fIlogin_program\fP instead of /bin/login.
This allows the use of a non-standard login program (for example,
one that asks for a dial-up password or that uses a different
password file).
.TP
--m
-Try to extract the baud rate the \fIconnect\fP status message
-produced by some Hayes(tm)-compatible modems. These status
+\-m
+Try to extract the baud rate the CONNECT status message
+produced by Hayes(tm)\-compatible modems. These status
messages are of the form: "<junk><speed><junk>".
-\fIagetty\fP assumes that the modem emits its status message at
+\fBagetty\fP assumes that the modem emits its status message at
the same speed as specified with (the first) \fIbaud_rate\fP value
on the command line.
.sp
-Since the \fI-m\fP feature may fail on heavily-loaded systems,
+Since the \fI\-m\fP feature may fail on heavily-loaded systems,
you still should enable BREAK processing by enumerating all
expected baud rates on the command line.
+.TP
+\-n
+Do not prompt the user for a login name. This can be used in
+connection with \-l option to invoke a non-standard login process such
+as a BBS system. Note that with the \-n option, \fBagetty\fR gets no input from
+user who logs in and therefore won't be able to figure out parity,
+character size, and newline processing of the connection. It defaults to
+space parity, 7 bit characters, and ASCII CR (13) end-of-line character.
+Beware that the program that \fBagetty\fR starts (usually /bin/login)
+is run as root.
.TP
--t timeout
+\-t \fItimeout\fP
Terminate if no user name could be read within \fItimeout\fP
seconds. This option should probably not be used with hard-wired
lines.
.TP
--L
-Force the line to be local line with no need for carrier detect. This can
-be useful when you have locally attached terminal where the serial line
+\-L
+Force the line to be a local line with no need for carrier detect. This can
+be useful when you have a locally attached terminal where the serial line
does not set the carrier detect signal.
.TP
--w
-Wait for the user or the modem to send a carriage-return or a linefeed
-character before sending the /etc/issue file and the login prompt.
+\-w
+Wait for the user or the modem to send a carriage-return or a
+linefeed character before sending the \fI/etc/issue\fP (or other) file
+and the login prompt. Very useful in connection with the \-I option.
.PP
.SH EXAMPLES
.na
.nf
-This section shows sample entries for the \fI/etc/inittab\fP file.
+This section shows sample command entries for the \fI/etc/inittab\fP file.
+
+For a hard-wired line or a console tty:
+.ti +5
+/sbin/agetty 9600 ttyS1
-For a hard-wired line:
+For a directly connected terminal without proper carriage detect wiring:
+(try this if your terminal just sleeps instead of giving you a password:
+prompt.)
.ti +5
-tty1:con80x60:/sbin/agetty 9600 tty1
+/sbin/agetty \-L 9600 ttyS1 vt100
-For a dial-in line with a 9600/2400/1200 baud modem:
+For a old style dial-in line with a 9600/2400/1200 baud modem:
.ti +5
-ttyS1:dumb:/sbin/agetty -mt60 ttyS1 9600,2400,1200
+/sbin/agetty \-mt60 ttyS1 9600,2400,1200
-These examples assume you use the simpleinit(8) init program for Linux.
-If you use a SysV like init (does /etc/inittab mention "respawn"?), refer
-to the appropriate manual page.
+For a Hayes modem with a fixed 115200 bps interface to the machine:
+(the example init string turns off modem echo and result codes, makes
+modem/computer DCD track modem/modem DCD, makes a DTR drop cause a
+dis-connection and turn on auto-answer after 1 ring.)
+.ti +5
+/sbin/agetty \-w \-I 'ATE0Q1&D2&C1S0=1\\015' 115200 ttyS1
.SH ISSUE ESCAPES
-The \fI/etc/issue\fP file may contain certain escape codes to display the
-system name, date and time etc. All escape codes consist of a backslash
-(\\) immediately followed by one of the letters explained below.
+The issue-file (\fI/etc/issue\fP or the file set with the \-f option)
+may contain certain escape codes to display the system name, date and
+time etc. All escape codes consist of a backslash (\\) immediately
+followed by one of the letters explained below.
.TP
b
@@ -203,19 +245,19 @@ This is thingol.orcan.dk (Linux i386 1.1.9) 18:29:30
.na
.nf
/var/run/utmp, the system status file.
-/etc/issue, printed before the login prompt (System V only).
+/etc/issue, printed before the login prompt.
/dev/console, problem reports (if syslog(3) is not used).
-/etc/inittab (Linux simpleinit(8) configuration file).
+/etc/inittab, \fIinit\fP(8) configuration file.
.SH BUGS
.ad
.fi
The baud-rate detection feature (the \fI-m\fP option) requires that
-\fIagetty\fP be scheduled soon enough after completion of a dial-in
+\fBagetty\fP be scheduled soon enough after completion of a dial-in
call (within 30 ms with modems that talk at 2400 baud). For robustness,
-always use the \fI-m\fP option in combination with a multiple baud
+always use the \fI\-m\fP option in combination with a multiple baud
rate command-line argument, so that BREAK processing is enabled.
-The text in the /etc/issue file and the login prompt
+The text in the \fI/etc/issue\fP file (or other) and the login prompt
are always output with 7-bit characters and space parity.
The baud-rate detection feature (the \fI-m\fP option) requires that
@@ -237,7 +279,10 @@ Department of Mathematics and Computer Science
Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
Peter Orbaek <poe@daimi.aau.dk>
-Linux port.
+Linux port and more options. Still maintains the code.
+
+Eric Rasmussen <ear@usfirst.org>
+Added \-f option to display custom login messages on different terminals.
.SH CREATION DATE
.na
@@ -246,8 +291,4 @@ Sat Nov 25 22:51:05 MET 1989
.SH LAST MODIFICATION
.na
.nf
-91/09/01 23:22:00
-.SH VERSION/RELEASE
-.na
-.nf
-1.29
+96/07/20
diff --git a/login-utils/agetty.c b/login-utils/agetty.c
index c7595bf37..ba28336b6 100644
--- a/login-utils/agetty.c
+++ b/login-utils/agetty.c
@@ -2,6 +2,8 @@
Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
This program is freely distributable. The entire man-page used to
be here. Now read the real man-page agetty.8 instead.
+
+ -f option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
*/
#ifndef lint
@@ -25,7 +27,7 @@ char sccsid[] = "@(#) agetty.c 1.29 9/1/91 23:22:00";
#include <memory.h>
#include <sys/file.h>
-#ifdef linux
+#ifdef __linux__
#include "pathnames.h"
#include <sys/param.h>
#define USE_SYSLOG
@@ -111,8 +113,9 @@ extern void closelog();
* executable small on systems that do not have shared libraries (System V
* Release <3).
*/
-
+#ifndef BUFSIZ
#define BUFSIZ 1024
+#endif
/*
* When multiple baud rates are specified on the command line, the first one
@@ -129,10 +132,11 @@ struct options {
int flags; /* toggle switches, see below */
int timeout; /* time-out period */
char *login; /* login program */
- int numspeed; /* number of baud rates to try */
- int speeds[MAX_SPEED]; /* baud rates to be tried */
char *tty; /* name of tty */
char *initstring; /* modem init string */
+ char *issue; /* alternative issue file */
+ int numspeed; /* number of baud rates to try */
+ int speeds[MAX_SPEED]; /* baud rates to be tried */
};
#define F_PARSE (1<<0) /* process modem status messages */
@@ -141,6 +145,8 @@ struct options {
#define F_LOCAL (1<<3) /* force local */
#define F_INITSTRING (1<<4) /* initstring is set */
#define F_WAITCRLF (1<<5) /* wait for CR or LF */
+#define F_CUSTISSUE (1<<6) /* give alternative issue file */
+#define F_NOPROMPT (1<<7) /* don't ask for login name! */
/* Storage for things detected while the login name was read. */
@@ -157,9 +163,52 @@ struct chardata {
struct chardata init_chardata = {
DEF_ERASE, /* default erase character */
DEF_KILL, /* default kill character */
- 0, /* always filled in at runtime */
+ 13, /* default eol char */
0, /* space parity */
- 0, /* always filled in at runtime */
+ 0, /* no capslock */
+};
+
+struct Speedtab {
+ long speed;
+ int code;
+};
+
+static struct Speedtab speedtab[] = {
+ { 50, B50 },
+ { 75, B75 },
+ { 110, B110 },
+ { 134, B134 },
+ { 150, B150 },
+ { 200, B200 },
+ { 300, B300 },
+ { 600, B600 },
+ { 1200, B1200 },
+ { 1800, B1800 },
+ { 2400, B2400 },
+ { 4800, B4800 },
+ { 9600, B9600 },
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef EXTA
+ { 19200, EXTA },
+#endif
+#ifdef EXTB
+ { 38400, EXTB },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+#ifdef B230400
+ { 230400, B230400 },
+#endif
+ { 0, 0 },
};
#define P_(s) ()
@@ -196,13 +245,16 @@ main(argc, argv)
int argc;
char **argv;
{
- char *logname; /* login name, given to /bin/login */
+ char *logname = NULL; /* login name, given to /bin/login */
struct chardata chardata; /* set by get_logname() */
struct termio termio; /* terminal mode bits */
static struct options options = {
F_ISSUE, /* show /etc/issue (SYSV_STYLE) */
0, /* no timeout */
_PATH_LOGIN, /* default login program */
+ "tty1", /* default tty line */
+ "", /* modem init string */
+ ISSUE, /* default issue file */
0, /* no baud rates known yet */
};
@@ -215,7 +267,7 @@ main(argc, argv)
#endif
#ifdef DEBUGGING
- dbf = fopen("/dev/tty1", "w");
+ dbf = fopen("/dev/ttyp0", "w");
{ int i;
@@ -229,7 +281,7 @@ main(argc, argv)
parse_args(argc, argv, &options);
-#ifdef linux
+#ifdef __linux__
setsid();
#endif
@@ -239,10 +291,11 @@ main(argc, argv)
update_utmp(options.tty);
#endif
+ debug("calling open_tty\n");
/* Open the tty as standard { input, output, error }. */
open_tty(options.tty, &termio, options.flags & F_LOCAL);
-#ifdef linux
+#ifdef __linux__
{
int iv;
@@ -251,39 +304,50 @@ main(argc, argv)
}
#endif
/* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */
-
+ debug("calling termio_init\n");
termio_init(&termio, options.speeds[FIRST_SPEED], options.flags & F_LOCAL);
- /* write the modem init string and flush the buffers */
+ /* write the modem init string and DON'T flush the buffers */
if (options.flags & F_INITSTRING) {
+ debug("writing init string\n");
write(1, options.initstring, strlen(options.initstring));
- ioctl(1, TCFLSH, 2);
}
- /* Optionally detect the baud rate from the modem status message. */
+ if (!(options.flags & F_LOCAL)) {
+ /* go to blocking write mode unless -L is specified */
+ fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK);
+ }
+ /* Optionally detect the baud rate from the modem status message. */
+ debug("before autobaud\n");
if (options.flags & F_PARSE)
auto_baud(&termio);
/* Set the optional timer. */
-
if (options.timeout)
(void) alarm((unsigned) options.timeout);
-
+
/* optionally wait for CR or LF before writing /etc/issue */
if (options.flags & F_WAITCRLF) {
char ch;
+ debug("waiting for cr-lf\n");
while(read(0, &ch, 1) == 1) {
ch &= 0x7f; /* strip "parity bit" */
+#ifdef DEBUGGING
+ fprintf(dbf, "read %c\n", ch);
+#endif
if (ch == '\n' || ch == '\r') break;
}
}
- /* Read the login name. */
-
- while ((logname = get_logname(&options, &chardata, &termio)) == 0)
- next_speed(&termio, &options);
+ chardata = init_chardata;
+ if (!(options.flags & F_NOPROMPT)) {
+ /* Read the login name. */
+ debug("reading login name\n");
+ while ((logname = get_logname(&options, &chardata, &termio)) == 0)
+ next_speed(&termio, &options);
+ }
/* Disable timer. */
@@ -317,7 +381,7 @@ parse_args(argc, argv, op)
extern int optind; /* getopt */
int c;
- while (isascii(c = getopt(argc, argv, "I:Lhil:mt:w"))) {
+ while (isascii(c = getopt(argc, argv, "I:Lf:hil:mt:wn"))) {
switch (c) {
case 'I':
if (!(op->initstring = malloc(strlen(optarg)))) {
@@ -362,6 +426,10 @@ parse_args(argc, argv, op)
case 'L': /* force local */
op->flags |= F_LOCAL;
break;
+ case 'f': /* custom issue file */
+ op->flags |= F_CUSTISSUE;
+ op->issue = optarg;
+ break;
case 'h': /* enable h/w flow control */
op->flags |= F_RTSCTS;
break;
@@ -374,6 +442,9 @@ parse_args(argc, argv, op)
case 'm': /* parse modem status message */
op->flags |= F_PARSE;
break;
+ case 'n':
+ op->flags |= F_NOPROMPT;
+ break;
case 't': /* time out */
if ((op->timeout = atoi(optarg)) <= 0)
error("bad timeout value: %s", optarg);
@@ -433,8 +504,8 @@ void
update_utmp(line)
char *line;
{
- struct utmp ut;
- long ut_size = sizeof(ut); /* avoid nonsense */
+ struct utmp ut;
+ time_t t;
int ut_fd;
int mypid = getpid();
long time();
@@ -451,7 +522,7 @@ update_utmp(line)
* entry in the utmp file.
*/
-#ifdef linux
+#ifdef __linux__
utmpname(_PATH_UTMP);
setutent();
while ((utp = getutent())
@@ -465,27 +536,37 @@ update_utmp(line)
memset(&ut, 0, sizeof(ut));
strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
}
- endutent();
+ /*endutent();*/
strncpy(ut.ut_user, "LOGIN", sizeof(ut.ut_user));
strncpy(ut.ut_line, line, sizeof(ut.ut_line));
- time(&ut.ut_time);
+ time(&t);
+ ut.ut_time = t;
ut.ut_type = LOGIN_PROCESS;
ut.ut_pid = mypid;
pututline(&ut);
endutent();
- if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
- flock(ut_fd, LOCK_EX);
- write(ut_fd, &ut, sizeof(ut));
- flock(ut_fd, LOCK_UN);
- close(ut_fd);
+ {
+ int lf;
+
+ if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
+ flock(lf, LOCK_EX);
+ if ((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
+ write(ut_fd, &ut, sizeof(ut));
+ close(ut_fd);
+ }
+ flock(lf, LOCK_UN);
+ close(lf);
+ }
}
#else
if ((ut_fd = open(UTMP_FILE, 2)) < 0) {
error("%s: open for update: %m", UTMP_FILE);
} else {
+ long ut_size = sizeof(ut); /* avoid nonsense */
+
while (read(ut_fd, (char *) &ut, sizeof(ut)) == sizeof(ut)) {
if (ut.ut_type == INIT_PROCESS && ut.ut_pid == mypid) {
ut.ut_type = LOGIN_PROCESS;
@@ -500,7 +581,7 @@ update_utmp(line)
}
error("%s: no utmp entry", line);
}
-#endif /* linux */
+#endif /* __linux__ */
}
#endif
@@ -537,7 +618,8 @@ open_tty(tty, tp, local)
(void) close(0);
errno = 0; /* ignore close(2) errors */
- if (open(tty, (local ? O_RDWR|O_NONBLOCK : O_RDWR), 0) != 0)
+ debug("open(2)\n");
+ if (open(tty, O_RDWR|O_NONBLOCK, 0) != 0)
error("/dev/%s: cannot open as standard input: %m", tty);
} else {
@@ -552,7 +634,7 @@ open_tty(tty, tp, local)
}
/* Set up standard output and standard error file descriptors. */
-
+ debug("duping\n");
if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */
error("%s: dup problem: %m", tty); /* we have a problem */
@@ -598,9 +680,9 @@ termio_init(tp, speed, local)
* reads will be done in raw mode anyway. Errors will be dealt with
* lateron.
*/
-#ifdef linux
- /* flush input and output queues, important for modems! */
- (void) ioctl(0, TCFLSH, 2);
+#ifdef __linux__
+ /* flush input and output queues, important for modems! */
+ (void) ioctl(0, TCFLSH, TCIOFLUSH);
#endif
tp->c_cflag = CS8 | HUPCL | CREAD | speed;
@@ -612,9 +694,10 @@ termio_init(tp, speed, local)
tp->c_cc[VMIN] = 1;
tp->c_cc[VTIME] = 0;
(void) ioctl(0, TCSETA, tp);
- if (local) {
- (void) fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NDELAY);
- }
+
+ /* go to blocking input even in local mode */
+ fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK);
+
debug("term_io 2\n");
}
@@ -698,7 +781,7 @@ do_prompt(op, tp)
(void) write(1, "\r\n", 2); /* start a new line */
#ifdef ISSUE /* optional: show /etc/issue */
- if ((op->flags & F_ISSUE) && (fd = fopen(ISSUE, "r"))) {
+ if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) {
oflag = tp->c_oflag; /* save current setting */
tp->c_oflag |= (ONLCR | OPOST); /* map NL in output to CR-NL */
(void) ioctl(0, TCSETAW, tp);
@@ -733,8 +816,14 @@ do_prompt(op, tp)
break;
case 'o':
- (void) printf ("%s", uts.domainname);
- break;
+ {
+ char domainname[256];
+
+ getdomainname(domainname, sizeof(domainname));
+ domainname[sizeof(domainname)-1] = '\0';
+ printf ("%s", domainname);
+ }
+ break;
case 'd':
case 't':
@@ -769,13 +858,15 @@ do_prompt(op, tp)
case 'b':
{
- char *zpeedz[] = { "0", "50", "75", "110", "134.5",
- "150", "200", "300", "600", "1200",
- "1800", "2400", "4800", "9600",
- "19200", "38400" };
+ int i;
- (void) printf ("%s", zpeedz[tp->c_cflag & CBAUD]);
- break;
+ for (i = 0; speedtab[i].speed; i++) {
+ if (speedtab[i].code == (tp->c_cflag & CBAUD)) {
+ printf("%ld", speedtab[i].speed);
+ break;
+ }
+ }
+ break;
}
case 'u':
case 'U':
@@ -806,7 +897,7 @@ do_prompt(op, tp)
(void) fclose(fd);
}
#endif
-#ifdef linux
+#ifdef __linux__
{
char hn[MAXHOSTNAMELEN+1];
@@ -858,7 +949,7 @@ char *get_logname(op, cp, tp)
/* Flush pending input (esp. after parsing or switching the baud rate). */
(void) sleep(1);
- (void) ioctl(0, TCFLSH, (struct termio *) 0);
+ (void) ioctl(0, TCFLSH, TCIFLUSH);
/* Prompt for and read a login name. */
@@ -960,7 +1051,7 @@ termio_final(op, tp, cp)
tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */
tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */
tp->c_cc[VEOL] = DEF_EOL;
-#ifdef linux
+#ifdef __linux__
tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */
#else
tp->c_cc[VSWTCH] = DEF_SWITCH; /* default switch character */
@@ -1033,38 +1124,6 @@ int
bcode(s)
char *s;
{
- struct Speedtab {
- long speed;
- int code;
- };
- static struct Speedtab speedtab[] = {
- 50, B50,
- 75, B75,
- 110, B110,
- 134, B134,
- 150, B150,
- 200, B200,
- 300, B300,
- 600, B600,
- 1200, B1200,
- 1800, B1800,
- 2400, B2400,
- 4800, B4800,
- 9600, B9600,
-#ifdef B19200
- 19200, B19200,
-#endif
-#ifdef B38400
- 38400, B38400,
-#endif
-#ifdef EXTA
- 19200, EXTA,
-#endif
-#ifdef EXTB
- 38400, EXTB,
-#endif
- 0, 0,
- };
struct Speedtab *sp;
long speed = atol(s);
@@ -1079,15 +1138,11 @@ bcode(s)
void
usage()
{
-#if defined(SYSV_STYLE) && !defined(linux)
static char msg[] =
- "[-i] [-l login_program] [-m] [-t timeout] line baud_rate,...";
-#else
- static char msg[] =
- "[-h] [-l login_program] [-m] [-t timeout] baud_rate,... line";
-#endif
+ "[-hiLmw] [-l login_program] [-t timeout] [-I initstring] baud_rate,... line [termtype]\nor\t[-hiLmw] [-l login_program] [-t timeout] [-I initstring] line baud_rate,... [termtype]";
- error("usage: %s %s", progname, msg);
+ fprintf(stderr, "Usage: %s %s\n", progname, msg);
+ exit(1);
}
/* error - report errors to console or syslog; only understands %s and %m */
@@ -1157,7 +1212,7 @@ error(va_alist)
*/
#ifdef USE_SYSLOG
- (void) openlog(progname, LOG_PID, LOG_AUTH);
+ (void) openlog(progname, LOG_PID, LOG_AUTHPRIV);
(void) syslog(LOG_ERR, "%s", buf);
closelog();
#else
diff --git a/login-utils/checktty.c b/login-utils/checktty.c
index 8daa17204..e5d03815a 100644
--- a/login-utils/checktty.c
+++ b/login-utils/checktty.c
@@ -1,7 +1,13 @@
/* checktty.c - linked into login, checks user against /etc/usertty
Created 25-Aug-95 by Peter Orbaek <poe@daimi.aau.dk>
+ Fixed by JDS June 1996 to clear lists and close files
*/
+#define _GNU_SOURCE /* for snprintf */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
#include <pwd.h>
#include <grp.h>
#include <string.h>
@@ -14,7 +20,7 @@
#include <netdb.h>
#include <sys/syslog.h>
-#ifdef linux
+#ifdef __linux__
# include <sys/sysmacros.h>
# include <linux/major.h>
#endif
@@ -22,7 +28,7 @@
#include "pathnames.h"
/* functions in login.c */
-void badlogin(char *s);
+void badlogin(const char *s);
void sleepexit(int);
extern struct hostent hostaddress;
extern char *hostname;
@@ -32,7 +38,7 @@ struct hostent hostaddress;
char *hostname;
void
-badlogin(char *s)
+badlogin(const char *s)
{
printf("badlogin: %s\n", s);
}
@@ -45,6 +51,9 @@ sleepexit(int x)
}
#endif
+static gid_t mygroups[NGROUPS];
+static int num_groups;
+
#define NAMELEN 128
/* linked list of names */
@@ -52,9 +61,7 @@ struct grplist {
struct grplist *next;
char name[NAMELEN];
};
-
-struct grplist *mygroups = NULL;
-
+
enum State { StateUsers, StateGroups, StateClasses };
#define CLASSNAMELEN 32
@@ -67,57 +74,25 @@ struct ttyclass {
struct ttyclass *ttyclasses = NULL;
-static void
-add_group(char *group)
-{
- struct grplist *ge;
-
- ge = (struct grplist *)malloc(sizeof(struct grplist));
-
- /* we can't just bail out at this stage! */
- if (!ge) {
- printf("login: memory low, login may fail\n");
- syslog(LOG_WARNING, "can't malloc grplist");
- return;
- }
-
- ge->next = mygroups;
- strncpy(ge->name, group, NAMELEN);
- mygroups = ge;
-}
-
static int
am_in_group(char *group)
{
- struct grplist *ge;
-
- for (ge = mygroups; ge; ge = ge->next) {
- if (strcmp(ge->name, group) == 0) return 1;
- }
- return 0;
+ struct group *g;
+ gid_t *ge;
+
+ g = getgrnam(group);
+ if (g) {
+ for (ge = mygroups; ge < mygroups + num_groups; ge++) {
+ if (g->gr_gid== *ge) return 1;
+ }
+ }
+ return 0;
}
static void
-find_groups(gid_t defgrp, char *user)
+find_groups(gid_t defgrp, const char *user)
{
- struct group *gp;
- char **p;
-
- setgrent();
- while ((gp = getgrent())) {
- if (gp->gr_gid == defgrp) {
- add_group(gp->gr_name);
- } else {
- for(p = gp->gr_mem; *p; p++) {
- if (strcmp(user, *p) == 0) {
- add_group(gp->gr_name);
- break;
- }
- }
- }
-
- }
- endgrent();
+ num_groups = getgroups(NGROUPS, mygroups);
}
static struct ttyclass *
@@ -135,6 +110,7 @@ new_class(char *class)
tc->next = ttyclasses;
tc->first = NULL;
strncpy(tc->classname, class, CLASSNAMELEN);
+ tc->classname[CLASSNAMELEN-1] = 0;
ttyclasses = tc;
return tc;
}
@@ -155,21 +131,30 @@ add_to_class(struct ttyclass *tc, char *tty)
ge->next = tc->first;
strncpy(ge->name, tty, NAMELEN);
+ ge->name[NAMELEN-1] = 0;
tc->first = ge;
}
/* return true if tty is a pty. Very linux dependent */
static int
-isapty(tty)
- char *tty;
+isapty(const char *tty)
{
char devname[100];
struct stat stb;
-#ifdef linux
- strcpy(devname, "/dev/");
- strncat(devname, tty, 80);
+ snprintf(devname, sizeof(devname), "/dev/%s", tty);
+
+#if defined(__linux__) && defined(PTY_SLAVE_MAJOR)
+ /* this is for linux 1.3 and newer */
+ if((stat(devname, &stb) >= 0)
+ && major(stb.st_rdev) == PTY_SLAVE_MAJOR) {
+ return 1;
+ }
+#endif
+
+#if defined(__linux__)
+ /* this is for linux versions before 1.3, backward compat. */
if((stat(devname, &stb) >= 0)
&& major(stb.st_rdev) == TTY_MAJOR
&& minor(stb.st_rdev) >= 192) {
@@ -181,9 +166,7 @@ isapty(tty)
/* match the hostname hn against the pattern pat */
static int
-hnmatch(hn, pat)
- char *hn;
- char *pat;
+hnmatch(const char *hn, const char *pat)
{
int x1, x2, x3, x4, y1, y2, y3, y4;
unsigned long p, mask, a;
@@ -260,7 +243,7 @@ timeok(struct tm *t, char *spec)
Also return true if hostname matches the hostname pattern, class
or a pattern in the class named by class. */
static int
-in_class(char *tty, char *class)
+in_class(const char *tty, char *class)
{
struct ttyclass *tc;
struct grplist *ge;
@@ -276,7 +259,8 @@ in_class(char *tty, char *class)
if (class[0] == '[') {
if ((p = strchr(class, ']'))) {
*p = 0;
- strcpy(timespec, class+1);
+ strncpy(timespec, class+1, sizeof(timespec));
+ timespec[sizeof(timespec)-1] = 0;
*p = ']';
if(!timeok(tm, timespec)) return 0;
class = p+1;
@@ -297,7 +281,8 @@ in_class(char *tty, char *class)
if (n[0] == '[') {
if ((p = strchr(n, ']'))) {
*p = 0;
- strcpy(timespec, n+1);
+ strncpy(timespec, n+1, sizeof(timespec));
+ timespec[sizeof(timespec)-1] = 0;
*p = ']';
if(!timeok(tm, timespec)) continue;
n = p+1;
@@ -316,11 +301,41 @@ in_class(char *tty, char *class)
return 0;
}
+/* start JDS - SBA */
+void
+free_group(struct grplist *ge)
+{
+ if (ge) {
+ memset(ge->name, 0, NAMELEN);
+ free_group(ge->next);
+ free(ge->next);
+ ge->next = NULL;
+ }
+}
+
+void
+free_class(struct ttyclass *tc)
+{
+ if (tc) {
+ memset(tc->classname, 0, CLASSNAMELEN);
+ free_group(tc->first);
+ tc->first = NULL;
+ free_class(tc->next);
+ free(tc->next);
+ tc->next = NULL;
+ }
+}
+
+void
+free_all(void)
+{
+ free_class(ttyclasses);
+ ttyclasses = NULL;
+}
+/* end JDS - SBA */
+
void
-checktty(user, tty, pwd)
- char *user;
- char *tty;
- struct passwd *pwd;
+checktty(const char *user, const char *tty, struct passwd *pwd)
{
FILE *f;
char buf[256], defaultbuf[256];
@@ -335,7 +350,10 @@ checktty(user, tty, pwd)
if (!(f = fopen(_PATH_USERTTY, "r"))) return;
#endif
- if (pwd == NULL) return; /* misspelled username handled elsewhere */
+ if (pwd == NULL) {
+ fclose(f);
+ return; /* misspelled username handled elsewhere */
+ }
find_groups(pwd->pw_gid, user);
@@ -348,6 +366,7 @@ checktty(user, tty, pwd)
if (buf[0] == '*') {
strncpy(defaultbuf, buf, 256);
+ defaultbuf[255] = 0;
continue;
}
@@ -369,6 +388,7 @@ checktty(user, tty, pwd)
while((ptr = strtok(NULL, "\t\n "))) {
if (in_class(tty, ptr)) {
fclose(f);
+ free_all(); /* JDS */
return;
}
}
@@ -388,7 +408,10 @@ checktty(user, tty, pwd)
if (defaultbuf[0]) {
strtok(defaultbuf, " \t");
while((ptr = strtok(NULL, "\t\n "))) {
- if (in_class(tty, ptr)) return;
+ if (in_class(tty, ptr)) {
+ free_all(); /* JDS */
+ return;
+ }
}
/* there was a default rule, but user didn't match, reject! */
@@ -410,6 +433,7 @@ checktty(user, tty, pwd)
/* users not matched in /etc/usertty are by default allowed access
on all tty's */
+ free_all(); /* JDS */
}
#ifdef TESTING
diff --git a/login-utils/chfn.c b/login-utils/chfn.c
index 207bcb254..e81c5c18b 100644
--- a/login-utils/chfn.c
+++ b/login-utils/chfn.c
@@ -6,16 +6,25 @@
* modify it under the terms of the gnu general public license.
* there is no warranty.
*
- * $Author: faith $
- * $Revision: 1.8 $
- * $Date: 1995/10/12 14:46:35 $
+ * $Author: aebr $
+ * $Revision: 1.15 $
+ * $Date: 1997/07/06 23:10:41 $
*
* Updated Thu Oct 12 09:19:26 1995 by faith@cs.unc.edu with security
* patches from Zefram <A.Main@dcs.warwick.ac.uk>
*
+ * Hacked by Peter Breitenlohner, peb@mppmu.mpg.de,
+ * to allow peaceful coexistence with yp: using the changes by
+ * Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, from
+ * passwd.c (now moved to setpwnam.c);
+ * to remove trailing empty fields. Oct 5, 96.
+ *
*/
-static char rcsId[] = "$Version: $Id: chfn.c,v 1.8 1995/10/12 14:46:35 faith Exp $ $";
+static char rcsId[] = "$Version: $Id: chfn.c,v 1.15 1997/07/06 23:10:41 aebr Exp $ $";
+
+#define _XOPEN_SOURCE /* for crypt() */
+#define _BSD_SOURCE /* for strcasecmp() */
#include <sys/types.h>
#include <stdio.h>
@@ -26,6 +35,14 @@ static char rcsId[] = "$Version: $Id: chfn.c,v 1.8 1995/10/12 14:46:35 faith Exp
#include <errno.h>
#include <ctype.h>
#include <getopt.h>
+#include "../version.h"
+
+#if REQUIRE_PASSWORD && USE_PAM
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+#endif
+
+extern int is_local(char *);
#undef P
#if __STDC__
@@ -38,7 +55,6 @@ typedef unsigned char boolean;
#define false 0
#define true 1
-static char *version_string = "chfn 0.9a beta";
static char *whoami;
static char buf[1024];
@@ -62,10 +78,9 @@ static int check_gecos_string P((char *msg, char *gecos));
static boolean set_changed_data P((struct finfo *oldfp, struct finfo *newfp));
static int save_new_data P((struct finfo *pinfo));
static void *xmalloc P((int bytes));
-#if 0
-extern int strcasecmp P((char *, char *));
+
extern int setpwnam P((struct passwd *pwd));
-#endif
+
#define memzero(ptr, size) memset((char *) ptr, 0, size)
int main (argc, argv)
@@ -78,6 +93,11 @@ int main (argc, argv)
boolean interactive;
int status;
extern int errno;
+#if REQUIRE_PASSWORD && USE_PAM
+ pam_handle_t *pamh = NULL;
+ int retcode;
+ struct pam_conv conv = { misc_conv, NULL };
+#endif
/* whoami is the program name for error messages */
whoami = argv[0];
@@ -114,7 +134,13 @@ int main (argc, argv)
return (-1); }
}
- /* reality check */
+ if (!(is_local(oldf.username))) {
+ fprintf (stderr, "%s: can only change local entries; use yp%s instead.\n",
+ whoami, whoami);
+ exit(1);
+ }
+
+ /* Reality check */
if (uid != 0 && uid != oldf.pw->pw_uid) {
errno = EACCES;
perror (whoami);
@@ -124,6 +150,31 @@ int main (argc, argv)
printf ("Changing finger information for %s.\n", oldf.username);
#if REQUIRE_PASSWORD
+# if USE_PAM
+ if(uid != 0) {
+ if (pam_start("chfn", oldf.username, &conv, &pamh)) {
+ puts("Password error.");
+ exit(1);
+ }
+ if (pam_authenticate(pamh, 0)) {
+ puts("Password error.");
+ exit(1);
+ }
+ retcode = pam_acct_mgmt(pamh, 0);
+ if (retcode == PAM_AUTHTOKEN_REQD) {
+ retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+ } else if (retcode) {
+ puts("Password error.");
+ exit(1);
+ }
+ if (pam_setcred(pamh, 0)) {
+ puts("Password error.");
+ exit(1);
+ }
+ /* no need to establish a session; this isn't a session-oriented
+ * activity... */
+ }
+# else /* USE_PAM */
/* require password, unless root */
if(uid != 0 && oldf.pw->pw_passwd && oldf.pw->pw_passwd[0]) {
pwdstr = getpass("Password: ");
@@ -133,7 +184,8 @@ int main (argc, argv)
exit(1);
}
}
-#endif
+# endif /* USE_PAM */
+#endif /* REQUIRE_PASSWORD */
if (interactive) ask_info (&oldf, &newf);
@@ -176,7 +228,7 @@ static boolean parse_argv (argc, argv, pinfo)
if (c == EOF) break;
/* version? output version and exit. */
if (c == 'v') {
- printf ("%s\n", version_string);
+ printf ("%s\n", util_linux_version);
exit (0);
}
if (c == 'u') {
@@ -191,7 +243,10 @@ static boolean parse_argv (argc, argv, pinfo)
/* ok, we were given an argument */
info_given = true;
status = 0;
- strcpy (buf, whoami); strcat (buf, ": ");
+
+ strncpy (buf, whoami, sizeof(buf)-128);
+ buf[sizeof(buf)-128-1] = 0;
+ strcat (buf, ": ");
/* now store the argument */
switch (c) {
@@ -404,6 +459,12 @@ static int save_new_data (pinfo)
sprintf (gecos, "%s,%s,%s,%s,%s", pinfo->full_name, pinfo->office,
pinfo->office_phone, pinfo->home_phone, pinfo->other);
+ /* remove trailing empty fields (but not subfields of pinfo->other) */
+ if (! pinfo->other[0] ) {
+ while (len > 0 && gecos[len-1] == ',') len--;
+ gecos[len] = 0;
+ }
+
/* write the new struct passwd to the passwd file. */
pinfo->pw->pw_gecos = gecos;
if (setpwnam (pinfo->pw) < 0) {
diff --git a/login-utils/chsh.c b/login-utils/chsh.c
index 9ffd81b2f..3cafc966b 100644
--- a/login-utils/chsh.c
+++ b/login-utils/chsh.c
@@ -6,17 +6,27 @@
* modify it under the terms of the gnu general public license.
* there is no warranty.
*
- * $Author: faith $
- * $Revision: 1.8 $
- * $Date: 1995/10/12 14:46:35 $
+ * $Author: aebr $
+ * $Revision: 1.16 $
+ * $Date: 1997/07/06 00:12:08 $
*
* Updated Thu Oct 12 09:33:15 1995 by faith@cs.unc.edu with security
- * patches from Zefram <A.Main@dcs.warwick.ac.uk>
+ * patches from Zefram <A.Main@dcs.warwick.ac.uk>
+ *
+ * Updated Mon Jul 1 18:46:22 1996 by janl@math.uio.no with security
+ * suggestion from Zefram. Disallowing users with shells not in /etc/shells
+ * from changing their shell.
+ *
+ * Hacked by Peter Breitenlohner, peb@mppmu.mpg.de,
+ * to allow peaceful coexistence with yp: using the changes by
+ * Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, from
+ * passwd.c (now moved to setpwnam.c). Oct 5, 96.
*
*/
-static char rcsId[] = "$Version: $Id: chsh.c,v 1.8 1995/10/12 14:46:35 faith Exp $ $";
+static char rcsId[] = "$Version: $Id: chsh.c,v 1.16 1997/07/06 00:12:08 aebr Exp $ $";
+#define _XOPEN_SOURCE /* to get definition of crypt() */
#if 0
#define _POSIX_SOURCE 1
#endif
@@ -30,6 +40,14 @@ static char rcsId[] = "$Version: $Id: chsh.c,v 1.8 1995/10/12 14:46:35 faith Exp
#include <errno.h>
#include <ctype.h>
#include <getopt.h>
+#include "../version.h"
+
+#if REQUIRE_PASSWORD && USE_PAM
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+#endif
+
+extern int is_local(char *);
#undef P
#if __STDC__
@@ -42,7 +60,10 @@ typedef unsigned char boolean;
#define false 0
#define true 1
-static char *version_string = "chsh 0.9a beta";
+/* Only root is allowed to assign a luser a non-listed shell, by default */
+#define ONLY_LISTED_SHELLS 1
+
+
static char *whoami;
static char buf[FILENAME_MAX];
@@ -70,6 +91,11 @@ int main (argc, argv)
struct sinfo info;
struct passwd *pw;
extern int errno;
+#if REQUIRE_PASSWORD && USE_PAM
+ pam_handle_t *pamh = NULL;
+ int retcode;
+ struct pam_conv conv = { misc_conv, NULL };
+#endif
/* whoami is the program name for error messages */
whoami = argv[0];
@@ -96,21 +122,21 @@ int main (argc, argv)
return (-1); }
}
+ if (!(is_local(pw->pw_name))) {
+ fprintf (stderr, "%s: can only change local entries; use yp%s instead.\n
+",
+ whoami, whoami);
+ exit(1);
+ }
+
oldshell = pw->pw_shell;
if (!oldshell[0]) oldshell = "/bin/sh";
/* reality check */
-#if 0
- /* Require current shell to be in list.
- This is not a reasonable expectation on
- most Linux systems, and the error is
- confusing. */
if (uid != 0 && (uid != pw->pw_uid || !get_shell_list(oldshell))) {
-#else
- if (uid != 0 && uid != pw->pw_uid) {
-#endif
errno = EACCES;
- perror (whoami);
+ fprintf(stderr,"%s: Your shell is not in /etc/shells, shell change"
+ " denied\n",whoami);
return (-1);
}
@@ -118,16 +144,43 @@ int main (argc, argv)
printf( "Changing shell for %s.\n", pw->pw_name );
-#ifdef REQUIRE_PASSWORD
+#if REQUIRE_PASSWORD
+# if USE_PAM
+ if(uid != 0) {
+ if (pam_start("chsh", pw->pw_name, &conv, &pamh)) {
+ puts("Password error.");
+ exit(1);
+ }
+ if (pam_authenticate(pamh, 0)) {
+ puts("Password error.");
+ exit(1);
+ }
+ retcode = pam_acct_mgmt(pamh, 0);
+ if (retcode == PAM_AUTHTOKEN_REQD) {
+ retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+ } else if (retcode) {
+ puts("Password error.");
+ exit(1);
+ }
+ if (pam_setcred(pamh, 0)) {
+ puts("Password error.");
+ exit(1);
+ }
+ /* no need to establish a session; this isn't a session-oriented
+ * activity... */
+ }
+# else /* USE_PAM */
/* require password, unless root */
if(uid != 0 && pw->pw_passwd && pw->pw_passwd[0]) {
pwdstr = getpass("Password: ");
- if(strncmp(pw->pw_passwd, crypt(pwdstr, pw->pw_passwd), 13)) {
+ if(strncmp(pw->pw_passwd,
+ crypt(pwdstr, pw->pw_passwd), 13)) {
puts("Incorrect password.");
exit(1);
}
}
-#endif
+# endif /* USE_PAM */
+#endif /* REQUIRE_PASSWORD */
if (! shell) {
shell = prompt ("New shell", oldshell);
@@ -178,7 +231,7 @@ static void parse_argv (argc, argv, pinfo)
case EOF:
break;
case 'v':
- printf ("%s\n", version_string);
+ printf ("%s\n", util_linux_version);
exit (0);
case 'u':
usage (stdout);
@@ -246,7 +299,7 @@ static char *prompt (question, def_val)
if (len <= 0) return NULL;
ans[len] = 0;
cp = (char *) xmalloc (len + 1);
- strcpy (cp, buf);
+ strcpy (cp, ans);
return cp;
}
@@ -287,17 +340,17 @@ static int check_shell (shell)
#if ONLY_LISTED_SHELLS
if (! get_shell_list (shell)) {
if (!getuid())
- printf ("Warning: \"%s\" is not listed as a valid shell.\n", shell);
+ printf ("Warning: \"%s\" is not listed in /etc/shells\n", shell);
else {
- printf ("%s: \"%s\" is not listed as a valid shell.\n",
+ printf ("%s: \"%s\" is not listed in /etc/shells.\n",
whoami, shell);
- printf( "%s: use -l option to see list\n" );
+ printf( "%s: use -l option to see list\n", whoami );
exit(1);
}
}
#else
if (! get_shell_list (shell)) {
- printf ("Warning: \"%s\" is not listed as a valid shell.\n", shell);
+ printf ("Warning: \"%s\" is not listed in /etc/shells.\n", shell);
printf( "Use %s -l to see list.\n", whoami );
}
#endif
diff --git a/login-utils/cryptocard.c b/login-utils/cryptocard.c
new file mode 100644
index 000000000..e735c7273
--- /dev/null
+++ b/login-utils/cryptocard.c
@@ -0,0 +1,222 @@
+/* cryptocard.c - support for the CRYPTOCard
+ RB-1 Challenge-Response Token, initial code by
+ bentson@grieg.seaslug.org (Randolph Bentson) on 3-Dec-96,
+ Hacked severely by poe@daimi.aau.dk.
+ This relies on an implementation of DES in a library, currently
+ it interfaces with the koontz-des.tar.gz implementation which
+ can be found in:
+
+ ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/des/
+
+ (Link with the fdes.o file from that distribution)
+
+ and with Eric A. Young's libdes implementation used in SSLeay. Also
+ available from the above ftp site. Link with the libdes.a library.
+
+ The sources for this code are maintained in
+
+ ftp://ftp.daimi.aau.dk/pub/linux/poe/poeigl-X.XX.tar.gz
+*/
+#ifdef CRYPTOCARD
+
+/******************** CONFIGURATION section *****************************/
+/*--------------- select ONE DES implementation ------------------------*/
+/*#define KOONTZ_DES */
+#define EAY_LIBDES
+/*--------------- define if on little endian machine (Intel x86) -------*/
+#define LITTLE_ENDIAN
+/******************** end of CONFIGURATION section **********************/
+
+#define _BSD_SOURCE
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#ifdef KOONTZ_DES
+#include "../koontz-des/des.h"
+#endif /* KOONTZ_DES */
+
+#ifdef EAY_LIBDES
+#include "../libdes/des.h"
+#endif /* EAY_LIBDES */
+
+extern char *getpass(const char *prompt);
+extern struct passwd *pwd;
+extern int timeout;
+
+static char *
+generate_challenge(void)
+{
+ static char challenge_str[30];
+ int rfd;
+ unsigned long clong;
+
+ /* create and present a challenge string */
+ if ((rfd = open("/dev/urandom", O_RDONLY)) < 0) {
+ syslog(LOG_NOTICE, "couldn't open /dev/urandom");
+ return NULL;
+ }
+ if (read(rfd, &clong, 4) < 4) {
+ close(rfd);
+ syslog(LOG_NOTICE, "couldn't read random data from /dev/urandom");
+ return NULL;
+ }
+ close(rfd);
+
+ sprintf(challenge_str,"%08lu", clong);
+ return challenge_str;
+}
+
+static char *
+get_key()
+{
+ int success = 0;
+ char keyfile[MAXPATHLEN];
+ static char key[10];
+ int rfd;
+ struct stat statbuf;
+
+ snprintf(keyfile, sizeof(keyfile), "%s/.cryptocard", pwd->pw_dir);
+
+ if ((rfd = open(keyfile, O_RDONLY)) < 0) {
+ syslog(LOG_NOTICE, "can't open %s for reading", keyfile);
+ goto bail_out;
+ }
+ if (fstat(rfd, &statbuf) < 0) {
+ syslog(LOG_NOTICE, "can't stat(%s)", keyfile);
+ goto close_and_bail_out;
+ }
+ if ((statbuf.st_uid != pwd->pw_uid)
+ || ((statbuf.st_mode & S_IFMT) != S_IFREG)
+ || (statbuf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) {
+ syslog(LOG_NOTICE, "%s doesn't have the correct filemodes", keyfile);
+ goto close_and_bail_out;
+ }
+
+ if (read(rfd, key, 8) < 8) {
+ syslog(LOG_NOTICE, "can't read data from %s", keyfile);
+ goto close_and_bail_out;
+ }
+
+ key[8] = 0;
+ success = 1;
+
+close_and_bail_out:
+ close(rfd);
+
+bail_out:
+ if (success)
+ return key;
+ else
+ return NULL;
+}
+
+static int
+check_response(char *challenge, char *response, char *key)
+{
+ char buf[20];
+
+#ifdef KOONTZ_DES
+ extern void des (union LR_block *);
+ extern void loadkey(char *,int);
+ extern void set_des_mode(int);
+
+ union LR_block data;
+
+ strncpy((char *)data.string, (char *)challenge, 8);
+ set_des_mode(ENCRYPT);
+ loadkey(key, NOSHIFT);
+ des(&data);
+
+ memset(key, 0, 8); /* no need for the secret key anymore, scratch it */
+
+ sprintf(buf, "%2.2X%2.2X%2.2X%2.2X",
+ (int)(data.LR[0]) & 0xff,
+ (int)(data.LR[0]>>8) & 0xff,
+ (int)(data.LR[0]>>16) & 0xff,
+ (int)(data.LR[0]>>24) & 0xff);
+#endif /* KOONTZ_DES */
+#ifdef EAY_LIBDES
+ des_cblock res;
+ des_key_schedule ks;
+
+ des_set_key((des_cblock *)key, ks);
+ memset(key, 0, 8);
+ des_ecb_encrypt((des_cblock *)challenge, &res, ks, DES_ENCRYPT);
+
+#ifdef LITTLE_ENDIAN
+ /* use this on Intel x86 boxes */
+ sprintf(buf, "%2.2X%2.2X%2.2X%2.2X",
+ res[0], res[1], res[2], res[3]);
+#else /* ie. BIG_ENDIAN */
+ /* use this on big endian RISC boxes */
+ sprintf(buf, "%2.2X%2.2X%2.2X%2.2X",
+ res[3], res[2], res[1], res[0]);
+#endif /* LITTLE_ENDIAN */
+#endif /* EAY_LIBDES */
+
+ /* return success only if ALL requirements have been met */
+ if (strncmp(buf, response, 8) == 0)
+ return 1;
+
+ return 0;
+}
+
+int
+cryptocard(void)
+{
+ char prompt[80];
+ char *challenge;
+ char *key;
+ char *response;
+
+ challenge = generate_challenge();
+ if (challenge == NULL) return 0;
+
+ snprintf(prompt, sizeof(prompt), "%s Password: ", challenge);
+
+ alarm((unsigned int)timeout); /* give user time to fiddle with card */
+ response = getpass(prompt); /* presents challenge and gets response */
+
+ if (response == NULL) return 0;
+
+ /* This requires some explanation: As root we may not be able to
+ read the directory of the user if it is on an NFS mounted
+ filesystem. We temporarily set our effective uid to the user-uid
+ making sure that we keep root privs. in the real uid.
+
+ A portable solution would require a fork(), but we rely on Linux
+ having the BSD setreuid() */
+
+ {
+ uid_t ruid = getuid();
+ gid_t egid = getegid();
+
+ setregid(-1, pwd->pw_gid);
+ setreuid(0, pwd->pw_uid);
+
+ /* now we can access the file */
+ /* get the (properly qualified) key */
+ key = get_key();
+
+ /* reset to root privs */
+ setuid(0); /* setreuid doesn't do it alone! */
+ setreuid(ruid, 0);
+ setregid(-1, egid);
+
+ if (key == NULL) return 0;
+ }
+
+ return check_response(challenge, response, key);
+}
+
+#endif /* CRYPTOCARD */
diff --git a/login-utils/islocal.c b/login-utils/islocal.c
index a4cfb16ab..5480c5744 100644
--- a/login-utils/islocal.c
+++ b/login-utils/islocal.c
@@ -1,13 +1,22 @@
-/* islocal.c - returns true if user is registered in the local
+/*
+ islocal.c - returns true if user is registered in the local
/etc/passwd file. Written by Alvaro Martinez Echevarria,
alvaro@enano.etsit.upm.es, to allow peaceful coexistence with yp. Nov 94.
+
Hacked a bit by poe@daimi.aau.dk
See also ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil*
+
+ Hacked by Peter Breitenlohner, peb@mppmu.mpg.de,
+ to distinguish user names where one is a prefix of the other,
+ and to use "pathnames.h". Oct 5, 96.
+
*/
#include <stdio.h>
#include <string.h>
+#include "pathnames.h"
+
#define MAX_LENGTH 1024
int
@@ -16,14 +25,16 @@ is_local(char *user)
FILE *fd;
char line[MAX_LENGTH];
int local = 0;
+ int len;
- if(!(fd = fopen("/etc/passwd", "r"))) {
- puts("Can't read /etc/passwd, exiting.");
+ if(!(fd = fopen(_PATH_PASSWD, "r"))) {
+ fprintf(stderr,"Can't read %s, exiting.",_PATH_PASSWD);
exit(1);
}
+ len = strlen(user);
while(fgets(line, MAX_LENGTH, fd) > 0) {
- if(!strncmp(line, user, strlen(user))) {
+ if(!strncmp(line, user, len) && line[len] == ':') {
local = 1;
break;
}
diff --git a/login-utils/last.c b/login-utils/last.c
index bc8294978..fa9f8f837 100644
--- a/login-utils/last.c
+++ b/login-utils/last.c
@@ -201,72 +201,82 @@ wtmp()
(void)signal(SIGQUIT, onintr);
while (--bl >= 0) {
- if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 ||
- (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) {
- fprintf(stderr, "last: %s: ", file);
- perror((char *)NULL);
- exit(1);
- }
- for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) {
- /*
- * if the terminal line is '~', the machine stopped.
- * see utmp(5) for more info.
- */
- if (!strncmp(bp->ut_line, "~", LMAX)) {
- /* everybody just logged out */
- for (T = ttylist; T; T = T->next)
- T->logout = -bp->ut_time;
- currentout = -bp->ut_time;
- crmsg = strncmp(bp->ut_name, "shutdown", NMAX) ? "crash" : "down ";
- if (!bp->ut_name[0])
- (void)strcpy(bp->ut_name, "reboot");
- if (want(bp, NO)) {
- ct = ctime(&bp->ut_time);
- if(bp->ut_type != LOGIN_PROCESS) {
- print_partial_line(bp);
- putchar('\n');
- }
- if (maxrec && !--maxrec)
- return;
- }
- continue;
- }
- /* find associated tty */
- for (T = ttylist;; T = T->next) {
- if (!T) {
- /* add new one */
- T = addtty(bp->ut_line);
- break;
- }
- if (!strncmp(T->tty, bp->ut_line, LMAX))
- break;
+ if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 ||
+ (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) {
+ fprintf(stderr, "last: %s: ", file);
+ perror((char *)NULL);
+ exit(1);
+ }
+ for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) {
+ /*
+ * if the terminal line is '~', the machine stopped.
+ * see utmp(5) for more info.
+ */
+ if (!strncmp(bp->ut_line, "~", LMAX)) {
+ /*
+ * utmp(5) also mentions that the user
+ * name should be 'shutdown' or 'reboot'.
+ * Not checking the name causes i.e. runlevel
+ * changes to be displayed as 'crash'. -thaele
+ */
+ if (!strncmp(bp->ut_user, "reboot", NMAX) ||
+ !strncmp(bp->ut_user, "shutdown", NMAX)) {
+ /* everybody just logged out */
+ for (T = ttylist; T; T = T->next)
+ T->logout = -bp->ut_time;
+ }
+
+ currentout = -bp->ut_time;
+ crmsg = strncmp(bp->ut_name, "shutdown", NMAX) ? "crash" : "down ";
+ if (!bp->ut_name[0])
+ (void)strcpy(bp->ut_name, "reboot");
+ if (want(bp, NO)) {
+ ct = ctime(&bp->ut_time);
+ if(bp->ut_type != LOGIN_PROCESS) {
+ print_partial_line(bp);
+ putchar('\n');
}
- if (bp->ut_name[0] && bp->ut_type != LOGIN_PROCESS
- && bp->ut_type != DEAD_PROCESS
- && want(bp, YES)) {
-
- print_partial_line(bp);
-
- if (!T->logout)
- puts(" still logged in");
- else {
- if (T->logout < 0) {
- T->logout = -T->logout;
- printf("- %s", crmsg);
- }
- else
- printf("- %5.5s", ctime(&T->logout)+11);
- delta = T->logout - bp->ut_time;
- if (delta < SECDAY)
- printf(" (%5.5s)\n", asctime(gmtime(&delta))+11);
- else
- printf(" (%ld+%5.5s)\n", delta / SECDAY, asctime(gmtime(&delta))+11);
- }
- if (maxrec != -1 && !--maxrec)
- return;
+ if (maxrec && !--maxrec)
+ return;
+ }
+ continue;
+ }
+ /* find associated tty */
+ for (T = ttylist;; T = T->next) {
+ if (!T) {
+ /* add new one */
+ T = addtty(bp->ut_line);
+ break;
+ }
+ if (!strncmp(T->tty, bp->ut_line, LMAX))
+ break;
+ }
+ if (bp->ut_name[0] && bp->ut_type != LOGIN_PROCESS
+ && bp->ut_type != DEAD_PROCESS
+ && want(bp, YES)) {
+
+ print_partial_line(bp);
+
+ if (!T->logout)
+ puts(" still logged in");
+ else {
+ if (T->logout < 0) {
+ T->logout = -T->logout;
+ printf("- %s", crmsg);
}
- T->logout = bp->ut_time;
+ else
+ printf("- %5.5s", ctime(&T->logout)+11);
+ delta = T->logout - bp->ut_time;
+ if (delta < SECDAY)
+ printf(" (%5.5s)\n", asctime(gmtime(&delta))+11);
+ else
+ printf(" (%ld+%5.5s)\n", delta / SECDAY, asctime(gmtime(&delta))+11);
+ }
+ if (maxrec != -1 && !--maxrec)
+ return;
}
+ T->logout = bp->ut_time;
+ }
}
ct = ctime(&buf[0].ut_time);
printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11);
diff --git a/login-utils/login.1 b/login-utils/login.1
index 0e1f5eff8..92a082c67 100644
--- a/login-utils/login.1
+++ b/login-utils/login.1
@@ -1,6 +1,6 @@
.\" Copyright 1993 Rickard E. Faith (faith@cs.unc.edu)
.\" May be distributed under the GNU General Public License
-.TH LOGIN 1 "1 February 1993" "Linux 0.99" "Linux Programmer's Manual"
+.TH LOGIN 1 "4 November 1996" "Util-linux 1.6" "Linux Programmer's Manual"
.SH NAME
login \- sign on
.SH SYNOPSIS
@@ -42,8 +42,8 @@ Failures will be logged with the
facility.
After these conditions are checked, the password will be requested and
-checks (if a password is required for this username). Ten attempts are
-allowed before
+checks (if a password is required for this username). Ten attempts
+are allowed before
.B login
dies, but after the first three, the response starts to get very slow.
Login failures are reported via the
@@ -52,27 +52,29 @@ facility. This facility is also used to report any successful root logins.
If the file
.I .hushlogin
-exists, then a "quiet" login is performed (this disables the checking of
-the checking of mail and the printing of the last login time and message of
-the day). Otherwise, if
+exists, then a "quiet" login is performed (this disables the checking
+of the checking of mail and the printing of the last login time and
+message of the day). Otherwise, if
.I /var/log/lastlog
-exists, the last login time is printed (and the current login is recorded).
+exists, the last login time is printed (and the current login is
+recorded).
-Random administrative things, such as setting the UID and GID of the tty
-are performed. The TERM environment variable is preserved, if it exists
-(other environment variables are preserved if the
+Random administrative things, such as setting the UID and GID of the
+tty are performed. The TERM environment variable is preserved, if it
+exists (other environment variables are preserved if the
.B \-p
option is used). Then the HOME, PATH, SHELL, TERM, MAIL, and LOGNAME
environment variables are set. PATH defaults to
.I /usr/local/bin:/bin:/usr/bin:.
for normal users, and to
.I /sbin:/bin:/usr/sbin:/usr/bin
-for root. Last, if this is not a "quiet" login, the message of the day is
-printed and the file with the user's name in
+for root. Last, if this is not a "quiet" login, the message of the
+day is printed and the file with the user's name in
.I /usr/spool/mail
will be checked, and a message printed if it has non-zero length.
-The user's shell is then started. If no shell is specified for the user in
+The user's shell is then started. If no shell is specified for the
+user in
.BR /etc/passwd ,
then
.B /bin/sh
@@ -102,41 +104,43 @@ Used by other servers (i.e.,
.BR telnetd (8))
to pass the name of the remote host to
.B login
-so that it may be placed in utmp and wtmp. Only the superuser may use this
-option.
+so that it may be placed in utmp and wtmp. Only the superuser may use
+this option.
.SH "SPECIAL ACCESS RESTRICTIONS"
The file
.I /etc/securetty
-lists the names of the ttys where root is allowed to log in. One name of
-a tty device without the /dev/ prefix must be specified on each line.
-If the file does not exist, root is allowed to log in on any tty.
+lists the names of the ttys where root is allowed to log in. One name
+of a tty device without the /dev/ prefix must be specified on each
+line. If the file does not exist, root is allowed to log in on any
+tty.
.PP
The file
.I /etc/usertty
-specifies additional access restrictions for specific users. If this file
-does not exist, no additional access restrictions are imposed. The file
-consists of a sequence of sections. There are three possible section
-types: CLASSES, GROUPS and USERS. A CLASSES section defines classes of
-ttys and hostname patterns, A GROUPS section defines allowed ttys and
-hosts on a per group basis, and a USERS section defines allowed ttys
-and hosts on a per user basis.
+specifies additional access restrictions for specific users. If this
+file does not exist, no additional access restrictions are
+imposed. The file consists of a sequence of sections. There are three
+possible section types: CLASSES, GROUPS and USERS. A CLASSES section
+defines classes of ttys and hostname patterns, A GROUPS section
+defines allowed ttys and hosts on a per group basis, and a USERS
+section defines allowed ttys and hosts on a per user basis.
.PP
-Each line in this file in may be no longer than 255 characters. Comments
-start with # character and extend to the end of the line.
+Each line in this file in may be no longer than 255
+characters. Comments start with # character and extend to the end of
+the line.
.PP
.SS "The CLASSES Section"
-A CLASSES section begins with the word CLASSES at the start of a line in all
-upper case. Each following line until the start of a new section or the
-end of the file consists of a sequence of words separated by tabs or
-spaces. Each line defines a class of ttys and host patterns.
+A CLASSES section begins with the word CLASSES at the start of a line
+in all upper case. Each following line until the start of a new
+section or the end of the file consists of a sequence of words
+separated by tabs or spaces. Each line defines a class of ttys and
+host patterns.
.PP
-The word at
-the beginning of a line becomes defined as a collective name for the
-ttys and host patterns specified at the rest of the line. This collective
-name can be used in any subsequent GROUPS or USERS section. No such class
-name must occur as part of the definition of a class in order to avoid
-problems with recursive classes.
+The word at the beginning of a line becomes defined as a collective
+name for the ttys and host patterns specified at the rest of the
+line. This collective name can be used in any subsequent GROUPS or
+USERS section. No such class name must occur as part of the definition
+of a class in order to avoid problems with recursive classes.
.PP
An example CLASSES section:
.PP
@@ -155,7 +159,7 @@ and
as the corresponding right hand sides.
.PP
-.SS "The GROUPS Section
+.SS "The GROUPS Section"
A GROUPS section defines allowed ttys and hosts on a per Unix group basis. If
a user is a member of a Unix group according to
.I /etc/passwd
@@ -184,9 +188,11 @@ stud myclass1 tty4
.PP
This example specifies that members of group
.I sys
-may log in on tty1 and from hosts in the bar.edu domain. Users in group
+may log in on tty1 and from hosts in the bar.edu domain. Users in
+group
.I stud
-may log in from hosts/ttys specified in the class myclass1 or from tty4.
+may log in from hosts/ttys specified in the class myclass1 or from
+tty4.
.PP
.SS "The USERS Section"
@@ -209,44 +215,48 @@ blue tty3 myclass2
.in -0.5
.fi
.PP
-This lets the user zacho login only on tty1 and from hosts with IP addreses
-in the range 130.225.16.0 \- 130.225.16.255, and user blue is allowed to
-log in from tty3 and whatever is specified in the class myclass2.
+This lets the user zacho login only on tty1 and from hosts with IP
+addreses in the range 130.225.16.0 \- 130.225.16.255, and user blue is
+allowed to log in from tty3 and whatever is specified in the class
+myclass2.
.PP
-There may be a line in a USERS section starting with a username of *. This
-is a default rule and it will be applied to any user not matching any other
-line.
+There may be a line in a USERS section starting with a username of
+*. This is a default rule and it will be applied to any user not
+matching any other line.
.PP
-If both a USERS line and GROUPS line match a user then the user is allowed
-access from the union of all the ttys/hosts mentioned in these specifications.
+If both a USERS line and GROUPS line match a user then the user is
+allowed access from the union of all the ttys/hosts mentioned in these
+specifications.
.SS Origins
-The tty and host pattern specifications used in the specification of classes,
-group and user access are called origins. An origin string may have
-one of these formats:
+The tty and host pattern specifications used in the specification of
+classes, group and user access are called origins. An origin string
+may have one of these formats:
.IP o
The name of a tty device without the /dev/ prefix, for example tty1 or
ttyS0.
.PP
.IP o
-The string @localhost, meaning that the user is allowed to telnet/rlogin
-from the local host to the same host. This also allows the user to for
-example run the command: xterm -e /bin/login.
+The string @localhost, meaning that the user is allowed to
+telnet/rlogin from the local host to the same host. This also allows
+the user to for example run the command: xterm -e /bin/login.
.PP
.IP o
A domain name suffix such as @.some.dom, meaning that the user may
-rlogin/telnet from any host whose domain name has the suffix .some.dom.
+rlogin/telnet from any host whose domain name has the suffix
+.some.dom.
.PP
.IP o
-A range of IPv4 addresses, written @x.x.x.x/y.y.y.y where x.x.x.x
-is the IP address in the usual dotted quad decimal notation, and
-y.y.y.y is a bitmask in the same notation specifying which bits in the
-address to compare with the IP address of the remote host. For example
+A range of IPv4 addresses, written @x.x.x.x/y.y.y.y where x.x.x.x is
+the IP address in the usual dotted quad decimal notation, and y.y.y.y
+is a bitmask in the same notation specifying which bits in the address
+to compare with the IP address of the remote host. For example
@130.225.16.0/255.255.254.0 means that the user may rlogin/telnet from
-any host whose IP address is in the range 130.225.16.0 \- 130.225.17.255.
+any host whose IP address is in the range 130.225.16.0 \-
+130.225.17.255.
.PP
-Any of the above origins may be prefixed by a time specification according
-to the syntax:
+Any of the above origins may be prefixed by a time specification
+according to the syntax:
.PP
.nf
timespec ::= '[' <day-or-hour> [':' <day-or-hour>]* ']'
@@ -256,16 +266,16 @@ hourspec ::= <hour> | <hour> '\-' <hour>
day-or-hour ::= <day> | <hourspec>
.fi
.PP
-For example, the origin [mon:tue:wed:thu:fri:8\-17]tty3 means that log in is
-allowed on mondays through fridays between 8:00 and 17:59 (5:59 pm) on tty3.
-This also shows that an hour range a\-b includes all moments between a:00 and
-b:59. A single hour specification (such as 10) means the time span between
-10:00 and 10:59.
+For example, the origin [mon:tue:wed:thu:fri:8\-17]tty3 means that log
+in is allowed on mondays through fridays between 8:00 and 17:59 (5:59
+pm) on tty3. This also shows that an hour range a\-b includes all
+moments between a:00 and b:59. A single hour specification (such as
+10) means the time span between 10:00 and 10:59.
.PP
-Not specifying any time prefix for a tty or host means log in from that origin
-is allowed any time. If you give a time prefix be sure to specify both a set
-of days and one or more hours or hour ranges. A time specification may
-not include any white space.
+Not specifying any time prefix for a tty or host means log in from
+that origin is allowed any time. If you give a time prefix be sure to
+specify both a set of days and one or more hours or hour ranges. A
+time specification may not include any white space.
.PP
If no default rule is given then users not matching any line
.I /etc/usertty
@@ -292,7 +302,9 @@ are allowed to log in from anywhere as is standard behavior.
.BR environ (7),
.BR shutdown (8)
.SH BUGS
-Linux, unlike other draconian operating systems, does not check quotas.
+
+Linux, unlike other draconian operating systems, does not check
+quotas.
The undocumented BSD
.B \-r
@@ -300,7 +312,7 @@ option is not supported. This may be required by some
.BR rlogind (8)
programs.
.SH AUTHOR
-Derived from BSD login 5.40 (5/9/89) by Michael Glad (glad@daimi.dk) for HP-UX
+Derived from BSD login 5.40 (5/9/89) by Michael Glad (glad@daimi.dk)
+for HP-UX
.br
Ported to Linux 0.12: Peter Orbaek (poe@daimi.aau.dk)
-
diff --git a/login-utils/login.c b/login-utils/login.c
index 33a0b03e7..c1626183e 100644
--- a/login-utils/login.c
+++ b/login-utils/login.c
@@ -1,57 +1,58 @@
/* This program is derived from 4.3 BSD software and is
subject to the copyright notice below.
-
+
The port to HP-UX has been motivated by the incapability
of 'rlogin'/'rlogind' as per HP-UX 6.5 (and 7.0) to transfer window sizes.
-
+
Changes:
-
+
- General HP-UX portation. Use of facilities not available
in HP-UX (e.g. setpriority) has been eliminated.
Utmp/wtmp handling has been ported.
-
+
- The program uses BSD command line options to be used
in connection with e.g. 'rlogind' i.e. 'new login'.
-
+
- HP features left out: logging of bad login attempts in /etc/btmp,
- they are sent to syslog
-
+ they are sent to syslog
+
password expiry
-
+
'*' as login shell, add it if you need it
- BSD features left out: quota checks
- password expiry
+ password expiry
analysis of terminal type (tset feature)
-
+
- BSD features thrown in: Security logging to syslogd.
This requires you to have a (ported) syslog
system -- 7.0 comes with syslog
-
+
'Lastlog' feature.
-
+
- A lot of nitty gritty details has been adjusted in favour of
HP-UX, e.g. /etc/securetty, default paths and the environment
variables assigned by 'login'.
-
+
- We do *nothing* to setup/alter tty state, under HP-UX this is
to be done by getty/rlogind/telnetd/some one else.
-
+
Michael Glad (glad@daimi.dk)
Computer Science Department
Aarhus University
Denmark
-
+
1990-07-04
-
+
1991-09-24 glad@daimi.aau.dk: HP-UX 8.0 port:
- - now explictly sets non-blocking mode on descriptors
- - strcasecmp is now part of HP-UX
+ - now explictly sets non-blocking mode on descriptors
+ - strcasecmp is now part of HP-UX
+
1992-02-05 poe@daimi.aau.dk: Ported the stuff to Linux 0.12
- From 1992 till now (1995) this code for Linux has been maintained at
+ From 1992 till now (1997) this code for Linux has been maintained at
ftp.daimi.aau.dk:/pub/linux/poe/
-*/
-
+ */
+
/*
* Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
* All rights reserved.
@@ -71,7 +72,7 @@
#ifndef lint
char copyright[] =
-"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
+ "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
@@ -85,6 +86,8 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89";
* login -f name (for pre-authenticated login: datakit, xterm, etc.)
*/
+#define _GNU_SOURCE /* to get definition of snprintf */
+
/* #define TESTING */
#ifdef TESTING
@@ -93,10 +96,12 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89";
#include <sys/param.h>
#endif
+#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <getopt.h>
#include <memory.h>
+#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
@@ -106,18 +111,24 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89";
#define index strchr
#define rindex strrchr
#include <sys/ioctl.h>
+#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
+#include <utmp.h>
#include <setjmp.h>
#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
#include <sys/syslog.h>
#include <sys/sysmacros.h>
#include <netdb.h>
+#ifdef __linux__
+# include <sys/sysmacros.h>
+# include <linux/major.h>
+#endif
+
#ifdef TESTING
# include "utmp.h"
#else
@@ -125,21 +136,39 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89";
#endif
#ifdef SHADOW_PWD
-#include <shadow.h>
+# include <shadow.h>
#endif
-#ifndef linux
-#include <tzfile.h>
+#ifdef USE_PAM
+# include <security/pam_appl.h>
+# include <security/pam_misc.h>
+# define PAM_MAX_LOGIN_TRIES 3
+# define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
+ fprintf(stderr,"\n%s\n",pam_strerror(retcode)); \
+ syslog(LOG_ERR,"%s",pam_strerror(retcode)); \
+ pam_end(pamh, retcode); exit(1); \
+ }
+# define PAM_END { retcode = pam_close_session(pamh,0); \
+ pam_end(pamh,retcode); }
+# define PAM_END { \
+ retcode = pam_close_session(pamh,0); pam_end(pamh,retcode); \
+}
+#endif
+
+#ifndef __linux__
+# include <tzfile.h>
#endif
#include <lastlog.h>
+#define SLEEP_EXIT_TIMEOUT 5
+
#if 0
/* from before we had a lastlog.h file in linux */
struct lastlog
- { long ll_time;
- char ll_line[12];
- char ll_host[16];
- };
+{ long ll_time;
+ char ll_line[12];
+ char ll_host[16];
+};
#endif
#include "pathnames.h"
@@ -153,11 +182,13 @@ void motd P_((void));
void sigint P_((void));
void checknologin P_((void));
void dolastlog P_((int quiet));
-void badlogin P_((char *name));
+void badlogin P_((const char *name));
char *stypeof P_((char *ttyid));
void checktty P_((char *user, char *tty, struct passwd *pwd));
-void getstr P_((char *buf, int cnt, char *err));
void sleepexit P_((int eval));
+#ifdef CRYPTOCARD
+int cryptocard P_((void));
+#endif
#undef P_
#ifdef KERBEROS
@@ -167,6 +198,12 @@ char realm[REALM_SZ];
int kerror = KSUCCESS, notickets = 1;
#endif
+#ifdef USE_TTY_GROUP
+# define TTY_MODE 0620
+#else
+# define TTY_MODE 0600
+#endif
+
#define TTYGRPNAME "tty" /* name of group to own ttys */
/**# define TTYGRPNAME "other" **/
@@ -178,7 +215,7 @@ int kerror = KSUCCESS, notickets = 1;
* This bounds the time given to login. Not a define so it can
* be patched on machines where it's too small.
*/
-#ifndef linux
+#ifndef __linux__
int timeout = 300;
#else
int timeout = 60;
@@ -190,19 +227,19 @@ char term[64], *hostname, *username, *tty;
struct hostent hostaddress;
char thishost[100];
-#ifndef linux
+#ifndef __linux__
struct sgttyb sgttyb;
struct tchars tc = {
- CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
-};
+ CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
+ };
struct ltchars ltc = {
- CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
-};
+ CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
+ };
#endif
-char *months[] =
- { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
- "Sep", "Oct", "Nov", "Dec" };
+const char *months[] =
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
+ "Sep", "Oct", "Nov", "Dec" };
/* provided by Linus Torvalds 16-Feb-93 */
void
@@ -210,7 +247,7 @@ opentty(const char * tty)
{
int i;
int fd = open(tty, O_RDWR);
-
+
for (i = 0 ; i < fd ; i++)
close(i);
for (i = 0 ; i < 3 ; i++)
@@ -219,657 +256,916 @@ opentty(const char * tty)
close(fd);
}
+/* true if the filedescriptor fd is a console tty, very Linux specific */
+static int
+consoletty(int fd)
+{
+#ifdef __linux__
+ struct stat stb;
+
+ if ((fstat(fd, &stb) >= 0)
+ && (major(stb.st_rdev) == TTY_MAJOR)
+ && (minor(stb.st_rdev) < 64)) {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+
int
main(argc, argv)
- int argc;
- char **argv;
+ int argc;
+ char **argv;
{
- extern int errno, optind;
- extern char *optarg, **environ;
- struct timeval tp;
- struct tm *ttp;
- struct group *gr;
- register int ch;
- register char *p;
- int ask, fflag, hflag, pflag, cnt;
- int quietlog, passwd_req, ioctlval;
- char *domain, *salt, *ttyn, *pp;
- char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
- char *ctime(), *ttyname(), *stypeof();
- time_t time();
- void timedout();
- char *termenv;
-
-#ifdef linux
- char tmp[100];
- /* Just as arbitrary as mountain time: */
- /* (void)setenv("TZ", "MET-1DST",0); */
+ extern int errno, optind;
+ extern char *optarg, **environ;
+ struct group *gr;
+ register int ch;
+ register char *p;
+ int ask, fflag, hflag, pflag, cnt;
+ int quietlog, passwd_req, ioctlval;
+ char *domain, *salt, *ttyn, *pp;
+ char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
+ char *ctime(), *ttyname(), *stypeof();
+ time_t time();
+ void timedout();
+ char *termenv;
+ char vcsn[20], vcsan[20];
+ char * childArgv[10];
+ char * buff;
+ int childArgc = 0;
+ int error = 0;
+#ifdef USE_PAM
+ int retcode;
+ pam_handle_t *pamh = NULL;
+ struct pam_conv conv = { misc_conv, NULL };
+ pid_t childPid;
+ int childStatus;
+ void * oldSigHandler;
#endif
- (void)signal(SIGALRM, timedout);
- (void)alarm((unsigned int)timeout);
- (void)signal(SIGQUIT, SIG_IGN);
- (void)signal(SIGINT, SIG_IGN);
- (void)setpriority(PRIO_PROCESS, 0, 0);
+#ifdef __linux__
+ char tmp[100];
+ /* Just as arbitrary as mountain time: */
+ /* (void)setenv("TZ", "MET-1DST",0); */
+#endif
+
+ signal(SIGALRM, timedout);
+ alarm((unsigned int)timeout);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+
+ setpriority(PRIO_PROCESS, 0, 0);
#ifdef HAVE_QUOTA
- (void)quota(Q_SETUID, 0, 0, 0);
+ quota(Q_SETUID, 0, 0, 0);
#endif
-
- /*
- * -p is used by getty to tell login not to destroy the environment
- * -f is used to skip a second login authentication
- * -h is used by other servers to pass the name of the remote
- * host to login so that it may be placed in utmp and wtmp
- */
- (void)gethostname(tbuf, sizeof(tbuf));
- (void)strncpy(thishost, tbuf, sizeof(thishost)-1);
- domain = index(tbuf, '.');
-
- hostname = NULL;
- fflag = hflag = pflag = 0;
- passwd_req = 1;
- while ((ch = getopt(argc, argv, "fh:p")) != EOF)
- switch (ch) {
- case 'f':
- fflag = 1;
- break;
-
- case 'h':
- if (getuid()) {
- (void)fprintf(stderr,
- "login: -h for super-user only.\n");
- exit(1);
- }
- hflag = 1;
- if (domain && (p = index(optarg, '.')) &&
- strcasecmp(p, domain) == 0)
- *p = 0;
- hostname = optarg;
- {
- struct hostent *he = gethostbyname(hostname);
- if (he) {
- memcpy(&hostaddress, he, sizeof(hostaddress));
- } else {
- memset(&hostaddress, 0, sizeof(hostaddress));
- }
- }
- break;
-
- case 'p':
- pflag = 1;
- break;
- case '?':
- default:
- (void)fprintf(stderr,
- "usage: login [-fp] [username]\n");
- exit(1);
- }
- argc -= optind;
- argv += optind;
- if (*argv) {
- username = *argv;
- ask = 0;
- } else
- ask = 1;
-
-#ifndef linux
- ioctlval = 0;
- (void)ioctl(0, TIOCLSET, &ioctlval);
- (void)ioctl(0, TIOCNXCL, 0);
- (void)fcntl(0, F_SETFL, ioctlval);
- (void)ioctl(0, TIOCGETP, &sgttyb);
- sgttyb.sg_erase = CERASE;
- sgttyb.sg_kill = CKILL;
- (void)ioctl(0, TIOCSLTC, &ltc);
- (void)ioctl(0, TIOCSETC, &tc);
- (void)ioctl(0, TIOCSETP, &sgttyb);
-
- /*
- * Be sure that we're in
- * blocking mode!!!
- * This is really for HPUX
- */
- ioctlval = 0;
- (void)ioctl(0, FIOSNBIO, &ioctlval);
+
+ /*
+ * -p is used by getty to tell login not to destroy the environment
+ * -f is used to skip a second login authentication
+ * -h is used by other servers to pass the name of the remote
+ * host to login so that it may be placed in utmp and wtmp
+ */
+ gethostname(tbuf, sizeof(tbuf));
+ strncpy(thishost, tbuf, sizeof(thishost)-1);
+ thishost[sizeof(thishost)-1] = 0;
+ domain = index(tbuf, '.');
+
+ username = tty = hostname = NULL;
+ fflag = hflag = pflag = 0;
+ passwd_req = 1;
+ while ((ch = getopt(argc, argv, "fh:p")) != EOF)
+ switch (ch) {
+ case 'f':
+ fflag = 1;
+ break;
+
+ case 'h':
+ if (getuid()) {
+ fprintf(stderr,
+ "login: -h for super-user only.\n");
+ exit(1);
+ }
+ hflag = 1;
+ if (domain && (p = index(optarg, '.')) &&
+ strcasecmp(p, domain) == 0)
+ *p = 0;
+ hostname = optarg;
+ {
+ struct hostent *he = gethostbyname(hostname);
+ if (he) {
+ memcpy(&hostaddress, he, sizeof(hostaddress));
+ } else {
+ memset(&hostaddress, 0, sizeof(hostaddress));
+ }
+ }
+ break;
+
+ case 'p':
+ pflag = 1;
+ break;
+
+ case '?':
+ default:
+ fprintf(stderr,
+ "usage: login [-fp] [username]\n");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+ if (*argv) {
+ username = *argv;
+ ask = 0;
+ } else
+ ask = 1;
+
+#ifndef __linux__
+ ioctlval = 0;
+ ioctl(0, TIOCLSET, &ioctlval);
+ ioctl(0, TIOCNXCL, 0);
+ fcntl(0, F_SETFL, ioctlval);
+ ioctl(0, TIOCGETP, &sgttyb);
+ sgttyb.sg_erase = CERASE;
+ sgttyb.sg_kill = CKILL;
+ ioctl(0, TIOCSLTC, &ltc);
+ ioctl(0, TIOCSETC, &tc);
+ ioctl(0, TIOCSETP, &sgttyb);
+
+ /*
+ * Be sure that we're in
+ * blocking mode!!!
+ * This is really for HPUX
+ */
+ ioctlval = 0;
+ ioctl(0, FIOSNBIO, &ioctlval);
#endif
-
- for (cnt = getdtablesize(); cnt > 2; cnt--)
- close(cnt);
-
- ttyn = ttyname(0);
- if (ttyn == NULL || *ttyn == '\0') {
- (void)sprintf(tname, "%s??", _PATH_TTY);
- ttyn = tname;
+
+ for (cnt = getdtablesize(); cnt > 2; cnt--)
+ close(cnt);
+
+ ttyn = ttyname(0);
+ if (ttyn == NULL || *ttyn == '\0') {
+ snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
+ ttyn = tname;
+ }
+
+ /* find names of Virtual Console devices, for later mode change */
+ {
+ char *p = ttyn;
+ /* find number of tty */
+ while (*p && !isdigit(*p)) p++;
+
+ strcpy(vcsn, "/dev/vcs"); strcat(vcsn, p);
+ strcpy(vcsan, "/dev/vcsa"); strcat(vcsan, p);
+ }
+
+ setpgrp();
+
+ {
+ struct termios tt, ttt;
+
+ tcgetattr(0, &tt);
+ ttt = tt;
+ ttt.c_cflag &= ~HUPCL;
+
+ if((chown(ttyn, 0, 0) == 0) && (chmod(ttyn, 0622) == 0)) {
+ tcsetattr(0,TCSAFLUSH,&ttt);
+ signal(SIGHUP, SIG_IGN); /* so vhangup() wont kill us */
+ vhangup();
+ signal(SIGHUP, SIG_DFL);
}
+
+ setsid();
+
+ /* re-open stdin,stdout,stderr after vhangup() closed them */
+ /* if it did, after 0.99.5 it doesn't! */
+ opentty(ttyn);
+ tcsetattr(0,TCSAFLUSH,&tt);
+ }
+
+ if ((tty = rindex(ttyn, '/')))
+ ++tty;
+ else
+ tty = ttyn;
+
+ openlog("login", LOG_ODELAY, LOG_AUTHPRIV);
+
+#ifdef USE_PAM
+ /* username is initialized to NULL
+ and if specified on the command line it is set.
+ Therefore, we are safe not setting it to anything
+ */
+
+ retcode = pam_start("login",username, &conv, &pamh);
+ if(retcode != PAM_SUCCESS) {
+ fprintf(stderr,"login: PAM Failure, aborting: %s\n",
+ pam_strerror(retcode));
+ syslog(LOG_ERR,"Couldn't initialize PAM: %s", pam_strerror(retcode));
+ exit(99);
+ }
+ /* hostname & tty are either set to NULL or their correct values,
+ depending on how much we know */
+ retcode = pam_set_item(pamh, PAM_RHOST, hostname);
+ PAM_FAIL_CHECK;
+ retcode = pam_set_item(pamh, PAM_TTY, tty);
+ PAM_FAIL_CHECK;
+ /* if fflag == 1, then the user has already been authenticated */
+ if (fflag && (getuid() == 0))
+ passwd_req = 0;
+ else
+ passwd_req = 1;
- setpgrp();
-
- {
- struct termios tt, ttt;
-
- tcgetattr(0, &tt);
- ttt = tt;
- ttt.c_cflag &= ~HUPCL;
-
- if((chown(ttyn, 0, 0) == 0) && (chmod(ttyn, 0622) == 0)) {
- tcsetattr(0,TCSAFLUSH,&ttt);
- signal(SIGHUP, SIG_IGN); /* so vhangup() wont kill us */
- vhangup();
- signal(SIGHUP, SIG_DFL);
- }
-
- setsid();
-
- /* re-open stdin,stdout,stderr after vhangup() closed them */
- /* if it did, after 0.99.5 it doesn't! */
- opentty(ttyn);
- tcsetattr(0,TCSAFLUSH,&tt);
+ if(passwd_req == 1) {
+ int failcount=0;
+
+ /* there may be better ways to deal with some of these
+ conditions, but at least this way I don't think we'll
+ be giving away information... */
+ /* Perhaps someday we can trust that all PAM modules will
+ pay attention to failure count and get rid of MAX_LOGIN_TRIES? */
+
+ retcode = pam_authenticate(pamh, 0);
+ while((failcount++ < PAM_MAX_LOGIN_TRIES) &&
+ ((retcode == PAM_AUTH_ERR) ||
+ (retcode == PAM_USER_UNKNOWN) ||
+ (retcode == PAM_CRED_INSUFFICIENT) ||
+ (retcode == PAM_AUTHINFO_UNAVAIL))) {
+ pam_get_item(pamh, PAM_USER, (const void **) &username);
+ syslog(LOG_NOTICE,"FAILED LOGIN %d FROM %s FOR %s, %s",
+ failcount, hostname,username,pam_strerror(retcode));
+ fprintf(stderr,"Login incorrect\n\n");
+ pam_set_item(pamh,PAM_USER,NULL);
+ retcode = pam_authenticate(pamh, 0);
}
- if ((tty = rindex(ttyn, '/')))
- ++tty;
- else
- tty = ttyn;
-
- openlog("login", LOG_ODELAY, LOG_AUTH);
-
- for (cnt = 0;; ask = 1) {
- ioctlval = 0;
-#ifndef linux
- (void)ioctl(0, TIOCSETD, &ioctlval);
-#endif
+ if (retcode != PAM_SUCCESS) {
+ pam_get_item(pamh, PAM_USER, (const void **) &username);
- if (ask) {
- fflag = 0;
- getloginname();
- }
-
- /* Dirty patch to fix a gigantic security hole when using
- yellow pages. This problem should be solved by the
- libraries, and not by programs, but this must be fixed
- urgently! If the first char of the username is '+', we
- avoid login success.
- Feb 95 <alvaro@etsit.upm.es> */
-
- if (username[0] == '+') {
- puts("Illegal username");
- badlogin(username);
- sleepexit(1);
- }
+ if (retcode == PAM_MAXTRIES)
+ syslog(LOG_NOTICE,"TOO MANY LOGIN TRIES (%d) FROM %s FOR "
+ "%s, %s", failcount, hostname, username,
+ pam_strerror(retcode));
+ else
+ syslog(LOG_NOTICE,"FAILED LOGIN SESSION FROM %s FOR %s, %s",
+ hostname, username, pam_strerror(retcode));
- (void)strcpy(tbuf, username);
- if ((pwd = getpwnam(username)))
- salt = pwd->pw_passwd;
- else
- salt = "xx";
-
- checktty(username, tty, pwd); /* in checktty.c */
+ fprintf(stderr,"\nLogin incorrect\n");
+ pam_end(pamh, retcode);
+ exit(0);
+ }
- /* if user not super-user, check for disabled logins */
- if (pwd == NULL || pwd->pw_uid)
- checknologin();
+ retcode = pam_acct_mgmt(pamh, 0);
- /*
- * Disallow automatic login to root; if not invoked by
- * root, disallow if the uid's differ.
- */
- if (fflag && pwd) {
- int uid = getuid();
+ if(retcode == PAM_AUTHTOKEN_REQD) {
+ retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+ }
- passwd_req = pwd->pw_uid == 0 ||
- (uid && uid != pwd->pw_uid);
- }
+ PAM_FAIL_CHECK;
+ }
- /*
- * If trying to log in as root, but with insecure terminal,
- * refuse the login attempt.
- */
- if (pwd && pwd->pw_uid == 0 && !rootterm(tty)) {
- (void)fprintf(stderr,
- "%s login refused on this terminal.\n",
- pwd->pw_name);
-
- if (hostname)
- syslog(LOG_NOTICE,
- "LOGIN %s REFUSED FROM %s ON TTY %s",
- pwd->pw_name, hostname, tty);
- else
- syslog(LOG_NOTICE,
- "LOGIN %s REFUSED ON TTY %s",
- pwd->pw_name, tty);
- continue;
- }
+ /* Grab the user information out of the password file for future usage
+ First get the username that we are actually using, though.
+ */
+ retcode = pam_get_item(pamh, PAM_USER, (const void **) &username);
+ setpwent();
+ pwd = getpwnam(username);
+ if (pwd) initgroups(username, pwd->pw_gid);
- /*
- * If no pre-authentication and a password exists
- * for this user, prompt for one and verify it.
- */
- if (!passwd_req || (pwd && !*pwd->pw_passwd))
- break;
+ retcode = pam_setcred(pamh, PAM_CRED_ESTABLISH);
+ PAM_FAIL_CHECK;
- setpriority(PRIO_PROCESS, 0, -4);
- pp = getpass("Password: ");
- p = crypt(pp, salt);
- setpriority(PRIO_PROCESS, 0, 0);
+ retcode = pam_open_session(pamh, 0);
+ PAM_FAIL_CHECK;
-#ifdef KERBEROS
+#else /* ! USE_PAM */
- /*
- * If not present in pw file, act as we normally would.
- * If we aren't Kerberos-authenticated, try the normal
- * pw file for a password. If that's ok, log the user
- * in without issueing any tickets.
- */
-
- if (pwd && !krb_get_lrealm(realm,1)) {
- /*
- * get TGT for local realm; be careful about uid's
- * here for ticket file ownership
- */
- (void)setreuid(geteuid(),pwd->pw_uid);
- kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm,
- "krbtgt", realm, DEFAULT_TKT_LIFE, pp);
- (void)setuid(0);
- if (kerror == INTK_OK) {
- memset(pp, 0, strlen(pp));
- notickets = 0; /* user got ticket */
- break;
- }
- }
-#endif
- (void) memset(pp, 0, strlen(pp));
- if (pwd && !strcmp(p, pwd->pw_passwd))
- break;
-
- (void)printf("Login incorrect\n");
- failures++;
- badlogin(username); /* log ALL bad logins */
-
- /* we allow 10 tries, but after 3 we start backing off */
- if (++cnt > 3) {
- if (cnt >= 10) {
- sleepexit(1);
- }
- sleep((unsigned int)((cnt - 3) * 5));
- }
+ for (cnt = 0;; ask = 1) {
+ ioctlval = 0;
+# ifndef __linux__
+ ioctl(0, TIOCSETD, &ioctlval);
+# endif
+
+ if (ask) {
+ fflag = 0;
+ getloginname();
}
+
+ /* Dirty patch to fix a gigantic security hole when using
+ yellow pages. This problem should be solved by the
+ libraries, and not by programs, but this must be fixed
+ urgently! If the first char of the username is '+', we
+ avoid login success.
+ Feb 95 <alvaro@etsit.upm.es> */
+
+ if (username[0] == '+') {
+ puts("Illegal username");
+ badlogin(username);
+ sleepexit(1);
+ }
+
+ /* (void)strcpy(tbuf, username); why was this here? */
+ if ((pwd = getpwnam(username))) {
+# ifdef SHADOW_PWD
+ struct spwd *sp;
+
+ if ((sp = getspnam(username)))
+ pwd->pw_passwd = sp->sp_pwdp;
+# endif
+ salt = pwd->pw_passwd;
+ } else
+ salt = "xx";
+
+ if (pwd) {
+ initgroups(username, pwd->pw_gid);
+ checktty(username, tty, pwd); /* in checktty.c */
+ }
+
+ /* if user not super-user, check for disabled logins */
+ if (pwd == NULL || pwd->pw_uid)
+ checknologin();
+
+ /*
+ * Disallow automatic login to root; if not invoked by
+ * root, disallow if the uid's differ.
+ */
+ if (fflag && pwd) {
+ int uid = getuid();
+
+ passwd_req = pwd->pw_uid == 0 ||
+ (uid && uid != pwd->pw_uid);
+ }
+
+ /*
+ * If trying to log in as root, but with insecure terminal,
+ * refuse the login attempt.
+ */
+ if (pwd && pwd->pw_uid == 0 && !rootterm(tty)) {
+ fprintf(stderr,
+ "%s login refused on this terminal.\n",
+ pwd->pw_name);
+
+ if (hostname)
+ syslog(LOG_NOTICE,
+ "LOGIN %s REFUSED FROM %s ON TTY %s",
+ pwd->pw_name, hostname, tty);
+ else
+ syslog(LOG_NOTICE,
+ "LOGIN %s REFUSED ON TTY %s",
+ pwd->pw_name, tty);
+ continue;
+ }
+
+ /*
+ * If no pre-authentication and a password exists
+ * for this user, prompt for one and verify it.
+ */
+ if (!passwd_req || (pwd && !*pwd->pw_passwd))
+ break;
+
+ setpriority(PRIO_PROCESS, 0, -4);
+ pp = getpass("Password: ");
+
+# ifdef CRYPTOCARD
+ if (strncmp(pp, "CRYPTO", 6) == 0) {
+ if (pwd && cryptocard()) break;
+ }
+# endif /* CRYPTOCARD */
+
+ p = crypt(pp, salt);
+ setpriority(PRIO_PROCESS, 0, 0);
- /* committed to login -- turn off timeout */
- (void)alarm((unsigned int)0);
-
+# ifdef KERBEROS
+ /*
+ * If not present in pw file, act as we normally would.
+ * If we aren't Kerberos-authenticated, try the normal
+ * pw file for a password. If that's ok, log the user
+ * in without issueing any tickets.
+ */
+
+ if (pwd && !krb_get_lrealm(realm,1)) {
+ /*
+ * get TGT for local realm; be careful about uid's
+ * here for ticket file ownership
+ */
+ setreuid(geteuid(),pwd->pw_uid);
+ kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm,
+ "krbtgt", realm, DEFAULT_TKT_LIFE, pp);
+ setuid(0);
+ if (kerror == INTK_OK) {
+ memset(pp, 0, strlen(pp));
+ notickets = 0; /* user got ticket */
+ break;
+ }
+ }
+# endif /* KERBEROS */
+ memset(pp, 0, strlen(pp));
+ if (pwd && !strcmp(p, pwd->pw_passwd))
+ break;
+
+ printf("Login incorrect\n");
+ badlogin(username); /* log ALL bad logins */
+ failures++;
+
+ /* we allow 10 tries, but after 3 we start backing off */
+ if (++cnt > 3) {
+ if (cnt >= 10) {
+ sleepexit(1);
+ }
+ sleep((unsigned int)((cnt - 3) * 5));
+ }
+ }
+#endif /* !USE_PAM */
+
+ /* committed to login -- turn off timeout */
+ alarm((unsigned int)0);
+
#ifdef HAVE_QUOTA
- if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
- switch(errno) {
- case EUSERS:
- (void)fprintf(stderr,
- "Too many users logged on already.\nTry again later.\n");
- break;
- case EPROCLIM:
- (void)fprintf(stderr,
- "You have too many processes running.\n");
- break;
- default:
- perror("quota (Q_SETUID)");
- }
- sleepexit(0);
+ if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
+ switch(errno) {
+ case EUSERS:
+ fprintf(stderr,
+ "Too many users logged on already.\nTry again later.\n");
+ break;
+ case EPROCLIM:
+ fprintf(stderr,
+ "You have too many processes running.\n");
+ break;
+ default:
+ perror("quota (Q_SETUID)");
}
+ sleepexit(0);
+ }
#endif
+
+ /* paranoia... */
+#ifdef SHADOW_PWD
+ endspent();
+#endif
+ endpwent();
+
+ /* This requires some explanation: As root we may not be able to
+ read the directory of the user if it is on an NFS mounted
+ filesystem. We temporarily set our effective uid to the user-uid
+ making sure that we keep root privs. in the real uid.
+
+ A portable solution would require a fork(), but we rely on Linux
+ having the BSD setreuid() */
+
+ {
+ char tmpstr[MAXPATHLEN];
+ uid_t ruid = getuid();
+ gid_t egid = getegid();
+
+ snprintf(tmpstr, sizeof(tmpstr),
+ "%s/%s", pwd->pw_dir, _PATH_HUSHLOGIN);
+
+ setregid(-1, pwd->pw_gid);
+ setreuid(0, pwd->pw_uid);
+ quietlog = (access(tmpstr, R_OK) == 0);
+ setuid(0); /* setreuid doesn't do it alone! */
+ setreuid(ruid, 0);
+ setregid(-1, egid);
+ }
+
+#ifndef __linux__
+# ifdef KERBEROS
+ if (notickets && !quietlog)
+ printf("Warning: no Kerberos tickets issued\n");
+# endif
+
+# ifndef USE_PAM /* PAM does all of this for us */
+# define TWOWEEKS (14*24*60*60)
+ if (pwd->pw_change || pwd->pw_expire) {
+ struct timeval tp;
- /* paranoia... */
- endpwent();
-
- /* This requires some explanation: As root we may not be able to
- read the directory of the user if it is on an NFS mounted
- filesystem. We temporarily set our effective uid to the user-uid
- making sure that we keep root privs. in the real uid.
-
- A portable solution would require a fork(), but we rely on Linux
- having the BSD setreuid() */
-
- {
- char tmpstr[MAXPATHLEN];
- uid_t ruid = getuid();
- gid_t egid = getegid();
-
- strncpy(tmpstr, pwd->pw_dir, MAXPATHLEN-12);
- strncat(tmpstr, ("/" _PATH_HUSHLOGIN), MAXPATHLEN);
+ gettimeofday(&tp, (struct timezone *)NULL);
- setregid(-1, pwd->pw_gid);
- setreuid(0, pwd->pw_uid);
- quietlog = (access(tmpstr, R_OK) == 0);
- setuid(0); /* setreuid doesn't do it alone! */
- setreuid(ruid, 0);
- setregid(-1, egid);
+ if (pwd->pw_change) {
+ if (tp.tv_sec >= pwd->pw_change) {
+ printf("Sorry -- your password has expired.\n");
+ sleepexit(1);
+ }
+ else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) {
+ struct tm *ttp;
+ ttp = localtime(&pwd->pw_change);
+ printf("Warning: your password expires on %s %d, %d\n",
+ months[ttp->tm_mon], ttp->tm_mday,
+ TM_YEAR_BASE + ttp->tm_year);
+ }
}
-#ifndef linux
-#ifdef KERBEROS
- if (notickets && !quietlog)
- (void)printf("Warning: no Kerberos tickets issued\n");
-#endif
-
-#define TWOWEEKS (14*24*60*60)
- if (pwd->pw_change || pwd->pw_expire)
- (void)gettimeofday(&tp, (struct timezone *)NULL);
- if (pwd->pw_change)
- if (tp.tv_sec >= pwd->pw_change) {
- (void)printf("Sorry -- your password has expired.\n");
- sleepexit(1);
- }
- else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) {
- ttp = localtime(&pwd->pw_change);
- (void)printf("Warning: your password expires on %s %d, %d\n",
- months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year);
- }
- if (pwd->pw_expire)
- if (tp.tv_sec >= pwd->pw_expire) {
- (void)printf("Sorry -- your account has expired.\n");
- sleepexit(1);
- }
- else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) {
- ttp = localtime(&pwd->pw_expire);
- (void)printf("Warning: your account expires on %s %d, %d\n",
- months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year);
- }
-
- /* nothing else left to fail -- really log in */
- {
- struct utmp utmp;
-
- memset((char *)&utmp, 0, sizeof(utmp));
- (void)time(&utmp.ut_time);
- strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
- if (hostname)
- strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
- strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
- login(&utmp);
+ if (pwd->pw_expire) {
+ if (tp.tv_sec >= pwd->pw_expire) {
+ printf("Sorry -- your account has expired.\n");
+ sleepexit(1);
+ }
+ else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) {
+ struct tm *ttp;
+ ttp = localtime(&pwd->pw_expire);
+ printf("Warning: your account expires on %s %d, %d\n",
+ months[ttp->tm_mon], ttp->tm_mday,
+ TM_YEAR_BASE + ttp->tm_year);
+ }
+ }
+ }
+# endif /* !USE_PAM */
+
+ /* nothing else left to fail -- really log in */
+ {
+ struct utmp utmp;
+
+ memset((char *)&utmp, 0, sizeof(utmp));
+ time(&utmp.ut_time);
+ strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
+ /* ut_name may legally be non-null-terminated */
+ if (hostname) {
+ strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
+ utmp.ut_host[sizeof(utmp.ut_host)-1] = 0;
}
+ strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
+ utmp.ut_line[sizeof(utmp.ut_line)-1] = 0;
+ login(&utmp);
+ }
#else
- /* for linux, write entries in utmp and wtmp */
- {
- struct utmp ut;
- int wtmp;
- struct utmp *utp;
- pid_t mypid = getpid();
-
- utmpname(_PATH_UTMP);
- setutent();
- while ((utp = getutent())
- && !(utp->ut_pid == mypid)) /* nothing */;
-
- if (utp) {
- memcpy(&ut, utp, sizeof(ut));
- } else {
- /* some gettys/telnetds don't initialize utmp... */
- memset(&ut, 0, sizeof(ut));
- }
- endutent();
-
- if (ut.ut_id[0] == 0)
- strncpy(ut.ut_id, ttyn + 8, sizeof(ut.ut_id));
-
- strncpy(ut.ut_user, username, sizeof(ut.ut_user));
- strncpy(ut.ut_line, ttyn + 5, sizeof(ut.ut_line));
- time(&ut.ut_time);
- ut.ut_type = USER_PROCESS;
- ut.ut_pid = mypid;
- if (hostname) {
- strncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
- if (hostaddress.h_addr_list)
- memcpy(&ut.ut_addr, hostaddress.h_addr_list[0],
- sizeof(ut.ut_addr));
- }
-
- pututline(&ut);
- endutent();
-
- if((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
- flock(wtmp, LOCK_EX);
- write(wtmp, (char *)&ut, sizeof(ut));
- flock(wtmp, LOCK_UN);
- close(wtmp);
- }
+ /* for linux, write entries in utmp and wtmp */
+ {
+ struct utmp ut;
+ int wtmp;
+ struct utmp *utp;
+ time_t t;
+ pid_t mypid = getpid();
+
+ utmpname(_PATH_UTMP);
+ setutent();
+ while ((utp = getutent())
+ && !(utp->ut_pid == mypid)) /* nothing */;
+
+ if (utp) {
+ memcpy(&ut, utp, sizeof(ut));
+ } else {
+ /* some gettys/telnetds don't initialize utmp... */
+ memset(&ut, 0, sizeof(ut));
}
-#endif
-
- dolastlog(quietlog);
+ /* endutent(); superfluous, error for glibc */
-#ifndef linux
- if (!hflag) { /* XXX */
- static struct winsize win = { 0, 0, 0, 0 };
-
- (void)ioctl(0, TIOCSWINSZ, &win);
+ if (ut.ut_id[0] == 0)
+ strncpy(ut.ut_id, ttyn + 8, sizeof(ut.ut_id));
+
+ strncpy(ut.ut_user, username, sizeof(ut.ut_user));
+ strncpy(ut.ut_line, ttyn + 5, sizeof(ut.ut_line));
+ ut.ut_line[sizeof(ut.ut_line)-1] = 0;
+ time(&t);
+ ut.ut_time = t; /* ut_time is not always a time_t */
+ /* (we might test #ifdef _HAVE_UT_TV ) */
+ ut.ut_type = USER_PROCESS;
+ ut.ut_pid = mypid;
+ if (hostname) {
+ strncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
+ ut.ut_host[sizeof(ut.ut_host)-1] = 0;
+ if (hostaddress.h_addr_list)
+ memcpy(&ut.ut_addr, hostaddress.h_addr_list[0],
+ sizeof(ut.ut_addr));
}
+
+ pututline(&ut);
+ endutent();
+
+ {
+ int lf;
+ if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
+ flock(lf, LOCK_EX);
+ if ((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
+ write(wtmp, (char *)&ut, sizeof(ut));
+ close(wtmp);
+ }
+ flock(lf, LOCK_UN);
+ close(lf);
+ }
+ }
+ }
#endif
- (void)chown(ttyn, pwd->pw_uid,
- (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
-
-#ifdef USE_TTY_GROUP
- chmod(ttyn, 0620);
-#else
- chmod(ttyn, 0600);
+
+ dolastlog(quietlog);
+
+#ifndef __linux__
+ if (!hflag) { /* XXX */
+ static struct winsize win = { 0, 0, 0, 0 };
+
+ ioctl(0, TIOCSWINSZ, &win);
+ }
#endif
-
- setgid(pwd->pw_gid);
- initgroups(username, pwd->pw_gid);
-
+ chown(ttyn, pwd->pw_uid,
+ (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
+ chmod(ttyn, TTY_MODE);
+
+ /* if tty is one of the VC's then change owner and mode of the
+ special /dev/vcs devices as well */
+ if (consoletty(0)) {
+ chown(vcsn, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid));
+ chown(vcsan, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid));
+ chmod(vcsn, TTY_MODE);
+ chmod(vcsan, TTY_MODE);
+ }
+
+ setgid(pwd->pw_gid);
+
#ifdef HAVE_QUOTA
- quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
+ quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
#endif
-
- if (*pwd->pw_shell == '\0')
- pwd->pw_shell = _PATH_BSHELL;
-#ifndef linux
- /* turn on new line discipline for the csh */
- else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) {
- ioctlval = NTTYDISC;
- (void)ioctl(0, TIOCSETD, &ioctlval);
- }
+
+ if (*pwd->pw_shell == '\0')
+ pwd->pw_shell = _PATH_BSHELL;
+#ifndef __linux__
+ /* turn on new line discipline for the csh */
+ else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) {
+ ioctlval = NTTYDISC;
+ ioctl(0, TIOCSETD, &ioctlval);
+ }
#endif
-
- /* preserve TERM even without -p flag */
- {
- char *ep;
-
- if(!((ep = getenv("TERM")) && (termenv = strdup(ep))))
- termenv = "dumb";
- }
-
- /* destroy environment unless user has requested preservation */
- if (!pflag)
- {
+
+ /* preserve TERM even without -p flag */
+ {
+ char *ep;
+
+ if(!((ep = getenv("TERM")) && (termenv = strdup(ep))))
+ termenv = "dumb";
+ }
+
+ /* destroy environment unless user has requested preservation */
+ if (!pflag)
+ {
environ = (char**)malloc(sizeof(char*));
memset(environ, 0, sizeof(char*));
- }
-
-#ifndef linux
- (void)setenv("HOME", pwd->pw_dir, 1);
- (void)setenv("SHELL", pwd->pw_shell, 1);
- if (term[0] == '\0')
- strncpy(term, stypeof(tty), sizeof(term));
- (void)setenv("TERM", term, 0);
- (void)setenv("USER", pwd->pw_name, 1);
- (void)setenv("PATH", _PATH_DEFPATH, 0);
+ }
+
+#ifndef __linux__
+ setenv("HOME", pwd->pw_dir, 1);
+ setenv("SHELL", pwd->pw_shell, 1);
+ if (term[0] == '\0') {
+ strncpy(term, stypeof(tty), sizeof(term));
+ term[sizeof(term)-1] = 0;
+ }
+ setenv("TERM", term, 0);
+ setenv("USER", pwd->pw_name, 1);
+ setenv("PATH", _PATH_DEFPATH, 0);
#else
- (void)setenv("HOME", pwd->pw_dir, 0); /* legal to override */
- if(pwd->pw_uid)
- (void)setenv("PATH", _PATH_DEFPATH, 1);
- else
- (void)setenv("PATH", _PATH_DEFPATH_ROOT, 1);
- (void)setenv("SHELL", pwd->pw_shell, 1);
- (void)setenv("TERM", termenv, 1);
-
- /* mailx will give a funny error msg if you forget this one */
- (void)sprintf(tmp,"%s/%s",_PATH_MAILDIR,pwd->pw_name);
- (void)setenv("MAIL",tmp,0);
-
- /* LOGNAME is not documented in login(1) but
- HP-UX 6.5 does it. We'll not allow modifying it.
- */
- (void)setenv("LOGNAME", pwd->pw_name, 1);
+ setenv("HOME", pwd->pw_dir, 0); /* legal to override */
+ if(pwd->pw_uid)
+ setenv("PATH", _PATH_DEFPATH, 1);
+ else
+ setenv("PATH", _PATH_DEFPATH_ROOT, 1);
+
+ setenv("SHELL", pwd->pw_shell, 1);
+ setenv("TERM", termenv, 1);
+
+ /* mailx will give a funny error msg if you forget this one */
+ snprintf(tmp, sizeof(tmp), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
+ setenv("MAIL",tmp,0);
+
+ /* LOGNAME is not documented in login(1) but
+ HP-UX 6.5 does it. We'll not allow modifying it.
+ */
+ setenv("LOGNAME", pwd->pw_name, 1);
#endif
- if (tty[sizeof("tty")-1] == 'S')
- syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
-
- if (pwd->pw_uid == 0)
- if (hostname)
- syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s",
- tty, hostname);
- else
- syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty);
-
- if (!quietlog) {
- struct stat st;
-
- motd();
- (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
- if (stat(tbuf, &st) == 0 && st.st_size != 0)
- (void)printf("You have %smail.\n",
- (st.st_mtime > st.st_atime) ? "new " : "");
- }
+#ifdef USE_PAM
+ {
+ int i;
+ const char * const * env;
- (void)signal(SIGALRM, SIG_DFL);
- (void)signal(SIGQUIT, SIG_DFL);
- (void)signal(SIGINT, SIG_DFL);
- (void)signal(SIGTSTP, SIG_IGN);
- (void)signal(SIGHUP, SIG_DFL);
+ env = (const char * const *)pam_getenvlist(pamh);
- /* discard permissions last so can't get killed and drop core */
- if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) {
- syslog(LOG_ALERT, "setuid() failed");
- exit(1);
+ if (env != NULL) {
+ for (i=0; env[i++]; ) {
+ putenv(env[i-1]);
+ /* D(("env[%d] = %s", i-1,env[i-1])); */
+ }
}
-
- /* wait until here to change directory! */
- if (chdir(pwd->pw_dir) < 0) {
- (void)printf("No directory %s!\n", pwd->pw_dir);
- if (chdir("/"))
- exit(0);
- pwd->pw_dir = "/";
- (void)printf("Logging in with home = \"/\".\n");
+ }
+#endif
+
+ if (tty[sizeof("tty")-1] == 'S')
+ syslog(LOG_INFO, "DIALUP AT %s BY %s", tty, pwd->pw_name);
+
+ /* allow tracking of good logins.
+ -steve philp (sphilp@mail.alliance.net) */
+
+ if (pwd->pw_uid == 0) {
+ if (hostname)
+ syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s",
+ tty, hostname);
+ else
+ syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty);
+ } else {
+ if (hostname)
+ syslog(LOG_INFO, "LOGIN ON %s BY %s FROM %s", tty,
+ pwd->pw_name, hostname);
+ else
+ syslog(LOG_INFO, "LOGIN ON %s BY %s", tty,
+ pwd->pw_name);
+ }
+
+ if (!quietlog) {
+ struct stat st;
+
+ motd();
+ snprintf(tbuf, sizeof(tbuf),
+ "%s/%s", _PATH_MAILDIR, pwd->pw_name);
+ if (stat(tbuf, &st) == 0 && st.st_size != 0)
+ printf("You have %smail.\n",
+ (st.st_mtime > st.st_atime) ? "new " : "");
+ }
+
+ signal(SIGALRM, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGHUP, SIG_DFL);
+
+ /* discard permissions last so can't get killed and drop core */
+ if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) {
+ syslog(LOG_ALERT, "setuid() failed");
+#ifdef USE_PAM
+ PAM_END;
+#endif
+ exit(1);
+ }
+
+ /* wait until here to change directory! */
+ if (chdir(pwd->pw_dir) < 0) {
+ printf("No directory %s!\n", pwd->pw_dir);
+ if (chdir("/")) {
+#ifdef USE_PAM
+ PAM_END;
+#endif
+ exit(0);
}
-
- /* if the shell field has a space: treat it like a shell script */
- if (strchr(pwd->pw_shell, ' ')) {
- char *buff = malloc(strlen(pwd->pw_shell) + 6);
- if (buff) {
- strcpy(buff, "exec ");
- strcat(buff, pwd->pw_shell);
- execlp("/bin/sh", "-sh", "-c", buff, (char *)0);
- fprintf(stderr, "login: couldn't exec shell script: %s.\n",
- strerror(errno));
- exit(0);
- }
+ pwd->pw_dir = "/";
+ printf("Logging in with home = \"/\".\n");
+ }
+
+ /* if the shell field has a space: treat it like a shell script */
+ if (strchr(pwd->pw_shell, ' ')) {
+ buff = malloc(strlen(pwd->pw_shell) + 6);
+
+ if (!buff) {
fprintf(stderr, "login: no memory for shell script.\n");
exit(0);
}
+ strcpy(buff, "exec ");
+ strcat(buff, pwd->pw_shell);
+ childArgv[childArgc++] = "/bin/sh";
+ childArgv[childArgc++] = "-sh";
+ childArgv[childArgc++] = "-c";
+ childArgv[childArgc++] = buff;
+ } else {
tbuf[0] = '-';
- strcpy(tbuf + 1, ((p = rindex(pwd->pw_shell, '/')) ?
- p + 1 : pwd->pw_shell));
-
- execlp(pwd->pw_shell, tbuf, (char *)0);
- (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno));
+ strncpy(tbuf + 1, ((p = rindex(pwd->pw_shell, '/')) ?
+ p + 1 : pwd->pw_shell),
+ sizeof(tbuf)-1);
+ tbuf[sizeof(tbuf)-1] = 0;
+
+ childArgv[childArgc++] = pwd->pw_shell;
+ childArgv[childArgc++] = tbuf;
+ }
+
+ childArgv[childArgc++] = NULL;
+
+#ifndef USE_PAM
+ execvp(childArgv[0], childArgv + 1);
+ error = 1;
+#else /* USE_PAM */
+ oldSigHandler = signal(SIGINT, SIG_IGN);
+ childPid = fork();
+ if (childPid < 0) {
+ /* error in fork() */
+ fprintf(stderr,"login: failure forking: %s", strerror(errno));
+ PAM_END;
exit(0);
+ } else if (childPid) {
+ /* parent */
+ wait(&childStatus);
+ signal(SIGINT, oldSigHandler);
+ PAM_END;
+
+ if (!WIFEXITED(&childStatus)) error = 1;
+ } else {
+ /* child */
+ execvp(childArgv[0], childArgv + 1);
+ exit(1);
+ }
+#endif /* USE_PAM */
+
+ if (error) {
+ if (!strcmp(childArgv[0], "/bin/sh"))
+ fprintf(stderr, "login: couldn't exec shell script: %s.\n",
+ strerror(errno));
+ else
+ fprintf(stderr, "login: no shell: %s.\n", strerror(errno));
+ }
+
+ exit(0);
}
void
getloginname()
{
- register int ch;
- register char *p;
- static char nbuf[UT_NAMESIZE + 1];
- int cnt, cnt2;
-
- cnt2 = 0;
- for (;;) {
- cnt = 0;
- (void)printf("\n%s login: ", thishost); fflush(stdout);
- for (p = nbuf; (ch = getchar()) != '\n'; ) {
- if (ch == EOF) {
- badlogin("EOF");
- exit(0);
- }
- if (p < nbuf + UT_NAMESIZE)
- *p++ = ch;
-
- cnt++;
- if (cnt > UT_NAMESIZE + 20) {
- fprintf(stderr, "login name much too long.\n");
- badlogin("NAME too long");
- exit(0);
- }
- }
- if (p > nbuf)
- if (nbuf[0] == '-')
- (void)fprintf(stderr,
- "login names may not start with '-'.\n");
- else {
- *p = '\0';
- username = nbuf;
- break;
- }
-
- cnt2++;
- if (cnt2 > 50) {
- fprintf(stderr, "too many bare linefeeds.\n");
- badlogin("EXCESSIVE linefeeds");
- exit(0);
- }
+ register int ch;
+ register char *p;
+ static char nbuf[UT_NAMESIZE + 1];
+ int cnt, cnt2;
+
+ cnt2 = 0;
+ for (;;) {
+ cnt = 0;
+ printf("\n%s login: ", thishost); fflush(stdout);
+ for (p = nbuf; (ch = getchar()) != '\n'; ) {
+ if (ch == EOF) {
+ badlogin("EOF");
+ exit(0);
+ }
+ if (p < nbuf + UT_NAMESIZE)
+ *p++ = ch;
+
+ cnt++;
+ if (cnt > UT_NAMESIZE + 20) {
+ fprintf(stderr, "login name much too long.\n");
+ badlogin("NAME too long");
+ exit(0);
+ }
+ }
+ if (p > nbuf)
+ if (nbuf[0] == '-')
+ fprintf(stderr,
+ "login names may not start with '-'.\n");
+ else {
+ *p = '\0';
+ username = nbuf;
+ break;
+ }
+
+ cnt2++;
+ if (cnt2 > 50) {
+ fprintf(stderr, "too many bare linefeeds.\n");
+ badlogin("EXCESSIVE linefeeds");
+ exit(0);
}
+ }
}
-void timedout()
+void
+timedout()
{
- struct termio ti;
-
- (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
-
- /* reset echo */
- (void) ioctl(0, TCGETA, &ti);
- ti.c_lflag |= ECHO;
- (void) ioctl(0, TCSETA, &ti);
- exit(0);
+ struct termio ti;
+
+ fprintf(stderr, "Login timed out after %d seconds\n", timeout);
+
+ /* reset echo */
+ ioctl(0, TCGETA, &ti);
+ ti.c_lflag |= ECHO;
+ ioctl(0, TCSETA, &ti);
+ exit(0);
}
int
rootterm(ttyn)
- char *ttyn;
-#ifndef linux
+ char *ttyn;
+#ifndef __linux__
{
- struct ttyent *t;
-
- return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE);
+ struct ttyent *t;
+
+ return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE);
}
#else
{
- int fd;
- char buf[100],*p;
- int cnt, more;
-
- fd = open(SECURETTY, O_RDONLY);
- if(fd < 0) return 1;
-
- /* read each line in /etc/securetty, if a line matches our ttyline
- then root is allowed to login on this tty, and we should return
- true. */
- for(;;) {
+ int fd;
+ char buf[100],*p;
+ int cnt, more;
+
+ fd = open(SECURETTY, O_RDONLY);
+ if(fd < 0) return 1;
+
+ /* read each line in /etc/securetty, if a line matches our ttyline
+ then root is allowed to login on this tty, and we should return
+ true. */
+ for(;;) {
p = buf; cnt = 100;
while(--cnt >= 0 && (more = read(fd, p, 1)) == 1 && *p != '\n') p++;
if(more && *p == '\n') {
- *p = '\0';
- if(!strcmp(buf, ttyn)) {
- close(fd);
- return 1;
- } else
- continue;
+ *p = '\0';
+ if(!strcmp(buf, ttyn)) {
+ close(fd);
+ return 1;
+ } else
+ continue;
} else {
- close(fd);
- return 0;
+ close(fd);
+ return 0;
}
- }
+ }
}
#endif
@@ -878,121 +1174,108 @@ jmp_buf motdinterrupt;
void
motd()
{
- register int fd, nchars;
- void (*oldint)(), sigint();
- char tbuf[8192];
-
- if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
- return;
- oldint = signal(SIGINT, sigint);
- if (setjmp(motdinterrupt) == 0)
- while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
- (void)write(fileno(stdout), tbuf, nchars);
- (void)signal(SIGINT, oldint);
- (void)close(fd);
+ register int fd, nchars;
+ void (*oldint)(), sigint();
+ char tbuf[8192];
+
+ if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
+ return;
+ oldint = signal(SIGINT, sigint);
+ if (setjmp(motdinterrupt) == 0)
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ write(fileno(stdout), tbuf, nchars);
+ signal(SIGINT, oldint);
+ close(fd);
}
-void sigint()
+void
+sigint()
{
- longjmp(motdinterrupt, 1);
+ longjmp(motdinterrupt, 1);
}
+#ifndef USE_PAM /* PAM takes care of this */
void
checknologin()
{
- register int fd, nchars;
- char tbuf[8192];
-
- if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
- while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
- (void)write(fileno(stdout), tbuf, nchars);
- sleepexit(0);
- }
+ register int fd, nchars;
+ char tbuf[8192];
+
+ if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ write(fileno(stdout), tbuf, nchars);
+ sleepexit(0);
+ }
}
+#endif
void
dolastlog(quiet)
- int quiet;
+ int quiet;
{
- struct lastlog ll;
- int fd;
-
- if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
- (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
- if (!quiet) {
- if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
- ll.ll_time != 0) {
- (void)printf("Last login: %.*s ",
- 24-5, (char *)ctime(&ll.ll_time));
-
- if (*ll.ll_host != '\0')
- printf("from %.*s\n",
- (int)sizeof(ll.ll_host), ll.ll_host);
- else
- printf("on %.*s\n",
- (int)sizeof(ll.ll_line), ll.ll_line);
- }
- (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
- }
- memset((char *)&ll, 0, sizeof(ll));
- (void)time(&ll.ll_time);
- strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
- if (hostname)
- strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
- (void)write(fd, (char *)&ll, sizeof(ll));
- (void)close(fd);
+ struct lastlog ll;
+ int fd;
+
+ if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
+ lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
+ if (!quiet) {
+ if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
+ ll.ll_time != 0) {
+ printf("Last login: %.*s ",
+ 24-5, (char *)ctime(&ll.ll_time));
+
+ if (*ll.ll_host != '\0')
+ printf("from %.*s\n",
+ (int)sizeof(ll.ll_host), ll.ll_host);
+ else
+ printf("on %.*s\n",
+ (int)sizeof(ll.ll_line), ll.ll_line);
+ }
+ lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
}
+ memset((char *)&ll, 0, sizeof(ll));
+ time(&ll.ll_time);
+ strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+ ll.ll_line[sizeof(ll.ll_line)-1] = 0;
+ if (hostname) {
+ strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
+ ll.ll_host[sizeof(ll.ll_host)-1] = 0;
+ }
+ write(fd, (char *)&ll, sizeof(ll));
+ close(fd);
+ }
}
void
-badlogin(name)
- char *name;
+badlogin(const char *name)
{
- if (hostname)
- syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s",
- failures, failures > 1 ? "S" : "", hostname, name);
- else
- syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s",
- failures, failures > 1 ? "S" : "", tty, name);
+ if (hostname)
+ syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s",
+ failures, failures > 1 ? "S" : "", hostname, name);
+ else
+ syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s",
+ failures, failures > 1 ? "S" : "", tty, name);
}
#undef UNKNOWN
#define UNKNOWN "su"
-#ifndef linux
+#ifndef __linux__
char *
stypeof(ttyid)
- char *ttyid;
+ char *ttyid;
{
- struct ttyent *t;
+ struct ttyent *t;
- return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
+ return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
}
#endif
-void
-getstr(buf, cnt, err)
- char *buf, *err;
- int cnt;
-{
- char ch;
-
- do {
- if (read(0, &ch, sizeof(ch)) != sizeof(ch))
- exit(1);
- if (--cnt < 0) {
- (void)fprintf(stderr, "%s too long\r\n", err);
- sleepexit(1);
- }
- *buf++ = ch;
- } while (ch);
-}
-
+/* should not be called from PAM code... Why? */
void
sleepexit(eval)
- int eval;
+ int eval;
{
- sleep((unsigned int)5);
- exit(eval);
+ sleep(SLEEP_EXIT_TIMEOUT);
+ exit(eval);
}
-
diff --git a/login-utils/mesg.c b/login-utils/mesg.c
index 79d3ef21e..4e4916357 100644
--- a/login-utils/mesg.c
+++ b/login-utils/mesg.c
@@ -36,6 +36,8 @@
* SUCH DAMAGE.
*
* Modified Fri Mar 10 20:27:19 1995, faith@cs.unc.edu, for Linux
+ * Modified Mon Jul 1 18:14:10 1996, janl@ifi.uio.no, writing to stdout
+ * as suggested by Michael Meskes <meskes@Informatik.RWTH-Aachen.DE>
*
*/
@@ -84,10 +86,10 @@ main(argc, argv)
if (*argv == NULL) {
if (sb.st_mode & (S_IWGRP | S_IWOTH)) {
- (void)fprintf(stderr, "is y\n");
+ (void)fprintf(stdout, "is y\n");
exit(0);
}
- (void)fprintf(stderr, "is n\n");
+ (void)fprintf(stdout, "is n\n");
exit(1);
}
diff --git a/login-utils/newgrp.c b/login-utils/newgrp.c
index ba13fdeb1..65dd00d95 100644
--- a/login-utils/newgrp.c
+++ b/login-utils/newgrp.c
@@ -3,6 +3,7 @@
/* Vesa Roukonen added code for asking password */
/* Currently maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/ */
+#define _XOPEN_SOURCE /* for crypt() */
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
diff --git a/login-utils/passwd.1 b/login-utils/passwd.1
index f2bf9de90..c696c53d3 100644
--- a/login-utils/passwd.1
+++ b/login-utils/passwd.1
@@ -1,49 +1,112 @@
.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu)
.\" May be distributed under the GNU General Public License
-.TH PASSWD 1 "22 June 1994" "Linux 1.2" "Linux Programmer's Manual"
+.TH PASSWD 1 "11 November 1996" "Util-linux 2.6" "Linux Programmer's Manual"
.SH NAME
passwd \- change password
.SH SYNOPSIS
-.BR "passwd [ " name " [ " password " ] ]"
+.BR "passwd"
+.RB [ " \-o " ]
+.RB [ " \-q " ]
+.RB [ " \-v " ]
+.RI [ " name " [ " password " ]]
+.br
+.BR "passwd \-f "
+.RI [ " arguments to chfn " ]
+.br
+.BR "passwd \-s "
+.RI [ " arguments to chsh " ]
+
.SH DESCRIPTION
Without arguments
.B passwd
will change the password for the current user. First the user is asked for
the old password, then prompted twice for the new password in order to
-catch typing errors. The new password must be at least six characters long,
-and have both upper and lower case letters or non-letters. The new password
-must not be equal to the old password, and it must not match the username.
+catch typing errors.
The one and two argument forms may only be used by the superuser. Using the
-one argument form, the superuser may change the password for that user.
-The superuser is not asked for the users old password, and the rules
-for proper passwords are not applied since the superuser may have legitimate
+one argument form, the superuser may change the password for that
+.IR user .
+The superuser is not asked for the users old password, but the rules
+for proper passwords are also applied unless the
+.B "\-o"
+option is used. The superuser may have legitimate
reasons to choose a non-conformant password.
The two argument form gives the
-.I user
-the password stated as the second argument. This may be useful when
-giving many users an initial generated password.
+.IR user " the " password
+stated as the second argument. This may be useful when giving many
+users an initial generated password. But it can also be extremely
+dangerous. A simple script bug might change to root password to
+something unknown.
Giving an empty string as the second argument erases the password for the
-user.
+user, but only in combination with the
+.B "\-o"
+option.
+
+Password changes may get logged using the
+.BR syslog (3)
+facility, depending on compile-time defines (on by default).
+If so, every change will
+be logged at a low level as auth.notice, except for changing the root
+password with will be logged with auth.warning.
+
+.SH OPTIONS
+.TP
+.B "\-f, \-\-fullname"
+Change the user's full name (the GECOS field of the passwd entry).
+Invokes /usr/bin/chfn with the non-option command line arguments.
+.TP
+.B "\-o, \-\-force"
+Turn off simplicity checks on the new password. This option may only
+be used by the super user. This is intend to allow simple initial
+passwords given by the superuser.
+.TP
+.B "\-s, \-\-shell"
+Change the user's shell by invoking /usr/bin/chsh with the non-option
+command line arguments.
+.TP
+.B "\-q, \-\-quiet, \-\-silent"
+In this mode passwd won't tell that the passwd get's changed.
+.TP
+.B "\-v, \-V, \-\-version"
+Prints version information and exits.
+
+.SH PASSWORD RULES
+The new password must fulfill these rules:
+.TP
+o
+be at least six characters long;
+.TP
+o
+must not be equal to the old password;
+
+.TP
+o
+must contain characters out of at least two of the following classes:
+upper and lower case letters, digits and non alphanumeric characters;
+
+.TP
+o
+must not match neither the username nor any word of the realname,
+neither in normal nor in reverse order, neither at the beginning nor
+at the end.
.SH FILES
+.TP
.I /etc/passwd
-.br
-.I /etc/shells
+The password file.
.SH "SEE ALSO"
.BR chsh (1),
-.BR chfn (1)
-.SH BUGS
-A password consisting of all digits is allowed.
+.BR chfn (1),
+.BR syslog (3),
+.BR syslog.conf (5),
+.BR passwd (8).
+.SH AUTHOR
+Peter Orbaek (poe@daimi.aau.dk).
.br
-No warnings are printed if the superuser chooses a poor password.
+Martin Schulze (joey@infodrom.north.de) with extensive rewriting and
+improving done.
.br
-The
-.B \-f
-and
-.B \-s
-options are not supported.
-.SH AUTHOR
-Peter Orbaek (poe@daimi.aau.dk)
+.SH MAINTAINER
+Nicolai Langfeldt (janl@math.uio.no)
diff --git a/login-utils/passwd.c b/login-utils/passwd.c
index 1c786e94e..f707c0521 100644
--- a/login-utils/passwd.c
+++ b/login-utils/passwd.c
@@ -1,12 +1,43 @@
-/* passwd.c - change password on an account
+/*
+ * passwd.c - change password on an account
+ *
* Initially written for Linux by Peter Orbaek <poe@daimi.aau.dk>
* Currently maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/
+
+ Hacked by Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es,
+ to allow peaceful coexistence with yp. Nov 94.
+
+ Hacked to allow root to set passwd from command line.
+ by Arpad Magossanyi (mag@tas.vein.hu)
+
+ Hacked by Peter Breitenlohner, peb@mppmu.mpg.de,
+ moved Alvaro's changes to setpwnam.c (so they get used
+ by chsh and chfn as well). Oct 5, 96.
+
*/
-/* Hacked by Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es,
- to allow peaceful coexistence with yp. Nov 94. */
-/* Hacked to allow root to set passwd from command line.
- by Arpad Magossanyi (mag@tas.vein.hu) */
+/*
+ * Sun Oct 15 13:18:34 1995 Martin Schulze <joey@finlandia.infodrom.north.de>
+ *
+ * I have completely rewritten the whole argument handlig (what?)
+ * to support two things. First I wanted "passwd $user $pw" to
+ * work and second I wanted simplicity checks to be done for
+ * root, too. Only root can turn this of using the -f
+ * switch. Okay, I started with this to support -V version
+ * information, but one thing comes to the next. *sigh*
+ * In a later step perhaps we'll be able to support shadow
+ * passwords. (?)
+ *
+ * I have also included a DEBUG mode (-DDEBUG) to test the
+ * argument handling _without_ any write attempt to
+ * /etc/passwd.
+ *
+ * If you're paranoid about security on your system, you may want
+ * to add -DLOGALL to CFLAGS. This will turn on additional syslog
+ * logging of every password change. (user changes are logged as
+ * auth.notice, but changing root's password is logged as
+ * auth.warning. (Of course, the password itself is not logged.)
+ */
/*
* Usage: passwd [username [password]]
@@ -17,7 +48,10 @@
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
+#include <stdarg.h>
#include <termios.h>
+#include <getopt.h>
+#include <malloc.h>
#include <fcntl.h>
#include <pwd.h>
#include <ctype.h>
@@ -26,21 +60,170 @@
#include <errno.h>
#include <sys/resource.h>
-extern int is_local(char *);
+#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1
+#include <crypt.h>
+#endif
+
+#if 0
+# include "../version.h"
+#else
+char version[] = "admutil 1.18, 15-Oct-95";
+#endif
+
+#ifndef _PATH_CHFN
+# define _PATH_CHFN "/usr/bin/chfn"
+# define _PATH_CHSH "/usr/bin/chsh"
+#endif
+
+#define LOGALL
+
+#ifdef LOGALL
+#include <syslog.h>
+#endif /* LOGALL */
+
+extern int is_local(char *); /* islocal.c */
+extern int setpwnam(struct passwd *); /* setpwnam.c */
#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
-#define MAX_LENGTH 1024
-
static void
-pexit(str)
- char *str;
+pexit(char *str, ...)
{
- perror(str);
+ va_list vlst;
+
+ va_start(vlst, str);
+ vfprintf(stderr, str, vlst);
+ fprintf(stderr, ": ");
+ perror("");
+ va_end(vlst);
exit(1);
}
+/*
+ * Do various checks for stupid passwords here...
+ *
+ * This would probably be the best place for checking against
+ * dictionaries. :-)
+ */
+
+int check_passwd_string(char *passwd, char *string)
+{
+ int r;
+ char *p, *q;
+
+ r = 0;
+ /* test for string at the beginning of passwd */
+ for (p = passwd, q = string; *q && *p; q++, p++) {
+ if(tolower(*p) != tolower(*q)) {
+ r++;
+ break;
+ }
+ }
+
+ /* test for reverse string at the beginning of passwd */
+ for (p = passwd, q = string + strlen(string)-1;
+ *p && q >= string; p++, q--) {
+ if(tolower(*p) != tolower(*q)) {
+ r++;
+ break;
+ }
+ }
+
+ /* test for string at the end of passwd */
+ for (p = passwd + strlen(passwd)-1, q = string + strlen(string)-1;
+ q >= string && p >= passwd; q--, p--) {
+ if(tolower(*p) != tolower(*q)) {
+ r++;
+ break;
+ }
+ }
+
+ /* test for reverse string at the beginning of passwd */
+ for (p = passwd + strlen(passwd)-1, q = string;
+ p >= passwd && *q; p--, q++) {
+ if(tolower(*p) != tolower(*q)) {
+ r++;
+ break;
+ }
+ }
+
+ if (r != 4) {
+ return 0;
+ }
+ return 1;
+}
+
+int check_passwd(char *passwd, char *oldpasswd, char *user, char *gecos)
+{
+ int ucase, lcase, digit, other;
+ char *c, *g, *p;
+
+ if ( (strlen(passwd) < 6) ) {
+ printf("The password must have at least 6 characters, try again.\n");
+ return 0;
+ }
+
+ other = digit = ucase = lcase = 0;
+ for (p = passwd; *p; p++) {
+ ucase = ucase || isupper(*p);
+ lcase = lcase || islower(*p);
+ digit = digit || isdigit(*p);
+ other = other || !isalnum(*p);
+ }
+
+ if ( (other + digit + ucase + lcase) < 2) {
+ printf("The password must contain characters out of two of the following\n");
+ printf("classes: upper and lower case letters, digits and non alphanumeric\n");
+ printf("characters. See passwd(1) for more information.\n");
+ return 0;
+ }
+
+ if ( oldpasswd[0] && !strncmp(oldpasswd, crypt(passwd, oldpasswd), 13) ) {
+ printf("You cannot reuse the old password.\n");
+ return 0;
+ }
+
+ if ( !check_passwd_string(passwd, user) ) {
+ printf("Please don't use something like your username as password!\n");
+ return 0;
+ }
+
+ /* check against realname */
+ if ( (c = index(gecos, ',')) ) {
+ if ( c-gecos && (g = (char *)malloc (c-gecos+1)) ) {
+ strncpy (g, gecos, c-gecos);
+ g[c-gecos] = 0;
+ while ( (c=rindex(g, ' ')) ) {
+ if ( !check_passwd_string(passwd, c+1) ) {
+ printf("Please don't use something like your realname as password!\n");
+ free (g);
+ return 0;
+ }
+ *c = '\0';
+ } /* while */
+ if ( !check_passwd_string(passwd, g) ) {
+ printf("Please don't use something like your realname as password!\n");
+ free (g);
+ return 0;
+ }
+ free (g);
+ } /* if malloc */
+ }
+
+ /*
+ * if ( !check_password_dict(passwd) ) ...
+ */
+
+ return 1; /* fine */
+}
+
+void usage()
+{
+ printf ("Usage: passwd [username [password]]\n");
+ printf("Only root may use the one and two argument forms.\n");
+}
+
int
main(argc, argv)
int argc;
@@ -50,56 +233,101 @@ main(argc, argv)
uid_t gotuid = getuid();
char *pwdstr = NULL, *cryptstr, *oldstr;
char pwdstr1[10];
- int ucase, lcase, other;
- char *p, *q, *user;
+ char *user;
time_t tm;
char salt[2];
- FILE *fd_in, *fd_out;
- char line[MAX_LENGTH];
- char colonuser[16];
- int error=0;
- int r;
- int ptmp;
-#ifndef USE_SETPWNAM
- struct rlimit rlim;
-#endif
+ int force_passwd = 0;
+ int silent = 0;
+ char c;
+ int opt_index;
+ int fullname = 0, shell = 0;
+ static const struct option long_options[] =
+ {
+ {"fullname", no_argument, 0, 'f'},
+ {"shell", no_argument, 0, 's'},
+ {"force", no_argument, 0, 'o'},
+ {"quiet", no_argument, 0, 'q'},
+ {"silent", no_argument, 0, 'q'},
+ {"version", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
- if(argc > 3) {
- puts("Too many arguments");
- exit(1);
- } else if(argc >= 2) {
- if(gotuid) {
- puts("Only root can change the password for others");
+ optind = 0;
+ while ( (c = getopt_long(argc, argv, "foqsvV", long_options, &opt_index)) != -1 ) {
+ switch (c) {
+ case 'f':
+ fullname = 1;
+ break;
+ case 's':
+ shell = 1;
+ break;
+ case 'o':
+ force_passwd = 1;
+ break;
+ case 'q':
+ silent = 1;
+ break;
+ case 'V':
+ case 'v':
+ printf("%s\n", version);
+ exit(0);
+ default:
+ fprintf(stderr, "Usage: passwd [-foqsvV] [user [password]]\n");
exit(1);
- }
- user = argv[1];
-
- if (argc == 3) pwdstr = argv[2];
-
- } else {
- if (!(user = getlogin())) {
- if (!(pe = getpwuid( getuid() ))) {
+ } /* switch (c) */
+ } /* while */
+
+ if (fullname || shell) {
+ char *args[100];
+ int i, j;
+
+ setuid(getuid()); /* drop special privs. */
+ if (fullname)
+ args[0] = _PATH_CHFN;
+ else
+ args[0] = _PATH_CHSH;
+
+ for (i = optind, j = 1; (i < argc) && (j < 99); i++, j++)
+ args[j] = argv[i];
+
+ args[j] = NULL;
+ execv(args[0], args);
+ fprintf(stderr, "Can't exec %s: %s\n", args[0], strerror(errno));
+ exit(1);
+ }
+
+ switch (argc - optind) {
+ case 0:
+ if ( !(user = getlogin()) ) {
+ if ( !(pe = getpwuid( getuid() )) ) {
pexit("Cannot find login name");
} else
- user = pe->pw_name;
+ user = pe->pw_name;
}
- }
+ break;
+ case 1:
+ if(gotuid) {
+ printf("Only root can change the password for others.\n");
+ exit (1);
+ } else
+ user = argv[optind];
+ break;
+ case 2:
+ if(gotuid) {
+ printf("Only root can change the password for others.\n");
+ exit(1);
+ } else {
+ user = argv[optind];
+ pwdstr = argv[optind+1];
+ }
+ break;
+ default:
+ printf("Too many arguments.\n");
+ exit (1);
+ } /* switch */
-#ifndef USE_SETPWNAM
- umask(022);
-
- rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
- setrlimit(RLIMIT_CPU, &rlim);
- setrlimit(RLIMIT_FSIZE, &rlim);
- setrlimit(RLIMIT_STACK, &rlim);
- setrlimit(RLIMIT_DATA, &rlim);
- setrlimit(RLIMIT_RSS, &rlim);
- rlim.rlim_cur = rlim.rlim_max = 0;
- setrlimit(RLIMIT_CORE, &rlim);
-#endif
-
if(!(pe = getpwnam(user))) {
- pexit("Can't find username anywhere. Are you really a user?");
+ pexit("Can't find username anywhere. Is `%s' really a user?", user);
}
if (!(is_local(user))) {
@@ -113,9 +341,11 @@ main(argc, argv)
exit(1);
}
- printf( "Changing password for %s\n", user );
+ if ( !silent )
+ printf( "Changing password for %s\n", user );
- if(gotuid && pe->pw_passwd && pe->pw_passwd[0]) {
+ if ( (gotuid && pe->pw_passwd && pe->pw_passwd[0])
+ || (!gotuid && !strcmp(user,"root")) ) {
oldstr = getpass("Enter old password: ");
if(strncmp(pe->pw_passwd, crypt(oldstr, pe->pw_passwd), 13)) {
puts("Illegal password, imposter.");
@@ -123,7 +353,10 @@ main(argc, argv)
}
}
- if (!pwdstr) {
+ if ( pwdstr ) { /* already set on command line */
+ if ( !force_passwd && !check_passwd(pwdstr, pe->pw_passwd, user, pe->pw_gecos) )
+ exit (1);
+ } else {
/* password not set on command line by root, ask for it ... */
redo_it:
@@ -132,126 +365,53 @@ main(argc, argv)
puts("Password not changed.");
exit(1);
}
-
- if((strlen(pwdstr) < 6) && gotuid) {
- puts("The password must have at least 6 characters, try again.");
- goto redo_it;
- }
-
- other = ucase = lcase = 0;
- for(p = pwdstr; *p; p++) {
- ucase = ucase || isupper(*p);
- lcase = lcase || islower(*p);
- other = other || !isalpha(*p);
- }
-
- if((!ucase || !lcase) && !other && gotuid) {
- puts("The password must have both upper- and lowercase");
- puts("letters, or non-letters; try again.");
- goto redo_it;
- }
-
- if (pe->pw_passwd[0]
- && !strncmp(pe->pw_passwd, crypt(pwdstr, pe->pw_passwd), 13)
- && gotuid) {
- puts("You cannot reuse the old password.");
- goto redo_it;
- }
-
- r = 0;
- for(p = pwdstr, q = pe->pw_name; *q && *p; q++, p++) {
- if(tolower(*p) != tolower(*q)) {
- r = 1;
- break;
- }
- }
-
- for(p = pwdstr + strlen(pwdstr)-1, q = pe->pw_name;
- *q && p >= pwdstr; q++, p--) {
- if(tolower(*p) != tolower(*q)) {
- r += 2;
- break;
- }
- }
-
- if(gotuid && r != 3) {
- puts("Please don't use something like your username as password!");
+
+ if ( (gotuid || (!gotuid && !force_passwd))
+ && !check_passwd(pwdstr, pe->pw_passwd, user, pe->pw_gecos) )
goto redo_it;
- }
-
- /* do various other checks for stupid passwords here... */
strncpy(pwdstr1, pwdstr, 9);
+ pwdstr1[9] = 0;
pwdstr = getpass("Re-type new password: ");
if(strncmp(pwdstr, pwdstr1, 8)) {
puts("You misspelled it. Password not changed.");
exit(1);
}
- } /* pwdstr != argv[2] i.e. password set on command line */
+ } /* pwdstr i.e. password set on command line */
- time(&tm);
+ time(&tm); tm ^= getpid();
salt[0] = bin_to_ascii(tm & 0x3f);
salt[1] = bin_to_ascii((tm >> 6) & 0x3f);
cryptstr = crypt(pwdstr, salt);
if (pwdstr[0] == 0) cryptstr = "";
-#ifdef USE_SETPWNAM
+#ifdef LOGALL
+ openlog("passwd", 0, LOG_AUTH);
+ if (gotuid)
+ syslog(LOG_NOTICE,"password changed, user %s",user);
+ else {
+ if ( !strcmp(user, "root") )
+ syslog(LOG_WARNING,"ROOT PASSWORD CHANGED");
+ else
+ syslog(LOG_NOTICE,"password changed by root, user %s",user);
+ }
+ closelog();
+#endif /* LOGALL */
+
pe->pw_passwd = cryptstr;
+#ifdef DEBUG
+ printf ("calling setpwnam to set password.\n");
+#else
if (setpwnam( pe ) < 0) {
perror( "setpwnam" );
printf( "Password *NOT* changed. Try again later.\n" );
exit( 1 );
}
-#else
- if ((ptmp = open("/etc/ptmp", O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0) {
- pexit("Can't exclusively open /etc/ptmp, can't update password");
- }
- fd_out = fdopen(ptmp, "w");
-
- if(!(fd_in = fopen("/etc/passwd", "r"))) {
- pexit("Can't read /etc/passwd, can't update password");
- }
-
- strcpy(colonuser, user);
- strcat(colonuser, ":");
- while(fgets(line, sizeof(line), fd_in)) {
- if(!strncmp(line,colonuser,strlen(colonuser))) {
- pe->pw_passwd = cryptstr;
- if(putpwent(pe, fd_out) < 0) {
- error = 1;
- }
- } else {
- if(fputs(line,fd_out) < 0) {
- error = 1;
- }
- }
- if(error) {
- puts("Error while writing new password file, password not changed.");
- fclose(fd_out);
- endpwent();
- unlink("/etc/ptmp");
- exit(1);
- }
- }
- fclose(fd_in);
- fclose(fd_out);
-
- unlink("/etc/passwd.OLD"); /* passwd.OLD not required */
- if (link("/etc/passwd", "/etc/passwd.OLD"))
- pexit("link(/etc/passwd, /etc/passwd.OLD) failed: no change");
- if (unlink("/etc/passwd") < 0)
- pexit("unlink(/etc/passwd) failed: no change");
- if (link("/etc/ptmp", "/etc/passwd") < 0)
- pexit("link(/etc/ptmp, /etc/passwd) failed: PASSWD file DROPPED!!");
- if (unlink("/etc/ptmp") < 0)
- pexit("unlink(/etc/ptmp) failed: /etc/ptmp still exists");
-
- chmod("/etc/passwd", 0644);
- chown("/etc/passwd", 0, 0);
#endif
-
- puts("Password changed.");
+
+ if ( !silent )
+ printf("Password changed.\n");
exit(0);
}
diff --git a/login-utils/setpwnam.c b/login-utils/setpwnam.c
index 8a01c6ec5..1f1067cf1 100644
--- a/login-utils/setpwnam.c
+++ b/login-utils/setpwnam.c
@@ -8,6 +8,11 @@
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
+ * Edited 11/10/96 (DD/MM/YY ;-) by Nicolai Langfeldt (janl@math.uio.no)
+ * to read /etc/passwd directly so that passwd, chsh and chfn can work
+ * on machines that run NIS (né YP). Changes will not be made to
+ * usernames starting with +.
+ *
* This file is distributed with no warranty.
*
* Usage:
@@ -17,15 +22,25 @@
* 2) edit the fields you want to edit.
* 3) call setpwnam() with the edited struct passwd.
*
- * You should never directly read from or write to /etc/passwd.
- * All user database queries should be directed through
- * getpwnam() and setpwnam().
+ * A _normal user_ program should never directly manipulate
+ * /etc/passwd but use getpwnam() and (family, as well as)
+ * setpwnam().
+ *
+ * But, setpwnam was made to _edit_ the password file. For use by
+ * chfn, chsh and passwd. _I_ _HAVE_ to read and write /etc/passwd
+ * directly. Let those who say nay be forever silent and think about
+ * how getpwnam (and family) works on a machine running YP.
+ *
+ * Added checks for failure of malloc() and removed error reporting
+ * to stderr, this is a library function and should not print on the
+ * screen, but return appropriate error codes.
+ * 27-Jan-97 - poe@daimi.aau.dk
*
* Thanks to "two guys named Ian".
- */
-/* $Author: faith $
- * $Revision: 1.5 $
- * $Date: 1995/10/12 14:46:36 $
+ *
+ * $Author: poer $
+ * $Revision: 1.13 $
+ * $Date: 1997/06/23 08:26:29 $
*/
#undef DEBUG
@@ -43,207 +58,164 @@
#include <errno.h>
#include <signal.h>
#include <sys/resource.h>
-#ifdef BSD43
-#include <sys/file.h>
-#endif
+#include <sys/stat.h>
#include <paths.h>
-#include "pathnames.h"
-
-extern int errno;
+#include "setpwnam.h"
-typedef int boolean;
-#define false 0
-#define true 1
-
-#ifndef DEBUG
-#define PASSWD_FILE _PATH_PASSWD
-#define PTMP_FILE _PATH_PTMP
-#define PTMPTMP_FILE _PATH_PTMPTMP
-#else
-#define PASSWD_FILE "/tmp/passwd"
-#define PTMP_FILE "/tmp/ptmp"
-#define PTMPTMP_FILE "/tmp/ptmptmp"
-#endif
-
-static int copy_pwd (struct passwd *src, struct passwd *dest);
-static char *xstrdup (char *str);
static void pw_init(void);
/*
* setpwnam () --
* takes a struct passwd in which every field is filled in and valid.
- * If the given username exists in the passwd file, his entry is
+ * If the given username exists in the passwd file, the entry is
* replaced with the given entry.
*/
-int setpwnam (struct passwd *pwd)
+int
+setpwnam (struct passwd *pwd)
{
- FILE *fp;
+ FILE *fp = NULL, *pwf = NULL;
int x, save_errno, fd, ret;
- struct passwd *entry;
boolean found;
- struct passwd spwd;
int oldumask;
+ int namelen;
+ int buflen = 256;
+ int contlen;
+ char *linebuf = malloc(buflen);
- /* getpwent() returns a pointer to a static buffer.
- * "pwd" might have some from getpwent(), so we have to copy it to
- * some other buffer before calling getpwent().
- */
- if (copy_pwd (pwd, &spwd) < 0)
- return (-1);
+ if (!linebuf) return -1;
oldumask = umask(0); /* Create with exact permissions */
+
pw_init();
/* sanity check */
for (x = 0; x < 3; x++) {
- if (x > 0) sleep (1);
- fd = open (PTMPTMP_FILE, O_WRONLY|O_CREAT, 0644);
- if(fd == -1) {
- perror(PTMPTMP_FILE);
+ if (x > 0) sleep(1);
+ fd = open(PTMPTMP_FILE, O_WRONLY|O_CREAT, 0644);
+ if (fd == -1) {
umask(oldumask);
- return (-1);
+ return -1;
}
ret = link(PTMPTMP_FILE, PTMP_FILE);
unlink(PTMPTMP_FILE);
- if(ret == -1)
+ if (ret == -1)
close(fd);
else
break;
}
-
umask(oldumask);
- if (ret == -1) return (-1);
+ if (ret == -1) return -1;
/* ptmp should be owned by root.root or root.wheel */
- if (chown (PTMP_FILE, (uid_t) 0, (gid_t) 0) < 0)
- perror ("chown");
+ if (chown(PTMP_FILE, (uid_t) 0, (gid_t) 0) < 0) return -1;
/* open ptmp for writing and passwd for reading */
- fp = fdopen (fd, "w");
- if (! fp) goto fail;
+ fp = fdopen(fd, "w");
+ if (!fp) goto fail;
- setpwent ();
+ pwf = fopen(PASSWD_FILE, "r");
+ if (!pwf) goto fail;
+
+ namelen = strlen(pwd->pw_name);
/* parse the passwd file */
found = false;
- while ((entry = getpwent ()) != NULL) {
- if (! strcmp (spwd.pw_name, entry->pw_name)) {
- entry = &spwd;
- found = true;
- }
- if (putpwent (entry, fp) < 0) goto fail;
+ /* Do you wonder why I don't use getpwent? Read comments at top of file */
+ while (fgets(linebuf, buflen, pwf) != NULL) {
+ contlen = strlen(linebuf);
+ while (linebuf[contlen-1] != '\n' && !feof(pwf)) {
+ /* Extend input buffer if it failed getting the whole line */
+
+ /* So now we double the buffer size */
+ buflen *= 2;
+
+ linebuf = realloc(linebuf, buflen);
+ if (linebuf == NULL) goto fail;
+
+ /* And fill the rest of the buffer */
+ if (fgets(&linebuf[contlen], buflen/2, pwf) == NULL) break;
+ contlen = strlen(linebuf);
+
+ /* That was a lot of work for nothing. Gimme perl! */
+ }
+
+ /* Is this the username we were sent to change? */
+ if (!found && linebuf[namelen] == ':' &&
+ !strncmp(linebuf, pwd->pw_name, namelen)) {
+ /* Yes! So go forth in the name of the Lord and change it! */
+ if (putpwent(pwd, fp) < 0) goto fail;
+ found = true;
+ continue;
+ }
+ /* Nothing in particular happened, copy input to output */
+ fputs(linebuf, fp);
}
- if (fclose (fp) < 0) goto fail;
+
+ if (fclose(fp) < 0) goto fail;
+ fp = NULL;
close (fd);
- endpwent ();
+ fd = -1;
+ fclose (pwf); /* I don't think I want to know if this failed */
+ pwf = NULL;
- if (! found) {
+ if (!found) {
errno = ENOENT; /* give me something better */
goto fail;
}
/* we don't care if we can't remove the backup file */
- unlink (PASSWD_FILE".OLD");
+ unlink(PASSWD_FILE".OLD");
/* we don't care if we can't create the backup file */
- link (PASSWD_FILE, PASSWD_FILE".OLD");
+ link(PASSWD_FILE, PASSWD_FILE".OLD");
/* we DO care if we can't rename to the passwd file */
- if (rename (PTMP_FILE, PASSWD_FILE) < 0)
+ if(rename(PTMP_FILE, PASSWD_FILE) < 0)
goto fail;
/* finally: success */
return 0;
- fail:
+fail:
save_errno = errno;
- if (fp) fclose (fp);
+ if (fp != NULL) fclose (fp);
+ if (pwf != NULL) fclose(pwf);
if (fd >= 0) close (fd);
- endpwent ();
- unlink (PTMP_FILE);
+ if (linebuf != NULL) free(linebuf);
+ unlink(PTMP_FILE);
errno = save_errno;
- return (-1);
+ return -1;
}
-#define memzero(ptr, size) memset((char *) ptr, 0, size)
-static int failed;
-
-static int copy_pwd (struct passwd *src, struct passwd *dest)
-{
- /* this routine destroys abstraction barriers. it's not portable
- * across systems, or even across different versions of the C library
- * on a given system. it's dangerous and evil and wrong and I dispise
- * getpwent() for forcing me to write this.
- */
- failed = 0;
- memzero (dest, sizeof (struct passwd));
- dest->pw_name = xstrdup (src->pw_name);
- dest->pw_passwd = xstrdup (src->pw_passwd);
- dest->pw_uid = src->pw_uid;
- dest->pw_gid = src->pw_gid;
- dest->pw_gecos = xstrdup (src->pw_gecos);
- dest->pw_dir = xstrdup (src->pw_dir);
- dest->pw_shell = xstrdup (src->pw_shell);
- return (failed);
-}
+/* Set up the limits so that we're not foiled */
-static char *xstrdup (char *str)
+static void
+pw_init()
{
- char *dup;
-
- if (! str)
- return NULL;
- dup = (char *) malloc (strlen (str) + 1);
- if (! dup) {
- failed = -1;
- return NULL;
- }
- strcpy (dup, str);
- return dup;
-}
+ struct rlimit rlim;
-#ifdef NO_PUTPWENT
-
-int putpwent (const struct passwd *p, FILE *stream)
-{
- if (p == NULL || stream == NULL) {
- errno = EINVAL;
- return (-1);
- }
- if (fprintf (stream, "%s:%s:%u:%u:%s:%s:%s\n",
- p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid,
- p->pw_gecos, p->pw_dir, p->pw_shell) < 0)
- return (-1);
- return(0);
-}
+ /* Unlimited resource limits. */
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ setrlimit(RLIMIT_CPU, &rlim);
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ setrlimit(RLIMIT_STACK, &rlim);
+ setrlimit(RLIMIT_DATA, &rlim);
+ setrlimit(RLIMIT_RSS, &rlim);
+#ifndef DEBUG
+ /* Don't drop core (not really necessary, but GP's). */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
#endif
-static void
-pw_init()
-{
- struct rlimit rlim;
-
- /* Unlimited resource limits. */
- rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
- (void)setrlimit(RLIMIT_CPU, &rlim);
- (void)setrlimit(RLIMIT_FSIZE, &rlim);
- (void)setrlimit(RLIMIT_STACK, &rlim);
- (void)setrlimit(RLIMIT_DATA, &rlim);
- (void)setrlimit(RLIMIT_RSS, &rlim);
-
- /* Don't drop core (not really necessary, but GP's). */
- rlim.rlim_cur = rlim.rlim_max = 0;
- (void)setrlimit(RLIMIT_CORE, &rlim);
-
- /* Turn off signals. */
- (void)signal(SIGALRM, SIG_IGN);
- (void)signal(SIGHUP, SIG_IGN);
- (void)signal(SIGINT, SIG_IGN);
- (void)signal(SIGPIPE, SIG_IGN);
- (void)signal(SIGQUIT, SIG_IGN);
- (void)signal(SIGTERM, SIG_IGN);
- (void)signal(SIGTSTP, SIG_IGN);
- (void)signal(SIGTTOU, SIG_IGN);
-
- /* Create with exact permissions. */
- (void)umask(0);
+ /* Turn off signals. */
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+
+ /* Create with exact permissions. */
+ umask(0);
}
diff --git a/login-utils/setpwnam.h b/login-utils/setpwnam.h
new file mode 100644
index 000000000..b4790f7ab
--- /dev/null
+++ b/login-utils/setpwnam.h
@@ -0,0 +1,38 @@
+/*
+ * setpwnam.h --
+ * define several paths
+ *
+ * (c) 1994 Martin Schulze <joey@infodrom.north.de>
+ * This file is based on setpwnam.c which is
+ * (c) 1994 Salvatore Valente <svalente@mit.edu>
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include "pathnames.h"
+
+#define false 0
+#define true 1
+
+typedef int boolean;
+
+#ifndef DEBUG
+#define PASSWD_FILE _PATH_PASSWD
+#define PTMP_FILE _PATH_PTMP
+#define PTMPTMP_FILE _PATH_PTMPTMP
+
+#define GROUP_FILE _PATH_GROUP
+#define GTMP_FILE _PATH_GTMP
+#define GTMPTMP_FILE _PATH_GTMPTMP
+#else
+#define PASSWD_FILE "/tmp/passwd"
+#define PTMP_FILE "/tmp/ptmp"
+#define PTMPTMP_FILE "/tmp/ptmptmp"
+
+#define GROUP_FILE "/tmp/group"
+#define GTMP_FILE "/tmp/gtmp"
+#define GTMPTMP_FILE "/tmp/gtmptmp"
+#endif
diff --git a/login-utils/shutdown.8 b/login-utils/shutdown.8
index 21b384124..443acc2af 100644
--- a/login-utils/shutdown.8
+++ b/login-utils/shutdown.8
@@ -5,11 +5,11 @@
shutdown \- close down the system
.SH SYNOPSIS
.nf
-.BR "shutdown [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]"
-.BR "reboot [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]"
-.BR "fastboot [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]"
-.BR "halt [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]"
-.BR "fasthalt [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]"
+.BR "shutdown [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]"
+.BR "reboot [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]"
+.BR "fastboot [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]"
+.BR "halt [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]"
+.BR "fasthalt [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]"
.fi
.SH DESCRIPTION
.\" " for emacs hilit19
@@ -17,7 +17,11 @@ In general,
.B shutdown
prepares the system for a power down or reboot. A absolute or delta time
can be given, and periodic messages will be sent to all users warning of
-the shutdown.
+the shutdown. If no message is specified on the command line,
+.B shutdown
+will ask for a message to be sent, unless the
+.B \-q
+option is set.
.B halt
is the same as
diff --git a/login-utils/shutdown.c b/login-utils/shutdown.c
index 155154c21..a63cbd6e9 100644
--- a/login-utils/shutdown.c
+++ b/login-utils/shutdown.c
@@ -56,6 +56,7 @@ int opt_fast; /* true if fast boot */
char message[90]; /* reason for shutdown if any... */
int opt_single = 0; /* true is we want to boot singleuser */
char *whom; /* who is shutting the system down */
+int opt_msgset = 0; /* message set on command line */
/* #define DEBUGGING */
@@ -156,7 +157,7 @@ main(argc, argv)
timeout = 0;
} else if(argv[c][0] == '+') {
timeout = 60 * atoi(&argv[c][1]);
- } else {
+ } else if (isdigit(argv[c][0])) {
char *colon;
int hour = 0;
int minute = 0;
@@ -180,11 +181,15 @@ main(argc, argv)
fprintf(stderr, "That must be tomorrow, can't you wait till then?\n");
exit(1);
}
+ } else {
+ strncpy(message, argv[c], sizeof(message));
+ message[sizeof(message)-1] = '\0';
+ opt_msgset = 1;
}
}
}
- if(!opt_quiet) {
+ if(!opt_quiet && !opt_msgset) {
/* now ask for message, gets() is insecure */
int cnt = sizeof(message)-1;
char *ptr;
@@ -196,8 +201,9 @@ main(argc, argv)
ptr++;
}
*ptr = '\0';
- } else
+ } else if (!opt_msgset) {
strcpy(message, "for maintenance; bounce, bounce");
+ }
#ifdef DEBUGGING
printf("timeout = %d, quiet = %d, reboot = %d\n",
@@ -221,7 +227,7 @@ main(argc, argv)
}
- if((fd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT)) >= 0) {
+ if((fd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT, 0644)) >= 0) {
WR("\r\nThe system is being shut down within 5 minutes\r\n");
write(fd, message, strlen(message));
WR("\r\nLogin is therefore prohibited.\r\n");
@@ -249,13 +255,13 @@ main(argc, argv)
closelog();
if(opt_fast)
- if((fd = open("/fastboot", O_WRONLY|O_CREAT)) >= 0)
+ if((fd = open("/fastboot", O_WRONLY|O_CREAT, 0644)) >= 0)
close(fd);
kill(1, SIGTSTP); /* tell init not to spawn more getty's */
write_wtmp();
if(opt_single)
- close(open(_PATH_SINGLE, O_CREAT|O_WRONLY));
+ close(open(_PATH_SINGLE, O_CREAT|O_WRONLY, 0644));
sync();
@@ -288,9 +294,12 @@ main(argc, argv)
if(opt_reboot) {
reboot(0xfee1dead, 672274793, 0x1234567);
} else {
+ freopen(_PATH_CONSOLE, "w", stdout);
printf("\nNow you can turn off the power...\n");
- /* allow C-A-D now, faith@cs.unc.edu */
+ fflush(stdout);
+ /* allow C-A-D now, faith@cs.unc.edu, re-fixed 8-Jul-96 */
reboot(0xfee1dead, 672274793, 0x89abcdef);
+ reboot(0xfee1dead, 672274793, 0xcdef0123);
}
/* NOTREACHED */
exit(0); /* to quiet gcc */
@@ -364,7 +373,7 @@ write_wtmp()
time(&ut.ut_time);
ut.ut_type = BOOT_TIME;
- if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) {
+ if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0644)) >= 0) {
write(fd, (char *)&ut, sizeof(ut));
close(fd);
}
diff --git a/login-utils/simpleinit.8 b/login-utils/simpleinit.8
index a506e1ae9..ad942d3b3 100644
--- a/login-utils/simpleinit.8
+++ b/login-utils/simpleinit.8
@@ -90,11 +90,11 @@ An example is as follows:
.nf
.RS
-tty1:console:/sbin/getty 9600 tty1
-tty2:console:/sbin/getty 9600 tty2
-tty3:console:/sbin/getty 9600 tty3
-tty4:console:/sbin/getty 9600 tty4
-# tty5:console:/sbin/getty 9600 tty5
+tty1:linux:/sbin/getty 9600 tty1
+tty2:linux:/sbin/getty 9600 tty2
+tty3:linux:/sbin/getty 9600 tty3
+tty4:linux:/sbin/getty 9600 tty4
+# tty5:linux:/sbin/getty 9600 tty5
# ttyS1:dumb:/sbin/getty 9600 ttyS1
# ttyS2:dumb:/sbin/getty -m -t60 2400 ttyS2
.RE
diff --git a/login-utils/simpleinit.c b/login-utils/simpleinit.c
index 3a39dcd45..14d8cfad2 100644
--- a/login-utils/simpleinit.c
+++ b/login-utils/simpleinit.c
@@ -140,7 +140,7 @@ int main(int argc, char *argv[])
/* clear utmp entry, and append to wtmp if possible */
{
struct utmp *ut;
- int ut_fd;
+ int ut_fd, lf;
utmpname(_PATH_UTMP);
setutent();
@@ -152,13 +152,17 @@ int main(int argc, char *argv[])
ut->ut_type = DEAD_PROCESS;
ut->ut_pid = 0;
ut->ut_addr = 0;
- endutent();
+ /*endutent();*/
pututline(ut);
- if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
- flock(ut_fd, LOCK_EX|LOCK_NB);
- write(ut_fd, ut, sizeof(struct utmp));
- flock(ut_fd, LOCK_UN|LOCK_NB);
- close(ut_fd);
+
+ if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
+ flock(lf, LOCK_EX|LOCK_NB);
+ if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
+ write(ut_fd, ut, sizeof(struct utmp));
+ close(ut_fd);
+ }
+ flock(lf, LOCK_UN|LOCK_NB);
+ close(lf);
}
break;
}
@@ -431,7 +435,7 @@ void set_tz()
void write_wtmp()
{
- int fd;
+ int fd, lf;
struct utmp ut;
memset((char *)&ut, 0, sizeof(ut));
@@ -439,11 +443,14 @@ void write_wtmp()
memset(ut.ut_name, 0, sizeof(ut.ut_name));
time(&ut.ut_time);
ut.ut_type = BOOT_TIME;
-
- if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) {
- flock(fd, LOCK_EX|LOCK_NB); /* make sure init won't hang */
- write(fd, (char *)&ut, sizeof(ut));
- flock(fd, LOCK_UN|LOCK_NB);
- close(fd);
+
+ if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
+ flock(lf, LOCK_EX|LOCK_NB); /* make sure init won't hang */
+ if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) {
+ write(fd, (char *)&ut, sizeof(ut));
+ close(fd);
+ }
+ flock(lf, LOCK_UN|LOCK_NB);
+ close(lf);
}
}
diff --git a/login-utils/ttymsg.c b/login-utils/ttymsg.c
index e6aa39615..1f5fd1f5d 100644
--- a/login-utils/ttymsg.c
+++ b/login-utils/ttymsg.c
@@ -68,7 +68,7 @@ ttymsg(iov, iovcnt, line, tmout)
char *line;
int tmout;
{
- static char device[MAXNAMLEN] = _PATH_DEV;
+ static char device[MAXNAMLEN];
static char errbuf[1024];
register int cnt, fd, left, wret;
struct iovec localiov[6];
@@ -77,17 +77,13 @@ ttymsg(iov, iovcnt, line, tmout)
if (iovcnt > sizeof(localiov) / sizeof(localiov[0]))
return ("too many iov's (change code in wall/ttymsg.c)");
- (void) strcpy(device + sizeof(_PATH_DEV) - 1, line);
- if (strchr(device + sizeof(_PATH_DEV) - 1, '/')) {
+ if (strchr(line, '/')) {
/* A slash is an attempt to break security... */
-#ifdef __linux__
- (void) sprintf(errbuf, "'/' in \"%s\"", device);
-#else
(void) snprintf(errbuf, sizeof(errbuf), "'/' in \"%s\"",
device);
-#endif
return (errbuf);
}
+ (void) snprintf(device, sizeof(device), "%s%s", _PATH_DEV, line);
/*
* open will fail on slip lines or exclusive-use lines
@@ -96,13 +92,8 @@ ttymsg(iov, iovcnt, line, tmout)
if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
if (errno == EBUSY || errno == EACCES)
return (NULL);
-#ifdef __linux__
- (void) sprintf(errbuf,
- "%s: %s", device, strerror(errno));
-#else
(void) snprintf(errbuf, sizeof(errbuf),
"%s: %s", device, strerror(errno));
-#endif
return (errbuf);
}
@@ -140,13 +131,8 @@ ttymsg(iov, iovcnt, line, tmout)
}
cpid = fork();
if (cpid < 0) {
-#ifdef __linux__
- (void) sprintf(errbuf,
- "fork: %s", strerror(errno));
-#else
(void) snprintf(errbuf, sizeof(errbuf),
"fork: %s", strerror(errno));
-#endif
(void) close(fd);
return (errbuf);
}
@@ -172,13 +158,8 @@ ttymsg(iov, iovcnt, line, tmout)
(void) close(fd);
if (forked)
_exit(1);
-#ifdef __linux__
- (void) sprintf(errbuf,
- "%s: %s", device, strerror(errno));
-#else
(void) snprintf(errbuf, sizeof(errbuf),
"%s: %s", device, strerror(errno));
-#endif
return (errbuf);
}
diff --git a/login-utils/vigr.8 b/login-utils/vigr.8
new file mode 100644
index 000000000..ff72d7ae6
--- /dev/null
+++ b/login-utils/vigr.8
@@ -0,0 +1 @@
+.so man8/vipw.8
diff --git a/login-utils/vipw.8 b/login-utils/vipw.8
index b2786d0e5..7f15d951d 100644
--- a/login-utils/vipw.8
+++ b/login-utils/vipw.8
@@ -30,16 +30,21 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)vipw.8 6.7 (Berkeley) 3/16/91
-.\" $Id: vipw.8,v 1.2 1995/03/12 01:33:13 faith Exp $
+.\" $Id: vipw.8,v 1.3 1996/07/02 16:57:55 janl Exp $
.\"
-.Dd March 16, 1991
+.Dd 7 July 1996
.Dt VIPW 8
-.Os BSD 4
+.Os Util-Linux 2.6
.Sh NAME
-.Nm vipw
-.Nd edit the password file
+.Nm vipw, vigr
+.Nd edit the password or group files
.Sh SYNOPSIS
.Nm vipw
+.Op -V
+.Op --version
+.Nm vigr
+.Op -V
+.Op --version
.Sh DESCRIPTION
.Nm Vipw
edits the password file after setting the appropriate locks,
@@ -51,6 +56,9 @@ to try again later. The default editor for
.Nm vipw
is
.Xr vi 1 .
+.br
+.Nm Vigr
+edits the group file in the same manner as vipw.
.Sh ENVIRONMENT
If the following environment variable exists it will be utilized by
.Nm vipw :
@@ -67,6 +75,10 @@ will be invoked instead of the default editor
.Xr passwd 5
.Sh HISTORY
The
-.Nm
+.Nm vipw
command appeared in
.Bx 4.0 .
+.br
+The
+.Nm vigr
+command appeared in Util-Linux 2.6.
diff --git a/login-utils/vipw.c b/login-utils/vipw.c
index 681d9a658..6eff4f3b3 100644
--- a/login-utils/vipw.c
+++ b/login-utils/vipw.c
@@ -33,6 +33,10 @@
* Updated Thu Oct 12 09:56:55 1995 by faith@cs.unc.edu with security
* patches from Zefram <A.Main@dcs.warwick.ac.uk>
*
+ * Updated Thu Nov 9 21:58:53 1995 by Martin Schulze
+ * <joey@finlandia.infodrom.north.de>. Support for vigr.
+ *
+ * Martin Schulze's patches adapted to Util-Linux by Nicolai Langfeldt.
*/
#ifndef lint
@@ -43,9 +47,11 @@ char copyright[] =
#ifndef lint
/*static char sccsid[] = "from: @(#)vipw.c 5.16 (Berkeley) 3/3/91";*/
-static char rcsid[] = "$Id: vipw.c,v 1.4 1995/10/12 14:46:36 faith Exp $";
+static char rcsid[] = "$Id: vipw.c,v 1.6 1997/07/06 00:12:23 aebr Exp $";
#endif /* not lint */
+static char version_string[] = "vipw 1.4";
+
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
@@ -63,13 +69,20 @@ static char rcsid[] = "$Id: vipw.c,v 1.4 1995/10/12 14:46:36 faith Exp $";
#include <paths.h>
#include <unistd.h>
-#include "pathnames.h"
+#include "setpwnam.h"
+#define FILENAMELEN 67
-char *progname = "vipw";
-void pw_error __P((char *, int, int));
+char *progname;
+enum { VIPW, VIGR };
+int program;
+char orig_file[FILENAMELEN]; /* original file /etc/passwd or /etc/group */
+char tmp_file[FILENAMELEN]; /* tmp file */
+char tmptmp_file[FILENAMELEN]; /* very tmp file */
+void pw_error __P((char *, int, int));
+void
copyfile(from, to)
register int from, to;
{
@@ -79,9 +92,10 @@ copyfile(from, to)
while ((nr = read(from, buf, sizeof(buf))) > 0)
for (off = 0; off < nr; nr -= nw, off += nw)
if ((nw = write(to, buf + off, nr)) < 0)
- pw_error(_PATH_PTMP, 1, 1);
+ pw_error(tmp_file, 1, 1);
+
if (nr < 0)
- pw_error(_PATH_PASSWD, 1, 1);
+ pw_error(orig_file, 1, 1);
}
@@ -120,7 +134,6 @@ int
pw_lock()
{
int lockfd, fd, ret;
- char *p;
/*
* If the password file doesn't exist, the system is hosed.
@@ -128,34 +141,37 @@ pw_lock()
* that users can't get at the encrypted passwords while editing.
* Open should allow flock'ing the file; see 4.4BSD. XXX
*/
- lockfd = open(_PATH_PASSWD, O_RDONLY, 0);
+ lockfd = open(orig_file, O_RDONLY, 0);
+
if (lockfd < 0) {
(void)fprintf(stderr, "%s: %s: %s\n",
- progname, _PATH_PASSWD, strerror(errno));
+ progname, orig_file, strerror(errno));
exit(1);
}
#if 0 /* flock()ing is superfluous here, with the ptmp/ptmptmp system. */
if (flock(lockfd, LOCK_EX|LOCK_NB)) {
(void)fprintf(stderr,
- "%s: the password file is busy.\n", progname);
+ "%s: the %s file is busy.\n", progname,
+ program == VIPW ? "password" : "group" );
exit(1);
}
#endif
- if ((fd = open(_PATH_PTMPTMP, O_WRONLY|O_CREAT, 0644)) == -1) {
- (void)fprintf(stderr,
- "%s: %s: %s\n", progname, _PATH_PTMPTMP, strerror(errno));
- exit(1);
+ if ((fd = open(tmptmp_file, O_WRONLY|O_CREAT, 0644)) == -1) {
+ (void)fprintf(stderr,
+ "%s: %s: %s\n", progname, tmptmp_file, strerror(errno));
+ exit(1);
}
- ret = link(_PATH_PTMPTMP, _PATH_PTMP);
- (void)unlink(_PATH_PTMPTMP);
+ ret = link(tmptmp_file, tmp_file);
+ (void)unlink(tmptmp_file);
if (ret == -1) {
if (errno == EEXIST)
(void)fprintf(stderr,
- "%s: the password file is busy\n", progname);
+ "%s: the %s file is busy\n", progname,
+ program == VIPW ? "password" : "group" );
else
(void)fprintf(stderr, "%s: can't link %s: %s\n", progname,
- _PATH_PTMP, strerror(errno));
+ tmp_file, strerror(errno));
exit(1);
}
copyfile(lockfd, fd);
@@ -167,15 +183,18 @@ pw_lock()
void
pw_unlock()
{
- unlink(_PATH_PASSWD ".OLD");
- link(_PATH_PASSWD, _PATH_PASSWD ".OLD" );
- if (rename(_PATH_PTMP, _PATH_PASSWD) == -1) {
- (void)fprintf(stderr,
- "%s: can't unlock %s: %s (your changes are still in %s)\n",
- progname, _PATH_PASSWD, strerror(errno), _PATH_PTMP);
- exit(1);
- }
- (void)unlink(_PATH_PTMP);
+ char tmp[FILENAMELEN];
+
+ sprintf(tmp, "%s%s", orig_file, ".OLD");
+ unlink(tmp);
+ link(orig_file, tmp);
+ if (rename(tmp_file, orig_file) == -1) {
+ (void)fprintf(stderr,
+ "%s: can't unlock %s: %s (your changes are still in %s)\n",
+ progname, orig_file, strerror(errno), tmp_file);
+ exit(1);
+ }
+ (void)unlink(tmp_file);
}
@@ -199,7 +218,7 @@ pw_edit(notsetuid)
(void)setgid(getgid());
(void)setuid(getuid());
}
- execlp(editor, p, _PATH_PTMP, NULL);
+ execlp(editor, p, tmp_file, NULL);
_exit(1);
}
for (;;) {
@@ -231,28 +250,48 @@ pw_error(name, err, eval)
(void)fprintf(stderr, "%s\n", strerror(sverrno));
}
(void)fprintf(stderr,
- "%s: %s unchanged\n", progname, _PATH_PASSWD);
- (void)unlink(_PATH_PTMP);
+ "%s: %s unchanged\n", progname, orig_file);
+ (void)unlink(tmp_file);
exit(eval);
}
-main()
+int main(int argc, char *argv[])
{
- register int pfd, tfd;
- struct stat begin, end;
-
- pw_init();
- pw_lock();
-
- if (stat(_PATH_PTMP, &begin))
- pw_error(_PATH_PTMP, 1, 1);
- pw_edit(0);
- if (stat(_PATH_PTMP, &end))
- pw_error(_PATH_PTMP, 1, 1);
- if (begin.st_mtime == end.st_mtime) {
- (void)fprintf(stderr, "vipw: no changes made\n");
- pw_error((char *)NULL, 0, 0);
- }
- pw_unlock();
- exit(0);
+ struct stat begin, end;
+
+ bzero(tmp_file, FILENAMELEN);
+ progname = (rindex(argv[0], '/')) ? rindex(argv[0], '/') + 1 : argv[0];
+ if (!strcmp(progname, "vigr")) {
+ program = VIGR;
+ strncpy(orig_file, GROUP_FILE, FILENAMELEN-1);
+ strncpy(tmp_file, GTMP_FILE, FILENAMELEN-1);
+ strncpy(tmptmp_file, GTMPTMP_FILE, FILENAMELEN-1);
+ }
+ else {
+ program = VIPW;
+ strncpy(orig_file, PASSWD_FILE, FILENAMELEN-1);
+ strncpy(tmp_file, PTMP_FILE, FILENAMELEN-1);
+ strncpy(tmptmp_file, PTMPTMP_FILE, FILENAMELEN-1);
+ }
+
+ if ((argc > 1) &&
+ (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) {
+ printf("%s\n", version_string);
+ exit(0);
+ }
+
+ pw_init();
+ pw_lock();
+
+ if (stat(tmp_file, &begin))
+ pw_error(tmp_file, 1, 1);
+ pw_edit(0);
+ if (stat(tmp_file, &end))
+ pw_error(tmp_file, 1, 1);
+ if (begin.st_mtime == end.st_mtime) {
+ (void)fprintf(stderr, "%s: no changes made\n", progname);
+ pw_error((char *)NULL, 0, 0);
+ }
+ pw_unlock();
+ exit(0);
}
diff --git a/login-utils/wall.c b/login-utils/wall.c
index 7f3e61235..7957ae299 100644
--- a/login-utils/wall.c
+++ b/login-utils/wall.c
@@ -127,7 +127,7 @@ usage:
continue;
#endif
strncpy(line, utmp.ut_line, sizeof(utmp.ut_line));
- line[sizeof(utmp.ut_line)] = '\0';
+ line[sizeof(utmp.ut_line)-1] = '\0';
if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL)
(void)fprintf(stderr, "wall: %s\n", p);
}
@@ -145,11 +145,11 @@ makemsg(fname)
time_t now, time();
FILE *fp;
int fd;
- char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[15];
+ char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[64];
char *getlogin(), *strcpy(), *ttyname();
- (void)strcpy(tmpname, _PATH_TMP);
- (void)strcat(tmpname, "/wall.XXXXXX");
+ (void)snprintf(tmpname, sizeof(tmpname),
+ "%s/wall.XXXXXX", _PATH_TMP);
if (!(fd = mkstemp(tmpname)) || !(fp = fdopen(fd, "r+"))) {
(void)fprintf(stderr, "wall: can't open temporary file.\n");
exit(1);
@@ -171,11 +171,13 @@ makemsg(fname)
* in column 80, but that can't be helped.
*/
(void)fprintf(fp, "\r%79s\r\n", " ");
- (void)sprintf(lbuf, "Broadcast Message from %s@%s",
- whom, hostname);
+ (void)snprintf(lbuf, sizeof(lbuf),
+ "Broadcast Message from %s@%s",
+ whom, hostname);
(void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf);
- (void)sprintf(lbuf, " (%s) at %d:%02d ...", ttyname(2),
- lt->tm_hour, lt->tm_min);
+ (void)snprintf(lbuf, sizeof(lbuf),
+ " (%s) at %d:%02d ...", ttyname(2),
+ lt->tm_hour, lt->tm_min);
(void)fprintf(fp, "%-79.79s\r\n", lbuf);
}
(void)fprintf(fp, "%79s\r\n", " ");