/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:
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 Copyright © 2007-2008 Teddy Hogeborn and Björn
 
12
 * 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
 */
 
31
 
 
32
#define _FORTIFY_SOURCE 2
19
33
 
20
34
#define _LARGEFILE_SOURCE
21
35
#define _FILE_OFFSET_BITS 64
34
48
#include <avahi-common/error.h>
35
49
 
36
50
//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 */
 
51
#include <sys/types.h>          /* socket(), inet_pton() */
 
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
53
                                   struct in6_addr, inet_pton() */
 
54
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
 
55
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
41
56
 
42
57
#include <unistd.h>             /* close() */
43
58
#include <netinet/in.h>
62
77
#define DH_BITS 1024
63
78
 
64
79
bool debug = false;
65
 
char *interface = "eth0";
66
80
 
67
81
typedef struct {
68
82
  gnutls_session_t session;
71
85
} encrypted_session;
72
86
 
73
87
 
74
 
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
 
88
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
89
                            char **new_packet, const char *homedir){
75
90
  gpgme_data_t dh_crypto, dh_plain;
76
91
  gpgme_ctx_t ctx;
77
92
  gpgme_error_t rc;
78
93
  ssize_t ret;
79
 
  size_t new_packet_capacity = 0;
80
 
  size_t new_packet_length = 0;
 
94
  ssize_t new_packet_capacity = 0;
 
95
  ssize_t new_packet_length = 0;
81
96
  gpgme_engine_info_t engine_info;
82
97
 
83
98
  if (debug){
84
 
    fprintf(stderr, "Attempting to decrypt password from gpg packet\n");
 
99
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
85
100
  }
86
101
  
87
102
  /* Init GPGME */
132
147
    return -1;
133
148
  }
134
149
  
135
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
150
  /* Decrypt data from the FILE pointer to the plaintext data
 
151
     buffer */
136
152
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
137
153
  if (rc != GPG_ERR_NO_ERROR){
138
154
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
141
157
  }
142
158
 
143
159
  if(debug){
144
 
    fprintf(stderr, "decryption of gpg packet succeeded\n");
 
160
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
145
161
  }
146
162
 
147
163
  if (debug){
150
166
    if (result == NULL){
151
167
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
152
168
    } else {
153
 
      fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
154
 
      fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
 
169
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
170
              result->unsupported_algorithm);
 
171
      fprintf(stderr, "Wrong key usage: %d\n",
 
172
              result->wrong_key_usage);
155
173
      if(result->file_name != NULL){
156
174
        fprintf(stderr, "File name: %s\n", result->file_name);
157
175
      }
163
181
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
164
182
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
165
183
          fprintf(stderr, "Secret key available: %s\n",
166
 
                  recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
 
184
                  recipient->status == GPG_ERR_NO_SECKEY
 
185
                  ? "No" : "Yes");
167
186
          recipient = recipient->next;
168
187
        }
169
188
      }
174
193
  gpgme_data_release(dh_crypto);
175
194
  
176
195
  /* Seek back to the beginning of the GPGME plaintext data buffer */
177
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
196
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
178
197
 
179
198
  *new_packet = 0;
180
199
  while(true){
181
200
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
182
 
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
 
201
      *new_packet = realloc(*new_packet,
 
202
                            (unsigned int)new_packet_capacity
 
203
                            + BUFFER_SIZE);
183
204
      if (*new_packet == NULL){
184
205
        perror("realloc");
185
206
        return -1;
187
208
      new_packet_capacity += BUFFER_SIZE;
188
209
    }
189
210
    
190
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
 
211
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
212
                          BUFFER_SIZE);
191
213
    /* Print the data, if any */
192
214
    if (ret == 0){
193
 
      /* If password is empty, then a incorrect error will be printed */
194
215
      break;
195
216
    }
196
217
    if(ret < 0){
220
241
  return ret;
221
242
}
222
243
 
223
 
