/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:
1
 
/* $Id$ */
2
 
 
3
 
/* PLEASE NOTE *
4
 
 * This file demonstrates how to use Avahi's core API, this is
5
 
 * the embeddable mDNS stack for embedded applications.
 
1
/*  -*- coding: utf-8 -*- */
 
2
/*
 
3
 * Mandos client - get and decrypt data from a Mandos server
6
4
 *
7
 
 * End user applications should *not* use this API and should use
8
 
 * the D-Bus or C APIs, please see
9
 
 * client-browse-services.c and glib-integration.c
10
 
 * 
11
 
 * I repeat, you probably do *not* want to use this example.
 
5
 * This program is partly derived from an example program for an Avahi
 
6
 * service browser, downloaded from
 
7
 * <http://avahi.org/browser/examples/core-browse-services.c>.  This
 
8
 * includes the following functions: "resolve_callback",
 
9
 * "browse_callback", and parts of "main".
 
10
 * 
 
11
 * Everything else is
 
12
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
13
 * 
 
14
 * This program is free software: you can redistribute it and/or
 
15
 * modify it under the terms of the GNU General Public License as
 
16
 * published by the Free Software Foundation, either version 3 of the
 
17
 * License, or (at your option) any later version.
 
18
 * 
 
19
 * This program is distributed in the hope that it will be useful, but
 
20
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
22
 * General Public License for more details.
 
23
 * 
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program.  If not, see
 
26
 * <http://www.gnu.org/licenses/>.
 
27
 * 
 
28
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
29
 * <https://www.fukt.bsnet.se/~teddy/>.
12
30
 */
13
31
 
14
 
/***
15
 
  This file is part of avahi.
16
 
 
17
 
  avahi is free software; you can redistribute it and/or modify it
18
 
  under the terms of the GNU Lesser General Public License as
19
 
  published by the Free Software Foundation; either version 2.1 of the
20
 
  License, or (at your option) any later version.
21
 
 
22
 
  avahi is distributed in the hope that it will be useful, but WITHOUT
23
 
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24
 
  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
25
 
  Public License for more details.
26
 
 
27
 
  You should have received a copy of the GNU Lesser General Public
28
 
  License along with avahi; if not, write to the Free Software
29
 
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30
 
  USA.
31
 
***/
32
 
 
 
32
/* Needed by GPGME, specifically gpgme_data_seek() */
33
33
#define _LARGEFILE_SOURCE
34
34
#define _FILE_OFFSET_BITS 64
35
35
 
47
47
#include <avahi-common/error.h>
48
48
 
49
49
//mandos client part
50
 
#include <sys/types.h>          /* socket(), setsockopt(), inet_pton() */
51
 
#include <sys/socket.h>         /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */
52
 
#include <gnutls/gnutls.h>      /* ALL GNUTLS STUFF */
53
 
#include <gnutls/openpgp.h>     /* gnutls with openpgp stuff */
 
50
#include <sys/types.h>          /* socket(), inet_pton() */
 
51
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
52
                                   struct in6_addr, inet_pton() */
 
53
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
 
54
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
54
55
 
55
56
#include <unistd.h>             /* close() */
56
57
#include <netinet/in.h>
63
64
#include <errno.h>              /* perror() */
64
65
#include <gpgme.h>
65
66
 
 
67
// getopt long
 
68
#include <getopt.h>
66
69
 
67
70
#ifndef CERT_ROOT
68
71
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
72
75
#define BUFFER_SIZE 256
73
76
#define DH_BITS 1024
74
77
 
 
78
bool debug = false;
 
79
 
75
80
typedef struct {
76
81
  gnutls_session_t session;
77
82
  gnutls_certificate_credentials_t cred;
79
84
} encrypted_session;
80
85
 
81
86
 
82
 
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
 
87
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
88
                            char **new_packet, const char *homedir){
83
89
  gpgme_data_t dh_crypto, dh_plain;
84
90
  gpgme_ctx_t ctx;
85
91
  gpgme_error_t rc;
86
92
  ssize_t ret;
87
 
  size_t new_packet_capacity = 0;
88
 
  size_t new_packet_length = 0;
 
93
  ssize_t new_packet_capacity = 0;
 
94
  ssize_t new_packet_length = 0;
89
95
  gpgme_engine_info_t engine_info;
90
96
 
 
97
  if (debug){
 
98
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
99
  }
 
100
  
91
101
  /* Init GPGME */
92
102
  gpgme_check_version(NULL);
93
103
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
136
146
    return -1;
137
147
  }
