/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: Björn Påhlsson
  • Date: 2007-12-11 23:40:35 UTC
  • Revision ID: belorn@braxen-20071211234035-m1nsu41vuzkak69h
Python based server
Added client configfile

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
33
 
 
34
 
#define _LARGEFILE_SOURCE
35
 
#define _FILE_OFFSET_BITS 64
36
 
 
37
 
#include <stdio.h>
38
 
#include <assert.h>
39
 
#include <stdlib.h>
40
 
#include <time.h>
41
 
#include <net/if.h>             /* if_nametoindex */
42
 
 
43
 
#include <avahi-core/core.h>
44
 
#include <avahi-core/lookup.h>
45
 
#include <avahi-core/log.h>
46
 
#include <avahi-common/simple-watch.h>
47
 
#include <avahi-common/malloc.h>
48
 
#include <avahi-common/error.h>
49
 
 
50
 
//mandos client part
51
 
#include <sys/types.h>          /* socket(), setsockopt(),
52
 
                                   inet_pton() */
53
 
#include <sys/socket.h>         /* socket(), setsockopt(),
54
 
                                   struct sockaddr_in6,
55
 
                                   struct in6_addr, inet_pton() */
56
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
57
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
58
 
 
59
 
#include <unistd.h>             /* close() */
60
 
#include <netinet/in.h>
61
 
#include <stdbool.h>            /* true */
62
 
#include <string.h>             /* memset */
63
 
#include <arpa/inet.h>          /* inet_pton() */
64
 
#include <iso646.h>             /* not */
65
 
 
66
 
// gpgme
67
 
#include <errno.h>              /* perror() */
68
 
#include <gpgme.h>
69
 
 
70
 
// getopt long
71
 
#include <getopt.h>
72
 
 
73
 
#ifndef CERT_ROOT
74
 
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
75
 
#endif
76
 
#define CERTFILE CERT_ROOT "openpgp-client.txt"
77
 
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
78
 
#define BUFFER_SIZE 256
79
 
#define DH_BITS 1024
80
 
 
81
 
bool debug = false;
82
 
 
83
 
typedef struct {
84
 
  gnutls_session_t session;
85
 
  gnutls_certificate_credentials_t cred;
86
 
  gnutls_dh_params_t dh_params;
87
 
} encrypted_session;
88
 
 
89
 
 
90
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
91
 
                            char **new_packet, const char *homedir){
92
 
  gpgme_data_t dh_crypto, dh_plain;
93
 
  gpgme_ctx_t ctx;
94
 
  gpgme_error_t rc;
95
 
  ssize_t ret;
96
 
  ssize_t new_packet_capacity = 0;
97
 
  ssize_t new_packet_length = 0;
98
 
  gpgme_engine_info_t engine_info;
99
 
 
100
 
  if (debug){
101
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
102
 
  }
103
 
  
104
 
  /* Init GPGME */
105
 
  gpgme_check_version(NULL);
106
 
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
107
 
  
108
 
  /* Set GPGME home directory */
109
 
  rc = gpgme_get_engine_info (&engine_info);
110
 
  if (rc != GPG_ERR_NO_ERROR){
111
 
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
112
 
            gpgme_strsource(rc), gpgme_strerror(rc));
113
 
    return -1;
114
 
  }
115
 
  while(engine_info != NULL){
116
 
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
117
 
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
118
 
                            engine_info->file_name, homedir);
119
 
      break;
120
 
    }
121
 
    engine_info = engine_info->next;
122
 
  }
123
 
  if(engine_info == NULL){
124
 
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
125
 
    return -1;
126
 
  }
127
 
  
128
 
  /* Create new GPGME data buffer from packet buffer */
129
 
  rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
130
 
  if (rc != GPG_ERR_NO_ERROR){
131
 
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
132
 
            gpgme_strsource(rc), gpgme_strerror(rc));
133
 
    return -1;
134
 
  }
135
 
  
136
 
  /* Create new empty GPGME data buffer for the plaintext */
