/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/mandos-client.c

  • Committer: Teddy Hogeborn
  • Date: 2008-12-10 01:26:02 UTC
  • mfrom: (237.1.2 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20081210012602-vhz3h75xkj24t340
First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

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 © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
12
 * Copyright © 2008 Teddy Hogeborn
 
13
 * Copyright © 2008 Björn Påhlsson
13
14
 * 
14
15
 * This program is free software: you can redistribute it and/or
15
16
 * modify it under the terms of the GNU General Public License as
47
48
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
48
49
                                   sockaddr_in6, PF_INET6,
49
50
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
50
 
                                   uid_t, gid_t */
51
 
#include <inttypes.h>           /* PRIu16 */
 
51
                                   uid_t, gid_t, open(), opendir(), DIR */
 
52
#include <sys/stat.h>           /* open() */
52
53
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
53
54
                                   struct in6_addr, inet_pton(),
54
55
                                   connect() */
 
56
#include <fcntl.h>              /* open() */
 
57
#include <dirent.h>             /* opendir(), struct dirent, readdir() */
 
58
#include <inttypes.h>           /* PRIu16 */
55
59
#include <assert.h>             /* assert() */
56
60
#include <errno.h>              /* perror(), errno */
57
61
#include <time.h>               /* time() */
58
62
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
59
63
                                   SIOCSIFFLAGS, if_indextoname(),
60
64
                                   if_nametoindex(), IF_NAMESIZE */
 
65
#include <netinet/in.h>
61
66
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
62
67
                                   getuid(), getgid(), setuid(),
63
68
                                   setgid() */
64
 
#include <netinet/in.h>
65
69
#include <arpa/inet.h>          /* inet_pton(), htons */
66
70
#include <iso646.h>             /* not, and */
67
71
#include <argp.h>               /* struct argp_option, error_t, struct
98
102
 
99
103
#define BUFFER_SIZE 256
100
104
 
 
105
#define PATHDIR "/conf/conf.d/mandos"
 
106
#define SECKEY "seckey.txt"
 
107
#define PUBKEY "pubkey.txt"
 
108
 
101
109
bool debug = false;
102
 
static const char *keydir = "/conf/conf.d/mandos";
103
110
static const char mandos_protocol_version[] = "1";
104
 
const char *argp_program_version = "password-request 1.0";
 
111
const char *argp_program_version = "mandos-client " VERSION;
105
112
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
106
113
 
107
114
/* Used for passing in values through the Avahi callback functions */
112
119
  unsigned int dh_bits;
113
120
  gnutls_dh_params_t dh_params;
114
121
  const char *priority;
 
122
  gpgme_ctx_t ctx;
115
123
} mandos_context;
116
124
 
117
125
/*
132
140
}
133
141
 
134
142
/* 
135
 
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
136
 
 * Returns -1 on error
 
143
 * Initialize GPGME.
137
144
 */
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;
 
145
static bool init_gpgme(mandos_context *mc, const char *seckey,
 
146
                       const char *pubkey, const char *tempdir){
 
147
  int ret;
144
148
  gpgme_error_t rc;
145
 
  ssize_t ret;
146
 
  size_t plaintext_capacity = 0;
147
 
  ssize_t plaintext_length = 0;
148
149
  gpgme_engine_info_t engine_info;
149
150
  
 
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
  
150
187
  if (debug){
151
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
188
    fprintf(stderr, "Initialize gpgme\n");
152
189
  }
153
190
  
154
191
  /* Init GPGME */
157
194
  if (rc != GPG_ERR_NO_ERROR){
158
195
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
159
196
            gpgme_strsource(rc), gpgme_strerror(rc));
160
 
    return -1;
 
197
    return false;
161
198
  }
162
199
  
163
 
  /* Set GPGME home directory for the OpenPGP engine only */
 
200
    /* Set GPGME home directory for the OpenPGP engine only */
164
201
  rc = gpgme_get_engine_info (&engine_info);
165
202
  if (rc != GPG_ERR_NO_ERROR){
166
203
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
167
204
            gpgme_strsource(rc), gpgme_strerror(rc));
168
 
    return -1;
 
205
    return false;
169
206
  }
170
207
  while(engine_info != NULL){
171
208
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
172
209
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
173
 
                            engine_info->file_name, homedir);
 
210
                            engine_info->file_name, tempdir);
174
211
      break;
175
212
    }
176
213
    engine_info = engine_info->next;
177
214
  }
178
215
  if(engine_info == NULL){
179
 
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
180
 
    return -1;
 
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");
181
251
  }
182
252
  
183
253
  /* Create new GPGME data buffer from memory cryptotext */
