#define _BSD_SOURCE
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOGIN_PERMS               (S_IRUSR|S_IWUSR)    /* for login prompts */
#define LOGIN_KEEP_ENV            01
#define LOGIN_HAVE_RHOST          02
#define LOGIN_GARBLED            010
#define LOGIN_FORCE_AUTH          04
#define LOGIN_FALSE                0
#define LOGIN_TRUE                 1

void parse_args(int argc, const char **argv, const char **user,
        const char **login_remote_host, int *login_flags)
{
    int is_option = 1;      /*
                             * this is to allow "--" to terminate options
                             * -it also allows login names to begin with
                             * "-" - which seems strange.
                             */
    while (--argc > 0) {
        if ( (*++argv)[0] == '-' && is_option ) {
            switch ((*argv)[1]) {
            case '-':
                is_option = 0;                   /* last option entered */
                break;
            case 'p':
                *login_flags |= LOGIN_KEEP_ENV;
                break;
            case 'h':
                *login_flags |= LOGIN_HAVE_RHOST;
                {
                    const char *hn;

                    hn = 2+*argv;
                    if (hn[0] || (--argc > 0 && (hn = *++argv))) 
		    {
                        *login_remote_host = strdup (hn);
                        hn = NULL;
                        if (*login_remote_host != NULL)
                            break;
                    }
                    hn = NULL;
                }
                *login_flags |= LOGIN_GARBLED;
                break;
            case 'f':
                *login_flags |= LOGIN_FORCE_AUTH;
                break;
            default:
                (void) fprintf(stderr,"unrecognized request: %s ?\n", argv[0]);
                *login_flags |= LOGIN_GARBLED;
            }
        } else {
            *user = (*argv);
        }
    }

    if ((*login_flags & LOGIN_GARBLED))
    {
        (void) fprintf (stderr, "usage:\n\tlogin [`username'] \t - login [as user]\n \t-p\t\t - do not destroy environment\n \t-h `hostname'\t - from hostname\n\t-f\t\t - pre-authenticated\n\t--\t\t - stop treating arguments as flags\n");
        (void) sleep(60);
        exit (1);
    }
}
int login_get_terminal(const char **terminal_name)
{
    /* identify terminal */

    *terminal_name = ttyname(STDIN_FILENO);
    if (*terminal_name == NULL || !(*(terminal_name)[0])) 
    { 
    /* no terminal known? */
        return LOGIN_FALSE;
    }

    /* possess terminal */
    {
        if (chown(*terminal_name, 0, 0)
            || chmod(*terminal_name, LOGIN_PERMS)) {
            return LOGIN_FALSE;                  /* couldn't own terminal */
        }
    }

    /* reset terminal */
    {
        struct termios old_terminal;
        struct sigaction old_action, tmp_action;

        /* remember the current terminal settings; set by getty etc.. */
        if (tcgetattr(STDIN_FILENO, &old_terminal) < 0) {
            return LOGIN_FALSE;
        }

        /*
         * terminate all the processes (other than this one)
         * that want to use this terminal...
         */

        sigemptyset(&tmp_action.sa_mask);
        tmp_action.sa_flags = 0;
        tmp_action.sa_handler = SIG_IGN;       /* ignore signal */
        if (sigaction(SIGHUP, &tmp_action, &old_action) != 0) {
            return LOGIN_FALSE;                /* trouble with signals */
        }

        /* signal shield up here */
        (void) vhangup();           /* SIGHUP to all users of terminal */
        /* signal shield down again */

        if (sigaction(SIGHUP, &old_action, NULL) != 0) {
            return LOGIN_FALSE;
        }

        /*
         * We have the terminal to ourselves now...
         */

        setsid();

        /* ensure STDIN/OUT/ERR_FILENOs point to the terminal */
        {
            int fildes;

            fildes = open(*terminal_name, O_RDWR);
            if (fildes < 0) {
                return LOGIN_FALSE;
            }

            /* realign STD.. to terminal (just in case) */
            if ( dup2(fildes, STDIN_FILENO) < 0
                 || dup2(fildes, STDOUT_FILENO) < 0
                 || dup2(fildes, STDERR_FILENO) < 0 ) {
                return LOGIN_FALSE;
            }

            if ( fildes != STDIN_FILENO && fildes != STDOUT_FILENO
                 && fildes != STDERR_FILENO ) {
                close(fildes);
            }
        }

        /* reset the terminal settings to their previous values.. */

        if ( tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_terminal) < 0 ) {
            return LOGIN_FALSE;
        }
    }

    /* we have the terminal for our use. */

    return LOGIN_TRUE;
}
