summaryrefslogtreecommitdiffstats
path: root/autologin.c
diff options
context:
space:
mode:
authorNalin Dahyabhai <nalin.dahyabhai@pobox.com>2008-03-20 11:58:00 -0400
committerNalin Dahyabhai <nalin.dahyabhai@pobox.com>2008-03-20 11:58:00 -0400
commit48037909a5a5c8e0640c33352de6aa942f532d8c (patch)
tree6123e59209f23cf9f35314729ed0aed0adc04ebc /autologin.c
downloadautologin-48037909a5a5c8e0640c33352de6aa942f532d8c.tar.gz
autologin-48037909a5a5c8e0640c33352de6aa942f532d8c.tar.xz
autologin-48037909a5a5c8e0640c33352de6aa942f532d8c.zip
- stable version
Diffstat (limited to 'autologin.c')
-rw-r--r--autologin.c330
1 files changed, 330 insertions, 0 deletions
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 <nalin@redhat.com>
+ * 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 <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <security/pam_appl.h>
+#include <utempter.h>
+
+#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;
+}