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