/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/mandosclient.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-03 03:33:56 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080803033356-6aemgj0g0hoz91ow
* plugins.d/mandosclient.c (pgp_packet_decrypt): Renamed variables.
                                                 On debug, show
                                                 decrypted plaintext
                                                 in hexadecimal.  Free
                                                 the GPGME data
                                                 buffers even on
                                                 errors.

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
#define _LARGEFILE_SOURCE
33
33
#define _FILE_OFFSET_BITS 64
34
34
 
35
 
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY() */
36
 
 
37
35
#include <stdio.h>
38
36
#include <assert.h>
39
37
#include <stdlib.h>
51
49
#include <avahi-common/malloc.h>
52
50
#include <avahi-common/error.h>
53
51
 
54
 
/* Mandos client part */
 
52
//mandos client part
55
53
#include <sys/types.h>          /* socket(), inet_pton() */
56
54
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
57
55
                                   struct in6_addr, inet_pton() */
64
62
#include <string.h>             /* memset */
65
63
#include <arpa/inet.h>          /* inet_pton() */
66
64
#include <iso646.h>             /* not */
67
 
#include <net/if.h>             /* IF_NAMESIZE */
68
 
#include <argp.h>               /* struct argp_option,
69
 
                                   struct argp_state, struct argp,
70
 
                                   argp_parse() */
71
 
/* GPGME */
 
65
 
 
66
// gpgme
72
67
#include <errno.h>              /* perror() */
73
68
#include <gpgme.h>
74
69
 
 
70
// getopt_long
 
71
#include <getopt.h>
 
72
 
75
73
#define BUFFER_SIZE 256
76
74
 
 
75
static const char *keydir = "/conf/conf.d/mandos";
 
76
static const char *pubkeyfile = "pubkey.txt";
 
77
static const char *seckeyfile = "seckey.txt";
 
78
 
77
79
bool debug = false;
78
 
const char *keydir = "/conf/conf.d/mandos";
79
 
const char *argp_program_version = "mandosclient 0.9";
80
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
81
 
const char mandos_protocol_version[] = "1";
82
80
 
83
81
/* Used for passing in values through all the callback functions */
84
82
typedef struct {
86
84
  AvahiServer *server;
87
85
  gnutls_certificate_credentials_t cred;
88
86
  unsigned int dh_bits;
89
 
  gnutls_dh_params_t dh_params;
90
87
  const char *priority;
91
88
} mandos_context;
92
89
 
93
 
size_t adjustbuffer(char **buffer, size_t buffer_length,
94
 
                  size_t buffer_capacity){
95
 
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
96
 
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
97
 
    if (buffer == NULL){
98
 
      return 0;
99
 
    }
100
 
    buffer_capacity += BUFFER_SIZE;
101
 
  }
102
 
  return buffer_capacity;
103
 
}
104
 
 
105
90
/* 
106
91
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
107
92
 * Returns -1 on error
114
99
  gpgme_ctx_t ctx;
115
100
  gpgme_error_t rc;
116
101
  ssize_t ret;
117
 
  size_t plaintext_capacity = 0;
 
102
  ssize_t plaintext_capacity = 0;
118
103
  ssize_t plaintext_length = 0;
119
104
  gpgme_engine_info_t engine_info;
120
105
  
230
215
  
231
216
  *plaintext = NULL;
232
217
  while(true){
233
 
    plaintext_capacity = adjustbuffer(plaintext, (size_t)plaintext_length,
234
 
                                      plaintext_capacity);
235
 
    if (plaintext_capacity == 0){
236
 
        perror("adjustbuffer");
 
218
    if (plaintext_length + BUFFER_SIZE > plaintext_capacity){
 
219
      *plaintext = realloc(*plaintext,
 
220
                            (unsigned int)plaintext_capacity
 
221
                            + BUFFER_SIZE);
 
222
      if (*plaintext == NULL){
 
223
        perror("realloc");
237
224
        plaintext_length = -1;
238
225
        goto decrypt_end;
 
226
      }
 
227
      plaintext_capacity += BUFFER_SIZE;
239
228
    }
240
229
    
241
230
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
255
244
 
256
245
  if(debug){
257
246
    fprintf(stderr, "Decrypted password is: ");
258
 
    for(ssize_t i = 0; i < plaintext_length; i++){
 
247
    for(size_t i = 0; i < plaintext_length; i++){
259
248
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
260
249
    }
261
250
    fprintf(stderr, "\n");
278
267
  return ret;
279
268
}
280
269
 
281
 
/* GnuTLS log function callback */
282
270
static void debuggnutls(__attribute__((unused)) int level,
283
271
                        const char* string){
284
 
  fprintf(stderr, "GnuTLS: %s", string);
 
272
  fprintf(stderr, "%s", string);
285
273
}
286
274
 
