/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-29 03:35:39 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080729033539-08zecoj3jwlkpjhw
* server.conf: New file.

* mandos-clients.conf: Renamed to clients.conf.

* Makefile (FORTIFY): New.
  (CFLAGS): Include $(FORTIFY).

* plugins.d/mandosclient.c (main): New "if_index" variable.  Bug fix:
                                   check if interface exists.  New
                                   "--connect" option.

* server.py (serviceInterface): Removed; replaced by
                                "AvahiService.interface".  All users
                                changed.
  (AvahiError, AvahiServiceError, AvahiGroupError): New exception
                                                    classes.
  (AvahiService): New class.
  (serviceName): Removed; replaced by "AvahiService.name".  All users
                 changed.
  (serviceType): Removed; replaced by "AvahiService.type".  All users
                 changed.
  (servicePort): Removed; replaced by "AvahiService.port".  All users
                 changed.
  (serviceTXT): Removed; replaced by "AvahiService.TXT".  All users
                changed.
  (domain): Removed; replaced by "AvahiService.domain".  All users
            changed.
  (host): Removed; replaced by "AvahiService.host".  All users
          changed.
  (rename_count): Removed; replaced by "AvahiService.rename_count" and
                 "AvahiService.max_renames".  All users changed.
  (Client.__init__): If no secret or secfile, raise TypeError instead
                     of RuntimeError.
  (Client.last_seen): Renamed to "Client.last_checked_ok".  All users
                      changed.
  (Client.stop, Client.stop_checker): Use "getattr" with default value
                                      instead of "hasattr".
  (Client.still_valid): Removed "now" argument.
  (Client.handle): Separate the "no client found" and "client invalid"
                   cases for clearer code.
  (IPv6_TCPServer.__init__): "options" argument replaced by
                             "settings".  All callers changed.
  (IPv6_TCPServer.options): Replaced by "IPv6_TCPServer.settings".
                            All users changed.
  (IPv6_TCPServer.server_bind): Use getattr instead of hasattr.
  (add_service): Removed; replaced by "AvahiService.add".  All callers
                 changed.
  (remove_service): Removed; replaced by "AvahiService.remove".  All
                    callers changed.
  (entry_group_state_changed): On entry group collision, call the new
                               AvahiService.rename method.  Raise
                               AvahiGroupError on group error.
  (if_nametoindex): Use ctypes.utils.find_library to locate the C
                    library.  Cache the result.  Loop on EINTR.
  (daemon): Use os.path.devnull to locate "/dev/null".
  (killme): Removed.  All callers changed to do "sys.exit()" instead,
            except where stated otherwise.
  (main): Removed "exitstatus".  Removed all default values from all
          non-bool options.  New option "--configdir".  New variables
          "server_defaults" and "server_settings", read from
          "%(configdir)s/server.conf".  Let any supplied command line
          options override server settings.   Variable "defaults"
          renamed to "client_defaults", which is read from
          "clients.conf" instead of "mandos-clients.conf".  New global
          AvahiService object "service" replaces old global variables.
          Catch AvahiError and exit with error if caught.

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