/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-31 19:48:05 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080731194805-mseis21dxwrdfqhk
* plugins.d/mandosclient.c (start_mandos_communication): Changed
                                                        "if_index" to
                                                        be of type
                                                        "AvahiIfIndex".
                                                        All callers
                                                        changed.
 (main): Add default values to "interface" and "if_index".  Only
         change if_index from default if "interface" was given.

* server.py (IPv6_TCPServer.server_bind): Bug fix: test if interface
                                          is empty, not if equal to
                                          avahi.IF_UNSPEC.
  (if_nametoindex): Bug fix; typo: assign to _func[0], not func[0].
  (main): Bug fix: Do not set service.interface unless the interface
          setting has been given.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***
2
 
  This file is part of avahi.
3
 
 
4
 
  avahi is free software; you can redistribute it and/or modify it
5
 
  under the terms of the GNU Lesser General Public License as
6
 
  published by the Free Software Foundation; either version 2.1 of the
7
 
  License, or (at your option) any later version.
8
 
 
9
 
  avahi is distributed in the hope that it will be useful, but WITHOUT
10
 
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11
 
  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12
 
  Public License for more details.
13
 
 
14
 
  You should have received a copy of the GNU Lesser General Public
15
 
  License along with avahi; if not, write to the Free Software
16
 
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17
 
  USA.
18
 
***/
 
1
/*  -*- coding: utf-8 -*- */
 
2
/*
 
3
 * Mandos client - get and decrypt data from a Mandos server
 
4
 *
 
5
 * This program is partly derived from an example program for an Avahi
 
6
 * service browser, downloaded from
 
7
 * <http://avahi.org/browser/examples/core-browse-services.c>.  This
 
8
 * includes the following functions: "resolve_callback",
 
9
 * "browse_callback", and parts of "main".
 
10
 * 
 
11
 * Everything else is
 
12
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
13
 * 
 
14
 * This program is free software: you can redistribute it and/or
 
15
 * modify it under the terms of the GNU General Public License as
 
16
 * published by the Free Software Foundation, either version 3 of the
 
17
 * License, or (at your option) any later version.
 
18
 * 
 
19
 * This program is distributed in the hope that it will be useful, but
 
20
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
22
 * General Public License for more details.
 
23
 * 
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program.  If not, see
 
26
 * <http://www.gnu.org/licenses/>.
 
27
 * 
 
28
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
29
 * <https://www.fukt.bsnet.se/~teddy/>.
 
30
 */
19
31
 
 
32
/* Needed by GPGME, specifically gpgme_data_seek() */
20
33
#define _LARGEFILE_SOURCE
21
34
#define _FILE_OFFSET_BITS 64
22
35
 
34
47
#include <avahi-common/error.h>
35
48
 
36
49
//mandos client part
37
 
#include <sys/types.h>          /* socket(), setsockopt(), inet_pton() */
38
 
#include <sys/socket.h>         /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */
39
 
#include <gnutls/gnutls.h>      /* ALL GNUTLS STUFF */
40
 
#include <gnutls/openpgp.h>     /* gnutls with openpgp stuff */
 
50
#include <sys/types.h>          /* socket(), inet_pton() */
 
51
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
52
                                   struct in6_addr, inet_pton() */
 
53
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
 
54
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
41
55
 
42
56
#include <unistd.h>             /* close() */
43
57
#include <netinet/in.h>
62
76
#define DH_BITS 1024
63
77
 
64
78
bool debug = false;
65
 
char *interface = "eth0";
66
79
 
67
80
typedef struct {
68
81
  gnutls_session_t session;
71
84
} encrypted_session;
72
85
 
73
86
 
74
 
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
 
87
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
88
                            char **new_packet, const char *homedir){
75
89
  gpgme_data_t dh_crypto, dh_plain;
76
90
  gpgme_ctx_t ctx;
77
91
  gpgme_error_t rc;
78
92
  ssize_t ret;
79
 
  size_t new_packet_capacity = 0;
80
 
  size_t new_packet_length = 0;
 
93
  ssize_t new_packet_capacity = 0;
 
94
  ssize_t new_packet_length = 0;
81
95
  gpgme_engine_info_t engine_info;
82
96
 
83
97
  if (debug){
84
 
    fprintf(stderr, "Attempting to decrypt password from gpg packet\n");
 
98
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
85
99
  }
86
100
  
87
101
  /* Init GPGME */
132
146
    return -1;
133
147
  }
134
148
  
135
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
149
  /* Decrypt data from the FILE pointer to the plaintext data
 
150
     buffer */
