/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-16 03:29:08 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080816032908-ihw7c05r2mnyk389
Add feature to specify custom environment variables for plugins.

* plugin-runner.c (plugin): New members "environ" and "envc" to
                            contain possible custom environment.
  (getplugin): Return NULL on failure instead of doing exit(); all
               callers changed.
  (add_to_char_array): New helper function for "add_argument" and
                       "add_environment".
  (addargument): Renamed to "add_argument".  Return bool.  Call
                 "add_to_char_array" to actually do things.
  (add_environment): New; analogous to "add_argument".
  (addcustomargument): Renamed to "add_to_argv" to avoid confusion
                       with "add_argument".
  (main): New options "--global-envs" and "--envs-for" to specify
          custom environment for plugins.  Print environment for
          plugins in debug mode.  Use asprintf instead of strcpy and
          strcat.  Use execve() for plugins with custom environments.
          Free environment for plugin when freeing plugin list.

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
48
48
                                   sockaddr_in6, PF_INET6,
49
49
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
50
 
                                   uid_t, gid_t, open(), opendir(), DIR */
51
 
#include <sys/stat.h>           /* open() */
 
50
                                   uid_t, gid_t */
 
51
#include <inttypes.h>           /* PRIu16 */
52
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
53
53
                                   struct in6_addr, inet_pton(),
54
54
                                   connect() */
55
 
#include <fcntl.h>              /* open() */
56
 
#include <dirent.h>             /* opendir(), struct dirent, readdir() */
57
 
#include <inttypes.h>           /* PRIu16 */
58
55
#include <assert.h>             /* assert() */
59
56
#include <errno.h>              /* perror(), errno */
60
57
#include <time.h>               /* time() */
61
58
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
62
59
                                   SIOCSIFFLAGS, if_indextoname(),
63
60
                                   if_nametoindex(), IF_NAMESIZE */
64
 
#include <netinet/in.h>
65
61
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
66
62
                                   getuid(), getgid(), setuid(),
67
63
                                   setgid() */
 
64
#include <netinet/in.h>
68
65
#include <arpa/inet.h>          /* inet_pton(), htons */
69
66
#include <iso646.h>             /* not, and */
70
67
#include <argp.h>               /* struct argp_option, error_t, struct
101
98
 
102
99
#define BUFFER_SIZE 256
103
100
 
104
 
/*
105
 
  #define PATHDIR "/conf/conf.d/mandos"
106
 
*/
107
 
 
108
 
#define PATHDIR "/conf/conf.d/mandos"
109
 
#define SECKEY "seckey.txt"
110
 
#define PUBKEY "pubkey.txt"
111
 
 
112
101
bool debug = false;
 
102
static const char *keydir = "/conf/conf.d/mandos";
113
103
static const char mandos_protocol_version[] = "1";
114
 
const char *argp_program_version = "mandos-client 1.0";
 
104
const char *argp_program_version = "password-request 1.0";
115
105
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
116
106
 
117
107
/* Used for passing in values through the Avahi callback functions */
122
112
  unsigned int dh_bits;
123
113
  gnutls_dh_params_t dh_params;
124
114
  const char *priority;
125
 
  gpgme_ctx_t ctx;
126
115
} mandos_context;
127
116
 
128
117
/*
143
132
}
144
133
 
145
134
/* 
146
 
 * Initialize GPGME.
 
135
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
 
136
 * Returns -1 on error
147
137
 */
148
 
