/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: Teddy Hogeborn
  • Date: 2008-07-22 06:25:35 UTC
  • mfrom: (24.1.2 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080722062535-whz5do0b3dzw6m08
Merge.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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.
 
1
/*  -*- coding: utf-8 -*- */
 
2
/*
 
3
 * Mandos client - get and decrypt data from a Mandos server
6
4
 *
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.
 
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/>.
12
30
 */
13
31
 
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
 
***/
 
32
#define _FORTIFY_SOURCE 2
32
33
 
33
34
#define _LARGEFILE_SOURCE
34
35
#define _FILE_OFFSET_BITS 64
47
48
#include <avahi-common/error.h>
48
49
 
49
50
//mandos client part
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 */
 
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 */
54
56
 
55
57
#include <unistd.h>             /* close() */
56
58
#include <netinet/in.h>
63
65
#include <errno.h>              /* perror() */
64
66
#include <gpgme.h>
65
67
 
 
68
// getopt long
 
69
#include <getopt.h>
66
70
 
67
71
#ifndef CERT_ROOT
68
72
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
72
76
#define BUFFER_SIZE 256
73
77
#define DH_BITS 1024
74
78
 
 
79
bool debug = false;
 
80
 
75
81
typedef struct {
76
82
  gnutls_session_t session;
77
83
  gnutls_certificate_credentials_t cred;
79
85
} encrypted_session;
80
86
 
81
87
 
82
 
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){
83
90
  gpgme_data_t dh_crypto, dh_plain;
84
91
  gpgme_ctx_t ctx;
85
92
  gpgme_error_t rc;
86
93
  ssize_t ret;
87
 
  size_t new_packet_capacity = 0;
88
 
  size_t new_packet_length = 0;
 
94
  ssize_t new_packet_capacity = 0;
 
95
  ssize_t new_packet_length = 0;
89
96
  gpgme_engine_info_t engine_info;
90
97
 
 
98
  if (debug){
 
99
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
100
  }
 
101
  
91
102
  /* Init GPGME */
92
103
  gpgme_check_version(NULL);
93
104
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
136
147
    return -1;
137
148
  }
138
149
  
139
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
150
  /* Decrypt data from the FILE pointer to the plaintext data
 
151
     buffer */
140
152
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
141
153
  if (rc != GPG_ERR_NO_ERROR){
142
154
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
143
155
            gpgme_strsource(rc), gpgme_strerror(rc));
144
156
    return -1;
145
157
  }
 
158
 
 
159
  if(debug){
 
160
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
 
161
  }
 
162
 
 
163
  if (debug){
 
164
    gpgme_decrypt_result_t result;
 
165
    result = gpgme_op_decrypt_result(ctx);
 
166
    if (result == NULL){
 
167
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
168
    } else {
 
169
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
170
              result->unsupported_algorithm);
 
171
      fprintf(stderr, "Wrong key usage: %d\n",
 
172
              result->wrong_key_usage);
 
173
      if(result->file_name != NULL){
 
174
        fprintf(stderr, "File name: %s\n", result->file_name);
 
175
      }
 
176
      gpgme_recipient_t recipient;
 
177
      recipient = result->recipients;
 
178
      if(recipient){
 
179
        while(recipient != NULL){
 
180
          fprintf(stderr, "Public key algorithm: %s\n",
 
181
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
182
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
183
          fprintf(stderr, "Secret key available: %s\n",
 
184
                  recipient->status == GPG_ERR_NO_SECKEY
 
185
                  ? "No" : "Yes");
 
186
          recipient = recipient->next;
 
187
        }
 
188
      }
 
189
    }
 
190
  }
146
191
  
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
 
 
167
192
  /* Delete the GPGME FILE pointer cryptotext data buffer */
168
193
  gpgme_data_release(dh_crypto);
169
194
  
170
195
  /* Seek back to the beginning of the GPGME plaintext data buffer */
171
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
196
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
172
197
 
173
198
  *new_packet = 0;
174
199
  while(true){
175
200
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
176
 
      *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);
177
204
      if (*new_packet == NULL){
178
205
        perror("realloc");
179
206
        return -1;
181
208
      new_packet_capacity += BUFFER_SIZE;
182
209
    }
183
210
    
184
 
    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);
185
213
    /* Print the data, if any */
186
214
    if (ret == 0){
187
 
      /* If password is empty, then a incorrect error will be printed */
188
215
      break;
189
216
    }
190
217
    if(ret < 0){
194
221
    new_packet_length += ret;
195
222
  }