138
148
  
139
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
149
  /* Decrypt data from the FILE pointer to the plaintext data
 
150
     buffer */
140
151
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
141
152
  if (rc != GPG_ERR_NO_ERROR){
142
153
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
143
154
            gpgme_strsource(rc), gpgme_strerror(rc));
144
155
    return -1;
145
156
  }
 
157
 
 
158
  if(debug){
 
159
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
 
160
  }
 
161
 
 
162
  if (debug){
 
163
    gpgme_decrypt_result_t result;
 
164
    result = gpgme_op_decrypt_result(ctx);
 
165
    if (result == NULL){
 
166
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
167
    } else {
 
168
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
169
              result->unsupported_algorithm);
 
170
      fprintf(stderr, "Wrong key usage: %d\n",
 
171
              result->wrong_key_usage);
 
172
      if(result->file_name != NULL){
 
173
        fprintf(stderr, "File name: %s\n", result->file_name);
 
174
      }
 
175
      gpgme_recipient_t recipient;
 
176
      recipient = result->recipients;
 
177
      if(recipient){
 
178
        while(recipient != NULL){
 
179
          fprintf(stderr, "Public key algorithm: %s\n",
 
180
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
181
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
182
          fprintf(stderr, "Secret key available: %s\n",
 
183
                  recipient->status == GPG_ERR_NO_SECKEY
 
184
                  ? "No" : "Yes");
 
185
          recipient = recipient->next;
 
186
        }
 
187
      }
 
188
    }
 
189
  }
146
190
  
147
 
/*   gpgme_decrypt_result_t result; */
148
 
/*   result = gpgme_op_decrypt_result(ctx); */
149
 
/*   fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm); */
150
 
/*   fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage); */
151
 
/*   if(result->file_name != NULL){ */
152
 
/*     fprintf(stderr, "File name: %s\n", result->file_name); */
153
 
/*   } */
154
 
/*   gpgme_recipient_t recipient; */
155
 
/*   recipient = result->recipients; */
156
 
/*   if(recipient){ */
157
 
/*     while(recipient != NULL){ */
158
 
/*       fprintf(stderr, "Public key algorithm: %s\n", */
159
 
/*            gpgme_pubkey_algo_name(recipient->pubkey_algo)); */
160
 
/*       fprintf(stderr, "Key ID: %s\n", recipient->keyid); */
161
 
/*       fprintf(stderr, "Secret key available: %s\n", */
162
 
/*            recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes"); */
163
 
/*       recipient = recipient->next; */
164
 
/*     } */
165
 
/*   } */
166
 
 
167
191
  /* Delete the GPGME FILE pointer cryptotext data buffer */
168
192
  gpgme_data_release(dh_crypto);
169
193
  
170
194
  /* Seek back to the beginning of the GPGME plaintext data buffer */
171
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
195
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
172
196
 
173
197
  *new_packet = 0;
174
198
  while(true){
175
199
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
176
 
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
 
200
      *new_packet = realloc(*new_packet,
 
201
                            (unsigned int)new_packet_capacity
 
202
                            + BUFFER_SIZE);
177
203
      if (*new_packet == NULL){
178
204
        perror("realloc");
179
205
        return -1;
181
207
      new_packet_capacity += BUFFER_SIZE;
182
208
    }
183
209
    
184
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
 
210
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
211
                          BUFFER_SIZE);
185
212
    /* Print the data, if any */
186
213
    if (ret == 0){
187
 
      /* If password is empty, then a incorrect error will be printed */
188
214
      break;
189
215
    }
190
216
    if(ret < 0){
194
220
    new_packet_length += ret;
195
221
  }
196
222
 
197
 
   /* Delete the GPGME plaintext data buffer */
 
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
  /*   } */
 
230
  
 
231
  /* Delete the GPGME plaintext data buffer */
198
232
  gpgme_data_release(dh_plain);
199
233
  return new_packet_length;
200
234
}
206
240
  return ret;
207
241
}
208
242
 
209
 
