/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,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
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 */
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
66
#include <iso646.h>             /* not, and */
71
67
#include <argp.h>               /* struct argp_option, error_t, struct
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 = 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 = 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
 
    if (debug){
279
 
      gpgme_decrypt_result_t result;
280
 
      result = gpgme_op_decrypt_result(mc->ctx);
281
 
      if (result == NULL){
282
 
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
283
 
      } else {
284
 
        fprintf(stderr, "Unsupported algorithm: %s\n",
285
 
                result->unsupported_algorithm);
286
 
        fprintf(stderr, "Wrong key usage: %u\n",
287
 
                result->wrong_key_usage);
288
 
        if(result->file_name != NULL){
289
 
          fprintf(stderr, "File name: %s\n", result->file_name);
290
 
        }
291
 
        gpgme_recipient_t recipient;
292
 
        recipient = result->recipients;
293
 
        if(recipient){
294
 
          while(recipient != NULL){
295
 
            fprintf(stderr, "Public key algorithm: %s\n",
296
 
                    gpgme_pubkey_algo_name(recipient->pubkey_algo));
297
 
            fprintf(stderr, "Key ID: %s\n", recipient->keyid);
298
 
            fprintf(stderr, "Secret key available: %s\n",
299
 
                    recipient->status == GPG_ERR_NO_SECKEY
300
 
                    ? "No" : "Yes");
301
 
            recipient = recipient->next;
302
 
          }
303
 
        }
304
 
      }
305
 
    }
306
217
    goto decrypt_end;
307
218
  }
308
219
  
310
221
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
311
222
  }
312
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
  
313
253
  /* Seek back to the beginning of the GPGME plaintext data buffer */
314
254
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
315
 
    perror("gpgme_data_seek");
 
255
    perror("pgpme_data_seek");
316
256
    plaintext_length = -1;
317
257
    goto decrypt_end;
318
258
  }
342
282
    }
343
283
    plaintext_length += ret;
344
284
  }
345
 
  
 
285
 
346
286
  if(debug){
347
287
    fprintf(stderr, "Decrypted password is: ");
348
288
    for(ssize_t i = 0; i < plaintext_length; i++){
362
302
}
363
303
 
364
304
static const char * safer_gnutls_strerror (int value) {
365
 
  const char *ret = gnutls_strerror (value); /* Spurious warning */
 
305
  const char *ret = gnutls_strerror (value);
366
306
  if (ret == NULL)
367
307
    ret = "(unknown)";
368
308
  return ret;
401
341
  /* OpenPGP credentials */
402
342
  gnutls_certificate_allocate_credentials(&mc->cred);
403
343
  if (ret != GNUTLS_E_SUCCESS){
404
 
    fprintf (stderr, "GnuTLS memory error: %s\n", /* Spurious
405
 
                                                     warning */
 
344
    fprintf (stderr, "GnuTLS memory error: %s\n",
406
345
             safer_gnutls_strerror(ret));
407
346
    gnutls_global_deinit ();
408
347
    return -1;
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,
527
466
    perror("socket");
528
467
    return -1;
529
468
  }
530
 
  
 
469
 
531
470
  if(debug){
532
471
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
533
472
      perror("if_indextoname");
536
475
    fprintf(stderr, "Binding to interface %s\n", interface);
537
476
  }
538
477
  
539
 
  memset(&to, 0, sizeof(to));
 
478
  memset(&to, 0, sizeof(to));   /* Spurious warning */
540
479
  to.in6.sin6_family = AF_INET6;
541
480
  /* It would be nice to have a way to detect if we were passed an
542
481
     IPv4 address here.   Now we assume an IPv6 address. */
572
511
    perror("connect");
573
512
    return -1;
574
513
  }
575
 
  
 
514
 
576
515
  const char *out = mandos_protocol_version;
577
516
  written = 0;
578
517
  while (true){
596
535
      }
597
536
    }
598
537
  }
599
 
  
 
538
 
600
539
  if(debug){
601
540
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
602
541
  }
603
542
  
604
543
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
605
 
  
 
544
 
606
545
  do{
607
546
    ret = gnutls_handshake (session);
608
547
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
622
561
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
623
562
            ip);
624
563
  }
625
 
  
 
564
 
626
565
  while(true){
627
566
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
628
567
                                   buffer_capacity);
672
611
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
673
612
  
674
613
  if (buffer_length > 0){
675
 
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
 
614
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
676
615
                                               buffer_length,
677
 
                                               &decrypted_buffer);
 
616
                                               &decrypted_buffer,
 
617
                                               keydir);
678
618
    if (decrypted_buffer_size >= 0){
679
619
      written = 0;
680
620
      while(written < (size_t) decrypted_buffer_size){
695
635
    } else {
696
636
      retval = -1;
697
637
    }
698
 
  } else {
699
 
    retval = -1;
700
638
  }
701
639
  
702
640
  /* Shutdown procedure */
703
641
  
704
642
 mandos_end:
705
643
  free(buffer);
706
 
  ret = TEMP_FAILURE_RETRY(close(tcp_sd));
