/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/passprompt.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-02 10:48:24 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080802104824-fx0miwp9o4g9r31e
* plugbasedclient.c (struct process): New fields "eof", "completed",
                                      and "status".
  (handle_sigchld): New function.
  (main): Initialize "dir" to NULL to only closedir() it if necessary.
          Move "process_list" to be a global variable to be accessible
          by "handle_sigchld".  Make "handle_sigchld" handle SIGCHLD.
          Remove redundant check for NULL "dir".  Free "filename" when
          no longer used.  Block SIGCHLD around fork()/exec().
          Restore normal signals in child.  Only loop while running
          processes exist.  Print process buffer when the process is
          done and it has emitted EOF, not when it only emits EOF.
          Remove processes from list which exit non-cleanly.  In
          cleaning up, closedir() if necessary.  Bug fix: set next
          pointer correctly when freeing process list.

* plugins.d/passprompt.c (main): Do not ignore SIGQUIT.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
                                   sigaction, sigemptyset(),
34
34
                                   sigaction(), sigaddset(), SIGINT,
35
35
                                   SIGQUIT, SIGHUP, SIGTERM */
36
 
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
36
#include <stddef.h>             /* NULL, size_t */
37
37
#include <sys/types.h>          /* ssize_t */
38
38
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
39
 
                                   getopt_long, getenv() */
 
39
                                   getopt_long */
40
40
#include <stdio.h>              /* fprintf(), stderr, getline(),
41
41
                                   stdin, feof(), perror(), fputc(),
42
42
                                   stdout, getopt_long */
44
44
#include <iso646.h>             /* or, not */
45
45
#include <stdbool.h>            /* bool, false, true */
46
46
#include <string.h>             /* strlen, rindex, strncmp, strcmp */
47
 
#include <argp.h>               /* struct argp_option, struct
48
 
                                   argp_state, struct argp,
49
 
                                   argp_parse(), error_t,
50
 
                                   ARGP_KEY_ARG, ARGP_KEY_END,
51
 
                                   ARGP_ERR_UNKNOWN */
 
47
#include <getopt.h>             /* getopt_long */
52
48
 
53
49
volatile bool quit_now = false;
54
50
bool debug = false;
55
 
const char *argp_program_version = "password-prompt 1.0";
56
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
57
51
 
58
 
static void termination_handler(__attribute__((unused))int signum){
 
52
void termination_handler(__attribute__((unused))int signum){
59
53
  quit_now = true;
60
54
}
61
55
 
69
63
  struct sigaction old_action,
70
64
    new_action = { .sa_handler = termination_handler,
71
65
                   .sa_flags = 0 };
72
 
  {
73
 
    struct argp_option options[] = {
74
 
      { .name = "prefix", .key = 'p',
75
 
        .arg = "PREFIX", .flags = 0,
76
 
        .doc = "Prefix shown before the prompt", .group = 2 },
77
 
      { .name = "debug", .key = 128,
78
 
        .doc = "Debug mode", .group = 3 },
79
 
      { .name = NULL }
80
 
    };
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) {
86
 
      case 'p':
87
 
        prefix = arg;
88
 
        break;
89
 
      case 128:
90
 
        debug = true;
91
 
        break;
92
 
      case ARGP_KEY_ARG:
93
 
        argp_usage (state);
94
 
        break;
95
 
      case ARGP_KEY_END:
96
 
        break;
97
 
      default:
98
 
        return ARGP_ERR_UNKNOWN;
99
 
      }
100
 
      return 0;
 
66
 
 
67
  while (true){
 
68
    static struct option long_options[] = {
 
69
      {"debug", no_argument, (int *)&debug, 1},
 
70
      {"prefix", required_argument, 0, 'p'},
 
71
      {0, 0, 0, 0} };
 
72
 
 
73
    int option_index = 0;
 
74
    ret = getopt_long (argc, argv, "p:", long_options, &option_index);
 
75
 
 
76
    if (ret == -1){
 
77
      break;
101
78
    }
102
 
  
103
 
    struct argp argp = { .options = options, .parser = parse_opt,
104
 
                         .args_doc = "",
105
 
                         .doc = "Mandos password-prompt -- Read and"
106
 
                         " output a password" };
107
 
    ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
108
 
    if (ret == ARGP_ERR_UNKNOWN){
109
 
      fprintf(stderr, "Unknown error while parsing arguments\n");
110
 
      return EXIT_FAILURE;
 
79
      
 
80
    switch(ret){
 
81
    case 0:
 
82
      break;
 
83
    case 'p':
 
84
      prefix = optarg;
 
85
      break;
 
86
    default:
 
87
      fprintf(stderr, "bad arguments\n");
 
88
      exit(EXIT_FAILURE);
111
89
    }
112
90
  }
113
 
    
 
91
      
114
92
  if (debug){
115
93
    fprintf(stderr, "Starting %s\n", argv[0]);
116
94
  }
119
97
  }
120
98
  
121
99
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
122
 
    perror("tcgetattr");
123
100
    return EXIT_FAILURE;
124
101
  }
125
102
  
127
104
  sigaddset(&new_action.sa_mask, SIGINT);
128
105
  sigaddset(&new_action.sa_mask, SIGHUP);
129
106
  sigaddset(&new_action.sa_mask, SIGTERM);
130
 
  ret = sigaction(SIGINT, NULL, &old_action);
