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

  • Committer: Teddy Hogeborn
  • Date: 2015-03-10 18:03:38 UTC
  • mto: (237.7.304 trunk)
  • mto: This revision was merged to the branch mainline in revision 325.
  • Revision ID: teddy@recompile.se-20150310180338-pcxw6r2qmw9k6br9
Add ":!RSA" to GnuTLS priority string, to disallow non-DHE kx.

If Mandos was somehow made to use a non-ephemeral Diffie-Hellman key
exchange algorithm in the TLS handshake, any saved network traffic
could then be decrypted later if the Mandos client key was obtained.
By default, Mandos uses ephemeral DH key exchanges which does not have
this problem, but a non-ephemeral key exchange algorithm was still
enabled by default.  The simplest solution is to simply turn that off,
which ensures that Mandos will always use ephemeral DH key exchanges.

There is a "PFS" priority string specifier, but we can't use it because:

1. Security-wise, it is a mix between "NORMAL" and "SECURE128" - it
   enables a lot more algorithms than "SECURE256".

2. It is only available since GnuTLS 3.2.4.

Thanks to Andreas Fischer <af@bantuX.org> for reporting this issue.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Plymouth - Read a password from Plymouth and output it
4
4
 * 
5
 
 * Copyright © 2010 Teddy Hogeborn
6
 
 * Copyright © 2010 Björn Påhlsson
 
5
 * Copyright © 2010-2014 Teddy Hogeborn
 
6
 * Copyright © 2010-2014 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
19
19
 * along with this program.  If not, see
20
20
 * <http://www.gnu.org/licenses/>.
21
21
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
22
 * Contact the authors at <mandos@recompile.se>.
23
23
 */
24
24
 
25
25
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
36
36
#include <stddef.h>             /* NULL */
37
37
#include <string.h>             /* strchr(), memcmp() */
38
38
#include <stdio.h>              /* asprintf(), perror(), fopen(),
39
 
                                   fscanf() */
 
39
                                   fscanf(), vasprintf(), fprintf(),
 
40
                                   vfprintf() */
40
41
#include <unistd.h>             /* close(), readlink(), read(),
41
42
                                   fork(), setsid(), chdir(), dup2(),
42
43
                                   STDERR_FILENO, execv(), access() */
50
51
#include <error.h>              /* error() */
51
52
#include <errno.h>              /* TEMP_FAILURE_RETRY */
52
53
#include <argz.h>               /* argz_count(), argz_extract() */
 
54
#include <stdarg.h>             /* va_list, va_start(), ... */
53
55
 
54
56
sig_atomic_t interrupted_by_signal = 0;
55
 
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
 
56
63
const char plymouth_path[] = "/bin/plymouth";
57
64
const char plymouthd_path[] = "/sbin/plymouthd";
58
65
const char *plymouthd_default_argv[] = {"/sbin/plymouthd",
59
66
                                        "--mode=boot",
60
67
                                        "--attach-to-session",
61
 
                                        "--pid-file="
62
 
                                        "/dev/.initramfs/"
63
 
                                        "plymouth.pid",
64
68
                                        NULL };
65
69
 
66
70
static void termination_handler(__attribute__((unused))int signum){
70
74
  interrupted_by_signal = 1;
71
75
}
72
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
 
