/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/password-request.c

Added manual pages for:
      clients.conf
      mandos.conf
      mandos
      mandos-client
      password-prompt
      password-request

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));
 
322
    gnutls_global_deinit ();
300
323
    return -1;
301
324
  }
302
325
  
309
332
  ret = gnutls_certificate_set_openpgp_key_file
310
333
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
311
334
  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",
 
335
    fprintf(stderr,
 
336
            "Error[%d] while reading the OpenPGP key pair ('%s',"
 
337
            " '%s')\n", ret, pubkeyfile, seckeyfile);
 
338
    fprintf(stdout, "The GnuTLS error is: %s\n",
317
339
            safer_gnutls_strerror(ret));
318
 
    return -1;
319
 
  }
320
 
  
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){
 
340
    goto globalfail;
 
341
  }
 
342
  
 
343
  /* GnuTLS server initialization */
 
344
  ret = gnutls_dh_params_init(&mc->dh_params);
 
345
  if (ret != GNUTLS_E_SUCCESS) {
 
346
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
 
347
             " %s\n", safer_gnutls_strerror(ret));
 
348
    goto globalfail;
 
349
  }
 
350
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
351
  if (ret != GNUTLS_E_SUCCESS) {
 
352
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
 
353
             safer_gnutls_strerror(ret));
 
354
    goto globalfail;
 
355
  }
 
356
  
 
357
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
 
358
 
 
359
  return 0;
 
360
 
 
361
 globalfail:
 
362
 
 
363
  gnutls_certificate_free_credentials (mc->cred);
 
364
  gnutls_global_deinit ();
 
365
  return -1;
 
366
 
 
367
}
 
368
 
 
369
static int init_gnutls_session(mandos_context *mc,
 
370
                               gnutls_session_t *session){
 
371
  int ret;
 
372
  /* GnuTLS session creation */
 
373
  ret = gnutls_init(session, GNUTLS_SERVER);
 
374
  if (ret != GNUTLS_E_SUCCESS){
341
375
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
342
376
            safer_gnutls_strerror(ret));
343
377
  }
344
378
  
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;
 
379
  {
 
380
    const char *err;
 
381
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
 
382
    if (ret != GNUTLS_E_SUCCESS) {
 
383
      fprintf(stderr, "Syntax error at: %s\n", err);
 
384
      fprintf(stderr, "GnuTLS error: %s\n",
 
385
              safer_gnutls_strerror(ret));
 
386
      gnutls_deinit (*session);
 
387
      return -1;
 
388
    }
351
389
  }
352
390
  
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",
 
391
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
392
                               mc->cred);
 
393
  if (ret != GNUTLS_E_SUCCESS) {
 
394
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
357
395
            safer_gnutls_strerror(ret));
 
396
    gnutls_deinit (*session);
358
397
    return -1;
359
398
  }
360
399
  
367
406
  return 0;
368
407
}
369
408
 
 
409
/* Avahi log function callback */
370
410
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
371
411
                      __attribute__((unused)) const char *txt){}
