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