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

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
 * includes the following functions: "resolve_callback",
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
 
 * Everything else is
12
 
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
11
 * Everything else is Copyright © 2007-2008 Teddy Hogeborn and Björn
 
12
 * Påhlsson.
13
13
 * 
14
14
 * This program is free software: you can redistribute it and/or
15
15
 * modify it under the terms of the GNU General Public License as
25
25
 * along with this program.  If not, see
26
26
 * <http://www.gnu.org/licenses/>.
27
27
 * 
28
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
28
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
29
 * <https://www.fukt.bsnet.se/~teddy/>.
29
30
 */
30
31
 
31
 
/* Needed by GPGME, specifically gpgme_data_seek() */
 
32
#define _FORTIFY_SOURCE 2
 
33
 
32
34
#define _LARGEFILE_SOURCE
33
35
#define _FILE_OFFSET_BITS 64
34
36
 
37
39
#include <stdlib.h>
38
40
#include <time.h>
39
41
#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 */
44
42
 
45
43
#include <avahi-core/core.h>
46
44
#include <avahi-core/lookup.h>
67
65
#include <errno.h>              /* perror() */
68
66
#include <gpgme.h>
69
67
 
70
 
// getopt_long
 
68
// getopt long
71
69
#include <getopt.h>
72
70
 
 
71
#ifndef CERT_ROOT
 
72
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
 
73
#endif
 
74
#define CERTFILE CERT_ROOT "openpgp-client.txt"
 
75
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
73
76
#define BUFFER_SIZE 256
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
#define DH_BITS 1024
78
78
 
79
79
bool debug = false;
80
80
 
81
 
/* Used for passing in values through all the callback functions */
82
81
typedef struct {
83
 
  AvahiSimplePoll *simple_poll;
84
 
  AvahiServer *server;
 
82
  gnutls_session_t session;
85
83
  gnutls_certificate_credentials_t cred;
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){
 
84
  gnutls_dh_params_t dh_params;
 
85
} encrypted_session;
 
86
 
 
87
 
 
88
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
89
                            char **new_packet, const char *homedir){
98
90
  gpgme_data_t dh_crypto, dh_plain;
99
91
  gpgme_ctx_t ctx;
100
92
  gpgme_error_t rc;
101
93
  ssize_t ret;
102
 
  ssize_t plaintext_capacity = 0;
103
 
  ssize_t plaintext_length = 0;
 
94
  ssize_t new_packet_capacity = 0;
 
95
  ssize_t new_packet_length = 0;
104
96
  gpgme_engine_info_t engine_info;
105
 
  
 
97
 
106
98
  if (debug){
107
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
99
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
108
100
  }
109
101
  
110
102
  /* Init GPGME */
111
103
  gpgme_check_version(NULL);
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
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
118
105
  
119
 
  /* Set GPGME home directory for the OpenPGP engine only */
 
106
  /* Set GPGME home directory */
120
107
  rc = gpgme_get_engine_info (&engine_info);
121
108
  if (rc != GPG_ERR_NO_ERROR){
122
109
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
132
119
    engine_info = engine_info->next;
133
120
  }
134
121
  if(engine_info == NULL){
135
 
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
 
122
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
136
123
    return -1;
137
124
  }
138
125
  
139
 
  /* Create new GPGME data buffer from memory cryptotext */
140
 
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
141
 
                               0);
 
126
  /* Create new GPGME data buffer from packet buffer */
 
127
  rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
142
128
  if (rc != GPG_ERR_NO_ERROR){
143
129
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
144
130
            gpgme_strsource(rc), gpgme_strerror(rc));
150
136
  if (rc != GPG_ERR_NO_ERROR){
151
137
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
152
138
            gpgme_strsource(rc), gpgme_strerror(rc));
153
 
    gpgme_data_release(dh_crypto);
154
139
    return -1;
155
140
  }
156
141
  
159
144
  if (rc != GPG_ERR_NO_ERROR){
160
145
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
161
146
            gpgme_strsource(rc), gpgme_strerror(rc));
162
 
    plaintext_length = -1;
163
 
    goto decrypt_end;
 
147
    return -1;
164
148
  }
165
149
  
166
 
  /* Decrypt data from the cryptotext data buffer to the plaintext
167
 
     data buffer */
 
150
  /* Decrypt data from the FILE pointer to the plaintext data
 
151
     buffer */
168
152
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
169
153
  if (rc != GPG_ERR_NO_ERROR){
170
154
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
171
155
            gpgme_strsource(rc), gpgme_strerror(rc));
172
 
    plaintext_length = -1;
173
 
    goto decrypt_end;
 
