/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-21 04:42:08 UTC
  • mfrom: (15.1.3 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080721044208-y8v1sjmvalfiehrv
Merge.

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
***/
 
19
 
 
20
#define _LARGEFILE_SOURCE
 
21
#define _FILE_OFFSET_BITS 64
 
22
 
 
23
#include <stdio.h>
 
24
#include <assert.h>
 
25
#include <stdlib.h>
 
26
#include <time.h>
 
27
#include <net/if.h>             /* if_nametoindex */
 
28
 
 
29
#include <avahi-core/core.h>
 
30
#include <avahi-core/lookup.h>
 
31
#include <avahi-core/log.h>
 
32
#include <avahi-common/simple-watch.h>
 
33
#include <avahi-common/malloc.h>
 
34
#include <avahi-common/error.h>
 
35
 
 
36
//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 */
 
41
 
 
42
#include <unistd.h>             /* close() */
 
43
#include <netinet/in.h>
 
44
#include <stdbool.h>            /* true */
 
45
#include <string.h>             /* memset */
 
46
#include <arpa/inet.h>          /* inet_pton() */
 
47
#include <iso646.h>             /* not */
 
48
 
 
49
// gpgme
 
50
#include <errno.h>              /* perror() */
 
51
#include <gpgme.h>
 
52
 
 
53
// getopt long
 
54
#include <getopt.h>
 
55
 
 
56
#ifndef CERT_ROOT
 
57
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
 
58
#endif
 
59
#define CERTFILE CERT_ROOT "openpgp-client.txt"
 
60
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
 
61
#define BUFFER_SIZE 256
 
62
#define DH_BITS 1024
 
63
 
 
64
bool debug = false;
 
65
char *interface = "eth0";
 
66
 
 
67
typedef struct {
 
68
  gnutls_session_t session;
 
69
  gnutls_certificate_credentials_t cred;
 
70
  gnutls_dh_params_t dh_params;
 
71
} encrypted_session;
 
72
 
 
73
 
 
74
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
 
75
  gpgme_data_t dh_crypto, dh_plain;
 
76
  gpgme_ctx_t ctx;
 
77
  gpgme_error_t rc;
 
78
  ssize_t ret;
 
79
  size_t new_packet_capacity = 0;
 
80
  size_t new_packet_length = 0;
 
81
  gpgme_engine_info_t engine_info;
 
82
 
 
83
  if (debug){
 
84
    fprintf(stderr, "Attempting to decrypt password from gpg packet\n");
 
85
  }
 
86
  
 
87
  /* Init GPGME */
 
88
  gpgme_check_version(NULL);
 
89
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
90
  
 
91
  /* Set GPGME home directory */
 
92
  rc = gpgme_get_engine_info (&engine_info);
 
93
  if (rc != GPG_ERR_NO_ERROR){
 
94
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
 
95
            gpgme_strsource(rc), gpgme_strerror(rc));
 
96
    return -1;
 
97
  }
 
98
  while(engine_info != NULL){
 
99
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
 
100
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
 
101
                            engine_info->file_name, homedir);
 
102
      break;
 
103
    }
 
104
    engine_info = engine_info->next;
 
105
  }
 
106
  if(engine_info == NULL){
 
107
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
 
108
    return -1;
 
109
  }
 
110
  
 
111
  /* Create new GPGME data buffer from packet buffer */
 
112
  rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
 
113
  if (rc != GPG_ERR_NO_ERROR){
 
114
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
 
115
            gpgme_strsource(rc), gpgme_strerror(rc));
 
116
    return -1;
 
117
  }
 
118
  
 
119
  /* Create new empty GPGME data buffer for the plaintext */
 
120
  rc = gpgme_data_new(&dh_plain);
 
121
  if (rc != GPG_ERR_NO_ERROR){
 
122
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
 
123
            gpgme_strsource(rc), gpgme_strerror(rc));
 
124
    return -1;
 
125
  }
 
126
  
 
127
  /* Create new GPGME "context" */
 
128
  rc = gpgme_new(&ctx);
 
129
  if (rc != GPG_ERR_NO_ERROR){
 
130
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
 
131
            gpgme_strsource(rc), gpgme_strerror(rc));
 
132
    return -1;
 
133
  }
 
134
  
 
135
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
136
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
 
137
  if (rc != GPG_ERR_NO_ERROR){
 
138
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
 
139
            gpgme_strsource(rc), gpgme_strerror(rc));
 
140
    return -1;
 
141
  }
 
142
 
 
143
  if(debug){
 
144
    fprintf(stderr, "decryption of gpg packet succeeded\n");
 
145
  }
 