707
 
  if(ret == -1){
708
 
    perror("close");
709
 
  }
 
644
  close(tcp_sd);
710
645
  gnutls_deinit (session);
711
646
  return retval;
712
647
}
726
661
                             flags,
727
662
                             void* userdata) {
728
663
  mandos_context *mc = userdata;
729
 
  assert(r);
 
664
  assert(r);                    /* Spurious warning */
730
665
  
731
666
  /* Called whenever a service has been resolved successfully or
732
667
     timed out */
768
703
                             flags,
769
704
                             void* userdata) {
770
705
  mandos_context *mc = userdata;
771
 
  assert(b);
 
706
  assert(b);                    /* Spurious warning */
772
707
  
773
708
  /* Called whenever a new services becomes available on the LAN or
774
709
     is removed from the LAN */
808
743
  }
809
744
}
810
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
 
811
758
int main(int argc, char *argv[]){
812
759
    AvahiSServiceBrowser *sb = NULL;
813
760
    int error;
819
766
    uid_t uid;
820
767
    gid_t gid;
821
768
    char *connect_to = NULL;
822
 
    char tempdir[] = "/tmp/mandosXXXXXX";
823
769
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
824
 
    const char *seckey = PATHDIR "/" SECKEY;
825
 
    const char *pubkey = PATHDIR "/" PUBKEY;
826
 
    
 
770
    char *pubkeyfilename = NULL;
 
771
    char *seckeyfilename = NULL;
 
772
    const char *pubkeyname = "pubkey.txt";
 
773
    const char *seckeyname = "seckey.txt";
827
774
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
828
 
                          .dh_bits = 1024, .priority = "SECURE256"
829
 
                          ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
775
                          .dh_bits = 1024, .priority = "SECURE256"};
830
776
    bool gnutls_initalized = false;
831
 
    bool gpgme_initalized = false;
832
777
    
833
778
    {
834
779
      struct argp_option options[] = {
835
780
        { .name = "debug", .key = 128,
836
781
          .doc = "Debug mode", .group = 3 },
837
782
        { .name = "connect", .key = 'c',
838
 
          .arg = "ADDRESS:PORT",
839
 
          .doc = "Connect directly to a specific Mandos server",
 
783
          .arg = "IP",
 
784
          .doc = "Connect directly to a sepcified mandos server",
840
785
          .group = 1 },
841
786
        { .name = "interface", .key = 'i',
842
 
          .arg = "NAME",
843
 
          .doc = "Interface that will be used to search for Mandos"
844
 
          " 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",
845
793
          .group = 1 },
846
794
        { .name = "seckey", .key = 's',
847
 
          .arg = "FILE",
848
 
          .doc = "OpenPGP secret key file base name",
 
795
          .arg = "SECKEY",
 
796
          .doc = "Secret openpgp key for gnutls authentication",
849
797
          .group = 1 },
850
798
        { .name = "pubkey", .key = 'p',
851
 
          .arg = "FILE",
852
 
          .doc = "OpenPGP public key file base name",
 
799
          .arg = "PUBKEY",
 
800
          .doc = "Public openpgp key for gnutls authentication",
853
801
          .group = 2 },
854
802
        { .name = "dh-bits", .key = 129,
855
803
          .arg = "BITS",
856
 
          .doc = "Bit length of the prime number used in the"
857
 
          " Diffie-Hellman key exchange",
 
804
          .doc = "dh-bits to use in gnutls communication",
858
805
          .group = 2 },
859
806
        { .name = "priority", .key = 130,
860
 
          .arg = "STRING",
861
 
          .doc = "GnuTLS priority string for the TLS handshake",
862
 
          .group = 1 },
 
807
          .arg = "PRIORITY",
 
808
          .doc = "GNUTLS priority", .group = 1 },
863
809
        { .name = NULL }
864
810
      };
 
811
 
865
812
      
866
813
      error_t parse_opt (int key, char *arg,
867
814
                         struct argp_state *state) {
868
815
        /* Get the INPUT argument from `argp_parse', which we know is
869
816
           a pointer to our plugin list pointer. */
870
817
        switch (key) {
871
 
        case 128:               /* --debug */
 
818
        case 128:
872
819
          debug = true;
873
820
          break;
874
 
        case 'c':               /* --connect */
 
821
        case 'c':
875
822
          connect_to = arg;
876
823
          break;
877
 
        case 'i':               /* --interface */
 
824
        case 'i':
878
825
          interface = arg;
879
826
          break;
880
 
        case 's':               /* --seckey */
881
 
          seckey = arg;
882
 
          break;
883
 
        case 'p':               /* --pubkey */
884
 
          pubkey = arg;
885
 
          break;
886
 
        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:
887
837
          errno = 0;
888
838
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
889
839
          if (errno){
891
841
            exit(EXIT_FAILURE);
892
842
          }
893
843
          break;
894
 
        case 130:               /* --priority */
 
844
        case 130:
895
845
          mc.priority = arg;
896
846
          break;
897
847
        case ARGP_KEY_ARG:
903
853
        }
904
854
        return 0;
905
855
      }
