add NOMMU fixme's; move move_fd from runit_lib to libbb; nuke fd_copy
[platform/upstream/busybox.git] / loginutils / login.c
index 5b4edd8..791e44d 100644 (file)
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
 
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <termios.h>
-#include <unistd.h>
+#include "busybox.h"
 #include <utmp.h>
 #include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <ctype.h>
-#include <time.h>
+#include <syslog.h>
 
-#include "busybox.h"
-#ifdef CONFIG_SELINUX
+#if ENABLE_SELINUX
 #include <selinux/selinux.h>  /* for is_selinux_enabled()  */
 #include <selinux/get_context_list.h> /* for get_default_context() */
 #include <selinux/flask.h> /* for security class definitions  */
 #include <errno.h>
 #endif
 
-#ifdef CONFIG_FEATURE_UTMP
-// import from utmp.c
-static void checkutmp(int picky);
-static void setutmp(const char *name, const char *line);
-/* Stuff global to this file */
-static struct utmp utent;
-#endif
+enum {
+       TIMEOUT = 60,
+       EMPTY_USERNAME_COUNT = 10,
+       USERNAME_SIZE = 32,
+       TTYNAME_SIZE = 32,
+};
 
-// login defines
-#define TIMEOUT       60
-#define EMPTY_USERNAME_COUNT    10
-#define USERNAME_SIZE 32
+static char* short_tty;
 
+#if ENABLE_FEATURE_UTMP
+/* vv  Taken from tinylogin utmp.c  vv */
+/*
+ * read_or_build_utent - see if utmp file is correct for this process
+ *
+ *     System V is very picky about the contents of the utmp file
+ *     and requires that a slot for the current process exist.
+ *     The utmp file is scanned for an entry with the same process
+ *     ID.  If no entry exists the process exits with a message.
+ *
+ *     The "picky" flag is for network and other logins that may
+ *     use special flags.  It allows the pid checks to be overridden.
+ *     This means that getty should never invoke login with any
+ *     command line flags.
+ */
 
-static int check_nologin ( int amroot );
+static void read_or_build_utent(struct utmp *utptr, int picky)
+{
+       struct utmp *ut;
+       pid_t pid = getpid();
 
-#if defined CONFIG_FEATURE_SECURETTY
-static int check_tty ( const char *tty );
+       setutent();
 
-#else
-static inline int check_tty ( const char *tty )  { return 1; }
+       /* First, try to find a valid utmp entry for this process.  */
+       while ((ut = getutent()))
+               if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
+               (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))
+                       break;
 
+       /* If there is one, just use it, otherwise create a new one.  */
+       if (ut) {
+               *utptr = *ut;
+       } else {
+               if (picky)
+                       bb_error_msg_and_die("no utmp entry found");
+
+               memset(utptr, 0, sizeof(*utptr));
+               utptr->ut_type = LOGIN_PROCESS;
+               utptr->ut_pid = pid;
+               strncpy(utptr->ut_line, short_tty, sizeof(utptr->ut_line));
+               /* This one is only 4 chars wide. Try to fit something
+                * remotely meaningful by skipping "tty"... */
+               strncpy(utptr->ut_id, short_tty + 3, sizeof(utptr->ut_id));
+               strncpy(utptr->ut_user, "LOGIN", sizeof(utptr->ut_user));
+               utptr->ut_time = time(NULL);
+       }
+       if (!picky)     /* root login */
+               memset(utptr->ut_host, 0, sizeof(utptr->ut_host));
+}
+
+/*
+ * write_utent - put a USER_PROCESS entry in the utmp file
+ *
+ *     write_utent changes the type of the current utmp entry to
+ *     USER_PROCESS.  the wtmp file will be updated as well.
+ */
+static void write_utent(struct utmp *utptr, const char *username)
+{
+       utptr->ut_type = USER_PROCESS;
+       strncpy(utptr->ut_user, username, sizeof(utptr->ut_user));
+       utptr->ut_time = time(NULL);
+       /* other fields already filled in by read_or_build_utent above */
+       setutent();
+       pututline(utptr);
+       endutent();
+#if ENABLE_FEATURE_WTMP
+       if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
+               close(creat(bb_path_wtmp_file, 0664));
+       }
+       updwtmp(bb_path_wtmp_file, utptr);
 #endif
