/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugins.d/plymouth.c

  • Committer: Teddy Hogeborn
  • Date: 2014-07-25 22:44:20 UTC
  • mto: This revision was merged to the branch mainline in revision 724.
  • Revision ID: teddy@recompile.se-20140725224420-4a5ct2ptt0hsc92z
Require Python 2.7.

This is in preparation for the eventual move to Python 3, which will
happen as soon as all Python modules required by Mandos are available.
The mandos-ctl and mandos-monitor programs are already portable
between Python 2.6 and Python 3 without changes; this change will
bring the requirement up to Python 2.7.

* INSTALL (Prerequisites/Libraries/Mandos Server): Document
                                                   requirement of
                                                   Python 2.7; remove
                                                   Python-argparse
                                                   which is in the
                                                   Python 2.7 standard
                                                   library.
* debian/control (Source: mandos/Build-Depends-Indep): Depend on
                                                       exactly the
                                                       python2.7
                                                       package and all
                                                       the Python 2.7
                                                       versions of the
                                                       python modules.
  (Package: mandos/Depends): - '' - but still depend on python (<=2.7)
                            and the generic versions of the Python
                            modules; this is for mandos-ctl and
                            mandos-monitor, both of which are
                            compatible with Python 3, and use
                            #!/usr/bin/python.
* mandos: Use #!/usr/bin/python2.7 instead of #!/usr/bin/python.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  -*- coding: utf-8 -*- */
 
2
/*
 
3
 * Plymouth - Read a password from Plymouth and output it
 
4
 * 
 
5
 * Copyright © 2010-2014 Teddy Hogeborn
 
6
 * Copyright © 2010-2014 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
 
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 * 
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program.  If not, see
 
20
 * <http://www.gnu.org/licenses/>.
 
21
 * 
 
22
 * Contact the authors at <mandos@recompile.se>.
 
23
 */
 
24
 
1
25
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
2
26
#include <signal.h>             /* sig_atomic_t, struct sigaction,
3
27
                                   sigemptyset(), sigaddset(), SIGINT,
12
36
#include <stddef.h>             /* NULL */
13
37
#include <string.h>             /* strchr(), memcmp() */
14
38
#include <stdio.h>              /* asprintf(), perror(), fopen(),
15
 
                                   fscanf() */
 
39
                                   fscanf(), vasprintf(), fprintf(),
 
40
                                   vfprintf() */
16
41
#include <unistd.h>             /* close(), readlink(), read(),
17
42
                                   fork(), setsid(), chdir(), dup2(),
18
43
                                   STDERR_FILENO, execv(), access() */
26
51
#include <error.h>              /* error() */
27
52
#include <errno.h>              /* TEMP_FAILURE_RETRY */
28
53
#include <argz.h>               /* argz_count(), argz_extract() */
 
54
#include <stdarg.h>             /* va_list, va_start(), ... */
29
55
 
30
56
sig_atomic_t interrupted_by_signal = 0;
31
 
const char plymouth_pid[] = "/dev/.initramfs/plymouth.pid";
 
57
 
 
58
/* Used by Ubuntu 11.04 (Natty Narwahl) */
 
59
const char plymouth_old_pid[] = "/dev/.initramfs/plymouth.pid";
 
60
/* Used by Ubuntu 11.10 (Oneiric Ocelot) */
 
61
const char plymouth_pid[] = "/run/initramfs/plymouth.pid";
 
62
 
32
63
const char plymouth_path[] = "/bin/plymouth";
33
64
const char plymouthd_path[] = "/sbin/plymouthd";
34
65
const char *plymouthd_default_argv[] = {"/sbin/plymouthd",
35
66
                                        "--mode=boot",
36
67
                                        "--attach-to-session",
37
 
                                        "--pid-file="
38
 
                                        "/dev/.initramfs/"
39
 
                                        "plymouth.pid",
40
68
                                        NULL };
41
69
 
42
70
static void termination_handler(__attribute__((unused))int signum){
46
74
  interrupted_by_signal = 1;
47
75
}
48
76
 
 
77
/* Function to use when printing errors */
 
78
__attribute__((format (gnu_printf, 3, 4)))
 
