/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-16 03:29:08 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080816032908-ihw7c05r2mnyk389
Add feature to specify custom environment variables for plugins.

* plugin-runner.c (plugin): New members "environ" and "envc" to
                            contain possible custom environment.
  (getplugin): Return NULL on failure instead of doing exit(); all
               callers changed.
  (add_to_char_array): New helper function for "add_argument" and
                       "add_environment".
  (addargument): Renamed to "add_argument".  Return bool.  Call
                 "add_to_char_array" to actually do things.
  (add_environment): New; analogous to "add_argument".
  (addcustomargument): Renamed to "add_to_argv" to avoid confusion
                       with "add_argument".
  (main): New options "--global-envs" and "--envs-for" to specify
          custom environment for plugins.  Print environment for
          plugins in debug mode.  Use asprintf instead of strcpy and
          strcat.  Use execve() for plugins with custom environments.
          Free environment for plugin when freeing plugin list.

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
 
                                   getopt_long, getenv() */
 
39
                                   getopt_long */
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){
83
73
    struct argp_option options[] = {
84
74
      { .name = "prefix", .key = 'p',
85
75
        .arg = "PREFIX", .flags = 0,
86
 
        .doc = "Prefix shown before the prompt", .group = 2 },
 
76
        .doc = "Prefix used before the passprompt", .group = 2 },
87
77
      { .name = "debug", .key = 128,
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
 
                         .doc = "Mandos password-prompt -- Read and"
114
 
                         " output a password" };
115
 
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
116
 
    if(ret == ARGP_ERR_UNKNOWN){
 
105
                         .doc = "Mandos Passprompt -- Provides a passprompt" };
 
106
    ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
107
    if (ret == ARGP_ERR_UNKNOWN){
117
108
      fprintf(stderr, "Unknown error while parsing arguments\n");
118
 
      return EX_SOFTWARE;
 
109
      return EXIT_FAILURE;
119
110
    }
120
111
  }
