/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugins.d/usplash.c

  • Committer: Teddy Hogeborn
  • Date: 2008-12-10 01:26:02 UTC
  • mfrom: (237.1.2 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20081210012602-vhz3h75xkj24t340
First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Usplash - Read a password from usplash and output it
 
3
 * Passprompt - Read a password from usplash and output it
4
4
 * 
5
 
 * Copyright © 2008-2011 Teddy Hogeborn
6
 
 * Copyright © 2008-2011 Björn Påhlsson
 
5
 * Copyright © 2008 Teddy Hogeborn
 
6
 * Copyright © 2008 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
19
19
 * along with this program.  If not, see
20
20
 * <http://www.gnu.org/licenses/>.
21
21
 * 
22
 
 * Contact the authors at <mandos@recompile.se>.
 
22
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
23
 * <https://www.fukt.bsnet.se/~teddy/>.
23
24
 */
24
25
 
25
 
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
 
26
#define _GNU_SOURCE             /* asprintf() */
26
27
#include <signal.h>             /* sig_atomic_t, struct sigaction,
27
28
                                   sigemptyset(), sigaddset(), SIGINT,
28
29
                                   SIGHUP, SIGTERM, sigaction(),
31
32
#include <fcntl.h>              /* open(), O_WRONLY, O_RDONLY */
32
33
#include <iso646.h>             /* and, or, not*/
33
34
#include <errno.h>              /* errno, EINTR */
34
 
#include <error.h>
35
35
#include <sys/types.h>          /* size_t, ssize_t, pid_t, DIR, struct
36
36
                                   dirent */
37
37
#include <stddef.h>             /* NULL */
38
 
#include <string.h>             /* strlen(), memcmp(), strerror() */
39
 
#include <stdio.h>              /* asprintf(), vasprintf(), vprintf(),
40
 
                                   fprintf() */
 
38
#include <string.h>             /* strlen(), memcmp() */
 
39
#include <stdio.h>              /* asprintf(), perror() */
41
40
#include <unistd.h>             /* close(), write(), readlink(),
42
41
                                   read(), STDOUT_FILENO, sleep(),
43
42
                                   fork(), setuid(), geteuid(),
44
43
                                   setsid(), chdir(), dup2(),
45
44
                                   STDERR_FILENO, execv() */
46
 
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
47
 
                                   EXIT_SUCCESS, malloc(), _exit(),
48
 
                                   getenv() */
 
45
#include <stdlib.h>             /* free(), EXIT_FAILURE, strtoul(),
 
46
                                   realloc(), EXIT_SUCCESS, malloc(),
 
47
                                   _exit() */
 
48
#include <stdlib.h>             /* getenv() */
49
49
#include <dirent.h>             /* opendir(), readdir(), closedir() */
50
 
#include <inttypes.h>           /* intmax_t, strtoimax() */
51
50
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
52
 
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
53
 
#include <argz.h>               /* argz_count(), argz_extract() */
54
 
#include <stdarg.h>             /* va_list, va_start(), ... */
55
51
 
56
52
sig_atomic_t interrupted_by_signal = 0;
57
 
int signal_received;
58
 
const char usplash_name[] = "/sbin/usplash";
59
 
 
60
 
/* Function to use when printing errors */
61
 
void error_plus(int status, int errnum, const char *formatstring,
62
 
                ...){
63
 
  va_list ap;
64
 
  char *text;
65
 
  int ret;
66
 
  
67
 
  va_start(ap, formatstring);
68
 
  ret = vasprintf(&text, formatstring, ap);
69
 
  if (ret == -1){
70
 
    fprintf(stderr, "Mandos plugin %s: ",
71
 
            program_invocation_short_name);
72
 
    vfprintf(stderr, formatstring, ap);
73
 
    fprintf(stderr, ": ");
74
 
    fprintf(stderr, "%s\n", strerror(errnum));
75
 
    error(status, errno, "vasprintf while printing error");
76
 
    return;
77
 
  }
78
 
  fprintf(stderr, "Mandos plugin ");
79
 
  error(status, errnum, "%s", text);
80
 
  free(text);
81
 
}
82
 
 
83
 
static void termination_handler(int signum){
84
 
  if(interrupted_by_signal){
85
 
    return;
86
 
  }
 
53
 
 
54
static void termination_handler(__attribute__((unused))int signum){
87
55
  interrupted_by_signal = 1;
88
 
  signal_received = signum;
89
56
}
90
57
 
91
 
static bool usplash_write(int *fifo_fd_r,
92
 
                          const char *cmd, const char *arg){
 
58
static bool usplash_write(const char *cmd, const char *arg){
93
59
  /* 
94
 
   * usplash_write(&fd, "TIMEOUT", "15") will write "TIMEOUT 15\0"
95
 
   * usplash_write(&fd, "PULSATE", NULL) will write "PULSATE\0"
 
60
   * usplash_write("TIMEOUT", "15") will write "TIMEOUT 15\0"
 
61
   * usplash_write("PULSATE", NULL) will write "PULSATE\0"
96
62
   * SEE ALSO
97
63
   *         usplash_write(8)
98
64
   */
99
65
  int ret;
100
 
  if(*fifo_fd_r == -1){
101
 
    ret = open("/dev/.initramfs/usplash_fifo", O_WRONLY);
102
 
    if(ret == -1){
 
66
  int fifo_fd;
 
67
  do{
 
68
    fifo_fd = open("/dev/.initramfs/usplash_fifo", O_WRONLY);
 
69
    if(fifo_fd == -1 and (errno != EINTR or interrupted_by_signal)){
103
70
      return false;
104
71
    }
105
 
    *fifo_fd_r = ret;
106
 
  }
 
72
  }while(fifo_fd == -1);
107
73
  
108
74
  const char *cmd_line;
109
75
  size_t cmd_line_len;
110
76
  char *cmd_line_alloc = NULL;
111
77
  if(arg == NULL){
112
78
    cmd_line = cmd;
113
 
    cmd_line_len = strlen(cmd) + 1;
114
 
  } else {
115
 
    do {
 
79
    cmd_line_len = strlen(cmd);
 
80
  }else{
 
81
    do{
116
82
      ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg);
117
 
      if(ret == -1){
 
83
      if(ret == -1 and (errno != EINTR or interrupted_by_signal)){
118
84
        int e = errno;
119
 
        TEMP_FAILURE_RETRY(close(*fifo_fd_r));
 
85
        close(fifo_fd);
120
86
        errno = e;
121
87
        return false;
122
88
      }
123
 
    } while(ret == -1);
 
89
    }while(ret == -1);
124
90
    cmd_line = cmd_line_alloc;
125
91
    cmd_line_len = (size_t)ret + 1;
126
92
  }
127
93
  
128
94
  size_t written = 0;
129
 
  ssize_t sret = 0;
130
 
  while(written < cmd_line_len){
131
 
    sret = write(*fifo_fd_r, cmd_line + written,
132
 
                 cmd_line_len - written);
133
 
    if(sret == -1){
134
 
      int e = errno;
135
 
      TEMP_FAILURE_RETRY(close(*fifo_fd_r));
136
 
      free(cmd_line_alloc);
137
 
      errno = e;
138
 
      return false;
 
95
  while(not interrupted_by_signal and written < cmd_line_len){
 
96
    ret = write(fifo_fd, cmd_line + written,
 
97
                cmd_line_len - written);
 
98
    if(ret == -1){
 
99
      if(errno != EINTR or interrupted_by_signal){
 
100
        int e = errno;
 
101
        close(fifo_fd);
 
102
        free(cmd_line_alloc);
 
103
        errno = e;
 
104
        return false;
 
105
      } else {
 
106
        continue;
 
107
      }
139
108
    }
140
 
    written += (size_t)sret;
 
109
    written += (size_t)ret;
141
110
  }
142
111
  free(cmd_line_alloc);
143
 
  
 
112
  do{
 
113
    ret = close(fifo_fd);
 
114
    if(ret == -1 and (errno != EINTR or interrupted_by_signal)){
 
115
      return false;
 
116
    }
 
117
  }while(ret == -1);
 
118
  if(interrupted_by_signal){
 
119
    return false;
 
120
  }
144
121
  return true;
145
122
}
146
123
 
147
 
/* Create prompt string */
148
 
char *makeprompt(void){
149
 
  int ret = 0;
150
 
  char *prompt;
151
 
  const char *const cryptsource = getenv("cryptsource");
152
 
  const char *const crypttarget = getenv("crypttarget");
153
 
  const char prompt_start[] = "Enter passphrase to unlock the disk";
154
 
  
155
 
  if(cryptsource == NULL){
156
 
    if(crypttarget == NULL){
157
 
      ret = asprintf(&prompt, "%s: ", prompt_start);
158
 
    } else {
159
 
      ret = asprintf(&prompt, "%s (%s): ", prompt_start,
160
 
                     crypttarget);
161
 
    }
162
 
  } else {
163
 
    if(crypttarget == NULL){
164
 
      ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
165
 
    } else {
166
 
      ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
167
 
                     cryptsource, crypttarget);
168
 
    }
169
 
  }
170
 
  if(ret == -1){
171
 
    return NULL;
172
 
  }
173
 
  return prompt;
174
 
}
175
 
 
176
 
pid_t find_usplash(char **cmdline_r, size_t *cmdline_len_r){
177
 
  int ret = 0;
178
 
  ssize_t sret = 0;
 
124
int main(__attribute__((unused))int argc,
 
125
         __attribute__((unused))char **argv){
 
126
  int ret = 0;
 
127
  ssize_t sret;
 
128
  bool an_error_occured = false;
 
129
  
 
130
  /* Create prompt string */
 
131
  char *prompt = NULL;
 
132
  {
 
133
    const char *const cryptsource = getenv("cryptsource");
 
134
    const char *const crypttarget = getenv("crypttarget");
 
135
    const char prompt_start[] = "Enter passphrase to unlock the disk";
 
136
    
 
137
    if(cryptsource == NULL){
 
138
      if(crypttarget == NULL){
 
139
        ret = asprintf(&prompt, "%s: ", prompt_start);
 
140
      } else {
 
141
        ret = asprintf(&prompt, "%s (%s): ", prompt_start,
 
142
                       crypttarget);
 
143
      }
 
144
    } else {
 
145
      if(crypttarget == NULL){
 
146
        ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
 
147
      } else {
 
148
        ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
 
149
                       cryptsource, crypttarget);
 
150
      }
 
151
    }
 
152
    if(ret == -1){
 
153
      return EXIT_FAILURE;
 
154
    }
 
155
  }
 
156
  
 
157
  /* Find usplash process */
 
158
  pid_t usplash_pid = 0;
179
159
  char *cmdline = NULL;
180
160
  size_t cmdline_len = 0;
181
 
  DIR *proc_dir = opendir("/proc");
182
 
  if(proc_dir == NULL){
183
 
    error_plus(0, errno, "opendir");
184
 
    return -1;
185
 
  }
186
 
  errno = 0;
187
 
  for(struct dirent *proc_ent = readdir(proc_dir);
188
 
      proc_ent != NULL;
189
 
      proc_ent = readdir(proc_dir)){
190
 
    pid_t pid;
191
 
    {
192
 
      intmax_t tmpmax;
193
 
      char *tmp;
194
 
      tmpmax = strtoimax(proc_ent->d_name, &tmp, 10);
195
 
      if(errno != 0 or tmp == proc_ent->d_name or *tmp != '\0'
196
 
         or tmpmax != (pid_t)tmpmax){
 
161
  const char usplash_name[] = "/sbin/usplash";
 
162
  {
 
163
    DIR *proc_dir = opendir("/proc");
 
164
    if(proc_dir == NULL){
 
165
      free(prompt);
 
166
      perror("opendir");
 
167
      return EXIT_FAILURE;
 
168
    }
 
169
    for(struct dirent *proc_ent = readdir(proc_dir);
 
170
        proc_ent != NULL;
 
171
        proc_ent = readdir(proc_dir)){
 
172
      pid_t pid = (pid_t) strtoul(proc_ent->d_name, NULL, 10);
 
173
      if(pid == 0){
197
174
        /* Not a process */
198
 
        errno = 0;
199
 
        continue;
200
 
      }
201
 
      pid = (pid_t)tmpmax;
202
 
    }
203
 
    /* Find the executable name by doing readlink() on the
204
 
       /proc/<pid>/exe link */
205
 
    char exe_target[sizeof(usplash_name)];
206
 
    {
207
 
      /* create file name string */
208
 
      char *exe_link;
209
 
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
210
 
      if(ret == -1){
211
 
        error_plus(0, errno, "asprintf");
212
 
        goto fail_find_usplash;
213
 
      }
214
 
      
215
 
      /* Check that it refers to a symlink owned by root:root */
216
 
      struct stat exe_stat;
217
 
      ret = lstat(exe_link, &exe_stat);
218
 
      if(ret == -1){
219
 
        if(errno == ENOENT){
220
 
          free(exe_link);
221
 
          continue;
222
 
        }
223
 
        error_plus(0, errno, "lstat");
224
 
        free(exe_link);
225
 
        goto fail_find_usplash;
226
 
      }
227
 
      if(not S_ISLNK(exe_stat.st_mode)
228
 
         or exe_stat.st_uid != 0
229
 
         or exe_stat.st_gid != 0){
230
 
        free(exe_link);
231
 
        continue;
232
 
      }
233
 
        
234
 
      sret = readlink(exe_link, exe_target, sizeof(exe_target));
235
 
      free(exe_link);
236
 
    }
237
 
    /* Compare executable name */
238
 
    if((sret != ((ssize_t)sizeof(exe_target)-1))
239
 
       or (memcmp(usplash_name, exe_target,
240
 
                  sizeof(exe_target)-1) != 0)){
241
 
      /* Not it */
242
 
      continue;
243
 
    }
244
 
    /* Found usplash */
245
 
    /* Read and save the command line of usplash in "cmdline" */
246
 
    {
247
 
      /* Open /proc/<pid>/cmdline  */
248
 
      int cl_fd;
 
175
        continue;
 
176
      }
 
177
      /* Find the executable name by doing readlink() on the
 
178
         /proc/<pid>/exe link */
 
179
      char exe_target[sizeof(usplash_name)];
249
180
      {
250
 
        char *cmdline_filename;
251
 
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
252
 
                       proc_ent->d_name);
253
 
        if(ret == -1){
254
 
          error_plus(0, errno, "asprintf");
255
 
          goto fail_find_usplash;
256
 
        }
257
 
        cl_fd = open(cmdline_filename, O_RDONLY);
258
 
        free(cmdline_filename);
259
 
        if(cl_fd == -1){
260
 
          error_plus(0, errno, "open");
261
 
          goto fail_find_usplash;
 
181
        /* create file name string */
 
182
        char *exe_link;
 
183
        ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
 
184
        if(ret == -1){
 
185
          perror("asprintf");
 
186
          free(prompt);
 
187
          closedir(proc_dir);
 
188
          return EXIT_FAILURE;
 
189
        }
 
190
        
 
191
        /* Check that it refers to a symlink owned by root:root */
 
192
        struct stat exe_stat;
 
193
        ret = lstat(exe_link, &exe_stat);
 
194
        if(ret == -1){
 
195
          perror("lstat");
 
196
          free(exe_link);
 
197
          free(prompt);
 
198
          closedir(proc_dir);
 
199
          return EXIT_FAILURE;
 
200
        }
 
201
        if(not S_ISLNK(exe_stat.st_mode)
 
202
           or exe_stat.st_uid != 0
 
203
           or exe_stat.st_gid != 0){
 
204
          free(exe_link);
 
205
          continue;
 
206
        }
 
207
        
 
208
        sret = readlink(exe_link, exe_target, sizeof(exe_target));
 
209
        free(exe_link);
 
210
        if(sret == -1){
 
211
          continue;
262
212
        }
263
213
      }
264
 
      size_t cmdline_allocated = 0;
265
 
      char *tmp;
266
 
      const size_t blocksize = 1024;
267
 
      do {
268
 
        /* Allocate more space? */
269
 
        if(cmdline_len + blocksize > cmdline_allocated){
270
 
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
271
 
          if(tmp == NULL){
272
 
            error_plus(0, errno, "realloc");
273
 
            close(cl_fd);
274
 
            goto fail_find_usplash;
 
214
      if((sret == ((ssize_t)sizeof(exe_target)-1))
 
215
         and (memcmp(usplash_name, exe_target,
 
216
                     sizeof(exe_target)-1) == 0)){
 
217
        usplash_pid = pid;
 
218
        /* Read and save the command line of usplash in "cmdline" */
 
219
        {
 
220
          /* Open /proc/<pid>/cmdline  */
 
221
          int cl_fd;
 
222
          {
 
223
            char *cmdline_filename;
 
224
            ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
 
225
                           proc_ent->d_name);
 
226
            if(ret == -1){
 
227
              perror("asprintf");
 
228
              free(prompt);
 
229
              closedir(proc_dir);
 
230
              return EXIT_FAILURE;
 
231
            }
 
232
            cl_fd = open(cmdline_filename, O_RDONLY);
 
233
            if(cl_fd == -1){
 
234
              perror("open");
 
235
              free(cmdline_filename);
 
236
              free(prompt);
 
237
              closedir(proc_dir);
 
238
              return EXIT_FAILURE;
 
239
            }
 
240
            free(cmdline_filename);
275
241
          }
276
 
          cmdline = tmp;
277
 
          cmdline_allocated += blocksize;
278
 
        }
279
 
        /* Read data */
280
 
        sret = read(cl_fd, cmdline + cmdline_len,
281
 
                    cmdline_allocated - cmdline_len);
282
 
        if(sret == -1){
283
 
          error_plus(0, errno, "read");
 
242
          size_t cmdline_allocated = 0;
 
243
          char *tmp;
 
244
          const size_t blocksize = 1024;
 
245
          do{
 
246
            if(cmdline_len + blocksize > cmdline_allocated){
 
247
              tmp = realloc(cmdline, cmdline_allocated + blocksize);
 
248
              if(tmp == NULL){
 
249
                perror("realloc");
 
250
                free(cmdline);
 
251
                free(prompt);
 
252
                closedir(proc_dir);
 
253
                return EXIT_FAILURE;
 
254
              }
 
255
              cmdline = tmp;
 
256
              cmdline_allocated += blocksize;
 
257
            }
 
258
            sret = read(cl_fd, cmdline + cmdline_len,
 
259
                        cmdline_allocated - cmdline_len);
 
260
            if(sret == -1){
 
261
              perror("read");
 
262
              free(cmdline);
 
263
              free(prompt);
 
264
              closedir(proc_dir);
 
265
              return EXIT_FAILURE;
 
266
            }
 
267
            cmdline_len += (size_t)sret;
 
268
          } while(sret != 0);
284
269
          close(cl_fd);
285
 
          goto fail_find_usplash;
286
270
        }
287
 
        cmdline_len += (size_t)sret;
288
 
      } while(sret != 0);
289
 
      ret = close(cl_fd);
290
 
      if(ret == -1){
291
 
        error_plus(0, errno, "close");
292
 
        goto fail_find_usplash;
 
271
        break;
293
272
      }
294
273
    }
295
 
    /* Close directory */
296
 
    ret = closedir(proc_dir);
297
 
    if(ret == -1){
298
 
      error_plus(0, errno, "closedir");
299
 
      goto fail_find_usplash;
300
 
    }
301
 
    /* Success */
302
 
    *cmdline_r = cmdline;
303
 
    *cmdline_len_r = cmdline_len;
304
 
    return pid;
305
 
  }
306
 
  
307
 
 fail_find_usplash:
308
 
  
309
 
  free(cmdline);
310
 
  if(proc_dir != NULL){
311
 
    int e = errno;
312
274
    closedir(proc_dir);
313
 
    errno = e;
314
 
  }
315
 
  return 0;
316
 
}
317
 
 
318
 
int main(__attribute__((unused))int argc,
319
 
         __attribute__((unused))char **argv){
320
 
  int ret = 0;
321
 
  ssize_t sret;
322
 
  int fifo_fd = -1;
323
 
  int outfifo_fd = -1;
324
 
  char *buf = NULL;
325
 
  size_t buf_len = 0;
326
 
  pid_t usplash_pid = -1;
327
 
  bool usplash_accessed = false;
328
 
  int status = EXIT_FAILURE;    /* Default failure exit status */
329
 
  
330
 
  char *prompt = makeprompt();
331
 
  if(prompt == NULL){
332
 
    status = EX_OSERR;
333
 
    goto failure;
334
 
  }
335
 
  
336
 
  /* Find usplash process */
337
 
  char *cmdline = NULL;
338
 
  size_t cmdline_len = 0;
339
 
  usplash_pid = find_usplash(&cmdline, &cmdline_len);
 
275
  }
340
276
  if(usplash_pid == 0){
341
 
    status = EX_UNAVAILABLE;
342
 
    goto failure;
 
277
    free(prompt);
 
278
    return EXIT_FAILURE;
343
279
  }
344
280
  
345
281
  /* Set up the signal handler */
348
284
      new_action = { .sa_handler = termination_handler,
349
285
                     .sa_flags = 0 };
350
286
    sigemptyset(&new_action.sa_mask);
351
 
    ret = sigaddset(&new_action.sa_mask, SIGINT);
352
 
    if(ret == -1){
353
 
      error_plus(0, errno, "sigaddset");
354
 
      status = EX_OSERR;
355
 
      goto failure;
356
 
    }
357
 
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
358
 
    if(ret == -1){
359
 
      error_plus(0, errno, "sigaddset");
360
 
      status = EX_OSERR;
361
 
      goto failure;
362
 
    }
363
 
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
364
 
    if(ret == -1){
365
 
      error_plus(0, errno, "sigaddset");
366
 
      status = EX_OSERR;
367
 
      goto failure;
368
 
    }
 
287
    sigaddset(&new_action.sa_mask, SIGINT);
 
288
    sigaddset(&new_action.sa_mask, SIGHUP);
 
289
    sigaddset(&new_action.sa_mask, SIGTERM);
369
290
    ret = sigaction(SIGINT, NULL, &old_action);
370
291
    if(ret == -1){
371
 
      if(errno != EINTR){
372
 
        error_plus(0, errno, "sigaction");
373
 
        status = EX_OSERR;
374
 
      }
375
 
      goto failure;
 
292
      perror("sigaction");
 
293
      free(prompt);
 
294
      return EXIT_FAILURE;
376
295
    }
377
296
    if(old_action.sa_handler != SIG_IGN){
378
297
      ret = sigaction(SIGINT, &new_action, NULL);
379
298
      if(ret == -1){
380
 
        if(errno != EINTR){
381
 
          error_plus(0, errno, "sigaction");
382
 
          status = EX_OSERR;
383
 
        }
384
 
        goto failure;
 
299
        perror("sigaction");
 
300
        free(prompt);
 
301
        return EXIT_FAILURE;
385
302
      }
386
303
    }
387
304
    ret = sigaction(SIGHUP, NULL, &old_action);
388
305
    if(ret == -1){
389
 
      if(errno != EINTR){
390
 
        error_plus(0, errno, "sigaction");
391
 
        status = EX_OSERR;
392
 
      }
393
 
      goto failure;
 
306
      perror("sigaction");
 
307
      free(prompt);
 
308
      return EXIT_FAILURE;
394
309
    }
395
310
    if(old_action.sa_handler != SIG_IGN){
396
311
      ret = sigaction(SIGHUP, &new_action, NULL);
397
312
      if(ret == -1){
398
 
        if(errno != EINTR){
399
 
          error_plus(0, errno, "sigaction");
400
 
          status = EX_OSERR;
401
 
        }
402
 
        goto failure;
 
313
        perror("sigaction");
 
314
        free(prompt);
 
315
        return EXIT_FAILURE;
403
316
      }
404
317
    }
405
318
    ret = sigaction(SIGTERM, NULL, &old_action);
406
319
    if(ret == -1){
407
 
      if(errno != EINTR){
408
 
        error_plus(0, errno, "sigaction");
409
 
        status = EX_OSERR;
410
 
      }
411
 
      goto failure;
 
320
      perror("sigaction");
 
321
      free(prompt);
 
322
      return EXIT_FAILURE;
412
323
    }
413
324
    if(old_action.sa_handler != SIG_IGN){
414
325
      ret = sigaction(SIGTERM, &new_action, NULL);
415
326
      if(ret == -1){
416
 
        if(errno != EINTR){
417
 
          error_plus(0, errno, "sigaction");
418
 
          status = EX_OSERR;
419
 
        }
420
 
        goto failure;
 
327
        perror("sigaction");
 
328
        free(prompt);
 
329
        return EXIT_FAILURE;
421
330
      }
422
331
    }
423
332
  }
424
333
  
425
 
  usplash_accessed = true;
426
334
  /* Write command to FIFO */
427
 
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
428
 
    if(errno != EINTR){
429
 
      error_plus(0, errno, "usplash_write");
430
 
      status = EX_OSERR;
431
 
    }
432
 
    goto failure;
433
 
  }
434
 
  
435
 
  if(interrupted_by_signal){
436
 
    goto failure;
437
 
  }
438
 
  
439
 
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
440
 
    if(errno != EINTR){
441
 
      error_plus(0, errno, "usplash_write");
442
 
      status = EX_OSERR;
443
 
    }
444
 
    goto failure;
445
 
  }
446
 
  
447
 
  if(interrupted_by_signal){
448
 
    goto failure;
449
 
  }
450
 
  
 
335
  if(not interrupted_by_signal){
 
336
    if(not usplash_write("TIMEOUT", "0")
 
337
       and (errno != EINTR)){
 
338
      perror("usplash_write");
 
339
      an_error_occured = true;
 
340
    }
 
341
  }
 
342
  if(not interrupted_by_signal and not an_error_occured){
 
343
    if(not usplash_write("INPUTQUIET", prompt)
 
344
       and (errno != EINTR)){
 
345
      perror("usplash_write");
 
346
      an_error_occured = true;
 
347
    }
 
348
  }
451
349
  free(prompt);
452
 
  prompt = NULL;
453
 
  
454
 
  /* Read reply from usplash */
455
 
  /* Open FIFO */
456
 
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
457
 
  if(outfifo_fd == -1){
458
 
    if(errno != EINTR){
459
 
      error_plus(0, errno, "open");
460
 
      status = EX_OSERR;
461
 
    }
462
 
    goto failure;
463
 
  }
464
 
  
465
 
  if(interrupted_by_signal){
466
 
    goto failure;
467
 
  }
468
 
  
469
 
  /* Read from FIFO */
470
 
  size_t buf_allocated = 0;
471
 
  const size_t blocksize = 1024;
472
 
  do {
473
 
    /* Allocate more space */
474
 
    if(buf_len + blocksize > buf_allocated){
475
 
      char *tmp = realloc(buf, buf_allocated + blocksize);
 
350
  
 
351
  /* This is not really a loop; while() is used to be able to "break"
 
352
     out of it; those breaks are marked "Big" */
 
353
  while(not interrupted_by_signal and not an_error_occured){
 
354
    char *buf = NULL;
 
355
    size_t buf_len = 0;
 
356
    
 
357
    /* Open FIFO */
 
358
    int fifo_fd;
 
359
    do{
 
360
      fifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
 
361
      if(fifo_fd == -1){
 
362
        if(errno != EINTR){
 
363
          perror("open");
 
364
          an_error_occured = true;
 
365
          break;
 
366
        }
 
367
        if(interrupted_by_signal){
 
368
          break;
 
369
        }
 
370
      }
 
371
    }while(fifo_fd == -1);
 
372
    if(interrupted_by_signal or an_error_occured){
 
373
      break;                    /* Big */
 
374
    }
 
375
    
 
376
    /* Read from FIFO */
 
377
    size_t buf_allocated = 0;
 
378
    const size_t blocksize = 1024;
 
379
    do{
 
380
      if(buf_len + blocksize > buf_allocated){
 
381
        char *tmp = realloc(buf, buf_allocated + blocksize);
 
382
        if(tmp == NULL){
 
383
          perror("realloc");
 
384
          an_error_occured = true;
 
385
          break;
 
386
        }
 
387
        buf = tmp;
 
388
        buf_allocated += blocksize;
 
389
      }
 
390
      do{
 
391
        sret = read(fifo_fd, buf + buf_len, buf_allocated - buf_len);
 
392
        if(sret == -1){
 
393
          if(errno != EINTR){
 
394
            perror("read");
 
395
            an_error_occured = true;
 
396
            break;
 
397
          }
 
398
          if(interrupted_by_signal){
 
399
            break;
 
400
          }
 
401
        }
 
402
      }while(sret == -1);
 
403
      if(interrupted_by_signal or an_error_occured){
 
404
        break;
 
405
      }
 
406
      
 
407
      buf_len += (size_t)sret;
 
408
    }while(sret != 0);
 
409
    close(fifo_fd);
 
410
    if(interrupted_by_signal or an_error_occured){
 
411
      break;                    /* Big */
 
412
    }
 
413
    
 
414
    if(not usplash_write("TIMEOUT", "15")
 
415
       and (errno != EINTR)){
 
416
        perror("usplash_write");
 
417
        an_error_occured = true;
 
418
    }
 
419
    if(interrupted_by_signal or an_error_occured){
 
420
      break;                    /* Big */
 
421
    }
 
422
    
 
423
    /* Print password to stdout */
 
424
    size_t written = 0;
 
425
    while(written < buf_len){
 
426
      do{
 
427
        sret = write(STDOUT_FILENO, buf + written, buf_len - written);
 
428
        if(sret == -1){
 
429
          if(errno != EINTR){
 
430
            perror("write");
 
431
            an_error_occured = true;
 
432
            break;
 
433
          }
 
434
          if(interrupted_by_signal){
 
435
            break;
 
436
          }
 
437
        }
 
438
      }while(sret == -1);
 
439
      if(interrupted_by_signal or an_error_occured){
 
440
        break;
 
441
      }
 
442
      written += (size_t)sret;
 
443
    }
 
444
    free(buf);
 
445
    if(not interrupted_by_signal and not an_error_occured){
 
446
      free(cmdline);
 
447
      return EXIT_SUCCESS;
 
448
    }
 
449
    break;                      /* Big */
 
450
  }                             /* end of non-loop while() */
 
451
  
 
452
  /* If we got here, an error or interrupt must have happened */
 
453
  
 
454
  /* Create argc and argv for new usplash*/
 
455
  int cmdline_argc = 0;
 
456
  char **cmdline_argv = malloc(sizeof(char *));
 
457
  {
 
458
    size_t position = 0;
 
459
    while(position < cmdline_len){
 
460
      char **tmp = realloc(cmdline_argv,
 
461
                           (sizeof(char *)
 
462
                            * (size_t)(cmdline_argc + 2)));
476
463
      if(tmp == NULL){
477
 
        if(errno != EINTR){
478
 
          error_plus(0, errno, "realloc");
479
 
          status = EX_OSERR;
480
 
        }
481
 
        goto failure;
482
 
      }
483
 
      buf = tmp;
484
 
      buf_allocated += blocksize;
485
 
    }
486
 
    sret = read(outfifo_fd, buf + buf_len,
487
 
                buf_allocated - buf_len);
488
 
    if(sret == -1){
489
 
      if(errno != EINTR){
490
 
        error_plus(0, errno, "read");
491
 
        status = EX_OSERR;
492
 
      }
493
 
      TEMP_FAILURE_RETRY(close(outfifo_fd));
494
 
      goto failure;
495
 
    }
496
 
    if(interrupted_by_signal){
497
 
      break;
498
 
    }
499
 
    
500
 
    buf_len += (size_t)sret;
501
 
  } while(sret != 0);
502
 
  ret = close(outfifo_fd);
503
 
  if(ret == -1){
504
 
    if(errno != EINTR){
505
 
      error_plus(0, errno, "close");
506
 
      status = EX_OSERR;
507
 
    }
508
 
    goto failure;
509
 
  }
510
 
  outfifo_fd = -1;
511
 
  
512
 
  if(interrupted_by_signal){
513
 
    goto failure;
514
 
  }
515
 
  
516
 
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
517
 
    if(errno != EINTR){
518
 
      error_plus(0, errno, "usplash_write");
519
 
      status = EX_OSERR;
520
 
    }
521
 
    goto failure;
522
 
  }
523
 
  
524
 
  if(interrupted_by_signal){
525
 
    goto failure;
526
 
  }
527
 
  
528
 
  ret = close(fifo_fd);
529
 
  if(ret == -1){
530
 
    if(errno != EINTR){
531
 
      error_plus(0, errno, "close");
532
 
      status = EX_OSERR;
533
 
    }
534
 
    goto failure;
535
 
  }
536
 
  fifo_fd = -1;
537
 
  
538
 
  /* Print password to stdout */
539
 
  size_t written = 0;
540
 
  while(written < buf_len){
541
 
    do {
542
 
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
543
 
      if(sret == -1){
544
 
        if(errno != EINTR){
545
 
          error_plus(0, errno, "write");
546
 
          status = EX_OSERR;
547
 
        }
548
 
        goto failure;
549
 
      }
550
 
    } while(sret == -1);
551
 
    
552
 
    if(interrupted_by_signal){
553
 
      goto failure;
554
 
    }
555
 
    written += (size_t)sret;
556
 
  }
557
 
  free(buf);
558
 
  buf = NULL;
559
 
  
560
 
  if(interrupted_by_signal){
561
 
    goto failure;
562
 
  }
563
 
  
564
 
  free(cmdline);
565
 
  return EXIT_SUCCESS;
566
 
  
567
 
 failure:
568
 
  
569
 
  free(buf);
570
 
  
571
 
  free(prompt);
572
 
  
573
 
  /* If usplash was never accessed, we can stop now */
574
 
  if(not usplash_accessed){
575
 
    return status;
576
 
  }
577
 
  
578
 
  /* Close FIFO */
579
 
  if(fifo_fd != -1){
580
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
581
 
    if(ret == -1 and errno != EINTR){
582
 
      error_plus(0, errno, "close");
583
 
    }
584
 
    fifo_fd = -1;
585
 
  }
586
 
  
587
 
  /* Close output FIFO */
588
 
  if(outfifo_fd != -1){
589
 
    ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
590
 
    if(ret == -1){
591
 
      error_plus(0, errno, "close");
592
 
    }
593
 
  }
594
 
  
595
 
  /* Create argv for new usplash*/
596
 
  char **cmdline_argv = malloc((argz_count(cmdline, cmdline_len) + 1)
597
 
                               * sizeof(char *)); /* Count args */
598
 
  if(cmdline_argv == NULL){
599
 
    error_plus(0, errno, "malloc");
600
 
    return status;
601
 
  }
602
 
  argz_extract(cmdline, cmdline_len, cmdline_argv); /* Create argv */
603
 
  
 
464
        perror("realloc");
 
465
        free(cmdline_argv);
 
466
        return EXIT_FAILURE;
 
467
      }
 
468
      cmdline_argv = tmp;
 
469
      cmdline_argv[cmdline_argc] = cmdline + position;
 
470
      cmdline_argc++;
 
471
      position += strlen(cmdline + position) + 1;
 
472
    }
 
473
    cmdline_argv[cmdline_argc] = NULL;
 
474
  }
604
475
  /* Kill old usplash */
605
476
  kill(usplash_pid, SIGTERM);
606
477
  sleep(2);
608
479
    kill(usplash_pid, SIGKILL);
609
480
    sleep(1);
610
481
  }
611
 
  
612
482
  pid_t new_usplash_pid = fork();
613
483
  if(new_usplash_pid == 0){
614
484
    /* Child; will become new usplash process */
615
485
    
616
486
    /* Make the effective user ID (root) the only user ID instead of
617
 
       the real user ID (_mandos) */
 
487
       the real user ID (mandos) */
618
488
    ret = setuid(geteuid());
619
489
    if(ret == -1){
620
 
      error_plus(0, errno, "setuid");
 
490
      perror("setuid");
621
491
    }
622
492
    
623
493
    setsid();
624
494
    ret = chdir("/");
625
 
    if(ret == -1){
626
 
      error_plus(0, errno, "chdir");
627
 
      _exit(EX_OSERR);
628
 
    }
629
495
/*     if(fork() != 0){ */
630
496
/*       _exit(EXIT_SUCCESS); */
631
497
/*     } */
632
498
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
633
499
    if(ret == -1){
634
 
      error_plus(0, errno, "dup2");
635
 
      _exit(EX_OSERR);
 
500
      perror("dup2");
 
501
      _exit(EXIT_FAILURE);
636
502
    }
637
503
    
638
504
    execv(usplash_name, cmdline_argv);
639
505
    if(not interrupted_by_signal){
640
 
      error_plus(0, errno, "execv");
 
506
      perror("execv");
641
507
    }
642
508
    free(cmdline);
643
509
    free(cmdline_argv);
644
 
    _exit(EX_OSERR);
 
510
    _exit(EXIT_FAILURE);
645
511
  }
646
512
  free(cmdline);
647
513
  free(cmdline_argv);
648
514
  sleep(2);
649
 
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
650
 
    if(errno != EINTR){
651
 
      error_plus(0, errno, "usplash_write");
652
 
    }
653
 
  }
654
 
  
655
 
  /* Close FIFO (again) */
656
 
  if(fifo_fd != -1){
657
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
658
 
    if(ret == -1 and errno != EINTR){
659
 
      error_plus(0, errno, "close");
660
 
    }
661
 
    fifo_fd = -1;
662
 
  }
663
 
  
664
 
  if(interrupted_by_signal){
665
 
    struct sigaction signal_action = { .sa_handler = SIG_DFL };
666
 
    sigemptyset(&signal_action.sa_mask);
667
 
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
668
 
                                            &signal_action, NULL));
669
 
    if(ret == -1){
670
 
      error_plus(0, errno, "sigaction");
671
 
    }
672
 
    do {
673
 
      ret = raise(signal_received);
674
 
    } while(ret != 0 and errno == EINTR);
675
 
    if(ret != 0){
676
 
      error_plus(0, errno, "raise");
677
 
      abort();
678
 
    }
679
 
    TEMP_FAILURE_RETRY(pause());
680
 
  }
681
 
  
682
 
  return status;
 
515
  if(not usplash_write("PULSATE", NULL)
 
516
     and (errno != EINTR)){
 
517
    perror("usplash_write");
 
518
  }
 
519
  
 
520
  return EXIT_FAILURE;
683
521
}