static bool init_gpgme(mandos_context *mc, const char *seckey,
149
 
                       const char *pubkey, const char *tempdir){
150
 
  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;
151
144
  gpgme_error_t rc;
 
145
  ssize_t ret;
 
146
  size_t plaintext_capacity = 0;
 
147
  ssize_t plaintext_length = 0;
152
148
  gpgme_engine_info_t engine_info;
153
149
  
154
 
  
155
 
  /*
156
 
   * Helper function to insert pub and seckey to the enigne keyring.
157
 
   */
158
 
  bool import_key(const char *filename){
159
 
    int fd;
160
 
    gpgme_data_t pgp_data;
161
 
    
162
 
    fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
163
 
    if(fd == -1){
164
 
      perror("open");
165
 
      return false;
166
 
    }
167
 
    
168
 
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
169
 
    if (rc != GPG_ERR_NO_ERROR){
170
 
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
171
 
              gpgme_strsource(rc), gpgme_strerror(rc));
172
 
      return false;
173
 
    }
174
 
    
175
 
    rc = gpgme_op_import(mc->ctx, pgp_data);
176
 
    if (rc != GPG_ERR_NO_ERROR){
177
 
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
178
 
              gpgme_strsource(rc), gpgme_strerror(rc));
179
 
      return false;
180
 
    }
181
 
    
182
 
    ret = TEMP_FAILURE_RETRY(close(fd));
183
 
    if(ret == -1){
184
 
      perror("close");
185
 
    }
186
 
    gpgme_data_release(pgp_data);
187
 
    return true;
188
 
  }
189
 
  
190
150
  if (debug){
191
 
    fprintf(stderr, "Initialize gpgme\n");
 
151
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
192
152
  }
193
153
  
194
154
  /* Init GPGME */
197
157
  if (rc != GPG_ERR_NO_ERROR){
198
158
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
199
159
            gpgme_strsource(rc), gpgme_strerror(rc));
200
 
    return false;
 
160
    return -1;
201
161
  }
202
162
  
203
 
    /* Set GPGME home directory for the OpenPGP engine only */
 
163
  /* Set GPGME home directory for the OpenPGP engine only */
204
164
  rc = gpgme_get_engine_info (&engine_info);
205
165
  if (rc != GPG_ERR_NO_ERROR){
206
166
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
207
167
            gpgme_strsource(rc), gpgme_strerror(rc));
208
 
    return false;
 
168
    return -1;
209
169
  }
210
170
  while(engine_info != NULL){
211
171
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
212
172
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
213
 
                            engine_info->file_name, tempdir);
 
173
                            engine_info->file_name, homedir);
214
174
      break;
215
175
    }
216
176
    engine_info = engine_info->next;
217
177
  }
218
178
  if(engine_info == NULL){
219
 
    fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
220
 
    return false;
221
 
  }
222
 
  
223
 
  /* Create new GPGME "context" */
224
 
  rc = gpgme_new(&(mc->ctx));
225
 
  if (rc != GPG_ERR_NO_ERROR){
226
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
227
 
            gpgme_strsource(rc), gpgme_strerror(rc));
228
 
    return false;
229
 
  }
230
 
  
231
 
  if (not import_key(pubkey) or not import_key(seckey)){
232
 
    return false;
233
 
  }
234
 
  
235
 
  return true; 
236
 
}
237
 
 
238
 
/* 
239
 
 * Decrypt OpenPGP data.
240
 
 * Returns -1 on error
241
 
 */
242
 
static ssize_t pgp_packet_decrypt (const mandos_context *mc,
243
 
                                   const char *cryptotext,
244
 
                                   size_t crypto_size,
245
 
                                   char **plaintext){
246
 
  gpgme_data_t dh_crypto, dh_plain;
247
 
  gpgme_error_t rc;
248
 
  ssize_t ret;
249
 
  size_t plaintext_capacity = 0;
250
 
  ssize_t plaintext_length = 0;
251
 
  
252
 
  if (debug){
253
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
179
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
 
180
    return -1;
254
181
  }
255
182
  
256
183
  /* Create new GPGME data buffer from memory cryptotext */
271
198
    return -1;
272
199
  }
273
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
  
274
210
  /* Decrypt data from the cryptotext data buffer to the plaintext
275
211
     data buffer */
276
 
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
 
212
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
277
213
  if (rc != GPG_ERR_NO_ERROR){
278
214
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
279
215
            gpgme_strsource(rc), gpgme_strerror(rc));
280
216
    plaintext_length = -1;
