/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 23:18:02 UTC
  • mfrom: (15.1.5 mandos) (15.1.5 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080721231802-0emzdsxkfy457p9u
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
 
***/
 
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>
50
65
#include <errno.h>              /* perror() */
51
66
#include <gpgme.h>
52
67
 
 
68
// getopt long
 
69
#include <getopt.h>
53
70
 
54
71
#ifndef CERT_ROOT
55
72
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
68
85
} encrypted_session;
69
86
 
70
87
 
71
 
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){
72
90
  gpgme_data_t dh_crypto, dh_plain;
73
91
  gpgme_ctx_t ctx;
74
92
  gpgme_error_t rc;
75
93
  ssize_t ret;
76
 
  size_t new_packet_capacity = 0;
77
 
  size_t new_packet_length = 0;
 
94
  ssize_t new_packet_capacity = 0;
 
95
  ssize_t new_packet_length = 0;
78
96
  gpgme_engine_info_t engine_info;
79
97
 
80
98
  if (debug){
81
 
    fprintf(stderr, "Attempting to decrypt password from gpg packet\n");
 
99
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
82
100
  }
83
101
  
84
102
  /* Init GPGME */
129
147
    return -1;
130
148
  }
131
149
  
132
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
150
  /* Decrypt data from the FILE pointer to the plaintext data
 
151
     buffer */
133
152
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
134
153
  if (rc != GPG_ERR_NO_ERROR){
135
154
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
138
157
  }
139
158
 
140
159
  if(debug){
141
 
    fprintf(stderr, "decryption of gpg packet succeeded\n");
 
160
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
142
161
  }
143
162
 
144
163
  if (debug){
147
166
    if (result == NULL){
148
167
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
149
168
    } else {
150
 
      fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
151
 
      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);
152
173
      if(result->file_name != NULL){
153
174
        fprintf(stderr, "File name: %s\n", result->file_name);
154
175
      }
160
181
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
161
182
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
162
183
          fprintf(stderr, "Secret key available: %s\n",
163
 
                  recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
 
184
                  recipient->status == GPG_ERR_NO_SECKEY
 
185
                  ? "No" : "Yes");
164
186
          recipient = recipient->next;
165
187
        }
166
188
      }
171
193
  gpgme_data_release(dh_crypto);
172
194
  
173
195
  /* Seek back to the beginning of the GPGME plaintext data buffer */
174
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
196
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
175
197
 
176
198
  *new_packet = 0;
177
199
  while(true){
178
200
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
179
 
      *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);
180
204
      if (*new_packet == NULL){
181
205
        perror("realloc");
182
206
        return -1;
184
208
      new_packet_capacity += BUFFER_SIZE;
185
209
    }
186
210
    
187
 
    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);
188
213
    /* Print the data, if any */
189
214
    if (ret == 0){
190
 
      /* If password is empty, then a incorrect error will be printed */
191
215
      break;
192
216
    }
193
217
    if(ret < 0){
197
221
    new_packet_length += ret;
198
222
  }
199
223
 
200
 
  if(debug){
201
 
    fprintf(stderr, "decrypted password is: %s\n", *new_packet);
202
 
  }
203
 
 
204
 
   /* Delete the GPGME plaintext data buffer */
 
224
  /* FIXME: check characters before printing to screen so to not print
 
225
     terminal control characters */
 
226
  /*   if(debug){ */
 
227
  /*     fprintf(stderr, "decrypted password is: "); */
 
228
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
 
229
  /*     fprintf(stderr, "\n"); */
 
230
  /*   } */
 
231
  
 
232
  /* Delete the GPGME plaintext data buffer */
205
233
  gpgme_data_release(dh_plain);
206
234
  return new_packet_length;
207
235
}
213
241
  return ret;
214
242
}
215
243
 
216
 
