/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-08-03 03:33:56 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080803033356-6aemgj0g0hoz91ow
* plugins.d/mandosclient.c (pgp_packet_decrypt): Renamed variables.
                                                 On debug, show
                                                 decrypted plaintext
                                                 in hexadecimal.  Free
                                                 the GPGME data
                                                 buffers even on
                                                 errors.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
#include <stdlib.h>
38
38
#include <time.h>
39
39
#include <net/if.h>             /* if_nametoindex */
 
40
#include <sys/ioctl.h>          /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
 
41
                                   SIOCSIFFLAGS */
 
42
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
 
43
                                   SIOCSIFFLAGS */
40
44
 
41
45
#include <avahi-core/core.h>
42
46
#include <avahi-core/lookup.h>
68
72
 
69
73
#define BUFFER_SIZE 256
70
74
 
71
 
static int dh_bits = 1024;
72
 
 
73
75
static const char *keydir = "/conf/conf.d/mandos";
74
76
static const char *pubkeyfile = "pubkey.txt";
75
77
static const char *seckeyfile = "seckey.txt";
76
78
 
77
79
bool debug = false;
78
80
 
79
 
/* Used for  */
 
81
/* Used for passing in values through all the callback functions */
80
82
typedef struct {
81
 
  gnutls_session_t session;
 
83
  AvahiSimplePoll *simple_poll;
 
84
  AvahiServer *server;
82
85
  gnutls_certificate_credentials_t cred;
83
 
  gnutls_dh_params_t dh_params;
84
 
} encrypted_session;
85
 
 
86
 
 
87
 
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
 
                                   char **new_packet,
 
86
  unsigned int dh_bits;
 
87
  const char *priority;
 
88
} mandos_context;
 
89
 
 
90
/* 
 
91
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
 
92
 * Returns -1 on error
 
93
 */
 
94
static ssize_t pgp_packet_decrypt (const char *cryptotext,
 
95
                                   size_t crypto_size,
 
96
                                   char **plaintext,
89
97
                                   const char *homedir){
90
98
  gpgme_data_t dh_crypto, dh_plain;
91
99
  gpgme_ctx_t ctx;
92
100
  gpgme_error_t rc;
93
101
  ssize_t ret;
94
 
  ssize_t new_packet_capacity = 0;
95
 
  ssize_t new_packet_length = 0;
 
102
  ssize_t plaintext_capacity = 0;
 
103
  ssize_t plaintext_length = 0;
96
104
  gpgme_engine_info_t engine_info;
97
 
 
 
105
  
98
106
  if (debug){
99
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
107
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
100
108
  }
101
109
  
102
110
  /* Init GPGME */
108
116
    return -1;
109
117
  }
110
118
  
111
 
  /* Set GPGME home directory */
 
119
  /* Set GPGME home directory for the OpenPGP engine only */
112
120
  rc = gpgme_get_engine_info (&engine_info);
113
121
  if (rc != GPG_ERR_NO_ERROR){
114
122
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
124
132
    engine_info = engine_info->next;
125
133
  }
126
134
  if(engine_info == NULL){
127
 
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
 
135
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
128
136
    return -1;
129
137
  }
130
138
  
131
 
  /* Create new GPGME data buffer from packet buffer */
132
 
  rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
 
139
  /* Create new GPGME data buffer from memory cryptotext */
 
140
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
 
141
                               0);
133
142
  if (rc != GPG_ERR_NO_ERROR){
134
143
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
135
144
            gpgme_strsource(rc), gpgme_strerror(rc));
141
150
  if (rc != GPG_ERR_NO_ERROR){
142
151
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
143
152
            gpgme_strsource(rc), gpgme_strerror(rc));
 
153
    gpgme_data_release(dh_crypto);
144
154
    return -1;
145
155
  }
146
156
  
149
159
  if (rc != GPG_ERR_NO_ERROR){
150
160
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
151
161
            gpgme_strsource(rc), gpgme_strerror(rc));
152
 
    return -1;
 
162
    plaintext_length = -1;
 
163
    goto decrypt_end;
153
164
  }
154
165
  
155
 
  /* Decrypt data from the FILE pointer to the plaintext data
156
 
     buffer */
 