79
void error_plus(int status, int errnum, const char *formatstring,
 
80
                ...){
 
81
  va_list ap;
 
82
  char *text;
 
83
  int ret;
 
84
  
 
85
  va_start(ap, formatstring);
 
86
  ret = vasprintf(&text, formatstring, ap);
 
87
  if(ret == -1){
 
88
    fprintf(stderr, "Mandos plugin %s: ",
 
89
            program_invocation_short_name);
 
90
    vfprintf(stderr, formatstring, ap);
 
91
    fprintf(stderr, ": ");
 
92
    fprintf(stderr, "%s\n", strerror(errnum));
 
93
    error(status, errno, "vasprintf while printing error");
 
94
    return;
 
95
  }
 
96
  fprintf(stderr, "Mandos plugin ");
 
97
  error(status, errnum, "%s", text);
 
98
  free(text);
 
99
}
 
100
 
49
101
/* Create prompt string */
50
102
char *makeprompt(void){
51
103
  int ret = 0;
52
104
  char *prompt;
53
105
  const char *const cryptsource = getenv("cryptsource");
54
106
  const char *const crypttarget = getenv("crypttarget");
55
 
  const char prompt_start[] = "Enter passphrase to unlock the disk";
 
107
  const char prompt_start[] = "Unlocking the disk";
 
108
  const char prompt_end[] = "Enter passphrase";
56
109
  
57
110
  if(cryptsource == NULL){
58
111
    if(crypttarget == NULL){
59
 
      ret = asprintf(&prompt, "%s: ", prompt_start);
 
112
      ret = asprintf(&prompt, "%s\n%s", prompt_start, prompt_end);
60
113
    } else {
61
 
      ret = asprintf(&prompt, "%s (%s): ", prompt_start,
62
 
                     crypttarget);
 
114
      ret = asprintf(&prompt, "%s (%s)\n%s", prompt_start,
 
115
                     crypttarget, prompt_end);
63
116
    }
64
117
  } else {
65
118
    if(crypttarget == NULL){
66
 
      ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
 
119
      ret = asprintf(&prompt, "%s %s\n%s", prompt_start, cryptsource,
 
120
                     prompt_end);
67
121
    } else {
68
 
      ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
69
 
                     cryptsource, crypttarget);
 
122
      ret = asprintf(&prompt, "%s %s (%s)\n%s", prompt_start,
 
123
                     cryptsource, crypttarget, prompt_end);
70
124
    }
71
125
  }
72
126
  if(ret == -1){
83
137
bool become_a_daemon(void){
84
138
  int ret = setuid(geteuid());
85
139
  if(ret == -1){
86
 
    error(0, errno, "setuid");
 
140
    error_plus(0, errno, "setuid");
87
141
  }
88
142
    
89
143
  setsid();
90
144
  ret = chdir("/");
91
145
  if(ret == -1){
92
 
    error(0, errno, "chdir");
 
146
    error_plus(0, errno, "chdir");
93
147
    return false;
94
148
  }
95
149
  ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
96
150
  if(ret == -1){
97
 
    error(0, errno, "dup2");
 
151
    error_plus(0, errno, "dup2");
98
152
    return false;
99
153
  }
100
154
  return true;
101
155
}
102
156
 
 
157
__attribute__((nonnull (2, 3)))
103
158
bool exec_and_wait(pid_t *pid_return, const char *path,
104
 
                   const char **argv, bool interruptable,
 
159
                   const char * const *argv, bool interruptable,
105
160
                   bool daemonize){
106
161
  int status;
107
162
  int ret;
108
163
  pid_t pid;
109
164
  pid = fork();
110
165
  if(pid == -1){
111
 
    error(0, errno, "fork");
 
166
    error_plus(0, errno, "fork");
112
167
    return false;
113
168
  }
114
169
  if(pid == 0){
118
173
        _exit(EX_OSERR);
119
174
      }
120
175
    }
121
 
 
 
176
    
122
177
    char **new_argv = NULL;
123
 
    char *tmp;
 
178
    char **tmp;
124
179
    int i = 0;
125
 
    for (; argv[i]!=(char *)NULL; i++){
 
180
    for (; argv[i]!=NULL; i++){
126
181
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 1));
127
 
      if (tmp == NULL){
128
 
        error(0, errno, "realloc");
 
182
      if(tmp == NULL){
 
183
        error_plus(0, errno, "realloc");
129
184
        free(new_argv);
130
185
        _exit(EX_OSERR);
131
186
      }
132
 
      new_argv = (char **)tmp;
 
187
      new_argv = tmp;
133
188
      new_argv[i] = strdup(argv[i]);
134
189
    }
135
 
    new_argv[i] = (char *) NULL;
 
190
    new_argv[i] = NULL;
136
191
    
137
192
    execv(path, (char *const *)new_argv);
138
 
    error(0, errno, "execv");
 
193
    error_plus(0, errno, "execv");
139
194
    _exit(EXIT_FAILURE);
140
195
  }
