/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/splashy.c

  • Committer: Teddy Hogeborn
  • Date: 2008-07-20 06:33:48 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080720063348-jscgy5p0itrgvlo8
* mandos-clients.conf ([foo]): Uncommented.
  ([foo]/secret): New.
  ([foo]/secfile): Commented out.
  ([foo]/checker): Changed to "fping -q -- %%(fqdn)s".
  ([foo]/timeout): New.

* server.py: New modeline for Python and Emacs.  Set a logging format.
  (Client.__init__): Bug fix: Choose either the value from the options
                     object or pass the argument through string_to_delta
                     for both "timeout" and "interval".
  (Client.checker_callback): Bug fix: Do not log spurious "Checker for
                             <foo> failed" messages.
  (Client.start_checker): Moved "Starting checker" log message down to
                          just before actually starting the subprocess.
                          Do not redirect the subprocesses' stdout to a
                          pipe.
  (peer_certificate, fingerprint): Added docstrings.
  (entry_group_state_changed): Call "killme()" instead of
                               "main_loop.quit()".
  (daemon, killme): New functions.
  (exitstatus, main_loop_started): New global variables.
  (__main__): Removed the "--cert", "--key", "--ca", and "--crl"
              options.  Removed the sleep command from the default
              checker.  Add a console logger in debug mode.  Call
              "killme()" instead of "main_loop.quit()" when there are no
              more clients.  Call "daemon()" if not in debug mode.
              Register "cleanup()" to run at exit.  Ignore some
              signals.  Catch DBusException to detect another running
              server and exit cleanly.  Exit with "exitstatus".
  (cleanup): New function.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#define _GNU_SOURCE             /* asprintf() */
2
 
#include <signal.h>             /* sig_atomic_t, struct sigaction,
3
 
                                   sigemptyset(), sigaddset(), SIGINT,
4
 
                                   SIGHUP, SIGTERM, sigaction,
5
 
                                   SIG_IGN, kill(), SIGKILL */
6
 
#include <stddef.h>             /* NULL */
7
 
#include <stdlib.h>             /* getenv() */
8
 
#include <stdio.h>              /* asprintf(), perror() */
9
 
#include <stdlib.h>             /* EXIT_FAILURE, free(), strtoul(),
10
 
                                   EXIT_SUCCESS */
11
 
#include <sys/types.h>          /* pid_t, DIR, struct dirent,
12
 
                                   ssize_t */
13
 
#include <dirent.h>             /* opendir(), readdir(), closedir() */
14
 
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
15
 
#include <iso646.h>             /* not, or, and */
16
 
#include <unistd.h>             /* readlink(), fork(), execl(),
17
 
                                   sleep(), dup2() STDERR_FILENO,
18
 
                                   STDOUT_FILENO, _exit() */
19
 
#include <string.h>             /* memcmp() */
20
 
#include <errno.h>              /* errno */
21
 
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
22
 
                                   WEXITSTATUS() */
23
 
 
24
 
sig_atomic_t interrupted_by_signal = 0;
25
 
 
26
 
static void termination_handler(__attribute__((unused))int signum){
27
 
  interrupted_by_signal = 1;
28
 
}
29
 
 
30
 
int main(__attribute__((unused))int argc,
31
 
         __attribute__((unused))char **argv){
32
 
  int ret = 0;
33
 
  
34
 
  /* Create prompt string */
35
 
  char *prompt = NULL;
36
 
  {
37
 
    const char *const cryptsource = getenv("cryptsource");
38
 
    const char *const crypttarget = getenv("crypttarget");
39
 
    const char *const prompt_start = "getpass "
40
 
      "Enter passphrase to unlock the disk";
41
 
    
42
 
    if(cryptsource == NULL){
43
 
      if(crypttarget == NULL){
44
 
        ret = asprintf(&prompt, "%s: ", prompt_start);
45
 
      } else {
46
 
        ret = asprintf(&prompt, "%s (%s): ", prompt_start,
47
 
                       crypttarget);
48
 
      }
49
 
    } else {
50
 
      if(crypttarget == NULL){
51
 
        ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
52
 
      } else {
53
 
        ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
54
 
                       cryptsource, crypttarget);
55
 
      }
56
 
    }
57
 
    if(ret == -1){
58
 
      return EXIT_FAILURE;
59
 
    }
60
 
  }