287
 
static int init_gnutls_global(mandos_context *mc,
288
 
                              const char *pubkeyfile,
289
 
                              const char *seckeyfile){
 
275
static int initgnutls(mandos_context *mc, gnutls_session_t *session,
 
276
                      gnutls_dh_params_t *dh_params){
 
277
  const char *err;
290
278
  int ret;
291
279
  
292
280
  if(debug){
295
283
 
296
284
  if ((ret = gnutls_global_init ())
297
285
      != GNUTLS_E_SUCCESS) {
298
 
    fprintf (stderr, "GnuTLS global_init: %s\n",
299
 
             safer_gnutls_strerror(ret));
 
286
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
300
287
    return -1;
301
288
  }
302
289
  
303
290
  if (debug){
304
 
    /* "Use a log level over 10 to enable all debugging options."
305
 
     * - GnuTLS manual
306
 
     */
307
291
    gnutls_global_set_log_level(11);
308
292
    gnutls_global_set_log_function(debuggnutls);
309
293
  }
310
294
  
311
 
  /* OpenPGP credentials */
 
295
  /* openpgp credentials */
312
296
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
313
297
      != GNUTLS_E_SUCCESS) {
314
 
    fprintf (stderr, "GnuTLS memory error: %s\n",
 
298
    fprintf (stderr, "memory error: %s\n",
315
299
             safer_gnutls_strerror(ret));
316
300
    return -1;
317
301
  }
325
309
  ret = gnutls_certificate_set_openpgp_key_file
326
310
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
327
311
  if (ret != GNUTLS_E_SUCCESS) {
328
 
    fprintf(stderr,
329
 
            "Error[%d] while reading the OpenPGP key pair ('%s',"
330
 
            " '%s')\n", ret, pubkeyfile, seckeyfile);
331
 
    fprintf(stdout, "The GnuTLS error is: %s\n",
 
312
    fprintf
 
313
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
314
       " '%s')\n",
 
315
       ret, pubkeyfile, seckeyfile);
 
316
    fprintf(stdout, "The Error is: %s\n",
332
317
            safer_gnutls_strerror(ret));
333
318
    return -1;
334
319
  }
335
320
  
336
 
  /* GnuTLS server initialization */
337
 
  ret = gnutls_dh_params_init(&mc->dh_params);
338
 
  if (ret != GNUTLS_E_SUCCESS) {
339
 
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
340
 
             " %s\n", safer_gnutls_strerror(ret));
341
 
    return -1;
342
 
  }
343
 
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
344
 
  if (ret != GNUTLS_E_SUCCESS) {
345
 
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
346
 
             safer_gnutls_strerror(ret));
347
 
    return -1;
348
 
  }
349
 
  
350
 
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
351
 
 
352
 
  return 0;
353
 
}
354
 
 
355
 
static int init_gnutls_session(mandos_context *mc, gnutls_session_t *session){
356
 
  int ret;
357
 
  /* GnuTLS session creation */
358
 
  ret = gnutls_init(session, GNUTLS_SERVER);
359
 
  if (ret != GNUTLS_E_SUCCESS){
 
321
  //GnuTLS server initialization
 
322
  if ((ret = gnutls_dh_params_init(dh_params))
 
323
      != GNUTLS_E_SUCCESS) {
 
324
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
 
325
             safer_gnutls_strerror(ret));
 
326
    return -1;
 
327
  }
 
328
  
 
329
  if ((ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits))
 
330
      != GNUTLS_E_SUCCESS) {
 
331
    fprintf (stderr, "Error in prime generation: %s\n",
 
332
             safer_gnutls_strerror(ret));
 
333
    return -1;
 
334
  }
 
