/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/mandosclient.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-03 01:09:36 UTC
  • mfrom: (24.1.9 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080803010936-ujme8tgxceszfbi1
* plugbasedclient.c (main): New "--userid" and "--groupid" options.
                            Take an additional non-option argument and
                            parse it as a plus-separated and -prefixed
                            list of additional options.

* plugins.d/mandosclient.c (DH_BITS): Replaced with
                                      "mandos_context.dh_bits".  All
                                      users changed.
  (certdir): Renamed to "keydir".  All users changed.
  (certfile): Renamed to "pubkeyfile".  All users changed.
  (certkey): Renamed to "seckeyfile".  All users changed.
  (encrypted_session): Replaced with "mandos_context".  All users
                       changed.
  (initgnutls): Take additional "session" and "dh_params" arguments.
                All callers changed.
  (start_mandos_communication): Take additional "mc" argument.  All
                                callers changed.  Print target IPv6
                                address if different than supplied
                                string.
  (simple_poll) Replaced with "mandos_context.simple_poll".  All users
                changed.
  (server): Replaced with "mandos_context.server".  All users changed.
  (main): Default interface to "eth0".  Rename "--certdir" to
          "--keydir", "--certkey" to "--seckey", and "--certfile" to
          "--pubkey".  New options "--dh-bits" and "--priority".  If
          the interface is not up, bring it up.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
 * along with this program.  If not, see
26
26
 * <http://www.gnu.org/licenses/>.
27
27
 * 
28
 
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
29
 
 * <https://www.fukt.bsnet.se/~teddy/>.
 
28
 * Contact the authors at <mandos@fukt.bsnet.se>.
30
29
 */
31
30
 
32
31
/* Needed by GPGME, specifically gpgme_data_seek() */
38
37
#include <stdlib.h>
39
38
#include <time.h>
40
39
#include <net/if.h>             /* if_nametoindex */
 
40
#include <sys/ioctl.h>          // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
 
41
#include <net/if.h>             // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
41
42
 
42
43
#include <avahi-core/core.h>
43
44
#include <avahi-core/lookup.h>
64
65
#include <errno.h>              /* perror() */
65
66
#include <gpgme.h>
66
67
 
67
 
// getopt long
 
68
// getopt_long
68
69
#include <getopt.h>
69
70
 
70
 
#ifndef CERT_ROOT
71
 
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
72
 
#endif
73
 
#define CERTFILE CERT_ROOT "openpgp-client.txt"
74
 
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
75
71
#define BUFFER_SIZE 256
76
 
#define DH_BITS 1024
 
72
 
 
73
static const char *keydir = "/conf/conf.d/mandos";
 
74
static const char *pubkeyfile = "pubkey.txt";
 
75
static const char *seckeyfile = "seckey.txt";
77
76
 
78
77
bool debug = false;
79
78
 
 
79
/* Used for passing in values through all the callback functions */
80
80
typedef struct {
81
 
  gnutls_session_t session;
 
81
  AvahiSimplePoll *simple_poll;
 
82
  AvahiServer *server;
82
83
  gnutls_certificate_credentials_t cred;
83
 
  gnutls_dh_params_t dh_params;
84
 
} encrypted_session;
85
 
 
86
 
 
87
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
 
                            char **new_packet, const char *homedir){
 
84
  unsigned int dh_bits;
 
85
  const char *priority;
 
86
} mandos_context;
 
87
 
 
88
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
89
                                   char **new_packet,
 
90
                                   const char *homedir){
89
91
  gpgme_data_t dh_crypto, dh_plain;
90
92
  gpgme_ctx_t ctx;
91
93
  gpgme_error_t rc;
100
102
  
101
103
  /* Init GPGME */
102
104
  gpgme_check_version(NULL);
103
 
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
105
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
106
  if (rc != GPG_ERR_NO_ERROR){
 
107
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
 
108
            gpgme_strsource(rc), gpgme_strerror(rc));
 
109
    return -1;
 
110
  }
104
111
  
105
112
  /* Set GPGME home directory */