372
412
 
 
413
/* Called when a Mandos server is found */
373
414
static int start_mandos_communication(const char *ip, uint16_t port,
374
415
                                      AvahiIfIndex if_index,
375
416
                                      mandos_context *mc){
376
417
  int ret, tcp_sd;
377
 
  struct sockaddr_in6 to;
 
418
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
378
419
  char *buffer = NULL;
379
420
  char *decrypted_buffer;
380
421
  size_t buffer_length = 0;
381
422
  size_t buffer_capacity = 0;
382
423
  ssize_t decrypted_buffer_size;
383
 
  size_t written = 0;
 
424
  size_t written;
384
425
  int retval = 0;
385
426
  char interface[IF_NAMESIZE];
386
427
  gnutls_session_t session;
387
 
  gnutls_dh_params_t dh_params;
 
428
  
 
429
  ret = init_gnutls_session (mc, &session);
 
430
  if (ret != 0){
 
431
    return -1;
 
432
  }
388
433
  
389
434
  if(debug){
390
435
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
406
451
  }
407
452
  
408
453
  memset(&to,0,sizeof(to));     /* Spurious warning */
409
 
  to.sin6_family = AF_INET6;
410
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
454
  to.in6.sin6_family = AF_INET6;
 
455
  /* It would be nice to have a way to detect if we were passed an
 
456
     IPv4 address here.   Now we assume an IPv6 address. */
 
457
  ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
411
458
  if (ret < 0 ){
412
459
    perror("inet_pton");
413
460
    return -1;
416
463
    fprintf(stderr, "Bad address: %s\n", ip);
417
464
    return -1;
418
465
  }
419
 
  to.sin6_port = htons(port);   /* Spurious warning */
 
466
  to.in6.sin6_port = htons(port);       /* Spurious warning */
420
467
  
421
 
  to.sin6_scope_id = (uint32_t)if_index;
 
468
  to.in6.sin6_scope_id = (uint32_t)if_index;
422
469
  
423
470
  if(debug){
424
471
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
425
472
    char addrstr[INET6_ADDRSTRLEN] = "";
426
 
    if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
 
473
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
427
474
                 sizeof(addrstr)) == NULL){
428
475
      perror("inet_ntop");
429
476
    } else {
433
480
    }
434
481
  }
435
482
  
436
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
 
483
  ret = connect(tcp_sd, &to.in, sizeof(to));
437
484
  if (ret < 0){
438
485
    perror("connect");
439
486
    return -1;
440
487
  }
441
 
  
442
 
  ret = initgnutls (mc, &session, &dh_params);
443
 
  if (ret != 0){
444
 
    retval = -1;
445
 
    return -1;
 
488
 
 
489
  const char *out = mandos_protocol_version;
 
490
  written = 0;
 
491
  while (true){
 
492
    size_t out_size = strlen(out);
 
493
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
494
                                   out_size - written));
 
495
    if (ret == -1){
 
496
      perror("write");
 
497
      retval = -1;
 
498
      goto mandos_end;
 
499
    }
 
500
    written += (size_t)ret;
 
501
    if(written < out_size){
 
502
      continue;
 
503
    } else {
 
504
      if (out == mandos_protocol_version){
 
505
        written = 0;
 
506
        out = "\r\n";
 
507
      } else {
 
508
        break;
 
509
      }
 
510
    }
 
511
  }
 
512
 
 
513
  if(debug){
 
514
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
446
515
  }
447
516
  
448
517
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
449
518
  
450
 
  if(debug){
451
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
452
 
  }
453
 
  
454
519
  ret = gnutls_handshake (session);
455
520
  
456
521
  if (ret != GNUTLS_E_SUCCESS){
457
522
    if(debug){
458
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
523
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
459
524
      gnutls_perror (ret);
460
525
    }
461
526
    retval = -1;
462
 
    goto exit;
 
527
    goto mandos_end;
463
528
  }
464
529
  
465
 
  //Retrieve OpenPGP packet that contains the wanted password
 
530
  /* Read OpenPGP packet that contains the wanted password */
466
531
  
467
532
  if(debug){
468
533
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
470
535
  }
471
536
 
472
537
  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;
 
538
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
 
539
                                   buffer_capacity);
 
540
    if (buffer_capacity == 0){
 
541
      perror("adjustbuffer");
 
542
      retval = -1;
 
543
      goto mandos_end;
480
544
    }
481
545
    
482
546
    ret = gnutls_record_recv(session, buffer+buffer_length,
492
556
      case GNUTLS_E_REHANDSHAKE:
493
557
        ret = gnutls_handshake (session);
494
558
        if (ret < 0){
495
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
 
559
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
496
560
          gnutls_perror (ret);
497
561
          retval = -1;
498
 
          goto exit;
 
562
          goto mandos_end;
499
563
        }
500
564
        break;
501
565
      default:
502
566
        fprintf(stderr, "Unknown error while reading data from"
503
 
                " encrypted session with mandos server\n");
 
567
                " encrypted session with Mandos server\n");