196
223
 
197
 
   /* 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 */
198
233
  gpgme_data_release(dh_plain);
199
234
  return new_packet_length;
200
235
}
206
241
  return ret;
207
242
}
208
243
 
209
 
void debuggnutls(int level, const char* string){
 
244
void debuggnutls(__attribute__((unused)) int level,
 
245
                 const char* string){
210
246
  fprintf(stderr, "%s", string);
211
247
}
212
248
 
214
250
  const char *err;
215
251
  int ret;
216
252
  
 
253
  if(debug){
 
254
    fprintf(stderr, "Initializing GnuTLS\n");
 
255
  }
 
256
  
217
257
  if ((ret = gnutls_global_init ())
218
258
      != GNUTLS_E_SUCCESS) {
219
259
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
220
260
    return -1;
221
261
  }
222
262
 
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
 
 
 
263
  if (debug){
 
264
    gnutls_global_set_log_level(11);
 
265
    gnutls_global_set_log_function(debuggnutls);
 
266
  }
 
267
  
228
268
  /* openpgp credentials */
229
269
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
230
270
      != GNUTLS_E_SUCCESS) {
231
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
271
    fprintf (stderr, "memory error: %s\n",
 
272
             safer_gnutls_strerror(ret));
232
273
    return -1;
233
274
  }
234
 
 
 
275
  
 
276
  if(debug){
 
277
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
278
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
 
279
            KEYFILE);
 
280
  }
 
281
  
235
282
  ret = gnutls_certificate_set_openpgp_key_file
236
283
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
237
284
  if (ret != GNUTLS_E_SUCCESS) {
238
285
    fprintf
239
 
      (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",
240
288
       ret, CERTFILE, KEYFILE);
241
289
    fprintf(stdout, "The Error is: %s\n",
242
290
            safer_gnutls_strerror(ret));
243
291
    return -1;
244
292
  }
245
 
 
246
 
  //Gnutls server initialization
 
293
  
 
294
  //GnuTLS server initialization
247
295
  if ((ret = gnutls_dh_params_init (&es->dh_params))
248
296
      != GNUTLS_E_SUCCESS) {
249
297
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
250
298
             safer_gnutls_strerror(ret));
251
299
    return -1;
252
300
  }
253
 
 
 
301
  
254
302
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
255
303
      != GNUTLS_E_SUCCESS) {
256
304
    fprintf (stderr, "Error in prime generation: %s\n",
257
305
             safer_gnutls_strerror(ret));
258
306
    return -1;
259
307
  }
260
 
 
 
308
  
261
309
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
262
 
 
263
 
  // Gnutls session creation
 
310
  
 
311
  // GnuTLS session creation
264
312
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
265
313
      != GNUTLS_E_SUCCESS){
266
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
314
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
267
315
            safer_gnutls_strerror(ret));
268
316
  }
269
 
 
 
317
  
270
318
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
271
319
      != GNUTLS_E_SUCCESS) {
272
320
    fprintf(stderr, "Syntax error at: %s\n", err);
273
 
    fprintf(stderr, "Gnutls error: %s\n",
 
321
    fprintf(stderr, "GnuTLS error: %s\n",
274
322
            safer_gnutls_strerror(ret));
275
323
    return -1;
276
324
  }
277
 
 
 
325
  
278
326
  if ((ret = gnutls_credentials_set
279
327
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
280
328
      != GNUTLS_E_SUCCESS) {
282
330
            safer_gnutls_strerror(ret));
283
331
    return -1;
284
332
  }
285
 
 
 
333
  
286
334
  /* ignore client certificate if any. */
287
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
335
  gnutls_certificate_server_set_request (es->session,
 
336
                                         GNUTLS_CERT_IGNORE);
288
337
  
289
338
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
290
339
  
291
340
  return 0;
292
341
}
293
342
 
294
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
343
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
344
               __attribute__((unused)) const char *txt){}
295
345
 