137
 
  rc = gpgme_data_new(&dh_plain);
138
 
  if (rc != GPG_ERR_NO_ERROR){
139
 
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
140
 
            gpgme_strsource(rc), gpgme_strerror(rc));
141
 
    return -1;
142
 
  }
143
 
  
144
 
  /* Create new GPGME "context" */
145
 
  rc = gpgme_new(&ctx);
146
 
  if (rc != GPG_ERR_NO_ERROR){
147
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
148
 
            gpgme_strsource(rc), gpgme_strerror(rc));
149
 
    return -1;
150
 
  }
151
 
  
152
 
  /* Decrypt data from the FILE pointer to the plaintext data
153
 
     buffer */
154
 
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
155
 
  if (rc != GPG_ERR_NO_ERROR){
156
 
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
157
 
            gpgme_strsource(rc), gpgme_strerror(rc));
158
 
    return -1;
159
 
  }
160
 
 
161
 
  if(debug){
162
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
163
 
  }
164
 
 
165
 
  if (debug){
166
 
    gpgme_decrypt_result_t result;
167
 
    result = gpgme_op_decrypt_result(ctx);
168
 
    if (result == NULL){
169
 
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
170
 
    } else {
171
 
      fprintf(stderr, "Unsupported algorithm: %s\n",
172
 
              result->unsupported_algorithm);
173
 
      fprintf(stderr, "Wrong key usage: %d\n",
174
 
              result->wrong_key_usage);
175
 
      if(result->file_name != NULL){
176
 
        fprintf(stderr, "File name: %s\n", result->file_name);
177
 
      }
178
 
      gpgme_recipient_t recipient;
179
 
      recipient = result->recipients;
180
 
      if(recipient){
181
 
        while(recipient != NULL){
182
 
          fprintf(stderr, "Public key algorithm: %s\n",
183
 
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
184
 
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
185
 
          fprintf(stderr, "Secret key available: %s\n",
186
 
                  recipient->status == GPG_ERR_NO_SECKEY
187
 
                  ? "No" : "Yes");
188
 
          recipient = recipient->next;
189
 
        }
190
 
      }
191
 
    }
192
 
  }
193
 
  
194
 
  /* Delete the GPGME FILE pointer cryptotext data buffer */
195
 
  gpgme_data_release(dh_crypto);
196
 
  
197
 
  /* Seek back to the beginning of the GPGME plaintext data buffer */
198
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
199
 
 
200
 
  *new_packet = 0;
201
 
  while(true){
202
 
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
203
 
      *new_packet = realloc(*new_packet,
204
 
                            (unsigned int)new_packet_capacity
205
 
                            + BUFFER_SIZE);
206
 
      if (*new_packet == NULL){
207
 
        perror("realloc");
208
 
        return -1;
209
 
      }
210
 
      new_packet_capacity += BUFFER_SIZE;
211
 
    }
212
 
    
213
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
214
 
                          BUFFER_SIZE);
215
 
    /* Print the data, if any */
216
 
    if (ret == 0){
217
 
      break;
218
 
    }
219
 
    if(ret < 0){
220
 
      perror("gpgme_data_read");
221
 
      return -1;
222
 
    }
223
 
    new_packet_length += ret;
224
 
  }
225
 
 
226
 
  /* FIXME: check characters before printing to screen so to not print
227
 
     terminal control characters */
228
 
  /*   if(debug){ */
229
 
  /*     fprintf(stderr, "decrypted password is: "); */
230
 
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
231
 
  /*     fprintf(stderr, "\n"); */
232
 
  /*   } */
233
 
  
234
 
  /* Delete the GPGME plaintext data buffer */
235
 
  gpgme_data_release(dh_plain);
236
 
  return new_packet_length;
237
 
}
238
 
 
239
 
static const char * safer_gnutls_strerror (int value) {
240
 
  const char *ret = gnutls_strerror (value);
241
 
  if (ret == NULL)
242
 
    ret = "(unknown)";
243
 
  return ret;
244
 
}
245
 
 
246
 