504
568
        retval = -1;
505
569
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
506
 
        goto exit;
 
570
        goto mandos_end;
507
571
      }
508
572
    } else {
509
573
      buffer_length += (size_t) ret;
510
574
    }
511
575
  }
512
576
  
 
577
  if(debug){
 
578
    fprintf(stderr, "Closing TLS session\n");
 
579
  }
 
580
  
 
581
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
582
  
513
583
  if (buffer_length > 0){
514
584
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
515
585
                                               buffer_length,
516
586
                                               &decrypted_buffer,
517
587
                                               keydir);
518
588
    if (decrypted_buffer_size >= 0){
 
589
      written = 0;
519
590
      while(written < (size_t) decrypted_buffer_size){
520
591
        ret = (int)fwrite (decrypted_buffer + written, 1,
521
592
                           (size_t)decrypted_buffer_size - written,
535
606
      retval = -1;
536
607
    }
537
608
  }
538
 
 
539
 
  //shutdown procedure
540
 
 
541
 
  if(debug){
542
 
    fprintf(stderr, "Closing TLS session\n");
543
 
  }
544
 
 
 
609
  
 
610
  /* Shutdown procedure */
 
611
  
 
612
 mandos_end:
545
613
  free(buffer);
546
 
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
547
 
 exit:
548
614
  close(tcp_sd);
549
615
  gnutls_deinit (session);
550
 
  gnutls_certificate_free_credentials (mc->cred);
551
 
  gnutls_global_deinit ();
552
616
  return retval;
553
617
}
554
618
 
575
639
  switch (event) {
576
640
  default:
577
641
  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,
 
642
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
 
643
            " of type '%s' in domain '%s': %s\n", name, type, domain,
580
644
            avahi_strerror(avahi_server_errno(mc->server)));
581
645
    break;
582
646
    
585
649
      char ip[AVAHI_ADDRESS_STR_MAX];
586
650
      avahi_address_snprint(ip, sizeof(ip), address);
587
651
      if(debug){
588
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
589
 
                " port %d\n", name, host_name, ip, port);
 
652
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %d) on"
 
653
                " port %d\n", name, host_name, ip, interface, port);
590
654
      }
591
655
      int ret = start_mandos_communication(ip, port, interface, mc);
592
656
      if (ret == 0){
617
681
  default:
618
682
  case AVAHI_BROWSER_FAILURE:
619
683
    
620
 
    fprintf(stderr, "(Browser) %s\n",
 
684
    fprintf(stderr, "(Avahi browser) %s\n",
621
685
            avahi_strerror(avahi_server_errno(mc->server)));
622
686
    avahi_simple_poll_quit(mc->simple_poll);
623
687
    return;
624
688
    
625
689
  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. */
 
690
    /* We ignore the returned Avahi resolver object. In the callback
 
691
       function we free it. If the Avahi server is terminated before
 
692
       the callback function is called the Avahi server will free the
 
693
       resolver for us. */
630
694
    
631
695
    if (!(avahi_s_service_resolver_new(mc->server, interface,
632
696
                                       protocol, name, type, domain,
633
697
                                       AVAHI_PROTO_INET6, 0,
634
698
                                       resolve_callback, mc)))
635
 
      fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
636
 
              avahi_strerror(avahi_server_errno(mc->server)));
 
699
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
 
700
              name, avahi_strerror(avahi_server_errno(mc->server)));
637
701
    break;
638
702
    
639
703
  case AVAHI_BROWSER_REMOVE:
641
705
    
642
706
  case AVAHI_BROWSER_ALL_FOR_NOW:
643
707
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
708
    if(debug){
 
709
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
710
    }
644
711
    break;
645
712
  }
646
713
}
666
733
}
667
734
 
668
735
 
669
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
670
 
    AvahiServerConfig config;
 