146
 
 
147
  if (debug){
 
148
    gpgme_decrypt_result_t result;
 
149
    result = gpgme_op_decrypt_result(ctx);
 
150
    if (result == NULL){
 
151
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
152
    } else {
 
153
      fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
 
154
      fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
 
155
      if(result->file_name != NULL){
 
156
        fprintf(stderr, "File name: %s\n", result->file_name);
 
157
      }
 
158
      gpgme_recipient_t recipient;
 
159
      recipient = result->recipients;
 
160
      if(recipient){
 
161
        while(recipient != NULL){
 
162
          fprintf(stderr, "Public key algorithm: %s\n",
 
163
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
164
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
165
          fprintf(stderr, "Secret key available: %s\n",
 
166
                  recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
 
167
          recipient = recipient->next;
 
168
        }
 
169
      }
 
170
    }
 
171
  }
 
172
  
 
173
  /* Delete the GPGME FILE pointer cryptotext data buffer */
 
174
  gpgme_data_release(dh_crypto);
 
175
  
 
176
  /* Seek back to the beginning of the GPGME plaintext data buffer */
 
177
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
178
 
 
179
  *new_packet = 0;
 
180
  while(true){
 
181
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
 
182
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
 
183
      if (*new_packet == NULL){
 
184
        perror("realloc");
 
185
        return -1;
 
186
      }
 
187
      new_packet_capacity += BUFFER_SIZE;
 
188
    }
 
189
    
 
190
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
 
191
    /* Print the data, if any */
 
192
    if (ret == 0){
 
193
      /* If password is empty, then a incorrect error will be printed */
 
194
      break;
 
195
    }
 
196
    if(ret < 0){
 
197
      perror("gpgme_data_read");
 
198
      return -1;
 
199
    }
 
200
    new_packet_length += ret;
 
201
  }
 
202
 
 
203
  /* FIXME: check characters before printing to screen so to not print
 
204
     terminal control characters */
 
205
  /*   if(debug){ */
 
206
  /*     fprintf(stderr, "decrypted password is: "); */
 
207
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
 
208
  /*     fprintf(stderr, "\n"); */
 
209
  /*   } */
 
210
  
 
211
  /* Delete the GPGME plaintext data buffer */
 
212
  gpgme_data_release(dh_plain);
 
213
  return new_packet_length;
 
214
}
 
215
 
 
216
static const char * safer_gnutls_strerror (int value) {
 
217
  const char *ret = gnutls_strerror (value);
 
218
  if (ret == NULL)
 
219
    ret = "(unknown)";
 
220
  return ret;
 
221
}
 
222
 
 
223
void debuggnutls(int level, const char* string){
 
224
  fprintf(stderr, "%s", string);
 
225
}
 
226
 
 
227
int initgnutls(encrypted_session *es){
 
228
  const char *err;
 
229
  int ret;
 
230
 
 
231
  if(debug){
 
232
    fprintf(stderr, "Initializing gnutls\n");
 
233
  }
 
234
 
 
235
  
 
236
  if ((ret = gnutls_global_init ())
 
237
      != GNUTLS_E_SUCCESS) {
 
238
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
 
239
    return -1;
 
240
  }
 
241
 
 
242
  if (debug){
 
243
    gnutls_global_set_log_level(11);
 
244
    gnutls_global_set_log_function(debuggnutls);
 
245
  }
 
246
  
 
247
 
 
248
  /* openpgp credentials */
 
249
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
 
250
      != GNUTLS_E_SUCCESS) {
 
251
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
252
    return -1;
 
253
  }
 
254
 
 
255
  if(debug){
 
256
    fprintf(stderr, "Attempting to use openpgp certificate %s"
 
257
            " and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
 
258
  }
 
259
 
 
260
  ret = gnutls_certificate_set_openpgp_key_file
 
261
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
 
262
  if (ret != GNUTLS_E_SUCCESS) {
 
263
    fprintf
 
264
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
 
265
       ret, CERTFILE, KEYFILE);
 
266
    fprintf(stdout, "The Error is: %s\n",
 
267
            safer_gnutls_strerror(ret));
 
268
    return -1;
 
269
  }
 
270
 
 
271
  //Gnutls server initialization
 
272
  if ((ret = gnutls_dh_params_init (&es->dh_params))
 
273
      != GNUTLS_E_SUCCESS) {
 
274
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
 
275
             safer_gnutls_strerror(ret));
 
276
    return -1;
 
277
  }
 
278
 
 
279
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
 
280
      != GNUTLS_E_SUCCESS) {
 
281
    fprintf (stderr, "Error in prime generation: %s\n",
 
282
             safer_gnutls_strerror(ret));
 
283
    return -1;
 
284
  }
 
285
 
 
286
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
 
287
 
 
288
  // Gnutls session creation
 
289
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
 
290
      != GNUTLS_E_SUCCESS){
 
291
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
292
            safer_gnutls_strerror(ret));
 
293
  }
 
294
 
 
295
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
 
