/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
1
#define _GNU_SOURCE		/* asprintf() */
2
#include <signal.h>		/* sig_atomic_t, struct sigaction,
3
				   sigemptyset(), sigaddset(),
4
				   sigaction, SIGINT, SIG_IGN, SIGHUP,
5
				   SIGTERM, kill(), SIGKILL */
6
#include <stddef.h>		/* NULL */
7
#include <stdlib.h>		/* getenv() */
8
#include <stdio.h>		/* asprintf(), perror() */
9
#include <stdlib.h>		/* EXIT_FAILURE, EXIT_SUCCESS,
10
				   strtoul(), free() */
11
#include <sys/types.h>		/* pid_t, DIR, struct dirent,
12
				   ssize_t */
13
#include <dirent.h>		/* opendir(), readdir(), closedir() */
14
#include <unistd.h>		/* readlink(), fork(), execl(),
15
				   _exit */
16
#include <string.h>		/* memcmp() */
17
#include <iso646.h>		/* and */
18
#include <errno.h>		/* errno */
19
#include <sys/wait.h>		/* waitpid(), WIFEXITED(),
20
				   WEXITSTATUS() */
21
22
sig_atomic_t interrupted_by_signal = 0;
23
24
static void termination_handler(__attribute__((unused))int signum){
25
  interrupted_by_signal = 1;
26
}
27
28
int main(__attribute__((unused))int argc, char **argv){
29
  int ret = 0;
30
  
31
  /* Create prompt string */
32
  char *prompt = NULL;
33
  {
34
    const char *const cryptsource = getenv("cryptsource");
35
    const char *const crypttarget = getenv("crypttarget");
36
    const char *const prompt_start = "getpass "
37
      "Enter passphrase to unlock the disk";
38
    
39
    if(cryptsource == NULL){
40
      if(crypttarget == NULL){
41
	ret = asprintf(&prompt, "%s: ", prompt_start);
42
      } else {
43
	ret = asprintf(&prompt, "%s (%s): ", prompt_start,
44
		       crypttarget);
45
      }
46
    } else {
47
      if(crypttarget == NULL){
48
	ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
49
      } else {
50
	ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
51
		       cryptsource, crypttarget);
52
      }
53
    }
54
    if(ret == -1){
55
      return EXIT_FAILURE;
56
    }
57
  }
58
  
59
  /* Find splashy process */
60
  pid_t splashy_pid = 0;
61
  {
62
    const char splashy_name[] = "/sbin/splashy";
63
    DIR *proc_dir = opendir("/proc");
64
    if(proc_dir == NULL){
65
      free(prompt);
66
      perror("opendir");
67
      return EXIT_FAILURE;
68
    }
69
    for(struct dirent *proc_ent = readdir(proc_dir);
70
	proc_ent != NULL;
71
	proc_ent = readdir(proc_dir)){
72
      pid_t pid = (pid_t) strtoul(proc_ent->d_name, NULL, 10);
73
      if(pid == 0){
74
	/* Not a process */
75
	continue;
76
      }
77
      /* Find the executable name by doing readlink() on the
78
	 /proc/<pid>/exe link */
79
      char *exe_link;
80
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
81
      if(ret == -1){
82
	perror("asprintf");
83
	free(prompt);
84
	closedir(proc_dir);
85
	return EXIT_FAILURE;
86
      }
87
      char exe_target[sizeof(splashy_name)];
88
      ssize_t sret = readlink(exe_link, exe_target,
89
			      sizeof(exe_target));
90
      if((sret == ((ssize_t)sizeof(exe_target)-1))
91
	 and (memcmp(splashy_name, exe_target,
92
		     sizeof(exe_target)-1) == 0)){
93
	splashy_pid = pid;
94
	break;
95
      }
96
    }
97
    closedir(proc_dir);
98
  }
99
  if(splashy_pid == 0){
100
    free(prompt);
101
    return EXIT_FAILURE;
102
  }