141
196
  if(pid_return != NULL){
150
205
    return false;
151
206
  }
152
207
  if(ret == -1){
153
 
    error(0, errno, "waitpid");
 
208
    error_plus(0, errno, "waitpid");
154
209
    return false;
155
210
  }
156
211
  if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
159
214
  return false;
160
215
}
161
216
 
 
217
__attribute__((nonnull))
162
218
int is_plymouth(const struct dirent *proc_entry){
163
219
  int ret;
164
220
  {
165
 
    uintmax_t maxvalue;
 
221
    uintmax_t proc_id;
166
222
    char *tmp;
167
223
    errno = 0;
168
 
    maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
224
    proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
169
225
 
170
226
    if(errno != 0 or *tmp != '\0'
171
 
       or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
227
       or proc_id != (uintmax_t)((pid_t)proc_id)){
172
228
      return 0;
173
229
    }
174
230
  }
175
 
  char exe_target[sizeof(plymouth_path)];
 
231
  char exe_target[sizeof(plymouthd_path)];
176
232
  char *exe_link;
177
233
  ret = asprintf(&exe_link, "/proc/%s/exe", proc_entry->d_name);
178
234
  if(ret == -1){
179
 
    error(0, errno, "asprintf");
 
235
    error_plus(0, errno, "asprintf");
180
236
    return 0;
181
237
  }
182
238
  
185
241
  if(ret == -1){
186
242
    free(exe_link);
187
243
    if(errno != ENOENT){
188
 
      error(0, errno, "lstat");
 
244
      error_plus(0, errno, "lstat");
189
245
    }
190
246
    return 0;
191
247
  }
199
255
  
200
256
  ssize_t sret = readlink(exe_link, exe_target, sizeof(exe_target));
201
257
  free(exe_link);
202
 
  if((sret != (ssize_t)sizeof(plymouth_path)-1) or
203
 
      (memcmp(plymouth_path, exe_target,
204
 
              sizeof(plymouth_path)-1) != 0)){
 
258
  if((sret != (ssize_t)sizeof(plymouthd_path)-1) or
 
259
      (memcmp(plymouthd_path, exe_target,
 
260
              sizeof(plymouthd_path)-1) != 0)){
205
261
    return 0;
206
262
  }
207
263
  return 1;
209
265
 
210
266
pid_t get_pid(void){
211
267
  int ret;
 
268
  uintmax_t proc_id = 0;
212
269
  FILE *pidfile = fopen(plymouth_pid, "r");
213
 
  uintmax_t maxvalue = 0;
 
270
  /* Try the new pid file location */
214
271
  if(pidfile != NULL){
215
 
    ret = fscanf(pidfile, "%" SCNuMAX, &maxvalue);
 
272
    ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
216
273
    if(ret != 1){
217
 
      maxvalue = 0;
 
274
      proc_id = 0;
218
275
    }
219
276
    fclose(pidfile);
220
277
  }
221
 
  if(maxvalue == 0){
222
 
    struct dirent **direntries;
 
278
  /* Try the old pid file location */
 
279
  if(proc_id == 0){
 
280
    pidfile = fopen(plymouth_pid, "r");
 
281
    if(pidfile != NULL){
 
282
      ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
 
283
      if(ret != 1){
 
284
        proc_id = 0;
 
285
      }
 
286
      fclose(pidfile);
 
287
    }
 
288
  }
 
289
  /* Look for a plymouth process */
 
290
  if(proc_id == 0){
 
291
    struct dirent **direntries = NULL;
223
292
    ret = scandir("/proc", &direntries, is_plymouth, alphasort);
224
 
    sscanf(direntries[0]->d_name, "%" SCNuMAX, &maxvalue);
 
293
    if(ret == -1){
 
294
      error_plus(0, errno, "scandir");
 
295
    }
 
296
    if(ret > 0){
 
297
      ret = sscanf(direntries[0]->d_name, "%" SCNuMAX, &proc_id);
 
298
      if(ret < 0){
 
299
        error_plus(0, errno, "sscanf");
 
300
      }
 
301
    }
 
302
    /* scandir might preallocate for this variable (man page unclear).
 
303
       even if ret == 0, therefore we need to free it. */
 
304
    free(direntries);
225
305
  }
226
306
  pid_t pid;
227
 
  pid = (pid_t)maxvalue;
228
 
  if((uintmax_t)pid == maxvalue){
 
307
  pid = (pid_t)proc_id;
 
308
  if((uintmax_t)pid == proc_id){
229
309
    return pid;
230
310
  }
231
311
  
232
312
  return 0;
233
313
}
234
314
 
235
 
const char **getargv(pid_t pid){
 
315
const char * const * getargv(pid_t pid){
236
316
  int cl_fd;
237
317
  char *cmdline_filename;
238
318
  ssize_t sret;
241
321
  ret = asprintf(&cmdline_filename, "/proc/%" PRIuMAX "/cmdline",
242
322
                 (uintmax_t)pid);
243
323
  if(ret == -1){
244
 
    error(0, errno, "asprintf");
 
324
    error_plus(0, errno, "asprintf");
245
325
    return NULL;
246
326
  }
247
327
  
249
329
  cl_fd = open(cmdline_filename, O_RDONLY);
250
330
  free(cmdline_filename);
251
331
  if(cl_fd == -1){
252
 
    error(0, errno, "open");
 
332
    error_plus(0, errno, "open");
253
333
    return NULL;
254
334
  }
255
335
  
263
343
    if(cmdline_len + blocksize > cmdline_allocated){
264
344
      tmp = realloc(cmdline, cmdline_allocated + blocksize);
265
345
      if(tmp == NULL){
266
 
        error(0, errno, "realloc");
 
346
        error_plus(0, errno, "realloc");
267
347
        free(cmdline);
268
348
        close(cl_fd);
269
349
        return NULL;
276
356
    sret = read(cl_fd, cmdline + cmdline_len,
277
357
                cmdline_allocated - cmdline_len);
278
358
    if(sret == -1){
279
 
      error(0, errno, "read");
 
359
      error_plus(0, errno, "read");
280
360
      free(cmdline);
281
361
      close(cl_fd);
282
362
      return NULL;
285
365
  } while(sret != 0);
286
366
  ret = close(cl_fd);
287
367
  if(ret == -1){
288
 
    error(0, errno, "close");
 
368
    error_plus(0, errno, "close");
289
369
    free(cmdline);
290
370
    return NULL;
291
371
  }
294
374
  char **argv = malloc((argz_count(cmdline, cmdline_len) + 1)
295
375
                       * sizeof(char *)); /* Get number of args */
296
376
  if(argv == NULL){
297
 
    error(0, errno, "argv = malloc()");
 
377
    error_plus(0, errno, "argv = malloc()");
298
378
    free(cmdline);
299
379
    return NULL;
300
380
  }
301
381
  argz_extract(cmdline, cmdline_len, argv); /* Create argv */
302
 
  return (const char **)argv;
 
382
  return (const char * const *)argv;
303
383
}
304
384
 
305
385
int main(__attribute__((unused))int argc,
327
407
        *sig != 0; sig++){
328
408
      ret = sigaddset(&new_action.sa_mask, *sig);
329
409
      if(ret == -1){
330
 
        error(EX_OSERR, errno, "sigaddset");
 
410
        error_plus(EX_OSERR, errno, "sigaddset");
331
411
      }
332
412
      ret = sigaction(*sig, NULL, &old_action);
333
413
      if(ret == -1){
334
 
        error(EX_OSERR, errno, "sigaction");
 
414
        error_plus(EX_OSERR, errno, "sigaction");
335
415
      }
336
416
      if(old_action.sa_handler != SIG_IGN){
337
417
        ret = sigaction(*sig, &new_action, NULL);
338
418
        if(ret == -1){
339
 
          error(EX_OSERR, errno, "sigaction");
 
419
          error_plus(EX_OSERR, errno, "sigaction");
340
420
        }
341
421
      }
342
422
    }
361
441
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
362
442
  free(prompt);
363
443
  if(ret == -1){
364
 
    error(EX_OSERR, errno, "asprintf");
 
444
    error_plus(EX_OSERR, errno, "asprintf");
365
445
  }
366
446
  
367
447
  /* plymouth ask-for-password --prompt="$prompt" */
380
460
  }
381
461
  kill_and_wait(plymouth_command_pid);
382
462
  
383
 
  const char **plymouthd_argv;
 
463
  const char * const *plymouthd_argv;
384
464
  pid_t pid = get_pid();
385
465
  if(pid == 0){
386
 
    error(0, 0, "plymouthd pid not found");
 
466
    error_plus(0, 0, "plymouthd pid not found");
387
467
    plymouthd_argv = plymouthd_default_argv;
388
468
  } else {
389
469
    plymouthd_argv = getargv(pid);