void debuggnutls(int level, const char* string){
 
244
void debuggnutls(__attribute__((unused)) int level,
 
245
                 const char* string){
217
246
  fprintf(stderr, "%s", string);
218
247
}
219
248
 
220
249
int initgnutls(encrypted_session *es){
221
250
  const char *err;
222
251
  int ret;
223
 
 
 
252
  
224
253
  if(debug){
225
 
    fprintf(stderr, "Initializing gnutls\n");
 
254
    fprintf(stderr, "Initializing GnuTLS\n");
226
255
  }
227
 
 
228
256
  
229
257
  if ((ret = gnutls_global_init ())
230
258
      != GNUTLS_E_SUCCESS) {
237
265
    gnutls_global_set_log_function(debuggnutls);
238
266
  }
239
267
  
240
 
 
241
268
  /* openpgp credentials */
242
269
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
243
270
      != GNUTLS_E_SUCCESS) {
244
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
271
    fprintf (stderr, "memory error: %s\n",
 
272
             safer_gnutls_strerror(ret));
245
273
    return -1;
246
274
  }
247
 
 
 
275
  
248
276
  if(debug){
249
 
    fprintf(stderr, "Attempting to use openpgp certificate %s"
250
 
            " 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);
251
280
  }
252
 
 
 
281
  
253
282
  ret = gnutls_certificate_set_openpgp_key_file
254
283
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
255
284
  if (ret != GNUTLS_E_SUCCESS) {
256
285
    fprintf
257
 
      (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",
258
288
       ret, CERTFILE, KEYFILE);
259
289
    fprintf(stdout, "The Error is: %s\n",
260
290
            safer_gnutls_strerror(ret));
261
291
    return -1;
262
292
  }
263
 
 
264
 
  //Gnutls server initialization
 
293
  
 
294
  //GnuTLS server initialization
265
295
  if ((ret = gnutls_dh_params_init (&es->dh_params))
266
296
      != GNUTLS_E_SUCCESS) {
267
297
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
268
298
             safer_gnutls_strerror(ret));
269
299
    return -1;
270
300
  }
271
 
 
 
301
  
272
302
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
273
303
      != GNUTLS_E_SUCCESS) {
274
304
    fprintf (stderr, "Error in prime generation: %s\n",
275
305
             safer_gnutls_strerror(ret));
276
306
    return -1;
277
307
  }
278
 
 
 
308
  
279
309
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
280
 
 
281
 
  // Gnutls session creation
 
310
  
 
311
  // GnuTLS session creation
282
312
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
283
313
      != GNUTLS_E_SUCCESS){
284
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
314
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
285
315
            safer_gnutls_strerror(ret));
286
316
  }
287
 
 
 
317
  
288
318
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
289
319
      != GNUTLS_E_SUCCESS) {
290
320
    fprintf(stderr, "Syntax error at: %s\n", err);
291
 
    fprintf(stderr, "Gnutls error: %s\n",
 
321
    fprintf(stderr, "GnuTLS error: %s\n",
292
322
            safer_gnutls_strerror(ret));
293
323
    return -1;
294
324
  }
295
 
 
 
325
  
296
326
  if ((ret = gnutls_credentials_set
297
327
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
298
328
      != GNUTLS_E_SUCCESS) {
300
330
            safer_gnutls_strerror(ret));
301
331
    return -1;
302
332
  }
303
 
 
 
333
  
304
334
  /* ignore client certificate if any. */
305
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
335
  gnutls_certificate_server_set_request (es->session,
 
336
                                         GNUTLS_CERT_IGNORE);
306
337
  
307
338
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
308
339
  
309
340
  return 0;
310
341
}
311
342
 
312
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
343
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
344
               __attribute__((unused)) const char *txt){}
313
345
 
314
 
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){
315
348
  int ret, tcp_sd;
316
349
  struct sockaddr_in6 to;
317
350
  encrypted_session es;
320
353
  size_t buffer_length = 0;
321
354
  size_t buffer_capacity = 0;
322
355
  ssize_t decrypted_buffer_size;
 
356
  size_t written = 0;
323
357
  int retval = 0;
324
 
  const char interface[] = "eth0";
325
 
 
 
358
  char interface[IF_NAMESIZE];
 
359
  
326
360
  if(debug){
327
361
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
328
362
  }
332
366
    perror("socket");
333
367
    return -1;
334
368
  }
335
 
 
 
369
  
 
370
  if(if_indextoname(if_index, interface) == NULL){
 
371
    if(debug){
 
372
      perror("if_indextoname");
 
373
    }
 
374
    return -1;
 
375
  }
 
376
  
336
377
  if(debug){
337
378
    fprintf(stderr, "Binding to interface %s\n", interface);
338
379
  }
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
380
  
346
 
  memset(&to,0,sizeof(to));
 
381
  memset(&to,0,sizeof(to));     /* Spurious warning */
347
382
  to.sin6_family = AF_INET6;
348
383
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
349
384
  if (ret < 0 ){
354
389
    fprintf(stderr, "Bad address: %s\n", ip);
355
390
    return -1;
356
391
  }
357
 
  to.sin6_port = htons(port);
358
 
  to.sin6_scope_id = if_nametoindex(interface);
359
 
 
 
392
  to.sin6_port = htons(port);   /* Spurious warning */
 
393
  
 
394
  to.sin6_scope_id = (uint32_t)if_index;
 
395
  
360
396
  if(debug){
361
397
    fprintf(stderr, "Connection to: %s\n", ip);
362
398
  }
372
408
    retval = -1;
373
409
    return -1;
374
410
  }
375
 
    
376
 
  
377
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
378
 
 
 
411
  
 
412
  gnutls_transport_set_ptr (es.session,
 
413
                            (gnutls_transport_ptr_t) tcp_sd);
 
414
  
379
415
  if(debug){
380
 
    fprintf(stderr, "Establishing tls session with %s\n", ip);
 
416
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
381
417
  }
382
 
 
383
418
  
384
419
  ret = gnutls_handshake (es.session);
385
420
  
