/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
 
 * 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(),
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
 
      switch (key) {
85
 
      case 'p':
86
 
        prefix = arg;
87
 
        break;
88
 
      case 128:
89
 
        debug = true;
90
 
        break;
91
 
      case ARGP_KEY_ARG:
92
 
        argp_usage(state);
93
 
        break;
94
 
      case ARGP_KEY_END:
95
 
        break;
96
 
      default:
97
 
        return ARGP_ERR_UNKNOWN;
98
 
      }
99
 
      return 0;
100
 
    }
101
 
    
102
 
    struct argp argp = { .options = options, .parser = parse_opt,
103
 
                         .args_doc = "",
104
 
                         .doc = "Mandos password-prompt -- Read and"
105
 
                         " output a password" };
106
 
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
107
 
    if(ret == ARGP_ERR_UNKNOWN){
108
 
      fprintf(stderr, "Unknown error while parsing arguments\n");
109
 
      return EXIT_FAILURE;
110
 
    }
111
 
  }
112
 
  
113
 
  if(debug){
114
 
    fprintf(stderr, "Starting %s\n", argv[0]);
115
 
  }
116
 
  if(debug){
117
 
    fprintf(stderr, "Storing current terminal attributes\n");
118
 
  }
119
 
  
120
 
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
121
 
    perror("tcgetattr");
 
37
  
 
38
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
122
39
    return EXIT_FAILURE;
123
40
  }
124
41
  
125
42
  sigemptyset(&new_action.sa_mask);
126
43
  sigaddset(&new_action.sa_mask, SIGINT);
 
44
  sigaddset(&new_action.sa_mask, SIGQUIT);
127
45
  sigaddset(&new_action.sa_mask, SIGHUP);
128
46
  sigaddset(&new_action.sa_mask, SIGTERM);
129
 
  ret = sigaction(SIGINT, NULL, &old_action);
130
 
  if(ret == -1){
131
 
    perror("sigaction");
132
 
    return EXIT_FAILURE;
133
 
  }
134
 
  if(old_action.sa_handler != SIG_IGN){
135
 
    ret = sigaction(SIGINT, &new_action, NULL);
136
 
    if(ret == -1){
137
 
      perror("sigaction");
138
 
      return EXIT_FAILURE;
139
 
    }
140
 
  }
141
 
  ret = sigaction(SIGHUP, NULL, &old_action);
142
 
  if(ret == -1){
143
 
    perror("sigaction");
144
 
    return EXIT_FAILURE;
145
 
  }
146
 
  if(old_action.sa_handler != SIG_IGN){
147
 
    ret = sigaction(SIGHUP, &new_action, NULL);
148
 
    if(ret == -1){
149
 
      perror("sigaction");
150
 
      return EXIT_FAILURE;
151
 
    }
152
 
  }
153
 
  ret = sigaction(SIGTERM, NULL, &old_action);
154
 
  if(ret == -1){
155
 
    perror("sigaction");
156
 
    return EXIT_FAILURE;
157
 
  }
158
 
  if(old_action.sa_handler != SIG_IGN){
159
 
    ret = sigaction(SIGTERM, &new_action, NULL);
160
 
    if(ret == -1){
161
 
      perror("sigaction");
162
 
      return EXIT_FAILURE;
163
 
    }
164
 
  }
165
 
  
166
 
  
167
 
  if(debug){
168
 
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
169
 
  }
 
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);
170
59
  
171
60
  t_new = t_old;
172
61
  t_new.c_lflag &= ~ECHO;
173
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
 
62
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
174
63
    perror("tcsetattr-echo");
175
64
    return EXIT_FAILURE;
176
65
  }
177
 
 
178
 
  if(debug){
179
 
    fprintf(stderr, "Waiting for input from stdin \n");
180
 
  }
 
66
  
181
67
  while(true){
182
 
    if(quit_now){
183
 
      if(debug){
184
 
        fprintf(stderr, "Interrupted by signal, exiting.\n");
185
 
      }
 
68
    if (quit_now){
186
69
      status = EXIT_FAILURE;
187
70
      break;
188
71
    }
189
 
 
190
 
    if(prefix){
191
 
      fprintf(stderr, "%s ", prefix);
192
 
    }
193
 
    {
194
 
      const char *cryptsource = getenv("cryptsource");
195
 
      const char *crypttarget = getenv("crypttarget");
196
 
      const char *const prompt
197
 
        = "Enter passphrase to unlock the disk";
198
 
      if(cryptsource == NULL){
199
 
        if(crypttarget == NULL){
200
 
          fprintf(stderr, "%s: ", prompt);
201
 
        } else {
202
 
          fprintf(stderr, "%s (%s): ", prompt, crypttarget);
203
 
        }
204
 
      } else {
205
 
        if(crypttarget == NULL){
206
 
          fprintf(stderr, "%s %s: ", prompt, cryptsource);
207
 
        } else {
208
 
          fprintf(stderr, "%s %s (%s): ", prompt, cryptsource,
209
 
                  crypttarget);
210
 
        }
211
 
      }
212
 
    }
 
72
    fprintf(stderr, "Password: ");
213
73
    ret = getline(&buffer, &n, stdin);
214
 
    if(ret > 0){
 
74
    if (ret > 0){
 
75
      fprintf(stdout, "%s", buffer);
215
76
      status = EXIT_SUCCESS;
216
 
      /* Make n = data size instead of allocated buffer size */
217
 
      n = (size_t)ret;
218
 
      /* Strip final newline */
219
 
      if(n>0 and buffer[n-1] == '\n'){
220
 
        buffer[n-1] = '\0';     /* not strictly necessary */
221
 
        n--;
222
 
      }
223
 
      size_t written = 0;
224
 
      while(written < n){
225
 
        ret = write(STDOUT_FILENO, buffer + written, n - written);
226
 
        if(ret < 0){
227
 
          perror("write");
228
 
          status = EXIT_FAILURE;
229
 
          break;
230
 
        }
231
 
        written += (size_t)ret;
232
 
      }
233
77
      break;
234
78
    }
235
 
    if(ret < 0){
236
 
      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)){
237
82
        perror("getline");
238
83
        status = EXIT_FAILURE;
239
84
        break;
240
85
      }
241
86
    }
242
 
    /* if(ret == 0), then the only sensible thing to do is to retry to
243
 
       read from stdin */
244
87
    fputc('\n', stderr);
245
 
    if(debug and not quit_now){
246
 
      /* If quit_now is true, we were interrupted by a signal, and
247
 
         will print that later, so no need to show this too. */
248
 
      fprintf(stderr, "getline() returned 0, retrying.\n");
249
 
    }
250
 
  }
251
 
  
252
 
  free(buffer);
253
 
  
254
 
  if(debug){
255
 
    fprintf(stderr, "Restoring terminal attributes\n");
256
 
  }
257
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
88
  }
 
89
 
 
90
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
258
91
    perror("tcsetattr+echo");
259
92
  }
260
93
  
261
 
  if(debug){
262
 
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
263
 
            status);
264
 
  }
265
 
  if(status == EXIT_SUCCESS){
266
 
    fputc('\n', stderr);
267
 
  }
268
 
  
269
94
  return status;
270
95
}