296
      != GNUTLS_E_SUCCESS) {
 
297
    fprintf(stderr, "Syntax error at: %s\n", err);
 
298
    fprintf(stderr, "Gnutls error: %s\n",
 
299
            safer_gnutls_strerror(ret));
 
300
    return -1;
 
301
  }
 
302
 
 
303
  if ((ret = gnutls_credentials_set
 
304
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
 
305
      != GNUTLS_E_SUCCESS) {
 
306
    fprintf(stderr, "Error setting a credentials set: %s\n",
 
307
            safer_gnutls_strerror(ret));
 
308
    return -1;
 
309
  }
 
310
 
 
311
  /* ignore client certificate if any. */
 
312
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
313
  
 
314
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
 
315
  
 
316
  return 0;
 
317
}
 
318
 
 
319
void empty_log(AvahiLogLevel level, const char *txt){}
 
320
 
 
321
int start_mandos_communication(char *ip, uint16_t port){
 
322
  int ret, tcp_sd;
 
323
  struct sockaddr_in6 to;
 
324
  encrypted_session es;
 
325
  char *buffer = NULL;
 
326
  char *decrypted_buffer;
 
327
  size_t buffer_length = 0;
 
328
  size_t buffer_capacity = 0;
 
329
  ssize_t decrypted_buffer_size;
 
330
  int retval = 0;
 
331
 
 
332
  if(debug){
 
333
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
 
334
  }
 
335
  
 
336
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
 
337
  if(tcp_sd < 0) {
 
338
    perror("socket");
 
339
    return -1;
 
340
  }
 
341
 
 
342
  if(debug){
 
343
    fprintf(stderr, "Binding to interface %s\n", interface);
 
344
  }
 
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
  
 
352
  memset(&to,0,sizeof(to));
 
353
  to.sin6_family = AF_INET6;
 
354
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
355
  if (ret < 0 ){
 
356
    perror("inet_pton");
 
357
    return -1;
 
358
  }  
 
359
  if(ret == 0){
 
360
    fprintf(stderr, "Bad address: %s\n", ip);
 
361
    return -1;
 
362
  }
 
363
  to.sin6_port = htons(port);
 
364
  to.sin6_scope_id = if_nametoindex(interface);
 
365
 
 
366
  if(debug){
 
367
    fprintf(stderr, "Connection to: %s\n", ip);
 
368
  }
 
369
  
 
370
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
 
371
  if (ret < 0){
 
372
    perror("connect");
 
373
    return -1;
 
374
  }
 
375
  
 
376
  ret = initgnutls (&es);
 
377
  if (ret != 0){
 
378
    retval = -1;
 
379
    return -1;
 
380
  }
 
381
    
 
382
  
 
383
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
 
384
 
 
385
  if(debug){
 
386
    fprintf(stderr, "Establishing tls session with %s\n", ip);
 
387
  }
 
388
 
 
389
  
 
390
  ret = gnutls_handshake (es.session);
 
391
  
 
392
  if (ret != GNUTLS_E_SUCCESS){
 
393
    fprintf(stderr, "\n*** Handshake failed ***\n");
 
394
    gnutls_perror (ret);
 
395
    retval = -1;
 
396
    goto exit;
 
397
  }
 
398
 
 
399
  //Retrieve gpg packet that contains the wanted password
 
400
 
 
401
  if(debug){
 
402
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
 
403
  }
 
404
 
 
405
  while(true){
 
406
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
 
407
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
 
408
      if (buffer == NULL){
 
409
        perror("realloc");
 
410
        goto exit;
 
411
      }
 
412
      buffer_capacity += BUFFER_SIZE;
 
413
    }
 
414
    
 
415
    ret = gnutls_record_recv
 
416
      (es.session, buffer+buffer_length, BUFFER_SIZE);
 
417
    if (ret == 0){
 
418
      break;
 
419
    }
 
420
    if (ret < 0){
 
421
      switch(ret){
 
422
      case GNUTLS_E_INTERRUPTED:
 
423
      case GNUTLS_E_AGAIN:
 
424
        break;
 
425
      case GNUTLS_E_REHANDSHAKE:
 
426
        ret = gnutls_handshake (es.session);
 
427
        if (ret < 0){
 
428
          fprintf(stderr, "\n*** Handshake failed ***\n");
 
429
          gnutls_perror (ret);
 
430
          retval = -1;
 
431
          goto exit;
 
432
        }
 
433
        break;
 
434
      default:
 
435
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
436
        retval = -1;
 
437
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
438
        goto exit;
 
439
      }
 
440
    } else {
 
441
      buffer_length += ret;
 
442
    }
 
443
  }
 
444
  
 
445
  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);
 
448
      free(decrypted_buffer);
 
449
    } else {
 
450
      retval = -1;
 
451
    }
 
452
  }
 