void debuggnutls(int level, const char* string){
 
243
void debuggnutls(__attribute__((unused)) int level,
 
244
                 const char* string){
210
245
  fprintf(stderr, "%s", string);
211
246
}
212
247
 
214
249
  const char *err;
215
250
  int ret;
216
251
  
 
252
  if(debug){
 
253
    fprintf(stderr, "Initializing GnuTLS\n");
 
254
  }
 
255
  
217
256
  if ((ret = gnutls_global_init ())
218
257
      != GNUTLS_E_SUCCESS) {
219
258
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
220
259
    return -1;
221
260
  }
222
261
 
223
 
  /* Uncomment to enable full debuggin on the gnutls library */
224
 
  /*   gnutls_global_set_log_level(11); */
225
 
  /*   gnutls_global_set_log_function(debuggnutls); */
226
 
 
227
 
 
 
262
  if (debug){
 
263
    gnutls_global_set_log_level(11);
 
264
    gnutls_global_set_log_function(debuggnutls);
 
265
  }
 
266
  
228
267
  /* openpgp credentials */
229
268
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
230
269
      != GNUTLS_E_SUCCESS) {
231
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
270
    fprintf (stderr, "memory error: %s\n",
 
271
             safer_gnutls_strerror(ret));
232
272
    return -1;
233
273
  }
234
 
 
 
274
  
 
275
  if(debug){
 
276
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
277
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
 
278
            KEYFILE);
 
279
  }
 
280
  
235
281
  ret = gnutls_certificate_set_openpgp_key_file
236
282
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
237
283
  if (ret != GNUTLS_E_SUCCESS) {
238
284
    fprintf
239
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
 
285
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
286
       " '%s')\n",
240
287
       ret, CERTFILE, KEYFILE);
241
288
    fprintf(stdout, "The Error is: %s\n",
242
289
            safer_gnutls_strerror(ret));
243
290
    return -1;
244
291
  }
245
 
 
246
 
  //Gnutls server initialization
 
292
  
 
293
  //GnuTLS server initialization
247
294
  if ((ret = gnutls_dh_params_init (&es->dh_params))
248
295
      != GNUTLS_E_SUCCESS) {
249
296
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
250
297
             safer_gnutls_strerror(ret));
251
298
    return -1;
252
299
  }
253
 
 
 
300
  
254
301
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
255
302
      != GNUTLS_E_SUCCESS) {
256
303
    fprintf (stderr, "Error in prime generation: %s\n",
257
304
             safer_gnutls_strerror(ret));
258
305
    return -1;
259
306
  }
260
 
 
 
307
  
261
308
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
262
 
 
263
 
  // Gnutls session creation
 
309
  
 
310
  // GnuTLS session creation
264
311
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
265
312
      != GNUTLS_E_SUCCESS){
266
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
313
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
267
314
            safer_gnutls_strerror(ret));
268
315
  }
269
 
 
 
316
  
270
317
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
271
318
      != GNUTLS_E_SUCCESS) {
272
319
    fprintf(stderr, "Syntax error at: %s\n", err);
273
 
    fprintf(stderr, "Gnutls error: %s\n",
 
320
    fprintf(stderr, "GnuTLS error: %s\n",
274
321
            safer_gnutls_strerror(ret));
275
322
    return -1;
276
323
  }
277
 
 
 
324
  
278
325
  if ((ret = gnutls_credentials_set
279
326
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
280
327
      != GNUTLS_E_SUCCESS) {
282
329
            safer_gnutls_strerror(ret));
283
330
    return -1;
284
331
  }
285
 
 
 
332
  
286
333
  /* ignore client certificate if any. */
287
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
334
  gnutls_certificate_server_set_request (es->session,
 
335
                                         GNUTLS_CERT_IGNORE);
288
336
  
289
337
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
290
338
  
291
339
  return 0;
292
340
}
293
341
 
294
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
342
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
343
               __attribute__((unused)) const char *txt){}
295
344
 
296
 
