/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-2010 Teddy Hogeborn
6
 
 * Copyright © 2008-2010 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
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             /* getline(), asprintf() */
67
67
int signal_received;
68
68
bool debug = false;
69
69
const char *argp_program_version = "password-prompt " VERSION;
70
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
70
const char *argp_program_bug_address = "<mandos@recompile.se>";
71
71
 
72
72
/* Needed for conflict resolution */
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
      }
208
209
    return 1;
209
210
  }
210
211
  
211
 
  struct dirent **direntries;
 
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
  }
 
218
  free(direntries);
217
219
  return ret > 0;
218
220
}
219
221
 
248
250
      { .name = NULL }
249
251
    };
250
252
    
 
253
    __attribute__((nonnull(3)))
251
254
    error_t parse_opt (int key, char *arg, struct argp_state *state){
252
255
      errno = 0;
253
256
      switch (key){
289
292
    case ENOMEM:
290
293
    default:
291
294
      errno = ret;
292
 
      error(0, errno, "argp_parse");
 
295
      error_plus(0, errno, "argp_parse");
293
296
      return EX_OSERR;
294
297
    case EINVAL:
295
298
      return EX_USAGE;
300
303
    fprintf(stderr, "Starting %s\n", argv[0]);
301
304
  }
302
305
 
303
 
  if (conflict_detection()){
 
306
  if(conflict_detection()){
304
307
    if(debug){
305
308
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
306
309
    }
313
316
  
314
317
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
315
318
    int e = errno;
316
 
    error(0, errno, "tcgetattr");
 
319
    error_plus(0, errno, "tcgetattr");
317
320
    switch(e){
318
321
    case EBADF:
319
322
    case ENOTTY:
326
329
  sigemptyset(&new_action.sa_mask);
327
330
  ret = sigaddset(&new_action.sa_mask, SIGINT);
328
331
  if(ret == -1){
329
 
    error(0, errno, "sigaddset");
 
332
    error_plus(0, errno, "sigaddset");
330
333
    return EX_OSERR;
331
334
  }
332
335
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
333
336
  if(ret == -1){
334
 
    error(0, errno, "sigaddset");
 
337
    error_plus(0, errno, "sigaddset");
335
338
    return EX_OSERR;
336
339
  }
337
340
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
338
341
  if(ret == -1){
339
 
    error(0, errno, "sigaddset");
 
342
    error_plus(0, errno, "sigaddset");
340
343
    return EX_OSERR;
341
344
  }
342
345
  /* Need to check if the handler is SIG_IGN before handling:
345
348
  */
346
349
  ret = sigaction(SIGINT, NULL, &old_action);
347
350
  if(ret == -1){
348
 
    error(0, errno, "sigaction");
 
351
    error_plus(0, errno, "sigaction");
349
352
    return EX_OSERR;
350
353
  }
351
354
  if(old_action.sa_handler != SIG_IGN){
352
355
    ret = sigaction(SIGINT, &new_action, NULL);
353
356
    if(ret == -1){
354
 
      error(0, errno, "sigaction");
 
357
      error_plus(0, errno, "sigaction");
355
358
      return EX_OSERR;
356
359
    }
357
360
  }
358
361
  ret = sigaction(SIGHUP, NULL, &old_action);
359
362
  if(ret == -1){
360
 
    error(0, errno, "sigaction");
 
363
    error_plus(0, errno, "sigaction");
361
364
    return EX_OSERR;
362
365
  }
363
366
  if(old_action.sa_handler != SIG_IGN){
364
367
    ret = sigaction(SIGHUP, &new_action, NULL);
365
368
    if(ret == -1){
366
 
      error(0, errno, "sigaction");
 
369
      error_plus(0, errno, "sigaction");
367
370
      return EX_OSERR;
368
371
    }
369
372
  }
370
373
  ret = sigaction(SIGTERM, NULL, &old_action);
371
374
  if(ret == -1){
372
 
    error(0, errno, "sigaction");
 
375
    error_plus(0, errno, "sigaction");
373
376
    return EX_OSERR;
374
377
  }
375
378
  if(old_action.sa_handler != SIG_IGN){
376
379
    ret = sigaction(SIGTERM, &new_action, NULL);
377
380
    if(ret == -1){
378
 
      error(0, errno, "sigaction");
 
381
      error_plus(0, errno, "sigaction");
379
382
      return EX_OSERR;
380
383
    }
381
384
  }
389
392
  t_new.c_lflag &= ~(tcflag_t)ECHO;
390
393
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
391
394
    int e = errno;
392
 
    error(0, errno, "tcsetattr-echo");
 
395
    error_plus(0, errno, "tcsetattr-echo");
393
396
    switch(e){
394
397
    case EBADF:
395
398
    case ENOTTY:
459
462
        sret = write(STDOUT_FILENO, buffer + written, n - written);
460
463
        if(sret < 0){
461
464
          int e = errno;
462
 
          error(0, errno, "write");
 
465
          error_plus(0, errno, "write");
463
466
          switch(e){
464
467
          case EBADF:
465
468
          case EFAULT:
481
484
      sret = close(STDOUT_FILENO);
482
485
      if(sret == -1){
483
486
        int e = errno;
484
 
        error(0, errno, "close");
 
487
        error_plus(0, errno, "close");
485
488
        switch(e){
486
489
        case EBADF:
487
490
          status = EX_OSFILE;
497
500
    if(sret < 0){
498
501
      int e = errno;
499
502
      if(errno != EINTR and not feof(stdin)){
500
 
        error(0, errno, "getline");
 
503
        error_plus(0, errno, "getline");
501
504
        switch(e){
502
505
        case EBADF:
503
506
          status = EX_UNAVAILABLE;
 
507
          break;
504
508
        case EIO:
505
509
        case EINVAL:
506
510
        default:
526
530
    fprintf(stderr, "Restoring terminal attributes\n");
527
531
  }
528
532
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
529
 
    error(0, errno, "tcsetattr+echo");
 
533
    error_plus(0, errno, "tcsetattr+echo");
530
534
  }
531
535
  
532
536
  if(quit_now){
534
538
    old_action.sa_handler = SIG_DFL;
535
539
    ret = sigaction(signal_received, &old_action, NULL);
536
540
    if(ret == -1){
537
 
      error(0, errno, "sigaction");
 
541
      error_plus(0, errno, "sigaction");
538
542
    }
539
543
    raise(signal_received);
540
544
  }