131
 
  if(ret == -1){
132
 
    perror("sigaction");
133
 
    return EXIT_FAILURE;
134
 
  }
135
 
  if (old_action.sa_handler != SIG_IGN){
136
 
    ret = sigaction(SIGINT, &new_action, NULL);
137
 
    if(ret == -1){
138
 
      perror("sigaction");
139
 
      return EXIT_FAILURE;
140
 
    }
141
 
  }
142
 
  ret = sigaction(SIGHUP, NULL, &old_action);
143
 
  if(ret == -1){
144
 
    perror("sigaction");
145
 
    return EXIT_FAILURE;
146
 
  }
147
 
  if (old_action.sa_handler != SIG_IGN){
148
 
    ret = sigaction(SIGHUP, &new_action, NULL);
149
 
    if(ret == -1){
150
 
      perror("sigaction");
151
 
      return EXIT_FAILURE;
152
 
    }
153
 
  }
154
 
  ret = sigaction(SIGTERM, NULL, &old_action);
155
 
  if(ret == -1){
156
 
    perror("sigaction");
157
 
    return EXIT_FAILURE;
158
 
  }
159
 
  if (old_action.sa_handler != SIG_IGN){
160
 
    ret = sigaction(SIGTERM, &new_action, NULL);
161
 
    if(ret == -1){
162
 
      perror("sigaction");
163
 
      return EXIT_FAILURE;
164
 
    }
165
 
  }
166
 
  
 
107
  sigaction(SIGINT, NULL, &old_action);
 
108
  if (old_action.sa_handler != SIG_IGN)
 
109
    sigaction(SIGINT, &new_action, NULL);
 
110
  sigaction(SIGHUP, NULL, &old_action);
 
111
  if (old_action.sa_handler != SIG_IGN)
 
112
    sigaction(SIGHUP, &new_action, NULL);
 
113
  sigaction(SIGTERM, NULL, &old_action);
 
114
  if (old_action.sa_handler != SIG_IGN)
 
115
    sigaction(SIGTERM, &new_action, NULL);
 
116
 
167
117
  
168
118
  if (debug){
169
119
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
181
131
  }
182
132
  while(true){
183
133
    if (quit_now){
184
 
      if(debug){
185
 
        fprintf(stderr, "Interrupted by signal, exiting.\n");
186
 
      }
187
134
      status = EXIT_FAILURE;
188
135
      break;
189
136
    }
190
137
 
191
138
    if(prefix){
192
 
      fprintf(stderr, "%s ", prefix);
193
 
    }
194
 
    {
195
 
      const char *cryptsource = getenv("cryptsource");
196
 
      const char *crypttarget = getenv("crypttarget");
197
 
      const char *const prompt
198
 
        = "Enter passphrase to unlock the disk";
199
 
      if(cryptsource == NULL){
200
 
        if(crypttarget == NULL){
201
 
          fprintf(stderr, "%s: ", prompt);
202
 
        } else {
203
 
          fprintf(stderr, "%s (%s): ", prompt, crypttarget);
204
 
        }
205
 
      } else {
206
 
        if(crypttarget == NULL){
207
 
          fprintf(stderr, "%s %s: ", prompt, cryptsource);
208
 
        } else {
209
 
          fprintf(stderr, "%s %s (%s): ", prompt, cryptsource,
210
 
                  crypttarget);
211
 
        }
212
 
      }
213
 
    }
 
139
      fprintf(stderr, "%s Password: ", prefix);
 
140
    } else {
 
141
      fprintf(stderr, "Password: ");
 
142
    }      
214
143
    ret = getline(&buffer, &n, stdin);
215
144
    if (ret > 0){
 
145
      fprintf(stdout, "%s", buffer);
216
146
      status = EXIT_SUCCESS;
217
 
      /* Make n = data size instead of allocated buffer size */
218
 
      n = (size_t)ret;
219
 
      size_t written = 0;
220
 
      while(written < n){
221
 
        ret = write(STDOUT_FILENO, buffer + written, n - written);
222
 
        if(ret < 0){
223
 
          perror("write");
224
 
          status = EXIT_FAILURE;
225
 
          break;
226
 
        }
227
 
        written += (size_t)ret;
228
 
      }
229
147
      break;
230
148
    }
 
149
    // ret == 0 makes no other sence than to retry to read from stdin
231
150
    if (ret < 0){
232
151
      if (errno != EINTR and not feof(stdin)){
233
152
        perror("getline");
235
154
        break;
236
155
      }
237
156
    }
238
 
    /* if(ret == 0), then the only sensible thing to do is to retry to
239
 
       read from stdin */
240
157
    fputc('\n', stderr);
241
 
    if(debug and not quit_now){
242
 
      /* If quit_now is true, we were interrupted by a signal, and
243
 
         will print that later, so no need to show this too. */
244
 
      fprintf(stderr, "getline() returned 0, retrying.\n");
245
 
    }
246
158
  }
247
 
  
 
159
 
248
160
  if (debug){
249
161
    fprintf(stderr, "Restoring terminal attributes\n");
250
162
  }
251
163
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
252
164
    perror("tcsetattr+echo");
253
165
  }
254
 
  
 
166
 
255
167
  if (debug){
256
 
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
257
 
            status);
 
168
    fprintf(stderr, "%s is exiting\n", argv[0]);
258
169
  }
259
170
  
260
171
  return status;