/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-31 19:48:05 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080731194805-mseis21dxwrdfqhk
* plugins.d/mandosclient.c (start_mandos_communication): Changed
                                                        "if_index" to
                                                        be of type
                                                        "AvahiIfIndex".
                                                        All callers
                                                        changed.
 (main): Add default values to "interface" and "if_index".  Only
         change if_index from default if "interface" was given.

* server.py (IPv6_TCPServer.server_bind): Bug fix: test if interface
                                          is empty, not if equal to
                                          avahi.IF_UNSPEC.
  (if_nametoindex): Bug fix; typo: assign to _func[0], not func[0].
  (main): Bug fix: Do not set service.interface unless the interface
          setting has been given.

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