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

  • Committer: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support:
Pluginbased client handler
rewritten Mandos client
       Avahi instead of udp server discovery
       openpgp encrypted key support
Passprompt stand alone application for direct console input
Added logging for Mandos server

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8; mode: c; mode: orgtbl -*- */
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
7
 
 * 
8
 
 * This program is free software: you can redistribute it and/or
9
 
 * modify it under the terms of the GNU General Public License as
10
 
 * published by the Free Software Foundation, either version 3 of the
11
 
 * License, or (at your option) any later version.
12
 
 * 
13
 
 * This program is distributed in the hope that it will be useful, but
14
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 
 * General Public License for more details.
17
 
 * 
18
 
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program.  If not, see
20
 
 * <http://www.gnu.org/licenses/>.
21
 
 * 
22
 
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
23
 
 * <https://www.fukt.bsnet.se/~teddy/>.
24
 
 */
25
 
 
26
1
#define _GNU_SOURCE             /* getline() */
27
 
 
 
2
#define _FORTIFY_SOURCE 2
28
3
#include <termios.h>            /* struct termios, tcsetattr(),
29
4
                                   TCSAFLUSH, tcgetattr(), ECHO */
30
5
#include <unistd.h>             /* struct termios, tcsetattr(),
33
8
#include <signal.h>             /* sig_atomic_t, raise(), struct
34
9
                                   sigaction, sigemptyset(),
35
10
                                   sigaction(), sigaddset(), SIGINT,
36
 
                                   SIGQUIT, SIGHUP, SIGTERM,
37
 
                                   raise() */
38
 
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
11
                                   SIGQUIT, SIGHUP, SIGTERM */
 
12
#include <stddef.h>             /* NULL, size_t */
39
13
#include <sys/types.h>          /* ssize_t */
40
 
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
41
 
                                   getopt_long, getenv() */
 
14
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE */
42
15
#include <stdio.h>              /* fprintf(), stderr, getline(),
43
16
                                   stdin, feof(), perror(), fputc(),
44
 
                                   stdout, getopt_long */
 
17
                                   stdout */
45
18
#include <errno.h>              /* errno, EINVAL */
46
19
#include <iso646.h>             /* or, not */
47
20
#include <stdbool.h>            /* bool, false, true */
48
 
#include <string.h>             /* strlen, rindex, strncmp, strcmp */
49
 
#include <argp.h>               /* struct argp_option, struct
50
 
                                   argp_state, struct argp,
51
 
                                   argp_parse(), error_t,
52
 
                                   ARGP_KEY_ARG, ARGP_KEY_END,
53
 
                                   ARGP_ERR_UNKNOWN */
54
 
 
55
 
volatile sig_atomic_t quit_now = 0;
56
 
int signal_received;
57
 
bool debug = false;
58
 
const char *argp_program_version = "password-prompt " VERSION;
59
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
60
 
 
61
 