166
  /* Decrypt data from the cryptotext data buffer to the plaintext
 
167
     data buffer */
157
168
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
158
169
  if (rc != GPG_ERR_NO_ERROR){
159
170
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
160
171
            gpgme_strsource(rc), gpgme_strerror(rc));
161
 
    return -1;
 
172
    plaintext_length = -1;
 
173
    goto decrypt_end;
162
174
  }
163
 
 
 
175
  
164
176
  if(debug){
165
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
 
177
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
166
178
  }
167
 
 
 
179
  
168
180
  if (debug){
169
181
    gpgme_decrypt_result_t result;
170
182
    result = gpgme_op_decrypt_result(ctx);
194
206
    }
195
207
  }
196
208
  
197
 
  /* Delete the GPGME FILE pointer cryptotext data buffer */
198
 
  gpgme_data_release(dh_crypto);
199
 
  
200
209
  /* Seek back to the beginning of the GPGME plaintext data buffer */
201
210
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
202
211
    perror("pgpme_data_seek");
 
212
    plaintext_length = -1;
 
213
    goto decrypt_end;
203
214
  }
204
215
  
205
 
  *new_packet = 0;
 
216
  *plaintext = NULL;
206
217
  while(true){
207
 
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
208
 
      *new_packet = realloc(*new_packet,
209
 
                            (unsigned int)new_packet_capacity
 
218
    if (plaintext_length + BUFFER_SIZE > plaintext_capacity){
 
219
      *plaintext = realloc(*plaintext,
 
220
                            (unsigned int)plaintext_capacity
210
221
                            + BUFFER_SIZE);
211
 
      if (*new_packet == NULL){
 
222
      if (*plaintext == NULL){
212
223
        perror("realloc");
213
 
        return -1;
 
224
        plaintext_length = -1;
 
225
        goto decrypt_end;
214
226
      }
215
 
      new_packet_capacity += BUFFER_SIZE;
 
227
      plaintext_capacity += BUFFER_SIZE;
216
228
    }
217
229
    
218
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
230
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
219
231
                          BUFFER_SIZE);
220
232
    /* Print the data, if any */
221
233
    if (ret == 0){
 
234
      /* EOF */
222
235
      break;
223
236
    }
224
237
    if(ret < 0){
225
238
      perror("gpgme_data_read");
226
 
      return -1;
 
239
      plaintext_length = -1;
 
240
      goto decrypt_end;
227
241
    }
228
 
    new_packet_length += ret;
 
242
    plaintext_length += ret;
229
243
  }
230
244
 
231
 
  /* FIXME: check characters before printing to screen so to not print
232
 
     terminal control characters */
233
 
  /*   if(debug){ */
234
 
  /*     fprintf(stderr, "decrypted password is: "); */
235
 
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
236
 
  /*     fprintf(stderr, "\n"); */
237
 
  /*   } */
 
245
  if(debug){
 
246
    fprintf(stderr, "Decrypted password is: ");
 
247
    for(size_t i = 0; i < plaintext_length; i++){
 
248
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
 
249
    }
 
250
    fprintf(stderr, "\n");
 
251
  }
 
252
  
 
253
 decrypt_end:
 
254
  
 
255
  /* Delete the GPGME cryptotext data buffer */
 
256
  gpgme_data_release(dh_crypto);
238
257
  
239
258
  /* Delete the GPGME plaintext data buffer */
240
259
  gpgme_data_release(dh_plain);
241
 
  return new_packet_length;
 
260
  return plaintext_length;
242
261
}
243
262
 
244
263
static const char * safer_gnutls_strerror (int value) {
253
272
  fprintf(stderr, "%s", string);
254
273
}
255
274
 
256
 
static int initgnutls(encrypted_session *es){
 
275
static int initgnutls(mandos_context *mc, gnutls_session_t *session,
 
276
                      gnutls_dh_params_t *dh_params){
257
277
  const char *err;
258
278
  int ret;
259
279
  
266
286
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
267
287
    return -1;
268
288
  }
269
 
 
 
289
  
270
290
  if (debug){
271
291
    gnutls_global_set_log_level(11);
272
292
    gnutls_global_set_log_function(debuggnutls);
273
293
  }
274
294
  
275
295
  /* openpgp credentials */
276
 
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
 
296
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
277
297
      != GNUTLS_E_SUCCESS) {
278
298
    fprintf (stderr, "memory error: %s\n",
279
299
             safer_gnutls_strerror(ret));
287
307
  }