198
268
    return -1;
199
269
  }
200
270
  
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
 
  
210
271
  /* Decrypt data from the cryptotext data buffer to the plaintext
211
272
     data buffer */
212
 
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
 
273
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
213
274
  if (rc != GPG_ERR_NO_ERROR){
214
275
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
215
276
            gpgme_strsource(rc), gpgme_strerror(rc));
216
277
    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
    }
217
306
    goto decrypt_end;
218
307
  }
219
308
  
221
310
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
222
311
  }
223
312
  
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
 
  
253
313
  /* Seek back to the beginning of the GPGME plaintext data buffer */
254
314
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
255
 
    perror("pgpme_data_seek");
 
315
    perror("gpgme_data_seek");
256
316
    plaintext_length = -1;
257
317
    goto decrypt_end;
258
318
  }
282
342
    }
283
343
    plaintext_length += ret;
284
344
  }
285
 
 
 
345
  
286
346
  if(debug){
287
347
    fprintf(stderr, "Decrypted password is: ");
288
348
    for(ssize_t i = 0; i < plaintext_length; i++){
302
362
}
303
363
 
304
364
static const char * safer_gnutls_strerror (int value) {
305
 
  const char *ret = gnutls_strerror (value);
 
365
  const char *ret = gnutls_strerror (value); /* Spurious warning */
306
366
  if (ret == NULL)
307
367
    ret = "(unknown)";
308
368
  return ret;
341
401
  /* OpenPGP credentials */
342
402
  gnutls_certificate_allocate_credentials(&mc->cred);
343
403
  if (ret != GNUTLS_E_SUCCESS){
344
 
    fprintf (stderr, "GnuTLS memory error: %s\n",
 
404
    fprintf (stderr, "GnuTLS memory error: %s\n", /* Spurious
 
405
                                                     warning */
345
406
             safer_gnutls_strerror(ret));
346
407
    gnutls_global_deinit ();
347
408
    return -1;
348
409
  }
349
410
  
350
411
  if(debug){
351
 
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
352
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
 
412
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
 
413
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
353
414
            seckeyfilename);
354
415
  }
355
416
  
360
421
    fprintf(stderr,
361
422
            "Error[%d] while reading the OpenPGP key pair ('%s',"
362
423
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
363
 
    fprintf(stdout, "The GnuTLS error is: %s\n",
 
424
    fprintf(stderr, "The GnuTLS error is: %s\n",
364
425
            safer_gnutls_strerror(ret));
365
426
    goto globalfail;
366
427
  }
380
441
  }
381
442
  
382
443
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
383
 
 
 
444
  
384
445
  return 0;
385
 
 
 
446
  
386
447
 globalfail:
387
 
 
 
448
  
388
449
  gnutls_certificate_free_credentials(mc->cred);
389
450
  gnutls_global_deinit();
 
451
  gnutls_dh_params_deinit(mc->dh_params);
390
452
  return -1;
391
 
 
392
453
}
393
454
 
394
455
static int init_gnutls_session(mandos_context *mc,
466
527
    perror("socket");
467
528
    return -1;
468
529
  }
469
 
 
 
530
  
470
531
  if(debug){
471
532
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
472
533
      perror("if_indextoname");
475
536
    fprintf(stderr, "Binding to interface %s\n", interface);
476
537
  }
477
538
  
478
 
  memset(&to, 0, sizeof(to));   /* Spurious warning */
 
539
  memset(&to, 0, sizeof(to));
479
540
  to.in6.sin6_family = AF_INET6;
480
541
  /* It would be nice to have a way to detect if we were passed an
481
542
     IPv4 address here.   Now we assume an IPv6 address. */
511
572
    perror("connect");
512
573
    return -1;
513
574
  }
514
 
 
 
575
  
515
576
  const char *out = mandos_protocol_version;
516
577
  written = 0;
517
578
  while (true){
535
596
      }
536
597
    }
537
598
  }
538
 
 
 
599
  
539
600
  if(debug){
540
601
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
541
602
  }
542
603
  
543
604
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
544
 
 
 
605
  
545
606
  do{
546
607
    ret = gnutls_handshake (session);
547
608
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
561
622
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
562
623
            ip);
563
624
  }
564
 
 
 
625
  
565
626
  while(true){
566
627
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
567
628
                                   buffer_capacity);
611
672
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
612
673
  
613
674
  if (buffer_length > 0){
614
 
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
675
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
615
676
                                               buffer_length,
616
 
                                               &decrypted_buffer,
617
 
                                               keydir);
 
677
                                               &decrypted_buffer);
