--- /dev/null
+diff -Nru mingetty-0.9.4.orig/mingetty.8 mingetty-0.9.4/mingetty.8
+--- mingetty-0.9.4.orig/mingetty.8 Sun Apr 29 19:38:31 2001
++++ mingetty-0.9.4/mingetty.8 Sun Apr 29 19:40:47 2001
+@@ -3,7 +3,7 @@
+ mingetty \- minimal getty for consoles
+ .SH SYNOPSIS
+ .B mingetty
+-[\-\-noclear] [\-\-long\-hostname]
++[\-\-noclear] [\-\-long\-hostname] [\-\-autologin username]
+ .I tty
+ .PP
+ .SH DESCRIPTION
+@@ -27,6 +27,41 @@
+ By default the hostname is only printed until the first dot.
+ With this option enabled, the full text from gethostname() is shown.
+ .TP
++.B \-\-autologin username
++Log the specified user onto the console (normally
++.IR /dev/tty1 )
++when the system is first booted without prompting for a username or
++password.
++.IP
++When the autologin option is supplied,
++.B mingetty
++will check that the controlling terminal is the console (normally
++.IR /dev/tty1 ),
++that a reasonable username has been supplied, and that this is the
++first autologin request since the system has booted. If all of these
++conditions have been met, a request for an unauthenticated login is
++passed to the
++.B login
++program. Otherwise, a normal interactive login is performed.
++.IP
++The
++.B login
++program may deny the request for an unauthenticated login. Typically
++this will happen when the user is root, has a UID of 0, or whenever a
++normal interactive login would be denied due to the access
++restrictions specified in the
++.IR nologin ,
++.IR usertty ,
++or
++.I securetty
++files.
++.IP
++Only a single autologin request will be issued after a system boot.
++If the automated login request is denied, or if the user logs out,
++.B mingetty
++will revert to performing normal interactive logins for all subsequent
++login requests.
++.TP
+ .B \-\-mono
+ Set terminal type to "linux-m" instead of default "linux" (for mono consoles)
+ .TP
+@@ -73,7 +108,8 @@
+ .PP
+ .SH FILES
+ .IR /etc/issue ,
+-.IR /var/run/utmp .
++.IR /var/run/utmp ,
++.IR /var/log/autologin .
+ .PP
+ .SH "SEE ALSO"
+ .BR mgetty (8),
+diff -Nru mingetty-0.9.4.orig/mingetty.c mingetty-0.9.4/mingetty.c
+--- mingetty-0.9.4.orig/mingetty.c Sun Apr 29 19:38:31 2001
++++ mingetty-0.9.4/mingetty.c Sun Apr 29 19:44:14 2001
+@@ -17,7 +17,7 @@
+ * should be very reliable. For a modem getty, I'd also use nothing else
+ * but mgetty.
+ *
+- * Usage: mingetty [--noclear] tty
++ * Usage: mingetty [--noclear] [--autologin username] tty
+ * Example entry in /etc/inittab: 1:123:respawn:/sbin/mingetty tty1
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -53,6 +53,20 @@
+ #endif
+
+ #ifdef linux
++/* Autologin stuff. Currently Linux-specific, since there's no
++ standard way of getting the system boot time. The kernel.h and the
++ sysinfo prototype are used to get the system uptime under Linux. */
++#include <linux/kernel.h>
++int sysinfo(struct sysinfo *info);
++
++/* AUTO_LAST points to a timestamp file used to limit autologins to
++ one per system boot. */
++#define AUTO_LAST "/var/log/autologin"
++
++/* AUTO_TTY is the tty on which autologins will be accepted. If set
++ to an empty string, autologins will be accepted on any tty. */
++#define AUTO_TTY "tty1"
++
+ #include <sys/param.h>
+ #define USE_SYSLOG
+ #endif
+@@ -84,6 +98,8 @@
+ static int noclear = 0;
+ /* Print the whole string of gethostname() instead of just until the next "." */
+ static int longhostname = 0;
++/* If supplied, attempt an automatic login with this username. */
++static char *autologin_name = NULL;
+ /* Set mono terminal type */
+ static int mono_term = 0;
+ /* Log onto remote host */
+@@ -398,6 +414,62 @@
+ return logname;
+ }
+
++/*
++ * autologin_ok -- returns 1 if it's okay to auto-login when:
++ * this login is from /dev/tty1; and
++ * there was a login name passed with the --autologin option; and
++ * the autologin_name contains only "nice" characters; and
++ * this is the first autologin attempt since the last boot;
++ * return 0 otherwise.
++ */
++static int autologin_ok(void)
++{
++ char c, *cp;
++ int stat_err, fd;
++ struct sysinfo info;
++ struct stat sbuf;
++
++ /* Autologins are restricted to AUTO_TTY if non-empty. */
++ if (AUTO_TTY[0] && strcmp(tty, AUTO_TTY))
++ return 0;
++
++ /* An all-alphanumeric autologin name must be supplied. */
++ if (autologin_name == NULL || autologin_name[0] == '\0')
++ return 0;
++ for (cp = autologin_name; (c = *cp); cp++)
++ if (!isalnum(c) && c != '_')
++ return 0;
++
++ /* Get the uptime in info.uptime, and the last autologin time
++ in sbuf.st_mtime. */
++ sysinfo(&info);
++ stat_err = stat(AUTO_LAST, &sbuf);
++
++ /* If a stat error other than "no such file" occurs, I don't
++ know what went wrong, so I'll proceed with caution by
++ denying the autologin request. */
++ if (stat_err && errno != ENOENT)
++ return 0;
++
++ /* If there's been an autologin granted since the last boot,
++ deny this and any subsequent attempts. Note that this test
++ is skipped if the AUTO_LAST file doesn't exist. */
++ if (!stat_err && time(NULL) - info.uptime < sbuf.st_mtime)
++ return 0;
++
++ /* Create the AUTO_LAST file. The mtime of this file provides
++ a persistent record of the last time that an autologin
++ request was granted. Deny the autologin request if either
++ the file open or file close fails. */
++ if ((fd=open(AUTO_LAST, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0)
++ return 0;
++ if (close(fd) != 0)
++ return 0;
++
++ /* All tests are okay, so grant the autologin request. */
++ return 1;
++}
++
+ static void usage (void)
+ {
+ error ("usage: '%s tty' with e.g. tty=tty1", progname);
+@@ -406,6 +478,7 @@
+ static struct option const long_options[] = {
+ { "noclear", no_argument, &noclear, 1},
+ { "long-hostname", no_argument, &longhostname, 1},
++ { "autologin", required_argument, NULL, 'a'},
+ { "mono", no_argument, &mono_term, 1},
+ { "remote-host", required_argument, NULL, 2},
+ { "login-program", required_argument, NULL, 3},
+@@ -441,6 +514,9 @@
+ strncpy(login_program, optarg, 1024);
+ login_program[1023] = '\0';
+ break;
++ case 'a':
++ autologin_name = optarg;
++ break;
+ default:
+ usage ();
+ }
+@@ -476,17 +552,21 @@
+ /* flush input and output queues, important for modems */
+ ioctl (0, TCFLSH, 2);
+
+- while ((logname = get_logname ()) == 0);
+-
+- if (!remote_login) {
+- if (!another_login)
+- strncpy(login_program, _PATH_LOGIN, 1024);
+- execl (login_program, login_program, "--", logname, NULL);
+- } else {
+- if (!another_login)
+- strncpy(login_program, _PATH_SSH, 1024);
+- execl (login_program, login_program, "-l", logname, remote_host, NULL);
+- }
++ if (autologin_ok()) {
++ execl (_PATH_LOGIN, _PATH_LOGIN, "-f", autologin_name, NULL);
++ } else {
++ while ((logname = get_logname ()) == 0);
++
++ if (!remote_login) {
++ if (!another_login)
++ strncpy(login_program, _PATH_LOGIN, 1024);
++ execl (login_program, login_program, "--", logname, NULL);
++ } else {
++ if (!another_login)
++ strncpy(login_program, _PATH_SSH, 1024);
++ execl (login_program, login_program, "-l", logname, remote_host, NULL);
++ }
++ }
+ error ("%s: can't exec %s: %s", login_program, tty, sys_errlist[errno]);
+ exit (0);
+ }
+diff -Nru mingetty-0.9.4.orig/mingetty.c~ mingetty-0.9.4/mingetty.c~
+--- mingetty-0.9.4.orig/mingetty.c~ Sun Apr 29 19:38:31 2001
++++ mingetty-0.9.4/mingetty.c~ Thu Jan 1 01:00:00 1970
+@@ -1,509 +0,0 @@
+-/* mingetty.c
+- *
+- * Copyright (C) 1996 Florian La Roche
+- * florian@jurix.jura.uni-sb.de florian@suse.de
+- *
+- * Newer versions should be on susix.jura.uni-sb.de/pub/linux/source/system
+- * or sunsite.unc.edu/pub/Linux/system/Admin/login or /pub/Linux/system/
+- * Daemons/init/.
+- *
+- * utmp-handling is from agetty in util-linux 2.5 (probably from
+- * Peter Orbaek <poe@daimi.aau.dk>)
+- *
+- * S.u.S.E. - GmbH has paid some of the time that was needed to write
+- * this program. Thanks a lot for their support.
+- *
+- * This getty can only be used as console getty. It is very small, but
+- * should be very reliable. For a modem getty, I'd also use nothing else
+- * but mgetty.
+- *
+- * Usage: mingetty [--noclear] tty
+- * Example entry in /etc/inittab: 1:123:respawn:/sbin/mingetty tty1
+- *
+- * 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.
+- *
+- */
+-
+-#define DEBUG_THIS 0
+-
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <unistd.h>
+-#include <string.h>
+-#include <sys/ioctl.h>
+-#include <errno.h>
+-#include <sys/stat.h>
+-#include <sys/file.h>
+-#include <signal.h>
+-#include <fcntl.h>
+-#include <stdarg.h>
+-#include <ctype.h>
+-#include <utmp.h>
+-#include <getopt.h>
+-
+-#ifndef _PATH_LOGIN
+-#define _PATH_LOGIN "/bin/login"
+-#endif
+-
+-#ifndef _PATH_SSH
+-#define _PATH_SSH "/usr/bin/ssh"
+-#endif
+-
+-#ifdef linux
+-#include <sys/param.h>
+-#define USE_SYSLOG
+-#endif
+-
+- /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
+-#ifdef USE_SYSLOG
+-#include <sys/syslog.h>
+-#endif
+-
+-#define ISSUE "/etc/issue" /* displayed before the login prompt */
+-#include <sys/utsname.h>
+-#include <time.h>
+-
+-#define LOGIN " login: " /* login prompt */
+-
+-/* name of this program (argv[0]) */
+-static char *progname;
+-/* on which tty line are we sitting? (e.g. tty1) */
+-static char *tty;
+-/* some information about this host */
+-static struct utsname uts;
+-/* the hostname */
+-static char hn[MAXHOSTNAMELEN + 1];
+-/* process ID of this program */
+-static pid_t pid;
+-/* current time */
+-static time_t cur_time;
+-/* do not send a reset string to the terminal ? */
+-static int noclear = 0;
+-/* Print the whole string of gethostname() instead of just until the next "." */
+-static int longhostname = 0;
+-/* Set mono terminal type */
+-static int mono_term = 0;
+-/* Log onto remote host */
+-static int remote_login = 0;
+-/* Remote hostname */
+-static char remote_host[1024];
+-/* Do we use user's login app? */
+-static int another_login = 0;
+-/* Login program */
+-static char login_program[1024];
+-
+-/*
+- * output error messages
+- */
+-static void error (const char *fmt, ...)
+-{
+- va_list va_alist;
+- char buf[256], *bp;
+-#ifndef USE_SYSLOG
+- int fd;
+-#endif
+-
+-#ifdef USE_SYSLOG
+- buf[0] = '\0';
+- bp = buf;
+-#else
+- strcpy (buf, progname);
+- strcat (buf, ": ");
+- bp = buf + strlen (buf);
+-#endif
+-
+- va_start (va_alist, fmt);
+- vsprintf (bp, fmt, va_alist);
+- va_end (va_alist);
+-
+-#ifdef USE_SYSLOG
+- openlog (progname, LOG_PID, LOG_AUTH);
+- syslog (LOG_ERR, buf);
+- closelog ();
+-#else
+- strcat (bp, "\r\n");
+- if ((fd = open ("/dev/console", 1)) >= 0) {
+- write (fd, buf, strlen (buf));
+- close (fd);
+- }
+-#endif
+- exit (1);
+-}
+-
+-/*
+- * update_utmp - update our utmp entry
+- *
+- * The utmp file holds miscellaneous information about things started by
+- * /sbin/init and other system-related events. Our purpose is to update
+- * the utmp entry for the current process, in particular the process
+- * type and the tty line we are listening to. Return successfully only
+- * if the utmp file can be opened for update, and if we are able to find
+- * our entry in the utmp file.
+- */
+-static void update_utmp (void)
+-{
+- struct utmp ut;
+- int ut_fd;
+- struct utmp *utp;
+- void locktimeout();
+-
+- utmpname (_PATH_UTMP);
+- setutent ();
+- while ((utp = getutent ()))
+- if (utp->ut_type == INIT_PROCESS && utp->ut_pid == pid)
+- break;
+-
+- if (utp) {
+- memcpy (&ut, utp, sizeof (ut));
+- } else {
+- /* some inits don't initialize utmp... */
+- /* XXX we should print out a warning message */
+- memset (&ut, 0, sizeof (ut));
+- strncpy (ut.ut_id, tty + 3, sizeof (ut.ut_id));
+- }
+- endutent ();
+-
+- strncpy (ut.ut_user, "LOGIN", sizeof (ut.ut_user));
+- strncpy (ut.ut_line, tty, sizeof (ut.ut_line));
+- ut.ut_time = cur_time;
+- ut.ut_type = LOGIN_PROCESS;
+- ut.ut_pid = pid;
+-
+- pututline (&ut);
+- endutent ();
+-
+- if ((ut_fd = open (_PATH_WTMP, O_APPEND | O_WRONLY)) >= 0) {
+- (void)signal(SIGALRM, locktimeout);
+- (void)alarm(3);
+- flock (ut_fd, LOCK_EX);
+- (void)alarm(0);
+- write (ut_fd, &ut, sizeof (ut));
+- flock (ut_fd, LOCK_UN);
+- close (ut_fd);
+- }
+-}
+-
+-/* open_tty - set up tty as standard { input, output, error } */
+-static void open_tty (void)
+-{
+- struct sigaction sa;
+- char buf[20];
+- int fd;
+-
+- /* Set up new standard input. */
+- strcpy (buf, "/dev/");
+- strcat (buf, tty);
+- if (chown (buf, 0, 0) || chmod (buf, 0600))
+- error ("%s: %s", buf, sys_errlist[errno]);
+-
+- sa.sa_handler = SIG_IGN;
+- sa.sa_flags = 0;
+- sigemptyset (&sa.sa_mask);
+- sigaction (SIGHUP, &sa, NULL);
+-
+- /* vhangup() will replace all open file descriptors that point to our
+- controlling tty by a dummy that will deny further reading/writing
+- to our device. It will also reset the tty to sane defaults, so we
+- don't have to modify the tty device for sane settings.
+- We also get a SIGHUP/SIGCONT.
+- */
+- if ((fd = open (buf, O_RDWR, 0)) < 0
+- || ioctl (fd, TIOCSCTTY, (void *)1) == -1)
+- error ("%s: cannot open tty: %s", buf, sys_errlist[errno]);
+- if (!isatty (fd))
+- error ("%s: not a tty", buf);
+-
+- vhangup ();
+- /* Get rid of the present stdout/stderr. */
+- close (2);
+- close (1);
+- close (0);
+- close (fd);
+- /* ioctl (0, TIOCNOTTY, (char *)1); */
+-
+- if (open (buf, O_RDWR, 0) != 0)
+- error ("%s: cannot open as standard input: %s", buf,
+- sys_errlist[errno]);
+-
+- /* Set up standard output and standard error file descriptors. */
+- if (dup (0) != 1 || dup (0) != 2)
+- error ("%s: dup problem: %s", buf, sys_errlist[errno]);
+-
+- /* Write a reset string to the terminal. This is very linux-specific
+- and should be checked for other systems. */
+- if (! noclear)
+- write (0, "\033c", 2);
+-
+- sa.sa_handler = SIG_DFL;
+- sa.sa_flags = 0;
+- sigemptyset (&sa.sa_mask);
+- sigaction (SIGHUP, &sa, NULL);
+-
+-#if DEBUG_THIS
+- printf ("session=%d, pid=%d, pgid=%d\n", getsid (0), getpid (),
+- getpgid (0));
+-#endif
+-}
+-
+-static void output_special_char (unsigned char c)
+-{
+- switch (c) {
+- case 's':
+- printf ("%s", uts.sysname);
+- break;
+- case 'n':
+- printf ("%s", uts.nodename);
+- break;
+- case 'r':
+- printf ("%s", uts.release);
+- break;
+- case 'v':
+- printf ("%s", uts.version);
+- break;
+- case 'm':
+- printf ("%s", uts.machine);
+- break;
+- case 'o':
+- printf ("%s", uts.domainname);
+- break;
+-#if 1
+- case 'd':
+- case 't':
+- {
+- char *weekday[] =
+- {"Sun", "Mon", "Tue", "Wed", "Thu",
+- "Fri", "Sat"};
+- char *month[] =
+- {"Jan", "Feb", "Mar", "Apr", "May",
+- "Jun", "Jul", "Aug", "Sep", "Oct",
+- "Nov", "Dec"};
+- time_t now;
+- struct tm *tm;
+-
+- time (&now);
+- tm = localtime (&now);
+-
+- if (c == 'd')
+- printf ("%s %s %d %d",
+- weekday[tm->tm_wday], month[tm->tm_mon],
+- tm->tm_mday,
+- tm->tm_year < 70 ? tm->tm_year + 2000 :
+- tm->tm_year + 1900);
+- else
+- printf ("%02d:%02d:%02d",
+- tm->tm_hour, tm->tm_min, tm->tm_sec);
+-
+- break;
+- }
+-#else
+- case 'd':
+- case 't':
+- {
+- char buff[20];
+- struct tm *tm = localtime (&cur_time);
+- strftime (buff, sizeof (buff),
+- c == 'd'? "%a %b %d %Y" : "%X", tm);
+- fputs (buff, stdout);
+- break;
+- }
+-#endif
+-
+- case 'l':
+- printf ("%s", tty);
+- break;
+- case 'u':
+- case 'U':
+- {
+- int users = 0;
+- struct utmp *ut;
+- setutent ();
+- while ((ut = getutent ()))
+- if (ut->ut_type == USER_PROCESS)
+- users++;
+- endutent ();
+- printf ("%d", users);
+- if (c == 'U')
+- printf (" user%s", users == 1 ? "" : "s");
+- break;
+- }
+- default:
+- putchar (c);
+- }
+-}
+-
+-/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
+-static void do_prompt (void)
+-{
+-#if ! OLD
+- FILE *fd;
+-#else
+- int fd;
+-#endif
+- char c;
+-
+- write (1, "\n", 1); /* start a new line */
+-#if ! OLD
+- if ((fd = fopen (ISSUE, "r"))) {
+- while ((c = getc (fd)) != EOF) {
+- if (c == '\\')
+- output_special_char (getc(fd));
+- else
+- putchar (c);
+- }
+- fflush (stdout);
+- fclose (fd);
+- }
+-#else
+- if ((fd = open (ISSUE, O_RDONLY)) >= 0) {
+- close (fd);
+- }
+-#endif
+- write (1, hn, strlen (hn));
+- write (1, LOGIN, sizeof (LOGIN) - 1);
+-}
+-
+-/* get_logname - get user name, establish speed, erase, kill, eol */
+-static char *get_logname (void)
+-{
+- static char logname[40];
+- char *bp;
+- unsigned char c;
+-
+- ioctl (0, TCFLSH, 0); /* flush pending input */
+-
+- for (*logname = 0; *logname == 0;) {
+- do_prompt ();
+- for (bp = logname;;) {
+- if (read (0, &c, 1) < 1) {
+- if (errno == EINTR || errno == EIO
+- || errno == ENOENT)
+- exit (0);
+- error ("%s: read: %s", tty, sys_errlist[errno]);
+- }
+- if (c == '\n' || c == '\r') {
+- *bp = 0;
+- break;
+- } else if (!isprint (c))
+- error ("%s: invalid character %c in login name",
+- tty, c);
+- else if (bp - logname >= sizeof (logname) - 1)
+- error ("%s: too long login name", tty);
+- else
+- *bp++ = c;
+- }
+- }
+- return logname;
+-}
+-
+-static void usage (void)
+-{
+- error ("usage: '%s tty' with e.g. tty=tty1", progname);
+-}
+-
+-static struct option const long_options[] = {
+- { "noclear", no_argument, &noclear, 1},
+- { "long-hostname", no_argument, &longhostname, 1},
+- { "mono", no_argument, &mono_term, 1},
+- { "remote-host", required_argument, NULL, 2},
+- { "login-program", required_argument, NULL, 3},
+- { 0, 0, 0, 0 }
+-};
+-
+-/*
+- * main program
+- */
+-int main (int argc, char **argv)
+-{
+- char *logname, *s;
+- int option_index = 0;
+- int c;
+-
+- progname = argv[0];
+- uname (&uts);
+- pid = getpid ();
+- time (&cur_time);
+-
+- while ((c = getopt_long (argc, argv, "", long_options, &option_index))
+- != EOF) {
+- switch (c) {
+- case 0:
+- break;
+- case 2:
+- remote_login = 1;
+- strncpy(remote_host, optarg, 1024);
+- remote_host[1023] = '\0';
+- break;
+- case 3:
+- another_login = 1;
+- strncpy(login_program, optarg, 1024);
+- login_program[1023] = '\0';
+- break;
+- default:
+- usage ();
+- }
+- }
+-
+- if (!remote_login)
+- gethostname (hn, MAXHOSTNAMELEN);
+- else {
+- strncpy(hn, remote_host, MAXHOSTNAMELEN);
+- hn[MAXHOSTNAMELEN] = '\0';
+- if ((!longhostname)&&(strchr(hn,'.')))
+- *(strchr(hn,'.')) = '\0';
+- }
+-
+- if (mono_term)
+- putenv ("TERM=linux-m");
+- else
+- putenv ("TERM=linux");
+-
+- if (!longhostname && (s = strchr(hn, '.')))
+- *s = '\0';
+- tty = argv[optind];
+- if (! tty)
+- usage ();
+-
+- update_utmp ();
+- open_tty ();
+-#if 0
+-#ifdef linux
+- ioctl (0, TIOCSPGRP, &pid);
+-#endif
+-#endif
+- /* flush input and output queues, important for modems */
+- ioctl (0, TCFLSH, 2);
+-
+- while ((logname = get_logname ()) == 0);
+-
+- if (!remote_login) {
+- if (!another_login)
+- strncpy(login_program, _PATH_LOGIN, 1024);
+- execl (login_program, login_program, "--", logname, NULL);
+- } else {
+- if (!another_login)
+- strncpy(login_program, _PATH_SSH, 1024);
+- execl (login_program, login_program, "-l", logname, remote_host, NULL);
+- }
+- error ("%s: can't exec %s: %s", login_program, tty, sys_errlist[errno]);
+- exit (0);
+-}
+-
+-
+-void locktimeout()
+-{
+-#ifdef USE_SYSLOG
+- openlog (progname, LOG_PID, LOG_AUTH);
+- syslog(LOG_ALERT, "Lock failed on wtmp");
+- closelog ();
+-#else
+- int fd;
+- char buf[]="Lock failed on wtmp\n";
+- if ((fd = open ("/dev/console", 1)) >= 0) {
+- write (fd, buf, strlen (buf));
+- close (fd);
+- }
+-#endif
+-}