/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/password-prompt.c

  • Committer: Teddy Hogeborn
  • Date: 2008-12-10 01:26:02 UTC
  • mfrom: (237.1.2 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20081210012602-vhz3h75xkj24t340
First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8; mode: c; mode: orgtbl -*- */
 
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Password-prompt - Read a password from the terminal and print it
 
3
 * Passprompt - Read a password from the terminal and print it
4
4
 * 
5
 
 * Copyright © 2008,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 Björn Påhlsson
 
5
 * Copyright © 2008 Teddy Hogeborn
 
6
 * Copyright © 2008 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
19
19
 * along with this program.  If not, see
20
20
 * <http://www.gnu.org/licenses/>.
21
21
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
22
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
23
 * <https://www.fukt.bsnet.se/~teddy/>.
23
24
 */
24
25
 
25
26
#define _GNU_SOURCE             /* getline() */
32
33
#include <signal.h>             /* sig_atomic_t, raise(), struct
33
34
                                   sigaction, sigemptyset(),
34
35
                                   sigaction(), sigaddset(), SIGINT,
35
 
                                   SIGQUIT, SIGHUP, SIGTERM,
36
 
                                   raise() */
 
36
                                   SIGQUIT, SIGHUP, SIGTERM */
37
37
#include <stddef.h>             /* NULL, size_t, ssize_t */
38
38
#include <sys/types.h>          /* ssize_t */
39
39
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
40
 
                                   getenv() */
 
40
                                   getopt_long, getenv() */
41
41
#include <stdio.h>              /* fprintf(), stderr, getline(),
42
 
                                   stdin, feof(), perror(), fputc()
43
 
                                */
44
 
#include <errno.h>              /* errno, EBADF, ENOTTY, EINVAL,
45
 
                                   EFAULT, EFBIG, EIO, ENOSPC, EINTR
46
 
                                */
 
42
                                   stdin, feof(), perror(), fputc(),
 
43
                                   stdout, getopt_long */
 
44
#include <errno.h>              /* errno, EINVAL */
47
45
#include <iso646.h>             /* or, not */
48
46
#include <stdbool.h>            /* bool, false, true */
49
47
#include <string.h>             /* strlen, rindex, strncmp, strcmp */
52
50
                                   argp_parse(), error_t,
53
51
                                   ARGP_KEY_ARG, ARGP_KEY_END,
54
52
                                   ARGP_ERR_UNKNOWN */
55
 
#include <sysexits.h>           /* EX_SOFTWARE, EX_OSERR,
56
 
                                   EX_UNAVAILABLE, EX_IOERR, EX_OK */
57
53
 
58
 
volatile sig_atomic_t quit_now = 0;
59
 
int signal_received;
 
54
volatile bool quit_now = false;
60
55
bool debug = false;
61
56
const char *argp_program_version = "password-prompt " VERSION;
62
57
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
63
58
 
64
 
static void termination_handler(int signum){
65
 
  if(quit_now){
66
 
    return;
67
 
  }
68
 
  quit_now = 1;
69
 
  signal_received = signum;
 
59
static void termination_handler(__attribute__((unused))int signum){
 
60
  quit_now = true;
70
61
}
71
62
 
72
63
int main(int argc, char **argv){
86
77
        .doc = "Prefix shown before the prompt", .group = 2 },
87
78
      { .name = "debug", .key = 128,
88
79
        .doc = "Debug mode", .group = 3 },
89
 
      /*
90
 
       * These reproduce what we would get without ARGP_NO_HELP
91
 
       */
92
 
      { .name = "help", .key = '?',
93
 
        .doc = "Give this help list", .group = -1 },
94
 
      { .name = "usage", .key = -3,
95
 
        .doc = "Give a short usage message", .group = -1 },
96
 
      { .name = "version", .key = 'V',
97
 
        .doc = "Print program version", .group = -1 },
98
80
      { .name = NULL }
99
81
    };
100
 
    
101
 
    error_t parse_opt (int key, char *arg, struct argp_state *state){
102
 
      errno = 0;
103
 
      switch (key){
 
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) {
104
87
      case 'p':
105
88
        prefix = arg;
106
89
        break;
107
90
      case 128:
108
91
        debug = true;
109
92
        break;
110
 
        /*
111
 
         * These reproduce what we would get without ARGP_NO_HELP
112
 
         */
113
 
      case '?':                 /* --help */
114
 
        argp_state_help(state, state->out_stream,
115
 
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
116
 
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
117
 
      case -3:                  /* --usage */
118
 
        argp_state_help(state, state->out_stream,
119
 
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
120
 
      case 'V':                 /* --version */
121
 
        fprintf(state->out_stream, "%s\n", argp_program_version);
122
 
        exit(argp_err_exit_status);
 
93
      case ARGP_KEY_ARG:
 
94
        argp_usage (state);
 
95
        break;
 
96
      case ARGP_KEY_END:
123
97
        break;
124
98
      default:
125
99
        return ARGP_ERR_UNKNOWN;
126
100
      }
127
 
      return errno;
 
101
      return 0;
128
102
    }
129
 
    
 
103
  
130
104
    struct argp argp = { .options = options, .parser = parse_opt,
131
105
                         .args_doc = "",
132
106
                         .doc = "Mandos password-prompt -- Read and"
133
107
                         " output a password" };
134
 
    ret = argp_parse(&argp, argc, argv,
135
 
                     ARGP_IN_ORDER | ARGP_NO_HELP, NULL, NULL);
136
 
    switch(ret){
137
 
    case 0:
138
 
      break;
139
 
    case ENOMEM:
140
 
    default:
141
 
      errno = ret;
142
 
      perror("argp_parse");
143
 
      return EX_OSERR;
144
 
    case EINVAL:
145
 
      return EX_USAGE;
 
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;
146
112
    }
147
113
  }
148
 
  
149
 
  if(debug){
 
114
    
 
115
  if (debug){
150
116
    fprintf(stderr, "Starting %s\n", argv[0]);
151
117
  }
152
 
  if(debug){
 
118
  if (debug){
153
119
    fprintf(stderr, "Storing current terminal attributes\n");
154
120
  }
155
121
  
156
 
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
157
 
    int e = errno;
 
122
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
158
123
    perror("tcgetattr");
159
 
    switch(e){
160
 
    case EBADF:
161
 
    case ENOTTY:
162
 
      return EX_UNAVAILABLE;
163
 
    default:
164
 
      return EX_OSERR;
165
 
    }
 
124
    return EXIT_FAILURE;
166
125
  }
167
126
  
168
127
  sigemptyset(&new_action.sa_mask);
169
 
  ret = sigaddset(&new_action.sa_mask, SIGINT);
170
 
  if(ret == -1){
171
 
    perror("sigaddset");
172
 
    return EX_OSERR;
173
 
  }
174
 
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
175
 
  if(ret == -1){
176
 
    perror("sigaddset");
177
 
    return EX_OSERR;
178
 
  }
179
 
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
180
 
  if(ret == -1){
181
 
    perror("sigaddset");
182
 
    return EX_OSERR;
183
 
  }
184
 
  /* Need to check if the handler is SIG_IGN before handling:
185
 
     | [[info:libc:Initial Signal Actions]] |
186
 
     | [[info:libc:Basic Signal Handling]]  |
187
 
  */
 
128
  sigaddset(&new_action.sa_mask, SIGINT);
 
129
  sigaddset(&new_action.sa_mask, SIGHUP);
 
130
  sigaddset(&new_action.sa_mask, SIGTERM);
188
131
  ret = sigaction(SIGINT, NULL, &old_action);
189
132
  if(ret == -1){
190
133
    perror("sigaction");
191
 
    return EX_OSERR;
 
134
    return EXIT_FAILURE;
192
135
  }
193
 
  if(old_action.sa_handler != SIG_IGN){
 
136
  if (old_action.sa_handler != SIG_IGN){
194
137
    ret = sigaction(SIGINT, &new_action, NULL);
195
138
    if(ret == -1){
196
139
      perror("sigaction");
197
 
      return EX_OSERR;
 
140
      return EXIT_FAILURE;
198
141
    }
199
142
  }
200
143
  ret = sigaction(SIGHUP, NULL, &old_action);
201
144
  if(ret == -1){
202
145
    perror("sigaction");
203
 
    return EX_OSERR;
 
146
    return EXIT_FAILURE;
204
147
  }
205
 
  if(old_action.sa_handler != SIG_IGN){
 
148
  if (old_action.sa_handler != SIG_IGN){
206
149
    ret = sigaction(SIGHUP, &new_action, NULL);
207
150
    if(ret == -1){
208
151
      perror("sigaction");
209
 
      return EX_OSERR;
 
152
      return EXIT_FAILURE;
210
153
    }
211
154
  }
212
155
  ret = sigaction(SIGTERM, NULL, &old_action);
213
156
  if(ret == -1){
214
157
    perror("sigaction");
215
 
    return EX_OSERR;
 
158
    return EXIT_FAILURE;
216
159
  }
217
 
  if(old_action.sa_handler != SIG_IGN){
 
160
  if (old_action.sa_handler != SIG_IGN){
218
161
    ret = sigaction(SIGTERM, &new_action, NULL);
219
162
    if(ret == -1){
220
163
      perror("sigaction");
221
 
      return EX_OSERR;
 
164
      return EXIT_FAILURE;
222
165
    }
223
166
  }
224
167
  
225
168
  
226
 
  if(debug){
 
169
  if (debug){
227
170
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
228
171
  }
229
172
  
230
173
  t_new = t_old;
231
 
  t_new.c_lflag &= ~(tcflag_t)ECHO;
232
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
233
 
    int e = errno;
 
174
  t_new.c_lflag &= ~ECHO;
 
175
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
234
176
    perror("tcsetattr-echo");
235
 
    switch(e){
236
 
    case EBADF:
237
 
    case ENOTTY:
238
 
      return EX_UNAVAILABLE;
239
 
    case EINVAL:
240
 
    default:
241
 
      return EX_OSERR;
242
 
    }
 
177
    return EXIT_FAILURE;
243
178
  }
244
 
  
245
 
  if(debug){
 
179
 
 
180
  if (debug){
246
181
    fprintf(stderr, "Waiting for input from stdin \n");
247
182
  }
248
183
  while(true){
249
 
    if(quit_now){
 
184
    if (quit_now){
250
185
      if(debug){
251
186
        fprintf(stderr, "Interrupted by signal, exiting.\n");
252
187
      }
278
213
      }
279
214
    }
280
215
    ret = getline(&buffer, &n, stdin);
281
 
    if(ret > 0){
 
216
    if (ret > 0){
282
217
      status = EXIT_SUCCESS;
283
218
      /* Make n = data size instead of allocated buffer size */
284
219
      n = (size_t)ret;
285
220
      /* Strip final newline */
286
 
      if(n > 0 and buffer[n-1] == '\n'){
 
221
      if(n>0 and buffer[n-1] == '\n'){
287
222
        buffer[n-1] = '\0';     /* not strictly necessary */
288
223
        n--;
289
224
      }
291
226
      while(written < n){
292
227
        ret = write(STDOUT_FILENO, buffer + written, n - written);
293
228
        if(ret < 0){
294
 
          int e = errno;
295
229
          perror("write");
296
 
          switch(e){
297
 
          case EBADF:
298
 
          case EFAULT:
299
 
          case EINVAL:
300
 
          case EFBIG:
301
 
          case EIO:
302
 
          case ENOSPC:
303
 
          default:
304
 
            status = EX_IOERR;
305
 
            break;
306
 
          case EINTR:
307
 
            status = EXIT_FAILURE;
308
 
            break;
309
 
          }
 
230
          status = EXIT_FAILURE;
310
231
          break;
311
232
        }
312
233
        written += (size_t)ret;
313
234
      }
314
 
      ret = close(STDOUT_FILENO);
315
 
      if(ret == -1){
316
 
        int e = errno;
317
 
        perror("close");
318
 
        switch(e){
319
 
        case EBADF:
320
 
          status = EX_OSFILE;
321
 
          break;
322
 
        case EIO:
323
 
        default:
324
 
          status = EX_IOERR;
325
 
          break;
326
 
        }
327
 
      }
328
235
      break;
329
236
    }
330
 
    if(ret < 0){
331
 
      int e = errno;
332
 
      if(errno != EINTR and not feof(stdin)){
 
237
    if (ret < 0){
 
238
      if (errno != EINTR and not feof(stdin)){
333
239
        perror("getline");
334
 
        switch(e){
335
 
        case EBADF:
336
 
          status = EX_UNAVAILABLE;
337
 
        case EIO:
338
 
        case EINVAL:
339
 
        default:
340
 
          status = EX_IOERR;
341
 
          break;
342
 
        }
 
240
        status = EXIT_FAILURE;
343
241
        break;
344
242
      }
345
243
    }
347
245
       read from stdin */
348
246
    fputc('\n', stderr);
349
247
    if(debug and not quit_now){
350
 
      /* If quit_now is nonzero, we were interrupted by a signal, and
 
248
      /* If quit_now is true, we were interrupted by a signal, and
351
249
         will print that later, so no need to show this too. */
352
250
      fprintf(stderr, "getline() returned 0, retrying.\n");
353
251
    }
354
252
  }
355
 
  
 
253
 
356
254
  free(buffer);
357
255
  
358
 
  if(debug){
 
256
  if (debug){
359
257
    fprintf(stderr, "Restoring terminal attributes\n");
360
258
  }
361
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
259
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
362
260
    perror("tcsetattr+echo");
363
261
  }
364
262
  
365
 
  if(quit_now){
366
 
    sigemptyset(&old_action.sa_mask);
367
 
    old_action.sa_handler = SIG_DFL;
368
 
    ret = sigaction(signal_received, &old_action, NULL);
369
 
    if(ret == -1){
370
 
      perror("sigaction");
371
 
    }
372
 
    raise(signal_received);
373
 
  }
374
 
  
375
 
  if(debug){
 
263
  if (debug){
376
264
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
377
265
            status);
378
266
  }
379
 
  if(status == EXIT_SUCCESS or status == EX_OK){
 
267
  if(status == EXIT_SUCCESS){
380
268
    fputc('\n', stderr);
381
269
  }
382
270