static void termination_handler(int signum){
62
 
  if(quit_now){
63
 
    return;
64
 
  }
65
 
  quit_now = 1;
66
 
  signal_received = signum;
 
21
 
 
22
volatile bool quit_now = false;
 
23
 
 
24
void termination_handler(int signum){
 
25
  quit_now = true;
67
26
}
68
27
 
69
28
int main(int argc, char **argv){
70
 
  ssize_t ret;
 
29
  ssize_t ret = -1;
71
30
  size_t n;
72
31
  struct termios t_new, t_old;
73
32
  char *buffer = NULL;
74
 
  char *prefix = NULL;
75
33
  int status = EXIT_SUCCESS;
76
34
  struct sigaction old_action,
77
35
    new_action = { .sa_handler = termination_handler,
78
36
                   .sa_flags = 0 };
79
 
  {
80
 
    struct argp_option options[] = {
81
 
      { .name = "prefix", .key = 'p',
82
 
        .arg = "PREFIX", .flags = 0,
83
 
        .doc = "Prefix shown before the prompt", .group = 2 },
84
 
      { .name = "debug", .key = 128,
85
 
        .doc = "Debug mode", .group = 3 },
86
 
      { .name = NULL }
87
 
    };
88
 
    
89
 
    error_t parse_opt (int key, char *arg, struct argp_state *state){
90
 
      switch (key){
91
 
      case 'p':
92
 
        prefix = arg;
93
 
        break;
94
 
      case 128:
95
 
        debug = true;
96
 
        break;
97
 
      case ARGP_KEY_ARG:
98
 
        argp_usage(state);
99
 
        break;
100
 
      case ARGP_KEY_END:
101
 
        break;
102
 
      default:
103
 
        return ARGP_ERR_UNKNOWN;
104
 
      }
105
 
      return 0;
106
 
    }
107
 
    
108
 
    struct argp argp = { .options = options, .parser = parse_opt,
109
 
                         .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){
114
 
      fprintf(stderr, "Unknown error while parsing arguments\n");
115
 
      return EXIT_FAILURE;
116
 
    }
117
 
  }
118
 
  
119
 
  if(debug){
120
 
    fprintf(stderr, "Starting %s\n", argv[0]);
121
 
  }
122
 
  if(debug){
123
 
    fprintf(stderr, "Storing current terminal attributes\n");
124
 
  }
125
 
  
126
 
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
127
 
    perror("tcgetattr");
 
37
  
 
38
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
128
39
    return EXIT_FAILURE;
129
40
  }
130
41
  
131
42
  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
 
  */
151
 
  ret = sigaction(SIGINT, NULL, &old_action);
152
 
  if(ret == -1){
153
 
    perror("sigaction");
154
 
    return EXIT_FAILURE;
155
 
  }
156
 
  if(old_action.sa_handler != SIG_IGN){
157
 
    ret = sigaction(SIGINT, &new_action, NULL);
158
 
    if(ret == -1){
159
 
      perror("sigaction");
160
 
      return EXIT_FAILURE;
161
 
    }
162
 
  }
163
 
  ret = sigaction(SIGHUP, NULL, &old_action);
164
 
  if(ret == -1){
165
 
    perror("sigaction");
166
 
    return EXIT_FAILURE;
167
 
  }
168
 
  if(old_action.sa_handler != SIG_IGN){
169
 
    ret = sigaction(SIGHUP, &new_action, NULL);
170
 
    if(ret == -1){
171
 
      perror("sigaction");
172
 
      return EXIT_FAILURE;
173
 
    }
174
 
  }
175
 
  ret = sigaction(SIGTERM, NULL, &old_action);
176
 
  if(ret == -1){
177
 
    perror("sigaction");
178
 
    return EXIT_FAILURE;
179
 
  }
180
 
  if(old_action.sa_handler != SIG_IGN){
181
 
    ret = sigaction(SIGTERM, &new_action, NULL);
182
 
    if(ret == -1){
183
 
      perror("sigaction");
184
 
      return EXIT_FAILURE;
185
 
    }
186
 
  }
187
 
  
188
 
  
189
 
  if(debug){
190
 
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
191
 
  }
 
43
  sigaddset(&new_action.sa_mask, SIGINT);
 
44
  sigaddset(&new_action.sa_mask, SIGQUIT);
 
45
  sigaddset(&new_action.sa_mask, SIGHUP);
 
46
  sigaddset(&new_action.sa_mask, SIGTERM);
 
47
  sigaction(SIGINT, NULL, &old_action);
 
48
  if (old_action.sa_handler != SIG_IGN)
 
49
    sigaction(SIGINT, &new_action, NULL);
 
50
  sigaction(SIGQUIT, NULL, &old_action);
 
51
  if (old_action.sa_handler != SIG_IGN)
 
52
    sigaction(SIGQUIT, &new_action, NULL);
 
53
  sigaction(SIGHUP, NULL, &old_action);
 
54
  if (old_action.sa_handler != SIG_IGN)
 
55
    sigaction(SIGHUP, &new_action, NULL);
 
56
  sigaction(SIGTERM, NULL, &old_action);
 
57
  if (old_action.sa_handler != SIG_IGN)
 
58
    sigaction(SIGTERM, &new_action, NULL);
192
59
  
193
60
  t_new = t_old;
194
61
  t_new.c_lflag &= ~ECHO;
195
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
 
62
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
196
63
    perror("tcsetattr-echo");
197
64
    return EXIT_FAILURE;
198
65
  }
199
 
 
200
 
  if(debug){
201
 
    fprintf(stderr, "Waiting for input from stdin \n");
202
 
  }
 
66
  
203
67
  while(true){
204
 
    if(quit_now){
205
 
      if(debug){
206
 
        fprintf(stderr, "Interrupted by signal, exiting.\n");
207
 
      }
 
68
    if (quit_now){
208
69
      status = EXIT_FAILURE;
209
70
      break;
210
71
    }
211
 
 
212
 
    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
 
    }
 
72
    fprintf(stderr, "Password: ");
235
73
    ret = getline(&buffer, &n, stdin);
236
 
    if(ret > 0){
 
74
    if (ret > 0){
 
75
      fprintf(stdout, "%s", buffer);
237
76
      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
77
      break;
256
78
    }
257
 
    if(ret < 0){
258
 
      if(errno != EINTR and not feof(stdin)){
 
79
    // ret == 0 makes no other sence than to retry to read from stdin
 
80
    if (ret < 0){
 
81
      if (errno != EINTR and not feof(stdin)){
259
82
        perror("getline");
260
83
        status = EXIT_FAILURE;
261
84
        break;
262
85
      }
263
86
    }
264
 
    /* if(ret == 0), then the only sensible thing to do is to retry to
265
 
       read from stdin */
266
87
    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
 
  }
273
 
  
274
 
  free(buffer);
275
 
  
276
 
  if(debug){
277
 
    fprintf(stderr, "Restoring terminal attributes\n");
278
 
  }
279
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
88
  }
 
89
 
 
90
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
280
91
    perror("tcsetattr+echo");
281
92
  }
282
93
  
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);
299
 
  }
300
 
  
301
94
  return status;
302
95
}