389
424
    retval = -1;
390
425
    goto exit;
391
426
  }
392
 
 
393
 
  //Retrieve gpg packet that contains the wanted password
394
 
 
 
427
  
 
428
  //Retrieve OpenPGP packet that contains the wanted password
 
429
  
395
430
  if(debug){
396
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
 
431
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
432
            ip);
397
433
  }
398
434
 
399
435
  while(true){
426
462
        }
427
463
        break;
428
464
      default:
429
 
        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");
430
467
        retval = -1;
431
468
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
432
469
        goto exit;
433
470
      }
434
471
    } else {
435
 
      buffer_length += ret;
 
472
      buffer_length += (size_t) ret;
436
473
    }
437
474
  }
438
475
  
439
476
  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);
 
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
      }
442
496
      free(decrypted_buffer);
443
497
    } else {
444
498
      retval = -1;
448
502
  //shutdown procedure
449
503
 
450
504
  if(debug){
451
 
    fprintf(stderr, "Closing tls session\n");
 
505
    fprintf(stderr, "Closing TLS session\n");
452
506
  }
453
507
 
454
508
  free(buffer);
466
520
 
467
521
static void resolve_callback(
468
522
    AvahiSServiceResolver *r,
469
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
523
    AvahiIfIndex interface,
470
524
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
471
525
    AvahiResolverEvent event,
472
526
    const char *name,
475
529
    const char *host_name,
476
530
    const AvahiAddress *address,
477
531
    uint16_t port,
478
 
    AvahiStringList *txt,
479
 
    AvahiLookupResultFlags flags,
 
532
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
533
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
480
534
    AVAHI_GCC_UNUSED void* userdata) {
481
535
    
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_communcation(ip, port);
498
 
            if (ret == 0){
499
 
              exit(EXIT_SUCCESS);
500
 
            } else {
501
 
              exit(EXIT_FAILURE);
502
 
            }
503
 
        }
 
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
      }
504
564
    }
505
 
    avahi_s_service_resolver_free(r);
 
565
  }
 
566
  avahi_s_service_resolver_free(r);
506
567
}
507
568
 
508
569
static void browse_callback(
517
578
    void* userdata) {
518
579
    
519
580
    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
 
 
 
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
    
524
586
    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;
 
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;
549
615
    }
550
616
}
551
617
 
552
618
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
553
619
    AvahiServerConfig config;
554
620
    AvahiSServiceBrowser *sb = NULL;
555
 
    const char db[] = "--debug";
556
621
    int error;
557
 
    int ret = 1;
 
622
    int ret;
558
623
    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
 
 
 
624
    const char *interface = "eth0";
 
625
    
 
626
    while (true){
 
627
      static struct option long_options[] = {
 
628
        {"debug", no_argument, (int *)&debug, 1},
 
629
        {"interface", required_argument, 0, 'i'},
 
630
        {0, 0, 0, 0} };
 
631
      
 
632
      int option_index = 0;
 
633
      ret = getopt_long (argc, argv, "i:", long_options,
 
634
                         &option_index);
 
635
      
 
636
      if (ret == -1){
 
637
        break;
 
638
      }
 
639
      
 
640
      switch(ret){
 
641
      case 0:
 
642
        break;
 
643
      case 'i':
 
644
        interface = optarg;
 
645
        break;
 
646
      default:
 
647
        exit(EXIT_FAILURE);
 
648
      }
 
649
    }
 
650
    
585
651
    if (not debug){
586
652
      avahi_set_log_function(empty_log);
587
653
    }
588
654
    
589
655
    /* Initialize the psuedo-RNG */
590
 
    srand(time(NULL));
 
656
    srand((unsigned int) time(NULL));
591
657
 
592
658
    /* Allocate main loop object */
593
659
    if (!(simple_poll = avahi_simple_poll_new())) {
604
670
    config.publish_domain = 0;
605
671
 
606
672
    /* Allocate a new server */
607
 
    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);
608
675
 
609
676
    /* Free the configuration data */
610
677
    avahi_server_config_free(&config);
611
678
 
612
679
    /* Check if creating the server object succeeded */
613
680
    if (!server) {
614
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
681
        fprintf(stderr, "Failed to create server: %s\n",
 
682
                avahi_strerror(error));
615
683
        returncode = EXIT_FAILURE;
616
684
        goto exit;
617
685
    }
618
686
    
619
687
    /* 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)));
 
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)));
622
697
        returncode = EXIT_FAILURE;
623
698
        goto exit;
624
699
    }
631
706
    
632
707
    avahi_simple_poll_loop(simple_poll);
633
708
    
634
 
exit:
 
709
 exit:
635
710
 
636
711
    if (debug){
637
712
      fprintf(stderr, "%s exiting\n", argv[0]);
647
722
    if (simple_poll)
648
723
        avahi_simple_poll_free(simple_poll);
649
724
 
650
 
    return ret;
 
725
    return returncode;
651
726
}