/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
33
32
#include <signal.h>             /* sig_atomic_t, raise(), struct
34
33
                                   sigaction, sigemptyset(),
35
34
                                   sigaction(), sigaddset(), SIGINT,
36
 
                                   SIGQUIT, SIGHUP, SIGTERM,
37
 
                                   raise() */
 
35
                                   SIGQUIT, SIGHUP, SIGTERM */
38
36
#include <stddef.h>             /* NULL, size_t, ssize_t */
39
37
#include <sys/types.h>          /* ssize_t */
40
38
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
41
 
                                   getopt_long, getenv() */
 
39
                                   getopt_long */
42
40
#include <stdio.h>              /* fprintf(), stderr, getline(),
43
41
                                   stdin, feof(), perror(), fputc(),
44
42
                                   stdout, getopt_long */
52
50
                                   ARGP_KEY_ARG, ARGP_KEY_END,
53
51
                                   ARGP_ERR_UNKNOWN */
54
52
 
55
 
volatile sig_atomic_t quit_now = 0;
56
 
int signal_received;
 
53
volatile bool quit_now = false;
57
54
bool debug = false;
58
 
const char *argp_program_version = "password-prompt " VERSION;
 
55
const char *argp_program_version = "password-prompt 1.0";
59
56
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
60
57
 
61
 
static void termination_handler(int signum){
62
 
  if(quit_now){
63
 
    return;
64
 
  }
65
 
  quit_now = 1;
66
 
  signal_received = signum;
 
58
static void termination_handler(__attribute__((unused))int signum){
 
59
  quit_now = true;
67
60
}
68
61
 
69
62
int main(int argc, char **argv){
80
73
    struct argp_option options[] = {
81
74
      { .name = "prefix", .key = 'p',
82
75
        .arg = "PREFIX", .flags = 0,
83
 
        .doc = "Prefix shown before the prompt", .group = 2 },
 
76
        .doc = "Prefix used before the passprompt", .group = 2 },
84
77
      { .name = "debug", .key = 128,
85
78
        .doc = "Debug mode", .group = 3 },
86
79
      { .name = NULL }
87
80
    };
88
 
    
89
 
    error_t parse_opt (int key, char *arg, struct argp_state *state){
90
 
      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) {
91
86
      case 'p':
92
87
        prefix = arg;
93
88
        break;
95
90
        debug = true;
96
91
        break;
97
92
      case ARGP_KEY_ARG:
98
 
        argp_usage(state);
 
93
        argp_usage (state);
99
94
        break;
100
95
      case ARGP_KEY_END:
101
96
        break;
104
99
      }
105
100
      return 0;
106
101
    }
107
 
    
 
102
  
108
103
    struct argp argp = { .options = options, .parser = parse_opt,
109
104
                         .args_doc = "",
110
 
                         .doc = "Mandos password-prompt -- Read and"
111
 
                         " output a password" };
112
 
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
113
 
    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){
114
108
      fprintf(stderr, "Unknown error while parsing arguments\n");
115
109
      return EXIT_FAILURE;
116
110
    }
117
111
  }
