/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/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:
1
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Mandos-client - get and decrypt data from a Mandos server
 
3
 * Mandos client - get and decrypt data from a Mandos server
4
4
 *
5
5
 * This program is partly derived from an example program for an Avahi
6
6
 * service browser, downloaded from
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
11
 * Everything else is
12
 
 * Copyright © 2008,2009 Teddy Hogeborn
13
 
 * Copyright © 2008,2009 Björn Påhlsson
 
12
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
14
13
 * 
15
14
 * This program is free software: you can redistribute it and/or
16
15
 * modify it under the terms of the GNU General Public License as
36
35
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
37
36
 
38
37
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
39
 
                                   stdout, ferror(), sscanf */
 
38
                                   stdout, ferror() */
40
39
#include <stdint.h>             /* uint16_t, uint32_t */
41
40
#include <stddef.h>             /* NULL, size_t, ssize_t */
42
41
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
48
47
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
49
48
                                   sockaddr_in6, PF_INET6,
50
49
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
51
 
                                   uid_t, gid_t, open(), opendir(), DIR */
52
 
#include <sys/stat.h>           /* open() */
 
50
                                   uid_t, gid_t */
 
51
#include <inttypes.h>           /* PRIu16 */
53
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
54
53
                                   struct in6_addr, inet_pton(),
55
54
                                   connect() */
56
 
#include <fcntl.h>              /* open() */
57
 
#include <dirent.h>             /* opendir(), struct dirent, readdir() */
58
 
#include <inttypes.h>           /* PRIu16, SCNu16 */
59
55
#include <assert.h>             /* assert() */
60
56
#include <errno.h>              /* perror(), errno */
61
57
#include <time.h>               /* time() */
62
58
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
63
59
                                   SIOCSIFFLAGS, if_indextoname(),
64
60
                                   if_nametoindex(), IF_NAMESIZE */
65
 
#include <netinet/in.h>
66
61
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
67
62
                                   getuid(), getgid(), setuid(),
68
63
                                   setgid() */
 
64
#include <netinet/in.h>
69
65
#include <arpa/inet.h>          /* inet_pton(), htons */
70
 
#include <iso646.h>             /* not, and, or */
 
66
#include <iso646.h>             /* not, and */
71
67
#include <argp.h>               /* struct argp_option, error_t, struct
72
68
                                   argp_state, struct argp,
73
69
                                   argp_parse(), ARGP_KEY_ARG,
102
98
 
103
99
#define BUFFER_SIZE 256
104
100
 
105
 
#define PATHDIR "/conf/conf.d/mandos"
106
 
#define SECKEY "seckey.txt"
107
 
#define PUBKEY "pubkey.txt"
108
 
 
109
101
bool debug = false;
 
102
static const char *keydir = "/conf/conf.d/mandos";
110
103
static const char mandos_protocol_version[] = "1";
111
 
const char *argp_program_version = "mandos-client " VERSION;
 
104
const char *argp_program_version = "password-request 1.0";
112
105
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
113
106
 
114
107
/* Used for passing in values through the Avahi callback functions */
119
112
  unsigned int dh_bits;
120
113
  gnutls_dh_params_t dh_params;
121
114
  const char *priority;
122
 
  gpgme_ctx_t ctx;
123
115
} mandos_context;
124
116
 
125
117
/*
140
132
}
141
133
 
142
134
/* 
143
 
 * Initialize GPGME.
 
135
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
 
136
 * Returns -1 on error
144
137
 */
145
 