281
 
    if (debug){
282
 
      gpgme_decrypt_result_t result;
283
 
      result = gpgme_op_decrypt_result(mc->ctx);
284
 
      if (result == NULL){
285
 
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
286
 
      } else {
287
 
        fprintf(stderr, "Unsupported algorithm: %s\n",
288
 
                result->unsupported_algorithm);
289
 
        fprintf(stderr, "Wrong key usage: %u\n",
290
 
                result->wrong_key_usage);
291
 
        if(result->file_name != NULL){
292
 
          fprintf(stderr, "File name: %s\n", result->file_name);
293
 
        }
294
 
        gpgme_recipient_t recipient;
295
 
        recipient = result->recipients;
296
 
        if(recipient){
297
 
          while(recipient != NULL){
298
 
            fprintf(stderr, "Public key algorithm: %s\n",
299
 
                    gpgme_pubkey_algo_name(recipient->pubkey_algo));
300
 
            fprintf(stderr, "Key ID: %s\n", recipient->keyid);
301
 
            fprintf(stderr, "Secret key available: %s\n",
302
 
                    recipient->status == GPG_ERR_NO_SECKEY
303
 
                    ? "No" : "Yes");
304
 
            recipient = recipient->next;
305
 
          }
306
 
        }
307
 
      }
308
 
    }
309
217
    goto decrypt_end;
310
218
  }
311
219
  
313
221
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
314
222
  }
315
223
  
 
224
  if (debug){
 
225
    gpgme_decrypt_result_t result;
 
226
    result = gpgme_op_decrypt_result(ctx);
 
227
    if (result == NULL){
 
228
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
229
    } else {
 
230
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
231
              result->unsupported_algorithm);
 
232
      fprintf(stderr, "Wrong key usage: %u\n",
 
233
              result->wrong_key_usage);
 
234
      if(result->file_name != NULL){
 
235
        fprintf(stderr, "File name: %s\n", result->file_name);
 
236
      }
 
237
      gpgme_recipient_t recipient;
 
238
      recipient = result->recipients;
 
239
      if(recipient){
 
240
        while(recipient != NULL){
 
241
          fprintf(stderr, "Public key algorithm: %s\n",
 
242
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
243
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
244
          fprintf(stderr, "Secret key available: %s\n",
 
245
                  recipient->status == GPG_ERR_NO_SECKEY
 
246
                  ? "No" : "Yes");
 
247
          recipient = recipient->next;
 
248
        }
 
249
      }
 
250
    }
 
251
  }
 
252
  
316
253
  /* Seek back to the beginning of the GPGME plaintext data buffer */
317
254
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
318
 
    perror("gpgme_data_seek");
 
255
    perror("pgpme_data_seek");
319
256
    plaintext_length = -1;
320
257
    goto decrypt_end;
321
258
  }
345
282
    }
346
283
    plaintext_length += ret;
347
284
  }
348
 
  
 
285
 