118
 
  
119
 
  if(debug){
 
112
    
 
113
  if (debug){
120
114
    fprintf(stderr, "Starting %s\n", argv[0]);
121
115
  }
122
 
  if(debug){
 
116
  if (debug){
123
117
    fprintf(stderr, "Storing current terminal attributes\n");
124
118
  }
125
119
  
126
 
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
127
 
    perror("tcgetattr");
 
120
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
128
121
    return EXIT_FAILURE;
129
122
  }
130
123
  
131
124
  sigemptyset(&new_action.sa_mask);
132
 
  ret = sigaddset(&new_action.sa_mask, SIGINT);
133
 
  if(ret == -1){
134
 
    perror("sigaddset");
135
 
    return EXIT_FAILURE;
136
 
  }
137
 
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
138
 
  if(ret == -1){
139
 
    perror("sigaddset");
140
 
    return EXIT_FAILURE;
141
 
  }
142
 
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
143
 
  if(ret == -1){
144
 
    perror("sigaddset");
145
 
    return EXIT_FAILURE;
146
 
  }
147
 
  /* Need to check if the handler is SIG_IGN before handling:
148
 
     | [[info:libc:Initial Signal Actions]] |
149
 
     | [[info:libc:Basic Signal Handling]]  |
150
 
  */
 
125
  sigaddset(&new_action.sa_mask, SIGINT);
 
126
  sigaddset(&new_action.sa_mask, SIGHUP);
 
127
  sigaddset(&new_action.sa_mask, SIGTERM);
151
128
  ret = sigaction(SIGINT, NULL, &old_action);
152
129
  if(ret == -1){
153
130
    perror("sigaction");
154
131
    return EXIT_FAILURE;
155
132
  }
156
 
  if(old_action.sa_handler != SIG_IGN){
 
133
  if (old_action.sa_handler != SIG_IGN){
157
134
    ret = sigaction(SIGINT, &new_action, NULL);
158
135
    if(ret == -1){
159
136
      perror("sigaction");
165
142
    perror("sigaction");
166
143
    return EXIT_FAILURE;
167
144
  }
168
 
  if(old_action.sa_handler != SIG_IGN){
 
145
  if (old_action.sa_handler != SIG_IGN){
169
146
    ret = sigaction(SIGHUP, &new_action, NULL);
170
147
    if(ret == -1){
171
148
      perror("sigaction");
177
154
    perror("sigaction");
178
155
    return EXIT_FAILURE;
179
156
  }
180
 
  if(old_action.sa_handler != SIG_IGN){
 
157
  if (old_action.sa_handler != SIG_IGN){
181
158
    ret = sigaction(SIGTERM, &new_action, NULL);
182
159
    if(ret == -1){
183
160
      perror("sigaction");
186
163
  }
187
164
  
188
165
  
189
 
  if(debug){
 
166
  if (debug){
190
167
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
191
168
  }
192
169
  
193
170
  t_new = t_old;
194
171
  t_new.c_lflag &= ~ECHO;
195
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
 
172
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
196
173
    perror("tcsetattr-echo");
197
174
    return EXIT_FAILURE;
198
175
  }
199
176
 
200
 
  if(debug){
 
177
  if (debug){
201
178
    fprintf(stderr, "Waiting for input from stdin \n");
202
179
  }
203
180
  while(true){
204
 
    if(quit_now){
205
 
      if(debug){
206
 
        fprintf(stderr, "Interrupted by signal, exiting.\n");
207
 
      }
 
181
    if (quit_now){
208
182
      status = EXIT_FAILURE;
209
183
      break;
210
184
    }
211
185
 
212
186
    if(prefix){
213
 
      fprintf(stderr, "%s ", prefix);
214
 
    }
215
 
    {
216
 
      const char *cryptsource = getenv("cryptsource");
217
 
      const char *crypttarget = getenv("crypttarget");
218
 
      const char *const prompt
219
 
        = "Enter passphrase to unlock the disk";
220
 
      if(cryptsource == NULL){
221
 
        if(crypttarget == NULL){
222
 
          fprintf(stderr, "%s: ", prompt);
223
 
        } else {
224
 
          fprintf(stderr, "%s (%s): ", prompt, crypttarget);
225
 
        }
226
 
      } else {
227
 
        if(crypttarget == NULL){
228
 
          fprintf(stderr, "%s %s: ", prompt, cryptsource);
229
 
        } else {
230
 
          fprintf(stderr, "%s %s (%s): ", prompt, cryptsource,
231
 
                  crypttarget);
232
 
        }
233
 
      }
234
 
    }
 
187
      fprintf(stderr, "%s Password: ", prefix);
 
188
    } else {
 
189
      fprintf(stderr, "Password: ");
 
190
    }      
235
191
    ret = getline(&buffer, &n, stdin);
236
 
    if(ret > 0){
 
192
    if (ret > 0){
 
193
      fprintf(stdout, "%s", buffer);
237
194
      status = EXIT_SUCCESS;
238
 
      /* Make n = data size instead of allocated buffer size */
239
 
      n = (size_t)ret;
240
 
      /* Strip final newline */
241
 
      if(n>0 and buffer[n-1] == '\n'){
242
 
        buffer[n-1] = '\0';     /* not strictly necessary */
243
 
        n--;
244
 
      }
245
 
      size_t written = 0;
246
 
      while(written < n){
247
 
        ret = write(STDOUT_FILENO, buffer + written, n - written);
248
 
        if(ret < 0){
249
 
          perror("write");
250
 
          status = EXIT_FAILURE;
251
 
          break;
252
 
        }
253
 
        written += (size_t)ret;
254
 
      }
255
195
      break;
256
196
    }
257
 
    if(ret < 0){
258
 
      if(errno != EINTR and not feof(stdin)){
 
197
    if (ret < 0){
 
198
      if (errno != EINTR and not feof(stdin)){
259
199
        perror("getline");
260
200
        status = EXIT_FAILURE;
261
201
        break;
264
204
    /* if(ret == 0), then the only sensible thing to do is to retry to
265
205
       read from stdin */
266
206
    fputc('\n', stderr);
267
 
    if(debug and not quit_now){
268
 
      /* If quit_now is nonzero, we were interrupted by a signal, and
269
 
         will print that later, so no need to show this too. */
270
 
      fprintf(stderr, "getline() returned 0, retrying.\n");
271
 
    }
272
207
  }
273
208
  
274
 
  free(buffer);
275
 
  
276
 
  if(debug){
 
209
  if (debug){
277
210
    fprintf(stderr, "Restoring terminal attributes\n");
278
211
  }
279
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
212
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
280
213
    perror("tcsetattr+echo");
281
214
  }
282
215
  
283
 
  if(quit_now){
284
 
    sigemptyset(&old_action.sa_mask);
285
 
    old_action.sa_handler = SIG_DFL;
286
 
    ret = sigaction(signal_received, &old_action, NULL);
287
 
    if(ret == -1){
288
 
      perror("sigaction");
289
 
    }
290
 
    raise(signal_received);
291
 
  }
292
 
  
293
 
  if(debug){
294
 
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
295
 
            status);
296
 
  }
297
 
  if(status == EXIT_SUCCESS){
298
 
    fputc('\n', stderr);
 
216
  if (debug){
 
217
    fprintf(stderr, "%s is exiting\n", argv[0]);
299
218
  }
300
219
  
301
220
  return status;