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