/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: 2008-08-29 05:53:59 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080829055359-wkdasnyxtylmnxus
* mandos.xml (EXAMPLE): Replaced all occurences of command name with
                        "&COMMANDNAME;".

* plugins.d/password-prompt.c (main): Improved some documentation
                                      strings.  Do perror() of
                                      tcgetattr() fails.  Add debug
                                      output if interrupted by signal.
                                      Loop over write() instead of
                                      using fwrite() when outputting
                                      password.  Add debug output if
                                      getline() returns 0, unless it
                                      was caused by a signal.  Add
                                      exit status code to debug
                                      output.

* plugins.d/password-prompt.xml: Changed all single quotes to double
                                 quotes for consistency.  Removed
                                 <?xml-stylesheet>.
  (ENTITY TIMESTAMP): New.  Automatically updated by Emacs time-stamp
                      by using Emacs local variables.
  (/refentry/refentryinfo/title): Changed to "Mandos Manual".
  (/refentry/refentryinfo/productname): Changed to "Mandos".
  (/refentry/refentryinfo/date): New; set to "&TIMESTAMP;".
  (/refentry/refentryinfo/copyright): Split copyright holders.
  (/refentry/refnamediv/refpurpose): Improved wording.
  (SYNOPSIS): Fix to use correct markup.  Add short options.
  (DESCRIPTION, OPTIONS): Improved wording.
  (OPTIONS): Improved wording.  Use more correct markup.  Document
             short options.
  (EXIT STATUS): Add text.
  (ENVIRONMENT): Document use of "cryptsource" and "crypttarget".
  (FILES): REMOVED.
  (BUGS): Add text.
  (EXAMPLE): Added some examples.
  (SECURITY): Added text.
  (SEE ALSO): Remove reference to mandos(8).  Add reference to
              crypttab(5).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8; mode: c; mode: orgtbl -*- */
 
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Password-prompt - Read a password from the terminal and print it
4
 
 * 
5
 
 * Copyright © 2008,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 Björn Påhlsson
 
3
 * Passprompt - Read a password from the terminal and print it
 
4
 *
 
5
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
7
6
 * 
8
7
 * This program is free software: you can redistribute it and/or
9
8
 * modify it under the terms of the GNU General Public License as
19
18
 * along with this program.  If not, see
20
19
 * <http://www.gnu.org/licenses/>.
21
20
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
21
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
22
 * <https://www.fukt.bsnet.se/~teddy/>.
23
23
 */
24
24
 
25
25
#define _GNU_SOURCE             /* getline() */
32
32
#include <signal.h>             /* sig_atomic_t, raise(), struct
33
33
                                   sigaction, sigemptyset(),
34
34
                                   sigaction(), sigaddset(), SIGINT,
35
 
                                   SIGQUIT, SIGHUP, SIGTERM,
36
 
                                   raise() */
 
35
                                   SIGQUIT, SIGHUP, SIGTERM */
37
36
#include <stddef.h>             /* NULL, size_t, ssize_t */
38
37
#include <sys/types.h>          /* ssize_t */
39
38
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
40
39
                                   getopt_long, getenv() */
41
40
#include <stdio.h>              /* fprintf(), stderr, getline(),
42
41
                                   stdin, feof(), perror(), fputc(),
43
 
                                   getopt_long */
44
 
#include <errno.h>              /* errno, EBADF, ENOTTY, EINVAL,
45
 
                                   EFAULT, EFBIG, EIO, ENOSPC, EINTR
46
 
                                */
 
42
                                   stdout, getopt_long */
 
43
#include <errno.h>              /* errno, EINVAL */
47
44
#include <iso646.h>             /* or, not */
48
45
#include <stdbool.h>            /* bool, false, true */
49
46
#include <string.h>             /* strlen, rindex, strncmp, strcmp */
52
49
                                   argp_parse(), error_t,
53
50
                                   ARGP_KEY_ARG, ARGP_KEY_END,
54
51
                                   ARGP_ERR_UNKNOWN */
55
 
#include <sysexits.h>           /* EX_SOFTWARE, EX_OSERR,
56
 
                                   EX_UNAVAILABLE, EX_IOERR, EX_OK */
57
52
 
58
 
volatile sig_atomic_t quit_now = 0;
59
 
int signal_received;
 
53
volatile bool quit_now = false;
60
54
bool debug = false;
61
 
const char *argp_program_version = "password-prompt " VERSION;
 
55
const char *argp_program_version = "password-prompt 1.0";
62
56
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
63
57
 
64
 
static void termination_handler(int signum){
65
 
  if(quit_now){
66
 
    return;
67
 
  }
68
 
  quit_now = 1;
69
 
  signal_received = signum;
 
58
static void termination_handler(__attribute__((unused))int signum){
 
59
  quit_now = true;
70
60
}
71
61
 
72
62
int main(int argc, char **argv){
88
78
        .doc = "Debug mode", .group = 3 },
89
79
      { .name = NULL }
90
80
    };
