/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-03-18 22:29:25 UTC
  • Revision ID: teddy@recompile.se-20190318222925-jvhek84dgcfgj6g3
mandos-ctl: Refactor tests

* mandos-ctl: Where the clients names "foo" and "barbar" do not refer
              to the actual mock clients in the TestCommand class,
              change all occurrences of these names to "client1" and
              "client2" (or just "client" when only one is used) .
              Also change all test doubles to use correct terminology;
              some things called mocks are actually stubs or spies,
              and rename all true mocks to have "mock" in their names.
              Also eliminate duplicate values in tests; derive values
              from previously defined values whenever possible.

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;
498
509
    if(sret < 0){
499
510
      int e = errno;
500
511
      if(errno != EINTR and not feof(stdin)){
501
 
        error(0, errno, "getline");
 
512
        error_plus(0, errno, "getline");
502
513
        switch(e){
503
514
        case EBADF:
504
515
          status = EX_UNAVAILABLE;
 
516
          break;
505
517
        case EIO:
506
518
        case EINVAL:
507
519
        default:
527
539
    fprintf(stderr, "Restoring terminal attributes\n");
528
540
  }
529
541
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
530
 
    error(0, errno, "tcsetattr+echo");
 
542
    error_plus(0, errno, "tcsetattr+echo");
531
543
  }
532
544
  
533
545
  if(quit_now){
535
547
    old_action.sa_handler = SIG_DFL;
536
548
    ret = sigaction(signal_received, &old_action, NULL);
537
549
    if(ret == -1){
538
 
      error(0, errno, "sigaction");
 
550
      error_plus(0, errno, "sigaction");
539
551
    }
540
552
    raise(signal_received);
541
553
  }