/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

  • Committer: Teddy Hogeborn
  • Date: 2008-08-29 05:53:59 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080829055359-wkdasnyxtylmnxus
* mandos.xml (EXAMPLE): Replaced all occurences of command name with
                        "&COMMANDNAME;".

* plugins.d/password-prompt.c (main): Improved some documentation
                                      strings.  Do perror() of
                                      tcgetattr() fails.  Add debug
                                      output if interrupted by signal.
                                      Loop over write() instead of
                                      using fwrite() when outputting
                                      password.  Add debug output if
                                      getline() returns 0, unless it
                                      was caused by a signal.  Add
                                      exit status code to debug
                                      output.

* plugins.d/password-prompt.xml: Changed all single quotes to double
                                 quotes for consistency.  Removed
                                 <?xml-stylesheet>.
  (ENTITY TIMESTAMP): New.  Automatically updated by Emacs time-stamp
                      by using Emacs local variables.
  (/refentry/refentryinfo/title): Changed to "Mandos Manual".
  (/refentry/refentryinfo/productname): Changed to "Mandos".
  (/refentry/refentryinfo/date): New; set to "&TIMESTAMP;".
  (/refentry/refentryinfo/copyright): Split copyright holders.
  (/refentry/refnamediv/refpurpose): Improved wording.
  (SYNOPSIS): Fix to use correct markup.  Add short options.
  (DESCRIPTION, OPTIONS): Improved wording.
  (OPTIONS): Improved wording.  Use more correct markup.  Document
             short options.
  (EXIT STATUS): Add text.
  (ENVIRONMENT): Document use of "cryptsource" and "crypttarget".
  (FILES): REMOVED.
  (BUGS): Add text.
  (EXAMPLE): Added some examples.
  (SECURITY): Added text.
  (SEE ALSO): Remove reference to mandos(8).  Add reference to
              crypttab(5).

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() */
 
35
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
36
36
 
37
 
#include <stdio.h>
38
 
#include <assert.h>
39
 
#include <stdlib.h>
40
 
#include <time.h>
41
 
#include <net/if.h>             /* if_nametoindex */
42
 
#include <sys/ioctl.h>          /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
43
 
                                   SIOCSIFFLAGS */
 
37
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
 
38
                                   stdout, ferror() */
 
39
#include <stdint.h>             /* uint16_t, uint32_t */
 
40
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
41
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
 
42
                                   srand() */
 
43
#include <stdbool.h>            /* bool, true */
 
44
#include <string.h>             /* memset(), strcmp(), strlen(),
 
45
                                   strerror(), asprintf(), strcpy() */
 
46
#include <sys/ioctl.h>          /* ioctl */
 
47
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
 
48
                                   sockaddr_in6, PF_INET6,
 
49
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
 
50
                                   uid_t, gid_t */
 
51
#include <inttypes.h>           /* PRIu16 */
 
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
53
                                   struct in6_addr, inet_pton(),
 
54
                                   connect() */
 
55
#include <assert.h>             /* assert() */
 
56
#include <errno.h>              /* perror(), errno */
 
57
#include <time.h>               /* time() */
44
58
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
45
 
                                   SIOCSIFFLAGS */
 
59
                                   SIOCSIFFLAGS, if_indextoname(),
 
60
                                   if_nametoindex(), IF_NAMESIZE */
 
61
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
 
62
                                   getuid(), getgid(), setuid(),
 
63
                                   setgid() */
 
64
#include <netinet/in.h>
 
65
#include <arpa/inet.h>          /* inet_pton(), htons */
 
66
#include <iso646.h>             /* not, and */
 
67
#include <argp.h>               /* struct argp_option, error_t, struct
 
68
                                   argp_state, struct argp,
 
69
                                   argp_parse(), ARGP_KEY_ARG,
 
70
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
46
71
 
 
72
/* Avahi */
 
73
/* All Avahi types, constants and functions
 
74
 Avahi*, avahi_*,
 
75
 AVAHI_* */
47
76
#include <avahi-core/core.h>
48
77
#include <avahi-core/lookup.h>
49
78
#include <avahi-core/log.h>
51
80
#include <avahi-common/malloc.h>
52
81
#include <avahi-common/error.h>
53
82
 
54
 
/* Mandos client part */
55
 
#include <sys/types.h>          /* socket(), inet_pton() */
56
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
57
 
                                   struct in6_addr, inet_pton() */