73
101
/* Create prompt string */
74
102
char *makeprompt(void){
75
103
  int ret = 0;
109
137
bool become_a_daemon(void){
110
138
  int ret = setuid(geteuid());
111
139
  if(ret == -1){
112
 
    error(0, errno, "setuid");
 
140
    error_plus(0, errno, "setuid");
113
141
  }
114
142
    
115
143
  setsid();
116
144
  ret = chdir("/");
117
145
  if(ret == -1){
118
 
    error(0, errno, "chdir");
 
146
    error_plus(0, errno, "chdir");
119
147
    return false;
120
148
  }
121
149
  ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
122
150
  if(ret == -1){
123
 
    error(0, errno, "dup2");
 
151
    error_plus(0, errno, "dup2");
124
152
    return false;
125
153
  }
126
154
  return true;
127
155
}
128
156
 
 
157
__attribute__((nonnull (2, 3)))
129
158
bool exec_and_wait(pid_t *pid_return, const char *path,
130
 
                   const char **argv, bool interruptable,
 
159
                   const char * const *argv, bool interruptable,
131
160
                   bool daemonize){
132
161
  int status;
133
162
  int ret;
134
163
  pid_t pid;
135
164
  pid = fork();
136
165
  if(pid == -1){
137
 
    error(0, errno, "fork");
 
166
    error_plus(0, errno, "fork");
138
167
    return false;
139
168
  }
140
169
  if(pid == 0){
150
179
    int i = 0;
151
180
    for (; argv[i]!=NULL; i++){
152
181
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 1));
153
 
      if (tmp == NULL){
154
 
        error(0, errno, "realloc");
 
182
      if(tmp == NULL){
 
183
        error_plus(0, errno, "realloc");
155
184
        free(new_argv);
156
185
        _exit(EX_OSERR);
157
186
      }
161
190
    new_argv[i] = NULL;
162
191
    
163
192
    execv(path, (char *const *)new_argv);
164
 
    error(0, errno, "execv");
 
193
    error_plus(0, errno, "execv");
165
194
    _exit(EXIT_FAILURE);
166
195
  }
167
196
  if(pid_return != NULL){
176
205
    return false;
177
206
  }
178
207
  if(ret == -1){
179
 
    error(0, errno, "waitpid");
 
208
    error_plus(0, errno, "waitpid");
180
209
    return false;
181
210
  }
182
211
  if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
185
214
  return false;
186
215
}
187
216
 
 
217
__attribute__((nonnull))
188
218
int is_plymouth(const struct dirent *proc_entry){
189
219
  int ret;
190
220
  {
191
 
    uintmax_t maxvalue;
 
221
    uintmax_t proc_id;
192
222
    char *tmp;
193
223
    errno = 0;
194
 
    maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
224
    proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
195
225
 
196
226
    if(errno != 0 or *tmp != '\0'
197
 
       or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
227
       or proc_id != (uintmax_t)((pid_t)proc_id)){
198
228
      return 0;
199
229
    }
200
230
  }
201
 
  char exe_target[sizeof(plymouth_path)];
 
231
  char exe_target[sizeof(plymouthd_path)];
202
232
  char *exe_link;
203
233
  ret = asprintf(&exe_link, "/proc/%s/exe", proc_entry->d_name);
204
234
  if(ret == -1){
205
 
    error(0, errno, "asprintf");
 
235
    error_plus(0, errno, "asprintf");
206
236
    return 0;
207
237
  }
208
238
  
211
241
  if(ret == -1){
212
242
    free(exe_link);
213
243
    if(errno != ENOENT){
214
 
      error(0, errno, "lstat");
 
244
      error_plus(0, errno, "lstat");
215
245
    }
216
246
    return 0;
217
247
  }
225
255
  
226
256
  ssize_t sret = readlink(exe_link, exe_target, sizeof(exe_target));
227
257
  free(exe_link);
228
 
  if((sret != (ssize_t)sizeof(plymouth_path)-1) or
229
 
      (memcmp(plymouth_path, exe_target,
230
 
              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)){
231
261
    return 0;
232
262
  }
233
263
  return 1;
235
265
 
236
266
pid_t get_pid(void){
237
267
  int ret;
 
268
  uintmax_t proc_id = 0;
238
269
  FILE *pidfile = fopen(plymouth_pid, "r");
239
 
  uintmax_t maxvalue = 0;
 
270
  /* Try the new pid file location */
240
271
  if(pidfile != NULL){
241
 
    ret = fscanf(pidfile, "%" SCNuMAX, &maxvalue);
 
272
    ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
242
273
    if(ret != 1){
243
 
      maxvalue = 0;
 
274
      proc_id = 0;
244
275
    }
245
276
    fclose(pidfile);
246
277
  }
247
 
  if(maxvalue == 0){
248
 
    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;
249
292
    ret = scandir("/proc", &direntries, is_plymouth, alphasort);
250
 
    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);
251
305
  }
252
306
  pid_t pid;
253
 
  pid = (pid_t)maxvalue;
254
 
  if((uintmax_t)pid == maxvalue){
 
307
  pid = (pid_t)proc_id;
 
308
  if((uintmax_t)pid == proc_id){
255
309
    return pid;
256
310
  }
257
311
  
258
312
  return 0;
259
313
}
260
314
 
261
 
const char **getargv(pid_t pid){
 
315
const char * const * getargv(pid_t pid){
262
316
  int cl_fd;
263
317
  char *cmdline_filename;
264
318
  ssize_t sret;
267
321
  ret = asprintf(&cmdline_filename, "/proc/%" PRIuMAX "/cmdline",
268
322
                 (uintmax_t)pid);
269
323
  if(ret == -1){
270
 
    error(0, errno, "asprintf");
 
324
    error_plus(0, errno, "asprintf");
271
325
    return NULL;
272
326
  }
273
327
  
275
329
  cl_fd = open(cmdline_filename, O_RDONLY);
276
330
  free(cmdline_filename);
277
331
  if(cl_fd == -1){
278
 
    error(0, errno, "open");
 
332
    error_plus(0, errno, "open");
279
333
    return NULL;
280
334
  }
281
335
  
289
343
    if(cmdline_len + blocksize > cmdline_allocated){
290
344
      tmp = realloc(cmdline, cmdline_allocated + blocksize);
291
345
      if(tmp == NULL){
292
 
        error(0, errno, "realloc");
 
346
        error_plus(0, errno, "realloc");
293
347
        free(cmdline);
294
348
        close(cl_fd);
295
349
        return NULL;
302
356
    sret = read(cl_fd, cmdline + cmdline_len,
303
357
                cmdline_allocated - cmdline_len);
304
358
    if(sret == -1){
305
 
      error(0, errno, "read");
 
359
      error_plus(0, errno, "read");
306
360
      free(cmdline);
307
361
      close(cl_fd);
308
362
      return NULL;
311
365
  } while(sret != 0);
312
366
  ret = close(cl_fd);
313
367
  if(ret == -1){
314
 
    error(0, errno, "close");
 
368
    error_plus(0, errno, "close");
315
369
    free(cmdline);
316
370
    return NULL;
317
371
  }
320
374
  char **argv = malloc((argz_count(cmdline, cmdline_len) + 1)
321
375
                       * sizeof(char *)); /* Get number of args */
322
376
  if(argv == NULL){
323
 
    error(0, errno, "argv = malloc()");
 
377
    error_plus(0, errno, "argv = malloc()");
324
378
    free(cmdline);
325
379
    return NULL;
326
380
  }
327
381
  argz_extract(cmdline, cmdline_len, argv); /* Create argv */
328
 
  return (const char **)argv;
 
382
  return (const char * const *)argv;
329
383
}
330
384
 
331
385
int main(__attribute__((unused))int argc,
353
407
        *sig != 0; sig++){
354
408
      ret = sigaddset(&new_action.sa_mask, *sig);
355
409
      if(ret == -1){
356
 
        error(EX_OSERR, errno, "sigaddset");
 
410
        error_plus(EX_OSERR, errno, "sigaddset");
357
411
      }
358
412
      ret = sigaction(*sig, NULL, &old_action);
359
413
      if(ret == -1){
360
 
        error(EX_OSERR, errno, "sigaction");
 
414
        error_plus(EX_OSERR, errno, "sigaction");
361
415
      }
362
416
      if(old_action.sa_handler != SIG_IGN){
363
417
        ret = sigaction(*sig, &new_action, NULL);
364
418
        if(ret == -1){
365
 
          error(EX_OSERR, errno, "sigaction");
 
419
          error_plus(EX_OSERR, errno, "sigaction");
366
420
        }
367
421
      }
368
422
    }
387
441
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
388
442
  free(prompt);
389
443
  if(ret == -1){
390
 
    error(EX_OSERR, errno, "asprintf");
 
444
    error_plus(EX_OSERR, errno, "asprintf");
391
445
  }
392
446
  
393
447
  /* plymouth ask-for-password --prompt="$prompt" */
406
460
  }
407
461
  kill_and_wait(plymouth_command_pid);
408
462
  
409
 
  const char **plymouthd_argv;
 
463
  const char * const *plymouthd_argv;
410
464
  pid_t pid = get_pid();
411
465
  if(pid == 0){
412
 
    error(0, 0, "plymouthd pid not found");
 
466
    error_plus(0, 0, "plymouthd pid not found");
413
467
    plymouthd_argv = plymouthd_default_argv;
414
468
  } else {
415
469
    plymouthd_argv = getargv(pid);