349
286
  if(debug){
350
287
    fprintf(stderr, "Decrypted password is: ");
351
288
    for(ssize_t i = 0; i < plaintext_length; i++){
365
302
}
366
303
 
367
304
static const char * safer_gnutls_strerror (int value) {
368
 
  const char *ret = gnutls_strerror (value); /* Spurious warning */
 
305
  const char *ret = gnutls_strerror (value);
369
306
  if (ret == NULL)
370
307
    ret = "(unknown)";
371
308
  return ret;
404
341
  /* OpenPGP credentials */
405
342
  gnutls_certificate_allocate_credentials(&mc->cred);
406
343
  if (ret != GNUTLS_E_SUCCESS){
407
 
    fprintf (stderr, "GnuTLS memory error: %s\n", /* Spurious
408
 
                                                     warning */
 
344
    fprintf (stderr, "GnuTLS memory error: %s\n",
409
345
             safer_gnutls_strerror(ret));
410
346
    gnutls_global_deinit ();
411
347
    return -1;
412
348
  }
413
349
  
414
350
  if(debug){
415
 
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
416
 
            " 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,
417
353
            seckeyfilename);
418
354
  }
419
355
  
424
360
    fprintf(stderr,
425
361
            "Error[%d] while reading the OpenPGP key pair ('%s',"
426
362
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
427
 
    fprintf(stderr, "The GnuTLS error is: %s\n",
 
363
    fprintf(stdout, "The GnuTLS error is: %s\n",
428
364
            safer_gnutls_strerror(ret));
429
365
    goto globalfail;
430
366
  }
444
380
  }
445
381
  
446
382
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
447
 
  
 
383
 
448
384
  return 0;
449
 
  
 
385
 
450
386
 globalfail:
451
 
  
 
387
 
452
388
  gnutls_certificate_free_credentials(mc->cred);
453
389
  gnutls_global_deinit();
454
 
  gnutls_dh_params_deinit(mc->dh_params);
455
390
  return -1;
 
391
 
456
392
}
457
393
 
458
394
static int init_gnutls_session(mandos_context *mc,
530
466
    perror("socket");
531
467
    return -1;
532
468
  }
533
 
  
 
469
 
534
470
  if(debug){
535
471
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
536
472
      perror("if_indextoname");
539
475
    fprintf(stderr, "Binding to interface %s\n", interface);
540
476
  }
541
477
  
542
 
  memset(&to, 0, sizeof(to));
 
478
  memset(&to, 0, sizeof(to));   /* Spurious warning */
543
479
  to.in6.sin6_family = AF_INET6;
544
480
  /* It would be nice to have a way to detect if we were passed an
545
481
     IPv4 address here.   Now we assume an IPv6 address. */
575
511
    perror("connect");
576
512
    return -1;
577
513
  }
578
 
  
 
514
 
579
515
  const char *out = mandos_protocol_version;
580
516
  written = 0;
581
517
  while (true){
599
535
      }
600
536
    }
601
537
  }
602
 
  
 
538
 
603
539
  if(debug){
604
540
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
605
541
  }
606
542
  
607
543
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
608
 
  
 
544
 
609
545
  do{
610
546
    ret = gnutls_handshake (session);
611
547
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
625
561
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
626
562
            ip);
627
563
  }
628
 
  
 
564
 
629
565
  while(true){
630
566
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
631
567
                                   buffer_capacity);
675
611
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
676
612
  
677
613
  if (buffer_length > 0){
678
 
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
 
614
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
679
615
                                               buffer_length,
680
 
                                               &decrypted_buffer);
 
616
                                               &decrypted_buffer,
 
617
                                               keydir);
681
618
    if (decrypted_buffer_size >= 0){
682
619
      written = 0;
683
620
      while(written < (size_t) decrypted_buffer_size){
698
635
    } else {
699
636
      retval = -1;
700
637
    }
701
 
  } else {
702
 
    retval = -1;
703
638
  }
704
639
  
705
640
  /* Shutdown procedure */
706
641
  
707
642
 mandos_end:
708
643
  free(buffer);
709
 
  ret = TEMP_FAILURE_RETRY(close(tcp_sd));
710
 
  if(ret == -1){
711
 
    perror("close");
712
 
  }
 
644
  close(tcp_sd);
713
645
  gnutls_deinit (session);
714
646
  return retval;
715
647
}
729
661
                             flags,
730
662
                             void* userdata) {
731
663
  mandos_context *mc = userdata;
732
 
  assert(r);
 
664
  assert(r);                    /* Spurious warning */
733
665
  
734
666
  /* Called whenever a service has been resolved successfully or
735
667
     timed out */
771
703
                             flags,
772
704
                             void* userdata) {
773
705
  mandos_context *mc = userdata;
774
 
  assert(b);
 
706
  assert(b);                    /* Spurious warning */
775
707
  
776
708
  /* Called whenever a new services becomes available on the LAN or
777
709
     is removed from the LAN */
811
743
  }
812
744
}
813
745
 
 
746
/* Combines file name and path and returns the malloced new
 
747
   string. some sane checks could/should be added */
 