58
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
59
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
60
 
 
61
 
#include <unistd.h>             /* close() */
62
 
#include <netinet/in.h>
63
 
#include <stdbool.h>            /* true */
64
 
#include <string.h>             /* memset */
65
 
#include <arpa/inet.h>          /* inet_pton() */
66
 
#include <iso646.h>             /* not */
67
 
#include <net/if.h>             /* IF_NAMESIZE */
 
83
/* GnuTLS */
 
84
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and
 
85
                                   functions:
 
86
                                   gnutls_*
 
87
                                   init_gnutls_session(),
 
88
                                   GNUTLS_* */
 
89
#include <gnutls/openpgp.h>     /* gnutls_certificate_set_openpgp_key_file(),
 
90
                                   GNUTLS_OPENPGP_FMT_BASE64 */
68
91
 
69
92
/* GPGME */
70
 
#include <errno.h>              /* perror() */
71
 
#include <gpgme.h>
72
 
 
73
 
/* getopt_long */
74
 
#include <getopt.h>
 
93
#include <gpgme.h>              /* All GPGME types, constants and
 
94
                                   functions:
 
95
                                   gpgme_*
 
96
                                   GPGME_PROTOCOL_OpenPGP,
 
97
                                   GPG_ERR_NO_* */
75
98
 
76
99
#define BUFFER_SIZE 256
77
100
 
 
101
bool debug = false;
78
102
static const char *keydir = "/conf/conf.d/mandos";
79
 
static const char *pubkeyfile = "pubkey.txt";
80
 
static const char *seckeyfile = "seckey.txt";
81
 
 
82
 
bool debug = false;
83
 
 
84
 
const char mandos_protocol_version[] = "1";
85
 
 
86
 
/* Used for passing in values through all the callback functions */
 
103
static const char mandos_protocol_version[] = "1";
 
104
const char *argp_program_version = "password-request 1.0";
 
105
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
106
 
 
107
/* Used for passing in values through the Avahi callback functions */
87
108
typedef struct {
88
109
  AvahiSimplePoll *simple_poll;
89
110
  AvahiServer *server;
93
114
  const char *priority;
94
115
} mandos_context;
95
116
 
 
117
/*
 
118
 * Make room in "buffer" for at least BUFFER_SIZE additional bytes.
 
119
 * "buffer_capacity" is how much is currently allocated,
 
120
 * "buffer_length" is how much is already used.
 
121
 */
96
122
size_t adjustbuffer(char **buffer, size_t buffer_length,
97
123
                  size_t buffer_capacity){
98
124
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
188
214
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
189
215
            gpgme_strsource(rc), gpgme_strerror(rc));
190
216
    plaintext_length = -1;
 
217
    if (debug){
 
218
      gpgme_decrypt_result_t result;
 
219
      result = gpgme_op_decrypt_result(ctx);
 
220
      if (result == NULL){
 
221
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
222
      } else {
 
223
        fprintf(stderr, "Unsupported algorithm: %s\n",
 
224
                result->unsupported_algorithm);
 
225
        fprintf(stderr, "Wrong key usage: %u\n",
 
226
                result->wrong_key_usage);
 
227
        if(result->file_name != NULL){
 
228
          fprintf(stderr, "File name: %s\n", result->file_name);
 
229
        }
 
230
        gpgme_recipient_t recipient;
 
231
        recipient = result->recipients;
 
232
        if(recipient){
 
233
          while(recipient != NULL){
 
234
            fprintf(stderr, "Public key algorithm: %s\n",
 
235
                    gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
236
            fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
237
            fprintf(stderr, "Secret key available: %s\n",
 
238
                    recipient->status == GPG_ERR_NO_SECKEY
 
239
                    ? "No" : "Yes");
 
240
            recipient = recipient->next;
 
241
          }
 
242
        }
 
243
      }
 
244
    }
191
245
    goto decrypt_end;
192
246
  }
193
247
  
195
249
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
196
250
  }
197
251
  
