/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/mandos-client.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
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Mandos-client - get and decrypt data from a Mandos server
 
3
 * Mandos client - get and decrypt data from a Mandos server
4
4
 *
5
5
 * This program is partly derived from an example program for an Avahi
6
6
 * service browser, downloaded from
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
11
 * Everything else is
12
 
 * Copyright © 2008,2009 Teddy Hogeborn
13
 
 * Copyright © 2008,2009 Björn Påhlsson
 
12
 * Copyright © 2008 Teddy Hogeborn
 
13
 * Copyright © 2008 Björn Påhlsson
14
14
 * 
15
15
 * This program is free software: you can redistribute it and/or
16
16
 * modify it under the terms of the GNU General Public License as
36
36
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
37
37
 
38
38
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
39
 
                                   stdout, ferror(), sscanf */
 
39
                                   stdout, ferror() */
40
40
#include <stdint.h>             /* uint16_t, uint32_t */
41
41
#include <stddef.h>             /* NULL, size_t, ssize_t */
42
42
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
48
48
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
49
49
                                   sockaddr_in6, PF_INET6,
50
50
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
51
 
                                   uid_t, gid_t, open(), opendir(),
52
 
                                   DIR */
 
51
                                   uid_t, gid_t, open(), opendir(), DIR */
53
52
#include <sys/stat.h>           /* open() */
54
53
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
55
54
                                   struct in6_addr, inet_pton(),
56
55
                                   connect() */
57
56
#include <fcntl.h>              /* open() */
58
 
#include <dirent.h>             /* opendir(), struct dirent, readdir()
59
 
                                 */
60
 
#include <inttypes.h>           /* PRIu16, intmax_t, SCNdMAX */
 
57
#include <dirent.h>             /* opendir(), struct dirent, readdir() */
 
58
#include <inttypes.h>           /* PRIu16 */
61
59
#include <assert.h>             /* assert() */
62
60
#include <errno.h>              /* perror(), errno */
63
 
#include <time.h>               /* time(), nanosleep() */
 
61
#include <time.h>               /* time() */
64
62
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
65
63
                                   SIOCSIFFLAGS, if_indextoname(),
66
64
                                   if_nametoindex(), IF_NAMESIZE */
69
67
                                   getuid(), getgid(), setuid(),
70
68
                                   setgid() */
71
69
#include <arpa/inet.h>          /* inet_pton(), htons */
72
 
#include <iso646.h>             /* not, and, or */
 
70
#include <iso646.h>             /* not, and */
73
71
#include <argp.h>               /* struct argp_option, error_t, struct
74
72
                                   argp_state, struct argp,
75
73
                                   argp_parse(), ARGP_KEY_ARG,
76
74
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
77
 
#include <sys/klog.h>           /* klogctl() */
78
75
 
79
76
/* Avahi */
80
77
/* All Avahi types, constants and functions
93
90
                                   gnutls_*
94
91
                                   init_gnutls_session(),
95
92
                                   GNUTLS_* */
96
 
#include <gnutls/openpgp.h>
97
 
                          /* gnutls_certificate_set_openpgp_key_file(),
 
93
#include <gnutls/openpgp.h>     /* gnutls_certificate_set_openpgp_key_file(),
98
94
                                   GNUTLS_OPENPGP_FMT_BASE64 */
99
95
 
100
96
/* GPGME */
133
129
 */