748
static char *combinepath(const char *first, const char *second){
 
749
  char *tmp;
 
750
  int ret = asprintf(&tmp, "%s/%s", first, second);
 
751
  if(ret < 0){
 
752
    return NULL;
 
753
  }
 
754
  return tmp;
 
755
}
 
756
 
 
757
 
814
758
int main(int argc, char *argv[]){
815
759
    AvahiSServiceBrowser *sb = NULL;
816
760
    int error;
822
766
    uid_t uid;
823
767
    gid_t gid;
824
768
    char *connect_to = NULL;
825
 
    char tempdir[] = "/tmp/mandosXXXXXX";
826
769
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
827
 
    const char *seckey = PATHDIR "/" SECKEY;
828
 
    const char *pubkey = PATHDIR "/" PUBKEY;
829
 
    
 
770
    char *pubkeyfilename = NULL;
 
771
    char *seckeyfilename = NULL;
 
772
    const char *pubkeyname = "pubkey.txt";
 
773
    const char *seckeyname = "seckey.txt";
830
774
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
831
 
                          .dh_bits = 1024, .priority = "SECURE256"
832
 
                          ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
775
                          .dh_bits = 1024, .priority = "SECURE256"};
833
776
    bool gnutls_initalized = false;
834
 
    bool gpgme_initalized = false;
835
777
    
836
778
    {
837
779
      struct argp_option options[] = {
838
780
        { .name = "debug", .key = 128,
839
781
          .doc = "Debug mode", .group = 3 },
840
782
        { .name = "connect", .key = 'c',
841
 
          .arg = "ADDRESS:PORT",
842
 
          .doc = "Connect directly to a specific Mandos server",
 
783
          .arg = "IP",
 
784
          .doc = "Connect directly to a sepcified mandos server",
843
785
          .group = 1 },
844
786
        { .name = "interface", .key = 'i',
845
 
          .arg = "NAME",
846
 
          .doc = "Interface that will be used to search for Mandos"
847
 
          " servers",
 
787
          .arg = "INTERFACE",
 
788
          .doc = "Interface that Avahi will conntect through",
 
789
          .group = 1 },
 
790
        { .name = "keydir", .key = 'd',
 
791
          .arg = "KEYDIR",
 
792
          .doc = "Directory where the openpgp keyring is",
848
793
          .group = 1 },
849
794
        { .name = "seckey", .key = 's',
850
 
          .arg = "FILE",
851
 
          .doc = "OpenPGP secret key file base name",
 
795
          .arg = "SECKEY",
 
796
          .doc = "Secret openpgp key for gnutls authentication",
852
797
          .group = 1 },
853
798
        { .name = "pubkey", .key = 'p',
854
 
          .arg = "FILE",
855
 
          .doc = "OpenPGP public key file base name",
 
799
          .arg = "PUBKEY",
 
800
          .doc = "Public openpgp key for gnutls authentication",
856
801
          .group = 2 },
857
802
        { .name = "dh-bits", .key = 129,
858
803
          .arg = "BITS",
859
 
          .doc = "Bit length of the prime number used in the"
860
 
          " Diffie-Hellman key exchange",
 
804
          .doc = "dh-bits to use in gnutls communication",
861
805
          .group = 2 },
862
806
        { .name = "priority", .key = 130,
863
 
          .arg = "STRING",
864
 
          .doc = "GnuTLS priority string for the TLS handshake",
865
 
          .group = 1 },
 
807
          .arg = "PRIORITY",
 
808
          .doc = "GNUTLS priority", .group = 1 },
866
809
        { .name = NULL }
867
810
      };
 
811
 
868
812
      