136
151
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
137
152
  if (rc != GPG_ERR_NO_ERROR){
138
153
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
141
156
  }
142
157
 
143
158
  if(debug){
144
 
    fprintf(stderr, "decryption of gpg packet succeeded\n");
 
159
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
145
160
  }
146
161
 
147
162
  if (debug){
150
165
    if (result == NULL){
151
166
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
152
167
    } else {
153
 
      fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
154
 
      fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
 
168
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
169
              result->unsupported_algorithm);
 
170
      fprintf(stderr, "Wrong key usage: %d\n",
 
171
              result->wrong_key_usage);
155
172
      if(result->file_name != NULL){
156
173
        fprintf(stderr, "File name: %s\n", result->file_name);
157
174
      }
163
180
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
164
181
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
165
182
          fprintf(stderr, "Secret key available: %s\n",
166
 
                  recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
 
183
                  recipient->status == GPG_ERR_NO_SECKEY
 
184
                  ? "No" : "Yes");
167
185
          recipient = recipient->next;
168
186
        }
169
187
      }
174
192
  gpgme_data_release(dh_crypto);
175
193
  
176
194
  /* Seek back to the beginning of the GPGME plaintext data buffer */
177
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
195
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
178
196
 
179
197
  *new_packet = 0;
180
198
  while(true){
181
199
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
182
 
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
 
200
      *new_packet = realloc(*new_packet,
 
201
                            (unsigned int)new_packet_capacity
 
202
                            + BUFFER_SIZE);
183
203
      if (*new_packet == NULL){
184
204
        perror("realloc");
185
205
        return -1;
187
207
      new_packet_capacity += BUFFER_SIZE;
188
208
    }
189
209
    
190
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
 
210
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
211
                          BUFFER_SIZE);
191
212
    /* Print the data, if any */
192
213
    if (ret == 0){
193
 
      /* If password is empty, then a incorrect error will be printed */
194
214
      break;
195
215
    }
196
216
    if(ret < 0){
220
240
  return ret;
221
241
}
222
242
 
223
 
void debuggnutls(int level, const char* string){
 
243
void debuggnutls(__attribute__((unused)) int level,
 
244
                 const char* string){
224
245
  fprintf(stderr, "%s", string);
225
246
}
226
247
 
227
248
int initgnutls(encrypted_session *es){
228
249
  const char *err;
229
250
  int ret;
230
 
 
 
251
  
231
252
  if(debug){
232
 
    fprintf(stderr, "Initializing gnutls\n");
 
253
    fprintf(stderr, "Initializing GnuTLS\n");
233
254
  }
234
 
 
235
255
  
236
256
  if ((ret = gnutls_global_init ())
237
257
      != GNUTLS_E_SUCCESS) {
244
264
    gnutls_global_set_log_function(debuggnutls);
245
265
  }
246
266
  
247
 
 
248
267
  /* openpgp credentials */
249
268
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
250
269
      != GNUTLS_E_SUCCESS) {
251
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
270
    fprintf (stderr, "memory error: %s\n",
 
271
             safer_gnutls_strerror(ret));
252
272
    return -1;
253
273
  }
254
 
 
 
274
  
255
275
  if(debug){
256
 
    fprintf(stderr, "Attempting to use openpgp certificate %s"
257
 
            " and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
 
276
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
277
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
 
278
            KEYFILE);
258
279
  }
259
 
 
 
280
  
260
281
  ret = gnutls_certificate_set_openpgp_key_file
261
282
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
262
283
  if (ret != GNUTLS_E_SUCCESS) {
263
284
    fprintf
264
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
 
285
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
286
       " '%s')\n",
265
287
       ret, CERTFILE, KEYFILE);
266
288
    fprintf(stdout, "The Error is: %s\n",
267
289
            safer_gnutls_strerror(ret));
268
290
    return -1;
269
291
  }
270
 
 
271
 
  //Gnutls server initialization
 
292
  
 
293
  //GnuTLS server initialization
272
294
  if ((ret = gnutls_dh_params_init (&es->dh_params))
273
295
      != GNUTLS_E_SUCCESS) {
274
296
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
275
297
             safer_gnutls_strerror(ret));
276
298
    return -1;
277
299
  }
278
 
 
 
300
  
279
301
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
280
302
      != GNUTLS_E_SUCCESS) {
281
303
    fprintf (stderr, "Error in prime generation: %s\n",
282
304
             safer_gnutls_strerror(ret));
283
305
    return -1;
284
306
  }
285
 
 
 
307
  
286
308
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
287
 
 
288
 
  // Gnutls session creation
 