618
678
    if (decrypted_buffer_size >= 0){
619
679
      written = 0;
620
680
      while(written < (size_t) decrypted_buffer_size){
635
695
    } else {
636
696
      retval = -1;
637
697
    }
 
698
  } else {
 
699
    retval = -1;
638
700
  }
639
701
  
640
702
  /* Shutdown procedure */
641
703
  
642
704
 mandos_end:
643
705
  free(buffer);
644
 
  close(tcp_sd);
 
706
  ret = TEMP_FAILURE_RETRY(close(tcp_sd));
 
707
  if(ret == -1){
 
708
    perror("close");
 
709
  }
645
710
  gnutls_deinit (session);
646
711
  return retval;
647
712
}
661
726
                             flags,
662
727
                             void* userdata) {
663
728
  mandos_context *mc = userdata;
664
 
  assert(r);                    /* Spurious warning */
 
729
  assert(r);
665
730
  
666
731
  /* Called whenever a service has been resolved successfully or
667
732
     timed out */
703
768
                             flags,
704
769
                             void* userdata) {
705
770
  mandos_context *mc = userdata;
706
 
  assert(b);                    /* Spurious warning */
 
771
  assert(b);
707
772
  
708
773
  /* Called whenever a new services becomes available on the LAN or
709
774
     is removed from the LAN */
743
808
  }
744
809
}
745
810
 
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
 
 
758
811
int main(int argc, char *argv[]){
759
812
    AvahiSServiceBrowser *sb = NULL;
760
813
    int error;
766
819
    uid_t uid;
767
820
    gid_t gid;
768
821
    char *connect_to = NULL;
 
822
    char tempdir[] = "/tmp/mandosXXXXXX";
769
823
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
770
 
    char *pubkeyfilename = NULL;
771
 
    char *seckeyfilename = NULL;
772
 
    const char *pubkeyname = "pubkey.txt";
773
 
    const char *seckeyname = "seckey.txt";
 
824
    const char *seckey = PATHDIR "/" SECKEY;
 
825
    const char *pubkey = PATHDIR "/" PUBKEY;
 
826
    
774
827
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
775
 
                          .dh_bits = 1024, .priority = "SECURE256"};
 
828
                          .dh_bits = 1024, .priority = "SECURE256"
 
829
                          ":!CTYPE-X.509:+CTYPE-OPENPGP" };
776
830
    bool gnutls_initalized = false;
 
831
    bool gpgme_initalized = false;
777
832
    
778
833
    {
779
834
      struct argp_option options[] = {
780
835
        { .name = "debug", .key = 128,
781
836
          .doc = "Debug mode", .group = 3 },
782
837
        { .name = "connect", .key = 'c',
783
 
          .arg = "IP",
784
 
          .doc = "Connect directly to a sepcified mandos server",
 
838
          .arg = "ADDRESS:PORT",
 
839
          .doc = "Connect directly to a specific Mandos server",
785
840
          .group = 1 },
786
841
        { .name = "interface", .key = 'i',
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",
 
842
          .arg = "NAME",
 
843
          .doc = "Interface that will be used to search for Mandos"
 
844
          " servers",
793
845
          .group = 1 },
794
846
        { .name = "seckey", .key = 's',
795
 
          .arg = "SECKEY",
796
 
          .doc = "Secret openpgp key for gnutls authentication",
 
847
          .arg = "FILE",
 
848
          .doc = "OpenPGP secret key file base name",
797
849
          .group = 1 },
798
850
        { .name = "pubkey", .key = 'p',
799
 
          .arg = "PUBKEY",
800
 
          .doc = "Public openpgp key for gnutls authentication",
 
851
          .arg = "FILE",
 
852
          .doc = "OpenPGP public key file base name",
801
853
          .group = 2 },
802
854
        { .name = "dh-bits", .key = 129,
803
855
          .arg = "BITS",
804
 
          .doc = "dh-bits to use in gnutls communication",
 
856
          .doc = "Bit length of the prime number used in the"
 
857
          " Diffie-Hellman key exchange",
805
858
          .group = 2 },
806
859
        { .name = "priority", .key = 130,
807
 
          .arg = "PRIORITY",
808
 
          .doc = "GNUTLS priority", .group = 1 },
 
860
          .arg = "STRING",
 
861
          .doc = "GnuTLS priority string for the TLS handshake",
 
862
          .group = 1 },
809
863
        { .name = NULL }
810
864
      };
811
 
 
812
865
      
