/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
1
/*  -*- coding: utf-8 -*- */
2
/*
261 by Teddy Hogeborn
* plugins.d/askpass-fifo.c: Fix name in header.
3
 * Splashy - Read a password from splashy and output it
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
4
 * 
246 by Teddy Hogeborn
* README: Update copyright year; add "2009".
5
 * Copyright © 2008,2009 Teddy Hogeborn
6
 * Copyright © 2008,2009 Björn Påhlsson
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
7
 * 
8
 * This program is free software: you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 * 
13
 * This program is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * General Public License for more details.
17
 * 
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program.  If not, see
20
 * <http://www.gnu.org/licenses/>.
21
 * 
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
22
 * Contact the authors at <mandos@fukt.bsnet.se>.
237.1.2 by Teddy Hogeborn
Further steps towards a D-Bus server interface, plus minor syntax
23
 */
24
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
25
#define _GNU_SOURCE		/* TEMP_FAILURE_RETRY(), asprintf() */
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
26
#include <signal.h>		/* sig_atomic_t, struct sigaction,
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
27
				   sigemptyset(), sigaddset(), SIGINT,
28
				   SIGHUP, SIGTERM, sigaction,
29
				   SIG_IGN, kill(), SIGKILL */
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
30
#include <stddef.h>		/* NULL */
31
#include <stdlib.h>		/* getenv() */
311 by Teddy Hogeborn
Overflows are not detected by sscanf(), so stop using it:
32
#include <stdio.h>		/* asprintf(), perror() */
264 by Teddy Hogeborn
* plugin-runner.c (main): Use "sscanf" instead of "strtol"; using the
33
#include <stdlib.h>		/* EXIT_FAILURE, free(),
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
34
				   EXIT_SUCCESS */
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
35
#include <sys/types.h>		/* pid_t, DIR, struct dirent,
36
				   ssize_t */
37
#include <dirent.h>		/* opendir(), readdir(), closedir() */
311 by Teddy Hogeborn
Overflows are not detected by sscanf(), so stop using it:
38
#include <inttypes.h>		/* intmax_t, strtoimax() */
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
39
#include <sys/stat.h>		/* struct stat, lstat(), S_ISLNK */
40
#include <iso646.h>		/* not, or, and */
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
41
#include <unistd.h>		/* readlink(), fork(), execl(),
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
42
				   sleep(), dup2() STDERR_FILENO,
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
43
				   STDOUT_FILENO, _exit(),
44
				   pause() */
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
45
#include <string.h>		/* memcmp() */
46
#include <errno.h>		/* errno */
47
#include <sys/wait.h>		/* waitpid(), WIFEXITED(),
48
				   WEXITSTATUS() */
49
50
sig_atomic_t interrupted_by_signal = 0;
362 by Teddy Hogeborn
* plugin-runner.c (getplugin, add_environment, main): Handle EINTR
51
int signal_received;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
52
362 by Teddy Hogeborn
* plugin-runner.c (getplugin, add_environment, main): Handle EINTR
53
static void termination_handler(int signum){
54
  if(interrupted_by_signal){
55
    return;
56
  }
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
57
  interrupted_by_signal = 1;
362 by Teddy Hogeborn
* plugin-runner.c (getplugin, add_environment, main): Handle EINTR
58
  signal_received = signum;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
59
}
60
208 by Teddy Hogeborn
* Makefile (PLUGINS): Added "plugins.d/usplash".
61
int main(__attribute__((unused))int argc,
62
	 __attribute__((unused))char **argv){
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
63
  int ret = 0;
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
64
  char *prompt = NULL;
65
  DIR *proc_dir = NULL;
66
  pid_t splashy_pid = 0;
67
  pid_t splashy_command_pid = 0;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
68
  
69
  /* Create prompt string */
70
  {
71
    const char *const cryptsource = getenv("cryptsource");
72
    const char *const crypttarget = getenv("crypttarget");
73
    const char *const prompt_start = "getpass "
74
      "Enter passphrase to unlock the disk";
75
    
76
    if(cryptsource == NULL){
77
      if(crypttarget == NULL){
78
	ret = asprintf(&prompt, "%s: ", prompt_start);
79
      } else {
80
	ret = asprintf(&prompt, "%s (%s): ", prompt_start,
81
		       crypttarget);
82
      }
83
    } else {
84
      if(crypttarget == NULL){
85
	ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
86
      } else {
87
	ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
88
		       cryptsource, crypttarget);
89
      }
90
    }
91
    if(ret == -1){
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
92
      prompt = NULL;
93
      goto failure;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
94
    }
95
  }
96
  
97
  /* Find splashy process */