906
 
      
 
856
 
907
857
      struct argp argp = { .options = options, .parser = parse_opt,
908
858
                           .args_doc = "",
909
859
                           .doc = "Mandos client -- Get and decrypt"
910
 
                           " passwords from a Mandos server" };
 
860
                           " passwords from mandos server" };
911
861
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
912
862
      if (ret == ARGP_ERR_UNKNOWN){
913
863
        fprintf(stderr, "Unknown error while parsing arguments\n");
915
865
        goto end;
916
866
      }
917
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
    }
918
891
    
919
892
    /* If the interface is down, bring it up */
920
893
    {
924
897
        exitcode = EXIT_FAILURE;
925
898
        goto end;
926
899
      }
927
 
      strcpy(network.ifr_name, interface);
 
900
      strcpy(network.ifr_name, interface); /* Spurious warning */
928
901
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
929
902
      if(ret == -1){
930
903
        perror("ioctl SIOCGIFFLAGS");
940
913
          goto end;
941
914
        }
942
915
      }
943
 
      ret = TEMP_FAILURE_RETRY(close(sd));
944
 
      if(ret == -1){
945
 
        perror("close");
946
 
      }
 
916
      close(sd);
947
917
    }
948
918
    
949
919
    uid = getuid();
959
929
      perror("setgid");
960
930
    }
961
931
    
962
 
    ret = init_gnutls_global(&mc, pubkey, seckey);
963
 
    if (ret == -1){
964
 
      fprintf(stderr, "init_gnutls_global failed\n");
965
 
      exitcode = EXIT_FAILURE;
966
 
      goto end;
967
 
    } else {
968
 
      gnutls_initalized = true;
969
 
    }
970
 
    
971
 
    if(mkdtemp(tempdir) == NULL){
972
 
      perror("mkdtemp");
973
 
      tempdir[0] = '\0';
974
 
      goto end;
975
 
    }
976
 
    
977
 
    if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
978
 
      fprintf(stderr, "gpgme_initalized failed\n");
979
 
      exitcode = EXIT_FAILURE;
980
 
      goto end;
981
 
    } else {
982
 
      gpgme_initalized = true;
983
 
    }
984
 
    
985
932
    if_index = (AvahiIfIndex) if_nametoindex(interface);
986
933
    if(if_index == 0){
987
934
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1030
977
        exitcode = EXIT_FAILURE;
1031
978
        goto end;
1032
979
    }
1033
 
    
 
980
 
1034
981
    {
1035
982
      AvahiServerConfig config;
1036
983
      /* Do not publish any local Zeroconf records */
1039
986
      config.publish_addresses = 0;
1040
987
      config.publish_workstation = 0;
1041
988
      config.publish_domain = 0;
1042
 
      
 
989
 
1043
990
      /* Allocate a new server */
1044
991
      mc.server = avahi_server_new(avahi_simple_poll_get
1045
992
                                   (mc.simple_poll), &config, NULL,
1046
993
                                   NULL, &error);
1047
 
      
 
994
    
1048
995
      /* Free the Avahi configuration data */
1049
996
      avahi_server_config_free(&config);
1050
997
    }
1070
1017
    }
1071
1018
    
1072
1019
    /* Run the main loop */
1073
 
    
 
1020
 
1074
1021
    if (debug){
1075
1022
      fprintf(stderr, "Starting Avahi loop search\n");
1076
1023
    }
1078
1025
    avahi_simple_poll_loop(mc.simple_poll);
1079
1026
    
1080
1027
 end:
1081
 
    
 
1028
 
1082
1029
    if (debug){
1083
1030
      fprintf(stderr, "%s exiting\n", argv[0]);
1084
1031
    }
1089
1036
    
1090
1037
    if (mc.server != NULL)
1091
1038
        avahi_server_free(mc.server);
1092
 
    
 
1039
 
1093
1040
    if (mc.simple_poll != NULL)
1094
1041
        avahi_simple_poll_free(mc.simple_poll);
1095
 
    
 
1042
    free(pubkeyfilename);
 
1043
    free(seckeyfilename);
 
1044
 
1096
1045
    if (gnutls_initalized){
1097
1046
      gnutls_certificate_free_credentials(mc.cred);
1098
1047
      gnutls_global_deinit ();
1099
 
      gnutls_dh_params_deinit(mc.dh_params);
1100
 
    }
1101
 
    
1102
 
    if(gpgme_initalized){
1103
 
      gpgme_release(mc.ctx);
1104
 
    }
1105
 
    
1106
 
    /* Removes the temp directory used by GPGME */
1107
 
    if(tempdir[0] != '\0'){
1108
 
      DIR *d;
1109
 
      struct dirent *direntry;
1110
 
      d = opendir(tempdir);
1111
 
      if(d == NULL){
1112
 
        perror("opendir");
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){
1139
 
        perror("rmdir");
1140
 
      }
1141
 
    }
1142
 
          
 
1048
    }
 
1049
    
1143
1050
    return exitcode;
1144
1051
}