813
866
      error_t parse_opt (int key, char *arg,
814
867
                         struct argp_state *state) {
815
868
        /* Get the INPUT argument from `argp_parse', which we know is
816
869
           a pointer to our plugin list pointer. */
817
870
        switch (key) {
818
 
        case 128:
 
871
        case 128:               /* --debug */
819
872
          debug = true;
820
873
          break;
821
 
        case 'c':
 
874
        case 'c':               /* --connect */
822
875
          connect_to = arg;
823
876
          break;
824
 
        case 'i':
 
877
        case 'i':               /* --interface */
825
878
          interface = arg;
826
879
          break;
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:
 
880
        case 's':               /* --seckey */
 
881
          seckey = arg;
 
882
          break;
 
883
        case 'p':               /* --pubkey */
 
884
          pubkey = arg;
 
885
          break;
 
886
        case 129:               /* --dh-bits */
837
887
          errno = 0;
838
888
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
839
889
          if (errno){
841
891
            exit(EXIT_FAILURE);
842
892
          }
843
893
          break;
844
 
        case 130:
 
894
        case 130:               /* --priority */
845
895
          mc.priority = arg;
846
896
          break;
847
897
        case ARGP_KEY_ARG:
853
903
        }
854
904
        return 0;
855
905
      }
856
 
 
 
906
      
857
907
      struct argp argp = { .options = options, .parser = parse_opt,
858
908
                           .args_doc = "",
859
909
                           .doc = "Mandos client -- Get and decrypt"
860
 
                           " passwords from mandos server" };
 
910
                           " passwords from a Mandos server" };
861
911
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
862
912
      if (ret == ARGP_ERR_UNKNOWN){
863
913
        fprintf(stderr, "Unknown error while parsing arguments\n");
865
915
        goto end;
866
916
      }
867
917
    }
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
 
    }
891
918
    
892
919
    /* If the interface is down, bring it up */
893
920
    {
897
924
        exitcode = EXIT_FAILURE;
898
925
        goto end;
899
926
      }
900
 
      strcpy(network.ifr_name, interface); /* Spurious warning */
 
927
      strcpy(network.ifr_name, interface);
901
928
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
902
929
      if(ret == -1){
903
930
        perror("ioctl SIOCGIFFLAGS");
913
940
          goto end;
914
941
        }
915
942
      }
916
 
      close(sd);
 
943
      ret = TEMP_FAILURE_RETRY(close(sd));
 
944
      if(ret == -1){
 
945
        perror("close");
 
946
      }
917
947
    }
918
948
    
919
949
    uid = getuid();
929
959
      perror("setgid");
930
960
    }
931
961
    
 
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
    
932
985
    if_index = (AvahiIfIndex) if_nametoindex(interface);
933
986
    if(if_index == 0){
934
987
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
977
1030
        exitcode = EXIT_FAILURE;
978
1031
        goto end;
979
1032
    }
980
 
 
 
1033
    
981
1034
    {
982
1035
      AvahiServerConfig config;
983
1036
      /* Do not publish any local Zeroconf records */
986
1039
      config.publish_addresses = 0;
987
1040
      config.publish_workstation = 0;
988
1041
      config.publish_domain = 0;
989
 
 
 
1042
      
990
1043
      /* Allocate a new server */
991
1044
      mc.server = avahi_server_new(avahi_simple_poll_get
992
1045
                                   (mc.simple_poll), &config, NULL,
993
1046
                                   NULL, &error);
994
 
    
 
1047
      
995
1048
      /* Free the Avahi configuration data */
996
1049
      avahi_server_config_free(&config);
997
1050
    }
1017
1070
    }
1018
1071
    
1019
1072
    /* Run the main loop */
1020
 
 
 
1073
    
1021
1074
    if (debug){
1022
1075
      fprintf(stderr, "Starting Avahi loop search\n");
1023
1076
    }
1025
1078
    avahi_simple_poll_loop(mc.simple_poll);
1026
1079
    
1027
1080
 end:
1028
 
 
 
1081
    
1029
1082
    if (debug){
1030
1083
      fprintf(stderr, "%s exiting\n", argv[0]);
1031
1084
    }
1036
1089
    
1037
1090
    if (mc.server != NULL)
1038
1091
        avahi_server_free(mc.server);
1039
 
 
 
1092
    
1040
1093
    if (mc.simple_poll != NULL)
1041
1094
        avahi_simple_poll_free(mc.simple_poll);
1042
 
    free(pubkeyfilename);
1043
 
    free(seckeyfilename);
1044
 
 
 
1095
    
1045
1096
    if (gnutls_initalized){
1046
1097
      gnutls_certificate_free_credentials(mc.cred);
1047
1098
      gnutls_global_deinit ();
1048
 
    }
1049
 
    
 
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
          
1050
1143
    return exitcode;
1051
1144
}