int start_mandos_communcation(char *ip, uint16_t port){
 
345
int start_mandos_communication(const char *ip, uint16_t port,
 
346
                               AvahiIfIndex if_index){
297
347
  int ret, tcp_sd;
298
348
  struct sockaddr_in6 to;
299
 
  struct in6_addr ip_addr;
300
349
  encrypted_session es;
301
350
  char *buffer = NULL;
302
351
  char *decrypted_buffer;
303
352
  size_t buffer_length = 0;
304
353
  size_t buffer_capacity = 0;
305
354
  ssize_t decrypted_buffer_size;
 
355
  size_t written = 0;
306
356
  int retval = 0;
307
 
 
 
357
  char interface[IF_NAMESIZE];
 
358
  
 
359
  if(debug){
 
360
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
 
361
            ip, port);
 
362
  }
308
363
  
309
364
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
310
365
  if(tcp_sd < 0) {
312
367
    return -1;
313
368
  }
314
369
  
315
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
316
 
  if(tcp_sd < 0) {
317
 
    perror("setsockopt bindtodevice");
 
370
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
371
    if(debug){
 
372
      perror("if_indextoname");
 
373
    }
318
374
    return -1;
319
375
  }
320
376
  
321
 
  memset(&to,0,sizeof(to));
 
377
  if(debug){
 
378
    fprintf(stderr, "Binding to interface %s\n", interface);
 
379
  }
 
380
  
 
381
  memset(&to,0,sizeof(to));     /* Spurious warning */
322
382
  to.sin6_family = AF_INET6;
323
 
  ret = inet_pton(AF_INET6, ip, &ip_addr);
 
383
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
324
384
  if (ret < 0 ){
325
385
    perror("inet_pton");
326
386
    return -1;
329
389
    fprintf(stderr, "Bad address: %s\n", ip);
330
390
    return -1;
331
391
  }
332
 
  to.sin6_port = htons(port);
333
 
  to.sin6_scope_id = if_nametoindex("eth0");
 
392
  to.sin6_port = htons(port);   /* Spurious warning */
 
393
  
 
394
  to.sin6_scope_id = (uint32_t)if_index;
 
395
  
 
396
  if(debug){
 
397
    fprintf(stderr, "Connection to: %s, 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
/*     } */
 
406
  }
334
407
  
335
408
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
336
409
  if (ret < 0){
343
416
    retval = -1;
344
417
    return -1;
345
418
  }
346
 
    
347
 
  
348
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
349
 
 
 
419
  
 
420
  gnutls_transport_set_ptr (es.session,
 
421
                            (gnutls_transport_ptr_t) tcp_sd);
 
422
  
 
423
  if(debug){
 
424
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
425
  }
 
426
  
350
427
  ret = gnutls_handshake (es.session);
351
428
  
352
429
  if (ret != GNUTLS_E_SUCCESS){
353
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
354
 
    gnutls_perror (ret);
 
430
    if(debug){
 
431
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
432
      gnutls_perror (ret);
 
433
    }
355
434
    retval = -1;
356
435
    goto exit;
357
436
  }
 
437
  
 
438
  //Retrieve OpenPGP packet that contains the wanted password
 
439
  
 
440
  if(debug){
 
441
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
442
            ip);
 
443
  }
358
444
 
359
 
  //retrive password
360
445
  while(true){
361
446
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
362
447
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
387
472
        }
388
473
        break;
389
474
      default:
390
 
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
475
        fprintf(stderr, "Unknown error while reading data from"
 
476
                " encrypted session with mandos server\n");
391
477
        retval = -1;
392
478
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
393
479
        goto exit;
394
480
      }
395
481
    } else {
396
 
      buffer_length += ret;
 
482
      buffer_length += (size_t) ret;
397
483
    }
398
484
  }
399
 
 
 
485
  
400
486
  if (buffer_length > 0){
401
 
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
 
487
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
488
                                               buffer_length,
 
489
                                               &decrypted_buffer,
 
490
                                               CERT_ROOT);
 
491
    if (decrypted_buffer_size >= 0){
 
492
      while(written < (size_t) decrypted_buffer_size){
 
493
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
494
                           (size_t)decrypted_buffer_size - written,
 
495
                           stdout);
 
496
        if(ret == 0 and ferror(stdout)){
 
497
          if(debug){
 
498
            fprintf(stderr, "Error writing encrypted data: %s\n",
 
499
                    strerror(errno));
 
500
          }
 
501
          retval = -1;
 
502
          break;
 
503
        }
 
504
        written += (size_t)ret;
 
505
      }
 
506
      free(decrypted_buffer);
 
507
    } else {
402
508
      retval = -1;
403
 
    } else {
404
 
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
405
 
      free(decrypted_buffer);
406
509
    }
407
510
  }
408
511
 
 
512
  //shutdown procedure
 
513
 
 
514
  if(debug){
 
515
    fprintf(stderr, "Closing TLS session\n");
 
516
  }
 
517
 
