/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-07-22 01:59:47 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080722015947-y7o6keji020nvrhw
* Makefile (OPTIMIZE): New; optimize for size.
  (CFLAGS): Use $(OPTIMIZE).

Show diffs side-by-side

added added

removed removed

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