309
  
 
310
  // GnuTLS session creation
289
311
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
290
312
      != GNUTLS_E_SUCCESS){
291
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
313
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
292
314
            safer_gnutls_strerror(ret));
293
315
  }
294
 
 
 
316
  
295
317
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
296
318
      != GNUTLS_E_SUCCESS) {
297
319
    fprintf(stderr, "Syntax error at: %s\n", err);
298
 
    fprintf(stderr, "Gnutls error: %s\n",
 
320
    fprintf(stderr, "GnuTLS error: %s\n",
299
321
            safer_gnutls_strerror(ret));
300
322
    return -1;
301
323
  }
302
 
 
 
324
  
303
325
  if ((ret = gnutls_credentials_set
304
326
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
305
327
      != GNUTLS_E_SUCCESS) {
307
329
            safer_gnutls_strerror(ret));
308
330
    return -1;
309
331
  }
310
 
 
 
332
  
311
333
  /* ignore client certificate if any. */
312
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
334
  gnutls_certificate_server_set_request (es->session,
 
335
                                         GNUTLS_CERT_IGNORE);
313
336
  
314
337
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
315
338
  
316
339
  return 0;
317
340
}
318
341
 
319
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
342
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
343
               __attribute__((unused)) const char *txt){}
320
344
 
321
 
int start_mandos_communication(char *ip, uint16_t port){
 
345
int start_mandos_communication(const char *ip, uint16_t port,
 
346
                               AvahiIfIndex if_index){
322
347
  int ret, tcp_sd;
323
348
  struct sockaddr_in6 to;
324
349
  encrypted_session es;
327
352
  size_t buffer_length = 0;
328
353
  size_t buffer_capacity = 0;
329
354
  ssize_t decrypted_buffer_size;
 
355
  size_t written = 0;
330
356
  int retval = 0;
331
 
 
 
357
  char interface[IF_NAMESIZE];
 
358
  
332
359
  if(debug){
333
 
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
 
360
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
 
361
            ip, port);
334
362
  }
335
363
  
336
364
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
338
366
    perror("socket");
339
367
    return -1;
340
368
  }
341
 
 
 
369
  
 
370
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
371
    if(debug){
 
372
      perror("if_indextoname");
 
373
    }
 
374
    return -1;
 
375
  }
 
376
  
342
377
  if(debug){
343
378
    fprintf(stderr, "Binding to interface %s\n", interface);
344
379
  }
345
 
 
346
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
347
 
  if(tcp_sd < 0) {
348
 
    perror("setsockopt bindtodevice");
349
 
    return -1;
350
 
  }
351
380
  
352
 
  memset(&to,0,sizeof(to));
 
381
  memset(&to,0,sizeof(to));     /* Spurious warning */
353
382
  to.sin6_family = AF_INET6;
354
383
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
355
384
  if (ret < 0 ){
360
389
    fprintf(stderr, "Bad address: %s\n", ip);
361
390
    return -1;
362
391
  }
363
 
  to.sin6_port = htons(port);
364
 
  to.sin6_scope_id = if_nametoindex(interface);
365
 
 
 
392
  to.sin6_port = htons(port);   /* Spurious warning */
 
393
  
 
394
  to.sin6_scope_id = (uint32_t)if_index;
 
395
  
366
396
  if(debug){
367
 
    fprintf(stderr, "Connection to: %s\n", ip);
 
397
    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
/*     } */
368
406
  }
369
407
  
370
408
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
378
416
    retval = -1;
379
417
    return -1;
380
418
  }
381
 
    
382
 
  
383
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
384
 
 
 
419
  
 
420
  gnutls_transport_set_ptr (es.session,
 
421
                            (gnutls_transport_ptr_t) tcp_sd);
 
422
  
385
423
  if(debug){
386
 
    fprintf(stderr, "Establishing tls session with %s\n", ip);
 
424
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
387
425
  }
388
 
 
389
426
  
390
427
  ret = gnutls_handshake (es.session);
391
428
  
392
429
  if (ret != GNUTLS_E_SUCCESS){
393
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
394
 
    gnutls_perror (ret);
 
430
    if(debug){
 
431
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
432
      gnutls_perror (ret);
 
433
    }
395
434
    retval = -1;
396
435
    goto exit;
397
436
  }
398
 
 
399
 
  //Retrieve gpg packet that contains the wanted password
400
 
 
 
437
  
 
438
  //Retrieve OpenPGP packet that contains the wanted password
 
439
  
401
440
  if(debug){
402
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
 
441
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
442
            ip);