288
308
  
289
309
  ret = gnutls_certificate_set_openpgp_key_file
290
 
    (es->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
310
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
291
311
  if (ret != GNUTLS_E_SUCCESS) {
292
312
    fprintf
293
313
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
299
319
  }
300
320
  
301
321
  //GnuTLS server initialization
302
 
  if ((ret = gnutls_dh_params_init (&es->dh_params))
 
322
  if ((ret = gnutls_dh_params_init(dh_params))
303
323
      != GNUTLS_E_SUCCESS) {
304
324
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
305
325
             safer_gnutls_strerror(ret));
306
326
    return -1;
307
327
  }
308
328
  
309
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, dh_bits))
 
329
  if ((ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits))
310
330
      != GNUTLS_E_SUCCESS) {
311
331
    fprintf (stderr, "Error in prime generation: %s\n",
312
332
             safer_gnutls_strerror(ret));
313
333
    return -1;
314
334
  }
315
335
  
316
 
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
 
336
  gnutls_certificate_set_dh_params(mc->cred, *dh_params);
317
337
  
318
338
  // GnuTLS session creation
319
 
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
 
339
  if ((ret = gnutls_init(session, GNUTLS_SERVER))
320
340
      != GNUTLS_E_SUCCESS){
321
341
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
322
342
            safer_gnutls_strerror(ret));
323
343
  }
324
344
  
325
 
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
 
345
  if ((ret = gnutls_priority_set_direct(*session, mc->priority, &err))
326
346
      != GNUTLS_E_SUCCESS) {
327
347
    fprintf(stderr, "Syntax error at: %s\n", err);
328
348
    fprintf(stderr, "GnuTLS error: %s\n",
330
350
    return -1;
331
351
  }
332
352
  
333
 
  if ((ret = gnutls_credentials_set
334
 
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
 
353
  if ((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
354
                                    mc->cred))
335
355
      != GNUTLS_E_SUCCESS) {
336
356
    fprintf(stderr, "Error setting a credentials set: %s\n",
337
357
            safer_gnutls_strerror(ret));
339
359
  }
340
360
  
341
361
  /* ignore client certificate if any. */
342
 
  gnutls_certificate_server_set_request (es->session,
 
362
  gnutls_certificate_server_set_request (*session,
343
363
                                         GNUTLS_CERT_IGNORE);
344
364
  
345
 
  gnutls_dh_set_prime_bits (es->session, dh_bits);
 
365
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
346
366
  
347
367
  return 0;
348
368
}
351
371
                      __attribute__((unused)) const char *txt){}
352
372
 
353
373
static int start_mandos_communication(const char *ip, uint16_t port,
354
 
                                      AvahiIfIndex if_index){
 
374
                                      AvahiIfIndex if_index,
 
375
                                      mandos_context *mc){
355
376
  int ret, tcp_sd;
356
377
  struct sockaddr_in6 to;
357
 
  encrypted_session es;
358
378
  char *buffer = NULL;
359
379
  char *decrypted_buffer;
360
380
  size_t buffer_length = 0;
363
383
  size_t written = 0;
364
384
  int retval = 0;
365
385
  char interface[IF_NAMESIZE];
 
386
  gnutls_session_t session;
 
387
  gnutls_dh_params_t dh_params;
366
388
  
367
389
  if(debug){
368
390
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
374
396
    perror("socket");
375
397
    return -1;
376
398
  }
377
 
  
378
 
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
379
 
    if(debug){
 
399
 
 
400
  if(debug){
 
401
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
380
402
      perror("if_indextoname");
 
403
      return -1;
381
404
    }
382
 
    return -1;
383
 
  }
384
 
  
385
 
  if(debug){
386
405
    fprintf(stderr, "Binding to interface %s\n", interface);
387
406
  }
388
407
  
392
411
  if (ret < 0 ){
393
412
    perror("inet_pton");
394
413
    return -1;
395
 
  }  
 
414
  }
396
415
  if(ret == 0){
397
416
    fprintf(stderr, "Bad address: %s\n", ip);
398
417
    return -1;
409
428
      perror("inet_ntop");
410
429
    } else {
411
430
      if(strcmp(addrstr, ip) != 0){
412
 
        fprintf(stderr, "Canonical address form: %s\n",
413
 
                addrstr, ntohs(to.sin6_port));
 
431
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
414
432
      }
415
433
    }
416
434
  }