335
  
 
336
  gnutls_certificate_set_dh_params(mc->cred, *dh_params);
 
337
  
 
338
  // GnuTLS session creation
 
339
  if ((ret = gnutls_init(session, GNUTLS_SERVER))
 
340
      != GNUTLS_E_SUCCESS){
360
341
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
361
342
            safer_gnutls_strerror(ret));
362
343
  }
363
344
  
364
 
  {
365
 
    const char *err;
366
 
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
367
 
    if (ret != GNUTLS_E_SUCCESS) {
368
 
      fprintf(stderr, "Syntax error at: %s\n", err);
369
 
      fprintf(stderr, "GnuTLS error: %s\n",
370
 
              safer_gnutls_strerror(ret));
371
 
      return -1;
372
 
    }
 
345
  if ((ret = gnutls_priority_set_direct(*session, mc->priority, &err))
 
346
      != GNUTLS_E_SUCCESS) {
 
347
    fprintf(stderr, "Syntax error at: %s\n", err);
 
348
    fprintf(stderr, "GnuTLS error: %s\n",
 
349
            safer_gnutls_strerror(ret));
 
350
    return -1;
373
351
  }
374
352
  
375
 
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
376
 
                               mc->cred);
377
 
  if (ret != GNUTLS_E_SUCCESS) {
378
 
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
 
353
  if ((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
354
                                    mc->cred))
 
355
      != GNUTLS_E_SUCCESS) {
 
356
    fprintf(stderr, "Error setting a credentials set: %s\n",
379
357
            safer_gnutls_strerror(ret));
380
358
    return -1;
381
359
  }
389
367
  return 0;
390
368
}
391
369
 
392
 
/* Avahi log function callback */
393
370
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
394
371
                      __attribute__((unused)) const char *txt){}
395
372
 
396
 
/* Called when a Mandos server is found */
397
373
static int start_mandos_communication(const char *ip, uint16_t port,
398
374
                                      AvahiIfIndex if_index,
399
375
                                      mandos_context *mc){
404
380
  size_t buffer_length = 0;
405
381
  size_t buffer_capacity = 0;
406
382
  ssize_t decrypted_buffer_size;
407
 
  size_t written;
 
383
  size_t written = 0;
408
384
  int retval = 0;
409
385
  char interface[IF_NAMESIZE];
410
386
  gnutls_session_t session;
411
387
  gnutls_dh_params_t dh_params;
412
388
  
413
 
  ret = init_gnutls_session (mc, &session);
414
 
  if (ret != 0){
415
 
    return -1;
416
 
  }
417
 
  
418
389
  if(debug){
419
390
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
420
391
            ip, port);
436
407
  
437
408
  memset(&to,0,sizeof(to));     /* Spurious warning */
438
409
  to.sin6_family = AF_INET6;
439
 
  /* It would be nice to have a way to detect if we were passed an
440
 
     IPv4 address here.   Now we assume an IPv6 address. */
441
410
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
442
411
  if (ret < 0 ){
443
412
    perror("inet_pton");
469
438
    perror("connect");
470
439
    return -1;
471
440
  }
472
 
 
473
 
  const char *out = mandos_protocol_version;
474
 
  written = 0;
475
 
  while (true){
476
 
    size_t out_size = strlen(out);
477
 
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
478
 
                                   out_size - written));
479
 
    if (ret == -1){
480
 
      perror("write");
481
 
      retval = -1;
482
 
      goto mandos_end;
483
 
    }
484
 
    written += (size_t)ret;
485
 
    if(written < out_size){
486
 
      continue;
487
 
    } else {
488
 
      if (out == mandos_protocol_version){
489
 
        written = 0;
490
 
        out = "\r\n";
491
 
      } else {
492
 
        break;
493
 
      }
494
 
    }
 
441
  
 
442
  ret = initgnutls (mc, &session, &dh_params);
 
443
  if (ret != 0){
 
444
    retval = -1;
 
445
    return -1;
495
446
  }
496
 
 
 
447
  
 
448
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
 
449
  