403
443
  }
404
444
 
405
445
  while(true){
432
472
        }
433
473
        break;
434
474
      default:
435
 
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
475
        fprintf(stderr, "Unknown error while reading data from"
 
476
                " encrypted session with mandos server\n");
436
477
        retval = -1;
437
478
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
438
479
        goto exit;
439
480
      }
440
481
    } else {
441
 
      buffer_length += ret;
 
482
      buffer_length += (size_t) ret;
442
483
    }
443
484
  }
444
485
  
445
486
  if (buffer_length > 0){
446
 
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
447
 
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
 
487
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
488
                                               buffer_length,
 
489
                                               &decrypted_buffer,
 
490
                                               CERT_ROOT);
 
491
    if (decrypted_buffer_size >= 0){
 
492
      while(written < (size_t) decrypted_buffer_size){
 
493
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
494
                           (size_t)decrypted_buffer_size - written,
 
495
                           stdout);
 
496
        if(ret == 0 and ferror(stdout)){
 
497
          if(debug){
 
498
            fprintf(stderr, "Error writing encrypted data: %s\n",
 
499
                    strerror(errno));
 
500
          }
 
501
          retval = -1;
 
502
          break;
 
503
        }
 
504
        written += (size_t)ret;
 
505
      }
448
506
      free(decrypted_buffer);
449
507
    } else {
450
508
      retval = -1;
454
512
  //shutdown procedure
455
513
 
456
514
  if(debug){
457
 
    fprintf(stderr, "Closing tls session\n");
 
515
    fprintf(stderr, "Closing TLS session\n");
458
516
  }
459
517
 
460
518
  free(buffer);
472
530
 
473
531
static void resolve_callback(
474
532
    AvahiSServiceResolver *r,
475
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
533
    AvahiIfIndex interface,
476
534
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
477
535
    AvahiResolverEvent event,
478
536
    const char *name,
481
539
    const char *host_name,
482
540
    const AvahiAddress *address,
483
541
    uint16_t port,
484
 
    AvahiStringList *txt,
485
 
    AvahiLookupResultFlags flags,
 
542
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
543
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
486
544
    AVAHI_GCC_UNUSED void* userdata) {
487
545
    
488
 
    assert(r);
489
 
 
490
 
    /* Called whenever a service has been resolved successfully or timed out */
491
 
 
492
 
    switch (event) {
493
 
        case AVAHI_RESOLVER_FAILURE:
494
 
            fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_server_errno(server)));
495
 
            break;
496
 
 
497
 
        case AVAHI_RESOLVER_FOUND: {
498
 
          char ip[AVAHI_ADDRESS_STR_MAX];
499
 
            avahi_address_snprint(ip, sizeof(ip), address);
500
 
            if(debug){
501
 
              fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
502
 
            }
503
 
            int ret = start_mandos_communication(ip, port);
504
 
            if (ret == 0){
505
 
              exit(EXIT_SUCCESS);
506
 
            } else {
507
 
              exit(EXIT_FAILURE);
508
 
            }
509
 
        }
 
546
  assert(r);                    /* Spurious warning */
 
547
  
 
548
  /* Called whenever a service has been resolved successfully or
 
549
     timed out */
 
550
  
 
551
  switch (event) {
 
552
  default:
 
553
  case AVAHI_RESOLVER_FAILURE:
 
554
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
 
555
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
556
            avahi_strerror(avahi_server_errno(server)));
 
557
    break;
 
558
    
 
559
  case AVAHI_RESOLVER_FOUND:
 
560
    {
 
561
      char ip[AVAHI_ADDRESS_STR_MAX];
 
562
      avahi_address_snprint(ip, sizeof(ip), address);
 
563
      if(debug){
 
564
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
 
565
                " port %d\n", name, host_name, ip, port);
 
566
      }
 
567
      int ret = start_mandos_communication(ip, port, interface);
 
568
      if (ret == 0){
 
569
        exit(EXIT_SUCCESS);
 
570
      }
510
571
    }
511
 
    avahi_s_service_resolver_free(r);
 
572
  }
 
573
  avahi_s_service_resolver_free(r);
512
574
}
513
575
 