409
518
  free(buffer);
410
 
 
411
 
  //shutdown procedure
412
519
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
413
520
 exit:
414
521
  close(tcp_sd);
423
530
 
424
531
static void resolve_callback(
425
532
    AvahiSServiceResolver *r,
426
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
533
    AvahiIfIndex interface,
427
534
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
428
535
    AvahiResolverEvent event,
429
536
    const char *name,
432
539
    const char *host_name,
433
540
    const AvahiAddress *address,
434
541
    uint16_t port,
435
 
    AvahiStringList *txt,
436
 
    AvahiLookupResultFlags flags,
 
542
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
543
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
437
544
    AVAHI_GCC_UNUSED void* userdata) {
438
545
    
439
 
    assert(r);
440
 
 
441
 
    /* Called whenever a service has been resolved successfully or timed out */
442
 
 
443
 
    switch (event) {
444
 
        case AVAHI_RESOLVER_FAILURE:
445
 
            fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_server_errno(server)));
446
 
            break;
447
 
 
448
 
        case AVAHI_RESOLVER_FOUND: {
449
 
          char ip[AVAHI_ADDRESS_STR_MAX];
450
 
            avahi_address_snprint(ip, sizeof(ip), address);
451
 
            int ret = start_mandos_communcation(ip, port);
452
 
            if (ret == 0){
453
 
              exit(EXIT_SUCCESS);
454
 
            } else {
455
 
              exit(EXIT_FAILURE);
456
 
            }
457
 
        }
 
546
  assert(r);                    /* Spurious warning */
 
547
  
 
548
  /* Called whenever a service has been resolved successfully or
 
549
     timed out */
 
550
  
 
551
  switch (event) {
 
552
  default:
 
553
  case AVAHI_RESOLVER_FAILURE:
 
554
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
 
555
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
556
            avahi_strerror(avahi_server_errno(server)));
 
557
    break;
 
558
    
 
559
  case AVAHI_RESOLVER_FOUND:
 
560
    {
 
561
      char ip[AVAHI_ADDRESS_STR_MAX];
 
562
      avahi_address_snprint(ip, sizeof(ip), address);
 
563
      if(debug){
 
564
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
 
565
                " port %d\n", name, host_name, ip, port);
 
566
      }
 
567
      int ret = start_mandos_communication(ip, port, interface);
 
568
      if (ret == 0){
 
569
        exit(EXIT_SUCCESS);
 
570
      }
458
571
    }
459
 
    avahi_s_service_resolver_free(r);
 
572
  }
 
573
  avahi_s_service_resolver_free(r);
460
574
}
461
575
 
462
576
static void browse_callback(
471
585
    void* userdata) {
472
586
    
473
587
    AvahiServer *s = userdata;
474
 
    assert(b);
475
 
 
476
 
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
477
 
 
 
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
    
478
593
    switch (event) {
479
 
 
480
 
        case AVAHI_BROWSER_FAILURE:
481
 
            
482
 
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
483
 
            avahi_simple_poll_quit(simple_poll);
484
 
            return;
485
 
 
486
 
        case AVAHI_BROWSER_NEW:
487
 
            /* We ignore the returned resolver object. In the callback
488
 
               function we free it. If the server is terminated before
489
 
               the callback function is called the server will free
490
 
               the resolver for us. */
491
 
            
492
 
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
493
 
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
494
 
            
495
 
            break;
496
 
 
497
 
        case AVAHI_BROWSER_REMOVE:
498
 
            break;
499
 
 
500
 
        case AVAHI_BROWSER_ALL_FOR_NOW:
501
 
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
502
 
            break;
 
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;
503
622
    }
504
623
}
505
624
 
507
626
    AvahiServerConfig config;
508
627
    AvahiSServiceBrowser *sb = NULL;
509
628
    int error;
510
 
    int ret = 1;
511
 
 
512
 
    avahi_set_log_function(empty_log);
 
629
    int ret;
 
630
    int returncode = EXIT_SUCCESS;
 
631
    const char *interface = NULL;
 
632
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
633
    char *connect_to = NULL;
 
634
    
 
635
    while (true){
 
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'},
 
640
        {0, 0, 0, 0} };
 
641
      
 
642
      int option_index = 0;
 
643
      ret = getopt_long (argc, argv, "i:", long_options,
 
644
                         &option_index);
 
