/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/mandosclient.c

  • Committer: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support:
Pluginbased client handler
rewritten Mandos client
       Avahi instead of udp server discovery
       openpgp encrypted key support
Passprompt stand alone application for direct console input
Added logging for Mandos server

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
 
1
/* $Id$ */
 
2
 
 
3
/* PLEASE NOTE *
 
4
 * This file demonstrates how to use Avahi's core API, this is
 
5
 * the embeddable mDNS stack for embedded applications.
4
6
 *
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/>.
 
7
 * End user applications should *not* use this API and should use
 
8
 * the D-Bus or C APIs, please see
 
9
 * client-browse-services.c and glib-integration.c
 
10
 * 
 
11
 * I repeat, you probably do *not* want to use this example.
30
12
 */
31
13
 
32
 
#define _FORTIFY_SOURCE 2
 
14
/***
 
15
  This file is part of avahi.
 
16
 
 
17
  avahi is free software; you can redistribute it and/or modify it
 
18
  under the terms of the GNU Lesser General Public License as
 
19
  published by the Free Software Foundation; either version 2.1 of the
 
20
  License, or (at your option) any later version.
 
21
 
 
22
  avahi is distributed in the hope that it will be useful, but WITHOUT
 
23
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
24
  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
 
25
  Public License for more details.
 
26
 
 
27
  You should have received a copy of the GNU Lesser General Public
 
28
  License along with avahi; if not, write to the Free Software
 
29
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
30
  USA.
 
31
***/
33
32
 
34
33
#define _LARGEFILE_SOURCE
35
34
#define _FILE_OFFSET_BITS 64
48
47
#include <avahi-common/error.h>
49
48
 
50
49
//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 */
 
50
#include <sys/types.h>          /* socket(), setsockopt(), inet_pton() */
 
51
#include <sys/socket.h>         /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */
 
52
#include <gnutls/gnutls.h>      /* ALL GNUTLS STUFF */
 
53
#include <gnutls/openpgp.h>     /* gnutls with openpgp stuff */
58
54
 
59
55
#include <unistd.h>             /* close() */
60
56
#include <netinet/in.h>
67
63
#include <errno.h>              /* perror() */
68
64
#include <gpgme.h>
69
65
 
70
 
// getopt long
71
 
#include <getopt.h>
72
66
 
73
67
#ifndef CERT_ROOT
74
68
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
78
72
#define BUFFER_SIZE 256
79
73
#define DH_BITS 1024
80
74
 
81
 
bool debug = false;
82
 
 
83
75
typedef struct {
84
76
  gnutls_session_t session;
85
77
  gnutls_certificate_credentials_t cred;
87
79
} encrypted_session;
88
80
 
89
81
 
90
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
91
 
                            char **new_packet, const char *homedir){
 
82
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
92
83
  gpgme_data_t dh_crypto, dh_plain;
93
84
  gpgme_ctx_t ctx;
94
85
  gpgme_error_t rc;
95
86
  ssize_t ret;
96
 
  ssize_t new_packet_capacity = 0;
97
 
  ssize_t new_packet_length = 0;
 
87
  size_t new_packet_capacity = 0;
 
88
  size_t new_packet_length = 0;
98
89
  gpgme_engine_info_t engine_info;
99
90
 
100
 
  if (debug){
101
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
102
 
  }
103
 
  
104
91
  /* Init GPGME */
105
92
  gpgme_check_version(NULL);
106
93
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
149
136
    return -1;
150
137
  }
151
138
  
152
 
  /* Decrypt data from the FILE pointer to the plaintext data
153
 
     buffer */
 
139
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
154
140
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
155
141
  if (rc != GPG_ERR_NO_ERROR){
156
142
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
157
143
            gpgme_strsource(rc), gpgme_strerror(rc));
158
144
    return -1;
159
145
  }
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
146
  
 
147
/*   gpgme_decrypt_result_t result; */
 
148
/*   result = gpgme_op_decrypt_result(ctx); */
 
149
/*   fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm); */
 
150
/*   fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage); */
 
151
/*   if(result->file_name != NULL){ */
 
152
/*     fprintf(stderr, "File name: %s\n", result->file_name); */
 
153
/*   } */
 
154
/*   gpgme_recipient_t recipient; */
 
155
/*   recipient = result->recipients; */
 
156
/*   if(recipient){ */
 
157
/*     while(recipient != NULL){ */
 
158
/*       fprintf(stderr, "Public key algorithm: %s\n", */
 
159
/*            gpgme_pubkey_algo_name(recipient->pubkey_algo)); */
 