156
    return -1;
174
157
  }
175
 
  
 
158
 
176
159
  if(debug){
177
 
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
 
160
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
178
161
  }
179
 
  
 
162
 
180
163
  if (debug){
181
164
    gpgme_decrypt_result_t result;
182
165
    result = gpgme_op_decrypt_result(ctx);
206
189
    }
207
190
  }
208
191
  
 
192
  /* Delete the GPGME FILE pointer cryptotext data buffer */
 
193
  gpgme_data_release(dh_crypto);
 
194
  
209
195
  /* Seek back to the beginning of the GPGME plaintext data buffer */
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;
 
196
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
 
197
 
 
198
  *new_packet = 0;
217
199
  while(true){
218
 
    if (plaintext_length + BUFFER_SIZE > plaintext_capacity){
219
 
      *plaintext = realloc(*plaintext,
220
 
                            (unsigned int)plaintext_capacity
 
200
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
 
201
      *new_packet = realloc(*new_packet,
 
202
                            (unsigned int)new_packet_capacity
221
203
                            + BUFFER_SIZE);
222
 
      if (*plaintext == NULL){
 
204
      if (*new_packet == NULL){
223
205
        perror("realloc");
224
 
        plaintext_length = -1;
225
 
        goto decrypt_end;
 
206
        return -1;
226
207
      }
227
 
      plaintext_capacity += BUFFER_SIZE;
 
208
      new_packet_capacity += BUFFER_SIZE;
228
209
    }
229
210
    
230
 
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
 
211
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
231
212
                          BUFFER_SIZE);
232
213
    /* Print the data, if any */
233
214
    if (ret == 0){
234
 
      /* EOF */
235
215
      break;
236
216
    }
237
217
    if(ret < 0){
238
218
      perror("gpgme_data_read");
239
 
      plaintext_length = -1;
240
 
      goto decrypt_end;
 
219
      return -1;
241
220
    }
242
 
    plaintext_length += ret;
 
221
    new_packet_length += ret;
243
222
  }
244
223
 
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);
 
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
  /*   } */
257
231
  
258
232
  /* Delete the GPGME plaintext data buffer */
259
233
  gpgme_data_release(dh_plain);
260
 
  return plaintext_length;
 
234
  return new_packet_length;
261
235
}
262
236
 
263
237
static const char * safer_gnutls_strerror (int value) {
267
241
  return ret;
268
242
}
269
243
 
270
 
static void debuggnutls(__attribute__((unused)) int level,
271
 
                        const char* string){
 
244
void debuggnutls(__attribute__((unused)) int level,
 
245
                 const char* string){
272
246
  fprintf(stderr, "%s", string);
273
247
}
274
248
 
275
 
static int initgnutls(mandos_context *mc, gnutls_session_t *session,
276
 
                      gnutls_dh_params_t *dh_params){
 
249
int initgnutls(encrypted_session *es){
277
250
  const char *err;
278
251
  int ret;
279
252
  
280
253
  if(debug){
281
254
    fprintf(stderr, "Initializing GnuTLS\n");
282
255
  }
283
 
 
 
256
  
284
257
  if ((ret = gnutls_global_init ())
285
258
      != GNUTLS_E_SUCCESS) {
286
259
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
287
260
    return -1;
288
261
  }
289
 
  
 
262
 
290
263
  if (debug){
291
264
    gnutls_global_set_log_level(11);
292
265
    gnutls_global_set_log_function(debuggnutls);
293
266
  }
294
267
  
295
268
  /* openpgp credentials */
296
 
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
 
269
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
297
270
      != GNUTLS_E_SUCCESS) {
298
271
    fprintf (stderr, "memory error: %s\n",
299
272
             safer_gnutls_strerror(ret));
302
275
  
303
276
  if(debug){
304
277
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
305
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
306
 
            seckeyfile);
 
278
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
 
279
            KEYFILE);
307
280
  }
308
281
  
309
282
  ret = gnutls_certificate_set_openpgp_key_file
310
 
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
283
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
311
284
  if (ret != GNUTLS_E_SUCCESS) {
312
285
    fprintf
313
286
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
314
287
       " '%s')\n",
315
 
       ret, pubkeyfile, seckeyfile);
 
288
       ret, CERTFILE, KEYFILE);
316
289
    fprintf(stdout, "The Error is: %s\n",
317
290
            safer_gnutls_strerror(ret));
318
291
    return -1;
319
292
  }
320
293
  
321
294
  //GnuTLS server initialization