106
113
  rc = gpgme_get_engine_info (&engine_info);
192
199
  gpgme_data_release(dh_crypto);
193
200
  
194
201
  /* Seek back to the beginning of the GPGME plaintext data buffer */
195
 
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
196
 
 
 
202
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
 
203
    perror("pgpme_data_seek");
 
204
  }
 
205
  
197
206
  *new_packet = 0;
198
207
  while(true){
199
208
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
240
249
  return ret;
241
250
}
242
251
 
243
 
void debuggnutls(__attribute__((unused)) int level,
244
 
                 const char* string){
 
252
static void debuggnutls(__attribute__((unused)) int level,
 
253
                        const char* string){
245
254
  fprintf(stderr, "%s", string);
246
255
}
247
256
 
248
 
int initgnutls(encrypted_session *es){
 
257
static int initgnutls(mandos_context *mc, gnutls_session_t *session,
 
258
                      gnutls_dh_params_t *dh_params){
249
259
  const char *err;
250
260
  int ret;
251
261
  
252
262
  if(debug){
253
263
    fprintf(stderr, "Initializing GnuTLS\n");
254
264
  }
255
 
  
 
265
 
256
266
  if ((ret = gnutls_global_init ())
257
267
      != GNUTLS_E_SUCCESS) {
258
268
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
259
269
    return -1;
260
270
  }
261
 
 
 
271
  
262
272
  if (debug){
263
273
    gnutls_global_set_log_level(11);
264
274
    gnutls_global_set_log_function(debuggnutls);
265
275
  }
266
276
  
267
277
  /* openpgp credentials */
268
 
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
 
278
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
269
279
      != GNUTLS_E_SUCCESS) {
270
280
    fprintf (stderr, "memory error: %s\n",
271
281
             safer_gnutls_strerror(ret));
274
284
  
275
285
  if(debug){
276
286
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
277
 
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
278
 
            KEYFILE);
 
287
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
 
288
            seckeyfile);
279
289
  }
280
290
  
281
291
  ret = gnutls_certificate_set_openpgp_key_file
282
 
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
 
292
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
283
293
  if (ret != GNUTLS_E_SUCCESS) {
284
294
    fprintf
285
295
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
286
296
       " '%s')\n",
287
 
       ret, CERTFILE, KEYFILE);
 
297
       ret, pubkeyfile, seckeyfile);
288
298
    fprintf(stdout, "The Error is: %s\n",
289
299
            safer_gnutls_strerror(ret));
290
300
    return -1;
291
301
  }
292
302
  
293
303
  //GnuTLS server initialization
294
 
  if ((ret = gnutls_dh_params_init (&es->dh_params))
 
304
  if ((ret = gnutls_dh_params_init(dh_params))
295
305
      != GNUTLS_E_SUCCESS) {
296
306
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
297
307
             safer_gnutls_strerror(ret));
298
308
    return -1;
299
309
  }
300
310
  
301
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
 
311
  if ((ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits))
302
312
      != GNUTLS_E_SUCCESS) {
303
313
    fprintf (stderr, "Error in prime generation: %s\n",
304
314
             safer_gnutls_strerror(ret));
305
315
    return -1;
306
316
  }
307
317
  
308
 
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
 
318
  gnutls_certificate_set_dh_params(mc->cred, *dh_params);
309
319
  
310
320
  // GnuTLS session creation
311
 
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
 
321
  if ((ret = gnutls_init(session, GNUTLS_SERVER))
312
322
      != GNUTLS_E_SUCCESS){
313
323
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
314
324
            safer_gnutls_strerror(ret));
315
325
  }
316
326
  
317
 
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
 