296
 
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){
297
348
  int ret, tcp_sd;
298
349
  struct sockaddr_in6 to;
299
 
  struct in6_addr ip_addr;
300
350
  encrypted_session es;
301
351
  char *buffer = NULL;
302
352
  char *decrypted_buffer;
303
353
  size_t buffer_length = 0;
304
354
  size_t buffer_capacity = 0;
305
355
  ssize_t decrypted_buffer_size;
 
356
  size_t written = 0;
306
357
  int retval = 0;
307
 
 
 
358
  char interface[IF_NAMESIZE];
 
359
  
 
360
  if(debug){
 
361
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
 
362
  }
308
363
  
309
364
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
310
365
  if(tcp_sd < 0) {
312
367
    return -1;
313
368
  }
314
369
  
315
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
316
 
  if(tcp_sd < 0) {
317
 
    perror("setsockopt bindtodevice");
 
370
  if(if_indextoname(if_index, interface) == NULL){
 
371
    if(debug){
 
372
      perror("if_indextoname");
 
373
    }
318
374
    return -1;
319
375
  }
320
376
  
321
 
  memset(&to,0,sizeof(to));
 
377
  if(debug){
 
378
    fprintf(stderr, "Binding to interface %s\n", interface);
 
379
  }
 
380
  
 
381
  memset(&to,0,sizeof(to));     /* Spurious warning */
322
382
  to.sin6_family = AF_INET6;
323
 
  ret = inet_pton(AF_INET6, ip, &ip_addr);
 
383
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
324
384
  if (ret < 0 ){
325
385
    perror("inet_pton");
326
386
    return -1;
329
389
    fprintf(stderr, "Bad address: %s\n", ip);
330
390
    return -1;
331
391
  }
332
 
  to.sin6_port = htons(port);
333
 
  to.sin6_scope_id = if_nametoindex("eth0");
 
392
  to.sin6_port = htons(port);   /* Spurious warning */
 
393
  
 
394
  to.sin6_scope_id = (uint32_t)if_index;
 
395
  
 
396
  if(debug){
 
397
    fprintf(stderr, "Connection to: %s\n", ip);
 
398
  }
334
399
  
335
400
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
336
401
  if (ret < 0){
343
408
    retval = -1;
344
409
    return -1;
345
410
  }
346
 
    
347
 
  
348
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
349
 
 
 
411
  
 
412
  gnutls_transport_set_ptr (es.session,
 
413
                            (gnutls_transport_ptr_t) tcp_sd);
 
414
  
 
415
  if(debug){
 
416
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
417
  }
 
418
  
350
419
  ret = gnutls_handshake (es.session);
351
420
  
352
421
  if (ret != GNUTLS_E_SUCCESS){
353
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
354
 
    gnutls_perror (ret);
 
422
    if(debug){
 
423
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
424
      gnutls_perror (ret);
 
425
    }
355
426
    retval = -1;
356
427
    goto exit;
357
428
  }
 
429
  
 
430
  //Retrieve OpenPGP packet that contains the wanted password
 
431
  
 
432
  if(debug){
 
433
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
434
            ip);
 
435
  }
358
436
 
359
 
  //retrive password
360
437
  while(true){
361
438
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
362
439
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
387
464
        }
388
465
        break;
389
466
      default:
390
 
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
467
        fprintf(stderr, "Unknown error while reading data from"
 
468
                " encrypted session with mandos server\n");
391
469
        retval = -1;
392
470
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
393
471
        goto exit;
394
472
      }
395
473
    } else {
396
 
      buffer_length += ret;
 
474
      buffer_length += (size_t) ret;
397
475
    }
398
476
  }
399
 
 
 
477
  
400
478
  if (buffer_length > 0){
401
 
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
 
479
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
480
                                               buffer_length,
 
481
                                               &decrypted_buffer,
 
482
                                               CERT_ROOT);
 
483
    if (decrypted_buffer_size >= 0){
 
484
      while(written < decrypted_buffer_size){
 
485
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
486
                           (size_t)decrypted_buffer_size - written,
 
487
                           stdout);
 
488
        if(ret == 0 and ferror(stdout)){
 
489
          if(debug){
 
490
            fprintf(stderr, "Error writing encrypted data: %s\n",
 
491
                    strerror(errno));
 
492
          }
 
493
          retval = -1;
 
494
          break;
 
495
        }
 
496
        written += (size_t)ret;
 
497
      }
 
498
      free(decrypted_buffer);
 
499
    } else {
402
500
      retval = -1;
403
 
    } else {
404
 
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
405
 
      free(decrypted_buffer);
406
501
    }
407
502
  }
408
503
 
 
504
  //shutdown procedure
 
505
 
 
506
  if(debug){
 
507
    fprintf(stderr, "Closing TLS session\n");
 
508
  }
 
509
 
409
510
  free(buffer);
410
 
 
411
 
  //shutdown procedure
412
511
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
413
512
 exit:
414
513
  close(tcp_sd);
423
522
 
