/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(),
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
 
#include <time.h>               /* nanosleep(), time() */
 
61
#include <time.h>               /* time() */
65
62
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
66
63
                                   SIOCSIFFLAGS, if_indextoname(),
67
64
                                   if_nametoindex(), IF_NAMESIZE */
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,
77
74
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
78
 
#ifdef __linux__
79
 
#include <sys/klog.h>           /* klogctl() */
80
 
#endif
81
75
 
82
76
/* Avahi */
83
77
/* All Avahi types, constants and functions
96
90
                                   gnutls_*
97
91
                                   init_gnutls_session(),
98
92
                                   GNUTLS_* */
99
 
#include <gnutls/openpgp.h>
100
 
                          /* gnutls_certificate_set_openpgp_key_file(),
 
93
#include <gnutls/openpgp.h>     /* gnutls_certificate_set_openpgp_key_file(),
101
94
                                   GNUTLS_OPENPGP_FMT_BASE64 */
102
95
 
103
96
/* GPGME */
136
129
 */
137
130
size_t adjustbuffer(char **buffer, size_t buffer_length,
138
131
                  size_t buffer_capacity){
139
 
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
 
132
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
140
133
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
141
 
    if(buffer == NULL){
 
134
    if (buffer == NULL){
142
135
      return 0;
143
136
    }
144
137
    buffer_capacity += BUFFER_SIZE;
157
150
  
158
151
  
159
152
  /*
160
 
   * Helper function to insert pub and seckey to the engine keyring.
 
153
   * Helper function to insert pub and seckey to the enigne keyring.
161
154
   */
162
155
  bool import_key(const char *filename){
163
156
    int fd;
164
157
    gpgme_data_t pgp_data;
165
158
    
166
 
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
 
159
    fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
167
160
    if(fd == -1){
168
161
      perror("open");
169
162
      return false;
170
163
    }
171
164
    
172
165
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
173
 
    if(rc != GPG_ERR_NO_ERROR){
 
166
    if (rc != GPG_ERR_NO_ERROR){
174
167
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
175
168
              gpgme_strsource(rc), gpgme_strerror(rc));
176
169
      return false;
177
170
    }
178
171
    
179
172
    rc = gpgme_op_import(mc->ctx, pgp_data);
180
 
    if(rc != GPG_ERR_NO_ERROR){
 
173
    if (rc != GPG_ERR_NO_ERROR){
181
174
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
182
175
              gpgme_strsource(rc), gpgme_strerror(rc));
183
176
      return false;
184
177
    }
185
178
    
186
 
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
 
179
    ret = TEMP_FAILURE_RETRY(close(fd));
187
180
    if(ret == -1){
188
181
      perror("close");
189
182
    }
191
184
    return true;
192
185
  }
193
186
  
194
 
  if(debug){
 
187
  if (debug){
195
188
    fprintf(stderr, "Initialize gpgme\n");
196
189
  }
197
190
  
198
191
  /* Init GPGME */
199
192
  gpgme_check_version(NULL);
200
193
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
201
 
  if(rc != GPG_ERR_NO_ERROR){
 
194
  if (rc != GPG_ERR_NO_ERROR){
202
195
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
203
196
            gpgme_strsource(rc), gpgme_strerror(rc));
204
197
    return false;
205
198
  }
206
199
  
207
200
    /* Set GPGME home directory for the OpenPGP engine only */
208
 
  rc = gpgme_get_engine_info(&engine_info);
209
 
  if(rc != GPG_ERR_NO_ERROR){
 
201
  rc = gpgme_get_engine_info (&engine_info);
 
202
  if (rc != GPG_ERR_NO_ERROR){
210
203
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
211
204
            gpgme_strsource(rc), gpgme_strerror(rc));
212
205
    return false;
226
219
  
227
220
  /* Create new GPGME "context" */
228
221
  rc = gpgme_new(&(mc->ctx));
229
 
  if(rc != GPG_ERR_NO_ERROR){
 
222
  if (rc != GPG_ERR_NO_ERROR){
230
223
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
231
224
            gpgme_strsource(rc), gpgme_strerror(rc));
232
225
    return false;
233
226
  }
234
227
  
235
 
  if(not import_key(pubkey) or not import_key(seckey)){
 
228
  if (not import_key(pubkey) or not import_key(seckey)){
236
229
    return false;
237
230
  }
238
231
  
243
236
 * Decrypt OpenPGP data.
244
237
 * Returns -1 on error
245
238
 */
246
 
static ssize_t pgp_packet_decrypt(const mandos_context *mc,
247
 
                                  const char *cryptotext,
248
 
                                  size_t crypto_size,
249
 
                                  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){
250
243
  gpgme_data_t dh_crypto, dh_plain;
251
244
  gpgme_error_t rc;
252
245
  ssize_t ret;
253
246
  size_t plaintext_capacity = 0;
254
247
  ssize_t plaintext_length = 0;
255
248
  
256
 
  if(debug){
 
249
  if (debug){
257
250
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
258
251
  }
259
252
  
260
253
  /* Create new GPGME data buffer from memory cryptotext */
261
254
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
262
255
                               0);
263
 
  if(rc != GPG_ERR_NO_ERROR){
 
256
  if (rc != GPG_ERR_NO_ERROR){
264
257
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
265
258
            gpgme_strsource(rc), gpgme_strerror(rc));
266
259
    return -1;
268
261
  
269
262
  /* Create new empty GPGME data buffer for the plaintext */
270
263
  rc = gpgme_data_new(&dh_plain);
271
 
  if(rc != GPG_ERR_NO_ERROR){
 
264
  if (rc != GPG_ERR_NO_ERROR){
272
265
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
273
266
            gpgme_strsource(rc), gpgme_strerror(rc));
274
267
    gpgme_data_release(dh_crypto);
278
271
  /* Decrypt data from the cryptotext data buffer to the plaintext
279
272
     data buffer */
280
273
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
281
 
  if(rc != GPG_ERR_NO_ERROR){
 
274
  if (rc != GPG_ERR_NO_ERROR){
282
275
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
283
276
            gpgme_strsource(rc), gpgme_strerror(rc));
284
277
    plaintext_length = -1;
285
 
    if(debug){
 
278
    if (debug){
286
279
      gpgme_decrypt_result_t result;
287
280
      result = gpgme_op_decrypt_result(mc->ctx);
288
 
      if(result == NULL){
 
281
      if (result == NULL){
289
282
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
290
283
      } else {
291
284
        fprintf(stderr, "Unsupported algorithm: %s\n",
318
311
  }
319
312
  
320
313
  /* Seek back to the beginning of the GPGME plaintext data buffer */
321
 
  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){
322
315
    perror("gpgme_data_seek");
323
316
    plaintext_length = -1;
324
317
    goto decrypt_end;
329
322
    plaintext_capacity = adjustbuffer(plaintext,
330
323
                                      (size_t)plaintext_length,
331
324
                                      plaintext_capacity);
332
 
    if(plaintext_capacity == 0){
 
325
    if (plaintext_capacity == 0){
333
326
        perror("adjustbuffer");
334
327
        plaintext_length = -1;
335
328
        goto decrypt_end;
338
331
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
339
332
                          BUFFER_SIZE);
340
333
    /* Print the data, if any */
341
 
    if(ret == 0){
 
334
    if (ret == 0){
342
335
      /* EOF */
343
336
      break;
344
337
    }
368
361
  return plaintext_length;
369
362
}
370
363
 
371
 
static const char * safer_gnutls_strerror(int value){
372
 
  const char *ret = gnutls_strerror(value); /* Spurious warning from
373
 
                                               -Wunreachable-code */
374
 
  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)
375
367
    ret = "(unknown)";
376
368
  return ret;
377
369
}
392
384
  }
393
385
  
394
386
  ret = gnutls_global_init();
395
 
  if(ret != GNUTLS_E_SUCCESS){
396
 
    fprintf(stderr, "GnuTLS global_init: %s\n",
397
 
            safer_gnutls_strerror(ret));
 
387
  if (ret != GNUTLS_E_SUCCESS) {
 
388
    fprintf (stderr, "GnuTLS global_init: %s\n",
 
389
             safer_gnutls_strerror(ret));
398
390
    return -1;
399
391
  }
400
392
  
401
 
  if(debug){
 
393
  if (debug){
402
394
    /* "Use a log level over 10 to enable all debugging options."
403
395
     * - GnuTLS manual
404
396
     */
408
400
  
409
401
  /* OpenPGP credentials */
410
402
  gnutls_certificate_allocate_credentials(&mc->cred);
411
 
  if(ret != GNUTLS_E_SUCCESS){
412
 
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
413
 
                                                  * from
414
 
                                                  * -Wunreachable-code
415
 
                                                  */
416
 
            safer_gnutls_strerror(ret));
417
 
    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 ();
418
408
    return -1;
419
409
  }
420
410
  
427
417
  ret = gnutls_certificate_set_openpgp_key_file
428
418
    (mc->cred, pubkeyfilename, seckeyfilename,
429
419
     GNUTLS_OPENPGP_FMT_BASE64);
430
 
  if(ret != GNUTLS_E_SUCCESS){
 
420
  if (ret != GNUTLS_E_SUCCESS) {
431
421
    fprintf(stderr,
432
422
            "Error[%d] while reading the OpenPGP key pair ('%s',"
433
423
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
438
428
  
439
429
  /* GnuTLS server initialization */
440
430
  ret = gnutls_dh_params_init(&mc->dh_params);
441
 
  if(ret != GNUTLS_E_SUCCESS){
442
 
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
443
 
            " %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));
444
434
    goto globalfail;
445
435
  }
446
436
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
447
 
  if(ret != GNUTLS_E_SUCCESS){
448
 
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
449
 
            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));
450
440
    goto globalfail;
451
441
  }
452
442
  
467
457
  int ret;
468
458
  /* GnuTLS session creation */
469
459
  ret = gnutls_init(session, GNUTLS_SERVER);
470
 
  if(ret != GNUTLS_E_SUCCESS){
 
460
  if (ret != GNUTLS_E_SUCCESS){
471
461
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
472
462
            safer_gnutls_strerror(ret));
473
463
  }
475
465
  {
476
466
    const char *err;
477
467
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
478
 
    if(ret != GNUTLS_E_SUCCESS){
 
468
    if (ret != GNUTLS_E_SUCCESS) {
479
469
      fprintf(stderr, "Syntax error at: %s\n", err);
480
470
      fprintf(stderr, "GnuTLS error: %s\n",
481
471
              safer_gnutls_strerror(ret));
482
 
      gnutls_deinit(*session);
 
472
      gnutls_deinit (*session);
483
473
      return -1;
484
474
    }
485
475
  }
486
476
  
487
477
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
488
478
                               mc->cred);
489
 
  if(ret != GNUTLS_E_SUCCESS){
 
479
  if (ret != GNUTLS_E_SUCCESS) {
490
480
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
491
481
            safer_gnutls_strerror(ret));
492
 
    gnutls_deinit(*session);
 
482
    gnutls_deinit (*session);
493
483
    return -1;
494
484
  }
495
485
  
496
486
  /* ignore client certificate if any. */
497
 
  gnutls_certificate_server_set_request(*session,
498
 
                                        GNUTLS_CERT_IGNORE);
 
487
  gnutls_certificate_server_set_request (*session,
 
488
                                         GNUTLS_CERT_IGNORE);
499
489
  
500
 
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
 
490
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
501
491
  
502
492
  return 0;
503
493
}
511
501
                                      AvahiIfIndex if_index,
512
502
                                      mandos_context *mc){
513
503
  int ret, tcp_sd;
514
 
  ssize_t sret;
515
504
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
516
505
  char *buffer = NULL;
517
506
  char *decrypted_buffer;
523
512
  char interface[IF_NAMESIZE];
524
513
  gnutls_session_t session;
525
514
  
526
 
  ret = init_gnutls_session(mc, &session);
527
 
  if(ret != 0){
 
515
  ret = init_gnutls_session (mc, &session);
 
516
  if (ret != 0){
528
517
    return -1;
529
518
  }
530
519
  
534
523
  }
535
524
  
536
525
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
537
 
  if(tcp_sd < 0){
 
526
  if(tcp_sd < 0) {
538
527
    perror("socket");
539
528
    return -1;
540
529
  }
552
541
  /* It would be nice to have a way to detect if we were passed an
553
542
     IPv4 address here.   Now we assume an IPv6 address. */
554
543
  ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
555
 
  if(ret < 0 ){
 
544
  if (ret < 0 ){
556
545
    perror("inet_pton");
557
546
    return -1;
558
547
  }
560
549
    fprintf(stderr, "Bad address: %s\n", ip);
561
550
    return -1;
562
551
  }
563
 
  to.in6.sin6_port = htons(port); /* Spurious warnings from
564
 
                                     -Wconversion and
565
 
                                     -Wunreachable-code */
 
552
  to.in6.sin6_port = htons(port); /* Spurious warning */
566
553
  
567
554
  to.in6.sin6_scope_id = (uint32_t)if_index;
568
555
  
581
568
  }
582
569
  
583
570
  ret = connect(tcp_sd, &to.in, sizeof(to));
584
 
  if(ret < 0){
 
571
  if (ret < 0){
585
572
    perror("connect");
586
573
    return -1;
587
574
  }
588
575
  
589
576
  const char *out = mandos_protocol_version;
590
577
  written = 0;
591
 
  while(true){
 
578
  while (true){
592
579
    size_t out_size = strlen(out);
593
 
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
580
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
594
581
                                   out_size - written));
595
 
    if(ret == -1){
 
582
    if (ret == -1){
596
583
      perror("write");
597
584
      retval = -1;
598
585
      goto mandos_end;
601
588
    if(written < out_size){
602
589
      continue;
603
590
    } else {
604
 
      if(out == mandos_protocol_version){
 
591
      if (out == mandos_protocol_version){
605
592
        written = 0;
606
593
        out = "\r\n";
607
594
      } else {
614
601
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
615
602
  }
616
603
  
617
 
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
604
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
618
605
  
619
606
  do{
620
 
    ret = gnutls_handshake(session);
 
607
    ret = gnutls_handshake (session);
621
608
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
622
609
  
623
 
  if(ret != GNUTLS_E_SUCCESS){
 
610
  if (ret != GNUTLS_E_SUCCESS){
624
611
    if(debug){
625
612
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
626
 
      gnutls_perror(ret);
 
613
      gnutls_perror (ret);
627
614
    }
628
615
    retval = -1;
629
616
    goto mandos_end;
639
626
  while(true){
640
627
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
641
628
                                   buffer_capacity);
642
 
    if(buffer_capacity == 0){
 
629
    if (buffer_capacity == 0){
643
630
      perror("adjustbuffer");
644
631
      retval = -1;
645
632
      goto mandos_end;
646
633
    }
647
634
    
648
 
    sret = gnutls_record_recv(session, buffer+buffer_length,
649
 
                              BUFFER_SIZE);
650
 
    if(sret == 0){
 
635
    ret = gnutls_record_recv(session, buffer+buffer_length,
 
636
                             BUFFER_SIZE);
 
637
    if (ret == 0){
651
638
      break;
652
639
    }
653
 
    if(sret < 0){
654
 
      switch(sret){
 
640
    if (ret < 0){
 
641
      switch(ret){
655
642
      case GNUTLS_E_INTERRUPTED:
656
643
      case GNUTLS_E_AGAIN:
657
644
        break;
658
645
      case GNUTLS_E_REHANDSHAKE:
659
646
        do{
660
 
          ret = gnutls_handshake(session);
 
647
          ret = gnutls_handshake (session);
661
648
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
662
 
        if(ret < 0){
 
649
        if (ret < 0){
663
650
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
664
 
          gnutls_perror(ret);
 
651
          gnutls_perror (ret);
665
652
          retval = -1;
666
653
          goto mandos_end;
667
654
        }
670
657
        fprintf(stderr, "Unknown error while reading data from"
671
658
                " encrypted session with Mandos server\n");
672
659
        retval = -1;
673
 
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
660
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
674
661
        goto mandos_end;
675
662
      }
676
663
    } else {
677
 
      buffer_length += (size_t) sret;
 
664
      buffer_length += (size_t) ret;
678
665
    }
679
666
  }
680
667
  
682
669
    fprintf(stderr, "Closing TLS session\n");
683
670
  }
684
671
  
685
 
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
672
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
686
673
  
687
 
  if(buffer_length > 0){
 
674
  if (buffer_length > 0){
688
675
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
689
676
                                               buffer_length,
690
677
                                               &decrypted_buffer);
691
 
    if(decrypted_buffer_size >= 0){
 
678
    if (decrypted_buffer_size >= 0){
692
679
      written = 0;
693
680
      while(written < (size_t) decrypted_buffer_size){
694
 
        ret = (int)fwrite(decrypted_buffer + written, 1,
695
 
                          (size_t)decrypted_buffer_size - written,
696
 
                          stdout);
 
681
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
682
                           (size_t)decrypted_buffer_size - written,
 
683
                           stdout);
697
684
        if(ret == 0 and ferror(stdout)){
698
685
          if(debug){
699
686
            fprintf(stderr, "Error writing encrypted data: %s\n",
716
703
  
717
704
 mandos_end:
718
705
  free(buffer);
719
 
  ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
 
706
  ret = TEMP_FAILURE_RETRY(close(tcp_sd));
720
707
  if(ret == -1){
721
708
    perror("close");
722
709
  }
723
 
  gnutls_deinit(session);
 
710
  gnutls_deinit (session);
724
711
  return retval;
725
712
}
726
713
 
737
724
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
738
725
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
739
726
                             flags,
740
 
                             void* userdata){
 
727
                             void* userdata) {
741
728
  mandos_context *mc = userdata;
742
729
  assert(r);
743
730
  
744
731
  /* Called whenever a service has been resolved successfully or
745
732
     timed out */
746
733
  
747
 
  switch(event){
 
734
  switch (event) {
748
735
  default:
749
736
  case AVAHI_RESOLVER_FAILURE:
750
737
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
758
745
      avahi_address_snprint(ip, sizeof(ip), address);
759
746
      if(debug){
760
747
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
761
 
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
762
 
                ip, (intmax_t)interface, port);
 
748
                PRIu16 ") on port %d\n", name, host_name, ip,
 
749
                interface, port);
763
750
      }
764
751
      int ret = start_mandos_communication(ip, port, interface, mc);
765
 
      if(ret == 0){
 
752
      if (ret == 0){
766
753
        avahi_simple_poll_quit(mc->simple_poll);
767
754
      }
768
755
    }
770
757
  avahi_s_service_resolver_free(r);
771
758
}
772
759
 
773
 
static void browse_callback(AvahiSServiceBrowser *b,
774
 
                            AvahiIfIndex interface,
775
 
                            AvahiProtocol protocol,
776
 
                            AvahiBrowserEvent event,
777
 
                            const char *name,
778
 
                            const char *type,
779
 
                            const char *domain,
780
 
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
781
 
                            flags,
782
 
                            void* userdata){
 
760
static void browse_callback( AvahiSServiceBrowser *b,
 
761
                             AvahiIfIndex interface,
 
762
                             AvahiProtocol protocol,
 
763
                             AvahiBrowserEvent event,
 
764
                             const char *name,
 
765
                             const char *type,
 
766
                             const char *domain,
 
767
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
768
                             flags,
 
769
                             void* userdata) {
783
770
  mandos_context *mc = userdata;
784
771
  assert(b);
785
772
  
786
773
  /* Called whenever a new services becomes available on the LAN or
787
774
     is removed from the LAN */
788
775
  
789
 
  switch(event){
 
776
  switch (event) {
790
777
  default:
791
778
  case AVAHI_BROWSER_FAILURE:
792
779
    
801
788
       the callback function is called the Avahi server will free the
802
789
       resolver for us. */
803
790
    
804
 
    if(!(avahi_s_service_resolver_new(mc->server, interface,
 
791
    if (!(avahi_s_service_resolver_new(mc->server, interface,
805
792
                                       protocol, name, type, domain,
806
793
                                       AVAHI_PROTO_INET6, 0,
807
794
                                       resolve_callback, mc)))
822
809
}
823
810
 
824
811
int main(int argc, char *argv[]){
825
 
  AvahiSServiceBrowser *sb = NULL;
826
 
  int error;
827
 
  int ret;
828
 
  intmax_t tmpmax;
829
 
  int numchars;
830
 
  int exitcode = EXIT_SUCCESS;
831
 
  const char *interface = "eth0";
832
 
  struct ifreq network;
833
 
  int sd;
834
 
  uid_t uid;
835
 
  gid_t gid;
836
 
  char *connect_to = NULL;
837
 
  char tempdir[] = "/tmp/mandosXXXXXX";
838
 
  bool tempdir_created = false;
839
 
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
840
 
  const char *seckey = PATHDIR "/" SECKEY;
841
 
  const char *pubkey = PATHDIR "/" PUBKEY;
842
 
  
843
 
  mandos_context mc = { .simple_poll = NULL, .server = NULL,
844
 
                        .dh_bits = 1024, .priority = "SECURE256"
845
 
                        ":!CTYPE-X.509:+CTYPE-OPENPGP" };
846
 
  bool gnutls_initialized = false;
847
 
  bool gpgme_initialized = false;
848
 
  double delay = 2.5;
849
 
  
850
 
  {
851
 
    struct argp_option options[] = {
852
 
      { .name = "debug", .key = 128,
853
 
        .doc = "Debug mode", .group = 3 },
854
 
      { .name = "connect", .key = 'c',
855
 
        .arg = "ADDRESS:PORT",
856
 
        .doc = "Connect directly to a specific Mandos server",
857
 
        .group = 1 },
858
 
      { .name = "interface", .key = 'i',
859
 
        .arg = "NAME",
860
 
        .doc = "Interface that will be used to search for Mandos"
861
 
        " servers",
862
 
        .group = 1 },
863
 
      { .name = "seckey", .key = 's',
864
 
        .arg = "FILE",
865
 
        .doc = "OpenPGP secret key file base name",
866
 
        .group = 1 },
867
 
      { .name = "pubkey", .key = 'p',
868
 
        .arg = "FILE",
869
 
        .doc = "OpenPGP public key file base name",
870
 
        .group = 2 },
871
 
      { .name = "dh-bits", .key = 129,
872
 
        .arg = "BITS",
873
 
        .doc = "Bit length of the prime number used in the"
874
 
        " Diffie-Hellman key exchange",
875
 
        .group = 2 },
876
 
      { .name = "priority", .key = 130,
877
 
        .arg = "STRING",
878
 
        .doc = "GnuTLS priority string for the TLS handshake",
879
 
        .group = 1 },
880
 
      { .name = "delay", .key = 131,
881
 
        .arg = "SECONDS",
882
 
        .doc = "Maximum delay to wait for interface startup",
883
 
        .group = 2 },
884
 
      { .name = NULL }
885
 
    };
886
 
    
887
 
    error_t parse_opt(int key, char *arg,
888
 
                      struct argp_state *state){
889
 
      switch(key){
890
 
      case 128:                 /* --debug */
891
 
        debug = true;
892
 
        break;
893
 
      case 'c':                 /* --connect */
894
 
        connect_to = arg;
895
 
        break;
896
 
      case 'i':                 /* --interface */
897
 
        interface = arg;
898
 
        break;
899
 
      case 's':                 /* --seckey */
900
 
        seckey = arg;
901
 
        break;
902
 
      case 'p':                 /* --pubkey */
903
 
        pubkey = arg;
904
 
        break;
905
 
      case 129:                 /* --dh-bits */
906
 
        ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
907
 
        if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
908
 
           or arg[numchars] != '\0'){
909
 
          fprintf(stderr, "Bad number of DH bits\n");
910
 
          exit(EXIT_FAILURE);
911
 
        }
912
 
        mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
913
 
        break;
914
 
      case 130:                 /* --priority */
915
 
        mc.priority = arg;
916
 
        break;
917
 
      case 131:                 /* --delay */
918
 
        ret = sscanf(arg, "%lf%n", &delay, &numchars);
919
 
        if(ret < 1 or arg[numchars] != '\0'){
920
 
          fprintf(stderr, "Bad delay\n");
921
 
          exit(EXIT_FAILURE);
922
 
        }
923
 
        break;
924
 
      case ARGP_KEY_ARG:
925
 
        argp_usage(state);
926
 
      case ARGP_KEY_END:
927
 
        break;
928
 
      default:
929
 
        return ARGP_ERR_UNKNOWN;
930
 
      }
931
 
      return 0;
932
 
    }
933
 
    
934
 
    struct argp argp = { .options = options, .parser = parse_opt,
935
 
                         .args_doc = "",
936
 
                         .doc = "Mandos client -- Get and decrypt"
937
 
                         " passwords from a Mandos server" };
938
 
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
939
 
    if(ret == ARGP_ERR_UNKNOWN){
940
 
      fprintf(stderr, "Unknown error while parsing arguments\n");
941
 
      exitcode = EXIT_FAILURE;
942
 
      goto end;
943
 
    }
944
 
  }
945
 
  
946
 
  /* If the interface is down, bring it up */
947
 
  {
948
 
#ifdef __linux__
949
 
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
950
 
       messages to mess up the prompt */
951
 
    ret = klogctl(8, NULL, 5);
952
 
    if(ret == -1){
953
 
      perror("klogctl");
954
 
    }
955
 
#endif
956
 
    
957
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
958
 
    if(sd < 0){
959
 
      perror("socket");
960
 
      exitcode = EXIT_FAILURE;
961
 
#ifdef __linux__
962
 
      ret = klogctl(7, NULL, 0);
963
 
      if(ret == -1){
964
 
        perror("klogctl");
965
 
      }
966
 
#endif
967
 
      goto end;
968
 
    }
969
 
    strcpy(network.ifr_name, interface);
970
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
971
 
    if(ret == -1){
972
 
      perror("ioctl SIOCGIFFLAGS");
973
 
#ifdef __linux__
974
 
      ret = klogctl(7, NULL, 0);
975
 
      if(ret == -1){
976
 
        perror("klogctl");
977
 
      }
978
 
#endif
979
 
      exitcode = EXIT_FAILURE;
980
 
      goto end;
981
 
    }
982
 
    if((network.ifr_flags & IFF_UP) == 0){
983
 
      network.ifr_flags |= IFF_UP;
984
 
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
985
 
      if(ret == -1){
986
 
        perror("ioctl SIOCSIFFLAGS");
987
 
        exitcode = EXIT_FAILURE;
988
 
#ifdef __linux__
989
 
        ret = klogctl(7, NULL, 0);
990
 
        if(ret == -1){
991
 
          perror("klogctl");
992
 
        }
993
 
#endif
994
 
        goto end;
995
 
      }
996
 
    }
997
 
    /* sleep checking until interface is running */
998
 
    for(int i=0; i < delay * 4; i++){
 
812
    AvahiSServiceBrowser *sb = NULL;
 
813
    int error;
 
814
    int ret;
 
815
    int exitcode = EXIT_SUCCESS;
 
816
    const char *interface = "eth0";
 
817
    struct ifreq network;
 
818
    int sd;
 
819
    uid_t uid;
 
820
    gid_t gid;
 
821
    char *connect_to = NULL;
 
822
    char tempdir[] = "/tmp/mandosXXXXXX";
 
823
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
824
    const char *seckey = PATHDIR "/" SECKEY;
 
825
    const char *pubkey = PATHDIR "/" PUBKEY;
 
826
    
 
827
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
 
828
                          .dh_bits = 1024, .priority = "SECURE256"
 
829
                          ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
830
    bool gnutls_initalized = false;
 
831
    bool gpgme_initalized = false;
 
832
    
 
833
    {
 
834
      struct argp_option options[] = {
 
835
        { .name = "debug", .key = 128,
 
836
          .doc = "Debug mode", .group = 3 },
 
837
        { .name = "connect", .key = 'c',
 
838
          .arg = "ADDRESS:PORT",
 
839
          .doc = "Connect directly to a specific Mandos server",
 
840
          .group = 1 },
 
841
        { .name = "interface", .key = 'i',
 
842
          .arg = "NAME",
 
843
          .doc = "Interface that will be used to search for Mandos"
 
844
          " servers",
 
845
          .group = 1 },
 
846
        { .name = "seckey", .key = 's',
 
847
          .arg = "FILE",
 
848
          .doc = "OpenPGP secret key file base name",
 
849
          .group = 1 },
 
850
        { .name = "pubkey", .key = 'p',
 
851
          .arg = "FILE",
 
852
          .doc = "OpenPGP public key file base name",
 
853
          .group = 2 },
 
854
        { .name = "dh-bits", .key = 129,
 
855
          .arg = "BITS",
 
856
          .doc = "Bit length of the prime number used in the"
 
857
          " Diffie-Hellman key exchange",
 
858
          .group = 2 },
 
859
        { .name = "priority", .key = 130,
 
860
          .arg = "STRING",
 
861
          .doc = "GnuTLS priority string for the TLS handshake",
 
862
          .group = 1 },
 
863
        { .name = NULL }
 
864
      };
 
865
      
 
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) {
 
871
        case 128:               /* --debug */
 
872
          debug = true;
 
873
          break;
 
874
        case 'c':               /* --connect */
 
875
          connect_to = arg;
 
876
          break;
 
877
        case 'i':               /* --interface */
 
878
          interface = arg;
 
879
          break;
 
880
        case 's':               /* --seckey */
 
881
          seckey = arg;
 
882
          break;
 
883
        case 'p':               /* --pubkey */
 
884
          pubkey = arg;
 
885
          break;
 
886
        case 129:               /* --dh-bits */
 
887
          errno = 0;
 
888
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
889
          if (errno){
 
890
            perror("strtol");
 
891
            exit(EXIT_FAILURE);
 
892
          }
 
893
          break;
 
894
        case 130:               /* --priority */
 
895
          mc.priority = arg;
 
896
          break;
 
897
        case ARGP_KEY_ARG:
 
898
          argp_usage (state);
 
899
        case ARGP_KEY_END:
 
900
          break;
 
901
        default:
 
902
          return ARGP_ERR_UNKNOWN;
 
903
        }
 
904
        return 0;
 
905
      }
 
906
      
 
907
      struct argp argp = { .options = options, .parser = parse_opt,
 
908
                           .args_doc = "",
 
909
                           .doc = "Mandos client -- Get and decrypt"
 
910
                           " passwords from a Mandos server" };
 
911
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
912
      if (ret == ARGP_ERR_UNKNOWN){
 
913
        fprintf(stderr, "Unknown error while parsing arguments\n");
 
914
        exitcode = EXIT_FAILURE;
 
915
        goto end;
 
916
      }
 
917
    }
 
918
    
 
919
    /* If the interface is down, bring it up */
 
920
    {
 
921
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
922
      if(sd < 0) {
 
923
        perror("socket");
 
924
        exitcode = EXIT_FAILURE;
 
925
        goto end;
 
926
      }
 
927
      strcpy(network.ifr_name, interface);
999
928
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1000
929
      if(ret == -1){
1001
930
        perror("ioctl SIOCGIFFLAGS");
1002
 
      } else if(network.ifr_flags & IFF_RUNNING){
1003
 
        break;
1004
 
      }
1005
 
      struct timespec sleeptime = { .tv_nsec = 250000000 };
1006
 
      ret = nanosleep(&sleeptime, NULL);
1007
 
      if(ret == -1 and errno != EINTR){
1008
 
        perror("nanosleep");
1009
 
      }
1010
 
    }
1011
 
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
1012
 
    if(ret == -1){
1013
 
      perror("close");
1014
 
    }
1015
 
#ifdef __linux__
1016
 
    /* Restores kernel loglevel to default */
1017
 
    ret = klogctl(7, NULL, 0);
1018
 
    if(ret == -1){
1019
 
      perror("klogctl");
1020
 
    }
1021
 
#endif
1022
 
  }
1023
 
  
1024
 
  uid = getuid();
1025
 
  gid = getgid();
1026
 
  
1027
 
  setgid(gid);
1028
 
  if(ret == -1){
1029
 
    perror("setgid");
1030
 
  }
1031
 
  
1032
 
  ret = setuid(uid);
1033
 
  if(ret == -1){
1034
 
    perror("setuid");
1035
 
  }
1036
 
  
1037
 
  ret = init_gnutls_global(&mc, pubkey, seckey);
1038
 
  if(ret == -1){
1039
 
    fprintf(stderr, "init_gnutls_global failed\n");
1040
 
    exitcode = EXIT_FAILURE;
1041
 
    goto end;
1042
 
  } else {
1043
 
    gnutls_initialized = true;
1044
 
  }
1045
 
  
1046
 
  if(mkdtemp(tempdir) == NULL){
1047
 
    perror("mkdtemp");
1048
 
    goto end;
1049
 
  }
1050
 
  tempdir_created = true;
1051
 
  
1052
 
  if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
1053
 
    fprintf(stderr, "init_gpgme failed\n");
1054
 
    exitcode = EXIT_FAILURE;
1055
 
    goto end;
1056
 
  } else {
1057
 
    gpgme_initialized = true;
1058
 
  }
1059
 
  
1060
 
  if_index = (AvahiIfIndex) if_nametoindex(interface);
1061
 
  if(if_index == 0){
1062
 
    fprintf(stderr, "No such interface: \"%s\"\n", interface);
1063
 
    exitcode = EXIT_FAILURE;
1064
 
    goto end;
1065
 
  }
1066
 
  
1067
 
  if(connect_to != NULL){
1068
 
    /* Connect directly, do not use Zeroconf */
1069
 
    /* (Mainly meant for debugging) */
1070
 
    char *address = strrchr(connect_to, ':');
1071
 
    if(address == NULL){
1072
 
      fprintf(stderr, "No colon in address\n");
1073
 
      exitcode = EXIT_FAILURE;
1074
 
      goto end;
1075
 
    }
1076
 
    uint16_t port;
1077
 
    ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
1078
 
    if(ret < 1 or tmpmax != (uint16_t)tmpmax
1079
 
       or address[numchars+1] != '\0'){
1080
 
      fprintf(stderr, "Bad port number\n");
1081
 
      exitcode = EXIT_FAILURE;
1082
 
      goto end;
1083
 
    }
1084
 
    port = (uint16_t)tmpmax;
1085
 
    *address = '\0';
1086
 
    address = connect_to;
1087
 
    ret = start_mandos_communication(address, port, if_index, &mc);
1088
 
    if(ret < 0){
1089
 
      exitcode = EXIT_FAILURE;
1090
 
    } else {
1091
 
      exitcode = EXIT_SUCCESS;
1092
 
    }
1093
 
    goto end;
1094
 
  }
1095
 
  
1096
 
  if(not debug){
1097
 
    avahi_set_log_function(empty_log);
1098
 
  }
1099
 
  
1100
 
  /* Initialize the pseudo-RNG for Avahi */
1101
 
  srand((unsigned int) time(NULL));
1102
 
  
1103
 
  /* Allocate main Avahi loop object */
1104
 
  mc.simple_poll = avahi_simple_poll_new();
1105
 
  if(mc.simple_poll == NULL){
1106
 
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1107
 
    exitcode = EXIT_FAILURE;
1108
 
    goto end;
1109
 
  }
1110
 
  
1111
 
  {
1112
 
    AvahiServerConfig config;
1113
 
    /* Do not publish any local Zeroconf records */
1114
 
    avahi_server_config_init(&config);
1115
 
    config.publish_hinfo = 0;
1116
 
    config.publish_addresses = 0;
1117
 
    config.publish_workstation = 0;
1118
 
    config.publish_domain = 0;
1119
 
    
1120
 
    /* Allocate a new server */
1121
 
    mc.server = avahi_server_new(avahi_simple_poll_get
1122
 
                                 (mc.simple_poll), &config, NULL,
1123
 
                                 NULL, &error);
1124
 
    
1125
 
    /* Free the Avahi configuration data */
1126
 
    avahi_server_config_free(&config);
1127
 
  }
1128
 
  
1129
 
  /* Check if creating the Avahi server object succeeded */
1130
 
  if(mc.server == NULL){
1131
 
    fprintf(stderr, "Failed to create Avahi server: %s\n",
1132
 
            avahi_strerror(error));
1133
 
    exitcode = EXIT_FAILURE;
1134
 
    goto end;
1135
 
  }
1136
 
  
1137
 
  /* Create the Avahi service browser */
1138
 
  sb = avahi_s_service_browser_new(mc.server, if_index,
1139
 
                                   AVAHI_PROTO_INET6, "_mandos._tcp",
1140
 
                                   NULL, 0, browse_callback, &mc);
1141
 
  if(sb == NULL){
1142
 
    fprintf(stderr, "Failed to create service browser: %s\n",
1143
 
            avahi_strerror(avahi_server_errno(mc.server)));
1144
 
    exitcode = EXIT_FAILURE;
1145
 
    goto end;
1146
 
  }
1147
 
  
1148
 
  /* Run the main loop */
1149
 
  
1150
 
  if(debug){
1151
 
    fprintf(stderr, "Starting Avahi loop search\n");
1152
 
  }
1153
 
  
1154
 
  avahi_simple_poll_loop(mc.simple_poll);
1155
 
  
 
931
        exitcode = EXIT_FAILURE;
 
932
        goto end;
 
933
      }
 
934
      if((network.ifr_flags & IFF_UP) == 0){
 
935
        network.ifr_flags |= IFF_UP;
 
936
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
937
        if(ret == -1){
 
938
          perror("ioctl SIOCSIFFLAGS");
 
939
          exitcode = EXIT_FAILURE;
 
940
          goto end;
 
941
        }
 
942
      }
 
943
      ret = TEMP_FAILURE_RETRY(close(sd));
 
944
      if(ret == -1){
 
945
        perror("close");
 
946
      }
 
947
    }
 
948
    
 
949
    uid = getuid();
 
950
    gid = getgid();
 
951
    
 
952
    ret = setuid(uid);
 
953
    if (ret == -1){
 
954
      perror("setuid");
 
955
    }
 
956
    
 
957
    setgid(gid);
 
958
    if (ret == -1){
 
959
      perror("setgid");
 
960
    }
 
961
    
 
962
    ret = init_gnutls_global(&mc, pubkey, seckey);
 
963
    if (ret == -1){
 
964
      fprintf(stderr, "init_gnutls_global failed\n");
 
965
      exitcode = EXIT_FAILURE;
 
966
      goto end;
 
967
    } else {
 
968
      gnutls_initalized = true;
 
969
    }
 
970
    
 
971
    if(mkdtemp(tempdir) == NULL){
 
972
      perror("mkdtemp");
 
973
      tempdir[0] = '\0';
 
974
      goto end;
 
975
    }
 
976
    
 
977
    if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
 
978
      fprintf(stderr, "gpgme_initalized failed\n");
 
979
      exitcode = EXIT_FAILURE;
 
980
      goto end;
 
981
    } else {
 
982
      gpgme_initalized = true;
 
983
    }
 
984
    
 
985
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
986
    if(if_index == 0){
 
987
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
988
      exit(EXIT_FAILURE);
 
989
    }
 
990
    
 
991
    if(connect_to != NULL){
 
992
      /* Connect directly, do not use Zeroconf */
 
993
      /* (Mainly meant for debugging) */
 
994
      char *address = strrchr(connect_to, ':');
 
995
      if(address == NULL){
 
996
        fprintf(stderr, "No colon in address\n");
 
997
        exitcode = EXIT_FAILURE;
 
998
        goto end;
 
999
      }
 
1000
      errno = 0;
 
1001
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
1002
      if(errno){
 
1003
        perror("Bad port number");
 
1004
        exitcode = EXIT_FAILURE;
 
1005
        goto end;
 
1006
      }
 
1007
      *address = '\0';
 
1008
      address = connect_to;
 
1009
      ret = start_mandos_communication(address, port, if_index, &mc);
 
1010
      if(ret < 0){
 
1011
        exitcode = EXIT_FAILURE;
 
1012
      } else {
 
1013
        exitcode = EXIT_SUCCESS;
 
1014
      }
 
1015
      goto end;
 
1016
    }
 
1017
    
 
1018
    if (not debug){
 
1019
      avahi_set_log_function(empty_log);
 
1020
    }
 
1021
    
 
1022
    /* Initialize the pseudo-RNG for Avahi */
 
1023
    srand((unsigned int) time(NULL));
 
1024
    
 
1025
    /* Allocate main Avahi loop object */
 
1026
    mc.simple_poll = avahi_simple_poll_new();
 
1027
    if (mc.simple_poll == NULL) {
 
1028
        fprintf(stderr, "Avahi: Failed to create simple poll"
 
1029
                " object.\n");
 
1030
        exitcode = EXIT_FAILURE;
 
1031
        goto end;
 
1032
    }
 
1033
    
 
1034
    {
 
1035
      AvahiServerConfig config;
 
1036
      /* Do not publish any local Zeroconf records */
 
1037
      avahi_server_config_init(&config);
 
1038
      config.publish_hinfo = 0;
 
1039
      config.publish_addresses = 0;
 
1040
      config.publish_workstation = 0;
 
1041
      config.publish_domain = 0;
 
1042
      
 
1043
      /* Allocate a new server */
 
1044
      mc.server = avahi_server_new(avahi_simple_poll_get
 
1045
                                   (mc.simple_poll), &config, NULL,
 
1046
                                   NULL, &error);
 
1047
      
 
1048
      /* Free the Avahi configuration data */
 
1049
      avahi_server_config_free(&config);
 
1050
    }
 
1051
    
 
1052
    /* Check if creating the Avahi server object succeeded */
 
1053
    if (mc.server == NULL) {
 
1054
        fprintf(stderr, "Failed to create Avahi server: %s\n",
 
1055
                avahi_strerror(error));
 
1056
        exitcode = EXIT_FAILURE;
 
1057
        goto end;
 
1058
    }
 
1059
    
 
1060
    /* Create the Avahi service browser */
 
1061
    sb = avahi_s_service_browser_new(mc.server, if_index,
 
1062
                                     AVAHI_PROTO_INET6,
 
1063
                                     "_mandos._tcp", NULL, 0,
 
1064
                                     browse_callback, &mc);
 
1065
    if (sb == NULL) {
 
1066
        fprintf(stderr, "Failed to create service browser: %s\n",
 
1067
                avahi_strerror(avahi_server_errno(mc.server)));
 
1068
        exitcode = EXIT_FAILURE;
 
1069
        goto end;
 
1070
    }
 
1071
    
 
1072
    /* Run the main loop */
 
1073
    
 
1074
    if (debug){
 
1075
      fprintf(stderr, "Starting Avahi loop search\n");
 
1076
    }
 
1077
    
 
1078
    avahi_simple_poll_loop(mc.simple_poll);
 
1079
    
1156
1080
 end:
1157
 
  
1158
 
  if(debug){
1159
 
    fprintf(stderr, "%s exiting\n", argv[0]);
1160
 
  }
1161
 
  
1162
 
  /* Cleanup things */
1163
 
  if(sb != NULL)
1164
 
    avahi_s_service_browser_free(sb);
1165
 
  
1166
 
  if(mc.server != NULL)
1167
 
    avahi_server_free(mc.server);
1168
 
  
1169
 
  if(mc.simple_poll != NULL)
1170
 
    avahi_simple_poll_free(mc.simple_poll);
1171
 
  
1172
 
  if(gnutls_initialized){
1173
 
    gnutls_certificate_free_credentials(mc.cred);
1174
 
    gnutls_global_deinit();
1175
 
    gnutls_dh_params_deinit(mc.dh_params);
1176
 
  }
1177
 
  
1178
 
  if(gpgme_initialized){
1179
 
    gpgme_release(mc.ctx);
1180
 
  }
1181
 
  
1182
 
  /* Removes the temp directory used by GPGME */
1183
 
  if(tempdir_created){
1184
 
    DIR *d;
1185
 
    struct dirent *direntry;
1186
 
    d = opendir(tempdir);
1187
 
    if(d == NULL){
1188
 
      if(errno != ENOENT){
 
1081
    
 
1082
    if (debug){
 
1083
      fprintf(stderr, "%s exiting\n", argv[0]);
 
1084
    }
 
1085
    
 
1086
    /* Cleanup things */
 
1087
    if (sb != NULL)
 
1088
        avahi_s_service_browser_free(sb);
 
1089
    
 
1090
    if (mc.server != NULL)
 
1091
        avahi_server_free(mc.server);
 
1092
    
 
1093
    if (mc.simple_poll != NULL)
 
1094
        avahi_simple_poll_free(mc.simple_poll);
 
1095
    
 
1096
    if (gnutls_initalized){
 
1097
      gnutls_certificate_free_credentials(mc.cred);
 
1098
      gnutls_global_deinit ();
 
1099
      gnutls_dh_params_deinit(mc.dh_params);
 
1100
    }
 
1101
    
 
1102
    if(gpgme_initalized){
 
1103
      gpgme_release(mc.ctx);
 
1104
    }
 
1105
    
 
1106
    /* Removes the temp directory used by GPGME */
 
1107
    if(tempdir[0] != '\0'){
 
1108
      DIR *d;
 
1109
      struct dirent *direntry;
 
1110
      d = opendir(tempdir);
 
1111
      if(d == NULL){
1189
1112
        perror("opendir");
1190
 
      }
1191
 
    } else {
1192
 
      while(true){
1193
 
        direntry = readdir(d);
1194
 
        if(direntry == NULL){
1195
 
          break;
1196
 
        }
1197
 
        /* Skip "." and ".." */
1198
 
        if(direntry->d_name[0] == '.'
1199
 
           and (direntry->d_name[1] == '\0'
1200
 
                or (direntry->d_name[1] == '.'
1201
 
                    and direntry->d_name[2] == '\0'))){
1202
 
          continue;
1203
 
        }
1204
 
        char *fullname = NULL;
1205
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
1206
 
                       direntry->d_name);
1207
 
        if(ret < 0){
1208
 
          perror("asprintf");
1209
 
          continue;
1210
 
        }
1211
 
        ret = remove(fullname);
1212
 
        if(ret == -1){
1213
 
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1214
 
                  strerror(errno));
1215
 
        }
1216
 
        free(fullname);
1217
 
      }
1218
 
      closedir(d);
1219
 
    }
1220
 
    ret = rmdir(tempdir);
1221
 
    if(ret == -1 and errno != ENOENT){
1222
 
      perror("rmdir");
1223
 
    }
1224
 
  }
1225
 
  
1226
 
  return exitcode;
 
1113
      } else {
 
1114
        while(true){
 
1115
          direntry = readdir(d);
 
1116
          if(direntry == NULL){
 
1117
            break;
 
1118
          }
 
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
          }
 
1134
        }
 
1135
        closedir(d);
 
1136
      }
 
1137
      ret = rmdir(tempdir);
 
1138
      if(ret == -1){
 
1139
        perror("rmdir");
 
1140
      }
 
1141
    }
 
1142
          
 
1143
    return exitcode;
1227
1144
}