327
  if ((ret = gnutls_priority_set_direct(*session, mc->priority, &err))
318
328
      != GNUTLS_E_SUCCESS) {
319
329
    fprintf(stderr, "Syntax error at: %s\n", err);
320
330
    fprintf(stderr, "GnuTLS error: %s\n",
322
332
    return -1;
323
333
  }
324
334
  
325
 
  if ((ret = gnutls_credentials_set
326
 
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
 
335
  if ((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
336
                                    mc->cred))
327
337
      != GNUTLS_E_SUCCESS) {
328
338
    fprintf(stderr, "Error setting a credentials set: %s\n",
329
339
            safer_gnutls_strerror(ret));
331
341
  }
332
342
  
333
343
  /* ignore client certificate if any. */
334
 
  gnutls_certificate_server_set_request (es->session,
 
344
  gnutls_certificate_server_set_request (*session,
335
345
                                         GNUTLS_CERT_IGNORE);
336
346
  
337
 
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
 
347
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
338
348
  
339
349
  return 0;
340
350
}
341
351
 
342
 
void empty_log(__attribute__((unused)) AvahiLogLevel level,
343
 
               __attribute__((unused)) const char *txt){}
 
352
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
353
                      __attribute__((unused)) const char *txt){}
344
354
 
345
 
int start_mandos_communication(const char *ip, uint16_t port,
346
 
                               AvahiIfIndex if_index){
 
355
static int start_mandos_communication(const char *ip, uint16_t port,
 
356
                                      AvahiIfIndex if_index,
 
357
                                      mandos_context *mc){
347
358
  int ret, tcp_sd;
348
359
  struct sockaddr_in6 to;
349
 
  encrypted_session es;
350
360
  char *buffer = NULL;
351
361
  char *decrypted_buffer;
352
362
  size_t buffer_length = 0;
355
365
  size_t written = 0;
356
366
  int retval = 0;
357
367
  char interface[IF_NAMESIZE];
 
368
  gnutls_session_t session;
 
369
  gnutls_dh_params_t dh_params;
358
370
  
359
371
  if(debug){
360
372
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
366
378
    perror("socket");
367
379
    return -1;
368
380
  }
369
 
  
370
 
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
371
 
    if(debug){
 
381
 
 
382
  if(debug){
 
383
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
372
384
      perror("if_indextoname");
 
385
      return -1;
373
386
    }
374
 
    return -1;
375
 
  }
376
 
  
377
 
  if(debug){
378
387
    fprintf(stderr, "Binding to interface %s\n", interface);
379
388
  }
380
389
  
384
393
  if (ret < 0 ){
385
394
    perror("inet_pton");
386
395
    return -1;
387
 
  }  
 
396
  }
388
397
  if(ret == 0){
389
398
    fprintf(stderr, "Bad address: %s\n", ip);
390
399
    return -1;
395
404
  
396
405
  if(debug){
397
406
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
398
 
/*     char addrstr[INET6_ADDRSTRLEN]; */
399
 
/*     if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
400
 
/*               sizeof(addrstr)) == NULL){ */
401
 
/*       perror("inet_ntop"); */
402
 
/*     } else { */
403
 
/*       fprintf(stderr, "Really connecting to: %s, port %d\n", */
404
 
/*            addrstr, ntohs(to.sin6_port)); */
405
 
/*     } */
 
407
    char addrstr[INET6_ADDRSTRLEN] = "";
 
408
    if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
 
409
                 sizeof(addrstr)) == NULL){
 
410
      perror("inet_ntop");
 
411
    } else {
 
412
      if(strcmp(addrstr, ip) != 0){
 
413
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
 
414
      }
 
415
    }
406
416
  }
407
417
  
408
418
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
411
421
    return -1;
412
422
  }
413
423
  
414
 
  ret = initgnutls (&es);
 
424
  ret = initgnutls (mc, &session, &dh_params);
415
425
  if (ret != 0){
416
426
    retval = -1;
417
427
    return -1;
418
428
  }
419
429
  
420
 
  gnutls_transport_set_ptr (es.session,
421
 
                            (gnutls_transport_ptr_t) tcp_sd);
 
430
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
422
431
  
423
432
  if(debug){
424
433
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
425
434
  }
426
435
  
427
 
  ret = gnutls_handshake (es.session);
 
436
  ret = gnutls_handshake (session);
428
437
  