322
 
  if ((ret = gnutls_dh_params_init(dh_params))
 
295
  if ((ret = gnutls_dh_params_init (&es->dh_params))
323
296
      != GNUTLS_E_SUCCESS) {
324
297
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
325
298
             safer_gnutls_strerror(ret));
326
299
    return -1;
327
300
  }
328
301
  
329
 
  if ((ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits))
 
302
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
330
303
      != GNUTLS_E_SUCCESS) {
331
304
    fprintf (stderr, "Error in prime generation: %s\n",
332
305
             safer_gnutls_strerror(ret));
333
306
    return -1;
334
307
  }
335
308
  
336
 
  gnutls_certificate_set_dh_params(mc->cred, *dh_params);
 
309
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
337
310
  
338
311
  // GnuTLS session creation
339
 
  if ((ret = gnutls_init(session, GNUTLS_SERVER))
 
312
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
340
313
      != GNUTLS_E_SUCCESS){
341
314
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
342
315
            safer_gnutls_strerror(ret));
343
316
  }
344
317
  
345
 
  if ((ret = gnutls_priority_set_direct(*session, mc->priority, &err))
 
318
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
346
319
      != GNUTLS_E_SUCCESS) {
347
320
    fprintf(stderr, "Syntax error at: %s\n", err);
348
321
    fprintf(stderr, "GnuTLS error: %s\n",
350
323
    return -1;
351
324
  }
352
325
  
353
 
  if ((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
354
 
                                    mc->cred))
 
326
  if ((ret = gnutls_credentials_set
 
327
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
355
328
      != GNUTLS_E_SUCCESS) {
356
329
    fprintf(stderr, "Error setting a credentials set: %s\n",
357
330
            safer_gnutls_strerror(ret));
359
332
  }
360
333
  
361
334
  /* ignore client certificate if any. */
362
 
  gnutls_certificate_server_set_request (*session,
 
335
  gnutls_certificate_server_set_request (es->session,
363
336
                                         GNUTLS_CERT_IGNORE);
364
337
  
365
 
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
 
338
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
366
339
  
367
340
  return 0;
368
341
}
369
342
 
370
 
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
371
 
                      __attribute__((unused)) const char *txt){}
 
343
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
344
               __attribute__((unused)) const char *txt){}
372
345
 
373
 
static int start_mandos_communication(const char *ip, uint16_t port,
374
 
                                      AvahiIfIndex if_index,
375
 
                                      mandos_context *mc){
 
346
int start_mandos_communication(const char *ip, uint16_t port,
 
347
                               unsigned int if_index){
376
348
  int ret, tcp_sd;
377
349
  struct sockaddr_in6 to;
 
350
  encrypted_session es;
378
351
  char *buffer = NULL;
379
352
  char *decrypted_buffer;
380
353
  size_t buffer_length = 0;
383
356
  size_t written = 0;
384
357
  int retval = 0;
385
358
  char interface[IF_NAMESIZE];
386
 
  gnutls_session_t session;
387
 
  gnutls_dh_params_t dh_params;
388
359
  
389
360
  if(debug){
390
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
391
 
            ip, port);
 
361
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
392
362
  }
393
363
  
394
364
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
396
366
    perror("socket");
397
367
    return -1;
398
368
  }
399
 
 
400
 
  if(debug){
401
 
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
369
  
 
370
  if(if_indextoname(if_index, interface) == NULL){
 
371
    if(debug){
402
372
      perror("if_indextoname");
403
 
      return -1;
404
373
    }
 
374
    return -1;
 
375
  }
 
376
  
 
377
  if(debug){
405
378
    fprintf(stderr, "Binding to interface %s\n", interface);
406
379
  }
407
380
  
411
384
  if (ret < 0 ){
412
385
    perror("inet_pton");
413
386
    return -1;
414
 
  }
 
387
  }  
415
388
  if(ret == 0){
416
389
    fprintf(stderr, "Bad address: %s\n", ip);
417
390
    return -1;
421
394
  to.sin6_scope_id = (uint32_t)if_index;
422
395
  
423
396
  if(debug){
424
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
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
 
    }
 
397
    fprintf(stderr, "Connection to: %s\n", ip);
434
398
  }
435
399
  
436
400
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
439
403
    return -1;
440
404
  }
441
405
  
442
 
  ret = initgnutls (mc, &session, &dh_params);
 
406
  ret = initgnutls (&es);
443
407
  if (ret != 0){
444
408
    retval = -1;
445
409
    return -1;
446
410
  }
447
411
  
448
 
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
 
412
  gnutls_transport_set_ptr (es.session,
 
413
                            (gnutls_transport_ptr_t) tcp_sd);
449
414
  
