/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 02:35:05 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080721023505-x7pjntkgur2h5jkg
* plugins.d/mandosclient.c (start_mandos_communcation): Renamed to
                                          "start_mandos_communication"

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