429
438
  if (ret != GNUTLS_E_SUCCESS){
430
439
    if(debug){
452
461
      buffer_capacity += BUFFER_SIZE;
453
462
    }
454
463
    
455
 
    ret = gnutls_record_recv
456
 
      (es.session, buffer+buffer_length, BUFFER_SIZE);
 
464
    ret = gnutls_record_recv(session, buffer+buffer_length,
 
465
                             BUFFER_SIZE);
457
466
    if (ret == 0){
458
467
      break;
459
468
    }
463
472
      case GNUTLS_E_AGAIN:
464
473
        break;
465
474
      case GNUTLS_E_REHANDSHAKE:
466
 
        ret = gnutls_handshake (es.session);
 
475
        ret = gnutls_handshake (session);
467
476
        if (ret < 0){
468
477
          fprintf(stderr, "\n*** Handshake failed ***\n");
469
478
          gnutls_perror (ret);
475
484
        fprintf(stderr, "Unknown error while reading data from"
476
485
                " encrypted session with mandos server\n");
477
486
        retval = -1;
478
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
487
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
479
488
        goto exit;
480
489
      }
481
490
    } else {
487
496
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
488
497
                                               buffer_length,
489
498
                                               &decrypted_buffer,
490
 
                                               CERT_ROOT);
 
499
                                               keydir);
491
500
    if (decrypted_buffer_size >= 0){
492
501
      while(written < (size_t) decrypted_buffer_size){
493
502
        ret = (int)fwrite (decrypted_buffer + written, 1,
516
525
  }
517
526
 
518
527
  free(buffer);
519
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
528
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
520
529
 exit:
521
530
  close(tcp_sd);
522
 
  gnutls_deinit (es.session);
523
 
  gnutls_certificate_free_credentials (es.cred);
 
531
  gnutls_deinit (session);
 
532
  gnutls_certificate_free_credentials (mc->cred);
524
533
  gnutls_global_deinit ();
525
534
  return retval;
526
535
}
527
536
 
528
 
static AvahiSimplePoll *simple_poll = NULL;
529
 
static AvahiServer *server = NULL;
530
 
 
531
 
static void resolve_callback(
532
 
    AvahiSServiceResolver *r,
533
 
    AvahiIfIndex interface,
534
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
535
 
    AvahiResolverEvent event,
536
 
    const char *name,
537
 
    const char *type,
538
 
    const char *domain,
539
 
    const char *host_name,
540
 
    const AvahiAddress *address,
541
 
    uint16_t port,
542
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
543
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
544
 
    AVAHI_GCC_UNUSED void* userdata) {
545
 
    
 
537
static void resolve_callback( AvahiSServiceResolver *r,
 
538
                              AvahiIfIndex interface,
 
539
                              AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
540
                              AvahiResolverEvent event,
 
541
                              const char *name,
 
542
                              const char *type,
 
543
                              const char *domain,
 
544
                              const char *host_name,
 
545
                              const AvahiAddress *address,
 
546
                              uint16_t port,
 
547
                              AVAHI_GCC_UNUSED AvahiStringList *txt,
 
548
                              AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
549
                              void* userdata) {
 
550
  mandos_context *mc = userdata;
546
551
  assert(r);                    /* Spurious warning */
547
552
  
548
553
  /* Called whenever a service has been resolved successfully or
553
558
  case AVAHI_RESOLVER_FAILURE:
554
559
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
555
560
            " type '%s' in domain '%s': %s\n", name, type, domain,
556
 
            avahi_strerror(avahi_server_errno(server)));
 
561
            avahi_strerror(avahi_server_errno(mc->server)));
557
562
    break;
558
563
    
559
564
  case AVAHI_RESOLVER_FOUND:
564
569
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
565
570
                " port %d\n", name, host_name, ip, port);
566
571
      }
567
 
      int ret = start_mandos_communication(ip, port, interface);
 
572
      int ret = start_mandos_communication(ip, port, interface, mc);
568
573
      if (ret == 0){
569
574
        exit(EXIT_SUCCESS);
570
575
      }
573
578
  avahi_s_service_resolver_free(r);
574
579
}
575
580
 
576
 
static void browse_callback(
577
 
    AvahiSServiceBrowser *b,
578
 
    AvahiIfIndex interface,
579
 
    AvahiProtocol protocol,
580
 
    AvahiBrowserEvent event,
581
 
    const char *name,
582
 
    const char *type,
583
 
    const char *domain,
584
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
585
 
    void* userdata) {
586
 
    
587
 
    AvahiServer *s = userdata;
588
 
    assert(b);                  /* Spurious warning */
589
 
    
590
 
    /* Called whenever a new services becomes available on the LAN or
591
 
       is removed from the LAN */
592
 
    
593
 
    switch (event) {
594
 
    default:
595
 
    case AVAHI_BROWSER_FAILURE:
596
 
      
597
 
      fprintf(stderr, "(Browser) %s\n",
598
 
              avahi_strerror(avahi_server_errno(server)));
599
 
      avahi_simple_poll_quit(simple_poll);
600
 
      return;
601
 
      
602
 
    case AVAHI_BROWSER_NEW:
603
 
      /* We ignore the returned resolver object. In the callback
604
 
         function we free it. If the server is terminated before
605
 
         the callback function is called the server will free
606
 
         the resolver for us. */
607
 
      
608
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
609
 
                                         type, domain,
610
 
                                         AVAHI_PROTO_INET6, 0,
611
 
                                         resolve_callback, s)))
612
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
613
 
                avahi_strerror(avahi_server_errno(s)));