453
 
 
454
  //shutdown procedure
 
455
 
 
456
  if(debug){
 
457
    fprintf(stderr, "Closing tls session\n");
 
458
  }
 
459
 
 
460
  free(buffer);
 
461
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
462
 exit:
 
463
  close(tcp_sd);
 
464
  gnutls_deinit (es.session);
 
465
  gnutls_certificate_free_credentials (es.cred);
 
466
  gnutls_global_deinit ();
 
467
  return retval;
 
468
}
 
469
 
 
470
static AvahiSimplePoll *simple_poll = NULL;
 
471
static AvahiServer *server = NULL;
 
472
 
 
473
static void resolve_callback(
 
474
    AvahiSServiceResolver *r,
 
475
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
476
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
477
    AvahiResolverEvent event,
 
478
    const char *name,
 
479
    const char *type,
 
480
    const char *domain,
 
481
    const char *host_name,
 
482
    const AvahiAddress *address,
 
483
    uint16_t port,
 
484
    AvahiStringList *txt,
 
485
    AvahiLookupResultFlags flags,
 
486
    AVAHI_GCC_UNUSED void* userdata) {
 
487
    
 
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
        }
 
510
    }
 
511
    avahi_s_service_resolver_free(r);
 
512
}
 
513
 
 
514
static void browse_callback(
 
515
    AvahiSServiceBrowser *b,
 
516
    AvahiIfIndex interface,
 
517
    AvahiProtocol protocol,
 
518
    AvahiBrowserEvent event,
 
519
    const char *name,
 
520
    const char *type,
 
521
    const char *domain,
 
522
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
523
    void* userdata) {
 
524
    
 
525
    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
 
 
530
    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;
 
555
    }
 
556
}
 
557
 
 
558
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
 
559
    AvahiServerConfig config;
 
560
    AvahiSServiceBrowser *sb = NULL;
 
561
    int error;
 
562
    int ret;
 
563
    int returncode = EXIT_SUCCESS;
 
564
 
 
565
    while (true){
 
566
      static struct option long_options[] = {
 
567
        {"debug", no_argument, (int *)&debug, 1},
 
568
        {"interface", required_argument, 0, 'i'},
 
569
        {0, 0, 0, 0} };
 
570
 
 
571
      int option_index = 0;
 
572
      ret = getopt_long (argc, argv, "i:", long_options, &option_index);
 
573
 
 
574
      if (ret == -1){
 
575
        break;
 
576
      }
 
577
      
 
578
      switch(ret){
 
579
      case 0:
 
580
        break;
 
581
      case 'i':
 
582
        interface = optarg;
 
583
        break;
 
584
      default:
 
585
        exit(EXIT_FAILURE);
 
586
      }
 
587
    }
 
588
    
 
589
    if (not debug){
 
590
      avahi_set_log_function(empty_log);
 
591
    }
 
592
    
 
593
    /* Initialize the psuedo-RNG */
 
594
    srand(time(NULL));
 
595
 
 
596
    /* Allocate main loop object */
 
597
    if (!(simple_poll = avahi_simple_poll_new())) {
 
598
        fprintf(stderr, "Failed to create simple poll object.\n");
 
599
        
 
600
        goto exit;
 
601
    }
 
602
 
 
603
    /* Do not publish any local records */
 
604
    avahi_server_config_init(&config);
 
605
    config.publish_hinfo = 0;
 
606
    config.publish_addresses = 0;
 
607
    config.publish_workstation = 0;
 
608
    config.publish_domain = 0;
 
609
 
 
610
    /* Allocate a new server */
 
611
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
612
 
 
613
    /* Free the configuration data */
 
614
    avahi_server_config_free(&config);
 
615
 
 
616
    /* Check if creating the server object succeeded */
 
617
    if (!server) {
 
618
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
619
        returncode = EXIT_FAILURE;
 
620
        goto exit;
 
621
    }
 
622
    
 
623
    /* 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)));
 
626
        returncode = EXIT_FAILURE;
 
627
        goto exit;
 
628
    }
 
629
    
 
630
    /* Run the main loop */
 
631
 
 
632
    if (debug){
 
633
      fprintf(stderr, "Starting avahi loop search\n");
 
634
    }
 
635
    
 
636
    avahi_simple_poll_loop(simple_poll);
 
637
    
 
638
exit:
 
639
 
 
640
    if (debug){
 
641
      fprintf(stderr, "%s exiting\n", argv[0]);
 
642
    }
 
643
    
 
644
    /* Cleanup things */
 
645
    if (sb)
 
646
        avahi_s_service_browser_free(sb);
 
647
    
 
648
    if (server)
 
649
        avahi_server_free(server);
 
650
 
 
651
    if (simple_poll)
 
652
        avahi_simple_poll_free(simple_poll);
 
653
 
 
654
    return returncode;
 
655
}