198
 
  if (debug){
199
 
    gpgme_decrypt_result_t result;
200
 
    result = gpgme_op_decrypt_result(ctx);
201
 
    if (result == NULL){
202
 
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
203
 
    } else {
204
 
      fprintf(stderr, "Unsupported algorithm: %s\n",
205
 
              result->unsupported_algorithm);
206
 
      fprintf(stderr, "Wrong key usage: %d\n",
207
 
              result->wrong_key_usage);
208
 
      if(result->file_name != NULL){
209
 
        fprintf(stderr, "File name: %s\n", result->file_name);
210
 
      }
211
 
      gpgme_recipient_t recipient;
212
 
      recipient = result->recipients;
213
 
      if(recipient){
214
 
        while(recipient != NULL){
215
 
          fprintf(stderr, "Public key algorithm: %s\n",
216
 
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
217
 
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
218
 
          fprintf(stderr, "Secret key available: %s\n",
219
 
                  recipient->status == GPG_ERR_NO_SECKEY
220
 
                  ? "No" : "Yes");
221
 
          recipient = recipient->next;
222
 
        }
223
 
      }
224
 
    }
225
 
  }
226
 
  
227
252
  /* Seek back to the beginning of the GPGME plaintext data buffer */
228
253
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
229
254
    perror("pgpme_data_seek");
233
258
  
234
259
  *plaintext = NULL;
235
260
  while(true){
236
 
    plaintext_capacity = adjustbuffer(plaintext, (size_t)plaintext_length,
 
261
    plaintext_capacity = adjustbuffer(plaintext,
 
262
                                      (size_t)plaintext_length,
237
263
                                      plaintext_capacity);
238
264
    if (plaintext_capacity == 0){
239
265
        perror("adjustbuffer");
275
301
}
276
302
 
277
303
static const char * safer_gnutls_strerror (int value) {
278
 
  const char *ret = gnutls_strerror (value);
 
304
  const char *ret = gnutls_strerror (value); /* Spurious warning */
279
305
  if (ret == NULL)
280
306
    ret = "(unknown)";
281
307
  return ret;
287
313
  fprintf(stderr, "GnuTLS: %s", string);
288
314
}
289
315
 
290
 
static int init_gnutls_global(mandos_context *mc){
 
316
static int init_gnutls_global(mandos_context *mc,
 
317
                              const char *pubkeyfilename,
 
318
                              const char *seckeyfilename){
291
319
  int ret;
292
320
  
293
321
  if(debug){
294
322
    fprintf(stderr, "Initializing GnuTLS\n");
295
323
  }
296
 
 
297
 
  if ((ret = gnutls_global_init ())
298
 
      != GNUTLS_E_SUCCESS) {
 
324
  
 
325
  ret = gnutls_global_init();
 
326
  if (ret != GNUTLS_E_SUCCESS) {
299
327
    fprintf (stderr, "GnuTLS global_init: %s\n",
300
328
             safer_gnutls_strerror(ret));
301
329
    return -1;
310
338
  }
311
339
  
312
340
  /* OpenPGP credentials */
313
 
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
314
 
      != GNUTLS_E_SUCCESS) {
315
 
    fprintf (stderr, "GnuTLS memory error: %s\n",
 
341
  gnutls_certificate_allocate_credentials(&mc->cred);
 
342
  if (ret != GNUTLS_E_SUCCESS){
 
343
    fprintf (stderr, "GnuTLS memory error: %s\n", /* Spurious
 
344
                                                     warning */
316
345
             safer_gnutls_strerror(ret));
 
346
    gnutls_global_deinit ();
317
347
    return -1;
318
348
  }
319
349
  
320
350
  if(debug){
321
351
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
322
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
323
 
            seckeyfile);
 
352
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
 
353
            seckeyfilename);
324
354
  }
325
355
  
326
356
  ret = gnutls_certificate_set_openpgp_key_file
327
 
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
357
    (mc->cred, pubkeyfilename, seckeyfilename,
 
358
     GNUTLS_OPENPGP_FMT_BASE64);
328
359
  if (ret != GNUTLS_E_SUCCESS) {
329
360
    fprintf(stderr,
330
361
            "Error[%d] while reading the OpenPGP key pair ('%s',"
331
 
            " '%s')\n", ret, pubkeyfile, seckeyfile);
 
362
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
332
363
    fprintf(stdout, "The GnuTLS error is: %s\n",
333
364
            safer_gnutls_strerror(ret));
334
 
    return -1;
 
365
    goto globalfail;
335
366
  }
336
367
  
337
368
  /* GnuTLS server initialization */
339
370
  if (ret != GNUTLS_E_SUCCESS) {
340
371
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
341
372
             " %s\n", safer_gnutls_strerror(ret));
342
 
    return -1;
 
373
    goto globalfail;
343
374
  }
344
375
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
345
376
  if (ret != GNUTLS_E_SUCCESS) {
346
377
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
347
378
             safer_gnutls_strerror(ret));
348
 
    return -1;
 
379
    goto globalfail;
349
380
  }
350
381
  
351
382
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
352
383
 
353
384
  return 0;
 
385
 
 
386
 globalfail:
 
387
 
 
388
  gnutls_certificate_free_credentials(mc->cred);
 
389
  gnutls_global_deinit();
 
390
  return -1;
 
391
 
354
392
}
355
393
 
356
 
static int init_gnutls_session(mandos_context *mc, gnutls_session_t *session){
 
394
static int init_gnutls_session(mandos_context *mc,
 
395
                               gnutls_session_t *session){
357
396
  int ret;
358
397
  /* GnuTLS session creation */
359
398
  ret = gnutls_init(session, GNUTLS_SERVER);
369
408
      fprintf(stderr, "Syntax error at: %s\n", err);
370
409
      fprintf(stderr, "GnuTLS error: %s\n",
371
410
              safer_gnutls_strerror(ret));
 
411
      gnutls_deinit (*session);
372
412
      return -1;
373
413
    }
374
414
  }
378
418
  if (ret != GNUTLS_E_SUCCESS) {
379
419
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
380
420
            safer_gnutls_strerror(ret));
 
421
    gnutls_deinit (*session);
381
422
    return -1;
382
423
  }
383
424
  
399
440
                                      AvahiIfIndex if_index,
400
441
                                      mandos_context *mc){
401
442
  int ret, tcp_sd;
402
 
  struct sockaddr_in6 to;
 
443
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
403
444
  char *buffer = NULL;
404
445
  char *decrypted_buffer;
405
446
  size_t buffer_length = 0;
409
450
  int retval = 0;
410
451
  char interface[IF_NAMESIZE];
411
452
  gnutls_session_t session;
412
 
  gnutls_dh_params_t dh_params;
413
453
  
414
454
  ret = init_gnutls_session (mc, &session);
415
455
  if (ret != 0){
417
457
  }
418
458
  
419
459
  if(debug){
420
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
421
 
            ip, port);
 
460
    fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16
 
461
            "\n", ip, port);