void debuggnutls(int level, const char* string){
 
244
void debuggnutls(__attribute__((unused)) int level,
 
245
                 const char* string){
224
246
  fprintf(stderr, "%s", string);
225
247
}
226
248
 
227
249
int initgnutls(encrypted_session *es){
228
250
  const char *err;
229
251
  int ret;
230
 
 
 
252
  
231
253
  if(debug){
232
 
    fprintf(stderr, "Initializing gnutls\n");
 
254
    fprintf(stderr, "Initializing GnuTLS\n");
233
255
  }
234
 
 
235
256
  
236
257
  if ((ret = gnutls_global_init ())
237
258
      != GNUTLS_E_SUCCESS) {
244
265
    gnutls_global_set_log_function(debuggnutls);
245
266
  }
246
267
  
247
 
 
248
268
  /* openpgp credentials */
249
269
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
250
270
      != GNUTLS_E_SUCCESS) {
251
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
271
    fprintf (stderr, "memory error: %s\n",
 
272
             safer_gnutls_strerror(ret));
252
273
    return -1;
253
274
  }
254
 
 
 
275
  
255
276
  if(debug){
256
 
    fprintf(stderr, "Attempting to use openpgp certificate %s"
257
 
            " and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
 
277
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
278
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
 
279
            KEYFILE);
258
280
  }
259
 
 
 
281
  
260
282
  ret = gnutls_certificate_set_openpgp_key_file
261
283
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
262
284
  if (ret != GNUTLS_E_SUCCESS) {
263
285
    fprintf
264
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
 
286
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
287
       " '%s')\n",
265
288
       ret, CERTFILE, KEYFILE);
266
289
    fprintf(stdout, "The Error is: %s\n",
267
290
            safer_gnutls_strerror(ret));
268
291
    return -1;
269
292
  }
270
 
 
271
 
  //Gnutls server initialization
 
293
  
 
294
  //GnuTLS server initialization
272
295
  if ((ret = gnutls_dh_params_init (&es->dh_params))
273
296
      != GNUTLS_E_SUCCESS) {
274
297
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
275
298
             safer_gnutls_strerror(ret));
276
299
    return -1;
277
300
  }
278
 
 
 
301
  
279
302
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
280
303
      != GNUTLS_E_SUCCESS) {
281
304
    fprintf (stderr, "Error in prime generation: %s\n",
282
305
             safer_gnutls_strerror(ret));
283
306
    return -1;
284
307
  }
285
 
 
 
308
  
286
309
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
287
 
 
288
 
  // Gnutls session creation
 
310
  
 
311
  // GnuTLS session creation
289
312
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
290
313
      != GNUTLS_E_SUCCESS){
291
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
314
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
292
315
            safer_gnutls_strerror(ret));
293
316
  }
294
 
 
 
317
  
295
318
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
296
319
      != GNUTLS_E_SUCCESS) {
297
320
    fprintf(stderr, "Syntax error at: %s\n", err);
298
 
    fprintf(stderr, "Gnutls error: %s\n",
 
321
    fprintf(stderr, "GnuTLS error: %s\n",
299
322
            safer_gnutls_strerror(ret));
300
323
    return -1;
301
324
  }
302
 
 
 
325
  
303
326
  if ((ret = gnutls_credentials_set
304
327
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
305
328
      != GNUTLS_E_SUCCESS) {
307
330
            safer_gnutls_strerror(ret));
308
331
    return -1;
309
332
  }
310
 
 
 
333
  
311
334
  /* ignore client certificate if any. */
312
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
335
  gnutls_certificate_server_set_request (es->session,
 
336
                                         GNUTLS_CERT_IGNORE);
313
337
  
314
338
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
315
339
  
316
340
  return 0;
317
341
}
318
342
 
319
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
343
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
344
               __attribute__((unused)) const char *txt){}
320
345
 
321
 
int start_mandos_communcation(char *ip, uint16_t port){
 
346
int start_mandos_communication(const char *ip, uint16_t port,
 
347
                               unsigned int if_index){
322
348
  int ret, tcp_sd;
323
349
  struct sockaddr_in6 to;
324
 
  struct in6_addr ip_addr;
325
350
  encrypted_session es;
326
351
  char *buffer = NULL;
327
352
  char *decrypted_buffer;
328
353
  size_t buffer_length = 0;
329
354
  size_t buffer_capacity = 0;
330
355
  ssize_t decrypted_buffer_size;
 
356
  size_t written = 0;
331
357
  int retval = 0;
332
 
 
 
358
  char interface[IF_NAMESIZE];
 
359
  
333
360
  if(debug){
334
361
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
335
362
  }
339
366
    perror("socket");
340
367
    return -1;
341
368
  }
342
 
 
 
369
  
 
370
  if(if_indextoname(if_index, interface) == NULL){
 
371
    if(debug){
 
372
      perror("if_indextoname");
 
373
    }
 
374
    return -1;
 
375
  }
 
376
  
343
377
  if(debug){
344
378
    fprintf(stderr, "Binding to interface %s\n", interface);
345
379
  }
346
 
 
347
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
348
 
  if(tcp_sd < 0) {
349
 
    perror("setsockopt bindtodevice");
350
 
    return -1;
351
 
  }
352
380
  
353
 
  memset(&to,0,sizeof(to));
 
381
  memset(&to,0,sizeof(to));     /* Spurious warning */
354
382
  to.sin6_family = AF_INET6;
355
 
  ret = inet_pton(AF_INET6, ip, &ip_addr);
 
383
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
356
384
  if (ret < 0 ){
357
385
    perror("inet_pton");
358
386
    return -1;
361
389
    fprintf(stderr, "Bad address: %s\n", ip);
362
390
    return -1;
363
391
  }
364
 
  to.sin6_port = htons(port);
365
 
  to.sin6_scope_id = if_nametoindex(interface);
366
 
 
 
392
  to.sin6_port = htons(port);   /* Spurious warning */
 
393
  
 
394
  to.sin6_scope_id = (uint32_t)if_index;
 
395
  
367
396
  if(debug){
368
397
    fprintf(stderr, "Connection to: %s\n", ip);
369
398
  }
379
408
    retval = -1;
380
409
    return -1;
381
410
  }