static bool init_gpgme(mandos_context *mc, const char *seckey,
146
 
                       const char *pubkey, const char *tempdir){
147
 
  int ret;
 
138
static ssize_t pgp_packet_decrypt (const char *cryptotext,
 
139
                                   size_t crypto_size,
 
140
                                   char **plaintext,
 
141
                                   const char *homedir){
 
142
  gpgme_data_t dh_crypto, dh_plain;
 
143
  gpgme_ctx_t ctx;
148
144
  gpgme_error_t rc;
 
145
  ssize_t ret;
 
146
  size_t plaintext_capacity = 0;
 
147
  ssize_t plaintext_length = 0;
149
148
  gpgme_engine_info_t engine_info;
150
149
  
151
 
  
152
 
  /*
153
 
   * Helper function to insert pub and seckey to the enigne keyring.
154
 
   */
155
 
  bool import_key(const char *filename){
156
 
    int fd;
157
 
    gpgme_data_t pgp_data;
158
 
    
159
 
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
160
 
    if(fd == -1){
161
 
      perror("open");
162
 
      return false;
163
 
    }
164
 
    
165
 
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
166
 
    if (rc != GPG_ERR_NO_ERROR){
167
 
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
168
 
              gpgme_strsource(rc), gpgme_strerror(rc));
169
 
      return false;
170
 
    }
171
 
    
172
 
    rc = gpgme_op_import(mc->ctx, pgp_data);
173
 
    if (rc != GPG_ERR_NO_ERROR){
174
 
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
175
 
              gpgme_strsource(rc), gpgme_strerror(rc));
176
 
      return false;
177
 
    }
178
 
    
179
 
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
180
 
    if(ret == -1){
181
 
      perror("close");
182
 
    }
183
 
    gpgme_data_release(pgp_data);
184
 
    return true;
185
 
  }
186
 
  
187
150
  if (debug){
188
 
    fprintf(stderr, "Initialize gpgme\n");
 
151
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
189
152
  }
190
153
  
191
154
  /* Init GPGME */
194
157
  if (rc != GPG_ERR_NO_ERROR){
195
158
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
196
159
            gpgme_strsource(rc), gpgme_strerror(rc));
197
 
    return false;
 
160
    return -1;
198
161
  }
199
162
  
200
 
    /* Set GPGME home directory for the OpenPGP engine only */
 
163
  /* Set GPGME home directory for the OpenPGP engine only */
201
164
  rc = gpgme_get_engine_info (&engine_info);
202
165
  if (rc != GPG_ERR_NO_ERROR){
203
166
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
204
167
            gpgme_strsource(rc), gpgme_strerror(rc));
205
 
    return false;
 
168
    return -1;
206
169
  }
207
170
  while(engine_info != NULL){
208
171
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
209
172
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
210
 
                            engine_info->file_name, tempdir);
 
173
                            engine_info->file_name, homedir);
211
174
      break;
212
175
    }
213
176
    engine_info = engine_info->next;
214
177
  }
215
178
  if(engine_info == NULL){
216
 
    fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
217
 
    return false;
218
 
  }
219
 
  
220
 
  /* Create new GPGME "context" */
221
 
  rc = gpgme_new(&(mc->ctx));
222
 
  if (rc != GPG_ERR_NO_ERROR){
223
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
224
 
            gpgme_strsource(rc), gpgme_strerror(rc));
225
 
    return false;
226
 
  }
227
 
  
228
 
  if (not import_key(pubkey) or not import_key(seckey)){
229
 
    return false;
230
 
  }
231
 
  
232
 
  return true; 
233
 
}
234
 
 
235
 
/* 
236
 
 * Decrypt OpenPGP data.
237
 
 * Returns -1 on error
238
 
 */
239
 
static ssize_t pgp_packet_decrypt (const mandos_context *mc,
240
 
                                   const char *cryptotext,
241
 
                                   size_t crypto_size,
242
 
                                   char **plaintext){
243
 
  gpgme_data_t dh_crypto, dh_plain;
244
 
  gpgme_error_t rc;
245
 
  ssize_t ret;
246
 
  size_t plaintext_capacity = 0;
247
 
  ssize_t plaintext_length = 0;
248
 
  
249
 
  if (debug){
250
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
179
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
 
180
    return -1;
251
181
  }
252
182
  
253
183
  /* Create new GPGME data buffer from memory cryptotext */
268
198
    return -1;
269
199
  }
270
200
  
 
201
  /* Create new GPGME "context" */
 
202
  rc = gpgme_new(&ctx);
 
203
  if (rc != GPG_ERR_NO_ERROR){
 
204
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
 
205
            gpgme_strsource(rc), gpgme_strerror(rc));
 
206
    plaintext_length = -1;
 
207
    goto decrypt_end;
 
208
  }
 
