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