From 48037909a5a5c8e0640c33352de6aa942f532d8c Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Thu, 20 Mar 2008 11:58:00 -0400 Subject: - stable version --- autologin.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 autologin.c (limited to 'autologin.c') diff --git a/autologin.c b/autologin.c new file mode 100644 index 0000000..31eb1f8 --- /dev/null +++ b/autologin.c @@ -0,0 +1,330 @@ +/* + * Autologin - sort of automatic execution on a terminal. + * Author: Nalin Dahyabhai + * Copyright (c) 2000,2005 Red Hat, Inc. + * + * This program is licensed under the terms of the GPL. + */ + +#ident "$Id: autologin.c,v 1.3 1999/12/19 22:37:45 nalin Exp $" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SLEEPYTIME 5 + +static int +converse(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) +{ + int i; + + resp = malloc(sizeof(struct pam_response*) * (num_msg + 1)); + if (resp == NULL) { + fprintf(stderr, "out of memory!\n"); + sleep(SLEEPYTIME); + _exit(1); + } + memset(resp, 0, sizeof(struct pam_response*) * (num_msg + 1)); + + for (i = 0; i < num_msg; i++) { + resp[i] = malloc(sizeof(struct pam_response)); + memset(resp[i], 0, sizeof(struct pam_response)); + resp[i]->resp_retcode = PAM_SUCCESS; + + switch (msg[i]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + case PAM_PROMPT_ECHO_ON: + resp[i]->resp = strdup(appdata_ptr ? + appdata_ptr : ""); + /* fall through */ + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + if ((msg[i]->msg != NULL) && + (strlen(msg[i]->msg) > 0)) { + fprintf(stderr, "%s", msg[i]->msg); + } + break; + default: + break; + } + } + return PAM_SUCCESS; +} + +static void +init_environment(pam_handle_t *pamh, struct passwd *pwd) +{ + char *tmp, **envlist; + const char *path; + int i; + + /* Set the same variables that login(1) would. */ + tmp = malloc(5 + strlen(pwd->pw_dir) + 1); + if (tmp == NULL) { + fprintf(stderr, "out of memory!\n"); + sleep(SLEEPYTIME); + _exit(1); + } + sprintf(tmp, "HOME=%s", pwd->pw_dir); + putenv(tmp); + + tmp = malloc(6 + strlen(pwd->pw_shell) + 1); + if (tmp == NULL) { + fprintf(stderr, "out of memory!\n"); + sleep(SLEEPYTIME); + _exit(1); + } + sprintf(tmp, "SHELL=%s", pwd->pw_shell); + putenv(tmp); + + tmp = malloc(8 + strlen(pwd->pw_name) + 1); + if (tmp == NULL) { + fprintf(stderr, "out of memory!\n"); + sleep(SLEEPYTIME); + _exit(1); + } + sprintf(tmp, "LOGNAME=%s", pwd->pw_name); + putenv(tmp); + + tmp = malloc(5 + strlen(pwd->pw_name) + 1); + if (tmp == NULL) { + fprintf(stderr, "out of memory!\n"); + sleep(SLEEPYTIME); + _exit(1); + } + sprintf(tmp, "USER=%s", pwd->pw_name); + putenv(tmp); + + if (pwd->pw_uid == 0) { + path = "/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin"; + } else { + path = "/usr/local/bin:" + "/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin"; + } + + asprintf(&tmp, "PATH=%s", path); + if (tmp == NULL) { + fprintf(stderr, "out of memory!\n"); + sleep(SLEEPYTIME); + _exit(1); + } + putenv(tmp); + + /* Set any environment variables which PAM would like for us to set. */ + envlist = pam_getenvlist(pamh); + for (i = 0; (envlist != NULL) && (envlist[i] != NULL); i++) { + putenv(envlist[i]); + } +} + +int +main(int argc, char **argv) +{ + int ret = 0; + int fd = 0; + pid_t child; + pam_handle_t *pamh = NULL; + char tty[PATH_MAX]; + char shell[PATH_MAX]; + struct passwd *pwd; + struct group *ttygrp; + struct stat st; + struct pam_conv conversation = { + converse, + "", + }; + + /* Verify that we were invoked correctly. */ + if ((argc < 3) || (argc > 4)) { + fprintf(stderr, "Incorrect invocation -- should be \"%s tty " + "user [command]\"\n", argv[0]); + sleep(SLEEPYTIME); + exit(1); + } + + /* Verify that the user exists. */ + pwd = getpwnam(argv[2]); + if (pwd == NULL) { + fprintf(stderr, "Unknown user \"%s\"!\n", argv[2]); + sleep(SLEEPYTIME); + exit(1); + } + ttygrp = getgrnam("tty"); + + /* Verify that the specified tty exists. */ + strncpy(tty, argv[1], sizeof(tty)); + if (stat(tty, &st) != 0) { + strncpy(tty, "/dev/", sizeof(tty)); + strncat(tty, argv[1], sizeof(tty)); + if (stat(tty, &st) != 0) { + fprintf(stderr, "Unknown tty \"%s\"!\n", argv[1]); + sleep(SLEEPYTIME); + exit(1); + } + } + + /* Make the tty our controlling terminal. */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + fd = open(tty, O_RDWR); + if (fd == -1) { + fprintf(stderr, "Error opening %s: %s.\n", tty, + strerror(errno)); + sleep(SLEEPYTIME); + exit(1); + } + if (dup2(fd, STDIN_FILENO) != STDIN_FILENO) { + fprintf(stderr, "Error dup2()ing to stdin: %s.\n", + strerror(errno)); + sleep(SLEEPYTIME); + exit(1); + } + if (dup2(fd, STDOUT_FILENO) != STDOUT_FILENO) { + fprintf(stderr, "Error dup2()ing to stdout: %s.\n", + strerror(errno)); + sleep(SLEEPYTIME); + exit(1); + } + if (dup2(fd, STDERR_FILENO) != STDERR_FILENO) { + fprintf(stderr, "Error dup2()ing to stderr: %s.\n", + strerror(errno)); + sleep(SLEEPYTIME); + exit(1); + } + if (dup2(fd, 3) != 3) { + fprintf(stderr, "Error dup2()ing to FD3: %s.\n", + strerror(errno)); + sleep(SLEEPYTIME); + exit(1); + } + if (fcntl(3, F_SETFD, FD_CLOEXEC) != 0) { + fprintf(stderr, "Error setting close-on-exec flag: %s.\n", + strerror(errno)); + sleep(SLEEPYTIME); + exit(1); + } + + /* Start PAM up, skip authentication, and open a session. */ + ret = pam_start("login", argv[2], &conversation, &pamh); + if (ret != PAM_SUCCESS) { + fprintf(stderr, "Error initializing libpam: %s\n", + pam_strerror(pamh, ret)); + sleep(SLEEPYTIME); + exit(1); + } + + pam_set_item(pamh, PAM_USER, argv[2]); + pam_set_item(pamh, PAM_TTY, argv[1]); + + pam_set_item(pamh, PAM_RHOST, NULL); + pam_set_item(pamh, PAM_RUSER, argv[2]); + + ret = pam_setcred(pamh, PAM_ESTABLISH_CRED); + if (ret != PAM_SUCCESS) { + fprintf(stderr, "Error establishing credentials: %s\n", + pam_strerror(pamh, ret)); + sleep(SLEEPYTIME); + exit(1); + } + + ret = pam_open_session(pamh, 0); + if (ret != PAM_SUCCESS) { + fprintf(stderr, "Error initializing session: %s\n", + pam_strerror(pamh, ret)); + sleep(SLEEPYTIME); + exit(1); + } + + /* Prepare argv[0] for the user's shell. */ + memset(shell, 0, sizeof(shell)); + if (rindex(pwd->pw_shell, '/') != NULL) { + strncpy(shell, rindex(pwd->pw_shell, '/'), sizeof(shell)); + } else { + strncpy(shell + 1, pwd->pw_shell, sizeof(shell)); + } + shell[0] = '-'; + + /* Set permissions on the device. */ + chown(tty, pwd->pw_uid, ttygrp ? ttygrp->gr_gid : 0); + chmod(tty, 0620); + + /* Log the login. */ + addToUtmp(tty, NULL, STDERR_FILENO); + + /* Fork. The child will exec the shell. */ + child = fork(); + if (child < 0) { + fprintf(stderr, "Error fork()ing: %s\n", strerror(errno)); + /* Don't leave an erroneous login behind. */ + removeFromUtmp(); + sleep(SLEEPYTIME); + exit(1); + } + + if (child == 0) { + /* We're in the child. */ + fprintf(stderr, ""); + initgroups(pwd->pw_name, pwd->pw_gid); + if (setuid(pwd->pw_uid) == 0) { + init_environment(pamh, pwd); + chdir(pwd->pw_dir); + /* If we have an argv[3], execute it instead. */ + if (argc >= 4) { + execlp(argv[3], argv[3], NULL); + } else { + execlp(pwd->pw_shell, shell, NULL); + } + } else { + fprintf(stderr, "Error becoming %s.\n", pwd->pw_name); + } + return 1; + } + if (child > 0) { + /* We're in the parent. */ + waitpid(child, NULL, 0); + kill(child, SIGHUP); + } + + /* Log the logout. */ + removeFromUtmp(); + + /* Reset permissions on the device. */ + chown(tty, st.st_uid, st.st_gid); + chmod(tty, st.st_mode); + + /* Clean up. */ + ret = pam_close_session(pamh, 0); + if (ret != PAM_SUCCESS) { + fprintf(stderr, "Error terminating session: %s\n", + pam_strerror(pamh, ret)); + sleep(SLEEPYTIME); + exit(1); + } + + ret = pam_setcred(pamh, PAM_DELETE_CRED); + if (ret != PAM_SUCCESS) { + fprintf(stderr, "Error deleting credentials: %s\n", + pam_strerror(pamh, ret)); + sleep(SLEEPYTIME); + exit(1); + } + + pam_end(pamh, PAM_SUCCESS); + + return 0; +} -- cgit