209
  
271
210
  /* Decrypt data from the cryptotext data buffer to the plaintext
272
211
     data buffer */
273
 
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
 
212
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
274
213
  if (rc != GPG_ERR_NO_ERROR){
275
214
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
276
215
            gpgme_strsource(rc), gpgme_strerror(rc));
277
216
    plaintext_length = -1;
278
217
    if (debug){
279
218
      gpgme_decrypt_result_t result;
280
 
      result = gpgme_op_decrypt_result(mc->ctx);
 
219
      result = gpgme_op_decrypt_result(ctx);
281
220
      if (result == NULL){
282
221
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
283
222
      } else {
312
251
  
313
252
  /* Seek back to the beginning of the GPGME plaintext data buffer */
314
253
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
315
 
    perror("gpgme_data_seek");
 
254
    perror("pgpme_data_seek");
316
255
    plaintext_length = -1;
317
256
    goto decrypt_end;
318
257
  }
342
281
    }
343
282
    plaintext_length += ret;
344
283
  }
345
 
  
 
284
 
346
285
  if(debug){
347
286
    fprintf(stderr, "Decrypted password is: ");
348
287
    for(ssize_t i = 0; i < plaintext_length; i++){
409
348
  }
410
349
  
411
350
  if(debug){
412
 
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
413
 
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
 
351
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
352
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
414
353
            seckeyfilename);
415
354
  }
416
355
  
421
360
    fprintf(stderr,
422
361
            "Error[%d] while reading the OpenPGP key pair ('%s',"
423
362
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
424
 
    fprintf(stderr, "The GnuTLS error is: %s\n",
 
363
    fprintf(stdout, "The GnuTLS error is: %s\n",
425
364
            safer_gnutls_strerror(ret));
426
365
    goto globalfail;
427
366
  }
441
380
  }
442
381
  
443
382
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
444
 
  
 
383
 
445
384
  return 0;
446
 
  
 
385
 
447
386
 globalfail:
448
 
  
 
387
 
449
388
  gnutls_certificate_free_credentials(mc->cred);
450
389
  gnutls_global_deinit();
451
 
  gnutls_dh_params_deinit(mc->dh_params);
452
390
  return -1;
 
391
 
453
392
}
454
393
 
455
394
static int init_gnutls_session(mandos_context *mc,
501
440
                                      AvahiIfIndex if_index,
502
441
                                      mandos_context *mc){
503
442
  int ret, tcp_sd;
504
 
  ssize_t sret;
505
443
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
506
444
  char *buffer = NULL;
507
445
  char *decrypted_buffer;
528
466
    perror("socket");
529
467
    return -1;
530
468
  }
531
 
  
 
469
 
532
470
  if(debug){
533
471
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
534
472
      perror("if_indextoname");
573
511
    perror("connect");
574
512
    return -1;
575
513
  }
576
 
  
 
514
 
577
515
  const char *out = mandos_protocol_version;
578
516
  written = 0;
579
517
  while (true){
580
518
    size_t out_size = strlen(out);
581
 
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
519
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
582
520
                                   out_size - written));
583
521
    if (ret == -1){
584
522
      perror("write");
597
535
      }
598
536
    }
599
537
  }
600
 
  
 
538
 
601
539
  if(debug){
602
540
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
603
541
  }
604
542
  
605
543
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
606
 
  
 
544
 
607
545
  do{
608
546
    ret = gnutls_handshake (session);
609
547
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
623
561
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
624
562
            ip);
625
563
  }
626
 
  
 
564
 
627
565
  while(true){
628
566
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
629
567
                                   buffer_capacity);
633
571
      goto mandos_end;
634
572
    }
635
573
    
636
 
    sret = gnutls_record_recv(session, buffer+buffer_length,
637
 
                              BUFFER_SIZE);
