summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Bogatov <KAction@gnu.org>2017-09-01 04:09:35 +0300
committerDmitry Bogatov <KAction@gnu.org>2018-02-14 19:10:28 +0300
commitd409f1899d83788d23ee2de03aef58d8e870b033 (patch)
tree72bba1af4427b58ede705943133e3d13fedad206
parentf8621b4aafe28a13c42de31b094f2763b1c3409f (diff)
New upstream version 0.7
-rw-r--r--.cvsignore4
-rw-r--r--CHANGES54
-rw-r--r--COPYING340
-rw-r--r--Makefile59
-rw-r--r--README51
-rw-r--r--README.PAM28
-rw-r--r--checkpassword-pam.c74
-rw-r--r--checkpassword-pam2.c131
-rw-r--r--checkpassword.c91
-rw-r--r--fgetty.890
-rw-r--r--fgetty.c319
-rw-r--r--fmt.h25
-rw-r--r--fmt_ulong.c13
-rw-r--r--login.c149
-rw-r--r--login2.c110
15 files changed, 1538 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 0000000..6d9d856
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,4 @@
+checkpassword
+fgetty
+login
+login2
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..a89f94b
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,54 @@
+0.7:
+ You can now run fgetty as "fgetty 1" and it will try "/dev/vc/1" and
+ "/dev/tty1" before giving up. That means, the same fgetty line can
+ be run with and without devfs. Your boot sequence may fail but at
+ least you get a getty!
+ call setsid in case your init does not do it. Minit and sysvinit do.
+ Now you can run fgetty under runit, and maybe even directly from
+ the console. Patch by John Palkovic.
+ checkpassword now gives an error message if stdout is a TTY.
+ fgetty now works (a little) if it can't set the controlling TTY.
+ checkpassword now also accepts an empty password if the password
+ field in /etc/passwd or /etc/shadow is empty.
+ fix bug if someone left descriptors open in login.c (Florian Westphal)
+
+0.6:
+ the utmp code was broken. It only looked for the PID, not for the
+ "line" (device). So utmp grew needlessly.
+ fixed make install
+ add man page from Tino Reichardt
+ Enrico Scholz sent a patch that adds --long-hostname and adds error
+ checking for gethostname when it is not \0-terminated.
+
+0.5
+ login will accept passwords up to 99 characters (previously it limited
+ to 8 because DES crypt() only looks at the first 8 characters anyway).
+ With MD5 crypt support, that's not so smart a move. Laurent BERCOT
+ reported this bug. Thanks, Laurent!
+
+ Also, login will try to add users to group "console". This can be
+ used to give console users write access to the sound device.
+
+0.4
+ fgetty will turn echo off before executing login. This fixes the
+ age-old security problem when the load is heavy at login:
+
+ host login: hax0r
+ imsol33tPassword: _
+
+0.3.1
+ login2 contained a bad beginner's error regarding error checking when
+ reading motd. If you didn't have motd, login2 would loop :-(
+ Found and fixed by Michael Bacarella.
+
+0.3
+ added a checkpassword that accepts a "nosetuid" flag in the
+ additional data section of the checkpassword API and then omits the
+ setuid(). Then, the called application (in the fgetty case,
+ /bin/login2) can do a "chown $UID. $TTY" before doing the setuid()
+ call itself, so finally, your TTY belongs to you. screen was always
+ complaining ;)
+
+0.2:
+ added login and login2 and edited README to "document" them.
+ fgetty will now also put $TTY and $HOST in the environment.
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..730a176
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,59 @@
+# Uncomment the following if you are a distribution maker and want to
+# install to somewhere else than /
+#DESTDIR=/tmp/fefix
+
+all: fgetty login login2 checkpassword
+
+DIET=diet -Os
+#CROSS=arm-linux-
+CROSS=
+LDFLAGS=-s
+
+%.o: %.c
+# gcc -march=i386 -mcpu=i386 -pipe -Os -fomit-frame-pointer -I../dietlibc/include -c $^ -DTEST
+ $(DIET) $(CROSS)$(CC) -pipe -Os -fomit-frame-pointer -I../dietlibc/include -c $^ -DTEST
+# gcc -march=i386 -mcpu=i386 -pipe -g -I../dietlibc/include -DTEST -c $^
+ $(CROSS)strip -x -R .comment -R .note $@
+
+%: %.o
+ $(DIET) $(CROSS)$(CC) -o $@ $^ $(LDFLAGS)
+
+fgetty: fgetty.o fmt_ulong.o
+
+login: login.o
+login2: login2.o
+checkpassword: checkpassword.o
+checkpassword-pam: checkpassword-pam.o checkpassword-pam2.o
+ $(CROSS)$(CC) -o $@ $^ -lmisc $(LDFLAGS)
+
+debug: fgetty.c fmt_ulong.o
+ gcc -g -o debug fgetty.c fmt_ulong.o -DDEBUG
+
+install:
+ install -d $(DESTDIR)/bin $(DESTDIR)/sbin $(DESTDIR)/usr/man/man8
+ install login $(DESTDIR)/bin/login1
+ install login2 $(DESTDIR)/bin
+ install fgetty $(DESTDIR)/sbin
+ install checkpassword $(DESTDIR)/bin/checkpassword.login
+ install -m 644 fgetty.8 $(DESTDIR)/usr/man/man8/fgetty.8
+ @echo "now change your /etc/inittab to do something like"
+ @echo " 1:123:respawn:/sbin/fgetty /dev/vc/1 --noclear"
+
+clean:
+ rm -f *.o fgetty debug dietgetty login login2 checkpassword core
+
+sigs: fgetty.sig login.sig login2.sig checkpassword.sig
+
+.SUFFIXES: .sig
+%.sig: %
+ gpg --detach-sign $<
+
+VERSION=fgetty-$(shell head -n 1 CHANGES|sed 's/://')
+CURNAME=$(notdir $(shell pwd))
+
+tar: clean rename
+ cd ..; tar cvvf $(VERSION).tar.bz2 $(VERSION) --use=bzip2 --exclude CVS
+
+rename:
+ if test $(CURNAME) != $(VERSION); then cd .. && mv $(CURNAME) $(VERSION); fi
+
diff --git a/README b/README
new file mode 100644
index 0000000..6e0b39c
--- /dev/null
+++ b/README
@@ -0,0 +1,51 @@
+
+This is actually a mingetty without the printfs.
+Why? Because then you can link it against dietlibc
+(http://www.fefe.de/dietlibc/).
+
+Actually, diet libc now supports printf, but not using it makes binaries
+smaller nonetheless.
+
+The difference is remarkable:
+
+USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
+root 5487 0.0 0.1 1180 444 tty5 S 00:40 0:00 /sbin/mingetty tty5
+root 6035 0.0 0.0 16 16 tty5 S 00:45 0:00 /sbin/fgetty tty5
+
+
+
+I saw that on some really absurdly broken crap Linux distributions
+(apparently the ones using PAM ;-}), login stay in memory as long as a
+user is logged in, wasting precious memory. So I decided to write a
+replacement login as well.
+
+My login uses the checkpassword (see http://cr.yp.to/checkpwd.html)
+password checking interface. For the casual end-user, this means that
+you will need to get and install checkpassword. For others, this means
+unprecedented flexibility for the system administrator, because the
+authentication for login can be done separately from login, and without
+sacrificing system resources.
+
+The default checkpassword program from http://cr.yp.to/checkpwd.html)
+checks against /etc/passwd and /etc/shadow, but the interface is general
+enough to make it possible to plug in different authentication, even
+RADIUS or LDAP or whatever you had in mind. You just have to write the
+trivial checkpassword utility for your authentication method. I plan to
+write a few small checkpassword variants to allow for shadowed MD5
+passwords from a CBD database, for example.
+
+This design has the following drawbacks:
+
+ 1. since checkpassword exits on error, there is no "bad
+ username/password pair" error message.
+ 2. For the same reason, there is no 1 second delay on bad passwords.
+
+We can't wrap checkpassword, because once the wrapper exits, init
+respawns fgetty. The only good solution would be to make a
+checkpassword that prints the error message and exits only after a one
+second delay.
+
+
+login and login2 do _not_ mess with the tty or apply /etc/environment.
+These are prime cases of unnecessary features in my eyes. Do that in
+your shell startup files or whatever.
diff --git a/README.PAM b/README.PAM
new file mode 100644
index 0000000..3c95aea
--- /dev/null
+++ b/README.PAM
@@ -0,0 +1,28 @@
+I received an email and a patch on Sep 15 2002. I incorporated the
+patch, here is the email.
+
+ From: <kromJx@crosswinds.net>
+ To: <web@fefe.de>
+ Subject: fgetty-0.6: a checkpassword with PAM support
+
+ Hi Felix,
+
+ I put together a checkpassword-pam program. I understand that
+ you don't like PAM, but nevertheless it could be useful to
+ someone else besides me. It is based on your checkpassword program
+ and the routines found in support-pam.c of the checkpassword-pam-0.95
+ program.
+
+ Feel free to edit/distribute/(or even ignore it) :-)
+
+ Thanks for writing/sharing such great non-bloated tools.
+
+ - J
+
+To build it, say
+
+ $ make checkpassword-pam
+
+Please note that you can't link checkpassword-pam with the diet libc,
+and I could not test the patch because I don't have PAM installed on any
+box.
diff --git a/checkpassword-pam.c b/checkpassword-pam.c
new file mode 100644
index 0000000..bbd012d
--- /dev/null
+++ b/checkpassword-pam.c
@@ -0,0 +1,74 @@
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+
+extern char** environ;
+
+unsigned int fmt_ulong(char *dest,unsigned long i) {
+ register unsigned long len,tmp,len2;
+ /* first count the number of bytes needed */
+ for (len=1, tmp=i; tmp>9; ++len) tmp/=10;
+ if (dest)
+ for (tmp=i, dest+=len, len2=len+1; --len2; tmp/=10)
+ *--dest = (tmp%10)+'0';
+ return len;
+}
+
+int main(int argc,char* argv[]) {
+ char buf[513];
+ char* last;
+ int len;
+ char *login,*ptr;
+ struct passwd *pw;
+
+ if (!argv[1]) return 2;
+ for (len=0; len<512; ) {
+ int tmp;
+ tmp=read(3,buf+len,512-len);
+ if (tmp==-1) return 111;
+ if (tmp==0) break;
+ len+=tmp;
+ }
+ close(3);
+ buf[len]=0; last=buf+len;
+ login=buf;
+ if ((pw=getpwnam(login))) {
+ ptr=login+strlen(login)+1;
+ if (!authenticate_using_pam("login", login, ptr)) {
+ char **env,**ep, *eptty;
+ char buf[100];
+ for (len=0; environ[len]; ++len) ;
+ env=alloca((len+4)*sizeof(char*));
+ ep=env;
+ for (len=0; environ[len]; ++len) {
+ if (!strncmp(environ[len],"USER=",5)) continue;
+ if (!strncmp(environ[len],"HOME=",5)) continue;
+ if (!strncmp(environ[len],"SHELL=",6)) continue;
+ if (!strncmp(environ[len],"UID=",4)) continue;
+ *ep=environ[len]; ++ep;
+ }
+ *ep=alloca(strlen(pw->pw_shell)+7); strcat(strcpy(*ep,"SHELL="),pw->pw_shell); ++ep;
+ *ep=alloca(strlen(login)+6); strcat(strcpy(*ep,"USER="),login); ++ep;
+ *ep=alloca(strlen(pw->pw_dir)+7); strcat(strcpy(*ep,"HOME="),pw->pw_dir); ++ep;
+ strcpy(buf,"UID=");
+ buf[4+fmt_ulong(buf+4,pw->pw_uid)]=0;
+ *ep=buf; ++ep;
+ *ep=0;
+
+ ptr+=strlen(ptr)+1; /* skip password */
+
+ if (initgroups(pw->pw_name,pw->pw_gid)==-1) return 1;
+/* if (setgroups(1,&pw->pw_gid)==-1) return 1; */
+ if (setgid(pw->pw_gid)==-1) return 1;
+ if (ptr) {
+ ptr+=strlen(ptr)+1; /* skip timestamp */
+ if (ptr>=last) ptr=0;
+ }
+ if (!ptr || strcmp(ptr,"nosetuid")) if (setuid(pw->pw_uid)==-1) return -1;
+ if (chdir(pw->pw_dir)==-1) return 111;
+ execve(argv[1],argv+1,env);
+ return 111;
+ }
+ }
+ return 1;
+}
diff --git a/checkpassword-pam2.c b/checkpassword-pam2.c
new file mode 100644
index 0000000..3fc7f3a
--- /dev/null
+++ b/checkpassword-pam2.c
@@ -0,0 +1,131 @@
+/*
+ PAM support for a fgetty-style checkpasswd
+
+ This file is a (slightly modified) concatenation of the files
+ pam-support.[ch] that come with Alexey Mahotkin's fine
+ "checkpassword-pam". Only the essential stuff has been kept, ie.
+ only what is needed to build a "checkpassword" compatible with the
+ one that is distributed with "fgetty".
+
+ Thanks, Alexey!
+*/
+/*
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ Copyright (c) Alexey Mahotkin <alexm@hsys.msk.ru> 2002
+
+ PAM support for checkpassword-pam
+
+*/
+#include <string.h>
+#include <security/pam_appl.h>
+
+static const char* global_password;
+
+static int
+conversation (int num_msg, const struct pam_message **msgs,
+ struct pam_response **resp, void *appdata_ptr)
+{
+ int i;
+ struct pam_response* responses;
+ (void) appdata_ptr;
+
+ /* safety check */
+ if (num_msg <= 0) {
+ return PAM_CONV_ERR;
+ }
+
+ /* allocate array of responses */
+ responses = calloc(num_msg, sizeof(struct pam_response));
+ if (!responses) {
+ return PAM_CONV_ERR;
+ }
+
+ for (i = 0; i < num_msg; i++) {
+ const struct pam_message *msg = msgs[i];
+ struct pam_response* response = &(responses[i]);
+ char* style = NULL;
+ switch (msg->msg_style) {
+ case PAM_PROMPT_ECHO_OFF: style = "PAM_PROMPT_ECHO_OFF"; break;
+ case PAM_PROMPT_ECHO_ON: style = "PAM_PROMPT_ECHO_ON"; break;
+ case PAM_ERROR_MSG: style = "PAM_ERROR_MSG"; break;
+ case PAM_TEXT_INFO: style = "PAM_TEXT_INFO"; break;
+ }
+
+ switch (msg->msg_style) {
+ case PAM_PROMPT_ECHO_OFF:
+ /* reply with password */
+ response->resp = strdup(global_password);
+ if (!response->resp)
+ return PAM_CONV_ERR;
+ break;
+
+ default:
+ return PAM_CONV_ERR;
+ }
+ response->resp_retcode = 0;
+ }
+
+ *resp = responses;
+
+ return PAM_SUCCESS;
+}
+
+
+
+int
+authenticate_using_pam (const char* service_name,
+ const char* username,
+ const char* password)
+{
+ struct pam_conv pam_conversation = { conversation, NULL };
+ pam_handle_t* pamh;
+ int retval;
+
+ /* to be used later from conversation() */
+ global_password = password;
+
+ /* initialize the PAM library */
+ retval = pam_start(service_name, username, &pam_conversation, &pamh);
+ if (retval != PAM_SUCCESS) {
+ return 111;
+ }
+
+ /* PAM_TTY is needed by the securetty module */
+ retval = pam_set_item(pamh, PAM_TTY, (void *)getenv("TTY"));
+ if (retval != PAM_SUCCESS) {
+ return 1;
+ }
+
+ /* Authenticate the user */
+ retval = pam_authenticate(pamh, 0);
+ if (retval != PAM_SUCCESS) {
+ return 1;
+ }
+
+ retval = pam_acct_mgmt(pamh, 0);
+ if (retval != PAM_SUCCESS) {
+ return 1;
+ }
+
+ retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ if (retval != PAM_SUCCESS) {
+ return 1;
+ }
+
+ /* terminate the PAM library */
+ retval = pam_end(pamh, retval);
+ if (retval != PAM_SUCCESS) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/checkpassword.c b/checkpassword.c
new file mode 100644
index 0000000..b7bbe85
--- /dev/null
+++ b/checkpassword.c
@@ -0,0 +1,91 @@
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <stdio.h>
+#ifdef __dietlibc__
+#include <write12.h>
+#else
+inline void __write2(const char* message) {
+ write(2,message,strlen(message));
+}
+#endif
+
+extern char** environ;
+
+unsigned int fmt_ulong(char *dest,unsigned long i) {
+ register unsigned long len,tmp,len2;
+ /* first count the number of bytes needed */
+ for (len=1, tmp=i; tmp>9; ++len) tmp/=10;
+ if (dest)
+ for (tmp=i, dest+=len, len2=len+1; --len2; tmp/=10)
+ *--dest = (tmp%10)+'0';
+ return len;
+}
+
+int main(int argc,char* argv[]) {
+ char buf[513];
+ char* last;
+ int len;
+ char *login,*passwd,*ptr;
+ struct passwd *pw;
+ struct spwd *spw;
+
+ if (!argv[1]) return 2;
+ for (len=0; len<512; ) {
+ int tmp;
+ tmp=read(3,buf+len,512-len);
+ if (tmp==-1) return 111;
+ if (tmp==0) break;
+ len+=tmp;
+ }
+ close(3);
+ buf[len]=0; last=buf+len;
+ login=buf;
+ if ((pw=getpwnam(login))) {
+ passwd=pw->pw_passwd;
+ if ((spw=getspnam(login)))
+ passwd=spw->sp_pwdp;
+ ptr=login+strlen(login)+1;
+ if (!*passwd || !strcmp(crypt(ptr,passwd),passwd)) {
+ char **env,**ep;
+ char buf[100];
+ for (len=0; environ[len]; ++len) ;
+ env=alloca((len+4)*sizeof(char*));
+ ep=env;
+ for (len=0; environ[len]; ++len) {
+ if (!strncmp(environ[len],"USER=",5)) continue;
+ if (!strncmp(environ[len],"HOME=",5)) continue;
+ if (!strncmp(environ[len],"SHELL=",6)) continue;
+ if (!strncmp(environ[len],"UID=",4)) continue;
+ *ep=environ[len]; ++ep;
+ }
+ *ep=alloca(strlen(pw->pw_shell)+7); strcat(strcpy(*ep,"SHELL="),pw->pw_shell); ++ep;
+ *ep=alloca(strlen(login)+6); strcat(strcpy(*ep,"USER="),login); ++ep;
+ *ep=alloca(strlen(pw->pw_dir)+7); strcat(strcpy(*ep,"HOME="),pw->pw_dir); ++ep;
+ strcpy(buf,"UID=");
+ buf[4+fmt_ulong(buf+4,pw->pw_uid)]=0;
+ *ep=buf; ++ep;
+ *ep=0;
+
+ ptr+=strlen(ptr)+1; /* skip password */
+
+ if (initgroups(pw->pw_name,pw->pw_gid)==-1) return 1;
+/* if (setgroups(1,&pw->pw_gid)==-1) return 1; */
+ if (setgid(pw->pw_gid)==-1) return 1;
+ if (ptr) {
+ ptr+=strlen(ptr)+1; /* skip timestamp */
+ if (ptr>=last) ptr=0;
+ }
+ if (!ptr || strcmp(ptr,"nosetuid")) if (setuid(pw->pw_uid)==-1) return -1;
+ if (chdir(pw->pw_dir)==-1) return 111;
+ execve(argv[1],argv+1,env);
+ return 111;
+ }
+ }
+ if (isatty(0) && isatty(1)) {
+ __write2("checkpassword: wrong password.\n");
+ sleep(5);
+ }
+ return 1;
+}
diff --git a/fgetty.8 b/fgetty.8
new file mode 100644
index 0000000..9c8af6d
--- /dev/null
+++ b/fgetty.8
@@ -0,0 +1,90 @@
+.\" Tino Reichardt <der@mcmilk.de> (2002-01-19)
+.TH FGETTY 8 "2002-01-19" "fgetty" "System Administrator's Manual"
+.SH "NAME"
+fgetty \- a small getty for linux
+.SH "SYNOPSIS"
+\fBfgetty\fR \fItty\fR [\fI--noclear\fR] [\fI--long-hostname\fR]
+.SH "DESCRIPTION"
+The command \fBfgetty\fP is normally invoked by \fIinit(8)\fP, opens a tty port,
+prompts for a login name and invokes the /bin/login command.
+.SH "OPTIONS"
+\fB--noclear\fR makes fgetty not clear the screen before displaying the
+login prompt.
+
+\fB--long-hostname\fR makes fgetty display the full
+hostname in the login prompt.
+.SH "FILES"
+.TS
+tab (@);
+l l.
+/etc/issue@ printed before the login prompt
+/etc/inittab@ \fIinit\fP(8) configuration file
+/var/run/utmp@ the system status file
+.TE
+.SH ISSUE ESCAPES
+The issue-file (\fI/etc/issue\fP or the 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.
+.TP
+d
+the current date. (eg: 2002-01-19)
+.TP
+s
+the system name, the name of the operating system. (eg: Linux)
+.TP
+l
+the name of the current tty line. (eg: tty3)
+.TP
+m
+the architecture identifier of the machine (eg: i586)
+.TP
+n
+the nodename of the machine, also known as the hostname. (eg: sirius)
+.TP
+o
+the domainname of the machine. (eg: (none))
+.TP
+r
+the release number of the OS. (eg: 2.4.3-i)
+.TP
+t
+the current time. (eg: 14:51:51)
+.TP
+u
+the number of current users logged in. (eg: 4)
+.TP
+U
+the string "1 user" or "<n> users", where <n> is the number of current
+users logged in. (eg: 4 users)
+.TP
+v
+Insert the version of the OS. (eg: #2 Fre Jan 18 23:05:45 CET 2002)
+.SH "ENVIRONMENT VARIABLES"
+.TS
+tab (@);
+l l.
+HOST@ is set to your hostname
+TERM@ is set to linux
+TTY@ is set to the current tty line
+.TE
+.SH "RETURN VALUES"
+.TS
+tab (@);
+l l.
+\fB1\fP @could not chown/chmod tty device
+\fB3\fP @could not open tty device
+\fB4\fP @not a typewriter
+\fB5\fP @vhangup failed
+\fB6\fP @could not open tty (can't happen)
+\fB7\fP @dup failed
+\fB8\fP @could not exec login
+\fB9\fP @read returned an unexpected error
+\fB10\fP @unprintable character in login name
+\fB11\fP @login name too long (>40)
+\fB13\fP @user name started with a dash
+\fB23\fP @received SIGQUIT
+.TE
+.SH "AUTHOR"
+Felix von Leitner <felix-fgetty@fefe.de>
+.PP
+Homepage: http://www.fefe.de/fgetty/
diff --git a/fgetty.c b/fgetty.c
new file mode 100644
index 0000000..c4a6241
--- /dev/null
+++ b/fgetty.c
@@ -0,0 +1,319 @@
+/* This is mostly mingetty without printf */
+
+#define _GNU_SOURCE
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <termios.h>
+#include <stdlib.h>
+
+#include "fmt.h"
+
+static struct utsname uts;
+static char hn[MAXHOSTNAMELEN + 6]="HOST=";
+static int hn_len=5;
+static time_t cur_time;
+static char *tty;
+
+static int noclear=0;
+
+void whine(const char* message) {
+ write(2,message,strlen(message));
+}
+
+void error(char *message,int exitcode) {
+ whine(message);
+ exit(exitcode);
+}
+
+static void echo_off() {
+ struct termios foo;
+ if (!tcgetattr(0,&foo)) {
+ foo.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ tcsetattr(0, TCSANOW, &foo);
+ }
+}
+
+int doutmp() {
+ off_t curpos;
+ struct utmp ut;
+ pid_t mypid=getpid();
+ int fd=open(_PATH_UTMP,O_RDWR);
+ if (fd) {
+ for (;;) {
+ int len;
+ curpos=lseek(fd,0,SEEK_CUR);
+ len=read(fd,&ut,sizeof(ut));
+ if (len!=sizeof(ut)) break;
+ if (ut.ut_pid==mypid || !strcmp(ut.ut_line,tty+5)) {
+/* write(1,"found my utmp record\n",21); */
+ break;
+ }
+ }
+ if (ut.ut_pid!=mypid) {
+ memset(&ut,0,sizeof(ut));
+ ut.ut_pid=mypid;
+ memcpy(ut.ut_id,tty+3,sizeof(ut.ut_id));
+ }
+ memcpy(ut.ut_user,"LOGIN",6);
+ memcpy(ut.ut_line,tty+5,sizeof(ut.ut_line));
+ ut.ut_tv.tv_sec=cur_time;
+ ut.ut_type=LOGIN_PROCESS;
+ lseek(fd,curpos,SEEK_SET);
+ write(fd,&ut,sizeof(ut));
+ close(fd);
+ }
+ if ((fd=open(_PATH_WTMP,O_APPEND|O_WRONLY))>=0) {
+ write(fd,&ut,sizeof(ut));
+ close(fd);
+ }
+}
+
+void sigquit_handler(int signum) {
+ error("SIGQUIT received\n",23);
+}
+
+void open_tty() {
+ struct sigaction sa;
+ int fd;
+ if (chown(tty,0,0) || chmod(tty,0600))
+ error("fgetty: could not chown/chmod tty device\n",1);
+ sa.sa_handler=SIG_IGN;
+ sa.sa_flags=0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGHUP,&sa,NULL);
+ sa.sa_handler=sigquit_handler;
+ sigaction(SIGQUIT,&sa,NULL);
+ setsid();
+ if ((fd=open(tty, O_RDWR, 0))<0)
+ error("fgetty: could not open tty device\n",3);
+ if (!isatty(fd))
+ error("fgetty: \"not a typewriter\" ;-)\n",4);
+ if (ioctl (fd, TIOCSCTTY, (void *)1)==0) {
+ if (vhangup()) /* linux specific */
+ error("fgetty: vhangup failed\n",5);
+ } else
+ whine("fgetty: warning: could not set controlling tty!\n");
+ close(2); close(1); close(0); close(fd);
+ if (open(tty,O_RDWR,0) != 0)
+ error("fgetty: could not open tty\n",6);
+ if (dup(0) != 1 || dup(0) != 2)
+ error("could not dup stdout and stderr\n",7);
+ if (!noclear)
+ write(0,"\033c",2); /* linux specific */
+ sa.sa_handler=SIG_DFL;
+ sa.sa_flags=0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGHUP,&sa,NULL);
+}
+
+void output_special_char(char c) {
+ switch (c) {
+ case 's': write(1,uts.sysname,strlen(uts.sysname)); break;
+ case 'n': write(1,uts.nodename,strlen(uts.nodename)); break;
+ case 'r': write(1,uts.release,strlen(uts.release)); break;
+ case 'v': write(1,uts.version,strlen(uts.version)); break;
+ case 'm': write(1,uts.machine,strlen(uts.machine)); break;
+ case 'o': write(1,uts.domainname,strlen(uts.domainname)); break;
+ case 't':
+ case 'd':
+ {
+ time_t now;
+ struct tm *tm;
+ char buf[30];
+ char *tmp;
+
+ time (&now);
+ tm = localtime (&now);
+ if (c == 'd') {
+ tmp=buf+fmt_ulong(buf,tm->tm_year+1900);
+ *tmp++='-';
+ tm->tm_mon++;
+ *tmp++=tm->tm_mon/10+'0';
+ *tmp++=tm->tm_mon%10+'0';
+ *tmp++='-';
+ *tmp++=tm->tm_mday/10+'0';
+ *tmp++=tm->tm_mday%10+'0';
+ *tmp++=0;
+ write(1,buf,strlen(buf));
+#if 0
+ /* ISO 8601 */
+ printf ("%d-%02d-%02d", tm->tm_year,
+ tm->tm_mon+1, tm->tm_mday);
+#endif
+ } else {
+ buf[0]=tm->tm_hour/10+'0';
+ buf[1]=tm->tm_hour%10+'0';
+ buf[2]=':';
+ buf[3]=tm->tm_min/10+'0';
+ buf[4]=tm->tm_min%10+'0';
+ buf[5]=':';
+ buf[6]=tm->tm_sec/10+'0';
+ buf[7]=tm->tm_sec%10+'0';
+ write(1,buf,8);
+ }
+#if 0
+ tmp=buf;
+ printf ("%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+#endif
+ break;
+ }
+ case 'l': write(1,tty+5,strlen(tty)-5); break;
+ case 'u':
+ case 'U':
+ {
+ int users=0;
+ struct utmp ut;
+ int fd=open(_PATH_UTMP,O_RDWR);
+ char buf[20];
+ if (fd) {
+ for (;;) {
+ int len;
+ len=read(fd,&ut,sizeof(ut));
+ if (len!=sizeof(ut)) break;
+ if (ut.ut_type == USER_PROCESS) users++;
+ }
+ close(fd);
+ }
+ write(1,buf,fmt_ulong(buf,users));
+ if (c=='U') {
+ if (users==1)
+ write(1," user",5);
+ else
+ write(1," users",6);
+ }
+ }
+ break;
+ default:
+ write(1,&c,1);
+ }
+}
+
+void do_prompt() {
+ int fd=open("/etc/issue",O_RDONLY);
+ char *buf;
+ off_t length;
+ write(1,"\n",1);
+ if (fd) {
+ char *c,*last;
+ length=lseek(fd,0,SEEK_END);
+ lseek(fd,0,SEEK_SET);
+ buf=alloca(length+1);
+ read(fd,buf,length);
+ close(fd);
+ last=buf+length;
+ for (c=buf; c<last; c++) {
+ if (*c=='\\')
+ output_special_char(*++c);
+ else
+ write(1,c,1);
+ }
+ }
+
+ write(1,hn+5,hn_len-5);
+ write(1," login: ",8);
+}
+
+static inline int _isprint(char c) {
+ return ((c>='A' && c<='Z') ||
+ (c>='a' && c<='z') ||
+ (c>='0' && c<='9') ||
+ (c=='_' || c=='.' || c==',' || c=='-'));
+}
+
+char *get_logname() {
+ static char logname[40];
+ char *c;
+ ioctl(0, TCFLSH, 0); /* flush pending input */
+ for (*logname=0; *logname==0; ) {
+ do_prompt();
+ for (c=logname;;) {
+ if (read(0,c,1)<1) {
+ if (errno==EINTR || errno==EIO || errno==ENOENT)
+ exit(0);
+ error("received strange error\n",9);
+ }
+ if (*c == '\n' || *c == '\r') {
+ *c=0;
+ break;
+ } else if (!_isprint(*c))
+ error("unprintable character in login name\n",10);
+ else if (c-logname >= sizeof(logname)-1)
+ error("login name too long\n",11);
+ else
+ c++;
+ }
+ }
+#if 0
+ write(1,"\n\ngot name ",11);
+ write(1,logname,strlen(logname));
+ write(1,"\n\n",2);
+#endif
+ return logname;
+}
+
+extern char ** environ;
+
+char ttybuf[20]="/dev/";
+char ttybuf2[25]="TTY=";
+
+int main(int argc,char *argv[]) {
+ char *loginargv[]={"/bin/login", "--", 0, 0};
+ char *logname;
+ int i;
+ char hostname_end='.';
+ tty=argv[1];
+ if (!tty)
+ error("usage: fgetty 1\n"
+ " fgetty vc/1\n"
+ " fgetty /dev/tty1\n",111);
+ if (tty[0]=='/')
+ strncpy(ttybuf,tty,15);
+ else if (isdigit(tty[0])) {
+ struct stat ss;
+ /* try prepending /dev/vc/1 and /dev/tty1 */
+ strcpy(ttybuf,"/dev/vc/"); strncpy(ttybuf+8,tty,3);
+ if (stat(ttybuf,&ss) && errno==ENOENT) {
+ ttybuf[5]=ttybuf[6]='t'; ttybuf[7]='y';
+ }
+ } else
+ strncpy(ttybuf+5,tty,10);
+ tty=ttybuf;
+ strcpy(ttybuf2+4,ttybuf);
+
+ uname(&uts);
+ if (gethostname(hn+5, MAXHOSTNAMELEN)!=0) hn[5]=0;
+ hn[5+MAXHOSTNAMELEN]=0;
+ putenv("TERM=linux");
+ putenv(ttybuf2);
+ putenv(hn);
+ time(&cur_time);
+ for (i=2; i<argc; ++i) {
+ if (!strcmp(argv[i],"--noclear"))
+ noclear=1;
+ else if (!strcmp(argv[i],"--long-hostname"))
+ hostname_end=0;
+ }
+ while (hn[hn_len]!=0 && hn[hn_len]!=hostname_end) ++hn_len;
+#ifndef DEBUG
+ doutmp();
+ open_tty();
+#endif
+ ioctl(0,TCFLSH,2); /* mingetty says this is important for modem users */
+ while ((logname=get_logname()) == 0);
+ if (logname[0]=='-') error("username may not start with a dash\n",13);
+ loginargv[2]=logname;
+ echo_off();
+#ifdef TEST
+ execve("/bin/login1", loginargv, environ);
+#else
+ execve("/bin/login", loginargv, environ);
+#endif
+ exit(8);
+}
diff --git a/fmt.h b/fmt.h
new file mode 100644
index 0000000..b0bfce5
--- /dev/null
+++ b/fmt.h
@@ -0,0 +1,25 @@
+#ifndef FMT_H
+#define FMT_H
+
+#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
+#define FMT_LEN ((char *) 0) /* convenient abbreviation */
+
+extern unsigned int fmt_uint(char *,unsigned int);
+extern unsigned int fmt_uint0(char *,unsigned int,unsigned int);
+extern unsigned int fmt_xint(char *,unsigned int);
+extern unsigned int fmt_nbbint(char *,unsigned int,unsigned int,unsigned int,unsigned int);
+extern unsigned int fmt_ushort(char *,unsigned short);
+extern unsigned int fmt_xshort(char *,unsigned short);
+extern unsigned int fmt_nbbshort(char *,unsigned int,unsigned int,unsigned int,unsigned short);
+extern unsigned int fmt_ulong(char *,unsigned long);
+extern unsigned int fmt_xlong(char *,unsigned long);
+extern unsigned int fmt_nbblong(char *,unsigned int,unsigned int,unsigned int,unsigned long);
+
+extern unsigned int fmt_plusminus(char *,int);
+extern unsigned int fmt_minus(char *,int);
+extern unsigned int fmt_0x(char *,int);
+
+extern unsigned int fmt_str(char *,const char *);
+extern unsigned int fmt_strn(char *,const char *,unsigned int);
+
+#endif
diff --git a/fmt_ulong.c b/fmt_ulong.c
new file mode 100644
index 0000000..db48bfd
--- /dev/null
+++ b/fmt_ulong.c
@@ -0,0 +1,13 @@
+#include "fmt.h"
+
+unsigned int fmt_ulong(register char *s,register unsigned long u)
+{
+ register unsigned int len; register unsigned long q;
+ len = 1; q = u;
+ while (q > 9) { ++len; q /= 10; }
+ if (s) {
+ s += len;
+ do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */
+ }
+ return len;
+}
diff --git a/login.c b/login.c
new file mode 100644
index 0000000..8a46a76
--- /dev/null
+++ b/login.c
@@ -0,0 +1,149 @@
+/* diet login without all the bloat but with checkpassword for pluggable
+ * authentication support. */
+
+/* algorithm:
+ 1. argv[1] is the user name
+ (optional: argv[2-argc] are environment variables)
+ 2. print "user's password: " to stdout
+ 3. set terminal to "don't echo"
+ 4. read password
+ 5. set terminal to "echo"
+ 6. fork and run checkpassword login2
+ 7. wait() for checkpassword
+ 8. if checkpassword returns 1, the password was wrong. sleep(1) and ++counter
+ 9. if counter reaches 5, sleep(5) and exit
+
+ login2 is expected to:
+
+ 1. kill ppid (i.e. this process) if it is run.
+ 2. print motd unless (-f .hushlogin)
+ 3. check for mail (maybe)
+ 4. set TERM according to /etc/ttytypes
+ 5. edit utmp and wtmp (uh-oh, how should we do this? We are not root any more!)
+ 6. exec $SHELL
+ */
+
+#define CHECKPASSWORD "/bin/checkpassword.login"
+#define FALLBACKCHECKPASSWORD "/bin/checkpassword"
+#define LOGIN2 "/bin/login2"
+
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <write12.h>
+
+void die(const char *message) {
+ __write2(message); __write2("\n");
+ exit(1);
+}
+
+struct termios oldtermios;
+
+static void echo_off() {
+ struct termios foo;
+ if (tcgetattr(0,&oldtermios))
+ die("tcgetattr failed");
+ foo=oldtermios;
+ foo.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ tcsetattr(0, TCSANOW, &foo);
+}
+
+static void echo_on() {
+ oldtermios.c_lflag |= ECHO | ECHOE | ECHOK;
+ tcsetattr(0, TCSANOW, &oldtermios);
+}
+
+main(int argc,char *argv[]) {
+ int filedes[2];
+ char *username=argv[1];
+ char *buf;
+ char __username[100];
+ char password[100];
+ int pwlen;
+ char *Argv[]={"checkpassword",LOGIN2,0};
+ pid_t child;
+ int utmpfd,wtmpfd;
+ {
+ int i=1;
+ while (username && username[0]=='-')
+ username=argv[++i];
+ }
+
+ if (!username) {
+ char *host=getenv("HOST");
+ if (host) {
+ int len=strlen(host);
+ host[len]=' ';
+ write(0,host,len+1);
+ host[len]=0;
+ }
+ __write1("login: ");
+ pwlen=read(0,__username,9);
+ if (pwlen<0) die("read failed");
+ __username[pwlen-1]=0; /* skip newline */
+ username=__username;
+ }
+ {
+ buf=alloca(strlen(username)+20);
+ strcpy(buf,username);
+ strcat(buf,"'s password: ");
+ __write1(buf);
+ }
+ echo_off();
+ pwlen=read(0,password,99);
+ if (pwlen<0) die("read failed");
+ password[pwlen-1]=0;
+ echo_on();
+ __write1("\n");
+
+ if (pipe(filedes))
+ die("pipe failed");
+ if (filedes[0]!=3)
+ die("pipe did not return fd 3");
+ switch (child=fork()) {
+ case -1:
+ die("login: could not fork");
+ case 0:
+ /* child */
+ close(3);
+ {
+ char buf[512];
+ int len;
+ len=strlen(username)+1;
+ strcpy(buf,username);
+ strlcpy(buf+len,password,512-len);
+ len+=strlen(password)+1;
+/* buf[len++]='Y'; */
+ len+=__ltostr(buf+len,512-len,time(0),10,0);
+ buf[len]=0;
+ if (len<400) {
+ strcpy(buf+len+1,"nosetuid");
+ len+=9;
+ }
+ write(4,buf,len+1);
+ close(4);
+ }
+ break;
+ default:
+ close(4);
+ utmpfd=open(_PATH_UTMP,O_RDWR);
+ if (utmpfd==-1) utmpfd=open("/dev/null",O_RDWR);
+ if (utmpfd>0 && utmpfd!=4) { dup2(utmpfd,4); close(utmpfd); utmpfd=4; };
+ wtmpfd=open(_PATH_WTMP,O_APPEND|O_WRONLY);
+ if (wtmpfd==-1) wtmpfd=open("/dev/null",O_WRONLY);
+ if (wtmpfd>0 && wtmpfd!=5) { dup2(wtmpfd,5); close(wtmpfd); wtmpfd=5; };
+ if (utmpfd!=4 || wtmpfd!=5) {
+ close(utmpfd); close(wtmpfd);
+ __write2("utmpfd!=4 || wtmpfd!=5\n");
+ }
+ execve(CHECKPASSWORD,Argv,environ);
+ if (errno==ENOENT)
+ execve(FALLBACKCHECKPASSWORD,Argv,environ);
+ die("login: could not exec checkpassword");
+ }
+}
diff --git a/login2.c b/login2.c
new file mode 100644
index 0000000..8aaf6d6
--- /dev/null
+++ b/login2.c
@@ -0,0 +1,110 @@
+/* diet login without all the bloat but with checkpassword for pluggable
+ * authentication support. */
+
+/* algorithm:
+ 1. print motd unless (-f .hushlogin)
+ 2. check for mail (maybe)
+ 3. set TERM according to /etc/ttytypes
+ 4. edit utmp and wtmp (passed as fd 4 and fd 5)
+ 5. exec $SHELL
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <grp.h>
+#include <write12.h>
+
+#include <sys/stat.h>
+
+void die(const char *message) {
+ __write2(message); __write2("\n");
+ exit(1);
+}
+
+extern char **environ;
+
+int doutmp(const char *login) {
+ off_t curpos;
+ struct utmp ut;
+ pid_t mypid=getpid();
+ int fd=4;
+ for (;;) {
+ int len;
+ curpos=lseek(fd,0,SEEK_CUR);
+ len=read(fd,&ut,sizeof(ut));
+ if (len!=sizeof(ut)) break;
+ if (ut.ut_pid==mypid) {
+/* write(1,"found my utmp record\n",21); */
+ break;
+ }
+ }
+ if (ut.ut_pid!=mypid) {
+ memset(&ut,0,sizeof(ut));
+ ut.ut_pid=mypid;
+ memcpy(ut.ut_id,getenv("TTY")+4+3,sizeof(ut.ut_id));
+ }
+ strncpy(ut.ut_user,login,sizeof(ut.ut_user));
+ ut.ut_tv.tv_sec=time(0);
+ ut.ut_type=USER_PROCESS;
+ lseek(fd,curpos,SEEK_SET);
+ write(fd,&ut,sizeof(ut));
+ close(4);
+ write(5,&ut,sizeof(ut));
+ close(5);
+}
+
+main(int argc,char *argv[]) {
+ int fd;
+ char *shell=getenv("SHELL");
+ char *Argv[]={"-sh",0};
+ char *login=getenv("USER");
+ if (getuid()==0) { /* checkpassword honored "nosetuid" */
+ char *tmp=getenv("UID");
+ char *tty=getenv("TTY");
+ if (tmp) {
+ uid_t u=strtoul(tmp,&tmp,10);
+ struct group *g=getgrnam("console");
+ gid_t gid=getgid();
+ if (*tmp==0)
+ chown(tty,u,gid);
+ initgroups(login,g?g->gr_gid:gid);
+ /* if it fails, too bad. checkpassword should already have made
+ * sure no additional groups are there */
+ setuid(u);
+ if (u && getuid()!=u) { die("getuid() != u!\n"); return 2; }
+ } else return 2;
+ }
+ close(11);
+ if ((fd=open(".hushlogin",O_RDONLY))>=0)
+ close(fd);
+ else {
+ if ((fd=open("/etc/motd",O_RDONLY))>=0) {
+ char buf[1024];
+ int len;
+ while ((len=read(fd,buf,1024))>0)
+ write(0,buf,len);
+ close(fd);
+ }
+ }
+ /* login passes open utmp and wtmp on fd #4 and #5 */
+ doutmp(login);
+ {
+ char *buf=alloca(strlen(login)+20);
+ strcpy(buf,"LOGNAME=");
+ strcat(buf,login);
+ putenv(buf);
+ if (shell) {
+ char *tmp=strrchr(shell,'/');
+ char *argv0=alloca(strlen(shell)+2);
+ if (tmp) ++tmp; else tmp=shell;
+ strcpy(argv0+1,tmp);
+ *argv0='-';
+ Argv[0]=argv0;
+ execve(shell,Argv,environ);
+ }
+ execve("/bin/sh",Argv,environ);
+ }
+}