/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/password-prompt.c

  • Committer: Teddy Hogeborn
  • Date: 2016-03-17 20:40:55 UTC
  • Revision ID: teddy@recompile.se-20160317204055-bhsh5xsidq7w5cxu
Client: Fix plymouth agent; broken since 1.7.2.

Fix an very old memory bug in the plymouth agent (which has been
present since its apperance in version 1.2), but which was only
recently detected at run time due to the new -fsanitize=address
compile- time flag, which has been used since version 1.7.2.  This
detection of a memory access violation causes the program to abort,
making the Plymouth graphical boot system unable to accept interactive
input of passwords when using the Mandos client.

* plugins.d/plymouth.c (exec_and_wait): Fix memory allocation bug when
  allocating new_argv.  Also tolerate a zero-length argv.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Password-prompt - Read a password from the terminal and print it
4
4
 * 
5
 
 * Copyright © 2008-2011 Teddy Hogeborn
6
 
 * Copyright © 2008-2011 Björn Påhlsson
 
5
 * Copyright © 2008-2016 Teddy Hogeborn
 
6
 * Copyright © 2008-2016 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
73
73
const char plymouth_name[] = "plymouthd";
74
74
 
75
75
/* Function to use when printing errors */
 
76
__attribute__((format (gnu_printf, 3, 4)))
76
77
void error_plus(int status, int errnum, const char *formatstring,
77
78
                ...){
78
79
  va_list ap;
81
82
  
82
83
  va_start(ap, formatstring);
83
84
  ret = vasprintf(&text, formatstring, ap);
84
 
  if (ret == -1){
 
85
  if(ret == -1){
85
86
    fprintf(stderr, "Mandos plugin %s: ",
86
87
            program_invocation_short_name);
87
88
    vfprintf(stderr, formatstring, ap);
88
 
    fprintf(stderr, ": ");
89
 
    fprintf(stderr, "%s\n", strerror(errnum));
 
89
    fprintf(stderr, ": %s\n", strerror(errnum));
90
90
    error(status, errno, "vasprintf while printing error");
91
91
    return;
92
92
  }
109
109
     from the terminal.  Password-prompt will exit if it detects
110
110
     plymouth since plymouth performs the same functionality.
111
111
   */
 
112
  __attribute__((nonnull))
112
113
  int is_plymouth(const struct dirent *proc_entry){
113
114
    int ret;
114
115
    int cl_fd;
115
116
    {
116
 
      uintmax_t maxvalue;
 
117
      uintmax_t proc_id;
117
118
      char *tmp;
118
119
      errno = 0;
119
 
      maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
120
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
120
121
      
121
122
      if(errno != 0 or *tmp != '\0'
122
 
         or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
123
         or proc_id != (uintmax_t)((pid_t)proc_id)){
123
124
        return 0;
124
125
      }
125
126
    }
128
129
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
129
130
                   proc_entry->d_name);
130
131
    if(ret == -1){
131
 
      error(0, errno, "asprintf");
 
132
      error_plus(0, errno, "asprintf");
132
133
      return 0;
133
134
    }
134
135
    
137
138
    free(cmdline_filename);
138
139
    if(cl_fd == -1){
139
140
      if(errno != ENOENT){
140
 
        error(0, errno, "open");
 
141
        error_plus(0, errno, "open");
141
142
      }
142
143
      return 0;
143
144
    }
154
155
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
155
156
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
156
157
          if(tmp == NULL){
157
 
            error(0, errno, "realloc");
 
158
            error_plus(0, errno, "realloc");
158
159
            free(cmdline);
159
160
            close(cl_fd);
160
161
            return 0;
167
168
        sret = read(cl_fd, cmdline + cmdline_len,
168
169
                    cmdline_allocated - cmdline_len);
169
170
        if(sret == -1){
170
 
          error(0, errno, "read");
 
171
          error_plus(0, errno, "read");
171
172
          free(cmdline);
172
173
          close(cl_fd);
173
174
          return 0;
176
177
      } while(sret != 0);
177
178
      ret = close(cl_fd);
178
179
      if(ret == -1){
179
 
        error(0, errno, "close");
 
180
        error_plus(0, errno, "close");
180
181
        free(cmdline);
181
182
        return 0;
182
183
      }
211
212
  struct dirent **direntries = NULL;
212
213
  int ret;
213
214
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
214
 
  if (ret == -1){
215
 
    error(1, errno, "scandir");
 
215
  if(ret == -1){
 
216
    error_plus(1, errno, "scandir");
216
217
  }
217
218
  free(direntries);
218
219
  return ret > 0;
249
250
      { .name = NULL }
250
251
    };
251
252
    
 
253
    __attribute__((nonnull(3)))
252
254
    error_t parse_opt (int key, char *arg, struct argp_state *state){
253
255
      errno = 0;
254
256
      switch (key){
290
292
    case ENOMEM:
291
293
    default:
292
294
      errno = ret;
293
 
      error(0, errno, "argp_parse");
 
295
      error_plus(0, errno, "argp_parse");
294
296
      return EX_OSERR;
295
297
    case EINVAL:
296
298
      return EX_USAGE;
301
303
    fprintf(stderr, "Starting %s\n", argv[0]);
302
304
  }
303
305
 
304
 
  if (conflict_detection()){
 
306
  if(conflict_detection()){
305
307
    if(debug){
306
308
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
307
309
    }
314
316
  
315
317
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
316
318
    int e = errno;
317
 
    error(0, errno, "tcgetattr");
 
319
    error_plus(0, errno, "tcgetattr");
318
320
    switch(e){
319
321
    case EBADF:
320
322
    case ENOTTY:
327
329
  sigemptyset(&new_action.sa_mask);
328
330
  ret = sigaddset(&new_action.sa_mask, SIGINT);
329
331
  if(ret == -1){
330
 
    error(0, errno, "sigaddset");
 
332
    error_plus(0, errno, "sigaddset");
331
333
    return EX_OSERR;
332
334
  }
333
335
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
334
336
  if(ret == -1){
335
 
    error(0, errno, "sigaddset");
 
337
    error_plus(0, errno, "sigaddset");
336
338
    return EX_OSERR;
337
339
  }
338
340
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
339
341
  if(ret == -1){
340
 
    error(0, errno, "sigaddset");
 
342
    error_plus(0, errno, "sigaddset");
341
343
    return EX_OSERR;
342
344
  }
343
345
  /* Need to check if the handler is SIG_IGN before handling:
346
348
  */
347
349
  ret = sigaction(SIGINT, NULL, &old_action);
348
350
  if(ret == -1){
349
 
    error(0, errno, "sigaction");
 
351
    error_plus(0, errno, "sigaction");
350
352
    return EX_OSERR;
351
353
  }
352
354
  if(old_action.sa_handler != SIG_IGN){
353
355
    ret = sigaction(SIGINT, &new_action, NULL);
354
356
    if(ret == -1){
355
 
      error(0, errno, "sigaction");
 
357
      error_plus(0, errno, "sigaction");
356
358
      return EX_OSERR;
357
359
    }
358
360
  }
359
361
  ret = sigaction(SIGHUP, NULL, &old_action);
360
362
  if(ret == -1){
361
 
    error(0, errno, "sigaction");
 
363
    error_plus(0, errno, "sigaction");
362
364
    return EX_OSERR;
363
365
  }
364
366
  if(old_action.sa_handler != SIG_IGN){
365
367
    ret = sigaction(SIGHUP, &new_action, NULL);
366
368
    if(ret == -1){
367
 
      error(0, errno, "sigaction");
 
369
      error_plus(0, errno, "sigaction");
368
370
      return EX_OSERR;
369
371
    }
370
372
  }
371
373
  ret = sigaction(SIGTERM, NULL, &old_action);
372
374
  if(ret == -1){
373
 
    error(0, errno, "sigaction");
 
375
    error_plus(0, errno, "sigaction");
374
376
    return EX_OSERR;
375
377
  }
376
378
  if(old_action.sa_handler != SIG_IGN){
377
379
    ret = sigaction(SIGTERM, &new_action, NULL);
378
380
    if(ret == -1){
379
 
      error(0, errno, "sigaction");
 
381
      error_plus(0, errno, "sigaction");
380
382
      return EX_OSERR;
381
383
    }
382
384
  }
390
392
  t_new.c_lflag &= ~(tcflag_t)ECHO;
391
393
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
392
394
    int e = errno;
393
 
    error(0, errno, "tcsetattr-echo");
 
395
    error_plus(0, errno, "tcsetattr-echo");
394
396
    switch(e){
395
397
    case EBADF:
396
398
    case ENOTTY:
460
462
        sret = write(STDOUT_FILENO, buffer + written, n - written);
461
463
        if(sret < 0){
462
464
          int e = errno;
463
 
          error(0, errno, "write");
 
465
          error_plus(0, errno, "write");
464
466
          switch(e){
465
467
          case EBADF:
466
468
          case EFAULT:
482
484
      sret = close(STDOUT_FILENO);
483
485
      if(sret == -1){
484
486
        int e = errno;
485
 
        error(0, errno, "close");
 
487
        error_plus(0, errno, "close");
486
488
        switch(e){
487
489
        case EBADF:
488
490
          status = EX_OSFILE;
498
500
    if(sret < 0){
499
501
      int e = errno;
500
502
      if(errno != EINTR and not feof(stdin)){
501
 
        error(0, errno, "getline");
 
503
        error_plus(0, errno, "getline");
502
504
        switch(e){
503
505
        case EBADF:
504
506
          status = EX_UNAVAILABLE;
 
507
          break;
505
508
        case EIO:
506
509
        case EINVAL:
507
510
        default:
527
530
    fprintf(stderr, "Restoring terminal attributes\n");
528
531
  }
529
532
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
530
 
    error(0, errno, "tcsetattr+echo");
 
533
    error_plus(0, errno, "tcsetattr+echo");
531
534
  }
532
535
  
533
536
  if(quit_now){
535
538
    old_action.sa_handler = SIG_DFL;
536
539
    ret = sigaction(signal_received, &old_action, NULL);
537
540
    if(ret == -1){
538
 
      error(0, errno, "sigaction");
 
541
      error_plus(0, errno, "sigaction");
539
542
    }
540
543
    raise(signal_received);
541
544
  }