121
 
  
122
 
  if(debug){
 
112
    
 
113
  if (debug){
123
114
    fprintf(stderr, "Starting %s\n", argv[0]);
124
115
  }
125
 
  if(debug){
 
116
  if (debug){
126
117
    fprintf(stderr, "Storing current terminal attributes\n");
127
118
  }
128
119
  
129
 
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
130
 
    int e = errno;
131
 
    perror("tcgetattr");
132
 
    switch(e){
133
 
    case EBADF:
134
 
    case ENOTTY:
135
 
      return EX_UNAVAILABLE;
136
 
    default:
137
 
      return EX_OSERR;
138
 
    }
 
120
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
 
121
    return EXIT_FAILURE;
139
122
  }
140
123
  
141
124
  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
 
  */
 
125
  sigaddset(&new_action.sa_mask, SIGINT);
 
126
  sigaddset(&new_action.sa_mask, SIGHUP);
 
127
  sigaddset(&new_action.sa_mask, SIGTERM);
161
128
  ret = sigaction(SIGINT, NULL, &old_action);
162
129
  if(ret == -1){
163
130
    perror("sigaction");
164
 
    return EX_OSERR;
 
131
    return EXIT_FAILURE;
165
132
  }
166
 
  if(old_action.sa_handler != SIG_IGN){
 
133
  if (old_action.sa_handler != SIG_IGN){
167
134
    ret = sigaction(SIGINT, &new_action, NULL);
168
135
    if(ret == -1){
169
136
      perror("sigaction");
170
 
      return EX_OSERR;
 
137
      return EXIT_FAILURE;
171
138
    }
172
139
  }
173
140
  ret = sigaction(SIGHUP, NULL, &old_action);
174
141
  if(ret == -1){
175
142
    perror("sigaction");
176
 
    return EX_OSERR;
 
143
    return EXIT_FAILURE;
177
144
  }
178
 
  if(old_action.sa_handler != SIG_IGN){
 
145
  if (old_action.sa_handler != SIG_IGN){
179
146
    ret = sigaction(SIGHUP, &new_action, NULL);
180
147
    if(ret == -1){
181
148
      perror("sigaction");
182
 
      return EX_OSERR;
 
149
      return EXIT_FAILURE;
183
150
    }
184
151
  }
185
152
  ret = sigaction(SIGTERM, NULL, &old_action);
186
153
  if(ret == -1){
187
154
    perror("sigaction");
188
 
    return EX_OSERR;
 
155
    return EXIT_FAILURE;
189
156
  }
190
 
  if(old_action.sa_handler != SIG_IGN){
 
157
  if (old_action.sa_handler != SIG_IGN){
191
158
    ret = sigaction(SIGTERM, &new_action, NULL);
192
159
    if(ret == -1){
193
160
      perror("sigaction");
194
 
      return EX_OSERR;
 
161
      return EXIT_FAILURE;
195
162
    }
196
163
  }
197
164
  
198
165
  
199
 
  if(debug){
 
166
  if (debug){
200
167
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
201
168
  }
202
169
  
203
170
  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;
 
171
  t_new.c_lflag &= ~ECHO;
 
172
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
207
173
    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
 
    }
 
174
    return EXIT_FAILURE;
216
175
  }
217
 
  
218
 
  if(debug){
 
176
 
 
177
  if (debug){
219
178
    fprintf(stderr, "Waiting for input from stdin \n");
220
179
  }
221
180
  while(true){
222
 
    if(quit_now){
223
 
      if(debug){
224
 
        fprintf(stderr, "Interrupted by signal, exiting.\n");
225
 
      }
 
181
    if (quit_now){
226
182
      status = EXIT_FAILURE;
227
183
      break;
228
184
    }
229
185
 
230
186
    if(prefix){
231
 
      fprintf(stderr, "%s ", prefix);
232
 
    }
233
 
    {
234
 
      const char *cryptsource = getenv("cryptsource");
235
 
      const char *crypttarget = getenv("crypttarget");
236
 
      const char *const prompt
237
 
        = "Enter passphrase to unlock the disk";
238
 
      if(cryptsource == NULL){
239
 
        if(crypttarget == NULL){
240
 
          fprintf(stderr, "%s: ", prompt);
241
 
        } else {
242
 
          fprintf(stderr, "%s (%s): ", prompt, crypttarget);
243
 
        }
244
 
      } else {
245
 
        if(crypttarget == NULL){
246
 
          fprintf(stderr, "%s %s: ", prompt, cryptsource);
247
 
        } else {
248
 
          fprintf(stderr, "%s %s (%s): ", prompt, cryptsource,
249
 
                  crypttarget);
250
 
        }
251
 
      }
252
 
    }
 
187
      fprintf(stderr, "%s Password: ", prefix);
 
188
    } else {
 
189
      fprintf(stderr, "Password: ");
 
190
    }      
253
191
    ret = getline(&buffer, &n, stdin);
254
 
    if(ret > 0){
 
192
    if (ret > 0){
 
193
      fprintf(stdout, "%s", buffer);
255
194
      status = EXIT_SUCCESS;
256
 
      /* Make n = data size instead of allocated buffer size */
257
 
      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
 
      size_t written = 0;
264
 
      while(written < n){
265
 
        ret = write(STDOUT_FILENO, buffer + written, n - written);
266
 
        if(ret < 0){
267
 
          int e = errno;
268
 
          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
 
          }
283
 
          break;
284
 
        }
285
 
        written += (size_t)ret;
286
 
      }
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
195
      break;
302
196
    }
303
 
    if(ret < 0){
304
 
      int e = errno;
305
 
      if(errno != EINTR and not feof(stdin)){
 
197
    if (ret < 0){
 
198
      if (errno != EINTR and not feof(stdin)){
306
199
        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
 
        }
 
200
        status = EXIT_FAILURE;
316
201
        break;
317
202
      }
318
203
    }
319
204
    /* if(ret == 0), then the only sensible thing to do is to retry to
320
205
       read from stdin */
321
206
    fputc('\n', stderr);
322
 
    if(debug and not quit_now){
323
 
      /* If quit_now is nonzero, we were interrupted by a signal, and
324
 
         will print that later, so no need to show this too. */
325
 
      fprintf(stderr, "getline() returned 0, retrying.\n");
326
 
    }
327
207
  }
328
208
  
329
 
  free(buffer);
330
 
  
331
 
  if(debug){
 
209
  if (debug){
332
210
    fprintf(stderr, "Restoring terminal attributes\n");
333
211
  }
334
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
212
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
335
213
    perror("tcsetattr+echo");
336
214
  }
337
215
  
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){
349
 
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
350
 
            status);
351
 
  }
352
 
  if(status == EXIT_SUCCESS or status == EX_OK){
353
 
    fputc('\n', stderr);
 
216
  if (debug){
 
217
    fprintf(stderr, "%s is exiting\n", argv[0]);
354
218
  }
355
219
  
356
220
  return status;