134
130
size_t adjustbuffer(char **buffer, size_t buffer_length,
135
131
                  size_t buffer_capacity){
136
 
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
 
132
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
137
133
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
138
 
    if(buffer == NULL){
 
134
    if (buffer == NULL){
139
135
      return 0;
140
136
    }
141
137
    buffer_capacity += BUFFER_SIZE;
160
156
    int fd;
161
157
    gpgme_data_t pgp_data;
162
158
    
163
 
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
 
159
    fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
164
160
    if(fd == -1){
165
161
      perror("open");
166
162
      return false;
167
163
    }
168
164
    
169
165
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
170
 
    if(rc != GPG_ERR_NO_ERROR){
 
166
    if (rc != GPG_ERR_NO_ERROR){
171
167
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
172
168
              gpgme_strsource(rc), gpgme_strerror(rc));
173
169
      return false;
174
170
    }
175
171
    
176
172
    rc = gpgme_op_import(mc->ctx, pgp_data);
177
 
    if(rc != GPG_ERR_NO_ERROR){
 
173
    if (rc != GPG_ERR_NO_ERROR){
178
174
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
179
175
              gpgme_strsource(rc), gpgme_strerror(rc));
180
176
      return false;
181
177
    }
182
178
    
183
 
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
 
179
    ret = TEMP_FAILURE_RETRY(close(fd));
184
180
    if(ret == -1){
185
181
      perror("close");
186
182
    }
188
184
    return true;
189
185
  }
190
186
  
191
 
  if(debug){
 
187
  if (debug){
192
188
    fprintf(stderr, "Initialize gpgme\n");
193
189
  }
194
190
  
195
191
  /* Init GPGME */
196
192
  gpgme_check_version(NULL);
197
193
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
198
 
  if(rc != GPG_ERR_NO_ERROR){
 
194
  if (rc != GPG_ERR_NO_ERROR){
199
195
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
200
196
            gpgme_strsource(rc), gpgme_strerror(rc));
201
197
    return false;
202
198
  }
203
199
  
204
200
    /* Set GPGME home directory for the OpenPGP engine only */
205
 
  rc = gpgme_get_engine_info(&engine_info);
206
 
  if(rc != GPG_ERR_NO_ERROR){
 
201
  rc = gpgme_get_engine_info (&engine_info);
 
202
  if (rc != GPG_ERR_NO_ERROR){
207
203
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
208
204
            gpgme_strsource(rc), gpgme_strerror(rc));
209
205
    return false;
223
219
  
224
220
  /* Create new GPGME "context" */
225
221
  rc = gpgme_new(&(mc->ctx));
226
 
  if(rc != GPG_ERR_NO_ERROR){
 
222
  if (rc != GPG_ERR_NO_ERROR){
227
223
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
228
224
            gpgme_strsource(rc), gpgme_strerror(rc));
229
225
    return false;
230
226
  }
231
227
  
232
 
  if(not import_key(pubkey) or not import_key(seckey)){
 
228
  if (not import_key(pubkey) or not import_key(seckey)){
233
229
    return false;
234
230
  }
235
231
  
240
236
 * Decrypt OpenPGP data.
241
237
 * Returns -1 on error
242
238
 */
243
 
static ssize_t pgp_packet_decrypt(const mandos_context *mc,
244
 
                                  const char *cryptotext,
245
 
                                  size_t crypto_size,
246
 
                                  char **plaintext){
 
239
static ssize_t pgp_packet_decrypt (const mandos_context *mc,
 
240
                                   const char *cryptotext,
 
241
                                   size_t crypto_size,
 
242
                                   char **plaintext){
247
243
  gpgme_data_t dh_crypto, dh_plain;
248
244
  gpgme_error_t rc;
249
245
  ssize_t ret;
250
246
  size_t plaintext_capacity = 0;
251
247
  ssize_t plaintext_length = 0;
252
248
  
253
 
  if(debug){
 
249
  if (debug){
254
250
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
255
251
  }
256
252
  
257
253
  /* Create new GPGME data buffer from memory cryptotext */
258
254
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
259
255
                               0);
260
 
  if(rc != GPG_ERR_NO_ERROR){
 
256
  if (rc != GPG_ERR_NO_ERROR){
261
257
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
262
258
            gpgme_strsource(rc), gpgme_strerror(rc));
263
259
    return -1;
265
261
  
266
262
  /* Create new empty GPGME data buffer for the plaintext */
267
263
  rc = gpgme_data_new(&dh_plain);
268
 
  if(rc != GPG_ERR_NO_ERROR){
 
264
  if (rc != GPG_ERR_NO_ERROR){
269
265
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
270
266
            gpgme_strsource(rc), gpgme_strerror(rc));
271
267
    gpgme_data_release(dh_crypto);
275
271
  /* Decrypt data from the cryptotext data buffer to the plaintext
276
272
     data buffer */
277
273
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
278
 
  if(rc != GPG_ERR_NO_ERROR){
 
274
  if (rc != GPG_ERR_NO_ERROR){
279
275
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
280
276
            gpgme_strsource(rc), gpgme_strerror(rc));
281
277
    plaintext_length = -1;
282
 
    if(debug){
 
278
    if (debug){
283
279
      gpgme_decrypt_result_t result;
284
280
      result = gpgme_op_decrypt_result(mc->ctx);
285
 
      if(result == NULL){
 
281
      if (result == NULL){
286
282
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
287
283
      } else {
288
284
        fprintf(stderr, "Unsupported algorithm: %s\n",
315
311
  }
316
312
  
317
313
  /* Seek back to the beginning of the GPGME plaintext data buffer */
318
 
  if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
 
314
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
319
315
    perror("gpgme_data_seek");
320
316
    plaintext_length = -1;
321
317
    goto decrypt_end;
326
322
    plaintext_capacity = adjustbuffer(plaintext,
327
323
                                      (size_t)plaintext_length,
328
324
                                      plaintext_capacity);
329
 
    if(plaintext_capacity == 0){
 
325
    if (plaintext_capacity == 0){
330
326
        perror("adjustbuffer");
331
327
        plaintext_length = -1;
332
328
        goto decrypt_end;
335
331
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
336
332
                          BUFFER_SIZE);
337
333
    /* Print the data, if any */
338
 
    if(ret == 0){
 
334
    if (ret == 0){
339
335
      /* EOF */
340
336
      break;
341
337
    }
365
361
  return plaintext_length;
366
362
}
367
363
 
368
 
static const char * safer_gnutls_strerror(int value) {
369
 
  const char *ret = gnutls_strerror(value); /* Spurious warning from
370
 
                                               -Wunreachable-code */
371
 
  if(ret == NULL)
 
364
static const char * safer_gnutls_strerror (int value) {
 
365
  const char *ret = gnutls_strerror (value); /* Spurious warning */
 
366
  if (ret == NULL)
372
367
    ret = "(unknown)";
373
368
  return ret;
374
369
}
389
384
  }
390
385
  
391
386
  ret = gnutls_global_init();
392
 
  if(ret != GNUTLS_E_SUCCESS) {
393
 
    fprintf(stderr, "GnuTLS global_init: %s\n",
394
 
            safer_gnutls_strerror(ret));
 
387
  if (ret != GNUTLS_E_SUCCESS) {
 
388
    fprintf (stderr, "GnuTLS global_init: %s\n",
 
389
             safer_gnutls_strerror(ret));
395
390
    return -1;
396
391
  }
397
392
  
398
 
  if(debug){
 
393
  if (debug){
399
394
    /* "Use a log level over 10 to enable all debugging options."
400
395
     * - GnuTLS manual
401
396
     */
405
400
  
406
401
  /* OpenPGP credentials */
407
402
  gnutls_certificate_allocate_credentials(&mc->cred);
408
 
  if(ret != GNUTLS_E_SUCCESS){
409
 
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
410
 
                                                  * from
411
 
                                                  * -Wunreachable-code
412
 
                                                  */
413
 
            safer_gnutls_strerror(ret));
414
 
    gnutls_global_deinit();
 
403
  if (ret != GNUTLS_E_SUCCESS){
 
404
    fprintf (stderr, "GnuTLS memory error: %s\n", /* Spurious
 
405
                                                     warning */
 
406
             safer_gnutls_strerror(ret));
 
407
    gnutls_global_deinit ();
415
408
    return -1;
416
409
  }
417
410
  
424
417
  ret = gnutls_certificate_set_openpgp_key_file
425
418
    (mc->cred, pubkeyfilename, seckeyfilename,
426
419
     GNUTLS_OPENPGP_FMT_BASE64);
427
 
  if(ret != GNUTLS_E_SUCCESS) {
 
420
  if (ret != GNUTLS_E_SUCCESS) {
428
421
    fprintf(stderr,
429
422
            "Error[%d] while reading the OpenPGP key pair ('%s',"
430
423
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
435
428
  
436
429
  /* GnuTLS server initialization */
437
430
  ret = gnutls_dh_params_init(&mc->dh_params);
438
 
  if(ret != GNUTLS_E_SUCCESS) {
439
 
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
440
 
            " %s\n", safer_gnutls_strerror(ret));
 
431
  if (ret != GNUTLS_E_SUCCESS) {
 
432
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
 
433
             " %s\n", safer_gnutls_strerror(ret));
441
434
    goto globalfail;
442
435
  }
443
436
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
444
 
  if(ret != GNUTLS_E_SUCCESS) {
445
 
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
446
 
            safer_gnutls_strerror(ret));
 
437
  if (ret != GNUTLS_E_SUCCESS) {
 
438
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
 
439
             safer_gnutls_strerror(ret));
447
440
    goto globalfail;
448
441
  }
449
442
  
464
457
  int ret;
465
458
  /* GnuTLS session creation */
466
459
  ret = gnutls_init(session, GNUTLS_SERVER);
467
 
  if(ret != GNUTLS_E_SUCCESS){
 
460
  if (ret != GNUTLS_E_SUCCESS){
468
461
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
469
462
            safer_gnutls_strerror(ret));
470
463
  }
472
465
  {
473
466
    const char *err;
474
467
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
475
 
    if(ret != GNUTLS_E_SUCCESS) {
 
468
    if (ret != GNUTLS_E_SUCCESS) {
476
469
      fprintf(stderr, "Syntax error at: %s\n", err);
477
470
      fprintf(stderr, "GnuTLS error: %s\n",
478
471
              safer_gnutls_strerror(ret));
479
 
      gnutls_deinit(*session);
 
472
      gnutls_deinit (*session);
480
473
      return -1;
481
474
    }
482
475
  }
483
476
  
484
477
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
485
478
                               mc->cred);
486
 
  if(ret != GNUTLS_E_SUCCESS) {
 
479
  if (ret != GNUTLS_E_SUCCESS) {
487
480
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
488
481
            safer_gnutls_strerror(ret));
489
 
    gnutls_deinit(*session);
 
482
    gnutls_deinit (*session);
490
483
    return -1;
491
484
  }
492
485
  
493
486
  /* ignore client certificate if any. */
494
 
  gnutls_certificate_server_set_request(*session,
495
 
                                        GNUTLS_CERT_IGNORE);
 
487
  gnutls_certificate_server_set_request (*session,
 
488
                                         GNUTLS_CERT_IGNORE);
496
489
  
497
 
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
 
490
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
498
491
  
499
492
  return 0;
500
493
}
508
501
                                      AvahiIfIndex if_index,
509
502
                                      mandos_context *mc){
510
503
  int ret, tcp_sd;
511
 
  ssize_t sret;
512
504
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
513
505
  char *buffer = NULL;
514
506
  char *decrypted_buffer;
520
512
  char interface[IF_NAMESIZE];
521
513
  gnutls_session_t session;
522
514
  
523
 
  ret = init_gnutls_session(mc, &session);
524
 
  if(ret != 0){
 
515
  ret = init_gnutls_session (mc, &session);
 
516
  if (ret != 0){
525
517
    return -1;
526
518
  }
527
519
  
549
541
  /* It would be nice to have a way to detect if we were passed an
550
542
     IPv4 address here.   Now we assume an IPv6 address. */
551
543
  ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
552
 
  if(ret < 0 ){
 
544
  if (ret < 0 ){
553
545
    perror("inet_pton");
554
546
    return -1;
555
547
  }
557
549
    fprintf(stderr, "Bad address: %s\n", ip);
558
550
    return -1;
559
551
  }
560
 
  to.in6.sin6_port = htons(port); /* Spurious warnings from
561
 
                                     -Wconversion and
562
 
                                     -Wunreachable-code */
 
552
  to.in6.sin6_port = htons(port); /* Spurious warning */
563
553
  
564
554
  to.in6.sin6_scope_id = (uint32_t)if_index;
565
555
  
578
568
  }
579
569
  
580
570
  ret = connect(tcp_sd, &to.in, sizeof(to));
581
 
  if(ret < 0){
 
571
  if (ret < 0){
582
572
    perror("connect");
583
573
    return -1;
584
574
  }
585
575
  
586
576
  const char *out = mandos_protocol_version;
587
577
  written = 0;
588
 
  while(true){
 
578
  while (true){
589
579
    size_t out_size = strlen(out);
590
 
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
580
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
591
581
                                   out_size - written));
592
 
    if(ret == -1){
 
582
    if (ret == -1){
593
583
      perror("write");
594
584
      retval = -1;
595
585
      goto mandos_end;
598
588
    if(written < out_size){
599
589
      continue;
600
590
    } else {
601
 
      if(out == mandos_protocol_version){
 
591
      if (out == mandos_protocol_version){
602
592
        written = 0;
603
593
        out = "\r\n";
604
594
      } else {
611
601
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
612
602
  }
613
603
  
614
 
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
604
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
615
605
  
616
606
  do{
617
 
    ret = gnutls_handshake(session);
 
607
    ret = gnutls_handshake (session);
618
608
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
619
609
  
620
 
  if(ret != GNUTLS_E_SUCCESS){
 
610
  if (ret != GNUTLS_E_SUCCESS){
621
611
    if(debug){
622
612
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
623
 
      gnutls_perror(ret);
 
613
      gnutls_perror (ret);
624
614
    }
625
615
    retval = -1;
626
616
    goto mandos_end;
636
626
  while(true){
637
627
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
638
628
                                   buffer_capacity);
639
 
    if(buffer_capacity == 0){
 
629
    if (buffer_capacity == 0){
640
630
      perror("adjustbuffer");
641
631
      retval = -1;
642
632
      goto mandos_end;
643
633
    }
644
634
    
645
 
    sret = gnutls_record_recv(session, buffer+buffer_length,
646
 
                              BUFFER_SIZE);
647
 
    if(sret == 0){
 
635
    ret = gnutls_record_recv(session, buffer+buffer_length,
 
636
                             BUFFER_SIZE);
 
637
    if (ret == 0){
648
638
      break;
649
639
    }
650
 
    if(sret < 0){
651
 
      switch(sret){
 
640
    if (ret < 0){
 
641
      switch(ret){
652
642
      case GNUTLS_E_INTERRUPTED:
653
643
      case GNUTLS_E_AGAIN:
654
644
        break;
655
645
      case GNUTLS_E_REHANDSHAKE:
656
646
        do{
657
 
          ret = gnutls_handshake(session);
 
647
          ret = gnutls_handshake (session);
658
648
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
659
 
        if(ret < 0){
 
649
        if (ret < 0){
660
650
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
661
 
          gnutls_perror(ret);
 
651
          gnutls_perror (ret);
662
652
          retval = -1;
663
653
          goto mandos_end;
664
654
        }
667
657
        fprintf(stderr, "Unknown error while reading data from"
668
658
                " encrypted session with Mandos server\n");
669
659
        retval = -1;
670
 
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
660
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
671
661
        goto mandos_end;
672
662
      }
673
663
    } else {
674
 
      buffer_length += (size_t) sret;
 
664
      buffer_length += (size_t) ret;
675
665
    }
676
666
  }
677
667
  
679
669
    fprintf(stderr, "Closing TLS session\n");
680
670
  }
681
671
  
682
 
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
672
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
683
673
  
684
 
  if(buffer_length > 0){
 
674
  if (buffer_length > 0){
685
675
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
686
676
                                               buffer_length,
687
677
                                               &decrypted_buffer);
688
 
    if(decrypted_buffer_size >= 0){
 
678
    if (decrypted_buffer_size >= 0){
689
679
      written = 0;
690
680
      while(written < (size_t) decrypted_buffer_size){
691
 
        ret = (int)fwrite(decrypted_buffer + written, 1,
692
 
                          (size_t)decrypted_buffer_size - written,
693
 
                          stdout);
 
681
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
682
                           (size_t)decrypted_buffer_size - written,
 
683
                           stdout);
694
684
        if(ret == 0 and ferror(stdout)){
695
685
          if(debug){
696
686
            fprintf(stderr, "Error writing encrypted data: %s\n",
713
703
  
714
704
 mandos_end:
715
705
  free(buffer);
716
 
  ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
 
706
  ret = TEMP_FAILURE_RETRY(close(tcp_sd));
717
707
  if(ret == -1){
718
708
    perror("close");
719
709
  }
720
 
  gnutls_deinit(session);
 
710
  gnutls_deinit (session);
721
711
  return retval;
722
712
}
723
713
 
741
731
  /* Called whenever a service has been resolved successfully or
742
732
     timed out */
743
733
  
744
 
  switch(event) {
 
734
  switch (event) {
745
735
  default:
746
736
  case AVAHI_RESOLVER_FAILURE:
747
737
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
755
745
      avahi_address_snprint(ip, sizeof(ip), address);
756
746
      if(debug){
757
747
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
758
 
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
759
 
                ip, (intmax_t)interface, port);
 
748
                PRIu16 ") on port %d\n", name, host_name, ip,
 
749
                interface, port);
760
750
      }
761
751
      int ret = start_mandos_communication(ip, port, interface, mc);
762
 
      if(ret == 0){
 
752
      if (ret == 0){
763
753
        avahi_simple_poll_quit(mc->simple_poll);
764
754
      }
765
755
    }
783
773
  /* Called whenever a new services becomes available on the LAN or
784
774
     is removed from the LAN */
785
775
  
786
 
  switch(event) {
 
776
  switch (event) {
787
777
  default:
788
778
  case AVAHI_BROWSER_FAILURE:
789
779
    
798
788
       the callback function is called the Avahi server will free the
799
789
       resolver for us. */
800
790
    
801
 
    if(!(avahi_s_service_resolver_new(mc->server, interface,
 
791
    if (!(avahi_s_service_resolver_new(mc->server, interface,
802
792
                                       protocol, name, type, domain,
803
793
                                       AVAHI_PROTO_INET6, 0,
804
794
                                       resolve_callback, mc)))
822
812
    AvahiSServiceBrowser *sb = NULL;
823
813
    int error;
824
814
    int ret;
825
 
    intmax_t tmpmax;
826
 
    int numchars;
827
815
    int exitcode = EXIT_SUCCESS;
828
816
    const char *interface = "eth0";
829
817
    struct ifreq network;
841
829
                          ":!CTYPE-X.509:+CTYPE-OPENPGP" };
842
830
    bool gnutls_initalized = false;
843
831
    bool gpgme_initalized = false;
844
 
    double delay = 2.5;
845
832
    
846
833
    {
847
834
      struct argp_option options[] = {
873
860
          .arg = "STRING",
874
861
          .doc = "GnuTLS priority string for the TLS handshake",
875
862
          .group = 1 },
876
 
        { .name = "delay", .key = 131,
877
 
          .arg = "SECONDS",
878
 
          .doc = "Maximum delay to wait for interface startup",
879
 
          .group = 2 },
880
863
        { .name = NULL }
881
864
      };
882
865
      
883
 
      error_t parse_opt(int key, char *arg,
884
 
                        struct argp_state *state) {
885
 
        switch(key) {
 
866
      error_t parse_opt (int key, char *arg,
 
867
                         struct argp_state *state) {
 
868
        /* Get the INPUT argument from `argp_parse', which we know is
 
869
           a pointer to our plugin list pointer. */
 
870
        switch (key) {
886
871
        case 128:               /* --debug */
887
872
          debug = true;
888
873
          break;
899
884
          pubkey = arg;
900
885
          break;
901
886
        case 129:               /* --dh-bits */
902
 
          ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
903
 
          if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
904
 
             or arg[numchars] != '\0'){
905
 
            fprintf(stderr, "Bad number of DH bits\n");
 
887
          errno = 0;
 
888
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
889
          if (errno){
 
890
            perror("strtol");
906
891
            exit(EXIT_FAILURE);
907
892
          }
908
 
          mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
909
893
          break;
910
894
        case 130:               /* --priority */
911
895
          mc.priority = arg;
912
896
          break;
913
 
        case 131:               /* --delay */
914
 
          ret = sscanf(arg, "%lf%n", &delay, &numchars);
915
 
          if(ret < 1 or arg[numchars] != '\0'){
916
 
            fprintf(stderr, "Bad delay\n");
917
 
            exit(EXIT_FAILURE);
918
 
          }
919
 
          break;
920
897
        case ARGP_KEY_ARG:
921
 
          argp_usage(state);
 
898
          argp_usage (state);
922
899
        case ARGP_KEY_END:
923
900
          break;
924
901
        default:
931
908
                           .args_doc = "",
932
909
                           .doc = "Mandos client -- Get and decrypt"
933
910
                           " passwords from a Mandos server" };
934
 
      ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
935
 
      if(ret == ARGP_ERR_UNKNOWN){
 
911
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
912
      if (ret == ARGP_ERR_UNKNOWN){
936
913
        fprintf(stderr, "Unknown error while parsing arguments\n");
937
914
        exitcode = EXIT_FAILURE;
938
915
        goto end;
941
918
    
942
919
    /* If the interface is down, bring it up */
943
920
    {
944
 
      // Lower kernel loglevel to KERN_NOTICE to avoid
945
 
      // KERN_INFO messages to mess up the prompt
946
 
      ret = klogctl(8, NULL, 5);
947
 
      if(ret == -1){
948
 
        perror("klogctl");
949
 
      }
950
 
 
951
921
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
952
922
      if(sd < 0) {
953
923
        perror("socket");
954
924
        exitcode = EXIT_FAILURE;
955
 
        ret = klogctl(7, NULL, 0);
956
 
        if(ret == -1){
957
 
          perror("klogctl");
958
 
        }
959
925
        goto end;
960
926
      }
961
927
      strcpy(network.ifr_name, interface);
962
928
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
963
929
      if(ret == -1){
964
930
        perror("ioctl SIOCGIFFLAGS");
965
 
        ret = klogctl(7, NULL, 0);
966
 
        if(ret == -1){
967
 
          perror("klogctl");
968
 
        }
969
931
        exitcode = EXIT_FAILURE;
970
932
        goto end;
971
933
      }
975
937
        if(ret == -1){
976
938
          perror("ioctl SIOCSIFFLAGS");
977
939
          exitcode = EXIT_FAILURE;
978
 
          ret = klogctl(7, NULL, 0);
979
 
          if(ret == -1){
980
 
            perror("klogctl");
981
 
          }
982
940
          goto end;
983
941
        }
984
942
      }
985
 
      // sleep checking until interface is running
986
 
      for(int i=0; i < delay * 4; i++){
987
 
        ret = ioctl(sd, SIOCGIFFLAGS, &network);
988
 
        if(ret == -1){
989
 
          perror("ioctl SIOCGIFFLAGS");
990
 
        } else if(network.ifr_flags & IFF_RUNNING){
991
 
          break;
992
 
        }
993
 
        struct timespec sleeptime = { .tv_nsec = 250000000 };
994
 
        nanosleep(&sleeptime, NULL);
995
 
      }
996
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
943
      ret = TEMP_FAILURE_RETRY(close(sd));
997
944
      if(ret == -1){
998
945
        perror("close");
999
946
      }
1000
 
      // Restores kernel loglevel to default
1001
 
      ret = klogctl(7, NULL, 0);
1002
 
      if(ret == -1){
1003
 
        perror("klogctl");
1004
 
      }
1005
947
    }
1006
948
    
1007
949
    uid = getuid();
1008
950
    gid = getgid();
1009
951
    
1010
952
    ret = setuid(uid);
1011
 
    if(ret == -1){
 
953
    if (ret == -1){
1012
954
      perror("setuid");
1013
955
    }
1014
956
    
1015
957
    setgid(gid);
1016
 
    if(ret == -1){
 
958
    if (ret == -1){
1017
959
      perror("setgid");
1018
960
    }
1019
961
    
1020
962
    ret = init_gnutls_global(&mc, pubkey, seckey);
1021
 
    if(ret == -1){
 
963
    if (ret == -1){
1022
964
      fprintf(stderr, "init_gnutls_global failed\n");
1023
965
      exitcode = EXIT_FAILURE;
1024
966
      goto end;
1055
997
        exitcode = EXIT_FAILURE;
1056
998
        goto end;
1057
999
      }
1058
 
      uint16_t port;
1059
 
      ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
1060
 
      if(ret < 1 or tmpmax != (uint16_t)tmpmax
1061
 
         or address[numchars+1] != '\0'){
1062
 
        fprintf(stderr, "Bad port number\n");
 
1000
      errno = 0;
 
1001
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
1002
      if(errno){
 
1003
        perror("Bad port number");
1063
1004
        exitcode = EXIT_FAILURE;
1064
1005
        goto end;
1065
1006
      }
1066
 
      port = (uint16_t)tmpmax;
1067
1007
      *address = '\0';
1068
1008
      address = connect_to;
1069
1009
      ret = start_mandos_communication(address, port, if_index, &mc);
1075
1015
      goto end;
1076
1016
    }
1077
1017
    
1078
 
    if(not debug){
 
1018
    if (not debug){
1079
1019
      avahi_set_log_function(empty_log);
1080
1020
    }
1081
1021
    
1084
1024
    
1085
1025
    /* Allocate main Avahi loop object */
1086
1026
    mc.simple_poll = avahi_simple_poll_new();
1087
 
    if(mc.simple_poll == NULL) {
 
1027
    if (mc.simple_poll == NULL) {
1088
1028
        fprintf(stderr, "Avahi: Failed to create simple poll"
1089
1029
                " object.\n");
1090
1030
        exitcode = EXIT_FAILURE;
1110
1050
    }
1111
1051
    
1112
1052
    /* Check if creating the Avahi server object succeeded */
1113
 
    if(mc.server == NULL) {
 
1053
    if (mc.server == NULL) {
1114
1054
        fprintf(stderr, "Failed to create Avahi server: %s\n",
1115
1055
                avahi_strerror(error));
1116
1056
        exitcode = EXIT_FAILURE;
1122
1062
                                     AVAHI_PROTO_INET6,
1123
1063
                                     "_mandos._tcp", NULL, 0,
1124
1064
                                     browse_callback, &mc);
1125
 
    if(sb == NULL) {
 
1065
    if (sb == NULL) {
1126
1066
        fprintf(stderr, "Failed to create service browser: %s\n",
1127
1067
                avahi_strerror(avahi_server_errno(mc.server)));
1128
1068
        exitcode = EXIT_FAILURE;
1131
1071
    
1132
1072
    /* Run the main loop */
1133
1073
    
1134
 
    if(debug){
 
1074
    if (debug){
1135
1075
      fprintf(stderr, "Starting Avahi loop search\n");
1136
1076
    }
1137
 
 
 
1077
    
1138
1078
    avahi_simple_poll_loop(mc.simple_poll);
1139
1079
    
1140
1080
 end:
1141
1081
    
1142
 
    if(debug){
 
1082
    if (debug){
1143
1083
      fprintf(stderr, "%s exiting\n", argv[0]);
1144
1084
    }
1145
1085
    
1146
1086
    /* Cleanup things */
1147
 
    if(sb != NULL)
 
1087
    if (sb != NULL)
1148
1088
        avahi_s_service_browser_free(sb);
1149
1089
    
1150
 
    if(mc.server != NULL)
 
1090
    if (mc.server != NULL)
1151
1091
        avahi_server_free(mc.server);
1152
1092
    
1153
 
    if(mc.simple_poll != NULL)
 
1093
    if (mc.simple_poll != NULL)
1154
1094
        avahi_simple_poll_free(mc.simple_poll);
1155
1095
    
1156
 
    if(gnutls_initalized){
 
1096
    if (gnutls_initalized){
1157
1097
      gnutls_certificate_free_credentials(mc.cred);
1158
 
      gnutls_global_deinit();
 
1098
      gnutls_global_deinit ();
1159
1099
      gnutls_dh_params_deinit(mc.dh_params);
1160
1100
    }
1161
1101
    
1169
1109
      struct dirent *direntry;
1170
1110
      d = opendir(tempdir);
1171
1111
      if(d == NULL){
1172
 
        if(errno != ENOENT){
1173
 
          perror("opendir");
1174
 
        }
 
1112
        perror("opendir");
1175
1113
      } else {
1176
1114
        while(true){
1177
1115
          direntry = readdir(d);
1178
1116
          if(direntry == NULL){
1179
1117
            break;
1180
1118
          }
1181
 
          if(direntry->d_type == DT_REG){
 
1119
          if (direntry->d_type == DT_REG){
1182
1120
            char *fullname = NULL;
1183
1121
            ret = asprintf(&fullname, "%s/%s", tempdir,
1184
1122
                           direntry->d_name);
1197
1135
        closedir(d);
1198
1136
      }
1199
1137
      ret = rmdir(tempdir);
1200
 
      if(ret == -1 and errno != ENOENT){
 
1138
      if(ret == -1){
1201
1139
        perror("rmdir");
1202
1140
      }
1203
1141
    }