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 +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 #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 ) - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _PATH_LOGIN -#define _PATH_LOGIN "/bin/login" -#endif - -#ifndef _PATH_SSH -#define _PATH_SSH "/usr/bin/ssh" -#endif - -#ifdef linux -#include -#define USE_SYSLOG -#endif - - /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */ -#ifdef USE_SYSLOG -#include -#endif - -#define ISSUE "/etc/issue" /* displayed before the login prompt */ -#include -#include - -#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 -}