61
 
  
62
 
  /* Find splashy process */
63
 
  pid_t splashy_pid = 0;
64
 
  {
65
 
    const char splashy_name[] = "/sbin/splashy";
66
 
    DIR *proc_dir = opendir("/proc");
67
 
    if(proc_dir == NULL){
68
 
      free(prompt);
69
 
      perror("opendir");
70
 
      return EXIT_FAILURE;
71
 
    }
72
 
    for(struct dirent *proc_ent = readdir(proc_dir);
73
 
        proc_ent != NULL;
74
 
        proc_ent = readdir(proc_dir)){
75
 
      pid_t pid = (pid_t) strtoul(proc_ent->d_name, NULL, 10);
76
 
      if(pid == 0){
77
 
        /* Not a process */
78
 
        continue;
79
 
      }
80
 
      /* Find the executable name by doing readlink() on the
81
 
         /proc/<pid>/exe link */
82
 
      char exe_target[sizeof(splashy_name)];
83
 
      ssize_t sret;
84
 
      {
85
 
        char *exe_link;
86
 
        ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
87
 
        if(ret == -1){
88
 
          perror("asprintf");
89
 
          free(prompt);
90
 
          closedir(proc_dir);
91
 
          return EXIT_FAILURE;
92
 
        }
93
 
        
94
 
        /* Check that it refers to a symlink owned by root:root */
95
 
        struct stat exe_stat;
96
 
        ret = lstat(exe_link, &exe_stat);
97
 
        if(ret == -1){
98
 
          perror("lstat");
99
 
          free(exe_link);
100
 
          free(prompt);
101
 
          closedir(proc_dir);
102
 
          return EXIT_FAILURE;
103
 
        }
104
 
        if(not S_ISLNK(exe_stat.st_mode)
105
 
           or exe_stat.st_uid != 0
106
 
           or exe_stat.st_gid != 0){
107
 
          free(exe_link);
108
 
          continue;
109
 
        }
110
 
        
111
 
        sret = readlink(exe_link, exe_target, sizeof(exe_target));
112
 
        free(exe_link);
113
 
      }
114
 
      if((sret == ((ssize_t)sizeof(exe_target)-1))
115
 
         and (memcmp(splashy_name, exe_target,
116
 
                     sizeof(exe_target)-1) == 0)){
117
 
        splashy_pid = pid;
118
 
        break;
119
 
      }
120
 
    }
121
 
    closedir(proc_dir);
122
 
  }
123
 
  if(splashy_pid == 0){
124
 
    free(prompt);
125
 
    return EXIT_FAILURE;
126
 
  }
127
 
  
128
 
  /* Set up the signal handler */
129
 
  {
130
 
    struct sigaction old_action,
131
 
      new_action = { .sa_handler = termination_handler,
132
 
                     .sa_flags = 0 };
133
 
    sigemptyset(&new_action.sa_mask);
134
 
    sigaddset(&new_action.sa_mask, SIGINT);
135
 
    sigaddset(&new_action.sa_mask, SIGHUP);
136
 
    sigaddset(&new_action.sa_mask, SIGTERM);
137
 
    ret = sigaction(SIGINT, NULL, &old_action);
138
 
    if(ret == -1){
139
 
      perror("sigaction");
140
 
      free(prompt);
141
 
      return EXIT_FAILURE;
142
 
    }
143
 
    if(old_action.sa_handler != SIG_IGN){
144
 
      ret = sigaction(SIGINT, &new_action, NULL);
145
 
      if(ret == -1){
146
 
        perror("sigaction");
147
 
        free(prompt);
148
 
        return EXIT_FAILURE;
149
 
      }
150
 
    }
151
 
    ret = sigaction(SIGHUP, NULL, &old_action);
152
 
    if(ret == -1){
153
 
      perror("sigaction");
154
 
      free(prompt);
155
 
      return EXIT_FAILURE;
156
 
    }
157
 
    if(old_action.sa_handler != SIG_IGN){
158
 
      ret = sigaction(SIGHUP, &new_action, NULL);
159
 
      if(ret == -1){
160
 
        perror("sigaction");
161
 
        free(prompt);
162
 
        return EXIT_FAILURE;
163
 
      }
164
 
    }
165
 
    ret = sigaction(SIGTERM, NULL, &old_action);
166
 
    if(ret == -1){
167
 
      perror("sigaction");
168
 
      free(prompt);
169
 
      return EXIT_FAILURE;
170
 
    }
171
 
    if(old_action.sa_handler != SIG_IGN){
172
 
      ret = sigaction(SIGTERM, &new_action, NULL);
173
 
      if(ret == -1){
174
 
        perror("sigaction");
175
 
        free(prompt);
176
 
        return EXIT_FAILURE;
177
 
      }
178
 
    }
179
 
  }