614
 
      break;
615
 
      
616
 
    case AVAHI_BROWSER_REMOVE:
617
 
      break;
618
 
      
619
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
620
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
621
 
      break;
622
 
    }
623
 
}
 
581
static void browse_callback( AvahiSServiceBrowser *b,
 
582
                             AvahiIfIndex interface,
 
583
                             AvahiProtocol protocol,
 
584
                             AvahiBrowserEvent event,
 
585
                             const char *name,
 
586
                             const char *type,
 
587
                             const char *domain,
 
588
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
589
                             void* userdata) {
 
590
  mandos_context *mc = userdata;
 
591
  assert(b);                    /* Spurious warning */
 
592
  
 
593
  /* Called whenever a new services becomes available on the LAN or
 
594
     is removed from the LAN */
 
595
  
 
596
  switch (event) {
 
597
  default:
 
598
  case AVAHI_BROWSER_FAILURE:
 
599
    
 
600
    fprintf(stderr, "(Browser) %s\n",
 
601
            avahi_strerror(avahi_server_errno(mc->server)));
 
602
    avahi_simple_poll_quit(mc->simple_poll);
 
603
    return;
 
604
    
 
605
  case AVAHI_BROWSER_NEW:
 
606
    /* We ignore the returned resolver object. In the callback
 
607
       function we free it. If the server is terminated before
 
608
       the callback function is called the server will free
 
609
       the resolver for us. */
 
610
    
 
611
    if (!(avahi_s_service_resolver_new(mc->server, interface, protocol, name,
 
612
                                       type, domain,
 
613
                                       AVAHI_PROTO_INET6, 0,
 
614
                                       resolve_callback, mc)))
 
615
      fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
 
616
              avahi_strerror(avahi_server_errno(mc->server)));
 
617
    break;
 
618
    
 
619
  case AVAHI_BROWSER_REMOVE:
 
620
    break;
 
621
    
 
622
  case AVAHI_BROWSER_ALL_FOR_NOW:
 
623
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
624
    break;
 
625
  }
 
626
}
 
627
 
 
628
/* Combines file name and path and returns the malloced new
 
629
   string. some sane checks could/should be added */
 