421
439
    return -1;
422
440
  }
423
441
  
424
 
  ret = initgnutls (&es);
 
442
  ret = initgnutls (mc, &session, &dh_params);
425
443
  if (ret != 0){
426
444
    retval = -1;
427
445
    return -1;
428
446
  }
429
447
  
430
 
  gnutls_transport_set_ptr (es.session,
431
 
                            (gnutls_transport_ptr_t) tcp_sd);
 
448
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
432
449
  
433
450
  if(debug){
434
451
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
435
452
  }
436
453
  
437
 
  ret = gnutls_handshake (es.session);
 
454
  ret = gnutls_handshake (session);
438
455
  
439
456
  if (ret != GNUTLS_E_SUCCESS){
440
457
    if(debug){
462
479
      buffer_capacity += BUFFER_SIZE;
463
480
    }
464
481
    
465
 
    ret = gnutls_record_recv
466
 
      (es.session, buffer+buffer_length, BUFFER_SIZE);
 
482
    ret = gnutls_record_recv(session, buffer+buffer_length,
 
483
                             BUFFER_SIZE);
467
484
    if (ret == 0){
468
485
      break;
469
486
    }
473
490
      case GNUTLS_E_AGAIN:
474
491
        break;
475
492
      case GNUTLS_E_REHANDSHAKE:
476
 
        ret = gnutls_handshake (es.session);
 
493
        ret = gnutls_handshake (session);
477
494
        if (ret < 0){
478
495
          fprintf(stderr, "\n*** Handshake failed ***\n");
479
496
          gnutls_perror (ret);
485
502
        fprintf(stderr, "Unknown error while reading data from"
486
503
                " encrypted session with mandos server\n");
487
504
        retval = -1;
488
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
505
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
489
506
        goto exit;
490
507
      }
491
508
    } else {
526
543
  }
527
544
 
528
545
  free(buffer);
529
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
546
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
530
547
 exit:
531
548
  close(tcp_sd);
532
 
  gnutls_deinit (es.session);
533
 
  gnutls_certificate_free_credentials (es.cred);
 
549
  gnutls_deinit (session);
 
550
  gnutls_certificate_free_credentials (mc->cred);
534
551
  gnutls_global_deinit ();
535
552
  return retval;
536
553
}
537
554
 
538
 
static AvahiSimplePoll *simple_poll = NULL;
539
 
static AvahiServer *server = NULL;
540
 
 
541
 