736
int main(int argc, char *argv[]){
671
737
    AvahiSServiceBrowser *sb = NULL;
672
738
    int error;
673
739
    int ret;
674
 
    int debug_int;
675
 
    int returncode = EXIT_SUCCESS;
 
740
    int exitcode = EXIT_SUCCESS;
676
741
    const char *interface = "eth0";
677
742
    struct ifreq network;
678
743
    int sd;
 
744
    uid_t uid;
 
745
    gid_t gid;
679
746
    char *connect_to = NULL;
680
747
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
748
    const char *pubkeyfile = "pubkey.txt";
 
749
    const char *seckeyfile = "seckey.txt";
681
750
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
682
751
                          .dh_bits = 1024, .priority = "SECURE256"};
 
752
    bool gnutls_initalized = false;
683
753
    
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);
 
754
    {
 
755
      struct argp_option options[] = {
 
756
        { .name = "debug", .key = 128,
 
757
          .doc = "Debug mode", .group = 3 },
 
758
        { .name = "connect", .key = 'c',
 
759
          .arg = "IP",
 
760
          .doc = "Connect directly to a sepcified mandos server",
 
761
          .group = 1 },
 
762
        { .name = "interface", .key = 'i',
 
763
          .arg = "INTERFACE",
 
764
          .doc = "Interface that Avahi will conntect through",
 
765
          .group = 1 },
 
766
        { .name = "keydir", .key = 'd',
 
767
          .arg = "KEYDIR",
 
768
          .doc = "Directory where the openpgp keyring is",
 
769
          .group = 1 },
 
770
        { .name = "seckey", .key = 's',
 
771
          .arg = "SECKEY",
 
772
          .doc = "Secret openpgp key for gnutls authentication",
 
773
          .group = 1 },
 
774
        { .name = "pubkey", .key = 'p',
 
775
          .arg = "PUBKEY",
 
776
          .doc = "Public openpgp key for gnutls authentication",
 
777
          .group = 2 },
 
778
        { .name = "dh-bits", .key = 129,
 
779
          .arg = "BITS",
 
780
          .doc = "dh-bits to use in gnutls communication",
 
781
          .group = 2 },
 
782
        { .name = "priority", .key = 130,
 
783
          .arg = "PRIORITY",
 
784
          .doc = "GNUTLS priority", .group = 1 },
 
785
        { .name = NULL }
 
786
      };
 
787
 
 
788
      
 
789
      error_t parse_opt (int key, char *arg,
 
790
                         struct argp_state *state) {
 
791
        /* Get the INPUT argument from `argp_parse', which we know is
 
792
           a pointer to our plugin list pointer. */
 
793
        switch (key) {
 
794
        case 128:
 
795
          debug = true;
 
796
          break;
 
797
        case 'c':
 
798
          connect_to = arg;
 
799
          break;
 
800
        case 'i':
 
801
          interface = arg;
 
802
          break;
 
803
        case 'd':
 
804
          keydir = arg;
 
805
          break;
 
806
        case 's':
 
807
          seckeyfile = arg;
 
808
          break;
 
809
        case 'p':
 
810
          pubkeyfile = arg;
 
811
          break;
 
812
        case 129:
 
813
          errno = 0;
 
814
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
815
          if (errno){
 
816
            perror("strtol");
 
817
            exit(EXIT_FAILURE);
 
818
          }
 
819
          break;
 
820
        case 130:
 
821
          mc.priority = arg;
 
822
          break;
 
823
        case ARGP_KEY_ARG:
 
824
          argp_usage (state);
 
825
          break;
 
826
          case ARGP_KEY_END:
 
827
            break;
 
828
        default:
 
829
          return ARGP_ERR_UNKNOWN;
729
830
        }
730
 
        break;
731
 
      case 'P':
732
 
        mc.priority = optarg;
733
 
        break;
734
 
      case '?':
735
 
      default:
736
 
        exit(EXIT_FAILURE);
 
831
        return 0;
737
832
      }
 
833
 
 
834
      struct argp argp = { .options = options, .parser = parse_opt,
 
835
                           .args_doc = "",
 
836
                           .doc = "Mandos client -- Get and decrypt"
 
837
                           " passwords from mandos server" };
 
838
      argp_parse (&argp, argc, argv, 0, 0, NULL);
738
839
    }