514
576
static void browse_callback(
523
585
    void* userdata) {
524
586
    
525
587
    AvahiServer *s = userdata;
526
 
    assert(b);
527
 
 
528
 
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
529
 
 
 
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
    
530
593
    switch (event) {
531
 
 
532
 
        case AVAHI_BROWSER_FAILURE:
533
 
            
534
 
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
535
 
            avahi_simple_poll_quit(simple_poll);
536
 
            return;
537
 
 
538
 
        case AVAHI_BROWSER_NEW:
539
 
            /* We ignore the returned resolver object. In the callback
540
 
               function we free it. If the server is terminated before
541
 
               the callback function is called the server will free
542
 
               the resolver for us. */
543
 
            
544
 
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
545
 
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
546
 
            
547
 
            break;
548
 
 
549
 
        case AVAHI_BROWSER_REMOVE:
550
 
            break;
551
 
 
552
 
        case AVAHI_BROWSER_ALL_FOR_NOW:
553
 
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
554
 
            break;
 
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;
555
622
    }
556
623
}
557
624
 
561
628
    int error;
562
629
    int ret;
563
630
    int returncode = EXIT_SUCCESS;
564
 
 
 
631
    const char *interface = NULL;
 
632
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
633
    char *connect_to = NULL;
 
634
    
565
635
    while (true){
566
636
      static struct option long_options[] = {
567
637
        {"debug", no_argument, (int *)&debug, 1},
 
638
        {"connect", required_argument, 0, 'c'},
568
639
        {"interface", required_argument, 0, 'i'},
569
640
        {0, 0, 0, 0} };
570
 
 
 
641
      
571
642
      int option_index = 0;
572
 
      ret = getopt_long (argc, argv, "i:", long_options, &option_index);
573
 
 
 
643
      ret = getopt_long (argc, argv, "i:", long_options,
 
644
                         &option_index);
 
645
      
574
646
      if (ret == -1){
575
647
        break;
576
648
      }
581
653
      case 'i':
582
654
        interface = optarg;
583
655
        break;
 
656
      case 'c':
 
657
        connect_to = optarg;
 
658
        break;
584
659
      default:
585
660
        exit(EXIT_FAILURE);
586
661
      }
587
662
    }
588
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
      }
 
670
    }
 
671
    
 
672
    if(connect_to != NULL){
 
673
      /* Connect directly, do not use Zeroconf */
 
674
      /* (Mainly meant for debugging) */
 
675
      char *address = strrchr(connect_to, ':');
 
676
      if(address == NULL){
 
677
        fprintf(stderr, "No colon in address\n");
 
678
        exit(EXIT_FAILURE);
 
679
      }
 
680
      errno = 0;
 
681
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
682
      if(errno){
 
683
        perror("Bad port number");
 
684
        exit(EXIT_FAILURE);
 
685
      }
 
686
      *address = '\0';
 
687
      address = connect_to;
 
688
      ret = start_mandos_communication(address, port, if_index);
 
689
      if(ret < 0){
 
690
        exit(EXIT_FAILURE);
 
691
      } else {
 
692
        exit(EXIT_SUCCESS);
 
693
      }
 
694
    }
 
695
    
589
696
    if (not debug){
590
697
      avahi_set_log_function(empty_log);
591
698
    }
592
699
    
593
700
    /* Initialize the psuedo-RNG */
594
 
    srand(time(NULL));
 
701
    srand((unsigned int) time(NULL));
595
702
 
596
703
    /* Allocate main loop object */
597
704
    if (!(simple_poll = avahi_simple_poll_new())) {
608
715
    config.publish_domain = 0;
609
716
 
610
717
    /* Allocate a new server */
611
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
718
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
719
                              &config, NULL, NULL, &error);
612
720
 
613
721
    /* Free the configuration data */
614
722
    avahi_server_config_free(&config);
615
723
 
616
724
    /* Check if creating the server object succeeded */
617
725
    if (!server) {
618
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
726
        fprintf(stderr, "Failed to create server: %s\n",
 
727
                avahi_strerror(error));
619
728
        returncode = EXIT_FAILURE;
620
729
        goto exit;
621
730
    }
622
731
    
623
732
    /* Create the service browser */
624
 
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
625
 
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
 
733
    sb = avahi_s_service_browser_new(server, if_index,
 
734
                                     AVAHI_PROTO_INET6,
 
735
                                     "_mandos._tcp", NULL, 0,
 
736
                                     browse_callback, server);
 
737
    if (!sb) {
 
738
        fprintf(stderr, "Failed to create service browser: %s\n",
 
739
                avahi_strerror(avahi_server_errno(server)));
626
740
        returncode = EXIT_FAILURE;
627
741
        goto exit;
628
742
    }
635
749
    
636
750
    avahi_simple_poll_loop(simple_poll);
637
751
    
638
 
exit:
 
752
 exit:
639
753
 
640
754
    if (debug){
641
755
      fprintf(stderr, "%s exiting\n", argv[0]);