/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/mandos-client.c

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(),
40
 
                                   remove() */
 
39
                                   stdout, ferror() */
41
40
#include <stdint.h>             /* uint16_t, uint32_t */
42
41
#include <stddef.h>             /* NULL, size_t, ssize_t */
43
42
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
49
48
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
50
49
                                   sockaddr_in6, PF_INET6,
51
50
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
52
 
                                   uid_t, gid_t, open(), opendir(),
53
 
                                   DIR */
 
51
                                   uid_t, gid_t, open(), opendir(), DIR */
54
52
#include <sys/stat.h>           /* open() */
55
53
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
56
54
                                   struct in6_addr, inet_pton(),
57
55
                                   connect() */
58
56
#include <fcntl.h>              /* open() */
59
 
#include <dirent.h>             /* opendir(), struct dirent, readdir()
60
 
                                 */
61
 
#include <inttypes.h>           /* PRIu16, intmax_t, SCNdMAX */
 
57
#include <dirent.h>             /* opendir(), struct dirent, readdir() */
 
58
#include <inttypes.h>           /* PRIu16 */
62
59
#include <assert.h>             /* assert() */
63
60
#include <errno.h>              /* perror(), errno */
64
61
#include <time.h>               /* time() */
70
67
                                   getuid(), getgid(), setuid(),
71
68
                                   setgid() */
72
69
#include <arpa/inet.h>          /* inet_pton(), htons */
73
 
#include <iso646.h>             /* not, and, or */
 
70
#include <iso646.h>             /* not, and */
74
71
#include <argp.h>               /* struct argp_option, error_t, struct
75
72
                                   argp_state, struct argp,
76
73
                                   argp_parse(), ARGP_KEY_ARG,
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;
839
827
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
840
828
                          .dh_bits = 1024, .priority = "SECURE256"
841
829
                          ":!CTYPE-X.509:+CTYPE-OPENPGP" };
842
 
    bool gnutls_initialized = false;
843
 
    bool gpgme_initialized = false;
 
830
    bool gnutls_initalized = false;
 
831
    bool gpgme_initalized = false;
844
832
    
845
833
    {
846
834
      struct argp_option options[] = {
875
863
        { .name = NULL }
876
864
      };
877
865
      
878
 
      error_t parse_opt(int key, char *arg,
879
 
                        struct argp_state *state) {
880
 
        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) {
881
871
        case 128:               /* --debug */
882
872
          debug = true;
883
873
          break;
894
884
          pubkey = arg;
895
885
          break;
896
886
        case 129:               /* --dh-bits */
897
 
          ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
898
 
          if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
899
 
             or arg[numchars] != '\0'){
900
 
            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");
901
891
            exit(EXIT_FAILURE);
902
892
          }
903
 
          mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
904
893
          break;
905
894
        case 130:               /* --priority */
906
895
          mc.priority = arg;
907
896
          break;
908
897
        case ARGP_KEY_ARG:
909
 
          argp_usage(state);
 
898
          argp_usage (state);
910
899
        case ARGP_KEY_END:
911
900
          break;
912
901
        default:
919
908
                           .args_doc = "",
920
909
                           .doc = "Mandos client -- Get and decrypt"
921
910
                           " passwords from a Mandos server" };
922
 
      ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
923
 
      if(ret == ARGP_ERR_UNKNOWN){
 
911
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
912
      if (ret == ARGP_ERR_UNKNOWN){
924
913
        fprintf(stderr, "Unknown error while parsing arguments\n");
925
914
        exitcode = EXIT_FAILURE;
926
915
        goto end;
951
940
          goto end;
952
941
        }
953
942
      }
954
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
943
      ret = TEMP_FAILURE_RETRY(close(sd));
955
944
      if(ret == -1){
956
945
        perror("close");
957
946
      }
961
950
    gid = getgid();
962
951
    
963
952
    ret = setuid(uid);
964
 
    if(ret == -1){
 
953
    if (ret == -1){
965
954
      perror("setuid");
966
955
    }
967
956
    
968
957
    setgid(gid);
969
 
    if(ret == -1){
 
958
    if (ret == -1){
970
959
      perror("setgid");
971
960
    }
972
961
    
973
962
    ret = init_gnutls_global(&mc, pubkey, seckey);
974
 
    if(ret == -1){
 
963
    if (ret == -1){
975
964
      fprintf(stderr, "init_gnutls_global failed\n");
976
965
      exitcode = EXIT_FAILURE;
977
966
      goto end;
978
967
    } else {
979
 
      gnutls_initialized = true;
 
968
      gnutls_initalized = true;
980
969
    }
981
970
    
982
971
    if(mkdtemp(tempdir) == NULL){
986
975
    }
987
976
    
988
977
    if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
989
 
      fprintf(stderr, "init_gpgme failed\n");
 
978
      fprintf(stderr, "gpgme_initalized failed\n");
990
979
      exitcode = EXIT_FAILURE;
991
980
      goto end;
992
981
    } else {
993
 
      gpgme_initialized = true;
 
982
      gpgme_initalized = true;
994
983
    }
995
984
    
996
985
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1008
997
        exitcode = EXIT_FAILURE;
1009
998
        goto end;
1010
999
      }
1011
 
      uint16_t port;
1012
 
      ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
1013
 
      if(ret < 1 or tmpmax != (uint16_t)tmpmax
1014
 
         or address[numchars+1] != '\0'){
1015
 
        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");
1016
1004
        exitcode = EXIT_FAILURE;
1017
1005
        goto end;
1018
1006
      }
1019
 
      port = (uint16_t)tmpmax;
1020
1007
      *address = '\0';
1021
1008
      address = connect_to;
1022
1009
      ret = start_mandos_communication(address, port, if_index, &mc);
1028
1015
      goto end;
1029
1016
    }