739
 
    debug = debug_int ? true : false;
740
 
    
 
840
      
741
841
    pubkeyfile = combinepath(keydir, pubkeyfile);
742
842
    if (pubkeyfile == NULL){
743
843
      perror("combinepath");
744
 
      returncode = EXIT_FAILURE;
745
 
      goto exit;
 
844
      exitcode = EXIT_FAILURE;
 
845
      goto end;
746
846
    }
747
847
    
748
848
    seckeyfile = combinepath(keydir, seckeyfile);
749
849
    if (seckeyfile == NULL){
750
850
      perror("combinepath");
751
 
      goto exit;
 
851
      goto end;
 
852
    }
 
853
 
 
854
    ret = init_gnutls_global(&mc, pubkeyfile, seckeyfile);
 
855
    if (ret == -1){
 
856
      fprintf(stderr, "init_gnutls_global\n");
 
857
      goto end;
 
858
    } else {
 
859
      gnutls_initalized = true;
 
860
    }
 
861
 
 
862
    uid = getuid();
 
863
    gid = getgid();
 
864
 
 
865
    ret = setuid(uid);
 
866
    if (ret == -1){
 
867
      perror("setuid");
 
868
    }
 
869
    
 
870
    setgid(gid);
 
871
    if (ret == -1){
 
872
      perror("setgid");
752
873
    }
753
874
    
754
875
    if_index = (AvahiIfIndex) if_nametoindex(interface);
763
884
      char *address = strrchr(connect_to, ':');
764
885
      if(address == NULL){
765
886
        fprintf(stderr, "No colon in address\n");
766
 
        exit(EXIT_FAILURE);
 
887
        exitcode = EXIT_FAILURE;
 
888
        goto end;
767
889
      }
768
890
      errno = 0;
769
891
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
770
892
      if(errno){
771
893
        perror("Bad port number");
772
 
        exit(EXIT_FAILURE);
 
894
        exitcode = EXIT_FAILURE;
 
895
        goto end;
773
896
      }
774
897
      *address = '\0';
775
898
      address = connect_to;
776
899
      ret = start_mandos_communication(address, port, if_index, &mc);
777
900
      if(ret < 0){
778
 
        exit(EXIT_FAILURE);
 
901
        exitcode = EXIT_FAILURE;
779
902
      } else {
780
 
        exit(EXIT_SUCCESS);
 
903
        exitcode = EXIT_SUCCESS;
781
904
      }
 
905
      goto end;
782
906
    }
783
907
    
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);
 
908
    /* If the interface is down, bring it up */
 
909
    {
 
910
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
911
      if(sd < 0) {
 
912
        perror("socket");
 
913
        exitcode = EXIT_FAILURE;
 
914
        goto end;
 
915
      }
 
916
      strcpy(network.ifr_name, interface); /* Spurious warning */
 
917
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
801
918
      if(ret == -1){
802
 
        perror("ioctl SIOCSIFFLAGS");
803
 
        returncode = EXIT_FAILURE;
804
 
        goto exit;
805
 
      }
 
919
        perror("ioctl SIOCGIFFLAGS");
 
920
        exitcode = EXIT_FAILURE;
 
921
        goto end;
 
922
      }
 
923
      if((network.ifr_flags & IFF_UP) == 0){
 
924
        network.ifr_flags |= IFF_UP;
 
925
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
926
        if(ret == -1){
 
927
          perror("ioctl SIOCSIFFLAGS");
 
928
          exitcode = EXIT_FAILURE;
 
929
          goto end;
 
930
        }
 
931
      }
 
932
      close(sd);
806
933
    }
807
 
    close(sd);
808
934
    