645
      
 
646
      if (ret == -1){
 
647
        break;
 
648
      }
 
649
      
 
650
      switch(ret){
 
651
      case 0:
 
652
        break;
 
653
      case 'i':
 
654
        interface = optarg;
 
655
        break;
 
656
      case 'c':
 
657
        connect_to = optarg;
 
658
        break;
 
659
      default:
 
660
        exit(EXIT_FAILURE);
 
661
      }
 
662
    }
 
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
      }
 
670
    }
 
671
    
 
672
    if(connect_to != NULL){
 
673
      /* Connect directly, do not use Zeroconf */
 
674
      /* (Mainly meant for debugging) */
 
675
      char *address = strrchr(connect_to, ':');
 
676
      if(address == NULL){
 
677
        fprintf(stderr, "No colon in address\n");
 
678
        exit(EXIT_FAILURE);
 
679
      }
 
680
      errno = 0;
 
681
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
682
      if(errno){
 
683
        perror("Bad port number");
 
684
        exit(EXIT_FAILURE);
 
685
      }
 
686
      *address = '\0';
 
687
      address = connect_to;
 
688
      ret = start_mandos_communication(address, port, if_index);
 
689
      if(ret < 0){
 
690
        exit(EXIT_FAILURE);
 
691
      } else {
 
692
        exit(EXIT_SUCCESS);
 
693
      }
 
694
    }
 
695
    
 
696
    if (not debug){
 
697
      avahi_set_log_function(empty_log);
 
698
    }
513
699
    
514
700
    /* Initialize the psuedo-RNG */
515
 
    srand(time(NULL));
 
701
    srand((unsigned int) time(NULL));
516
702
 
517
703
    /* Allocate main loop object */
518
704
    if (!(simple_poll = avahi_simple_poll_new())) {
519
705
        fprintf(stderr, "Failed to create simple poll object.\n");
520
 
        goto fail;
 
706
        
 
707
        goto exit;
521
708
    }
522
709
 
523
710
    /* Do not publish any local records */
527
714
    config.publish_workstation = 0;
528
715
    config.publish_domain = 0;
529
716
 
530
 
/*     /\* Set a unicast DNS server for wide area DNS-SD *\/ */
531
 
/*     avahi_address_parse("193.11.177.11", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]); */
532
 
/*     config.n_wide_area_servers = 1; */
533
 
/*     config.enable_wide_area = 1; */
534
 
    
535
717
    /* Allocate a new server */
536
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
718
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
719
                              &config, NULL, NULL, &error);
537
720
 
538
721
    /* Free the configuration data */
539
722
    avahi_server_config_free(&config);
540
723
 
541
 
    /* Check wether creating the server object succeeded */
 
724
    /* Check if creating the server object succeeded */
542
725
    if (!server) {
543
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
544
 
        goto fail;
 
726
        fprintf(stderr, "Failed to create server: %s\n",
 
727
                avahi_strerror(error));
 
728
        returncode = EXIT_FAILURE;
 
729
        goto exit;
545
730
    }
546
731
    
547
732
    /* Create the service browser */
548
 
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
549
 
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
550
 
        goto fail;
 
733
    sb = avahi_s_service_browser_new(server, if_index,
 
734
                                     AVAHI_PROTO_INET6,
 
735
                                     "_mandos._tcp", NULL, 0,
 
736
                                     browse_callback, server);
 
737
    if (!sb) {
 
738
        fprintf(stderr, "Failed to create service browser: %s\n",
 
739
                avahi_strerror(avahi_server_errno(server)));
 
740
        returncode = EXIT_FAILURE;
 
741
        goto exit;
551
742
    }
552
743
    
553
744
    /* Run the main loop */
 
745
 
 
746
    if (debug){
 
747
      fprintf(stderr, "Starting avahi loop search\n");
 
748
    }
 
749
    
554
750
    avahi_simple_poll_loop(simple_poll);
555
751
    
556
 
    ret = 0;
557
 
    
558
 
fail:
 
752
 exit:
 
753
 
 
754
    if (debug){
 
755
      fprintf(stderr, "%s exiting\n", argv[0]);
 
756
    }
559
757
    
560
758
    /* Cleanup things */
561
759
    if (sb)
567
765
    if (simple_poll)
568
766
        avahi_simple_poll_free(simple_poll);
569
767
 
570
 
    return ret;
 
768
    return returncode;
571
769
}