382
 
    
383
 
  
384
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
385
 
 
 
411
  
 
412
  gnutls_transport_set_ptr (es.session,
 
413
                            (gnutls_transport_ptr_t) tcp_sd);
 
414
  
386
415
  if(debug){
387
 
    fprintf(stderr, "Establishing tls session with %s\n", ip);
 
416
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
388
417
  }
389
 
 
390
418
  
391
419
  ret = gnutls_handshake (es.session);
392
420
  
396
424
    retval = -1;
397
425
    goto exit;
398
426
  }
399
 
 
400
 
  //Retrieve gpg packet that contains the wanted password
401
 
 
 
427
  
 
428
  //Retrieve OpenPGP packet that contains the wanted password
 
429
  
402
430
  if(debug){
403
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
 
431
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
432
            ip);
404
433
  }
405
434
 
406
435
  while(true){
433
462
        }
434
463
        break;
435
464
      default:
436
 
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
465
        fprintf(stderr, "Unknown error while reading data from"
 
466
                " encrypted session with mandos server\n");
437
467
        retval = -1;
438
468
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
439
469
        goto exit;
440
470
      }
441
471
    } else {
442
 
      buffer_length += ret;
 
472
      buffer_length += (size_t) ret;
443
473
    }
444
474
  }
445
475
  
446
476
  if (buffer_length > 0){
447
 
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
448
 
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
 
477
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
478
                                               buffer_length,
 
479
                                               &decrypted_buffer,
 
480
                                               CERT_ROOT);
 
481
    if (decrypted_buffer_size >= 0){
 
482
      while(written < decrypted_buffer_size){
 
483
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
484
                           (size_t)decrypted_buffer_size - written,
 
485
                           stdout);
 
486
        if(ret == 0 and ferror(stdout)){
 
487
          if(debug){
 
488
            fprintf(stderr, "Error writing encrypted data: %s\n",
 
489
                    strerror(errno));
 
490
          }
 
491
          retval = -1;
 
492
          break;
 
493
        }
 
494
        written += (size_t)ret;
 
495
      }
449
496
      free(decrypted_buffer);
450
497
    } else {
451
498
      retval = -1;
455
502
  //shutdown procedure
456
503
 
457
504
  if(debug){
458
 
    fprintf(stderr, "Closing tls session\n");
 
505
    fprintf(stderr, "Closing TLS session\n");
459
506
  }
460
507
 
461
508
  free(buffer);
473
520
 
474
521
static void resolve_callback(
475
522
    AvahiSServiceResolver *r,
476
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
523
    AvahiIfIndex interface,
477
524
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
478
525
    AvahiResolverEvent event,
479
526
    const char *name,
482
529
    const char *host_name,
483
530
    const AvahiAddress *address,
484
531
    uint16_t port,
485
 
    AvahiStringList *txt,
486
 
    AvahiLookupResultFlags flags,
 
532
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
533
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
487
534
    AVAHI_GCC_UNUSED void* userdata) {
488
535
    
489
 
    assert(r);
490
 
 
491
 
    /* Called whenever a service has been resolved successfully or timed out */
492
 
 
493
 
    switch (event) {
494
 
        case AVAHI_RESOLVER_FAILURE:
495
 
            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)));
496
 
            break;
497
 
 
498
 
        case AVAHI_RESOLVER_FOUND: {
499
 
          char ip[AVAHI_ADDRESS_STR_MAX];
500
 
            avahi_address_snprint(ip, sizeof(ip), address);
501
 
            if(debug){
502
 
              fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
503
 
            }
504
 
            int ret = start_mandos_communcation(ip, port);
505
 
            if (ret == 0){
506
 
              exit(EXIT_SUCCESS);
507
 
            } else {
508
 
              exit(EXIT_FAILURE);
509
 
            }
510
 
        }
 
536
  assert(r);                    /* Spurious warning */
 
537
  
 
538
  /* Called whenever a service has been resolved successfully or
 
539
     timed out */
 