422
462
  }
423
463
  
424
464
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
435
475
    fprintf(stderr, "Binding to interface %s\n", interface);
436
476
  }
437
477
  
438
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
439
 
  to.sin6_family = AF_INET6;
 
478
  memset(&to, 0, sizeof(to));
 
479
  to.in6.sin6_family = AF_INET6;
440
480
  /* It would be nice to have a way to detect if we were passed an
441
481
     IPv4 address here.   Now we assume an IPv6 address. */
442
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
482
  ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
443
483
  if (ret < 0 ){
444
484
    perror("inet_pton");
445
485
    return -1;
448
488
    fprintf(stderr, "Bad address: %s\n", ip);
449
489
    return -1;
450
490
  }
451
 
  to.sin6_port = htons(port);   /* Spurious warning */
 
491
  to.in6.sin6_port = htons(port); /* Spurious warning */
452
492
  
453
 
  to.sin6_scope_id = (uint32_t)if_index;
 
493
  to.in6.sin6_scope_id = (uint32_t)if_index;
454
494
  
455
495
  if(debug){
456
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
 
496
    fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
497
            port);
457
498
    char addrstr[INET6_ADDRSTRLEN] = "";
458
 
    if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
 
499
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
459
500
                 sizeof(addrstr)) == NULL){
460
501
      perror("inet_ntop");
461
502
    } else {
465
506
    }
466
507
  }
467
508
  
468
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
 
509
  ret = connect(tcp_sd, &to.in, sizeof(to));
469
510
  if (ret < 0){
470
511
    perror("connect");
471
512
    return -1;
500
541
  }
501
542
  
502
543
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
503
 
  
504
 
  ret = gnutls_handshake (session);
 