98
  {
99
    const char splashy_name[] = "/sbin/splashy";
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
100
    proc_dir = opendir("/proc");
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
101
    if(proc_dir == NULL){
102
      perror("opendir");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
103
      goto failure;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
104
    }
105
    for(struct dirent *proc_ent = readdir(proc_dir);
106
	proc_ent != NULL;
107
	proc_ent = readdir(proc_dir)){
264 by Teddy Hogeborn
* plugin-runner.c (main): Use "sscanf" instead of "strtol"; using the
108
      pid_t pid;
268 by Teddy Hogeborn
Fixes for sscanf usage:
109
      {
110
	intmax_t tmpmax;
311 by Teddy Hogeborn
Overflows are not detected by sscanf(), so stop using it:
111
	char *tmp;
112
	errno = 0;
113
	tmpmax = strtoimax(proc_ent->d_name, &tmp, 10);
114
	if(errno != 0 or tmp == proc_ent->d_name or *tmp != '\0'
115
	   or tmpmax != (pid_t)tmpmax){
268 by Teddy Hogeborn
Fixes for sscanf usage:
116
	  /* Not a process */
117
	  continue;
118
	}
119
	pid = (pid_t)tmpmax;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
120
      }
121
      /* Find the executable name by doing readlink() on the
122
	 /proc/<pid>/exe link */
123
      char exe_target[sizeof(splashy_name)];
208 by Teddy Hogeborn
* Makefile (PLUGINS): Added "plugins.d/usplash".
124
      ssize_t sret;
125
      {
126
	char *exe_link;
127
	ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
128
	if(ret == -1){
129
	  perror("asprintf");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
130
	  goto failure;
208 by Teddy Hogeborn
* Makefile (PLUGINS): Added "plugins.d/usplash".
131
	}
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
132
	
133
	/* Check that it refers to a symlink owned by root:root */
134
	struct stat exe_stat;
135
	ret = lstat(exe_link, &exe_stat);
136
	if(ret == -1){
262 by Teddy Hogeborn
* plugins.d/splashy.c (main): Do not abort if a process vanishes while
137
	  if(errno == ENOENT){
138
	    free(exe_link);
139
	    continue;
140
	  }
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
141
	  perror("lstat");
142
	  free(exe_link);
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
143
	  goto failure;
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
144
	}
145
	if(not S_ISLNK(exe_stat.st_mode)
146
	   or exe_stat.st_uid != 0
147
	   or exe_stat.st_gid != 0){
148
	  free(exe_link);
149
	  continue;
150
	}
151
	
208 by Teddy Hogeborn
* Makefile (PLUGINS): Added "plugins.d/usplash".
152
	sret = readlink(exe_link, exe_target, sizeof(exe_target));
153
	free(exe_link);
154
      }
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
155
      if((sret == ((ssize_t)sizeof(exe_target)-1))
156
	 and (memcmp(splashy_name, exe_target,
157
		     sizeof(exe_target)-1) == 0)){
158
	splashy_pid = pid;
159
	break;
160
      }
161
    }
162
    closedir(proc_dir);
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
163
    proc_dir = NULL;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
164
  }
165
  if(splashy_pid == 0){
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
166
    goto failure;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
167
  }
168
  
169
  /* Set up the signal handler */
170
  {
171
    struct sigaction old_action,
172
      new_action = { .sa_handler = termination_handler,
173
		     .sa_flags = 0 };
174
    sigemptyset(&new_action.sa_mask);
175
    sigaddset(&new_action.sa_mask, SIGINT);
362 by Teddy Hogeborn
* plugin-runner.c (getplugin, add_environment, main): Handle EINTR
176
    if(ret == -1){
177
      perror("sigaddset");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
178
      goto failure;
362 by Teddy Hogeborn
* plugin-runner.c (getplugin, add_environment, main): Handle EINTR
179
    }
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
180
    sigaddset(&new_action.sa_mask, SIGHUP);
362 by Teddy Hogeborn
* plugin-runner.c (getplugin, add_environment, main): Handle EINTR
181
    if(ret == -1){
182
      perror("sigaddset");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
183
      goto failure;
362 by Teddy Hogeborn
* plugin-runner.c (getplugin, add_environment, main): Handle EINTR
184
    }
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
185
    sigaddset(&new_action.sa_mask, SIGTERM);
362 by Teddy Hogeborn
* plugin-runner.c (getplugin, add_environment, main): Handle EINTR
186
    if(ret == -1){
187
      perror("sigaddset");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
188
      goto failure;
362 by Teddy Hogeborn
* plugin-runner.c (getplugin, add_environment, main): Handle EINTR
189
    }
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
190
    ret = sigaction(SIGINT, NULL, &old_action);
191
    if(ret == -1){
192
      perror("sigaction");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
193
      goto failure;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
194
    }
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
195
    if(old_action.sa_handler != SIG_IGN){
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
196
      ret = sigaction(SIGINT, &new_action, NULL);
197
      if(ret == -1){
198
	perror("sigaction");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
199
	goto failure;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
200
      }
201
    }
202
    ret = sigaction(SIGHUP, NULL, &old_action);
203
    if(ret == -1){
204
      perror("sigaction");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
205
      goto failure;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
206
    }
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
207
    if(old_action.sa_handler != SIG_IGN){
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
208
      ret = sigaction(SIGHUP, &new_action, NULL);
209
      if(ret == -1){
210
	perror("sigaction");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
211
	goto failure;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
212
      }
213
    }
214
    ret = sigaction(SIGTERM, NULL, &old_action);
215
    if(ret == -1){
216
      perror("sigaction");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
217
      goto failure;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
218
    }
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
219
    if(old_action.sa_handler != SIG_IGN){
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
220
      ret = sigaction(SIGTERM, &new_action, NULL);
221
      if(ret == -1){
222
	perror("sigaction");
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
223
	goto failure;
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
224
      }
225
    }
226
  }
