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