497
450
  if(debug){
498
451
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
499
452
  }
500
453
  
501
 
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
502
 
  
503
454
  ret = gnutls_handshake (session);
504
455
  
505
456
  if (ret != GNUTLS_E_SUCCESS){
506
457
    if(debug){
507
 
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
458
      fprintf(stderr, "\n*** Handshake failed ***\n");
508
459
      gnutls_perror (ret);
509
460
    }
510
461
    retval = -1;
511
 
    goto mandos_end;
 
462
    goto exit;
512
463
  }
513
464
  
514
 
  /* Read OpenPGP packet that contains the wanted password */
 
465
  //Retrieve OpenPGP packet that contains the wanted password
515
466
  
516
467
  if(debug){
517
468
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
519
470
  }
520
471
 
521
472
  while(true){
522
 
    buffer_capacity = adjustbuffer(&buffer, buffer_length, buffer_capacity);
523
 
    if (buffer_capacity == 0){
524
 
      perror("adjustbuffer");
525
 
      retval = -1;
526
 
      goto mandos_end;
 
473
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
 
474
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
 
475
      if (buffer == NULL){
 
476
        perror("realloc");
 
477
        goto exit;
 
478
      }
 
479
      buffer_capacity += BUFFER_SIZE;
527
480
    }
528
481
    
529
482
    ret = gnutls_record_recv(session, buffer+buffer_length,
539
492
      case GNUTLS_E_REHANDSHAKE:
540
493
        ret = gnutls_handshake (session);
541
494
        if (ret < 0){
542
 
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
495
          fprintf(stderr, "\n*** Handshake failed ***\n");
543
496
          gnutls_perror (ret);
544
497
          retval = -1;
545
 
          goto mandos_end;
 
498
          goto exit;
546
499
        }
547
500
        break;
548
501
      default:
549
502
        fprintf(stderr, "Unknown error while reading data from"
550
 
                " encrypted session with Mandos server\n");
 
503
                " encrypted session with mandos server\n");
551
504
        retval = -1;
552
505
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
553
 
        goto mandos_end;
 
506
        goto exit;
554
507
      }
555
508
    } else {
556
509
      buffer_length += (size_t) ret;
557
510
    }
558
511
  }
559
512
  
560
 
  if(debug){
561
 
    fprintf(stderr, "Closing TLS session\n");
562
 
  }
563
 
  
564
 
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
565
 
  
566
513
  if (buffer_length > 0){
567
514
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
568
515
                                               buffer_length,
569
516
                                               &decrypted_buffer,
570
517
                                               keydir);
571
518
    if (decrypted_buffer_size >= 0){
572
 
      written = 0;
573
519
      while(written < (size_t) decrypted_buffer_size){
574
520
        ret = (int)fwrite (decrypted_buffer + written, 1,
575
521
                           (size_t)decrypted_buffer_size - written,
589
535
      retval = -1;
590
536
    }
591
537
  }
592
 
  
593
 
  /* Shutdown procedure */
594
 
  
595
 
 mandos_end:
 
538
 
 
539
  //shutdown procedure
 
540
 
 
541
  if(debug){
 
542
    fprintf(stderr, "Closing TLS session\n");
 
543
  }
 
544
 
596
545
  free(buffer);
 
546
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
547
 exit:
597
548
  close(tcp_sd);
598
549
  gnutls_deinit (session);
599
550
  gnutls_certificate_free_credentials (mc->cred);
624
575
  switch (event) {
625
576
  default:
626
577
  case AVAHI_RESOLVER_FAILURE:
627
 
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
628
 
            " of type '%s' in domain '%s': %s\n", name, type, domain,
 
578
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
 
579
            " type '%s' in domain '%s': %s\n", name, type, domain,
629
580
            avahi_strerror(avahi_server_errno(mc->server)));
630
581
    break;
631
582
    
634
585
      char ip[AVAHI_ADDRESS_STR_MAX];
635
586
      avahi_address_snprint(ip, sizeof(ip), address);
636
587
      if(debug){
637
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %d) on"
638
 
                " port %d\n", name, host_name, ip, interface, port);
 
588
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
 
589
                " port %d\n", name, host_name, ip, port);
639
590
      }