static void resolve_callback(
542
 
    AvahiSServiceResolver *r,
543
 
    AvahiIfIndex interface,
544
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
545
 
    AvahiResolverEvent event,
546
 
    const char *name,
547
 
    const char *type,
548
 
    const char *domain,
549
 
    const char *host_name,
550
 
    const AvahiAddress *address,
551
 
    uint16_t port,
552
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
553
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
554
 
    AVAHI_GCC_UNUSED void* userdata) {
555
 
    
 
555
static void resolve_callback(AvahiSServiceResolver *r,
 
556
                             AvahiIfIndex interface,
 
557
                             AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
558
                             AvahiResolverEvent event,
 
559
                             const char *name,
 
560
                             const char *type,
 
561
                             const char *domain,
 
562
                             const char *host_name,
 
563
                             const AvahiAddress *address,
 
564
                             uint16_t port,
 
565
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
 
566
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
567
                             flags,
 
568
                             void* userdata) {
 
569
  mandos_context *mc = userdata;
556
570
  assert(r);                    /* Spurious warning */
557
571
  
558
572
  /* Called whenever a service has been resolved successfully or
563
577
  case AVAHI_RESOLVER_FAILURE:
564
578
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
565
579
            " type '%s' in domain '%s': %s\n", name, type, domain,
566
 
            avahi_strerror(avahi_server_errno(server)));
 
580
            avahi_strerror(avahi_server_errno(mc->server)));
567
581
    break;
568
582
    
569
583
  case AVAHI_RESOLVER_FOUND:
574
588
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
575
589
                " port %d\n", name, host_name, ip, port);
576
590
      }
577
 
      int ret = start_mandos_communication(ip, port, interface);
 
591
      int ret = start_mandos_communication(ip, port, interface, mc);
578
592
      if (ret == 0){
579
593
        exit(EXIT_SUCCESS);
580
594
      }
583
597
  avahi_s_service_resolver_free(r);
584
598
}
585
599
 
586
 
static void browse_callback(
587
 
    AvahiSServiceBrowser *b,
588
 
    AvahiIfIndex interface,
589
 
    AvahiProtocol protocol,
590
 
    AvahiBrowserEvent event,
591
 
    const char *name,
592
 
    const char *type,
593
 
    const char *domain,
594
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
595
 
    void* userdata) {
596
 
    
597
 
    AvahiServer *s = userdata;
598
 
    assert(b);                  /* Spurious warning */
599
 
    
600
 
    /* Called whenever a new services becomes available on the LAN or
601
 
       is removed from the LAN */
602
 
    
603
 
    switch (event) {
604
 
    default:
605
 
    case AVAHI_BROWSER_FAILURE:
606
 
      
607
 
      fprintf(stderr, "(Browser) %s\n",
608
 
              avahi_strerror(avahi_server_errno(server)));
609
 
      avahi_simple_poll_quit(simple_poll);
610
 
      return;
611
 
      
612
 
    case AVAHI_BROWSER_NEW:
613
 
      /* We ignore the returned resolver object. In the callback
614
 
         function we free it. If the server is terminated before
615
 
         the callback function is called the server will free
616
 
         the resolver for us. */
617
 
      
618
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
619
 
                                         type, domain,
620
 
                                         AVAHI_PROTO_INET6, 0,
621
 
                                         resolve_callback, s)))
622
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
623
 
                avahi_strerror(avahi_server_errno(s)));
624
 
      break;
625
 
      
626
 
    case AVAHI_BROWSER_REMOVE:
627
 
      break;
628
 
      
629
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
630
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
631
 
      break;
632
 
    }
 
600
static void browse_callback( AvahiSServiceBrowser *b,
 
601
                             AvahiIfIndex interface,
 
602
                             AvahiProtocol protocol,
 
603
                             AvahiBrowserEvent event,
 
604
                             const char *name,
 
605
                             const char *type,
 
606
                             const char *domain,
 
607
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
608
                             flags,
 
609
                             void* userdata) {
 
610
  mandos_context *mc = userdata;
 
611
  assert(b);                    /* Spurious warning */
 
612
  
 
613
  /* Called whenever a new services becomes available on the LAN or
 
614
     is removed from the LAN */
 
615
  
 
616
  switch (event) {
 
617
  default:
 
618
  case AVAHI_BROWSER_FAILURE:
 
619
    
 
620
    fprintf(stderr, "(Browser) %s\n",
 
621
            avahi_strerror(avahi_server_errno(mc->server)));
 
622
    avahi_simple_poll_quit(mc->simple_poll);
 
623
    return;
 
624
    
 
625
  case AVAHI_BROWSER_NEW:
 
626
    /* We ignore the returned resolver object. In the callback
 
627
       function we free it. If the server is terminated before
 
628
       the callback function is called the server will free
 
629
       the resolver for us. */
 
630
    
 
631
    if (!(avahi_s_service_resolver_new(mc->server, interface,
 
632
                                       protocol, name, type, domain,
 
633
                                       AVAHI_PROTO_INET6, 0,
 
634
                                       resolve_callback, mc)))
 
635
      fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
 
636
              avahi_strerror(avahi_server_errno(mc->server)));
 
637
    break;
 
638
    
 
639
  case AVAHI_BROWSER_REMOVE:
 
640
    break;
 
641
    
 
642
  case AVAHI_BROWSER_ALL_FOR_NOW:
 
643
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
644
    break;
 
645
  }
633
646
}
634
647
 