540
  
 
541
  switch (event) {
 
542
  default:
 
543
  case AVAHI_RESOLVER_FAILURE:
 
544
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
 
545
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
546
            avahi_strerror(avahi_server_errno(server)));
 
547
    break;
 
548
    
 
549
  case AVAHI_RESOLVER_FOUND:
 
550
    {
 
551
      char ip[AVAHI_ADDRESS_STR_MAX];
 
552
      avahi_address_snprint(ip, sizeof(ip), address);
 
553
      if(debug){
 
554
        fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
 
555
                host_name, ip, port);
 
556
      }
 
557
      int ret = start_mandos_communication(ip, port,
 
558
                                           (unsigned int) interface);
 
559
      if (ret == 0){
 
560
        exit(EXIT_SUCCESS);
 
561
      } else {
 
562
        exit(EXIT_FAILURE);
 
563
      }
511
564
    }
512
 
    avahi_s_service_resolver_free(r);
 
565
  }
 
566
  avahi_s_service_resolver_free(r);
513
567
}
514
568
 
515
569
static void browse_callback(
524
578
    void* userdata) {
525
579
    
526
580
    AvahiServer *s = userdata;
527
 
    assert(b);
528
 
 
529
 
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
530
 
 
 
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
    
531
586
    switch (event) {
532
 
 
533
 
        case AVAHI_BROWSER_FAILURE:
534
 
            
535
 
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
536
 
            avahi_simple_poll_quit(simple_poll);
537
 
            return;
538
 
 
539
 
        case AVAHI_BROWSER_NEW:
540
 
            /* We ignore the returned resolver object. In the callback
541
 
               function we free it. If the server is terminated before
542
 
               the callback function is called the server will free
543
 
               the resolver for us. */
544
 
            
545
 
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
546
 
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
547
 
            
548
 
            break;
549
 
 
550
 
        case AVAHI_BROWSER_REMOVE:
551
 
            break;
552
 
 
553
 
        case AVAHI_BROWSER_ALL_FOR_NOW:
554
 
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
555
 
            break;
 
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;
556
615
    }
557
616
}
558
617
 
562
621
    int error;
563
622
    int ret;
564
623
    int returncode = EXIT_SUCCESS;
565
 
 
 
624
    const char *interface = "eth0";
 
625
    
566
626
    while (true){
567
627
      static struct option long_options[] = {
568
628
        {"debug", no_argument, (int *)&debug, 1},
569
629
        {"interface", required_argument, 0, 'i'},
570
630
        {0, 0, 0, 0} };
571
 
 
 
631
      
572
632
      int option_index = 0;
573
 
      ret = getopt_long (argc, argv, "i:", long_options, &option_index);
574
 
 
 
633
      ret = getopt_long (argc, argv, "i:", long_options,
 
634
                         &option_index);
 
635
      
575
636
      if (ret == -1){
576
637
        break;
577
638
      }
592
653
    }
593
654
    
594
655
    /* Initialize the psuedo-RNG */
595
 
    srand(time(NULL));
 
656
    srand((unsigned int) time(NULL));
596
657
 
597
658
    /* Allocate main loop object */
598
659
    if (!(simple_poll = avahi_simple_poll_new())) {
609
670
    config.publish_domain = 0;
610
671
 
611
672
    /* Allocate a new server */
612
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
673
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
674
                              &config, NULL, NULL, &error);
613
675
 
614
676
    /* Free the configuration data */
615
677
    avahi_server_config_free(&config);
616
678
 
617
679
    /* Check if creating the server object succeeded */
618
680
    if (!server) {
619
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
681
        fprintf(stderr, "Failed to create server: %s\n",
 
682
                avahi_strerror(error));
620
683
        returncode = EXIT_FAILURE;
621
684
        goto exit;
622
685
    }
623
686
    
624
687
    /* Create the service browser */
625
 
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
626
 
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
 
688
    sb = avahi_s_service_browser_new(server,
 
689
                                     (AvahiIfIndex)
 
690
                                     if_nametoindex(interface),
 
691
                                     AVAHI_PROTO_INET6,
 
692
                                     "_mandos._tcp", NULL, 0,
 
693
                                     browse_callback, server);
 
694
    if (!sb) {
 
695
        fprintf(stderr, "Failed to create service browser: %s\n",
 
696
                avahi_strerror(avahi_server_errno(server)));
627
697
        returncode = EXIT_FAILURE;
628
698
        goto exit;
629
699
    }
636
706
    
637
707
    avahi_simple_poll_loop(simple_poll);
638
708
    
639
 
exit:
 
709
 exit:
640
710
 
641
711
    if (debug){
642
712
      fprintf(stderr, "%s exiting\n", argv[0]);