103
  
104
  /* Set up the signal handler */
105
  {
106
    struct sigaction old_action,
107
      new_action = { .sa_handler = termination_handler,
108
		     .sa_flags = 0 };
109
    sigemptyset(&new_action.sa_mask);
110
    sigaddset(&new_action.sa_mask, SIGINT);
111
    sigaddset(&new_action.sa_mask, SIGHUP);
112
    sigaddset(&new_action.sa_mask, SIGTERM);
113
    ret = sigaction(SIGINT, NULL, &old_action);
114
    if(ret == -1){
115
      perror("sigaction");
116
      free(prompt);
117
      return EXIT_FAILURE;
118
    }
119
    if (old_action.sa_handler != SIG_IGN){
120
      ret = sigaction(SIGINT, &new_action, NULL);
121
      if(ret == -1){
122
	perror("sigaction");
123
	free(prompt);
124
	return EXIT_FAILURE;
125
      }
126
    }
127
    ret = sigaction(SIGHUP, NULL, &old_action);
128
    if(ret == -1){
129
      perror("sigaction");
130
      free(prompt);
131
      return EXIT_FAILURE;
132
    }
133
    if (old_action.sa_handler != SIG_IGN){
134
      ret = sigaction(SIGHUP, &new_action, NULL);
135
      if(ret == -1){
136
	perror("sigaction");
137
	free(prompt);
138
	return EXIT_FAILURE;
139
      }
140
    }
141
    ret = sigaction(SIGTERM, NULL, &old_action);
142
    if(ret == -1){
143
      perror("sigaction");
144
      free(prompt);
145
      return EXIT_FAILURE;
146
    }
147
    if (old_action.sa_handler != SIG_IGN){
148
      ret = sigaction(SIGTERM, &new_action, NULL);
149
      if(ret == -1){
150
	perror("sigaction");
151
	free(prompt);
152
	return EXIT_FAILURE;
153
      }
154
    }
155
  }
156
  
157
  /* Fork off the splashy command to prompt for password */
158
  pid_t splashy_command_pid = 0;
159
  if(not interrupted_by_signal){
160
    splashy_command_pid = fork();
161
    if(splashy_command_pid == -1){
162
      if(not interrupted_by_signal){
163
	perror("fork");
164
      }
165
      return EXIT_FAILURE;
166
    }
167
    /* Child */
168
    if(splashy_command_pid == 0){
169
      const char splashy_command[] = "/sbin/splashy_update";
170
      ret = execl(splashy_command, splashy_command, prompt,
171
		  (char *)NULL);
172
      if(not interrupted_by_signal and errno != ENOENT){
173
	/* Don't report "File not found", since splashy might not be
174
	   installed. */
175
	perror("execl");
176
      }
177
      free(prompt);
178
      return EXIT_FAILURE;
179
    }
180
  }
181
  
182
  /* Parent */
183
  free(prompt);
184
  
185
  /* Wait for command to complete */
186
  int status;
187
  while(not interrupted_by_signal){
188
    waitpid(splashy_command_pid, &status, 0);
189
    if(not interrupted_by_signal
190
       and WIFEXITED(status) and WEXITSTATUS(status)==0){
191
      return EXIT_SUCCESS;
192
    }
193
  }
194
  kill(splashy_pid, SIGTERM);
195
  if(interrupted_by_signal){
196
    kill(splashy_command_pid, SIGTERM);
197
  }
198
199
  pid_t new_splashy_pid = fork();
200
  if(new_splashy_pid == 0){
201
    while(kill(splashy_pid, 0)){
202
      sleep(2);
203
      kill(splashy_pid, SIGKILL);
204
      sleep(1);
205
    }
206
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
207
    if(ret == -1){
208
      perror("dup2");
209
      _exit(EXIT_FAILURE);
210
    }
211
    execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
212
  }
213
  
214
  return EXIT_FAILURE;
215
}