/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/usplash.c

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