160
/*       fprintf(stderr, "Key ID: %s\n", recipient->keyid); */
 
161
/*       fprintf(stderr, "Secret key available: %s\n", */
 
162
/*            recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes"); */
 
163
/*       recipient = recipient->next; */
 
164
/*     } */
 
165
/*   } */
 
166
 
194
167
  /* Delete the GPGME FILE pointer cryptotext data buffer */
195
168
  gpgme_data_release(dh_crypto);
196
169
  
200
173
  *new_packet = 0;
201
174
  while(true){
202
175
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
203
 
      *new_packet = realloc(*new_packet,
204
 
                            (unsigned int)new_packet_capacity
205
 
                            + BUFFER_SIZE);
 
176
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
206
177
      if (*new_packet == NULL){
207
178
        perror("realloc");
208
179
        return -1;
210
181
      new_packet_capacity += BUFFER_SIZE;
211
182
    }
212
183
    
213
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
214
 
                          BUFFER_SIZE);
 
184
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
215
185
    /* Print the data, if any */
216
186
    if (ret == 0){
 
187
      /* If password is empty, then a incorrect error will be printed */
217
188
      break;
218
189
    }
219
190
    if(ret < 0){
223
194
    new_packet_length += ret;
224
195
  }
225
196
 
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 */
 
197
   /* Delete the GPGME plaintext data buffer */
235
198
  gpgme_data_release(dh_plain);
236
199
  return new_packet_length;
237
200
}
243
206
  return ret;
244
207
}
245
208
 
246
 
void debuggnutls(__attribute__((unused)) int level,
247
 
                 const char* string){
 
209
void debuggnutls(int level, const char* string){
248
210
  fprintf(stderr, "%s", string);
249
211
}
250
212
 
252
214
  const char *err;
253
215
  int ret;
254
216
  
255
 
  if(debug){
256
 
    fprintf(stderr, "Initializing GnuTLS\n");
257
 
  }
258
 
  
259
217
  if ((ret = gnutls_global_init ())
260
218
      != GNUTLS_E_SUCCESS) {
261
219
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
262
220
    return -1;
263
221
  }
264
222
 
265
 
  if (debug){
266
 
    gnutls_global_set_log_level(11);
267
 
    gnutls_global_set_log_function(debuggnutls);
268
 
  }
269
 
  
 
223
  /* Uncomment to enable full debuggin on the gnutls library */
 
224
  /*   gnutls_global_set_log_level(11); */
 
225
  /*   gnutls_global_set_log_function(debuggnutls); */
 
226
 
 
227
 
270
228
  /* openpgp credentials */
271
229
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
272
230
      != GNUTLS_E_SUCCESS) {
273
 
    fprintf (stderr, "memory error: %s\n",
274
 
             safer_gnutls_strerror(ret));
 
231
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
275
232
    return -1;
276
233
  }
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
 
  
 
234
 
284
235
  ret = gnutls_certificate_set_openpgp_key_file
285
236
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
286
237
  if (ret != GNUTLS_E_SUCCESS) {
287
238
    fprintf
288
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
289
 
       " '%s')\n",
 
239
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
290
240
       ret, CERTFILE, KEYFILE);
291
241
    fprintf(stdout, "The Error is: %s\n",
292
242
            safer_gnutls_strerror(ret));
293
243
    return -1;
294
244
  }
295
 
  
296
 
  //GnuTLS server initialization
 
245
 
 
246
  //Gnutls server initialization
297
247
  if ((ret = gnutls_dh_params_init (&es->dh_params))
298
248
      != GNUTLS_E_SUCCESS) {
299
249
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
300
250
             safer_gnutls_strerror(ret));
301
251
    return -1;
302
252
  }
303
 
  
 
253
 
304
254
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
305
255
      != GNUTLS_E_SUCCESS) {
306
256
    fprintf (stderr, "Error in prime generation: %s\n",
307
257
             safer_gnutls_strerror(ret));
308
258
    return -1;
309
259
  }
310
 
  
 
260
 
311
261
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
312
 
  
313
 
  // GnuTLS session creation
 
262
 
 
263
  // Gnutls session creation
314
264
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
315
265
      != GNUTLS_E_SUCCESS){
316
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
 
266
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
317
267
            safer_gnutls_strerror(ret));
318
268
  }
319
 
  
 
269
 
