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