/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 -*- */
 
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
 
1
26
#define _GNU_SOURCE             /* getline() */
2
 
#define _FORTIFY_SOURCE 2
 
27
 
3
28
#include <termios.h>            /* struct termios, tcsetattr(),
4
29
                                   TCSAFLUSH, tcgetattr(), ECHO */
5
30
#include <unistd.h>             /* struct termios, tcsetattr(),
9
34
                                   sigaction, sigemptyset(),
10
35
                                   sigaction(), sigaddset(), SIGINT,
11
36
                                   SIGQUIT, SIGHUP, SIGTERM */
12
 
#include <stddef.h>             /* NULL, size_t */
 
37
#include <stddef.h>             /* NULL, size_t, ssize_t */
13
38
#include <sys/types.h>          /* ssize_t */
14
 
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE */
 
39
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
 
40
                                   getopt_long, getenv() */
15
41
#include <stdio.h>              /* fprintf(), stderr, getline(),
16
42
                                   stdin, feof(), perror(), fputc(),
17
 
                                   stdout */
 
43
                                   stdout, getopt_long */
18
44
#include <errno.h>              /* errno, EINVAL */
19
45
#include <iso646.h>             /* or, not */
20
46
#include <stdbool.h>            /* bool, false, true */
21
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 */
22
53
 
23
54
volatile bool quit_now = false;
24
55
bool debug = false;
 
56
const char *argp_program_version = "password-prompt " VERSION;
 
57
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
25
58
 
26
 
void termination_handler(int signum){
 
59
static void termination_handler(__attribute__((unused))int signum){
27
60
  quit_now = true;
28
61
}
29
62
 
30
63
int main(int argc, char **argv){
31
 
  ssize_t ret = -1;
 
64
  ssize_t ret;
32
65
  size_t n;
33
66
  struct termios t_new, t_old;
34
67
  char *buffer = NULL;
 
68
  char *prefix = NULL;
35
69
  int status = EXIT_SUCCESS;
36
70
  struct sigaction old_action,
37
71
    new_action = { .sa_handler = termination_handler,
38
72
                   .sa_flags = 0 };
39
 
  const char db[] = "--debug";
40
 
  char *basename = rindex(argv[0], '/');
41
 
  if(basename == NULL){
42
 
    basename = argv[0];
43
 
  } else {
44
 
    basename++;
45
 
  }
46
 
 
47
 
  char *program_name = malloc(strlen(basename) + sizeof(db));
48
 
  if (program_name == NULL){
49
 
    perror("argv[0]");
50
 
    return EXIT_FAILURE;
51
 
  }
52
 
    
53
 
  program_name[0] = '\0';
54
 
    
55
 
  for (int i = 1; i < argc; i++){
56
 
    if (not strncmp(argv[i], db, 5)){
57
 
      strcat(strcat(strcat(program_name, db ), "="), basename);
58
 
      if(not strcmp(argv[i], db) or not strcmp(argv[i], program_name)){
 
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:
59
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;
60
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;
61
112
    }
62
113
  }
63
 
  free(program_name);
64
 
 
 
114
    
65
115
  if (debug){
66
116
    fprintf(stderr, "Starting %s\n", argv[0]);
67
117
  }
70
120
  }
71
121
  
72
122
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
 
123
    perror("tcgetattr");
73
124
    return EXIT_FAILURE;
74
125
  }
75
126
  
76
127
  sigemptyset(&new_action.sa_mask);
77
128
  sigaddset(&new_action.sa_mask, SIGINT);
78
 
  sigaddset(&new_action.sa_mask, SIGQUIT);
79
129
  sigaddset(&new_action.sa_mask, SIGHUP);
80
130
  sigaddset(&new_action.sa_mask, SIGTERM);
81
 
  sigaction(SIGINT, NULL, &old_action);
82
 
  if (old_action.sa_handler != SIG_IGN)
83
 
    sigaction(SIGINT, &new_action, NULL);
84
 
  sigaction(SIGQUIT, NULL, &old_action);
85
 
  if (old_action.sa_handler != SIG_IGN)
86
 
    sigaction(SIGQUIT, &new_action, NULL);
87
 
  sigaction(SIGHUP, NULL, &old_action);
88
 
  if (old_action.sa_handler != SIG_IGN)
89
 
    sigaction(SIGHUP, &new_action, NULL);
90
 
  sigaction(SIGTERM, NULL, &old_action);
91
 
  if (old_action.sa_handler != SIG_IGN)
92
 
    sigaction(SIGTERM, &new_action, NULL);
93
 
 
 
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
  
94
168
  
95
169
  if (debug){
96
170
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
108
182
  }
109
183
  while(true){
110
184
    if (quit_now){
 
185
      if(debug){
 
186
        fprintf(stderr, "Interrupted by signal, exiting.\n");
 
187
      }
111
188
      status = EXIT_FAILURE;
112
189
      break;
113
190
    }
114
 
    fprintf(stderr, "Password: ");
 
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
    }
115
215
    ret = getline(&buffer, &n, stdin);
116
216
    if (ret > 0){
117
 
      fprintf(stdout, "%s", buffer);
118
217
      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
      }
119
235
      break;
120
236
    }
121
 
    // ret == 0 makes no other sence than to retry to read from stdin
122
237
    if (ret < 0){
123
238
      if (errno != EINTR and not feof(stdin)){
124
239
        perror("getline");
126
241
        break;
127
242
      }
128
243
    }
 
244
    /* if(ret == 0), then the only sensible thing to do is to retry to
 
245
       read from stdin */
129
246
    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
    }
130
252
  }
131
253
 
 
254
  free(buffer);
 
255
  
132
256
  if (debug){
133
257
    fprintf(stderr, "Restoring terminal attributes\n");
134
258
  }
135
259
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
136
260
    perror("tcsetattr+echo");
137
261
  }
138
 
 
 
262
  
139
263
  if (debug){
140
 
    fprintf(stderr, "%s is exiting\n", argv[0]);
 
264
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
 
265
            status);
 
266
  }
 
267
  if(status == EXIT_SUCCESS){
 
268
    fputc('\n', stderr);
141
269
  }
142
270
  
143
271
  return status;