320
270
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
321
271
      != GNUTLS_E_SUCCESS) {
322
272
    fprintf(stderr, "Syntax error at: %s\n", err);
323
 
    fprintf(stderr, "GnuTLS error: %s\n",
 
273
    fprintf(stderr, "Gnutls error: %s\n",
324
274
            safer_gnutls_strerror(ret));
325
275
    return -1;
326
276
  }
327
 
  
 
277
 
328
278
  if ((ret = gnutls_credentials_set
329
279
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
330
280
      != GNUTLS_E_SUCCESS) {
332
282
            safer_gnutls_strerror(ret));
333
283
    return -1;
334
284
  }
335
 
  
 
285
 
336
286
  /* ignore client certificate if any. */
337
 
  gnutls_certificate_server_set_request (es->session,
338
 
                                         GNUTLS_CERT_IGNORE);
 
287
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
339
288
  
340
289
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
341
290
  
342
291
  return 0;
343
292
}
344
293
 
345
 
void empty_log(__attribute__((unused)) AvahiLogLevel level,
346
 
               __attribute__((unused)) const char *txt){}
 
294
void empty_log(AvahiLogLevel level, const char *txt){}
347
295
 
348
 
int start_mandos_communication(char *ip, uint16_t port,
349
 
                               unsigned int if_index){
 
296
int start_mandos_communcation(char *ip, uint16_t port){
350
297
  int ret, tcp_sd;
351
298
  struct sockaddr_in6 to;
 
299
  struct in6_addr ip_addr;
352
300
  encrypted_session es;
353
301
  char *buffer = NULL;
354
302
  char *decrypted_buffer;
356
304
  size_t buffer_capacity = 0;
357
305
  ssize_t decrypted_buffer_size;
358
306
  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
 
  }
 
307
 
364
308
  
365
309
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
366
310
  if(tcp_sd < 0) {
368
312
    return -1;
369
313
  }
370
314
  
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) {
 
315
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
 
316
  if(tcp_sd < 0) {
384
317
    perror("setsockopt bindtodevice");
385
318
    return -1;
386
319
  }
387
320
  
388
321
  memset(&to,0,sizeof(to));
389
322
  to.sin6_family = AF_INET6;
390
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
323
  ret = inet_pton(AF_INET6, ip, &ip_addr);
391
324
  if (ret < 0 ){
392
325
    perror("inet_pton");
393
326
    return -1;
396
329
    fprintf(stderr, "Bad address: %s\n", ip);
397
330
    return -1;
398
331
  }
399
 
  /* Spurious warnings for the next line, see for instance
400
 
     <http://bugs.debian.org/488884> */
401
332
  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
 
  }
 
333
  to.sin6_scope_id = if_nametoindex("eth0");
408
334
  
409
335
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
410
336
  if (ret < 0){
417
343
    retval = -1;
418
344
    return -1;
419
345
  }
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
 
  
 
346
    
 
347
  
 
348
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
 
349
 
428
350
  ret = gnutls_handshake (es.session);
429
351
  
430
352
  if (ret != GNUTLS_E_SUCCESS){
433
355
    retval = -1;
434
356
    goto exit;
435
357
  }
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
358
 
 
359
  //retrive password
444
360
  while(true){
445
361
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
446
362
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
471
387
        }
472
388
        break;
473
389
      default:
474
 
        fprintf(stderr, "Unknown error while reading data from"
475
 
                " encrypted session with mandos server\n");
 
390
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
476
391
        retval = -1;
477
392
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
478
393
        goto exit;
479
394
      }
480
395
    } else {
481
 
      buffer_length += (size_t) ret;
 
396
      buffer_length += ret;
482
397
    }
483
398
  }
484
 
  
 
399
 
485
400
  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
 
      }
 
401
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
 
402
      retval = -1;
 
403
    } else {
 
404
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
505
405
      free(decrypted_buffer);
506
 
    } else {
507
 
      retval = -1;
508
406
    }
509
407
  }
510
408
 
 
409
  free(buffer);
 
410
 
511
411
  //shutdown procedure
512
 
 
513
 
  if(debug){
514
 
    fprintf(stderr, "Closing TLS session\n");
515
 
  }
516
 
 
517
 
  free(buffer);
518
412
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
519
413
 exit:
520
414
  close(tcp_sd);
538
432
    const char *host_name,
539
433
    const AvahiAddress *address,
540
434
    uint16_t port,
541
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
542
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
435
    AvahiStringList *txt,
 
436
    AvahiLookupResultFlags flags,
543
437
    AVAHI_GCC_UNUSED void* userdata) {
544
438
    
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
 
      }
 
439
    assert(r);
 
440
 
 
441
    /* Called whenever a service has been resolved successfully or timed out */
 