424
523
static void resolve_callback(
425
524
    AvahiSServiceResolver *r,
426
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
525
    AvahiIfIndex interface,
427
526
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
428
527
    AvahiResolverEvent event,
429
528
    const char *name,
432
531
    const char *host_name,
433
532
    const AvahiAddress *address,
434
533
    uint16_t port,
435
 
    AvahiStringList *txt,
436
 
    AvahiLookupResultFlags flags,
 
534
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
535
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
437
536
    AVAHI_GCC_UNUSED void* userdata) {
438
537
    
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
 
        }
 
538
  assert(r);                    /* Spurious warning */
 
539
  
 
540
  /* Called whenever a service has been resolved successfully or
 
541
     timed out */
 
542
  
 
543
  switch (event) {
 
544
  default:
 
545
  case AVAHI_RESOLVER_FAILURE:
 
546
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
 
547
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
548
            avahi_strerror(avahi_server_errno(server)));
 
549
    break;
 
550
    
 
551
  case AVAHI_RESOLVER_FOUND:
 
552
    {
 
553
      char ip[AVAHI_ADDRESS_STR_MAX];
 
554
      avahi_address_snprint(ip, sizeof(ip), address);
 
555
      if(debug){
 
556
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
 
557
                " port %d\n", name, host_name, ip, port);
 
558
      }
 
559
      int ret = start_mandos_communication(ip, port,
 
560
                                           (unsigned int) interface);
 
561
      if (ret == 0){
 
562
        exit(EXIT_SUCCESS);
 
563
      }
458
564
    }
459
 
    avahi_s_service_resolver_free(r);
 
565
  }
 
566
  avahi_s_service_resolver_free(r);
460
567
}
461
568
 
462
569
static void browse_callback(
471
578
    void* userdata) {
472
579
    
473
580
    AvahiServer *s = userdata;
474
 
    assert(b);
475
 
 
476
 
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
477
 
 
 
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
    
478
586
    switch (event) {
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;
 
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;
503
615
    }
504
616
}
505
617
 
507
619
    AvahiServerConfig config;
508
620
    AvahiSServiceBrowser *sb = NULL;
509
621
    int error;
510
 
    int ret = 1;
511
 
 
512
 
    avahi_set_log_function(empty_log);
 
622
    int ret;
 
623
    int returncode = EXIT_SUCCESS;
 
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
    
 
651
    if (not debug){
 
652
      avahi_set_log_function(empty_log);
 
653
    }
513
654
    
514
655
    /* Initialize the psuedo-RNG */
515
 
    srand(time(NULL));
 
656
    srand((unsigned int) time(NULL));
516
657
 
517
658
    /* Allocate main loop object */
518
659
    if (!(simple_poll = avahi_simple_poll_new())) {
519
660
        fprintf(stderr, "Failed to create simple poll object.\n");
520
 
        goto fail;
 
661
        
 
662
        goto exit;
521
663
    }
522
664
 
523
665
    /* Do not publish any local records */
527
669
    config.publish_workstation = 0;
528
670
    config.publish_domain = 0;
529
671
 
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
 
    
535
672
    /* Allocate a new server */
536
 
    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);
537
675
 
538
676
    /* Free the configuration data */
539
677
    avahi_server_config_free(&config);
540
678
 
541
 
    /* Check wether creating the server object succeeded */
 
679
    /* Check if creating the server object succeeded */
542
680
    if (!server) {
543
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
544
 
        goto fail;
 
681
        fprintf(stderr, "Failed to create server: %s\n",
 
682
                avahi_strerror(error));
 
683
        returncode = EXIT_FAILURE;
 
684
        goto exit;
545
685
    }
546
686
    
547
687
    /* Create the service browser */
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;
 
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)));
 
697
        returncode = EXIT_FAILURE;
 
698
        goto exit;
551
699
    }
552
700
    
553
701
    /* Run the main loop */
 
702
 
 
703
    if (debug){
 
704
      fprintf(stderr, "Starting avahi loop search\n");
 
705
    }
 
706
    
554
707
    avahi_simple_poll_loop(simple_poll);
555
708
    
556
 
    ret = 0;
557
 
    
558
 
fail:
 
709
 exit:
 
710
 
 
711
    if (debug){
 
712
      fprintf(stderr, "%s exiting\n", argv[0]);
 
713
    }
559
714
    
560
715
    /* Cleanup things */
561
716
    if (sb)
567
722
    if (simple_poll)
568
723
        avahi_simple_poll_free(simple_poll);
569
724
 
570
 
    return ret;
 
725
    return returncode;
571
726
}