void debuggnutls(__attribute__((unused)) int level,
247
 
                 const char* string){
248
 
  fprintf(stderr, "%s", string);
249
 
}
250
 
 
251
 
int initgnutls(encrypted_session *es){
252
 
  const char *err;
253
 
  int ret;
254
 
  
255
 
  if(debug){
256
 
    fprintf(stderr, "Initializing GnuTLS\n");
257
 
  }
258
 
  
259
 
  if ((ret = gnutls_global_init ())
260
 
      != GNUTLS_E_SUCCESS) {
261
 
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
262
 
    return -1;
263
 
  }
264
 
 
265
 
  if (debug){
266
 
    gnutls_global_set_log_level(11);
267
 
    gnutls_global_set_log_function(debuggnutls);
268
 
  }
269
 
  
270
 
  /* openpgp credentials */
271
 
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
272
 
      != GNUTLS_E_SUCCESS) {
273
 
    fprintf (stderr, "memory error: %s\n",
274
 
             safer_gnutls_strerror(ret));
275
 
    return -1;
276
 
  }
277
 
  
278
 
  if(debug){
279
 
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
280
 
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
281
 
            KEYFILE);
282
 
  }
283
 
  
284
 
  ret = gnutls_certificate_set_openpgp_key_file
285
 
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
286
 
  if (ret != GNUTLS_E_SUCCESS) {
287
 
    fprintf
288
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
289
 
       " '%s')\n",
290
 
       ret, CERTFILE, KEYFILE);
291
 
    fprintf(stdout, "The Error is: %s\n",
292
 
            safer_gnutls_strerror(ret));
293
 
    return -1;
294
 
  }
295
 
  
296
 
  //GnuTLS server initialization
297
 
  if ((ret = gnutls_dh_params_init (&es->dh_params))
298
 
      != GNUTLS_E_SUCCESS) {
299
 
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
300
 
             safer_gnutls_strerror(ret));
301
 
    return -1;
302
 
  }
303
 
  
304
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
305
 
      != GNUTLS_E_SUCCESS) {
306
 
    fprintf (stderr, "Error in prime generation: %s\n",
307
 
             safer_gnutls_strerror(ret));
308
 
    return -1;
309
 
  }
310
 
  
311
 
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
312
 
  
313
 
  // GnuTLS session creation
314
 
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
315
 
      != GNUTLS_E_SUCCESS){
316
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
317
 
            safer_gnutls_strerror(ret));
318
 
  }
319
 
  
320
 
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
321
 
      != GNUTLS_E_SUCCESS) {
322
 
    fprintf(stderr, "Syntax error at: %s\n", err);
323
 
    fprintf(stderr, "GnuTLS error: %s\n",
324
 
            safer_gnutls_strerror(ret));
325
 
    return -1;
326
 
  }
327
 
  
328
 
  if ((ret = gnutls_credentials_set
329
 
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
330
 
      != GNUTLS_E_SUCCESS) {
331
 
    fprintf(stderr, "Error setting a credentials set: %s\n",
332
 
            safer_gnutls_strerror(ret));
333
 
    return -1;
334
 
  }
335
 
  
336
 
  /* ignore client certificate if any. */
337
 
  gnutls_certificate_server_set_request (es->session,
338
 
                                         GNUTLS_CERT_IGNORE);
339
 
  
340
 
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
341
 
  
342
 
  return 0;
343
 
}
344
 
 
345
 
void empty_log(__attribute__((unused)) AvahiLogLevel level,
346
 
               __attribute__((unused)) const char *txt){}
347
 
 
348
 