869
813
      error_t parse_opt (int key, char *arg,
870
814
                         struct argp_state *state) {
871
815
        /* Get the INPUT argument from `argp_parse', which we know is
872
816
           a pointer to our plugin list pointer. */
873
817
        switch (key) {
874
 
        case 128:               /* --debug */
 
818
        case 128:
875
819
          debug = true;
876
820
          break;
877
 
        case 'c':               /* --connect */
 
821
        case 'c':
878
822
          connect_to = arg;
879
823
          break;
880
 
        case 'i':               /* --interface */
 
824
        case 'i':
881
825
          interface = arg;
882
826
          break;
883
 
        case 's':               /* --seckey */
884
 
          seckey = arg;
885
 
          break;
886
 
        case 'p':               /* --pubkey */
887
 
          pubkey = arg;
888
 
          break;
889
 
        case 129:               /* --dh-bits */
 
827
        case 'd':
 
828
          keydir = arg;
 
829
          break;
 
830
        case 's':
 
831
          seckeyname = arg;
 
832
          break;
 
833
        case 'p':
 
834
          pubkeyname = arg;
 
835
          break;
 
836
        case 129:
890
837
          errno = 0;
891
838
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
892
839
          if (errno){
894
841
            exit(EXIT_FAILURE);
895
842
          }
896
843
          break;
897
 
        case 130:               /* --priority */
 
844
        case 130:
898
845
          mc.priority = arg;
899
846
          break;
900
847
        case ARGP_KEY_ARG:
906
853
        }
907
854
        return 0;
908
855
      }
909
 
      
 
856
 
910
857
      struct argp argp = { .options = options, .parser = parse_opt,
911
858
                           .args_doc = "",
912
859
                           .doc = "Mandos client -- Get and decrypt"
913
 
                           " passwords from a Mandos server" };
 
860
                           " passwords from mandos server" };
914
861
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
915
862
      if (ret == ARGP_ERR_UNKNOWN){
916
863
        fprintf(stderr, "Unknown error while parsing arguments\n");
918
865
        goto end;
919
866
      }
920
867
    }
 
868
      
 
869
    pubkeyfilename = combinepath(keydir, pubkeyname);
 
870
    if (pubkeyfilename == NULL){
 
871
      perror("combinepath");
 
872
      exitcode = EXIT_FAILURE;
 
873
      goto end;
 
874
    }
 
875
    
 
876
    seckeyfilename = combinepath(keydir, seckeyname);
 
877
    if (seckeyfilename == NULL){
 
878
      perror("combinepath");
 
879
      exitcode = EXIT_FAILURE;
 
880
      goto end;
 
881
    }
 
882
 
 
883
    ret = init_gnutls_global(&mc, pubkeyfilename, seckeyfilename);
 
884
    if (ret == -1){
 
885
      fprintf(stderr, "init_gnutls_global failed\n");
 
886
      exitcode = EXIT_FAILURE;
 
887
      goto end;
 
888
    } else {
 
889
      gnutls_initalized = true;
 
890
    }
921
891
    
922
892
    /* If the interface is down, bring it up */
923
893
    {
927
897
        exitcode = EXIT_FAILURE;
928
898
        goto end;
929
899
      }
930
 
      strcpy(network.ifr_name, interface);
 
900
      strcpy(network.ifr_name, interface); /* Spurious warning */
931
901
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
932
902
      if(ret == -1){
933
903
        perror("ioctl SIOCGIFFLAGS");
943
913
          goto end;
944
914
        }
945
915
      }
946
 
      ret = TEMP_FAILURE_RETRY(close(sd));
947
 
      if(ret == -1){
948
 
        perror("close");
949
 
      }
 
916
      close(sd);
950
917
    }
951
918
    
952
919
    uid = getuid();
962
929
      perror("setgid");
963
930
    }
964
931
    
965
 
    ret = init_gnutls_global(&mc, pubkey, seckey);
966
 
    if (ret == -1){
967
 
      fprintf(stderr, "init_gnutls_global failed\n");
968
 
      exitcode = EXIT_FAILURE;
969
 
      goto end;
970
 
    } else {
971
 
      gnutls_initalized = true;
972
 
    }
973
 
    
974
 
    if(mkdtemp(tempdir) == NULL){
975
 
      perror("mkdtemp");
976
 
      tempdir[0] = '\0';
977
 
      goto end;
978
 
    }
979
 
    
980
 
    if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
981
 
      fprintf(stderr, "gpgme_initalized failed\n");