638
 
    if (sret == 0){
 
574
    ret = gnutls_record_recv(session, buffer+buffer_length,
 
575
                             BUFFER_SIZE);
 
576
    if (ret == 0){
639
577
      break;
640
578
    }
641
 
    if (sret < 0){
642
 
      switch(sret){
 
579
    if (ret < 0){
 
580
      switch(ret){
643
581
      case GNUTLS_E_INTERRUPTED:
644
582
      case GNUTLS_E_AGAIN:
645
583
        break;
662
600
        goto mandos_end;
663
601
      }
664
602
    } else {
665
 
      buffer_length += (size_t) sret;
 
603
      buffer_length += (size_t) ret;
666
604
    }
667
605
  }
668
606
  
673
611
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
674
612
  
675
613
  if (buffer_length > 0){
676
 
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
 
614
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
677
615
                                               buffer_length,
678
 
                                               &decrypted_buffer);
 
616
                                               &decrypted_buffer,
 
617
                                               keydir);
679
618
    if (decrypted_buffer_size >= 0){
680
619
      written = 0;
681
620
      while(written < (size_t) decrypted_buffer_size){
704
643
  
705
644
 mandos_end:
706
645
  free(buffer);
707
 
  ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
708
 
  if(ret == -1){
709
 
    perror("close");
710
 
  }
 
646
  close(tcp_sd);
711
647
  gnutls_deinit (session);
712
648
  return retval;
713
649
}
809
745
  }
810
746
}
811
747
 
 
748
/* Combines file name and path and returns the malloced new
 
749
   string. some sane checks could/should be added */
 
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){
 
754
    return NULL;
 
755
  }
 
756
  return tmp;
 
757
}
 
758
 
 
759
 
812
760
int main(int argc, char *argv[]){
813
761
    AvahiSServiceBrowser *sb = NULL;
814
762
    int error;
820
768
    uid_t uid;
821
769
    gid_t gid;
822
770
    char *connect_to = NULL;
823
 
    char tempdir[] = "/tmp/mandosXXXXXX";
824
771
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
825
 
    const char *seckey = PATHDIR "/" SECKEY;
826
 
    const char *pubkey = PATHDIR "/" PUBKEY;
827
 
    
 
772
    char *pubkeyfilename = NULL;
 
773
    char *seckeyfilename = NULL;
 
774
    const char *pubkeyname = "pubkey.txt";
 
775
    const char *seckeyname = "seckey.txt";
828
776
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
829
 
                          .dh_bits = 1024, .priority = "SECURE256"
830
 
                          ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
777
                          .dh_bits = 1024, .priority = "SECURE256"};
831
778
    bool gnutls_initalized = false;
832
 
    bool gpgme_initalized = false;
833
779
    
834
780
    {
835
781
      struct argp_option options[] = {
836
782
        { .name = "debug", .key = 128,
837
783
          .doc = "Debug mode", .group = 3 },
838
784
        { .name = "connect", .key = 'c',
839
 
          .arg = "ADDRESS:PORT",
840
 
          .doc = "Connect directly to a specific Mandos server",
 
785
          .arg = "IP",
 
786
          .doc = "Connect directly to a sepcified mandos server",
841
787
          .group = 1 },
842
788
        { .name = "interface", .key = 'i',
843
 
          .arg = "NAME",
844
 
          .doc = "Interface that will be used to search for Mandos"
845
 
          " servers",
 
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",
846
795
          .group = 1 },
847
796
        { .name = "seckey", .key = 's',
848
 
          .arg = "FILE",
849
 
          .doc = "OpenPGP secret key file base name",
 
797
          .arg = "SECKEY",
 
798
          .doc = "Secret openpgp key for gnutls authentication",
850
799
          .group = 1 },
851
800
        { .name = "pubkey", .key = 'p',
852
 
          .arg = "FILE",
853
 
          .doc = "OpenPGP public key file base name",
 
801
          .arg = "PUBKEY",
 
802
          .doc = "Public openpgp key for gnutls authentication",
854
803
          .group = 2 },
855
804
        { .name = "dh-bits", .key = 129,
856
805
          .arg = "BITS",
857
 
          .doc = "Bit length of the prime number used in the"
858
 
          " Diffie-Hellman key exchange",
 
806
          .doc = "dh-bits to use in gnutls communication",
859
807
          .group = 2 },
860
808
        { .name = "priority", .key = 130,
861
 
          .arg = "STRING",
862
 
          .doc = "GnuTLS priority string for the TLS handshake",
863
 
          .group = 1 },
 
809
          .arg = "PRIORITY",
 
810
          .doc = "GNUTLS priority", .group = 1 },
864
811
        { .name = NULL }
865
812
      };
 