227
  
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
228
  if(interrupted_by_signal){
229
    goto failure;
230
  }
231
  
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
232
  /* Fork off the splashy command to prompt for password */
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
233
  splashy_command_pid = fork();
234
  if(splashy_command_pid != 0 and interrupted_by_signal){
235
    goto failure;
236
  }
237
  if(splashy_command_pid == -1){
238
    perror("fork");
239
    goto failure;
240
  }
241
  /* Child */
242
  if(splashy_command_pid == 0){
243
    if(not interrupted_by_signal){
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
244
      const char splashy_command[] = "/sbin/splashy_update";
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
245
      execl(splashy_command, splashy_command, prompt, (char *)NULL);
246
      perror("execl");
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
247
    }
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
248
    free(prompt);
249
    _exit(EXIT_FAILURE);
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
250
  }
251
  
252
  /* Parent */
253
  free(prompt);
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
254
  prompt = NULL;
255
  
256
  if(interrupted_by_signal){
257
    goto failure;
258
  }
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
259
  
260
  /* Wait for command to complete */
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
261
  {
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
262
    int status;
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
263
    do {
264
      ret = waitpid(splashy_command_pid, &status, 0);
265
    } while(ret == -1 and errno == EINTR
266
	    and not interrupted_by_signal);
267
    if(interrupted_by_signal){
268
      goto failure;
269
    }
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
270
    if(ret == -1){
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
271
      perror("waitpid");
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
272
      if(errno == ECHILD){
273
	splashy_command_pid = 0;
274
      }
275
    } else {
276
      /* The child process has exited */
277
      splashy_command_pid = 0;
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
278
      if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
279
	return EXIT_SUCCESS;
280
      }
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
281
    }
282
  }
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
283
  
284
 failure:
285
  
286
  free(prompt);
287
  
288
  if(proc_dir != NULL){
289
    TEMP_FAILURE_RETRY(closedir(proc_dir));
290
  }
291
  
292
  if(splashy_command_pid != 0){
293
    TEMP_FAILURE_RETRY(kill(splashy_command_pid, SIGTERM));
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
294
    
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
295
    TEMP_FAILURE_RETRY(kill(splashy_pid, SIGTERM));
296
    sleep(2);
297
    while(TEMP_FAILURE_RETRY(kill(splashy_pid, 0)) == 0){
298
      TEMP_FAILURE_RETRY(kill(splashy_pid, SIGKILL));
299
      sleep(1);
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
300
    }
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
301
    pid_t new_splashy_pid = TEMP_FAILURE_RETRY(fork());
302
    if(new_splashy_pid == 0){
303
      /* Child; will become new splashy process */
304
      
305
      /* Make the effective user ID (root) the only user ID instead of
306
	 the real user ID (_mandos) */
307
      ret = setuid(geteuid());
308
      if(ret == -1){
309
	perror("setuid");
310
      }
311
      
312
      setsid();
313
      ret = chdir("/");
314
      if(ret == -1){
315
	perror("chdir");
316
      }
317
/*       if(fork() != 0){ */
318
/* 	_exit(EXIT_SUCCESS); */
319
/*       } */
320
      ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace stdout */
321
      if(ret == -1){
322
	perror("dup2");
323
	_exit(EXIT_FAILURE);
324
      }
223 by Teddy Hogeborn
* .bzrignore (plugins.d/askpass-fifo): Added.
325
    
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
326
      execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
327
      perror("execl");
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
328
      _exit(EXIT_FAILURE);
329
    }
363 by Teddy Hogeborn
* plugin-runner.c: Minor stylistic changes.
330
  }
331
  
332
  if(interrupted_by_signal){
333
    struct sigaction signal_action;
334
    sigemptyset(&signal_action.sa_mask);
335
    signal_action.sa_handler = SIG_DFL;
336
    ret = TEMP_FAILURE_RETRY(sigaction(signal_received,
337
				       &signal_action, NULL));
338
    if(ret == -1){
339
      perror("sigaction");
340
    }
341
    do {
342
      ret = raise(signal_received);
343
    } while(ret != 0 and errno == EINTR);
344
    if(ret != 0){
345
      perror("raise");
346
      abort();
347
    }
348
    TEMP_FAILURE_RETRY(pause());
205 by Teddy Hogeborn
* Makefile (PLUGINS, uninstall-client,
349
  }
350
  
351
  return EXIT_FAILURE;
352
}