/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 -*- */
2
 
/*
3
 
 * Passprompt - Read a password from the terminal and print it
4
 
 *
5
 
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
6
 
 * 
7
 
 * This program is free software: you can redistribute it and/or
8
 
 * modify it under the terms of the GNU General Public License as
9
 
 * published by the Free Software Foundation, either version 3 of the
10
 
 * License, or (at your option) any later version.
11
 
 * 
12
 
 * This program is distributed in the hope that it will be useful, but
13
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 
 * General Public License for more details.
16
 
 * 
17
 
 * You should have received a copy of the GNU General Public License
18
 
 * along with this program.  If not, see
19
 
 * <http://www.gnu.org/licenses/>.
20
 
 * 
21
 
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
22
 
 * <https://www.fukt.bsnet.se/~teddy/>.
23
 
 */
24
 
 
25
1
#define _GNU_SOURCE             /* getline() */
26
 
 
 
2
#define _FORTIFY_SOURCE 2
27
3
#include <termios.h>            /* struct termios, tcsetattr(),
28
4
                                   TCSAFLUSH, tcgetattr(), ECHO */
29
5
#include <unistd.h>             /* struct termios, tcsetattr(),
33
9
                                   sigaction, sigemptyset(),
34
10
                                   sigaction(), sigaddset(), SIGINT,
35
11
                                   SIGQUIT, SIGHUP, SIGTERM */
36
 
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
12
#include <stddef.h>             /* NULL, size_t */
37
13
#include <sys/types.h>          /* ssize_t */
38
 
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
39
 
                                   getopt_long, getenv() */
 
14
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE */
40
15
#include <stdio.h>              /* fprintf(), stderr, getline(),
41
16
                                   stdin, feof(), perror(), fputc(),
42
 
                                   stdout, getopt_long */
 
17
                                   stdout */
43
18
#include <errno.h>              /* errno, EINVAL */
44
19
#include <iso646.h>             /* or, not */
45
20
#include <stdbool.h>            /* bool, false, true */
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 */
52
21
 
53
22
volatile bool quit_now = false;
54
 
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
23
 
58
 
static void termination_handler(__attribute__((unused))int signum){
 
24
void termination_handler(int signum){
59
25
  quit_now = true;
60
26
}
61
27
 
62
28
int main(int argc, char **argv){
63
 
  ssize_t ret;
 
29
  ssize_t ret = -1;
64
30
  size_t n;
65
31
  struct termios t_new, t_old;
66
32
  char *buffer = NULL;
67
 
  char *prefix = NULL;
68
33
  int status = EXIT_SUCCESS;
69
34
  struct sigaction old_action,
70
35
    new_action = { .sa_handler = termination_handler,
71
36
                   .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;
101
 
    }
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;
111
 
    }
112
 
  }
113
 
    
114
 
  if (debug){
115
 
    fprintf(stderr, "Starting %s\n", argv[0]);
116
 
  }
117
 
  if (debug){
118
 
    fprintf(stderr, "Storing current terminal attributes\n");
119
 
  }
120
37
  
121
38
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
122
 
    perror("tcgetattr");
123
39
    return EXIT_FAILURE;
124
40
  }
125
41
  
126
42
  sigemptyset(&new_action.sa_mask);
127
43
  sigaddset(&new_action.sa_mask, SIGINT);
 
44
  sigaddset(&new_action.sa_mask, SIGQUIT);
128
45
  sigaddset(&new_action.sa_mask, SIGHUP);
129
46
  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
 
  
167
 
  
168
 
  if (debug){
169
 
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
170
 
  }
 
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);
171
59
  
172
60
  t_new = t_old;
173
61
  t_new.c_lflag &= ~ECHO;
175
63
    perror("tcsetattr-echo");
176
64
    return EXIT_FAILURE;
177
65
  }
178
 
 
179
 
  if (debug){
180
 
    fprintf(stderr, "Waiting for input from stdin \n");
181
 
  }
 
66
  
182
67
  while(true){
183
68
    if (quit_now){
184
 
      if(debug){
185
 
        fprintf(stderr, "Interrupted by signal, exiting.\n");
186
 
      }
187
69
      status = EXIT_FAILURE;
188
70
      break;
189
71
    }
190
 
 
191
 
    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
 
    }
 
72
    fprintf(stderr, "Password: ");
214
73
    ret = getline(&buffer, &n, stdin);
215
74
    if (ret > 0){
 
75
      fprintf(stdout, "%s", buffer);
216
76
      status = EXIT_SUCCESS;
217
 
      /* Make n = data size instead of allocated buffer size */
218
 
      n = (size_t)ret;
219
 
      /* Strip final newline */
220
 
      if(n>0 and buffer[n-1] == '\n'){
221
 
        buffer[n-1] = '\0';     /* not strictly necessary */
222
 
        n--;
223
 
      }
224
 
      size_t written = 0;
225
 
      while(written < n){
226
 
        ret = write(STDOUT_FILENO, buffer + written, n - written);
227
 
        if(ret < 0){
228
 
          perror("write");
229
 
          status = EXIT_FAILURE;
230
 
          break;
231
 
        }
232
 
        written += (size_t)ret;
233
 
      }
234
77
      break;
235
78
    }
 
79
    // ret == 0 makes no other sence than to retry to read from stdin
236
80
    if (ret < 0){
237
81
      if (errno != EINTR and not feof(stdin)){
238
82
        perror("getline");
240
84
        break;
241
85
      }
242
86
    }
243
 
    /* if(ret == 0), then the only sensible thing to do is to retry to
244
 
       read from stdin */
245
87
    fputc('\n', stderr);
246
 
    if(debug and not quit_now){
247
 
      /* If quit_now is true, we were interrupted by a signal, and
248
 
         will print that later, so no need to show this too. */
249
 
      fprintf(stderr, "getline() returned 0, retrying.\n");
250
 
    }
251
88
  }
252
89
 
253
 
  free(buffer);
254
 
  
255
 
  if (debug){
256
 
    fprintf(stderr, "Restoring terminal attributes\n");
257
 
  }
258
90
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
259
91
    perror("tcsetattr+echo");
260
92
  }
261
93
  
262
 
  if (debug){
263
 
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
264
 
            status);
265
 
  }
266
 
  if(status == EXIT_SUCCESS){
267
 
    fputc('\n', stderr);
268
 
  }
269
 
  
270
94
  return status;
271
95
}