813
 
866
814
      
867
815
      error_t parse_opt (int key, char *arg,
868
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. */
869
819
        switch (key) {
870
 
        case 128:               /* --debug */
 
820
        case 128:
871
821
          debug = true;
872
822
          break;
873
 
        case 'c':               /* --connect */
 
823
        case 'c':
874
824
          connect_to = arg;
875
825
          break;
876
 
        case 'i':               /* --interface */
 
826
        case 'i':
877
827
          interface = arg;
878
828
          break;
879
 
        case 's':               /* --seckey */
880
 
          seckey = arg;
881
 
          break;
882
 
        case 'p':               /* --pubkey */
883
 
          pubkey = arg;
884
 
          break;
885
 
        case 129:               /* --dh-bits */
886
 
          ret = sscanf(arg, "%u", &mc.dh_bits);
887
 
          if(ret != 1){
888
 
            fprintf(stderr, "Bad number of DH bits\n");
 
829
        case 'd':
 
830
          keydir = arg;
 
831
          break;
 
832
        case 's':
 
833
          seckeyname = arg;
 
834
          break;
 
835
        case 'p':
 
836
          pubkeyname = arg;
 
837
          break;
 
838
        case 129:
 
839
          errno = 0;
 
840
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
841
          if (errno){
 
842
            perror("strtol");
889
843
            exit(EXIT_FAILURE);
890
844
          }
891
845
          break;
892
 
        case 130:               /* --priority */
 
846
        case 130:
893
847
          mc.priority = arg;
894
848
          break;
895
849
        case ARGP_KEY_ARG:
901
855
        }
902
856
        return 0;
903
857
      }
904
 
      
 
858
 
905
859
      struct argp argp = { .options = options, .parser = parse_opt,
906
860
                           .args_doc = "",
907
861
                           .doc = "Mandos client -- Get and decrypt"
908
 
                           " passwords from a Mandos server" };
 
862
                           " passwords from mandos server" };
909
863
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
910
864
      if (ret == ARGP_ERR_UNKNOWN){
911
865
        fprintf(stderr, "Unknown error while parsing arguments\n");
913
867
        goto end;
914
868
      }
915
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);
 
886
    if (ret == -1){
 
887
      fprintf(stderr, "init_gnutls_global failed\n");
 
888
      exitcode = EXIT_FAILURE;
 
889
      goto end;
 
890
    } else {
 
891
      gnutls_initalized = true;
 
892
    }
916
893
    
917
894
    /* If the interface is down, bring it up */
918
895
    {
938
915
          goto end;
939
916
        }
940
917
      }
941
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
942
 
      if(ret == -1){
943
 
        perror("close");
944
 
      }
 
918
      close(sd);
945
919
    }
946
920
    
947
921
    uid = getuid();
957
931
      perror("setgid");
958
932
    }
959
933
    
960
 
    ret = init_gnutls_global(&mc, pubkey, seckey);
961
 
    if (ret == -1){
962
 
      fprintf(stderr, "init_gnutls_global failed\n");
963
 
      exitcode = EXIT_FAILURE;
964
 
      goto end;
965
 
    } else {
966
 
      gnutls_initalized = true;
967
 
    }
968
 
    
969
 
    if(mkdtemp(tempdir) == NULL){
970
 
      perror("mkdtemp");
971
 
      tempdir[0] = '\0';
972
 
      goto end;
973
 
    }
974
 
    
975
 
    if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
976
 
      fprintf(stderr, "gpgme_initalized failed\n");
977
 
      exitcode = EXIT_FAILURE;
978
 
      goto end;
979
 
    } else {
980
 
      gpgme_initalized = true;
981
 
    }
982
 
    
983
934
    if_index = (AvahiIfIndex) if_nametoindex(interface);
984
935
    if(if_index == 0){
985
936
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
995
946
        exitcode = EXIT_FAILURE;
996
947
        goto end;
997
948
      }
998
 
      uint16_t port;