+}
+#else /* !ENABLE_FEATURE_UTMP */
+#define read_or_build_utent(utptr, picky) ((void)0)
+#define write_utent(utptr, username) ((void)0)
+#endif /* !ENABLE_FEATURE_UTMP */
 
-static int is_my_tty ( const char *tty );
-static int login_prompt ( char *buf_name );
-static void motd ( void );
+static void die_if_nologin_and_non_root(int amroot)
+{
+       FILE *fp;
+       int c;
 
+       if (access(bb_path_nologin_file, F_OK))
+               return;
 
-static void alarm_handler ( int sig ATTRIBUTE_UNUSED)
+       fp = fopen(bb_path_nologin_file, "r");
+       if (fp) {
+               while ((c = getc(fp)) != EOF)
+                       putchar((c=='\n') ? '\r' : c);
+               fflush(stdout);
+               fclose(fp);
+       } else
+               puts("\r\nSystem closed for routine maintenance\r");
+       if (!amroot)
+               exit(1);
+       puts("\r\n[Disconnect bypassed -- root login allowed.]\r");
+}
+
+#if ENABLE_FEATURE_SECURETTY
+static int check_securetty(void)
 {
-       fprintf (stderr, "\nLogin timed out after %d seconds.\n", TIMEOUT );
-       exit ( EXIT_SUCCESS );
+       FILE *fp;
+       int i;
+       char buf[BUFSIZ];
+
+       fp = fopen(bb_path_securetty_file, "r");
+       if (!fp) {
+               /* A missing securetty file is not an error. */
+               return 1;
+       }
+       while (fgets(buf, sizeof(buf)-1, fp)) {
+               for (i = strlen(buf)-1; i>=0; --i) {
+                       if (!isspace(buf[i]))
+                               break;
+               }
+               buf[++i] = '\0';
+               if ((buf[0]=='\0') || (buf[0]=='#'))
+                       continue;
+               if (strcmp(buf, short_tty) == 0) {
+                       fclose(fp);
+                       return 1;
+               }
+       }
+       fclose(fp);
+       return 0;
 }
+#else
+static inline int check_securetty(void) { return 1; }
+#endif
 
+static void get_username_or_die(char *buf, int size_buf)
+{
+       int c, cntdown;
+       cntdown = EMPTY_USERNAME_COUNT;
+prompt:
+       /* skip whitespace */
+       print_login_prompt();
+       do {
+               c = getchar();
+               if (c == EOF) exit(1);
+               if (c == '\n') {
+                       if (!--cntdown) exit(1);
+                       goto prompt;
+               }
+       } while (isspace(c));
+
+       *buf++ = c;
+       if (!fgets(buf, size_buf-2, stdin))
+               exit(1);
+       if (!strchr(buf, '\n'))
+               exit(1);
+       while (isgraph(*buf)) buf++;
+       *buf = '\0';
+}
 