1030
1017
    
1031
 
    if(not debug){
 
1018
    if (not debug){
1032
1019
      avahi_set_log_function(empty_log);
1033
1020
    }
1034
1021
    
1037
1024
    
1038
1025
    /* Allocate main Avahi loop object */
1039
1026
    mc.simple_poll = avahi_simple_poll_new();
1040
 
    if(mc.simple_poll == NULL) {
 
1027
    if (mc.simple_poll == NULL) {
1041
1028
        fprintf(stderr, "Avahi: Failed to create simple poll"
1042
1029
                " object.\n");
1043
1030
        exitcode = EXIT_FAILURE;
1063
1050
    }
1064
1051
    
1065
1052
    /* Check if creating the Avahi server object succeeded */
1066
 
    if(mc.server == NULL) {
 
1053
    if (mc.server == NULL) {
1067
1054
        fprintf(stderr, "Failed to create Avahi server: %s\n",
1068
1055
                avahi_strerror(error));
1069
1056
        exitcode = EXIT_FAILURE;
1075
1062
                                     AVAHI_PROTO_INET6,
1076
1063
                                     "_mandos._tcp", NULL, 0,
1077
1064
                                     browse_callback, &mc);
1078
 
    if(sb == NULL) {
 
1065
    if (sb == NULL) {
1079
1066
        fprintf(stderr, "Failed to create service browser: %s\n",
1080
1067
                avahi_strerror(avahi_server_errno(mc.server)));
1081
1068
        exitcode = EXIT_FAILURE;
1084
1071
    
1085
1072
    /* Run the main loop */
1086
1073
    
1087
 
    if(debug){
 
1074
    if (debug){
1088
1075
      fprintf(stderr, "Starting Avahi loop search\n");
1089
1076
    }
1090
1077
    
1092
1079
    
1093
1080
 end:
1094
1081
    
1095
 
    if(debug){
 
1082
    if (debug){
1096
1083
      fprintf(stderr, "%s exiting\n", argv[0]);
1097
1084
    }
1098
1085
    
1099
1086
    /* Cleanup things */
1100
 
    if(sb != NULL)
 
1087
    if (sb != NULL)
1101
1088
        avahi_s_service_browser_free(sb);
1102
1089
    
1103
 
    if(mc.server != NULL)
 
1090
    if (mc.server != NULL)
1104
1091
        avahi_server_free(mc.server);
1105
1092
    
1106
 
    if(mc.simple_poll != NULL)
 
1093
    if (mc.simple_poll != NULL)
1107
1094
        avahi_simple_poll_free(mc.simple_poll);
1108
1095
    
1109
 
    if(gnutls_initialized){
 
1096
    if (gnutls_initalized){
1110
1097
      gnutls_certificate_free_credentials(mc.cred);
1111
 
      gnutls_global_deinit();
 
1098
      gnutls_global_deinit ();
1112
1099
      gnutls_dh_params_deinit(mc.dh_params);
1113
1100
    }
1114
1101
    
1115
 
    if(gpgme_initialized){
 
1102
    if(gpgme_initalized){
1116
1103
      gpgme_release(mc.ctx);
1117
1104
    }
1118
1105
    
1122
1109
      struct dirent *direntry;
1123
1110
      d = opendir(tempdir);
1124
1111
      if(d == NULL){
1125
 
        if(errno != ENOENT){
1126
 
          perror("opendir");
1127
 
        }
 
1112
        perror("opendir");
1128
1113
      } else {
1129
1114
        while(true){
1130
1115
          direntry = readdir(d);
1131
1116
          if(direntry == NULL){
1132
1117
            break;
1133
1118
          }
1134
 
          /* Skip "." and ".." */
1135
 
          if(direntry->d_name[0] == '.'
1136
 
             and (direntry->d_name[1] == '\0'
1137
 
                  or (direntry->d_name[1] == '.'
1138
 
                      and direntry->d_name[2] == '\0'))){
1139
 
            continue;
1140
 
          }
1141
 
          char *fullname = NULL;
1142
 
          ret = asprintf(&fullname, "%s/%s", tempdir,
1143
 
                         direntry->d_name);
1144
 
          if(ret < 0){
1145
 
            perror("asprintf");
1146
 
            continue;
1147
 
          }
1148
 
          ret = remove(fullname);
1149
 
          if(ret == -1){
1150
 
            fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1151
 
                    strerror(errno));
1152
 
          }
1153
 
          free(fullname);
 
1119
          if (direntry->d_type == DT_REG){
 
1120
            char *fullname = NULL;
 
1121
            ret = asprintf(&fullname, "%s/%s", tempdir,
 
1122
                           direntry->d_name);
 
1123
            if(ret < 0){
 
1124
              perror("asprintf");
 
1125
              continue;
 
1126
            }
 
1127
            ret = unlink(fullname);
 
1128
            if(ret == -1){
 
1129
              fprintf(stderr, "unlink(\"%s\"): %s",
 
1130
                      fullname, strerror(errno));
 
1131
            }
 
1132
            free(fullname);
 
1133
          }
1154
1134
        }
1155
1135
        closedir(d);
1156
1136
      }
1157
1137
      ret = rmdir(tempdir);
1158
 
      if(ret == -1 and errno != ENOENT){
 
1138
      if(ret == -1){
1159
1139
        perror("rmdir");
1160
1140
      }
1161
1141
    }
1162
 
    
 
1142
          
1163
1143
    return exitcode;
1164
1144
}