999
 
      ret = sscanf(address+1, "%" SCNu16, &port);
1000
 
      if(ret != 1){
1001
 
        fprintf(stderr, "Bad port number\n");
 
949
      errno = 0;
 
950
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
951
      if(errno){
 
952
        perror("Bad port number");
1002
953
        exitcode = EXIT_FAILURE;
1003
954
        goto end;
1004
955
      }
1028
979
        exitcode = EXIT_FAILURE;
1029
980
        goto end;
1030
981
    }
1031
 
    
 
982
 
1032
983
    {
1033
984
      AvahiServerConfig config;
1034
985
      /* Do not publish any local Zeroconf records */
1037
988
      config.publish_addresses = 0;
1038
989
      config.publish_workstation = 0;
1039
990
      config.publish_domain = 0;
1040
 
      
 
991
 
1041
992
      /* Allocate a new server */
1042
993
      mc.server = avahi_server_new(avahi_simple_poll_get
1043
994
                                   (mc.simple_poll), &config, NULL,
1044
995
                                   NULL, &error);
1045
 
      
 
996
    
1046
997
      /* Free the Avahi configuration data */
1047
998
      avahi_server_config_free(&config);
1048
999
    }
1068
1019
    }
1069
1020
    
1070
1021
    /* Run the main loop */
1071
 
    
 
1022
 
1072
1023
    if (debug){
1073
1024
      fprintf(stderr, "Starting Avahi loop search\n");
1074
1025
    }
1076
1027
    avahi_simple_poll_loop(mc.simple_poll);
1077
1028
    
1078
1029
 end:
1079
 
    
 
1030
 
1080
1031
    if (debug){
1081
1032
      fprintf(stderr, "%s exiting\n", argv[0]);
1082
1033
    }
1087
1038
    
1088
1039
    if (mc.server != NULL)
1089
1040
        avahi_server_free(mc.server);
1090
 
    
 
1041
 
1091
1042
    if (mc.simple_poll != NULL)
1092
1043
        avahi_simple_poll_free(mc.simple_poll);
1093
 
    
 
1044
    free(pubkeyfilename);
 
1045
    free(seckeyfilename);
 
1046
 
1094
1047
    if (gnutls_initalized){
1095
1048
      gnutls_certificate_free_credentials(mc.cred);
1096
1049
      gnutls_global_deinit ();
1097
 
      gnutls_dh_params_deinit(mc.dh_params);
1098
 
    }
1099
 
    
1100
 
    if(gpgme_initalized){
1101
 
      gpgme_release(mc.ctx);
1102
 
    }
1103
 
    
1104
 
    /* Removes the temp directory used by GPGME */
1105
 
    if(tempdir[0] != '\0'){
1106
 
      DIR *d;
1107
 
      struct dirent *direntry;
1108
 
      d = opendir(tempdir);
1109
 
      if(d == NULL){
1110
 
        if(errno != ENOENT){
1111
 
          perror("opendir");
1112
 
        }
1113
 
      } else {
1114
 
        while(true){
1115
 
          direntry = readdir(d);
1116
 
          if(direntry == NULL){
1117
 
            break;
1118
 
          }
1119
 
          if (direntry->d_type == DT_REG){
1120
 
            char *fullname = NULL;
1121
 
            ret = asprintf(&fullname, "%s/%s", tempdir,
1122
 
                           direntry->d_name);
1123
 
            if(ret < 0){
1124
 
              perror("asprintf");
1125
 
              continue;
1126
 
            }
1127
 
            ret = unlink(fullname);
1128
 
            if(ret == -1){
1129
 
              fprintf(stderr, "unlink(\"%s\"): %s",
1130
 
                      fullname, strerror(errno));
1131
 
            }
1132
 
            free(fullname);
1133
 
          }
1134
 
        }
1135
 
        closedir(d);
1136
 
      }
1137
 
      ret = rmdir(tempdir);
1138
 
      if(ret == -1 and errno != ENOENT){
1139
 
        perror("rmdir");
1140
 
      }
1141
 
    }
1142
 
          
 
1050
    }
 
1051
    
1143
1052
    return exitcode;
1144
1053
}