450
415
  if(debug){
451
416
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
452
417
  }
453
418
  
454
 
  ret = gnutls_handshake (session);
 
419
  ret = gnutls_handshake (es.session);
455
420
  
456
421
  if (ret != GNUTLS_E_SUCCESS){
457
422
    if(debug){
479
444
      buffer_capacity += BUFFER_SIZE;
480
445
    }
481
446
    
482
 
    ret = gnutls_record_recv(session, buffer+buffer_length,
483
 
                             BUFFER_SIZE);
 
447
    ret = gnutls_record_recv
 
448
      (es.session, buffer+buffer_length, BUFFER_SIZE);
484
449
    if (ret == 0){
485
450
      break;
486
451
    }
490
455
      case GNUTLS_E_AGAIN:
491
456
        break;
492
457
      case GNUTLS_E_REHANDSHAKE:
493
 
        ret = gnutls_handshake (session);
 
458
        ret = gnutls_handshake (es.session);
494
459
        if (ret < 0){
495
460
          fprintf(stderr, "\n*** Handshake failed ***\n");
496
461
          gnutls_perror (ret);
502
467
        fprintf(stderr, "Unknown error while reading data from"
503
468
                " encrypted session with mandos server\n");
504
469
        retval = -1;
505
 
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
470
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
506
471
        goto exit;
507
472
      }
508
473
    } else {
514
479
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
515
480
                                               buffer_length,
516
481
                                               &decrypted_buffer,
517
 
                                               keydir);
 
482
                                               CERT_ROOT);
