/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

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