809
935
    if (not debug){
810
936
      avahi_set_log_function(empty_log);
811
937
    }
812
938
    
813
 
    /* Initialize the psuedo-RNG */
 
939
    /* Initialize the pseudo-RNG for Avahi */
814
940
    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",
 
941
    
 
942
    /* Allocate main Avahi loop object */
 
943
    mc.simple_poll = avahi_simple_poll_new();
 
944
    if (mc.simple_poll == NULL) {
 
945
        fprintf(stderr, "Avahi: Failed to create simple poll"
 
946
                " object.\n");
 
947
        exitcode = EXIT_FAILURE;
 
948
        goto end;
 
949
    }
 
950
 
 
951
    {
 
952
      AvahiServerConfig config;
 
953
      /* Do not publish any local Zeroconf records */
 
954
      avahi_server_config_init(&config);
 
955
      config.publish_hinfo = 0;
 
956
      config.publish_addresses = 0;
 
957
      config.publish_workstation = 0;
 
958
      config.publish_domain = 0;
 
959
 
 
960
      /* Allocate a new server */
 
961
      mc.server = avahi_server_new(avahi_simple_poll_get
 
962
                                   (mc.simple_poll), &config, NULL,
 
963
                                   NULL, &error);
 
964
    
 
965
      /* Free the Avahi configuration data */
 
966
      avahi_server_config_free(&config);
 
967
    }
 
968
    
 
969
    /* Check if creating the Avahi server object succeeded */
 
970
    if (mc.server == NULL) {
 
971
        fprintf(stderr, "Failed to create Avahi server: %s\n",
840
972
                avahi_strerror(error));
841
 
        returncode = EXIT_FAILURE;
842
 
        goto exit;
 
973
        exitcode = EXIT_FAILURE;
 
974
        goto end;
843
975
    }
844
976
    
845
 
    /* Create the service browser */
 
977
    /* Create the Avahi service browser */
846
978
    sb = avahi_s_service_browser_new(mc.server, if_index,
847
979
                                     AVAHI_PROTO_INET6,
848
980
                                     "_mandos._tcp", NULL, 0,
849
981
                                     browse_callback, &mc);
850
 
    if (!sb) {
 
982
    if (sb == NULL) {
851
983
        fprintf(stderr, "Failed to create service browser: %s\n",
852
984
                avahi_strerror(avahi_server_errno(mc.server)));
853
 
        returncode = EXIT_FAILURE;
854
 
        goto exit;
 
985
        exitcode = EXIT_FAILURE;
 
986
        goto end;
855
987
    }
856
988
    
857
989
    /* Run the main loop */
858
990
 
859
991
    if (debug){
860
 
      fprintf(stderr, "Starting avahi loop search\n");
 
992
      fprintf(stderr, "Starting Avahi loop search\n");
861
993
    }
862
994
    
863
995
    avahi_simple_poll_loop(mc.simple_poll);
864
996
    
865
 
 exit:
 
997
 end:
866
998
 
867
999
    if (debug){
868
1000
      fprintf(stderr, "%s exiting\n", argv[0]);
869
1001
    }
870
1002
    
871
1003
    /* Cleanup things */
872
 
    if (sb)
 
1004
    if (sb != NULL)
873
1005
        avahi_s_service_browser_free(sb);
874
1006
    
875
 
    if (mc.server)
 
1007
    if (mc.server != NULL)
876
1008
        avahi_server_free(mc.server);
877
1009
 
878
 
    if (mc.simple_poll)
 
1010
    if (mc.simple_poll != NULL)
879
1011
        avahi_simple_poll_free(mc.simple_poll);
880
1012
    free(pubkeyfile);
881
1013
    free(seckeyfile);
 
1014
 
 
1015
    if (gnutls_initalized){
 
1016
      gnutls_certificate_free_credentials (mc.cred);
 
1017
      gnutls_global_deinit ();
 
1018
    }
882
1019
    
883
 
    return returncode;
 
1020
    return exitcode;
884
1021
}