982
 
      exitcode = EXIT_FAILURE;
983
 
      goto end;
984
 
    } else {
985
 
      gpgme_initalized = true;
986
 
    }
987
 
    
988
932
    if_index = (AvahiIfIndex) if_nametoindex(interface);
989
933
    if(if_index == 0){
990
934
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1033
977
        exitcode = EXIT_FAILURE;
1034
978
        goto end;
1035
979
    }
1036
 
    
 
980
 
1037
981
    {
1038
982
      AvahiServerConfig config;
1039
983
      /* Do not publish any local Zeroconf records */
1042
986
      config.publish_addresses = 0;
1043
987
      config.publish_workstation = 0;
1044
988
      config.publish_domain = 0;
1045
 
      
 
989
 
1046
990
      /* Allocate a new server */
1047
991
      mc.server = avahi_server_new(avahi_simple_poll_get
1048
992
                                   (mc.simple_poll), &config, NULL,
1049
993
                                   NULL, &error);
1050
 
      
 
994
    
1051
995
      /* Free the Avahi configuration data */
1052
996
      avahi_server_config_free(&config);
1053
997
    }
1073
1017
    }
1074
1018
    
1075
1019
    /* Run the main loop */
1076
 
    
 
1020
 
1077
1021
    if (debug){
1078
1022
      fprintf(stderr, "Starting Avahi loop search\n");
1079
1023
    }
1081
1025
    avahi_simple_poll_loop(mc.simple_poll);
1082
1026
    
1083
1027
 end:
1084
 
    
 
1028
 
1085
1029
    if (debug){
1086
1030
      fprintf(stderr, "%s exiting\n", argv[0]);
1087
1031
    }
1092
1036
    
1093
1037
    if (mc.server != NULL)
1094
1038
        avahi_server_free(mc.server);
1095
 
    
 
1039
 
1096
1040
    if (mc.simple_poll != NULL)
1097
1041
        avahi_simple_poll_free(mc.simple_poll);
1098
 
    
 
1042
    free(pubkeyfilename);
 
1043
    free(seckeyfilename);
 
1044
 
1099
1045
    if (gnutls_initalized){
1100
1046
      gnutls_certificate_free_credentials(mc.cred);
1101
1047
      gnutls_global_deinit ();
1102
 
      gnutls_dh_params_deinit(mc.dh_params);
1103
 
    }
1104
 
    
1105
 
    if(gpgme_initalized){
1106
 
      gpgme_release(mc.ctx);
1107
 
    }
1108
 
    
1109
 
    /* Removes the temp directory used by GPGME */
1110
 
    if(tempdir[0] != '\0'){
1111
 
      DIR *d;
1112
 
      struct dirent *direntry;
1113
 
      d = opendir(tempdir);
1114
 
      if(d == NULL){
1115
 
        perror("opendir");
1116
 
      } else {
1117
 
        while(true){
1118
 
          direntry = readdir(d);
1119
 
          if(direntry == NULL){
1120
 
            break;
1121
 
          }
1122
 
          if (direntry->d_type == DT_REG){
1123
 
            char *fullname = NULL;
1124
 
            ret = asprintf(&fullname, "%s/%s", tempdir,
1125
 
                           direntry->d_name);
1126
 
            if(ret < 0){
1127
 
              perror("asprintf");
1128
 
              continue;
1129
 
            }
1130
 
            ret = unlink(fullname);
1131
 
            if(ret == -1){
1132
 
              fprintf(stderr, "unlink(\"%s\"): %s",
1133
 
                      fullname, strerror(errno));
1134
 
            }
1135
 
            free(fullname);
1136
 
          }
1137
 
        }
1138
 
        closedir(d);
1139
 
      }
1140
 
      ret = rmdir(tempdir);
1141
 
      if(ret == -1){
1142
 
        perror("rmdir");
1143
 
      }
1144
 
    }
1145
 
          
 
1048
    }
 
1049
    
1146
1050
    return exitcode;
1147
1051
}