From 48037909a5a5c8e0640c33352de6aa942f532d8c Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Thu, 20 Mar 2008 11:58:00 -0400 Subject: - stable version --- Makefile | 15 +++ README | 20 ++++ TODO | 0 autologin.8 | 29 +++++ autologin.c | 330 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ autologin.pamd | 3 + autologin.spec | 43 ++++++++ 7 files changed, 440 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 TODO create mode 100644 autologin.8 create mode 100644 autologin.c create mode 100644 autologin.pamd create mode 100644 autologin.spec diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..13ff2fe --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +CFLAGS=-Wall -Wextra +LDFLAGS=-lpam -lutempter -ldl + +all: autologin + +clean: + $(RM) autologin + +install: $(DESTDIR)/sbin/autologin $(DESTDIR)/usr/man/man8/autologin.8.gz + +$(DESTDIR)/sbin/autologin: autologin + install -m 711 $^ $@ + +$(DESTDIR)/usr/man/man8/autologin.8.gz: autologin.8 + cat autologin.8 | gzip > $(DESTDIR)/usr/man/man8/autologin.8.gz diff --git a/README b/README new file mode 100644 index 0000000..a4ecba6 --- /dev/null +++ b/README @@ -0,0 +1,20 @@ +This is a program you can use to automatically log in on a workstation when +it boots. Look for a line in /etc/inittab that looks like this: + +1:2345:respawn:/sbin/mingetty tty1 + +Replace it with this: + +1:2345:respawn:/sbin/autlogin tty1 joeuser + +And joeuser will be logged in automatically when the system boots. To have +some command other than a shell started, supply it as a third argument: + +1:2345:respawn:/sbin/autlogin tty1 joeuser startx + +Note that this is a potential security risk that's big enough to drive a truck +through, and it's only guaranteed to work with pam_unix and possibly pam_pwdb. + +Consider yourself warned. + +Nalin Dahyabhai diff --git a/TODO b/TODO new file mode 100644 index 0000000..e69de29 diff --git a/autologin.8 b/autologin.8 new file mode 100644 index 0000000..8ff7ac3 --- /dev/null +++ b/autologin.8 @@ -0,0 +1,29 @@ +.TH AUTOLOGIN 8 "Red Hat, Inc." "Red Hat Linux" \" -*- nroff -*- +.SH NAME +autologin \- run a program without having to log in first +.SH SYNOPSIS +.B autologin +\fItty\fP \fIuser\fP [command] +.SH DESCRIPTION +.B autologin +opens a specified terminal, becomes the specified user, and will either +start an interactive shell or run a specified command. This is intended +for use in your \fB/etc/inittab\fP file, but can be used elsewhere. + +.SH OPTIONS +.TP +.I tty +The name of the TTY device to use. Most of the time this will be one of +the virtual consoles, numbered from \fBtty1\fP to \fBtty12\fP. The \fB/dev\fP +prefix can be omitted. +.TP +.I user +The name of the user to become. Autologin will drop privileges to those of this +user before doing anything else. +.TP +.I command +An optional command to run. It must be a binary, either in the default PATH, or +given as a full pathname. If no command is specified, the user's shell will be +started interactively. +.SH AUTHOR +Nalin Dahyabhai 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; +} diff --git a/autologin.pamd b/autologin.pamd new file mode 100644 index 0000000..5d4b71a --- /dev/null +++ b/autologin.pamd @@ -0,0 +1,3 @@ +auth include login +account include login +session include login diff --git a/autologin.spec b/autologin.spec new file mode 100644 index 0000000..d770d73 --- /dev/null +++ b/autologin.spec @@ -0,0 +1,43 @@ +%define name autologin +%define version 0.02 +%define release 1 + +Summary: Auto Login Utility +Name: %{name} +Version: %{version} +Release: %{release} +License: GPLv2 +Group: Security Violations +Source: autologin.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description +This is a program you can use to automatically log in on a workstation when +it boots. This program is normally run from /etc/inittab replacing one of +your mingetty lines. This program is a huge security hole. + +%prep +%setup -n %{name} + +%build +make + +%install + +mkdir -p $RPM_BUILD_ROOT/sbin/ +mkdir -p $RPM_BUILD_ROOT/usr/man/man8/ +install autologin $RPM_BUILD_ROOT/sbin/ +cat autologin.8 | gzip > $RPM_BUILD_ROOT/usr/man/man8/autologin.8.gz + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc README TODO +%attr(711,root,root) /sbin/autologin +/usr/man/man8/autologin.8.gz + +%changelog +* Thu Mar 16 2000 Dale Lovelace +- First RPM build -- cgit