442
 
 
443
    switch (event) {
 
444
        case AVAHI_RESOLVER_FAILURE:
 
445
            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)));
 
446
            break;
 
447
 
 
448
        case AVAHI_RESOLVER_FOUND: {
 
449
          char ip[AVAHI_ADDRESS_STR_MAX];
 
450
            avahi_address_snprint(ip, sizeof(ip), address);
 
451
            int ret = start_mandos_communcation(ip, port);
 
452
            if (ret == 0){
 
453
              exit(EXIT_SUCCESS);
 
454
            } else {
 
455
              exit(EXIT_FAILURE);
 
456
            }
 
457
        }
574
458
    }
575
 
  }
576
 
  avahi_s_service_resolver_free(r);
 
459
    avahi_s_service_resolver_free(r);
577
460
}
578
461
 
579
462
static void browse_callback(
590
473
    AvahiServer *s = userdata;
591
474
    assert(b);
592
475
 
593
 
    /* Called whenever a new services becomes available on the LAN or
594
 
       is removed from the LAN */
 
476
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
595
477
 
596
478
    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;
 
479
 
 
480
        case AVAHI_BROWSER_FAILURE:
 
481
            
 
482
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
 
483
            avahi_simple_poll_quit(simple_poll);
 
484
            return;
 
485
 
 
486
        case AVAHI_BROWSER_NEW:
 
487
            /* We ignore the returned resolver object. In the callback
 
488
               function we free it. If the server is terminated before
 
489
               the callback function is called the server will free
 
490
               the resolver for us. */
 
491
            
 
492
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
 
493
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
 
494
            
 
495
            break;
 
496
 
 
497
        case AVAHI_BROWSER_REMOVE:
 
498
            break;
 
499
 
 
500
        case AVAHI_BROWSER_ALL_FOR_NOW:
 
501
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
502
            break;
625
503
    }
626
504
}
627
505
 
629
507
    AvahiServerConfig config;
630
508
    AvahiSServiceBrowser *sb = NULL;
631
509
    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
 
    }
 
510
    int ret = 1;
 
511
 
 
512
    avahi_set_log_function(empty_log);
664
513
    
665
514
    /* Initialize the psuedo-RNG */
666
 
    srand((unsigned int) time(NULL));
 
515
    srand(time(NULL));
667
516
 
668
517
    /* Allocate main loop object */
669
518
    if (!(simple_poll = avahi_simple_poll_new())) {
670
519
        fprintf(stderr, "Failed to create simple poll object.\n");
671
 
        
672
 
        goto exit;
 
520
        goto fail;
673
521
    }
674
522
 
675
523
    /* Do not publish any local records */
679
527
    config.publish_workstation = 0;
680
528
    config.publish_domain = 0;
681
529
 
 
530
/*     /\* Set a unicast DNS server for wide area DNS-SD *\/ */
 
531
/*     avahi_address_parse("193.11.177.11", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]); */
 
532
/*     config.n_wide_area_servers = 1; */
 
533
/*     config.enable_wide_area = 1; */
 
534
    
682
535
    /* Allocate a new server */
683
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
684
 
                              &config, NULL, NULL, &error);
 
536
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
685
537
 
686
538
    /* Free the configuration data */
687
539
    avahi_server_config_free(&config);
688
540
 
689
 
    /* Check if creating the server object succeeded */
 
541
    /* Check wether creating the server object succeeded */
690
542
    if (!server) {
691
 
        fprintf(stderr, "Failed to create server: %s\n",
692
 
                avahi_strerror(error));
693
 
        returncode = EXIT_FAILURE;
694
 
        goto exit;
 
543
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
544
        goto fail;
695
545
    }
696
546
    
697
547
    /* 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;
 
548
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
 
549
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
 
550
        goto fail;
709
551
    }
710
552
    
711
553
    /* Run the main loop */
712
 
 
713
 
    if (debug){
714
 
      fprintf(stderr, "Starting avahi loop search\n");
715
 
    }
716
 
    
717
554
    avahi_simple_poll_loop(simple_poll);
718
555
    
719
 
 exit:
720
 
 
721
 
    if (debug){
722
 
      fprintf(stderr, "%s exiting\n", argv[0]);
723
 
    }
 
556
    ret = 0;
 
557
    
 
558
fail:
724
559
    
725
560
    /* Cleanup things */
726
561
    if (sb)
732
567
    if (simple_poll)
733
568
        avahi_simple_poll_free(simple_poll);
734
569
 
735
 
    return returncode;
 
570
    return ret;
736
571
}