/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-04 21:25:55 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080804212555-rm7xxjze65f8avy3
* server.py: Cosmetic changes.

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