544
 
 
545
  do{
 
546
    ret = gnutls_handshake (session);
 
547
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
505
548
  
506
549
  if (ret != GNUTLS_E_SUCCESS){
507
550
    if(debug){
520
563
  }
521
564
 
522
565
  while(true){
523
 
    buffer_capacity = adjustbuffer(&buffer, buffer_length, buffer_capacity);
 
566
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
 
567
                                   buffer_capacity);
524
568
    if (buffer_capacity == 0){
525
569
      perror("adjustbuffer");
526
570
      retval = -1;
538
582
      case GNUTLS_E_AGAIN:
539
583
        break;
540
584
      case GNUTLS_E_REHANDSHAKE:
541
 
        ret = gnutls_handshake (session);
 
585
        do{
 
586
          ret = gnutls_handshake (session);
 
587
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
542
588
        if (ret < 0){
543
589
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
544
590
          gnutls_perror (ret);
589
635
    } else {
590
636
      retval = -1;
591
637
    }
 
638
  } else {
 
639
    retval = -1;
592
640
  }
593
641
  
594
642
  /* Shutdown procedure */
597
645
  free(buffer);
598
646
  close(tcp_sd);
599
647
  gnutls_deinit (session);
600
 
  gnutls_certificate_free_credentials (mc->cred);
601
 
  gnutls_global_deinit ();
602
648
  return retval;
603
649
}
604
650
 
617
663
                             flags,
618
664
                             void* userdata) {
619
665
  mandos_context *mc = userdata;
620
 
  assert(r);                    /* Spurious warning */
 
666
  assert(r);
621
667
  
622
668
  /* Called whenever a service has been resolved successfully or
623
669
     timed out */
635
681
      char ip[AVAHI_ADDRESS_STR_MAX];
636
682
      avahi_address_snprint(ip, sizeof(ip), address);
637
683
      if(debug){
638
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %d) on"
639
 
                " port %d\n", name, host_name, ip, interface, port);
 
684
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
 
685
                PRIu16 ") on port %d\n", name, host_name, ip,
 
686
                interface, port);
640
687
      }
641
688
      int ret = start_mandos_communication(ip, port, interface, mc);
642
689
      if (ret == 0){
643
 
        exit(EXIT_SUCCESS);
 
690
        avahi_simple_poll_quit(mc->simple_poll);
644
691
      }
645
692
    }
646
693
  }
658
705
                             flags,