+static void motd(void)
+{
+       FILE *fp;
+       int c;
+
+       fp = fopen(bb_path_motd_file, "r");
+       if (fp) {
+               while ((c = getc(fp)) != EOF)
+                       putchar(c);
+               fclose(fp);
+       }
+}
+
+static void alarm_handler(int sig ATTRIBUTE_UNUSED)
+{
+       /* This is the escape hatch!  Poor serial line users and the like
+        * arrive here when their connection is broken.
+        * We don't want to block here */
+       ndelay_on(1);
+       ndelay_on(2);
+       bb_info_msg("\r\nLogin timed out after %d seconds\r", TIMEOUT);
+       exit(EXIT_SUCCESS);
+}
+
+int login_main(int argc, char **argv);
 int login_main(int argc, char **argv)
 {
-       char tty[BUFSIZ];
-       char full_tty[200];
+       enum {
+               LOGIN_OPT_f = (1<<0),
+               LOGIN_OPT_h = (1<<1),
+               LOGIN_OPT_p = (1<<2),
+       };
        char fromhost[512];
        char username[USERNAME_SIZE];
        const char *tmp;
        int amroot;
-       int flag;
-       int failed;
-       int count=0;
-       struct passwd *pw, pw_copy;
-#ifdef CONFIG_WHEEL_GROUP
-       struct group *grp;
-#endif
-       int opt_preserve = 0;
-       int opt_fflag = 0;
-       char *opt_host = 0;
-       int alarmstarted = 0;
-#ifdef CONFIG_SELINUX
-       security_context_t user_sid = NULL;
-#endif
-
-       username[0]=0;
-       amroot = ( getuid ( ) == 0 );
-       signal ( SIGALRM, alarm_handler );
-       alarm ( TIMEOUT );
-       alarmstarted = 1;
-
-       while (( flag = getopt(argc, argv, "f:h:p")) != EOF ) {
-               switch ( flag ) {
-               case 'p':
-                       opt_preserve = 1;
-                       break;
-               case 'f':
-                       /*
-                        * username must be a separate token
-                        * (-f root, *NOT* -froot). --marekm
-                        */
-                       if ( optarg != argv[optind-1] )
-                               bb_show_usage( );
-
-                       if ( !amroot )          /* Auth bypass only if real UID is zero */
-                               bb_error_msg_and_die ( "-f permission denied" );
-
-                       safe_strncpy(username, optarg, USERNAME_SIZE);
-                       opt_fflag = 1;
-                       break;
-               case 'h':
-                       opt_host = optarg;
-                       break;
-               default:
-                       bb_show_usage( );
-               }
+       unsigned opt;
+       int count = 0;
+       struct passwd *pw;
+       char *opt_host = NULL;
+       char *opt_user = NULL;
+       char full_tty[TTYNAME_SIZE];
+       USE_SELINUX(security_context_t user_sid = NULL;)
+       USE_FEATURE_UTMP(struct utmp utent;)
+
+       short_tty = full_tty;
+       username[0] = '\0';
+       amroot = (getuid() == 0);
+       signal(SIGALRM, alarm_handler);
+       alarm(TIMEOUT);
+
+       opt = getopt32(argc, argv, "f:h:p", &opt_user, &opt_host);
+       if (opt & LOGIN_OPT_f) {
+               if (!amroot)
+                       bb_error_msg_and_die("-f is for root only");
+               safe_strncpy(username, opt_user, sizeof(username));
        }
+       if (optind < argc) /* user from command line (getty) */
+               safe_strncpy(username, argv[optind], sizeof(username));
 
-       if (optind < argc)             // user from command line (getty)
-               safe_strncpy(username, argv[optind], USERNAME_SIZE);
-
-       if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 ))
+       /* Let's find out and memorize our tty */
+       if (!isatty(0) || !isatty(1) || !isatty(2))
                return EXIT_FAILURE;            /* Must be a terminal */
+       safe_strncpy(full_tty, "UNKNOWN", sizeof(full_tty));
+       tmp = ttyname(0);
+       if (tmp) {
+               safe_strncpy(full_tty, tmp, sizeof(full_tty));
+               if (strncmp(full_tty, "/dev/", 5) == 0)
+                       short_tty = full_tty + 5;
+       }
 
