Release new version 2.13.0
[grml-scripts.git] / compile / grml-runtty.c
1 /*
2  * Copyright 2011 Christian Hofstaedtler. Licensed under GPL Version 2.
3  *
4  * Most of this is copied from fgetty, which is
5  *   Copyright Felix von Leitner, licensed under GPL Version 2.
6 */
7
8 #define _GNU_SOURCE
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <errno.h>
14 #include <pwd.h>
15 #include <grp.h>
16 #include <sys/param.h>
17 #include <sys/ioctl.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <syslog.h>
22 #include <signal.h>
23
24 char* tty;
25 char* prog;
26 char* user;
27
28 void error(const char* message, int exitcode) {
29   write(2, "E: ", 3);
30   write(2, message, strlen(message));
31   write(2, "\n", 1);
32   syslog(LOG_CRIT, "%s", message);
33   sleep(15);
34   closelog();
35   exit(exitcode);
36 }
37
38 void sigquit_handler(int signum) {
39   error("SIGQUIT received\n",23);
40 }
41
42 void setup_tty() {
43   struct sigaction sa;
44   int fd;
45   if (chown(tty,0,0) || chmod(tty,0600))
46     error("could not chown/chmod tty device\n",1);
47   sa.sa_handler=SIG_IGN;
48   sa.sa_flags=0;
49   sigemptyset(&sa.sa_mask);
50   sigaction(SIGHUP,&sa,NULL);
51   sa.sa_handler=sigquit_handler;
52   sigaction(SIGQUIT,&sa,NULL);
53
54   setsid();
55   if ((fd=open(tty, O_RDWR, 0))<0)
56     error("open tty failed", errno);
57   if (ioctl (fd, TIOCSCTTY, (void *)1) == -1)
58     error("ioctl TIOCSCTTY failed", errno);
59   if (!isatty(fd))
60     error("\"not a typewriter\" (isatty failed)", errno);
61   if (vhangup())        /* linux specific */
62     error("vhangup failed", errno);
63   close(2); close(1); close(0); close(fd);
64   if (open(tty, O_RDWR,0) != 0)
65     error("could not (re)open tty", errno);
66   if (dup(0) != 1 || dup(0) != 2)
67     error("could not dup stdout and stderr", errno);
68
69   sa.sa_handler=SIG_DFL;
70   sa.sa_flags=0;
71   sigemptyset(&sa.sa_mask);
72   sigaction(SIGHUP,&sa,NULL);
73 }
74
75 void setenvvar(char* envvar, char* value) {
76   /* buf ends up directly in env. can't use alloca */
77   char* buf = malloc(strlen(envvar) + strlen(value) + 2);
78   strcpy(buf, envvar);
79   strcat(buf, "=");
80   strcat(buf, value);
81   putenv(buf);
82 }
83
84 int main(int argc, char* argv[]) {
85   struct passwd* pw;
86
87   tty = argv[1];
88   prog = argv[2];
89   user = argv[3];
90
91   openlog("grml-runtty", LOG_CONS | LOG_PID, LOG_AUTHPRIV);
92
93   if (tty == NULL || prog == NULL || user == NULL)
94     error("Usage: grml-runtty /dev/ttyX /bin/bash user", 1);
95
96   pw = getpwnam(user);
97   if (!pw)
98     error("User does not exist", 1);
99
100   clearenv();
101   putenv("TERM=linux");
102   if (pw->pw_uid == 0) {
103     putenv("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
104   } else {
105     putenv("PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games");
106   }
107   setenvvar("TTY", tty);
108   setenvvar("USER", pw->pw_name);
109   setenvvar("LOGNAME", pw->pw_name);
110   setenvvar("SHELL", pw->pw_shell);
111   setenvvar("HOME", pw->pw_dir);
112   {
113     char uidbuf[15];
114     sprintf(uidbuf, "%i", pw->pw_uid);
115     setenvvar("UID", uidbuf);
116   }
117
118 #ifndef DEBUG
119   setup_tty();
120 #endif
121   chown(tty, pw->pw_uid, pw->pw_gid);
122
123   if (initgroups(pw->pw_name, pw->pw_gid) == -1)
124     error("initgroups failed", 1);
125   if (setgid(pw->pw_gid) == -1)
126     error("setgid failed", 1);
127   if (setuid(pw->pw_uid) == -1)
128     error("setuid failed", 1);
129
130   {
131     char *Argv[] = {prog, 0};
132     execve(prog, Argv, environ);
133   }
134
135   /* should never come here */
136   error("Program startup failed", 99);
137 }