518
483
    if (decrypted_buffer_size >= 0){
519
 
      while(written < (size_t) decrypted_buffer_size){
 
484
      while(written < decrypted_buffer_size){
520
485
        ret = (int)fwrite (decrypted_buffer + written, 1,
521
486
                           (size_t)decrypted_buffer_size - written,
522
487
                           stdout);
543
508
  }
544
509
 
545
510
  free(buffer);
546
 
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
511
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
547
512
 exit:
548
513
  close(tcp_sd);
549
 
  gnutls_deinit (session);
550
 
  gnutls_certificate_free_credentials (mc->cred);
 
514
  gnutls_deinit (es.session);
 
515
  gnutls_certificate_free_credentials (es.cred);
551
516
  gnutls_global_deinit ();
552
517
  return retval;
553
518
}
554
519
 
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;
 
520
static AvahiSimplePoll *simple_poll = NULL;
 
521
static AvahiServer *server = NULL;
 
522
 
 
523
static void resolve_callback(
 
524
    AvahiSServiceResolver *r,
 
525
    AvahiIfIndex interface,
 
526
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
527
    AvahiResolverEvent event,
 
528
    const char *name,
 
529
    const char *type,
 
530
    const char *domain,
 
531
    const char *host_name,
 
532
    const AvahiAddress *address,
 
533
    uint16_t port,
 
534
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
535
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
536
    AVAHI_GCC_UNUSED void* userdata) {
 
537
    
570
538
  assert(r);                    /* Spurious warning */
571
539
  
572
540
  /* Called whenever a service has been resolved successfully or
577
545
  case AVAHI_RESOLVER_FAILURE:
578
546
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
579
547
            " type '%s' in domain '%s': %s\n", name, type, domain,
580
 
            avahi_strerror(avahi_server_errno(mc->server)));
 
548
            avahi_strerror(avahi_server_errno(server)));
581
549
    break;
582
550
    
583
551
  case AVAHI_RESOLVER_FOUND:
588
556
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
589
557
                " port %d\n", name, host_name, ip, port);
590
558
      }
591
 
      int ret = start_mandos_communication(ip, port, interface, mc);
 
559
      int ret = start_mandos_communication(ip, port,
 
560
                                           (unsigned int) interface);
592
561
      if (ret == 0){
593
562
        exit(EXIT_SUCCESS);
594
563
      }
597
566
  avahi_s_service_resolver_free(r);
598
567
}
599
568
 
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
 
 
 
569
static void browse_callback(
 
570
    AvahiSServiceBrowser *b,
 
571
    AvahiIfIndex interface,
 
572
    AvahiProtocol protocol,
 
573
    AvahiBrowserEvent event,
 
574
    const char *name,
 
575
    const char *type,
 
576
    const char *domain,
 
577
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
578
    void* userdata) {
 
579
    
 
580
    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
    
 
586
    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;
 
615
    }
 
616
}
668
617
 
669
618
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
670
619
    AvahiServerConfig config;
671
620
    AvahiSServiceBrowser *sb = NULL;
672
621
    int error;
673
622
    int ret;
674
 
    int debug_int;
675
623
    int returncode = EXIT_SUCCESS;
676
624
    const char *interface = "eth0";
677
 
    struct ifreq network;
678
 
    int sd;
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"};
683
625
    
684
 
    debug_int = debug ? 1 : 0;
685
626
    while (true){
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'},
 
627
      static struct option long_options[] = {
 
628
        {"debug", no_argument, (int *)&debug, 1},
 
629
        {"interface", required_argument, 0, 'i'},
695
630
        {0, 0, 0, 0} };
696
631
      
697
632
      int option_index = 0;
708
643
      case 'i':
709
644
        interface = optarg;
710
645
        break;
711
 
      case 'c':
712
 
        connect_to = optarg;
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 '?':
735
646
      default:
736
647
        exit(EXIT_FAILURE);
737
648
      }
738
649
    }
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);
755
 
    if(if_index == 0){
756
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
757
 
      exit(EXIT_FAILURE);
758
 
    }
759
 
    
760
 
    if(connect_to != NULL){
761
 
      /* Connect directly, do not use Zeroconf */
762
 
      /* (Mainly meant for debugging) */
763
 
      char *address = strrchr(connect_to, ':');
764
 
      if(address == NULL){
765
 
        fprintf(stderr, "No colon in address\n");
766
 
        exit(EXIT_FAILURE);
767
 
      }
768
 
      errno = 0;
769
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
770
 
      if(errno){
771
 
        perror("Bad port number");
772
 
        exit(EXIT_FAILURE);
773
 
      }
774
 
      *address = '\0';
775
 
      address = connect_to;
776
 
      ret = start_mandos_communication(address, port, if_index, &mc);
777
 
      if(ret < 0){
778
 
        exit(EXIT_FAILURE);
779
 
      } else {
780
 
        exit(EXIT_SUCCESS);
781
 
      }
782
 
    }
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
650
    
809
651
    if (not debug){
810
652
      avahi_set_log_function(empty_log);
814
656
    srand((unsigned int) time(NULL));
815
657
 
816
658
    /* Allocate main loop object */
817
 
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
 
659
    if (!(simple_poll = avahi_simple_poll_new())) {
818
660
        fprintf(stderr, "Failed to create simple poll object.\n");
819
 
        returncode = EXIT_FAILURE;
 
661
        
820
662
        goto exit;
821
663
    }
822
664
 
828
670
    config.publish_domain = 0;
829
671
 
830
672
    /* Allocate a new server */
831
 
    mc.server=avahi_server_new(avahi_simple_poll_get(mc.simple_poll),
832
 
                               &config, NULL, NULL, &error);
833
 
    
 
673
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
674
                              &config, NULL, NULL, &error);
 
675
 
834
676
    /* Free the configuration data */
835
677
    avahi_server_config_free(&config);
836
 
    
 
678
 
837
679
    /* Check if creating the server object succeeded */
838
 
    if (!mc.server) {
 
680
    if (!server) {
839
681
        fprintf(stderr, "Failed to create server: %s\n",
840
682
                avahi_strerror(error));
841
683
        returncode = EXIT_FAILURE;
843
685
    }
844
686
    
845
687
    /* Create the service browser */
846
 
    sb = avahi_s_service_browser_new(mc.server, if_index,
 
688
    sb = avahi_s_service_browser_new(server,
 
689
                                     (AvahiIfIndex)
 
690
                                     if_nametoindex(interface),
847
691
                                     AVAHI_PROTO_INET6,
848
692
                                     "_mandos._tcp", NULL, 0,
849
 
                                     browse_callback, &mc);
 
693
                                     browse_callback, server);
850
694
    if (!sb) {
851
695
        fprintf(stderr, "Failed to create service browser: %s\n",
852
 
                avahi_strerror(avahi_server_errno(mc.server)));
 
696
                avahi_strerror(avahi_server_errno(server)));
853
697
        returncode = EXIT_FAILURE;
854
698
        goto exit;
855
699
    }
860
704
      fprintf(stderr, "Starting avahi loop search\n");
861
705
    }
862
706
    
863
 
    avahi_simple_poll_loop(mc.simple_poll);
 
707
    avahi_simple_poll_loop(simple_poll);
864
708
    
865
709
 exit:
866
710
 
872
716
    if (sb)
873
717
        avahi_s_service_browser_free(sb);
874
718
    
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
 
    
 
719
    if (server)
 
720
        avahi_server_free(server);
 
721
 
 
722
    if (simple_poll)
 
723
        avahi_simple_poll_free(simple_poll);
 
724
 
883
725
    return returncode;
884
726
}