630
static const char *combinepath(const char *first, const char *second){
 
631
  size_t f_len = strlen(first);
 
632
  size_t s_len = strlen(second);
 
633
  char *tmp = malloc(f_len + s_len + 2);
 
634
  if (tmp == NULL){
 
635
    return NULL;
 
636
  }
 
637
  if(f_len > 0){
 
638
    memcpy(tmp, first, f_len);  /* Spurious warning */
 
639
  }
 
640
  tmp[f_len] = '/';
 
641
  if(s_len > 0){
 
642
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
 
643
  }
 
644
  tmp[f_len + 1 + s_len] = '\0';
 
645
  return tmp;
 
646
}
 
647
 
624
648
 
625
649
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
626
650
    AvahiServerConfig config;
627
651
    AvahiSServiceBrowser *sb = NULL;
628
652
    int error;
629
653
    int ret;
 
654
    int debug_int;
630
655
    int returncode = EXIT_SUCCESS;
631
 
    const char *interface = NULL;
 
656
    const char *interface = "eth0";
 
657
    struct ifreq network;
 
658
    int sd;
 
659
    char *connect_to = NULL;
632
660
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
633
 
    char *connect_to = NULL;
 
661
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
 
662
                          .dh_bits = 1024, .priority = "SECURE256"};
634
663
    
 
664
    debug_int = debug ? 1 : 0;
635
665
    while (true){
636
 
      static struct option long_options[] = {
637
 
        {"debug", no_argument, (int *)&debug, 1},
638
 
        {"connect", required_argument, 0, 'c'},
639
 
        {"interface", required_argument, 0, 'i'},
 
666
      struct option long_options[] = {
 
667
        {"debug", no_argument, &debug_int, 1},
 
668
        {"connect", required_argument, NULL, 'c'},
 
669
        {"interface", required_argument, NULL, 'i'},
 
670
        {"keydir", required_argument, NULL, 'd'},
 
671
        {"seckey", required_argument, NULL, 's'},
 
672
        {"pubkey", required_argument, NULL, 'p'},
 
673
        {"dh-bits", required_argument, NULL, 'D'},
 
674
        {"priority", required_argument, NULL, 'P'},
640
675
        {0, 0, 0, 0} };
641
676
      
642
677
      int option_index = 0;
656
691
      case 'c':
657
692
        connect_to = optarg;
658
693
        break;
 
694
      case 'd':
 
695
        keydir = optarg;
 
696
        break;
 
697
      case 'p':
 
698
        pubkeyfile = optarg;
 
699
        break;
 
700
      case 's':
 
701
        seckeyfile = optarg;
 
702
        break;
 
703
      case 'D':
 
704
        errno = 0;
 
705
        mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
 
706
        if (errno){
 
707
          perror("strtol");
 
708
          exit(EXIT_FAILURE);
 
709
        }
 
710
        break;
 
711
      case 'P':
 
712
        mc.priority = optarg;
 
713
        break;
 
714
      case '?':
659
715
      default:
660
716
        exit(EXIT_FAILURE);
661
717
      }
662
718
    }
663
 
    
664
 
    if(interface != NULL){
665
 
      if_index = (AvahiIfIndex) if_nametoindex(interface);
666
 
      if(if_index == 0){
667
 
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
668
 
        exit(EXIT_FAILURE);
669
 
      }
 
719
    debug = debug_int ? true : false;
 
720
    
 
721
    pubkeyfile = combinepath(keydir, pubkeyfile);
 
722
    if (pubkeyfile == NULL){
 
723
      perror("combinepath");
 
724
      returncode = EXIT_FAILURE;
 
725
      goto exit;
 
726
    }
 
727
    
 
728
    seckeyfile = combinepath(keydir, seckeyfile);
 
729
    if (seckeyfile == NULL){
 
730
      perror("combinepath");
 
731
      goto exit;
 
732
    }
 
733
    
 
734
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
735
    if(if_index == 0){
 
736
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
737
      exit(EXIT_FAILURE);
670
738
    }
671
739
    
672
740
    if(connect_to != NULL){
685
753
      }
686
754
      *address = '\0';
687
755
      address = connect_to;
688
 
      ret = start_mandos_communication(address, port, if_index);
 
756
      ret = start_mandos_communication(address, port, if_index, &mc);
689
757
      if(ret < 0){
690
758
        exit(EXIT_FAILURE);
691
759
      } else {
693
761
      }
694
762
    }