640
591
      int ret = start_mandos_communication(ip, port, interface, mc);
641
592
      if (ret == 0){
666
617
  default:
667
618
  case AVAHI_BROWSER_FAILURE:
668
619
    
669
 
    fprintf(stderr, "(Avahi browser) %s\n",
 
620
    fprintf(stderr, "(Browser) %s\n",
670
621
            avahi_strerror(avahi_server_errno(mc->server)));
671
622
    avahi_simple_poll_quit(mc->simple_poll);
672
623
    return;
673
624
    
674
625
  case AVAHI_BROWSER_NEW:
675
 
    /* We ignore the returned Avahi resolver object. In the callback
676
 
       function we free it. If the Avahi server is terminated before
677
 
       the callback function is called the Avahi server will free the
678
 
       resolver for us. */
 
626
    /* We ignore the returned resolver object. In the callback
 
627
       function we free it. If the server is terminated before
 
628
       the callback function is called the server will free
 
629
       the resolver for us. */
679
630
    
680
631
    if (!(avahi_s_service_resolver_new(mc->server, interface,
681
632
                                       protocol, name, type, domain,
682
633
                                       AVAHI_PROTO_INET6, 0,
683
634
                                       resolve_callback, mc)))
684
 
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
685
 
              name, avahi_strerror(avahi_server_errno(mc->server)));
 
635
      fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
 
636
              avahi_strerror(avahi_server_errno(mc->server)));
686
637
    break;
687
638
    
688
639
  case AVAHI_BROWSER_REMOVE:
690
641
    
691
642
  case AVAHI_BROWSER_ALL_FOR_NOW:
692
643
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
693
 
    if(debug){
694
 
      fprintf(stderr, "No Mandos server found, still searching...\n");
695
 
    }
696
644
    break;
697
645
  }
698
646
}
718
666
}
719
667
 
720
668
 
721
 
int main(int argc, char *argv[]){
 
669
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
 
670
    AvahiServerConfig config;
722
671
    AvahiSServiceBrowser *sb = NULL;
723
672
    int error;
724
673
    int ret;
725
 
    int exitcode = EXIT_SUCCESS;
 
674
    int debug_int;
 
675
    int returncode = EXIT_SUCCESS;
726
676
    const char *interface = "eth0";
727
677
    struct ifreq network;
728
678
    int sd;
729
 
    uid_t uid;
730
 
    gid_t gid;
731
679
    char *connect_to = NULL;
732
680
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
733
 
    const char *pubkeyfile = "pubkey.txt";
734
 
    const char *seckeyfile = "seckey.txt";
735
681
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
736
682
                          .dh_bits = 1024, .priority = "SECURE256"};
737
683
    