-#ifdef CONFIG_FEATURE_UTMP
-       checkutmp ( !amroot );
-#endif
-
-       tmp = ttyname ( 0 );
-       if ( tmp && ( strncmp ( tmp, "/dev/", 5 ) == 0 ))
-               safe_strncpy ( tty, tmp + 5, sizeof( tty ));
-       else if ( tmp && *tmp == '/' )
-               safe_strncpy ( tty, tmp, sizeof( tty ));
-       else
-               safe_strncpy ( tty, "UNKNOWN", sizeof( tty ));
-
-#ifdef CONFIG_FEATURE_UTMP
-       if ( amroot )
-               memset ( utent.ut_host, 0, sizeof utent.ut_host );
-#endif
+       read_or_build_utent(&utent, !amroot);
 
-       if ( opt_host ) {
-#ifdef CONFIG_FEATURE_UTMP
-               safe_strncpy ( utent.ut_host, opt_host, sizeof( utent. ut_host ));
-#endif
-               snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s' from `%.200s'", tty, opt_host );
-       }
-       else
-               snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s'", tty );
+       if (opt_host) {
+               USE_FEATURE_UTMP(
+                       safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));
+               )
+               snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s' from "
+                                       "'%.200s'", short_tty, opt_host);
+       else
+               snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s'", short_tty);
 
        bb_setpgrp;
 
-       openlog ( "login", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH );
-
-       while ( 1 ) {
-               failed = 0;
+       openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
 
-               if ( !username[0] )
-                       if(!login_prompt ( username ))
-                               return EXIT_FAILURE;
+       while (1) {
+               if (!username[0])
+                       get_username_or_die(username, sizeof(username));
 
-               if ( !alarmstarted && ( TIMEOUT > 0 )) {
-                       alarm ( TIMEOUT );
-                       alarmstarted = 1;
+               pw = getpwnam(username);
+               if (!pw) {
+                       safe_strncpy(username, "UNKNOWN", sizeof(username));
+                       goto auth_failed;
                }
 
-               if (!( pw = getpwnam ( username ))) {
-                       pw_copy.pw_name   = "UNKNOWN";
-                       pw_copy.pw_passwd = "!";
-                       opt_fflag = 0;
-                       failed = 1;
-               } else
-                       pw_copy = *pw;
+               if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
+                       goto auth_failed;
 
-               pw = &pw_copy;
+               if (opt & LOGIN_OPT_f)
+                       break; /* -f USER: success without asking passwd */
 
-               if (( pw-> pw_passwd [0] == '!' ) || ( pw-> pw_passwd[0] == '*' ))
-                       failed = 1;
-
-               if ( opt_fflag ) {
-                       opt_fflag = 0;
-                       goto auth_ok;
-               }
-
-               if (!failed && ( pw-> pw_uid == 0 ) && ( !check_tty ( tty )))
-                       failed = 1;
+               if (pw->pw_uid == 0 && !check_securetty())
+                       goto auth_failed;
 
                /* Don't check the password if password entry is empty (!) */
-               if ( !pw-> pw_passwd[0] )
-                       goto auth_ok;
+               if (!pw->pw_passwd[0])
+                       break;
 
                /* authorization takes place here */
-               if ( correct_password ( pw ))
-                       goto auth_ok;
-
-               failed = 1;
-
-auth_ok:
-               if ( !failed)
+               if (correct_password(pw))
                        break;
 
+auth_failed:
+               opt &= ~LOGIN_OPT_f;
                bb_do_delay(FAIL_DELAY);
                puts("Login incorrect");
-               username[0] = 0;
-               if ( ++count == 3 ) {
-                       syslog ( LOG_WARNING, "invalid password for `%s'%s\n", pw->pw_name, fromhost);
+               if (++count == 3) {
+                       syslog(LOG_WARNING, "invalid password for '%s'%s",
+                                               username, fromhost);
                        return EXIT_FAILURE;
+               }
+               username[0] = '\0';
        }
-       }
-
-       alarm ( 0 );
-       if ( check_nologin ( pw-> pw_uid == 0 ))
-               return EXIT_FAILURE;
 
-#ifdef CONFIG_FEATURE_UTMP
-       setutmp ( username, tty );
-#endif
+       alarm(0);
+       die_if_nologin_and_non_root(pw->pw_uid == 0);
 
-       if ( *tty != '/' )
-               snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty);
-       else
-               safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 );
+       write_utent(&utent, username);
 
 #ifdef CONFIG_SELINUX