int start_mandos_communication(char *ip, uint16_t port,
349
 
                               unsigned int if_index){
350
 
  int ret, tcp_sd;
351
 
  struct sockaddr_in6 to;
352
 
  encrypted_session es;
353
 
  char *buffer = NULL;
354
 
  char *decrypted_buffer;
355
 
  size_t buffer_length = 0;
356
 
  size_t buffer_capacity = 0;
357
 
  ssize_t decrypted_buffer_size;
358
 
  int retval = 0;
359
 
  char interface[IF_NAMESIZE];
360
 
  
361
 
  if(debug){
362
 
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
363
 
  }
364
 
  
365
 
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
366
 
  if(tcp_sd < 0) {
367
 
    perror("socket");
368
 
    return -1;
369
 
  }
370
 
  
371
 
  if(if_indextoname(if_index, interface) == NULL){
372
 
    if(debug){
373
 
      perror("if_indextoname");
374
 
    }
375
 
    return -1;
376
 
  }
377
 
  
378
 
  if(debug){
379
 
    fprintf(stderr, "Binding to interface %s\n", interface);
380
 
  }
381
 
  
382
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
383
 
  if(ret < 0) {
384
 
    perror("setsockopt bindtodevice");
385
 
    return -1;
386
 
  }
387
 
  
388
 
  memset(&to,0,sizeof(to));
389
 
  to.sin6_family = AF_INET6;
390
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
391
 
  if (ret < 0 ){
392
 
    perror("inet_pton");
393
 
    return -1;
394
 
  }  
395
 
  if(ret == 0){
396
 
    fprintf(stderr, "Bad address: %s\n", ip);
397
 
    return -1;
398
 
  }
399
 
  /* Spurious warnings for the next line, see for instance
400
 
     <http://bugs.debian.org/488884> */
401
 
  to.sin6_port = htons(port);
402
 
  
403
 
  to.sin6_scope_id = (uint32_t)if_index;
404
 
  
405
 
  if(debug){
406
 
    fprintf(stderr, "Connection to: %s\n", ip);
407
 
  }
408
 
  
409
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
410
 
  if (ret < 0){
411
 
    perror("connect");
412
 
    return -1;
413
 
  }
414
 
  
415
 
  ret = initgnutls (&es);
416
 
  if (ret != 0){
417
 
    retval = -1;
418
 
    return -1;
419
 
  }
420
 
  
421
 
  gnutls_transport_set_ptr (es.session,
422
 
                            (gnutls_transport_ptr_t) tcp_sd);
423
 
  
424
 
  if(debug){
425
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
426
 
  }
427
 
  
428
 
  ret = gnutls_handshake (es.session);
429
 
  
430
 
  if (ret != GNUTLS_E_SUCCESS){
431
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
432
 
    gnutls_perror (ret);
433
 
    retval = -1;
434
 
    goto exit;
435
 
  }
436
 
  
437
 
  //Retrieve OpenPGP packet that contains the wanted password
438
 
  
439
 
  if(debug){
440
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
441
 
            ip);
442
 
  }
443
 
 
444
 
  while(true){
445
 
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
446
 
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
447
 
      if (buffer == NULL){
448
 
        perror("realloc");
449
 
        goto exit;
450
 
      }
451
 
      buffer_capacity += BUFFER_SIZE;
452
 
    }
453
 
    
454
 
    ret = gnutls_record_recv
455
 
      (es.session, buffer+buffer_length, BUFFER_SIZE);
456
 
    if (ret == 0){
457
 
      break;
458
 
    }
459
 
    if (ret < 0){
460
 
      switch(ret){
461
 
      case GNUTLS_E_INTERRUPTED:
462
 
      case GNUTLS_E_AGAIN:
463
 
        break;
464
 
      case GNUTLS_E_REHANDSHAKE:
465
 
        ret = gnutls_handshake (es.session);
466
 
        if (ret < 0){
467
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
468
 
          gnutls_perror (ret);
469
 
          retval = -1;
470
 
          goto exit;
471
 
        }
472
 
        break;
473
 
      default:
474
 
        fprintf(stderr, "Unknown error while reading data from"
475
 
                " encrypted session with mandos server\n");
476
 
        retval = -1;
477
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
478
 
        goto exit;
479
 
      }
480
 
    } else {
481
 
      buffer_length += (size_t) ret;
482
 
    }