635
648
/* Combines file name and path and returns the malloced new
642
655
    return NULL;
643
656
  }
644
657
  if(f_len > 0){
645
 
    memcpy(tmp, first, f_len);
 
658
    memcpy(tmp, first, f_len);  /* Spurious warning */
646
659
  }
647
660
  tmp[f_len] = '/';
648
661
  if(s_len > 0){
649
 
    memcpy(tmp + f_len + 1, second, s_len);
 
662
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
650
663
  }
651
664
  tmp[f_len + 1 + s_len] = '\0';
652
665
  return tmp;
658
671
    AvahiSServiceBrowser *sb = NULL;
659
672
    int error;
660
673
    int ret;
661
 
    int debug_int = 0;
 
674
    int debug_int;
662
675
    int returncode = EXIT_SUCCESS;
663
 
    const char *interface = NULL;
 
676
    const char *interface = "eth0";
 
677
    struct ifreq network;
 
678
    int sd;
 
679
    char *connect_to = NULL;
664
680
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
665
 
    char *connect_to = NULL;
 
681
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
 
682
                          .dh_bits = 1024, .priority = "SECURE256"};
666
683
    
667
684
    debug_int = debug ? 1 : 0;
668
685
    while (true){
669
 
      static struct option long_options[] = {
 
686
      struct option long_options[] = {
670
687
        {"debug", no_argument, &debug_int, 1},
671
 
        {"connect", required_argument, NULL, 'C'},
 
688
        {"connect", required_argument, NULL, 'c'},
672
689
        {"interface", required_argument, NULL, 'i'},
673
690
        {"keydir", required_argument, NULL, 'd'},
674
 
        {"seckey", required_argument, NULL, 'c'},
675
 
        {"pubkey", required_argument, NULL, 'k'},
 
691
        {"seckey", required_argument, NULL, 's'},
 
692
        {"pubkey", required_argument, NULL, 'p'},
676
693
        {"dh-bits", required_argument, NULL, 'D'},
 
694
        {"priority", required_argument, NULL, 'P'},
677
695
        {0, 0, 0, 0} };
678
696
      
679
697
      int option_index = 0;
690
708
      case 'i':
691
709
        interface = optarg;
692
710
        break;
693
 
      case 'C':
 
711
      case 'c':
694
712
        connect_to = optarg;
695
713
        break;
696
714
      case 'd':
697
715
        keydir = optarg;
698
716
        break;
699
 
      case 'c':
 
717
      case 'p':
700
718
        pubkeyfile = optarg;
701
719
        break;
702
 
      case 'k':
 
720
      case 's':
703
721
        seckeyfile = optarg;
704
722
        break;
705
723
      case 'D':
706
 
        dh_bits = atoi(optarg);
 
724
        errno = 0;
 
725
        mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
 
726
        if (errno){
 
727
          perror("strtol");
 
728
          exit(EXIT_FAILURE);
 
729
        }
 
730
        break;
 
731
      case 'P':
 
732
        mc.priority = optarg;
707
733
        break;
708
734
      case '?':
709
 
        break
710
735
      default:
711
736
        exit(EXIT_FAILURE);
712
737
      }
716
741
    pubkeyfile = combinepath(keydir, pubkeyfile);
717
742
    if (pubkeyfile == NULL){
718
743
      perror("combinepath");
719
 
      goto exit;
720
 
    }
721
 
    
722
 
    if(interface != NULL){
723
 
      if_index = (AvahiIfIndex) if_nametoindex(interface);
724
 
      if(if_index == 0){
725
 
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
726
 
        exit(EXIT_FAILURE);
727
 
      }
 
744
      returncode = EXIT_FAILURE;
 
745
      goto exit;
 
746
    }
 
747
    
 
748
    seckeyfile = combinepath(keydir, seckeyfile);
 
749
    if (seckeyfile == NULL){
 
750
      perror("combinepath");
 
751
      goto exit;
 
752
    }
 
753
    
 
754
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
755
    if(if_index == 0){
 
756
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
757
      exit(EXIT_FAILURE);
728
758
    }
729
759
    
730
760
    if(connect_to != NULL){
743
773
      }
744
774
      *address = '\0';
745
775
      address = connect_to;
746
 
      ret = start_mandos_communication(address, port, if_index);
 
776
      ret = start_mandos_communication(address, port, if_index, &mc);
747
777
      if(ret < 0){
748
778
        exit(EXIT_FAILURE);
749
779
      } else {
751
781
      }
752
782
    }