659
706
                             void* userdata) {
660
707
  mandos_context *mc = userdata;
661
 
  assert(b);                    /* Spurious warning */
 
708
  assert(b);
662
709
  
663
710
  /* Called whenever a new services becomes available on the LAN or
664
711
     is removed from the LAN */
700
747
 
701
748
/* Combines file name and path and returns the malloced new
702
749
   string. some sane checks could/should be added */
703
 
static const char *combinepath(const char *first, const char *second){
704
 
  size_t f_len = strlen(first);
705
 
  size_t s_len = strlen(second);
706
 
  char *tmp = malloc(f_len + s_len + 2);
707
 
  if (tmp == NULL){
 
750
static char *combinepath(const char *first, const char *second){
 
751
  char *tmp;
 
752
  int ret = asprintf(&tmp, "%s/%s", first, second);
 
753
  if(ret < 0){
708
754
    return NULL;
709
755
  }
710
 
  if(f_len > 0){
711
 
    memcpy(tmp, first, f_len);  /* Spurious warning */
712
 
  }
713
 
  tmp[f_len] = '/';
714
 
  if(s_len > 0){
715
 
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
716
 
  }
717
 
  tmp[f_len + 1 + s_len] = '\0';
718
756
  return tmp;
719
757
}
720
758
 
731
769
    gid_t gid;
732
770
    char *connect_to = NULL;
733
771
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
772
    char *pubkeyfilename = NULL;
 
773
    char *seckeyfilename = NULL;
 
774
    const char *pubkeyname = "pubkey.txt";
 
775
    const char *seckeyname = "seckey.txt";
734
776
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
735
777
                          .dh_bits = 1024, .priority = "SECURE256"};
 
778
    bool gnutls_initalized = false;
736
779
    
737
780
    {
738
 
      /* Temporary int to get the address of for getopt_long */
739
 
      int debug_int = debug ? 1 : 0;
740
 
      while (true){
741
 
        struct option long_options[] = {
742
 
          {"debug", no_argument, &debug_int, 1},
743
 
          {"connect", required_argument, NULL, 'c'},
744
 
          {"interface", required_argument, NULL, 'i'},
745
 
          {"keydir", required_argument, NULL, 'd'},
746
 
          {"seckey", required_argument, NULL, 's'},
747
 
          {"pubkey", required_argument, NULL, 'p'},
748
 
          {"dh-bits", required_argument, NULL, 'D'},
749
 
          {"priority", required_argument, NULL, 'P'},
750
 
          {0, 0, 0, 0} };
751
 
      
752
 
        int option_index = 0;
753
 
        ret = getopt_long (argc, argv, "i:", long_options,
754
 
                           &option_index);
755
 
      
756
 
        if (ret == -1){
 
781
      struct argp_option options[] = {
 
782
        { .name = "debug", .key = 128,
 
783
          .doc = "Debug mode", .group = 3 },
 
784
        { .name = "connect", .key = 'c',
 
785
          .arg = "IP",
 
786
          .doc = "Connect directly to a sepcified mandos server",
 
787
          .group = 1 },
 
788
        { .name = "interface", .key = 'i',
 
789
          .arg = "INTERFACE",
 
790
          .doc = "Interface that Avahi will conntect through",
 
791
          .group = 1 },
 
792
        { .name = "keydir", .key = 'd',
 
793
          .arg = "KEYDIR",
 
794
          .doc = "Directory where the openpgp keyring is",
 
795
          .group = 1 },
 
796
        { .name = "seckey", .key = 's',
 
797
          .arg = "SECKEY",
 
798
          .doc = "Secret openpgp key for gnutls authentication",
 
799
          .group = 1 },
 
800
        { .name = "pubkey", .key = 'p',
 
801
          .arg = "PUBKEY",
 
802
          .doc = "Public openpgp key for gnutls authentication",
 
803
          .group = 2 },
 
804
        { .name = "dh-bits", .key = 129,
 
805
          .arg = "BITS",
 
806
          .doc = "dh-bits to use in gnutls communication",
 
807
          .group = 2 },
 
808
        { .name = "priority", .key = 130,
 
809
          .arg = "PRIORITY",
 
810
          .doc = "GNUTLS priority", .group = 1 },
 
811
        { .name = NULL }
 
812
      };
 
813
 
 
814
      
 
815
      error_t parse_opt (int key, char *arg,
 
816
                         struct argp_state *state) {
 
817
        /* Get the INPUT argument from `argp_parse', which we know is
 
818
           a pointer to our plugin list pointer. */
 
819
        switch (key) {
 
820
        case 128:
 
821
          debug = true;
757
822
          break;
758
 
        }
759
 
      
760
 
        switch(ret){
761
 
        case 0:
 
823
        case 'c':
 
824
          connect_to = arg;
762
825
          break;
763
826
        case 'i':
764
 
          interface = optarg;
765
 
          break;
766
 
        case 'c':
767
 
          connect_to = optarg;
 
827
          interface = arg;
768
828
          break;
769
829
        case 'd':
770
 
          keydir = optarg;
 
830
          keydir = arg;
 
831
          break;
 
832
        case 's':
 
833
          seckeyname = arg;
771
834
          break;
772
835
        case 'p':
773
 
          pubkeyfile = optarg;
774
 
          break;
775
 
        case 's':
776
 
          seckeyfile = optarg;
777
 
          break;
778
 
        case 'D':
 
836
          pubkeyname = arg;
 
837
          break;
 
838
        case 129:
779
839
          errno = 0;
780
 
          mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
 
840
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
781
841
          if (errno){
782
842
            perror("strtol");
783
843
            exit(EXIT_FAILURE);
784
844
          }
785
845
          break;
786
 
        case 'P':
787
 
          mc.priority = optarg;
788
 
          break;
789
 
        case '?':
 
846
        case 130:
 
847
          mc.priority = arg;
 
848
          break;
 
849
        case ARGP_KEY_ARG:
 
850
          argp_usage (state);
 
851
        case ARGP_KEY_END:
 
852
          break;
790
853
        default:
791
 
          /* getopt_long() has already printed a message about the
792
 
             unrcognized option, so just exit. */
793
 
          exit(EXIT_FAILURE);
 
854
          return ARGP_ERR_UNKNOWN;
794
855
        }
795
 
      }
796
 
      /* Set the global debug flag from the temporary int */
797
 
      debug = debug_int ? true : false;
798
 
    }
799
 
    
800
 
    pubkeyfile = combinepath(keydir, pubkeyfile);
801
 
    if (pubkeyfile == NULL){
802
 
      perror("combinepath");
803
 
      exitcode = EXIT_FAILURE;
804
 
      goto end;
805
 
    }
806
 
    
807
 
    seckeyfile = combinepath(keydir, seckeyfile);
808
 
    if (seckeyfile == NULL){
809
 
      perror("combinepath");
810
 
      goto end;
811
 
    }
812
 
 
813
 
    ret = init_gnutls_global(&mc);
 
856
        return 0;
 
857
      }
 
858
 
 
859
      struct argp argp = { .options = options, .parser = parse_opt,
 
860
                           .args_doc = "",
 
861
                           .doc = "Mandos client -- Get and decrypt"
 
862
                           " passwords from mandos server" };
 
863
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
864
      if (ret == ARGP_ERR_UNKNOWN){
 
865
        fprintf(stderr, "Unknown error while parsing arguments\n");
 
866
        exitcode = EXIT_FAILURE;
 
867
        goto end;
 
868
      }
 
869
    }
 
870
      
 
871
    pubkeyfilename = combinepath(keydir, pubkeyname);
 
872
    if (pubkeyfilename == NULL){
 
873
      perror("combinepath");
 
874
      exitcode = EXIT_FAILURE;
 
875
      goto end;
 
876
    }
 
877
    
 
878
    seckeyfilename = combinepath(keydir, seckeyname);
 
879
    if (seckeyfilename == NULL){
 
880
      perror("combinepath");
 
881
      exitcode = EXIT_FAILURE;
 
882
      goto end;
 
883
    }
 
884
 
 
885
    ret = init_gnutls_global(&mc, pubkeyfilename, seckeyfilename);
814
886
    if (ret == -1){
815
 
      fprintf(stderr, "init_gnutls_global\n");
 
887
      fprintf(stderr, "init_gnutls_global failed\n");
 
888
      exitcode = EXIT_FAILURE;
816
889
      goto end;
817
 
    }
818
 
 
 
890
    } else {
 
891
      gnutls_initalized = true;
 
892
    }
 
893
    
 
894
    /* If the interface is down, bring it up */
 
895
    {
 
896
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
897
      if(sd < 0) {
 
898
        perror("socket");
 
899
        exitcode = EXIT_FAILURE;
 
900
        goto end;
 
901
      }
 
902
      strcpy(network.ifr_name, interface);
 
903
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
904
      if(ret == -1){
 
905
        perror("ioctl SIOCGIFFLAGS");
 
906
        exitcode = EXIT_FAILURE;
 
907
        goto end;
 
908
      }
 
909
      if((network.ifr_flags & IFF_UP) == 0){
 
910
        network.ifr_flags |= IFF_UP;
 
911
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
912
        if(ret == -1){
 
913
          perror("ioctl SIOCSIFFLAGS");
 
914
          exitcode = EXIT_FAILURE;
 
915
          goto end;
 
916
        }
 
917
      }
 
918
      close(sd);
 
919
    }
 
920
    
819
921
    uid = getuid();
820
922
    gid = getgid();
821
 
 
 
923
    
822
924
    ret = setuid(uid);
823
925
    if (ret == -1){
824
926
      perror("setuid");
862
964
      goto end;
863
965
    }
864
966
    
865
 
    /* If the interface is down, bring it up */
866
 
    {
867
 
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
868
 
      if(sd < 0) {
869
 
        perror("socket");
870
 
        exitcode = EXIT_FAILURE;
871
 
        goto end;
872
 
      }
873
 
      strcpy(network.ifr_name, interface); /* Spurious warning */
874
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
875
 
      if(ret == -1){
876
 
        perror("ioctl SIOCGIFFLAGS");
877
 
        exitcode = EXIT_FAILURE;
878
 
        goto end;
879
 
      }
880
 
      if((network.ifr_flags & IFF_UP) == 0){
881
 
        network.ifr_flags |= IFF_UP;
882
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
883
 
        if(ret == -1){
884
 
          perror("ioctl SIOCSIFFLAGS");
885
 
          exitcode = EXIT_FAILURE;
886
 
          goto end;
887
 
        }
888
 
      }
889
 
      close(sd);
890
 
    }
891
 
    
892
967
    if (not debug){
893
968
      avahi_set_log_function(empty_log);
894
969
    }
966
1041
 
967
1042
    if (mc.simple_poll != NULL)
968
1043
        avahi_simple_poll_free(mc.simple_poll);
969
 
    free(pubkeyfile);
970
 
    free(seckeyfile);
 
1044
    free(pubkeyfilename);
 
1045
    free(seckeyfilename);
 
1046
 
 
1047
    if (gnutls_initalized){
 
1048
      gnutls_certificate_free_credentials(mc.cred);
 
1049
      gnutls_global_deinit ();
 
1050
    }
971
1051
    
972
1052
    return exitcode;
973
1053
}