91
 
    
92
 
    error_t parse_opt (int key, char *arg, struct argp_state *state){
93
 
      switch (key){
 
81
  
 
82
    error_t parse_opt (int key, char *arg, struct argp_state *state) {
 
83
      /* Get the INPUT argument from `argp_parse', which we know is a
 
84
         pointer to our plugin list pointer. */
 
85
      switch (key) {
94
86
      case 'p':
95
87
        prefix = arg;
96
88
        break;
98
90
        debug = true;
99
91
        break;
100
92
      case ARGP_KEY_ARG:
101
 
        argp_usage(state);
 
93
        argp_usage (state);
102
94
        break;
103
95
      case ARGP_KEY_END:
104
96
        break;
107
99
      }
108
100
      return 0;
109
101
    }
110
 
    
 
102
  
111
103
    struct argp argp = { .options = options, .parser = parse_opt,
112
104
                         .args_doc = "",
113
105
                         .doc = "Mandos password-prompt -- Read and"
114
106
                         " output a password" };
115
 
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
116
 
    if(ret == ARGP_ERR_UNKNOWN){
 
107
    ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
108
    if (ret == ARGP_ERR_UNKNOWN){
117
109
      fprintf(stderr, "Unknown error while parsing arguments\n");
118
 
      return EX_SOFTWARE;
 
110
      return EXIT_FAILURE;
119
111
    }
120
112
  }
121
 
  
122
 
  if(debug){
 
113
    
 
114
  if (debug){
123
115
    fprintf(stderr, "Starting %s\n", argv[0]);
124
116
  }
125
 
  if(debug){
 
117
  if (debug){
126
118
    fprintf(stderr, "Storing current terminal attributes\n");
127
119
  }
128
120
  
129
 
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
130
 
    int e = errno;
 
121
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
131
122
    perror("tcgetattr");
132
 
    switch(e){
133
 
    case EBADF:
134
 
    case ENOTTY:
135
 
      return EX_UNAVAILABLE;
136
 
    default:
137
 
      return EX_OSERR;
138
 
    }
 
123
    return EXIT_FAILURE;
139
124
  }
140
125
  
141
126
  sigemptyset(&new_action.sa_mask);
142
 
  ret = sigaddset(&new_action.sa_mask, SIGINT);
143
 
  if(ret == -1){
144
 
    perror("sigaddset");
145
 
    return EX_OSERR;
146
 
  }
147
 
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
148
 
  if(ret == -1){
149
 
    perror("sigaddset");
150
 
    return EX_OSERR;
151
 
  }
152
 
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
153
 
  if(ret == -1){
154
 
    perror("sigaddset");
155
 
    return EX_OSERR;
156
 
  }
157
 
  /* Need to check if the handler is SIG_IGN before handling:
158
 
     | [[info:libc:Initial Signal Actions]] |
159
 
     | [[info:libc:Basic Signal Handling]]  |
160
 
  */
 
127
  sigaddset(&new_action.sa_mask, SIGINT);
 
128
  sigaddset(&new_action.sa_mask, SIGHUP);
 
129
  sigaddset(&new_action.sa_mask, SIGTERM);
161
130
  ret = sigaction(SIGINT, NULL, &old_action);
162
131
  if(ret == -1){
163
132
    perror("sigaction");
164
 
    return EX_OSERR;
 
133
    return EXIT_FAILURE;
165
134
  }
166
 
  if(old_action.sa_handler != SIG_IGN){
 
135
  if (old_action.sa_handler != SIG_IGN){
167
136
    ret = sigaction(SIGINT, &new_action, NULL);
168
137
    if(ret == -1){
169
138
      perror("sigaction");
170
 
      return EX_OSERR;
 
139
      return EXIT_FAILURE;
171
140
    }
172
141
  }
173
142
  ret = sigaction(SIGHUP, NULL, &old_action);
174
143
  if(ret == -1){
175
144
    perror("sigaction");
176
 
    return EX_OSERR;
 
145
    return EXIT_FAILURE;
177
146
  }
178
 
  if(old_action.sa_handler != SIG_IGN){
 
147
  if (old_action.sa_handler != SIG_IGN){
179
148
    ret = sigaction(SIGHUP, &new_action, NULL);
180
149
    if(ret == -1){
181
150
      perror("sigaction");
182
 
      return EX_OSERR;
 
151
      return EXIT_FAILURE;
183
152
    }
184
153
  }
185
154
  ret = sigaction(SIGTERM, NULL, &old_action);
186
155
  if(ret == -1){
187
156
    perror("sigaction");
188
 
    return EX_OSERR;
 
157
    return EXIT_FAILURE;
189
158
  }
190
 
  if(old_action.sa_handler != SIG_IGN){
 
159
  if (old_action.sa_handler != SIG_IGN){
191
160
    ret = sigaction(SIGTERM, &new_action, NULL);
192
161
    if(ret == -1){
193
162
      perror("sigaction");
194
 
      return EX_OSERR;
 
163
      return EXIT_FAILURE;
195
164
    }
196
165
  }
197
166
  
198
167
  
199
 
  if(debug){
 
168
  if (debug){
200
169
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
201
170
  }
202
171
  
203
172
  t_new = t_old;
204
 
  t_new.c_lflag &= ~(tcflag_t)ECHO;
205
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
206
 
    int e = errno;
 
173
  t_new.c_lflag &= ~ECHO;
 
174
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
207
175
    perror("tcsetattr-echo");
208
 
    switch(e){
209
 
    case EBADF:
210
 
    case ENOTTY:
211
 
      return EX_UNAVAILABLE;
212
 
    case EINVAL:
213
 
    default:
214
 
      return EX_OSERR;
215
 
    }
 
176
    return EXIT_FAILURE;
216
177
  }
217
 
  
218
 
  if(debug){
 
178
 
 
179
  if (debug){
219
180
    fprintf(stderr, "Waiting for input from stdin \n");
220
181
  }
221
182
  while(true){
222
 
    if(quit_now){
 
183
    if (quit_now){
223
184
      if(debug){
224
185
        fprintf(stderr, "Interrupted by signal, exiting.\n");
225
186
      }
251
212
      }
252
213
    }
253
214
    ret = getline(&buffer, &n, stdin);
254
 
    if(ret > 0){
 
215
    if (ret > 0){
255
216
      status = EXIT_SUCCESS;
256
217
      /* Make n = data size instead of allocated buffer size */
257
218
      n = (size_t)ret;
258
 
      /* Strip final newline */
259
 
      if(n > 0 and buffer[n-1] == '\n'){
260
 
        buffer[n-1] = '\0';     /* not strictly necessary */
261
 
        n--;
262
 
      }
263
219
      size_t written = 0;
264
220
      while(written < n){
265
221
        ret = write(STDOUT_FILENO, buffer + written, n - written);
266
222
        if(ret < 0){
267
 
          int e = errno;
268
223
          perror("write");
269
 
          switch(e){
270
 
          case EBADF:
271
 
          case EFAULT:
272
 
          case EINVAL:
273
 
          case EFBIG:
274
 
          case EIO:
275
 
          case ENOSPC:
276
 
          default:
277
 
            status = EX_IOERR;
278
 
            break;
279
 
          case EINTR:
280
 
            status = EXIT_FAILURE;
281
 
            break;
282
 
          }
 
224
          status = EXIT_FAILURE;
283
225
          break;
284
226
        }
285
227
        written += (size_t)ret;
286
228
      }
287
 
      ret = close(STDOUT_FILENO);
288
 
      if(ret == -1){
289
 
        int e = errno;
290
 
        perror("close");
291
 
        switch(e){
292
 
        case EBADF:
293
 
          status = EX_OSFILE;
294
 
          break;
295
 
        case EIO:
296
 
        default:
297
 
          status = EX_IOERR;
298
 
          break;
299
 
        }
300
 
      }
301
229
      break;
302
230
    }
303
 
    if(ret < 0){
304
 
      int e = errno;
305
 
      if(errno != EINTR and not feof(stdin)){
 
231
    if (ret < 0){
 
232
      if (errno != EINTR and not feof(stdin)){
306
233
        perror("getline");
307
 
        switch(e){
308
 
        case EBADF:
309
 
          status = EX_UNAVAILABLE;
310
 
        case EIO:
311
 
        case EINVAL:
312
 
        default:
313
 
          status = EX_IOERR;
314
 
          break;
315
 
        }
 
234
        status = EXIT_FAILURE;
316
235
        break;
317
236
      }
318
237
    }
320
239
       read from stdin */
321
240
    fputc('\n', stderr);
322
241
    if(debug and not quit_now){
323
 
      /* If quit_now is nonzero, we were interrupted by a signal, and
 
242
      /* If quit_now is true, we were interrupted by a signal, and
324
243
         will print that later, so no need to show this too. */
325
244
      fprintf(stderr, "getline() returned 0, retrying.\n");
326
245
    }
327
246
  }
328
247
  
329
 
  free(buffer);
330
 
  
331
 
  if(debug){
 
248
  if (debug){
332
249
    fprintf(stderr, "Restoring terminal attributes\n");
333
250
  }
334
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
251
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
335
252
    perror("tcsetattr+echo");
336
253
  }
337
254
  
338
 
  if(quit_now){
339
 
    sigemptyset(&old_action.sa_mask);
340
 
    old_action.sa_handler = SIG_DFL;
341
 
    ret = sigaction(signal_received, &old_action, NULL);
342
 
    if(ret == -1){
343
 
      perror("sigaction");
344
 
    }
345
 
    raise(signal_received);
346
 
  }
347
 
  
348
 
  if(debug){
 
255
  if (debug){
349
256
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
350
257
            status);
351
258
  }
352
 
  if(status == EXIT_SUCCESS or status == EX_OK){
353
 
    fputc('\n', stderr);
354
 
  }
355
259
  
356
260
  return status;
357
261
}