-       if (is_selinux_enabled())
-       {
+       if (is_selinux_enabled()) {
                security_context_t old_tty_sid, new_tty_sid;
 
-               if (get_default_context(username, NULL, &user_sid))
-               {
-                       fprintf(stderr, "Unable to get SID for %s\n", username);
-                       exit(1);
+               if (get_default_context(username, NULL, &user_sid)) {
+                       bb_error_msg_and_die("cannot get SID for %s",
+                                       username);
                }
-               if (getfilecon(full_tty, &old_tty_sid) < 0)
-               {
-                       fprintf(stderr, "getfilecon(%.100s) failed: %.100s\n", full_tty, strerror(errno));
-                       return EXIT_FAILURE;
+               if (getfilecon(full_tty, &old_tty_sid) < 0) {
+                       bb_perror_msg_and_die("getfilecon(%s) failed",
+                                       full_tty);
                }
-               if (security_compute_relabel(user_sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0)
-               {
-                       fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", full_tty, strerror(errno));
-                       return EXIT_FAILURE;
+               if (security_compute_relabel(user_sid, old_tty_sid,
+                                       SECCLASS_CHR_FILE, &new_tty_sid) != 0) {
+                       bb_perror_msg_and_die("security_change_sid(%s) failed",
+                                       full_tty);
                }
-               if(setfilecon(full_tty, new_tty_sid) != 0)
-               {
-                       fprintf(stderr, "chsid(%.100s, %s) failed: %.100s\n", full_tty, new_tty_sid, strerror(errno));
-                       return EXIT_FAILURE;
+               if (setfilecon(full_tty, new_tty_sid) != 0) {
+                       bb_perror_msg_and_die("chsid(%s, %s) failed",
+                                       full_tty, new_tty_sid);
                }
        }
 #endif
-       if ( !is_my_tty ( full_tty ))
-               syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty );
-
-       /* Try these, but don't complain if they fail
-        * (for example when the root fs is read only) */
-       chown ( full_tty, pw-> pw_uid, pw-> pw_gid );
-       chmod ( full_tty, 0600 );
+       /* Try these, but don't complain if they fail.
+        * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */
+       fchown(0, pw->pw_uid, pw->pw_gid);
+       fchmod(0, 0600);
+
+/* TODO: be nommu-friendly, use spawn? */
+       if (ENABLE_LOGIN_SCRIPTS) {
+               char *script = getenv("LOGIN_PRE_SUID_SCRIPT");
+               if (script) {
+                       char *t_argv[2] = { script, NULL };
+                       switch (fork()) {
+                       case -1: break;
+                       case 0: /* child */
+                               xchdir("/");
+                               setenv("LOGIN_TTY", full_tty, 1);
+                               setenv("LOGIN_USER", pw->pw_name, 1);
+                               setenv("LOGIN_UID", utoa(pw->pw_uid), 1);
+                               setenv("LOGIN_GID", utoa(pw->pw_gid), 1);
+                               setenv("LOGIN_SHELL", pw->pw_shell, 1);
+                               BB_EXECVP(script, t_argv);
+                               exit(1);
+                       default: /* parent */
+                               wait(NULL);
+                       }
+               }
+       }
 
-       change_identity ( pw );
-       tmp = pw-> pw_shell;
-       if(!tmp || !*tmp)
+       change_identity(pw);
+       tmp = pw->pw_shell;
+       if (!tmp || !*tmp)
                tmp = DEFAULT_SHELL;
-       setup_environment ( tmp, 1, !opt_preserve, pw );
+       setup_environment(tmp, 1, !(opt & LOGIN_OPT_p), pw);
 
-       motd ( );
-       signal ( SIGALRM, SIG_DFL );    /* default alarm signal */
+       motd();
 
-       if ( pw-> pw_uid == 0 )
-               syslog ( LOG_INFO, "root login %s\n", fromhost );
+       if (pw->pw_uid == 0)
+               syslog(LOG_INFO, "root login%s", fromhost);
 #ifdef CONFIG_SELINUX
        /* well, a simple setexeccon() here would do the job as well,
         * but let's play the game for now */
        set_current_security_context(user_sid);
 #endif
-       run_shell ( tmp, 1, 0, 0);      /* exec the shell finally. */
-
-       return EXIT_FAILURE;
-}
-
-
-
-static int login_prompt ( char *buf_name )
-{
-       char buf [1024];
-       char *sp, *ep;
-       int i;
-
-       for(i=0; i<EMPTY_USERNAME_COUNT; i++) {
-               print_login_prompt();
-
-               if ( !fgets ( buf, sizeof( buf ) - 1, stdin ))
-                       return 0;
-
-               if ( !strchr ( buf, '\n' ))
-                       return 0;
-
-               for ( sp = buf; isspace ( *sp ); sp++ ) { }
-               for ( ep = sp; isgraph ( *ep ); ep++ ) { }
-
-               *ep = 0;
-               safe_strncpy(buf_name, sp, USERNAME_SIZE);
-               if(buf_name[0])
-                       return 1;
-       }
-       return 0;
-}
-
-
-static int check_nologin ( int amroot )
-{
-       if ( access ( bb_path_nologin_file, F_OK ) == 0 ) {
-               FILE *fp;
-               int c;
-
-               if (( fp = fopen ( bb_path_nologin_file, "r" ))) {
-                       while (( c = getc ( fp )) != EOF )
-                               putchar (( c == '\n' ) ? '\r' : c );
-
-                       fflush ( stdout );
-                       fclose ( fp );
-               } else {
-                       puts ( "\r\nSystem closed for routine maintenance.\r" );
-               }
-               if ( !amroot )
-                       return 1;
-
-               puts ( "\r\n[Disconnect bypassed -- root login allowed.]\r" );
-       }
-       return 0;
-}
-
-#ifdef CONFIG_FEATURE_SECURETTY
-
-static int check_tty ( const char *tty )
-{
-       FILE *fp;
-       int i;
-       char buf[BUFSIZ];
-
-       if (( fp = fopen ( bb_path_securetty_file, "r" ))) {
-               while ( fgets ( buf, sizeof( buf ) - 1, fp )) {
-                       for ( i = strlen( buf ) - 1; i >= 0; --i ) {
-                               if ( !isspace ( buf[i] ))
-                                       break;
-                       }
-                       buf[++i] = '\0';
-                       if (( buf [0] == '\0' ) || ( buf [0] == '#' ))
-                               continue;
-
-                       if ( strcmp ( buf, tty ) == 0 ) {
-                               fclose ( fp );
-                               return 1;
-                       }
-               }
-               fclose(fp);
-               return 0;
-       }
-       /* A missing securetty file is not an error. */
-       return 1;
-}
-
-#endif
-
-/* returns 1 if true */
-static int is_my_tty ( const char *tty )
-{
-       struct stat by_name, by_fd;
-
-       if ( stat ( tty, &by_name ) || fstat ( 0, &by_fd ))
-               return 0;
-
-       if ( by_name. st_rdev != by_fd. st_rdev )
-               return 0;
-       else
-               return 1;
-}
-
-
-static void motd (void)
-{
-       FILE *fp;
-       int c;
-
-       if (( fp = fopen ( bb_path_motd_file, "r" ))) {
-               while (( c = getc ( fp )) != EOF )
-                       putchar ( c );
-               fclose ( fp );
-       }
-}
 
+       // util-linux login also does:
+       // /* start new session */
+       // setsid();
+       // /* TIOCSCTTY: steal tty from other process group */
+       // if (ioctl(0, TIOCSCTTY, 1)) error_msg...
 
-#ifdef CONFIG_FEATURE_UTMP
-// vv  Taken from tinylogin utmp.c  vv
+       /* set signals to defaults */
+       signal(SIGALRM, SIG_DFL);
+       /* Is this correct? This way user can ctrl-c out of /etc/profile,
+        * potentially creating security breach (tested with bash 3.0).
+        * But without this, bash 3.0 will not enable ctrl-c either.
+        * Maybe bash is buggy?
+        * Need to find out what standards say about /bin/login -
+        * should it leave SIGINT etc enabled or disabled? */
+       signal(SIGINT, SIG_DFL);
 
-#define        NO_UTENT \
-       "No utmp entry.  You must exec \"login\" from the lowest level \"sh\""
-#define        NO_TTY \
-       "Unable to determine your tty name."
+       run_shell(tmp, 1, 0, 0);        /* exec the shell finally */
 
-/*
- * checkutmp - see if utmp file is correct for this process
- *
- *     System V is very picky about the contents of the utmp file
- *     and requires that a slot for the current process exist.
- *     The utmp file is scanned for an entry with the same process
- *     ID.  If no entry exists the process exits with a message.
- *
- *     The "picky" flag is for network and other logins that may
- *     use special flags.  It allows the pid checks to be overridden.
- *     This means that getty should never invoke login with any
- *     command line flags.
- */
-
-static void checkutmp(int picky)
-{
-       char *line;
-       struct utmp *ut;
-       pid_t pid = getpid();
-
-       setutent();
-
-       /* First, try to find a valid utmp entry for this process.  */
-       while ((ut = getutent()))
-               if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
-                       (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))
-                       break;
-
-       /* If there is one, just use it, otherwise create a new one.  */
-       if (ut) {
-               utent = *ut;
-       } else {
-               time_t t_tmp;
-               
-               if (picky) {
-                       puts(NO_UTENT);
-                       exit(1);
-               }
-               line = ttyname(0);
-               if (!line) {
-                       puts(NO_TTY);
-                       exit(1);
-               }
-               if (strncmp(line, "/dev/", 5) == 0)
-                       line += 5;
-               memset(&utent, 0, sizeof utent);
-               utent.ut_type = LOGIN_PROCESS;
-               utent.ut_pid = pid;
-               strncpy(utent.ut_line, line, sizeof utent.ut_line);
-               /* XXX - assumes /dev/tty?? */
-               strncpy(utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
-               strncpy(utent.ut_user, "LOGIN", sizeof utent.ut_user);
-               t_tmp = (time_t)utent.ut_time;
-               time(&t_tmp);
-       }
-}
-
-/*
- * setutmp - put a USER_PROCESS entry in the utmp file
- *
- *     setutmp changes the type of the current utmp entry to
- *     USER_PROCESS.  the wtmp file will be updated as well.
- */
-
-static void setutmp(const char *name, const char *line ATTRIBUTE_UNUSED)
-{
-       time_t t_tmp = (time_t)utent.ut_time;
-
-       utent.ut_type = USER_PROCESS;
-       strncpy(utent.ut_user, name, sizeof utent.ut_user);
-       time(&t_tmp);
-       /* other fields already filled in by checkutmp above */
-       setutent();
-       pututline(&utent);
-       endutent();
-#ifdef CONFIG_FEATURE_WTMP
-       if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
-               close(creat(bb_path_wtmp_file, 0664));
-       }
-       updwtmp(bb_path_wtmp_file, &utent);
-#endif
+       return EXIT_FAILURE;
 }
-#endif /* CONFIG_FEATURE_UTMP */