483
 
  }
484
 
  
485
 
  if (buffer_length > 0){
486
 
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
487
 
                                               buffer_length,
488
 
                                               &decrypted_buffer,
489
 
                                               CERT_ROOT);
490
 
    if (decrypted_buffer_size >= 0){
491
 
      while(decrypted_buffer_size > 0){
492
 
        ret = fwrite (decrypted_buffer, 1, (size_t)decrypted_buffer_size,
493
 
                      stdout);
494
 
        if(ret == 0 and ferror(stdout)){
495
 
          if(debug){
496
 
            fprintf(stderr, "Error writing encrypted data: %s\n",
497
 
                    strerror(errno));
498
 
          }
499
 
          retval = -1;
500
 
          break;
501
 
        }
502
 
        decrypted_buffer += ret;
503
 
        decrypted_buffer_size -= ret;
504
 
      }
505
 
      free(decrypted_buffer);
506
 
    } else {
507
 
      retval = -1;
508
 
    }
509
 
  }
510
 
 
511
 
  //shutdown procedure
512
 
 
513
 
  if(debug){
514
 
    fprintf(stderr, "Closing TLS session\n");
515
 
  }
516
 
 
517
 
  free(buffer);
518
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
519
 
 exit:
520
 
  close(tcp_sd);
521
 
  gnutls_deinit (es.session);
522
 
  gnutls_certificate_free_credentials (es.cred);
523
 
  gnutls_global_deinit ();
524
 
  return retval;
525
 
}
526
 
 
527
 
static AvahiSimplePoll *simple_poll = NULL;
528
 
static AvahiServer *server = NULL;
529
 
 
530
 
static void resolve_callback(
531
 
    AvahiSServiceResolver *r,
532
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
533
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
534
 
    AvahiResolverEvent event,
535
 
    const char *name,
536
 
    const char *type,
537
 
    const char *domain,
538
 
    const char *host_name,
539
 
    const AvahiAddress *address,
540
 
    uint16_t port,
541
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
542
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
543
 
    AVAHI_GCC_UNUSED void* userdata) {
544
 
    
545
 
  assert(r);
546
 
 
547
 
  /* Called whenever a service has been resolved successfully or
548
 
     timed out */
549
 
 
550
 
  switch (event) {
551
 
  default:
552
 
  case AVAHI_RESOLVER_FAILURE:
553
 
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
554
 
            " type '%s' in domain '%s': %s\n", name, type, domain,
555
 
            avahi_strerror(avahi_server_errno(server)));
556
 
    break;
557
 
      
558
 
  case AVAHI_RESOLVER_FOUND:
559
 
    {
560
 
      char ip[AVAHI_ADDRESS_STR_MAX];
561
 
      avahi_address_snprint(ip, sizeof(ip), address);
562
 
      if(debug){
563
 
        fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
564
 
                host_name, ip, port);
565
 
      }
566
 
      int ret = start_mandos_communication(ip, port,
567
 
                                           (unsigned int)
568
 
                                           interface);
569
 
      if (ret == 0){
570
 
        exit(EXIT_SUCCESS);
571
 
      } else {
572
 
        exit(EXIT_FAILURE);
573
 
      }
574
 
    }
575
 
  }
576
 
  avahi_s_service_resolver_free(r);
577
 
}
578
 
 
579
 
static void browse_callback(
580
 
    AvahiSServiceBrowser *b,
581
 
    AvahiIfIndex interface,
582
 
    AvahiProtocol protocol,
583
 
    AvahiBrowserEvent event,
584
 
    const char *name,
585
 
    const char *type,
586
 
    const char *domain,
587
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
588
 
    void* userdata) {
589
 
    
590
 
    AvahiServer *s = userdata;
591
 
    assert(b);
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(server)));
602
 
      avahi_simple_poll_quit(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(s, interface, protocol, name,
612
 
                                         type, domain,
613
 
                                         AVAHI_PROTO_INET6, 0,
614
 
                                         resolve_callback, s)))