738
 
    {
739
 
      struct argp_option options[] = {
740
 
        { .name = "debug", .key = 128,
741
 
          .doc = "Debug mode", .group = 3 },
742
 
        { .name = "connect", .key = 'c',
743
 
          .arg = "IP",
744
 
          .doc = "Connect directly to a sepcified mandos server", .group = 1 },
745
 
        { .name = "interface", .key = 'i',
746
 
          .arg = "INTERFACE",
747
 
          .doc = "Interface that Avahi will conntect through", .group = 1 },
748
 
        { .name = "keydir", .key = 'd',
749
 
          .arg = "KEYDIR",
750
 
          .doc = "Directory where the openpgp keyring is", .group = 1 },
751
 
        { .name = "seckey", .key = 's',
752
 
          .arg = "SECKEY",
753
 
          .doc = "Secret openpgp key for gnutls authentication", .group = 1 },
754
 
        { .name = "pubkey", .key = 'p',
755
 
          .arg = "PUBKEY",
756
 
          .doc = "Public openpgp key for gnutls authentication", .group = 2 },
757
 
        { .name = "dh-bits", .key = 129,
758
 
          .arg = "BITS",
759
 
          .doc = "dh-bits to use in gnutls communication", .group = 2 },
760
 
        { .name = "priority", .key = 130,
761
 
          .arg = "PRIORITY",
762
 
          .doc = "GNUTLS priority", .group = 1 },
763
 
        { .name = NULL }
764
 
      };
765
 
 
766
 
      
767
 
      error_t parse_opt (int key, char *arg, struct argp_state *state) {
768
 
        /* Get the INPUT argument from `argp_parse', which we know is a
769
 
           pointer to our plugin list pointer. */
770
 
        switch (key) {
771
 
        case 128:
772
 
          debug = true;
773
 
          break;
774
 
        case 'c':
775
 
          connect_to = arg;
776
 
          break;
777
 
        case 'i':
778
 
          interface = arg;
779
 
          break;
780
 
        case 'd':
781
 
          keydir = arg;
782
 
          break;
783
 
        case 's':
784
 
          seckeyfile = arg;
785
 
          break;
786
 
        case 'p':
787
 
          pubkeyfile = arg;
788
 
          break;
789
 
        case 129:
790
 
          errno = 0;
791
 
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
792
 
          if (errno){
793
 
            perror("strtol");
794
 
            exit(EXIT_FAILURE);
795
 
          }
796
 
          break;
797
 
        case 130:
798
 
          mc.priority = arg;
799
 
          break;
800
 
        case ARGP_KEY_ARG:
801
 
          argp_usage (state);
802
 
          break;
803
 
          case ARGP_KEY_END:
804
 
            break;
805
 
        default:
806
 
          return ARGP_ERR_UNKNOWN;
 
684
    debug_int = debug ? 1 : 0;
 
685
    while (true){
 
686
      struct option long_options[] = {
 
687
        {"debug", no_argument, &debug_int, 1},
 
688
        {"connect", required_argument, NULL, 'c'},
 
689
        {"interface", required_argument, NULL, 'i'},
 
690
        {"keydir", required_argument, NULL, 'd'},
 
691
        {"seckey", required_argument, NULL, 's'},
 
692
        {"pubkey", required_argument, NULL, 'p'},
 
693
        {"dh-bits", required_argument, NULL, 'D'},
 
694
        {"priority", required_argument, NULL, 'P'},
 
695
        {0, 0, 0, 0} };
 
696
      
 
697
      int option_index = 0;
 
698
      ret = getopt_long (argc, argv, "i:", long_options,
 
699
                         &option_index);
 
700
      
 
701
      if (ret == -1){
 
702
        break;
 
703
      }
 
704
      
 
705
      switch(ret){
 
706
      case 0:
 
707
        break;
 
708
      case 'i':
 
709
        interface = optarg;
 
710
        break;
 
711
      case 'c':
 
712
        connect_to = optarg;
 
713
        break;
 
714
      case 'd':
 
715
        keydir = optarg;
 
716
        break;
 
717
      case 'p':
 
718
        pubkeyfile = optarg;
 
719
        break;
 
720
      case 's':
 
721
        seckeyfile = optarg;
 
722
        break;
 
723
      case 'D':
 
724
        errno = 0;
 
725
        mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
 
726
        if (errno){
 
727
          perror("strtol");
 
728
          exit(EXIT_FAILURE);
807
729
        }
808
 
        return 0;
 
730
        break;
 
731
      case 'P':
 
732
        mc.priority = optarg;
 
733
        break;
 
734
      case '?':
 
735
      default:
 
736
        exit(EXIT_FAILURE);
809
737
      }
810
 
 
811
 
      struct argp argp = { .options = options, .parser = parse_opt,
812
 
                           .args_doc = "",
813
 
                           .doc = "Mandos client -- Get and decrypt passwords from mandos server" };
814
 
      argp_parse (&argp, argc, argv, 0, 0, NULL);
815
738
    }
816
 
      
 
739
    debug = debug_int ? true : false;
 
740
    
817
741
    pubkeyfile = combinepath(keydir, pubkeyfile);
818
742
    if (pubkeyfile == NULL){
819
743
      perror("combinepath");
820
 
      exitcode = EXIT_FAILURE;
821
 
      goto end;
 
744
      returncode = EXIT_FAILURE;
 
745
      goto exit;
822
746
    }
823
747
    
824
748
    seckeyfile = combinepath(keydir, seckeyfile);
825
749
    if (seckeyfile == NULL){
826
750
      perror("combinepath");
827
 
      goto end;
828
 
    }
829
 
 
830
 
    ret = init_gnutls_global(&mc, pubkeyfile, seckeyfile);
831
 
    if (ret == -1){
832
 
      fprintf(stderr, "init_gnutls_global\n");
833
 
      goto end;
834
 
    }
835
 
 
836
 
    uid = getuid();
837
 
    gid = getgid();
838
 
 
839
 
    ret = setuid(uid);
840
 
    if (ret == -1){
841
 
      perror("setuid");
842
 
    }
843
 
    
844
 
    setgid(gid);
845
 
    if (ret == -1){
846
 
      perror("setgid");
 
751
      goto exit;
847
752
    }
848
753
    
849
754
    if_index = (AvahiIfIndex) if_nametoindex(interface);
858
763
      char *address = strrchr(connect_to, ':');
859
764
      if(address == NULL){
860
765
        fprintf(stderr, "No colon in address\n");
861
 
        exitcode = EXIT_FAILURE;
862
 
        goto end;
 
766
        exit(EXIT_FAILURE);
863
767
      }
864
768
      errno = 0;
865
769
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
866
770
      if(errno){
867
771
        perror("Bad port number");
868
 
        exitcode = EXIT_FAILURE;
869
 
        goto end;
 
772
        exit(EXIT_FAILURE);
870
773
      }
871
774
      *address = '\0';
872
775
      address = connect_to;
873
776
      ret = start_mandos_communication(address, port, if_index, &mc);
874
777
      if(ret < 0){
875
 
        exitcode = EXIT_FAILURE;
 
778
        exit(EXIT_FAILURE);
876
779
      } else {
877
 
        exitcode = EXIT_SUCCESS;
 
780
        exit(EXIT_SUCCESS);
878
781
      }
879
 
      goto end;
880
782
    }
881
783
    
882
 
    /* If the interface is down, bring it up */
883
 
    {
884
 
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
885
 
      if(sd < 0) {
886
 
        perror("socket");
887
 
        exitcode = EXIT_FAILURE;
888
 
        goto end;
889
 
      }
890
 
      strcpy(network.ifr_name, interface); /* Spurious warning */
891
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
784
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
785
    if(sd < 0) {
 
786
      perror("socket");
 
787
      returncode = EXIT_FAILURE;
 
788
      goto exit;
 
789
    }
 
790
    strcpy(network.ifr_name, interface); /* Spurious warning */
 
791
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
792
    if(ret == -1){
 
793
      
 
794
      perror("ioctl SIOCGIFFLAGS");
 
795
      returncode = EXIT_FAILURE;
 
796
      goto exit;
 
797
    }
 
798
    if((network.ifr_flags & IFF_UP) == 0){
 
799
      network.ifr_flags |= IFF_UP;
 
800
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
892
801
      if(ret == -1){
893
 
        perror("ioctl SIOCGIFFLAGS");
894
 
        exitcode = EXIT_FAILURE;
895
 
        goto end;
896
 
      }
897
 
      if((network.ifr_flags & IFF_UP) == 0){
898
 
        network.ifr_flags |= IFF_UP;
899
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
900
 
        if(ret == -1){
901
 
          perror("ioctl SIOCSIFFLAGS");
902
 
          exitcode = EXIT_FAILURE;
903
 
          goto end;
904
 
        }
905
 
      }
906
 
      close(sd);
 
802
        perror("ioctl SIOCSIFFLAGS");
 
803
        returncode = EXIT_FAILURE;
 
804
        goto exit;
 
805
      }
907
806
    }
 
807
    close(sd);
908
808
    
909
809
    if (not debug){
910
810
      avahi_set_log_function(empty_log);
911
811
    }
912
812
    
913
 
    /* Initialize the pseudo-RNG for Avahi */
 
813
    /* Initialize the psuedo-RNG */
914
814
    srand((unsigned int) time(NULL));
915
 
    
916
 
    /* Allocate main Avahi loop object */
917
 
    mc.simple_poll = avahi_simple_poll_new();
918
 
    if (mc.simple_poll == NULL) {
919
 
        fprintf(stderr, "Avahi: Failed to create simple poll"
920
 
                " object.\n");
921
 
        exitcode = EXIT_FAILURE;
922
 
        goto end;
923
 
    }
924
 
 
925
 
    {
926
 
      AvahiServerConfig config;
927
 
      /* Do not publish any local Zeroconf records */
928
 
      avahi_server_config_init(&config);
929
 
      config.publish_hinfo = 0;
930
 
      config.publish_addresses = 0;
931
 
      config.publish_workstation = 0;
932
 
      config.publish_domain = 0;
933
 
 
934
 
      /* Allocate a new server */
935
 
      mc.server = avahi_server_new(avahi_simple_poll_get
936
 
                                   (mc.simple_poll), &config, NULL,
937
 
                                   NULL, &error);
938
 
    
939
 
      /* Free the Avahi configuration data */
940
 
      avahi_server_config_free(&config);
941
 
    }
942
 
    
943
 
    /* Check if creating the Avahi server object succeeded */
944
 
    if (mc.server == NULL) {
945
 
        fprintf(stderr, "Failed to create Avahi server: %s\n",
 
815
 
 
816
    /* Allocate main loop object */
 
817
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
 
818
        fprintf(stderr, "Failed to create simple poll object.\n");
 
819
        returncode = EXIT_FAILURE;
 
820
        goto exit;
 
821
    }
 
822
 
 
823
    /* Do not publish any local records */
 
824
    avahi_server_config_init(&config);
 
825
    config.publish_hinfo = 0;
 
826
    config.publish_addresses = 0;
 
827
    config.publish_workstation = 0;
 
828
    config.publish_domain = 0;
 
829
 
 
830
    /* Allocate a new server */
 
831
    mc.server=avahi_server_new(avahi_simple_poll_get(mc.simple_poll),
 
832
                               &config, NULL, NULL, &error);
 
833
    
 
834
    /* Free the configuration data */
 
835
    avahi_server_config_free(&config);
 
836
    
 
837
    /* Check if creating the server object succeeded */
 
838
    if (!mc.server) {
 
839
        fprintf(stderr, "Failed to create server: %s\n",
946
840
                avahi_strerror(error));
947
 
        exitcode = EXIT_FAILURE;
948
 
        goto end;
 
841
        returncode = EXIT_FAILURE;
 
842
        goto exit;
949
843
    }
950
844
    
951
 
    /* Create the Avahi service browser */
 
845
    /* Create the service browser */
952
846
    sb = avahi_s_service_browser_new(mc.server, if_index,
953
847
                                     AVAHI_PROTO_INET6,
954
848
                                     "_mandos._tcp", NULL, 0,
955
849
                                     browse_callback, &mc);
956
 
    if (sb == NULL) {
 
850
    if (!sb) {
957
851
        fprintf(stderr, "Failed to create service browser: %s\n",
958
852
                avahi_strerror(avahi_server_errno(mc.server)));
959
 
        exitcode = EXIT_FAILURE;
960
 
        goto end;
 
853
        returncode = EXIT_FAILURE;
 
854
        goto exit;
961
855
    }
962
856
    
963
857
    /* Run the main loop */
964
858
 
965
859
    if (debug){
966
 
      fprintf(stderr, "Starting Avahi loop search\n");
 
860
      fprintf(stderr, "Starting avahi loop search\n");
967
861
    }
968
862
    
969
863
    avahi_simple_poll_loop(mc.simple_poll);
970
864
    
971
 
 end:
 
865
 exit:
972
866
 
973
867
    if (debug){
974
868
      fprintf(stderr, "%s exiting\n", argv[0]);
975
869
    }
976
870
    
977
871
    /* Cleanup things */
978
 
    if (sb != NULL)
 
872
    if (sb)
979
873
        avahi_s_service_browser_free(sb);
980
874
    
981
 
    if (mc.server != NULL)
 
875
    if (mc.server)
982
876
        avahi_server_free(mc.server);
983
877
 
984
 
    if (mc.simple_poll != NULL)
 
878
    if (mc.simple_poll)
985
879
        avahi_simple_poll_free(mc.simple_poll);
986
880
    free(pubkeyfile);
987
881
    free(seckeyfile);
988
882
    
989
 
    return exitcode;
 
883
    return returncode;
990
884
}