/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: 2019-07-14 22:39:15 UTC
  • Revision ID: teddy@recompile.se-20190714223915-aqjkms3t3taa6tye
Only use sanitizing options when debugging

The C compiler's sanitizing options introduce code in the output
binary which is fragile and not very security conscious.  It has
become clear that sanitizing is only really meant for use while
debugging.

As a side effect, this makes compilation faster, as the Makefile, for
production builds, no longer runs the compiler repeatedly to find all
its currently supported sanitizing options.

* Makefile (DEBUG): Add "$(SANITIZE)".
  (SANITIZE): Comment out.
  (CFLAGS): Remove "$(SANITIZE)".
  (plugins.d/mandos-client): Revert back to use plain $(LINK.c), since
                             we no longer need to remove the leak
                             sanitizer by overriding CFLAGS.

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
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
 
5
 * Copyright © 2008-2019 Teddy Hogeborn
 
6
 * Copyright © 2008-2019 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
14
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
18
 * General Public License for more details.
17
19
 * 
18
20
 * 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
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
21
22
 * 
22
23
 * Contact the authors at <mandos@recompile.se>.
23
24
 */
73
74
const char plymouth_name[] = "plymouthd";
74
75
 
75
76
/* Function to use when printing errors */
 
77
__attribute__((format (gnu_printf, 3, 4)))
76
78
void error_plus(int status, int errnum, const char *formatstring,
77
79
                ...){
78
80
  va_list ap;
81
83
  
82
84
  va_start(ap, formatstring);
83
85
  ret = vasprintf(&text, formatstring, ap);
84
 
  if (ret == -1){
 
86
  if(ret == -1){
85
87
    fprintf(stderr, "Mandos plugin %s: ",
86
88
            program_invocation_short_name);
87
89
    vfprintf(stderr, formatstring, ap);
88
 
    fprintf(stderr, ": ");
89
 
    fprintf(stderr, "%s\n", strerror(errnum));
 
90
    fprintf(stderr, ": %s\n", strerror(errnum));
90
91
    error(status, errno, "vasprintf while printing error");
91
92
    return;
92
93
  }
109
110
     from the terminal.  Password-prompt will exit if it detects
110
111
     plymouth since plymouth performs the same functionality.
111
112
   */
 
113
  __attribute__((nonnull))
112
114
  int is_plymouth(const struct dirent *proc_entry){
113
115
    int ret;
114
116
    int cl_fd;
115
117
    {
116
 
      uintmax_t maxvalue;
 
118
      uintmax_t proc_id;
117
119
      char *tmp;
118
120
      errno = 0;
119
 
      maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
121
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
120
122
      
121
123
      if(errno != 0 or *tmp != '\0'
122
 
         or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
124
         or proc_id != (uintmax_t)((pid_t)proc_id)){
123
125
        return 0;
124
126
      }
125
127
    }
128
130
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
129
131
                   proc_entry->d_name);
130
132
    if(ret == -1){
131
 
      error(0, errno, "asprintf");
 
133
      error_plus(0, errno, "asprintf");
132
134
      return 0;
133
135
    }
134
136
    
137
139
    free(cmdline_filename);
138
140
    if(cl_fd == -1){
139
141
      if(errno != ENOENT){
140
 
        error(0, errno, "open");
 
142
        error_plus(0, errno, "open");
141
143
      }
142
144
      return 0;
143
145
    }
154
156
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
155
157
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
156
158
          if(tmp == NULL){
157
 
            error(0, errno, "realloc");
 
159
            error_plus(0, errno, "realloc");
158
160
            free(cmdline);
159
161
            close(cl_fd);
160
162
            return 0;
167
169
        sret = read(cl_fd, cmdline + cmdline_len,
168
170
                    cmdline_allocated - cmdline_len);
169
171
        if(sret == -1){
170
 
          error(0, errno, "read");
 
172
          error_plus(0, errno, "read");
171
173
          free(cmdline);
172
174
          close(cl_fd);
173
175
          return 0;
176
178
      } while(sret != 0);
177
179
      ret = close(cl_fd);
178
180
      if(ret == -1){
179
 
        error(0, errno, "close");
 
181
        error_plus(0, errno, "close");
180
182
        free(cmdline);
181
183
        return 0;
182
184
      }
211
213
  struct dirent **direntries = NULL;
212
214
  int ret;
213
215
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
214
 
  if (ret == -1){
215
 
    error(1, errno, "scandir");
 
216
  if(ret == -1){
 
217
    error_plus(1, errno, "scandir");
 
218
  }
 
219
  {
 
220
    int i = ret;
 
221
    while(i--){
 
222
      free(direntries[i]);
 
223
    }
216
224
  }
217
225
  free(direntries);
218
226
  return ret > 0;
249
257
      { .name = NULL }
250
258
    };
251
259
    
 
260
    __attribute__((nonnull(3)))
252
261
    error_t parse_opt (int key, char *arg, struct argp_state *state){
253
262
      errno = 0;
254
263
      switch (key){
265
274
        argp_state_help(state, state->out_stream,
266
275
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
267
276
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
277
        __builtin_unreachable();
268
278
      case -3:                  /* --usage */
269
279
        argp_state_help(state, state->out_stream,
270
280
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
281
        __builtin_unreachable();
271
282
      case 'V':                 /* --version */
272
283
        fprintf(state->out_stream, "%s\n", argp_program_version);
273
284
        exit(argp_err_exit_status);
290
301
    case ENOMEM:
291
302
    default:
292
303
      errno = ret;
293
 
      error(0, errno, "argp_parse");
 
304
      error_plus(0, errno, "argp_parse");
294
305
      return EX_OSERR;
295
306
    case EINVAL:
296
307
      return EX_USAGE;
301
312
    fprintf(stderr, "Starting %s\n", argv[0]);
302
313
  }
303
314
 
304
 
  if (conflict_detection()){
 
315
  if(conflict_detection()){
305
316
    if(debug){
306
317
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
307
318
    }
314
325
  
315
326
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
316
327
    int e = errno;
317
 
    error(0, errno, "tcgetattr");
 
328
    error_plus(0, errno, "tcgetattr");
318
329
    switch(e){
319
330
    case EBADF:
320
331
    case ENOTTY:
327
338
  sigemptyset(&new_action.sa_mask);
328
339
  ret = sigaddset(&new_action.sa_mask, SIGINT);
329
340
  if(ret == -1){
330
 
    error(0, errno, "sigaddset");
 
341
    error_plus(0, errno, "sigaddset");
331
342
    return EX_OSERR;
332
343
  }
333
344
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
334
345
  if(ret == -1){
335
 
    error(0, errno, "sigaddset");
 
346
    error_plus(0, errno, "sigaddset");
336
347
    return EX_OSERR;
337
348
  }
338
349
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
339
350
  if(ret == -1){
340
 
    error(0, errno, "sigaddset");
 
351
    error_plus(0, errno, "sigaddset");
341
352
    return EX_OSERR;
342
353
  }
343
354
  /* Need to check if the handler is SIG_IGN before handling:
346
357
  */
347
358
  ret = sigaction(SIGINT, NULL, &old_action);
348
359
  if(ret == -1){
349
 
    error(0, errno, "sigaction");
 
360
    error_plus(0, errno, "sigaction");
350
361
    return EX_OSERR;
351
362
  }
352
363
  if(old_action.sa_handler != SIG_IGN){
353
364
    ret = sigaction(SIGINT, &new_action, NULL);
354
365
    if(ret == -1){
355
 
      error(0, errno, "sigaction");
 
366
      error_plus(0, errno, "sigaction");
356
367
      return EX_OSERR;
357
368
    }
358
369
  }
359
370
  ret = sigaction(SIGHUP, NULL, &old_action);
360
371
  if(ret == -1){
361
 
    error(0, errno, "sigaction");
 
372
    error_plus(0, errno, "sigaction");
362
373
    return EX_OSERR;
363
374
  }
364
375
  if(old_action.sa_handler != SIG_IGN){
365
376
    ret = sigaction(SIGHUP, &new_action, NULL);
366
377
    if(ret == -1){
367
 
      error(0, errno, "sigaction");
 
378
      error_plus(0, errno, "sigaction");
368
379
      return EX_OSERR;
369
380
    }
370
381
  }
371
382
  ret = sigaction(SIGTERM, NULL, &old_action);
372
383
  if(ret == -1){
373
 
    error(0, errno, "sigaction");
 
384
    error_plus(0, errno, "sigaction");
374
385
    return EX_OSERR;
375
386
  }
376
387
  if(old_action.sa_handler != SIG_IGN){
377
388
    ret = sigaction(SIGTERM, &new_action, NULL);
378
389
    if(ret == -1){
379
 
      error(0, errno, "sigaction");
 
390
      error_plus(0, errno, "sigaction");
380
391
      return EX_OSERR;
381
392
    }
382
393
  }
390
401
  t_new.c_lflag &= ~(tcflag_t)ECHO;
391
402
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
392
403
    int e = errno;
393
 
    error(0, errno, "tcsetattr-echo");
 
404
    error_plus(0, errno, "tcsetattr-echo");
394
405
    switch(e){
395
406
    case EBADF:
396
407
    case ENOTTY:
460
471
        sret = write(STDOUT_FILENO, buffer + written, n - written);
461
472
        if(sret < 0){
462
473
          int e = errno;
463
 
          error(0, errno, "write");
 
474
          error_plus(0, errno, "write");
464
475
          switch(e){
465
476
          case EBADF:
466
477
          case EFAULT:
482
493
      sret = close(STDOUT_FILENO);
483
494
      if(sret == -1){
484
495
        int e = errno;
485
 
        error(0, errno, "close");
 
496
        error_plus(0, errno, "close");
486
497
        switch(e){
487
498
        case EBADF:
488
499
          status = EX_OSFILE;
497
508
    }
498
509
    if(sret < 0){
499
510
      int e = errno;
500
 
      if(errno != EINTR and not feof(stdin)){
501
 
        error(0, errno, "getline");
502
 
        switch(e){
503
 
        case EBADF:
504
 
          status = EX_UNAVAILABLE;
505
 
        case EIO:
506
 
        case EINVAL:
507
 
        default:
508
 
          status = EX_IOERR;
 
511
      if(errno != EINTR){
 
512
        if(not feof(stdin)){
 
513
          error_plus(0, errno, "getline");
 
514
          switch(e){
 
515
          case EBADF:
 
516
            status = EX_UNAVAILABLE;
 
517
            break;
 
518
          case EIO:
 
519
          case EINVAL:
 
520
          default:
 
521
            status = EX_IOERR;
 
522
            break;
 
523
          }
509
524
          break;
 
525
        } else {
 
526
          clearerr(stdin);
510
527
        }
511
 
        break;
512
528
      }
513
529
    }
514
530
    /* if(sret == 0), then the only sensible thing to do is to retry
527
543
    fprintf(stderr, "Restoring terminal attributes\n");
528
544
  }
529
545
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
530
 
    error(0, errno, "tcsetattr+echo");
 
546
    error_plus(0, errno, "tcsetattr+echo");
531
547
  }
532
548
  
533
549
  if(quit_now){
535
551
    old_action.sa_handler = SIG_DFL;
536
552
    ret = sigaction(signal_received, &old_action, NULL);
537
553
    if(ret == -1){
538
 
      error(0, errno, "sigaction");
 
554
      error_plus(0, errno, "sigaction");
539
555
    }
540
556
    raise(signal_received);
541
557
  }