615
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
616
 
                avahi_strerror(avahi_server_errno(s)));
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
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
629
 
    AvahiServerConfig config;
630
 
    AvahiSServiceBrowser *sb = NULL;
631
 
    int error;
632
 
    int ret;
633
 
    int returncode = EXIT_SUCCESS;
634
 
    const char *interface = "eth0";
635
 
    
636
 
    while (true){
637
 
      static struct option long_options[] = {
638
 
        {"debug", no_argument, (int *)&debug, 1},
639
 
        {"interface", required_argument, 0, 'i'},
640
 
        {0, 0, 0, 0} };
641
 
 
642
 
      int option_index = 0;
643
 
      ret = getopt_long (argc, argv, "i:", long_options,
644
 
                         &option_index);
645
 
 
646
 
      if (ret == -1){
647
 
        break;
648
 
      }
649
 
      
650
 
      switch(ret){
651
 
      case 0:
652
 
        break;
653
 
      case 'i':
654
 
        interface = optarg;
655
 
        break;
656
 
      default:
657
 
        exit(EXIT_FAILURE);
658
 
      }
659
 
    }
660
 
    
661
 
    if (not debug){
662
 
      avahi_set_log_function(empty_log);
663
 
    }
664
 
    
665
 
    /* Initialize the psuedo-RNG */
666
 
    srand((unsigned int) time(NULL));
667
 
 
668
 
    /* Allocate main loop object */
669
 
    if (!(simple_poll = avahi_simple_poll_new())) {
670
 
        fprintf(stderr, "Failed to create simple poll object.\n");
671
 
        
672
 
        goto exit;
673
 
    }
674
 
 
675
 
    /* Do not publish any local records */
676
 
    avahi_server_config_init(&config);
677
 
    config.publish_hinfo = 0;
678
 
    config.publish_addresses = 0;
679
 
    config.publish_workstation = 0;
680
 
    config.publish_domain = 0;
681
 
 
682
 
    /* Allocate a new server */
683
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
684
 
                              &config, NULL, NULL, &error);
685
 
 
686
 
    /* Free the configuration data */
687
 
    avahi_server_config_free(&config);
688
 
 
689
 
    /* Check if creating the server object succeeded */
690
 
    if (!server) {
691
 
        fprintf(stderr, "Failed to create server: %s\n",
692
 
                avahi_strerror(error));
693
 
        returncode = EXIT_FAILURE;
694
 
        goto exit;
695
 
    }
696
 
    
697
 
    /* Create the service browser */
698
 
    sb = avahi_s_service_browser_new(server,
699
 
                                     (AvahiIfIndex)
700
 
                                     if_nametoindex(interface),
701
 
                                     AVAHI_PROTO_INET6,
702
 
                                     "_mandos._tcp", NULL, 0,
703
 
                                     browse_callback, server);
704
 
    if (!sb) {
705
 
        fprintf(stderr, "Failed to create service browser: %s\n",
706
 
                avahi_strerror(avahi_server_errno(server)));
707
 
        returncode = EXIT_FAILURE;
708
 
        goto exit;
709
 
    }
710
 
    
711
 
    /* Run the main loop */
712
 
 
713
 
    if (debug){
714
 
      fprintf(stderr, "Starting avahi loop search\n");
715
 
    }
716
 
    
717
 
    avahi_simple_poll_loop(simple_poll);
718
 
    
719
 
 exit:
720
 
 
721
 
    if (debug){
722
 
      fprintf(stderr, "%s exiting\n", argv[0]);
723
 
    }
724
 
    
725
 
    /* Cleanup things */
726
 
    if (sb)
727
 
        avahi_s_service_browser_free(sb);
728
 
    
729
 
    if (server)
730
 
        avahi_server_free(server);
731
 
 
732
 
    if (simple_poll)
733
 
        avahi_simple_poll_free(simple_poll);
734
 
 
735
 
    return returncode;
736
 
}