695
763
    
 
764
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
765
    if(sd < 0) {
 
766
      perror("socket");
 
767
      returncode = EXIT_FAILURE;
 
768
      goto exit;
 
769
    }
 
770
    strcpy(network.ifr_name, interface); /* Spurious warning */
 
771
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
772
    if(ret == -1){
 
773
      
 
774
      perror("ioctl SIOCGIFFLAGS");
 
775
      returncode = EXIT_FAILURE;
 
776
      goto exit;
 
777
    }
 
778
    if((network.ifr_flags & IFF_UP) == 0){
 
779
      network.ifr_flags |= IFF_UP;
 
780
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
781
      if(ret == -1){
 
782
        perror("ioctl SIOCSIFFLAGS");
 
783
        returncode = EXIT_FAILURE;
 
784
        goto exit;
 
785
      }
 
786
    }
 
787
    close(sd);
 
788
    
696
789
    if (not debug){
697
790
      avahi_set_log_function(empty_log);
698
791
    }
701
794
    srand((unsigned int) time(NULL));
702
795
 
703
796
    /* Allocate main loop object */
704
 
    if (!(simple_poll = avahi_simple_poll_new())) {
 
797
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
705
798
        fprintf(stderr, "Failed to create simple poll object.\n");
706
 
        
 
799
        returncode = EXIT_FAILURE;
707
800
        goto exit;
708
801
    }
709
802
 
715
808
    config.publish_domain = 0;
716
809
 
717
810
    /* Allocate a new server */
718
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
719
 
                              &config, NULL, NULL, &error);
720
 
 
 
811
    mc.server=avahi_server_new(avahi_simple_poll_get(mc.simple_poll),
 
812
                               &config, NULL, NULL, &error);
 
813
    
721
814
    /* Free the configuration data */
722
815
    avahi_server_config_free(&config);
723
 
 
 
816
    
724
817
    /* Check if creating the server object succeeded */
725
 
    if (!server) {
 
818
    if (!mc.server) {
726
819
        fprintf(stderr, "Failed to create server: %s\n",
727
820
                avahi_strerror(error));
728
821
        returncode = EXIT_FAILURE;
730
823
    }
731
824
    
732
825
    /* Create the service browser */
733
 
    sb = avahi_s_service_browser_new(server, if_index,
 
826
    sb = avahi_s_service_browser_new(mc.server, if_index,
734
827
                                     AVAHI_PROTO_INET6,
735
828
                                     "_mandos._tcp", NULL, 0,
736
 
                                     browse_callback, server);
 
829
                                     browse_callback, &mc);
737
830
    if (!sb) {
738
831
        fprintf(stderr, "Failed to create service browser: %s\n",
739
 
                avahi_strerror(avahi_server_errno(server)));
 
832
                avahi_strerror(avahi_server_errno(mc.server)));
740
833
        returncode = EXIT_FAILURE;
741
834
        goto exit;
742
835
    }
747
840
      fprintf(stderr, "Starting avahi loop search\n");
748
841
    }
749
842
    
750
 
    avahi_simple_poll_loop(simple_poll);
 
843
    avahi_simple_poll_loop(mc.simple_poll);
751
844
    
752
845
 exit:
753
846
 
759
852
    if (sb)
760
853
        avahi_s_service_browser_free(sb);
761
854
    
762
 
    if (server)
763
 
        avahi_server_free(server);
764
 
 
765
 
    if (simple_poll)
766
 
        avahi_simple_poll_free(simple_poll);
767
 
 
 
855
    if (mc.server)
 
856
        avahi_server_free(mc.server);
 
857
 
 
858
    if (mc.simple_poll)
 
859
        avahi_simple_poll_free(mc.simple_poll);
 
860
    free(pubkeyfile);
 
861
    free(seckeyfile);
 
862
    
768
863
    return returncode;
769
864
}