180
 
  
181
 
  /* Fork off the splashy command to prompt for password */
182
 
  pid_t splashy_command_pid = 0;
183
 
  if(not interrupted_by_signal){
184
 
    splashy_command_pid = fork();
185
 
    if(splashy_command_pid == -1){
186
 
      if(not interrupted_by_signal){
187
 
        perror("fork");
188
 
      }
189
 
      return EXIT_FAILURE;
190
 
    }
191
 
    /* Child */
192
 
    if(splashy_command_pid == 0){
193
 
      const char splashy_command[] = "/sbin/splashy_update";
194
 
      ret = execl(splashy_command, splashy_command, prompt,
195
 
                  (char *)NULL);
196
 
      if(not interrupted_by_signal){
197
 
        perror("execl");
198
 
      }
199
 
      free(prompt);
200
 
      _exit(EXIT_FAILURE);
201
 
    }
202
 
  }
203
 
  
204
 
  /* Parent */
205
 
  free(prompt);
206
 
  
207
 
  /* Wait for command to complete */
208
 
  if(not interrupted_by_signal and splashy_command_pid != 0){
209
 
    int status;
210
 
    ret = waitpid(splashy_command_pid, &status, 0);
211
 
    if(ret == -1){
212
 
      if(errno != EINTR){
213
 
        perror("waitpid");
214
 
      }
215
 
      if(errno == ECHILD){
216
 
        splashy_command_pid = 0;
217
 
      }
218
 
    } else {
219
 
      /* The child process has exited */
220
 
      splashy_command_pid = 0;
221
 
      if(not interrupted_by_signal and WIFEXITED(status)
222
 
         and WEXITSTATUS(status)==0){
223
 
        return EXIT_SUCCESS;
224
 
      }
225
 
    }
226
 
  }
227
 
  kill(splashy_pid, SIGTERM);
228
 
  if(interrupted_by_signal and splashy_command_pid != 0){
229
 
    kill(splashy_command_pid, SIGTERM);
230
 
  }
231
 
  sleep(2);
232
 
  while(kill(splashy_pid, 0) == 0){
233
 
    kill(splashy_pid, SIGKILL);
234
 
    sleep(1);
235
 
  }
236
 
  pid_t new_splashy_pid = fork();
237
 
  if(new_splashy_pid == 0){
238
 
    /* Child; will become new splashy process */
239
 
    
240
 
    /* Make the effective user ID (root) the only user ID instead of
241
 
       the real user ID (mandos) */
242
 
    ret = setuid(geteuid());
243
 
    if(ret == -1){
244
 
      perror("setuid");
245
 
    }
246
 
    
247
 
    setsid();
248
 
    ret = chdir("/");
249
 
/*     if(fork() != 0){ */
250
 
/*       _exit(EXIT_SUCCESS); */
251
 
/*     } */
252
 
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
253
 
    if(ret == -1){
254
 
      perror("dup2");
255
 
      _exit(EXIT_FAILURE);
256
 
    }
257
 
    
258
 
    execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
259
 
    if(not interrupted_by_signal){
260
 
      perror("execl");
261
 
    }
262
 
    _exit(EXIT_FAILURE);
263
 
  }
264
 
  
265
 
  return EXIT_FAILURE;
266
 
}