753
783
    
754
 
    seckeyfile = combinepath(keydir, seckeyfile);
755
 
    if (seckeyfile == NULL){
756
 
      perror("combinepath");
757
 
      goto exit;
758
 
    }
 
784
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
785
    if(sd < 0) {
 
786
      perror("socket");
 
787
      returncode = EXIT_FAILURE;
 
788
      goto exit;
 
789
    }
 
790
    strcpy(network.ifr_name, interface); /* Spurious warning */
 
791
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
792
    if(ret == -1){
 
793
      
 
794
      perror("ioctl SIOCGIFFLAGS");
 
795
      returncode = EXIT_FAILURE;
 
796
      goto exit;
 
797
    }
 
798
    if((network.ifr_flags & IFF_UP) == 0){
 
799
      network.ifr_flags |= IFF_UP;
 
800
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
801
      if(ret == -1){
 
802
        perror("ioctl SIOCSIFFLAGS");
 
803
        returncode = EXIT_FAILURE;
 
804
        goto exit;
 
805
      }
 
806
    }
 
807
    close(sd);
759
808
    
760
809
    if (not debug){
761
810
      avahi_set_log_function(empty_log);
765
814
    srand((unsigned int) time(NULL));
766
815
 
767
816
    /* Allocate main loop object */
768
 
    if (!(simple_poll = avahi_simple_poll_new())) {
 
817
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
769
818
        fprintf(stderr, "Failed to create simple poll object.\n");
770
 
        
 
819
        returncode = EXIT_FAILURE;
771
820
        goto exit;
772
821
    }
773
822
 
779
828
    config.publish_domain = 0;
780
829
 
781
830
    /* Allocate a new server */
782
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
783
 
                              &config, NULL, NULL, &error);
784
 
 
 
831
    mc.server=avahi_server_new(avahi_simple_poll_get(mc.simple_poll),
 
832
                               &config, NULL, NULL, &error);
 
833
    
785
834
    /* Free the configuration data */
786
835
    avahi_server_config_free(&config);
787
 
 
 
836
    
788
837
    /* Check if creating the server object succeeded */
789
 
    if (!server) {
 
838
    if (!mc.server) {
790
839
        fprintf(stderr, "Failed to create server: %s\n",
791
840
                avahi_strerror(error));
792
841
        returncode = EXIT_FAILURE;
794
843
    }
795
844
    
796
845
    /* Create the service browser */
797
 
    sb = avahi_s_service_browser_new(server, if_index,
 
846
    sb = avahi_s_service_browser_new(mc.server, if_index,
798
847
                                     AVAHI_PROTO_INET6,
799
848
                                     "_mandos._tcp", NULL, 0,
800
 
                                     browse_callback, server);
 
849
                                     browse_callback, &mc);
801
850
    if (!sb) {
802
851
        fprintf(stderr, "Failed to create service browser: %s\n",
803
 
                avahi_strerror(avahi_server_errno(server)));
 
852
                avahi_strerror(avahi_server_errno(mc.server)));
804
853
        returncode = EXIT_FAILURE;
805
854
        goto exit;
806
855
    }
811
860
      fprintf(stderr, "Starting avahi loop search\n");
812
861
    }
813
862
    
814
 
    avahi_simple_poll_loop(simple_poll);
 
863
    avahi_simple_poll_loop(mc.simple_poll);
815
864
    
816
865
 exit:
817
866
 
823
872
    if (sb)
824
873
        avahi_s_service_browser_free(sb);
825
874
    
826
 
    if (server)
827
 
        avahi_server_free(server);
 
875
    if (mc.server)
 
876
        avahi_server_free(mc.server);
828
877
 
829
 
    if (simple_poll)
830
 
        avahi_simple_poll_free(simple_poll);
 
878
    if (mc.simple_poll)
 
879
        avahi_simple_poll_free(mc.simple_poll);
831
880
    free(pubkeyfile);
832
881
    free(seckeyfile);
833
882