/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/mandosclient.c

  • Committer: Björn Påhlsson
  • Date: 2008-07-21 03:58:36 UTC
  • mfrom: (17 mandos)
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: belorn@braxen-20080721035836-v7220bmolr608r61
Added getopt_long support for mandosclient and passprompt
Added support for --interface for mandosclient
Added support for --prefix for passprompt

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8 -*- */
2
 
/*
3
 
 * Mandos client - get and decrypt data from a Mandos server
4
 
 *
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/>.
30
 
 */
 
1
/***
 
2
  This file is part of avahi.
 
3
 
 
4
  avahi is free software; you can redistribute it and/or modify it
 
5
  under the terms of the GNU Lesser General Public License as
 
6
  published by the Free Software Foundation; either version 2.1 of the
 
7
  License, or (at your option) any later version.
 
8
 
 
9
  avahi is distributed in the hope that it will be useful, but WITHOUT
 
10
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
11
  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
 
12
  Public License for more details.
 
13
 
 
14
  You should have received a copy of the GNU Lesser General Public
 
15
  License along with avahi; if not, write to the Free Software
 
16
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
17
  USA.
 
18
***/
31
19
 
32
 
/* Needed by GPGME, specifically gpgme_data_seek() */
33
20
#define _LARGEFILE_SOURCE
34
21
#define _FILE_OFFSET_BITS 64
35
22
 
47
34
#include <avahi-common/error.h>
48
35
 
49
36
//mandos client part
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 */
 
37
#include <sys/types.h>          /* socket(), setsockopt(), inet_pton() */
 
38
#include <sys/socket.h>         /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */
 
39
#include <gnutls/gnutls.h>      /* ALL GNUTLS STUFF */
 
40
#include <gnutls/openpgp.h>     /* gnutls with openpgp stuff */
55
41
 
56
42
#include <unistd.h>             /* close() */
57
43
#include <netinet/in.h>
76
62
#define DH_BITS 1024
77
63
 
78
64
bool debug = false;
 
65
char *interface = "eth0";
79
66
 
80
67
typedef struct {
81
68
  gnutls_session_t session;
84
71
} encrypted_session;
85
72
 
86
73
 
87
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
 
                            char **new_packet, const char *homedir){
 
74
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
89
75
  gpgme_data_t dh_crypto, dh_plain;
90
76
  gpgme_ctx_t ctx;
91
77
  gpgme_error_t rc;
92
78
  ssize_t ret;
93
 
  ssize_t new_packet_capacity = 0;
94
 
  ssize_t new_packet_length = 0;
 
79
  size_t new_packet_capacity = 0;
 
80
  size_t new_packet_length = 0;
95
81
  gpgme_engine_info_t engine_info;
96
82
 
97
83
  if (debug){
98
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
84
    fprintf(stderr, "Attempting to decrypt password from gpg packet\n");
99
85
  }
100
86
  
101
87
  /* Init GPGME */
146
132
    return -1;
147
133
  }
148
134
  
149
 
  /* Decrypt data from the FILE pointer to the plaintext data
150
 
     buffer */
 
135
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
151
136
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
152
137
  if (rc != GPG_ERR_NO_ERROR){
153
138
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
156
141
  }
157
142
 
158
143
  if(debug){
159
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
 
144
    fprintf(stderr, "decryption of gpg packet succeeded\n");
160
145
  }
161
146
 
162
147
  if (debug){
165
150
    if (result == NULL){
166
151
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
167
152
    } 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);
 
153
      fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
 
154
      fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
172
155
      if(result->file_name != NULL){
173
156
        fprintf(stderr, "File name: %s\n", result->file_name);
174
157
      }
180
163
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
181
164
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
182
165
          fprintf(stderr, "Secret key available: %s\n",
183
 
                  recipient->status == GPG_ERR_NO_SECKEY
184
 
                  ? "No" : "Yes");
 
166
                  recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
185
167
          recipient = recipient->next;
186
168
        }
187
169
      }
192
174
  gpgme_data_release(dh_crypto);
193
175
  
194
176
  /* Seek back to the beginning of the GPGME plaintext data buffer */
195
 
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
 
177
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
196
178
 
197
179
  *new_packet = 0;
198
180
  while(true){
199
181
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
200
 
      *new_packet = realloc(*new_packet,
201
 
                            (unsigned int)new_packet_capacity
202
 
                            + BUFFER_SIZE);
 
182
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
203
183
      if (*new_packet == NULL){
204
184
        perror("realloc");
205
185
        return -1;
207
187
      new_packet_capacity += BUFFER_SIZE;
208
188
    }
209
189
    
210
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
211
 
                          BUFFER_SIZE);
 
190
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
212
191
    /* Print the data, if any */
213
192
    if (ret == 0){
 
193
      /* If password is empty, then a incorrect error will be printed */
214
194
      break;
215
195
    }
216
196
    if(ret < 0){
240
220
  return ret;
241
221
}
242
222
 
243
 
void debuggnutls(__attribute__((unused)) int level,
244
 
                 const char* string){
 
223
void debuggnutls(int level, const char* string){
245
224
  fprintf(stderr, "%s", string);
246
225
}
247
226
 
248
227
int initgnutls(encrypted_session *es){
249
228
  const char *err;
250
229
  int ret;
251
 
  
 
230
 
252
231
  if(debug){
253
 
    fprintf(stderr, "Initializing GnuTLS\n");
 
232
    fprintf(stderr, "Initializing gnutls\n");
254
233
  }
 
234
 
255
235
  
256
236
  if ((ret = gnutls_global_init ())
257
237
      != GNUTLS_E_SUCCESS) {
264
244
    gnutls_global_set_log_function(debuggnutls);
265
245
  }
266
246
  
 
247
 
267
248
  /* openpgp credentials */
268
249
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
269
250
      != GNUTLS_E_SUCCESS) {
270
 
    fprintf (stderr, "memory error: %s\n",
271
 
             safer_gnutls_strerror(ret));
 
251
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
272
252
    return -1;
273
253
  }
274
 
  
 
254
 
275
255
  if(debug){
276
 
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
277
 
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
278
 
            KEYFILE);
 
256
    fprintf(stderr, "Attempting to use openpgp certificate %s"
 
257
            " and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
279
258
  }
280
 
  
 
259
 
281
260
  ret = gnutls_certificate_set_openpgp_key_file
282
261
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
283
262
  if (ret != GNUTLS_E_SUCCESS) {
284
263
    fprintf
285
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
286
 
       " '%s')\n",
 
264
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
287
265
       ret, CERTFILE, KEYFILE);
288
266
    fprintf(stdout, "The Error is: %s\n",
289
267
            safer_gnutls_strerror(ret));
290
268
    return -1;
291
269
  }
292
 
  
293
 
  //GnuTLS server initialization
 
270
 
 
271
  //Gnutls server initialization
294
272
  if ((ret = gnutls_dh_params_init (&es->dh_params))
295
273
      != GNUTLS_E_SUCCESS) {
296
274
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
297
275
             safer_gnutls_strerror(ret));
298
276
    return -1;
299
277
  }
300
 
  
 
278
 
301
279
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
302
280
      != GNUTLS_E_SUCCESS) {
303
281
    fprintf (stderr, "Error in prime generation: %s\n",
304
282
             safer_gnutls_strerror(ret));
305
283
    return -1;
306
284
  }
307
 
  
 
285
 
308
286
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
309
 
  
310
 
  // GnuTLS session creation
 
287
 
 
288
  // Gnutls session creation
311
289
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
312
290
      != GNUTLS_E_SUCCESS){
313
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
 
291
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
314
292
            safer_gnutls_strerror(ret));
315
293
  }
316
 
  
 
294
 
317
295
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
318
296
      != GNUTLS_E_SUCCESS) {
319
297
    fprintf(stderr, "Syntax error at: %s\n", err);
320
 
    fprintf(stderr, "GnuTLS error: %s\n",
 
298
    fprintf(stderr, "Gnutls error: %s\n",
321
299
            safer_gnutls_strerror(ret));
322
300
    return -1;
323
301
  }
324
 
  
 
302
 
325
303
  if ((ret = gnutls_credentials_set
326
304
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
327
305
      != GNUTLS_E_SUCCESS) {
329
307
            safer_gnutls_strerror(ret));
330
308
    return -1;
331
309
  }
332
 
  
 
310
 
333
311
  /* ignore client certificate if any. */
334
 
  gnutls_certificate_server_set_request (es->session,
335
 
                                         GNUTLS_CERT_IGNORE);
 
312
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
336
313
  
337
314
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
338
315
  
339
316
  return 0;
340
317
}
341
318
 
342
 
void empty_log(__attribute__((unused)) AvahiLogLevel level,
343
 
               __attribute__((unused)) const char *txt){}
 
319
void empty_log(AvahiLogLevel level, const char *txt){}
344
320
 
345
 
int start_mandos_communication(const char *ip, uint16_t port,
346
 
                               unsigned int if_index){
 
321
int start_mandos_communcation(char *ip, uint16_t port){
347
322
  int ret, tcp_sd;
348
323
  struct sockaddr_in6 to;
 
324
  struct in6_addr ip_addr;
349
325
  encrypted_session es;
350
326
  char *buffer = NULL;
351
327
  char *decrypted_buffer;
352
328
  size_t buffer_length = 0;
353
329
  size_t buffer_capacity = 0;
354
330
  ssize_t decrypted_buffer_size;
355
 
  size_t written = 0;
356
331
  int retval = 0;
357
 
  char interface[IF_NAMESIZE];
358
 
  
 
332
 
359
333
  if(debug){
360
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
361
 
            ip, port);
 
334
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
362
335
  }
363
336
  
364
337
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
366
339
    perror("socket");
367
340
    return -1;
368
341
  }
369
 
  
370
 
  if(if_indextoname(if_index, interface) == NULL){
371
 
    if(debug){
372
 
      perror("if_indextoname");
373
 
    }
374
 
    return -1;
375
 
  }
376
 
  
 
342
 
377
343
  if(debug){
378
344
    fprintf(stderr, "Binding to interface %s\n", interface);
379
345
  }
 
346
 
 
347
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
 
348
  if(tcp_sd < 0) {
 
349
    perror("setsockopt bindtodevice");
 
350
    return -1;
 
351
  }
380
352
  
381
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
 
353
  memset(&to,0,sizeof(to));
382
354
  to.sin6_family = AF_INET6;
383
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
355
  ret = inet_pton(AF_INET6, ip, &ip_addr);
384
356
  if (ret < 0 ){
385
357
    perror("inet_pton");
386
358
    return -1;
389
361
    fprintf(stderr, "Bad address: %s\n", ip);
390
362
    return -1;
391
363
  }
392
 
  to.sin6_port = htons(port);   /* Spurious warning */
393
 
  
394
 
  to.sin6_scope_id = (uint32_t)if_index;
395
 
  
 
364
  to.sin6_port = htons(port);
 
365
  to.sin6_scope_id = if_nametoindex(interface);
 
366
 
396
367
  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
 
/*     } */
 
368
    fprintf(stderr, "Connection to: %s\n", ip);
406
369
  }
407
370
  
408
371
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
416
379
    retval = -1;
417
380
    return -1;
418
381
  }
419
 
  
420
 
  gnutls_transport_set_ptr (es.session,
421
 
                            (gnutls_transport_ptr_t) tcp_sd);
422
 
  
 
382
    
 
383
  
 
384
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
 
385
 
423
386
  if(debug){
424
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
387
    fprintf(stderr, "Establishing tls session with %s\n", ip);
425
388
  }
 
389
 
426
390
  
427
391
  ret = gnutls_handshake (es.session);
428
392
  
429
393
  if (ret != GNUTLS_E_SUCCESS){
430
 
    if(debug){
431
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
432
 
      gnutls_perror (ret);
433
 
    }
 
394
    fprintf(stderr, "\n*** Handshake failed ***\n");
 
395
    gnutls_perror (ret);
434
396
    retval = -1;
435
397
    goto exit;
436
398
  }
437
 
  
438
 
  //Retrieve OpenPGP packet that contains the wanted password
439
 
  
 
399
 
 
400
  //Retrieve gpg packet that contains the wanted password
 
401
 
440
402
  if(debug){
441
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
442
 
            ip);
 
403
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
443
404
  }
444
405
 
445
406
  while(true){
472
433
        }
473
434
        break;
474
435
      default:
475
 
        fprintf(stderr, "Unknown error while reading data from"
476
 
                " encrypted session with mandos server\n");
 
436
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
477
437
        retval = -1;
478
438
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
479
439
        goto exit;
480
440
      }
481
441
    } else {
482
 
      buffer_length += (size_t) ret;
 
442
      buffer_length += ret;
483
443
    }
484
444
  }
485
445
  
486
446
  if (buffer_length > 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
 
      }
 
447
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
 
448
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
506
449
      free(decrypted_buffer);
507
450
    } else {
508
451
      retval = -1;
512
455
  //shutdown procedure
513
456
 
514
457
  if(debug){
515
 
    fprintf(stderr, "Closing TLS session\n");
 
458
    fprintf(stderr, "Closing tls session\n");
516
459
  }
517
460
 
518
461
  free(buffer);
530
473
 
531
474
static void resolve_callback(
532
475
    AvahiSServiceResolver *r,
533
 
    AvahiIfIndex interface,
 
476
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
534
477
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
535
478
    AvahiResolverEvent event,
536
479
    const char *name,
539
482
    const char *host_name,
540
483
    const AvahiAddress *address,
541
484
    uint16_t port,
542
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
543
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
485
    AvahiStringList *txt,
 
486
    AvahiLookupResultFlags flags,
544
487
    AVAHI_GCC_UNUSED void* userdata) {
545
488
    
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,
568
 
                                           (unsigned int) interface);
569
 
      if (ret == 0){
570
 
        exit(EXIT_SUCCESS);
571
 
      }
 
489
    assert(r);
 
490
 
 
491
    /* Called whenever a service has been resolved successfully or timed out */
 
492
 
 
493
    switch (event) {
 
494
        case AVAHI_RESOLVER_FAILURE:
 
495
            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)));
 
496
            break;
 
497
 
 
498
        case AVAHI_RESOLVER_FOUND: {
 
499
          char ip[AVAHI_ADDRESS_STR_MAX];
 
500
            avahi_address_snprint(ip, sizeof(ip), address);
 
501
            if(debug){
 
502
              fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
 
503
            }
 
504
            int ret = start_mandos_communcation(ip, port);
 
505
            if (ret == 0){
 
506
              exit(EXIT_SUCCESS);
 
507
            } else {
 
508
              exit(EXIT_FAILURE);
 
509
            }
 
510
        }
572
511
    }
573
 
  }
574
 
  avahi_s_service_resolver_free(r);
 
512
    avahi_s_service_resolver_free(r);
575
513
}
576
514
 
577
515
static void browse_callback(
586
524
    void* userdata) {
587
525
    
588
526
    AvahiServer *s = userdata;
589
 
    assert(b);                  /* Spurious warning */
590
 
    
591
 
    /* Called whenever a new services becomes available on the LAN or
592
 
       is removed from the LAN */
593
 
    
 
527
    assert(b);
 
528
 
 
529
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
 
530
 
594
531
    switch (event) {
595
 
    default:
596
 
    case AVAHI_BROWSER_FAILURE:
597
 
      
598
 
      fprintf(stderr, "(Browser) %s\n",
599
 
              avahi_strerror(avahi_server_errno(server)));
600
 
      avahi_simple_poll_quit(simple_poll);
601
 
      return;
602
 
      
603
 
    case AVAHI_BROWSER_NEW:
604
 
      /* We ignore the returned resolver object. In the callback
605
 
         function we free it. If the server is terminated before
606
 
         the callback function is called the server will free
607
 
         the resolver for us. */
608
 
      
609
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
610
 
                                         type, domain,
611
 
                                         AVAHI_PROTO_INET6, 0,
612
 
                                         resolve_callback, s)))
613
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
614
 
                avahi_strerror(avahi_server_errno(s)));
615
 
      break;
616
 
      
617
 
    case AVAHI_BROWSER_REMOVE:
618
 
      break;
619
 
      
620
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
621
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
622
 
      break;
 
532
 
 
533
        case AVAHI_BROWSER_FAILURE:
 
534
            
 
535
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
 
536
            avahi_simple_poll_quit(simple_poll);
 
537
            return;
 
538
 
 
539
        case AVAHI_BROWSER_NEW:
 
540
            /* We ignore the returned resolver object. In the callback
 
541
               function we free it. If the server is terminated before
 
542
               the callback function is called the server will free
 
543
               the resolver for us. */
 
544
            
 
545
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
 
546
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
 
547
            
 
548
            break;
 
549
 
 
550
        case AVAHI_BROWSER_REMOVE:
 
551
            break;
 
552
 
 
553
        case AVAHI_BROWSER_ALL_FOR_NOW:
 
554
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
555
            break;
623
556
    }
624
557
}
625
558
 
629
562
    int error;
630
563
    int ret;
631
564
    int returncode = EXIT_SUCCESS;
632
 
    const char *interface = "eth0";
633
 
    unsigned int if_index;
634
 
    char *connect_to = NULL;
635
 
    
 
565
 
636
566
    while (true){
637
567
      static struct option long_options[] = {
638
568
        {"debug", no_argument, (int *)&debug, 1},
639
 
        {"connect", required_argument, 0, 'c'},
640
569
        {"interface", required_argument, 0, 'i'},
641
570
        {0, 0, 0, 0} };
642
 
      
 
571
 
643
572
      int option_index = 0;
644
 
      ret = getopt_long (argc, argv, "i:", long_options,
645
 
                         &option_index);
646
 
      
 
573
      ret = getopt_long (argc, argv, "i:", long_options, &option_index);
 
574
 
647
575
      if (ret == -1){
648
576
        break;
649
577
      }
654
582
      case 'i':
655
583
        interface = optarg;
656
584
        break;
657
 
      case 'c':
658
 
        connect_to = optarg;
659
 
        break;
660
585
      default:
661
586
        exit(EXIT_FAILURE);
662
587
      }
663
588
    }
664
589
    
665
 
    if_index = if_nametoindex(interface);
666
 
    if(if_index == 0){
667
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
668
 
      exit(EXIT_FAILURE);
669
 
    }
670
 
    
671
 
    if(connect_to != NULL){
672
 
      /* Connect directly, do not use Zeroconf */
673
 
      /* (Mainly meant for debugging) */
674
 
      char *address = strrchr(connect_to, ':');
675
 
      if(address == NULL){
676
 
        fprintf(stderr, "No colon in address\n");
677
 
        exit(EXIT_FAILURE);
678
 
      }
679
 
      errno = 0;
680
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
681
 
      if(errno){
682
 
        perror("Bad port number");
683
 
        exit(EXIT_FAILURE);
684
 
      }
685
 
      *address = '\0';
686
 
      address = connect_to;
687
 
      ret = start_mandos_communication(address, port, if_index);
688
 
      if(ret < 0){
689
 
        exit(EXIT_FAILURE);
690
 
      } else {
691
 
        exit(EXIT_SUCCESS);
692
 
      }
693
 
    }
694
 
    
695
590
    if (not debug){
696
591
      avahi_set_log_function(empty_log);
697
592
    }
698
593
    
699
594
    /* Initialize the psuedo-RNG */
700
 
    srand((unsigned int) time(NULL));
 
595
    srand(time(NULL));
701
596
 
702
597
    /* Allocate main loop object */
703
598
    if (!(simple_poll = avahi_simple_poll_new())) {
714
609
    config.publish_domain = 0;
715
610
 
716
611
    /* Allocate a new server */
717
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
718
 
                              &config, NULL, NULL, &error);
 
612
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
719
613
 
720
614
    /* Free the configuration data */
721
615
    avahi_server_config_free(&config);
722
616
 
723
617
    /* Check if creating the server object succeeded */
724
618
    if (!server) {
725
 
        fprintf(stderr, "Failed to create server: %s\n",
726
 
                avahi_strerror(error));
 
619
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
727
620
        returncode = EXIT_FAILURE;
728
621
        goto exit;
729
622
    }
730
623
    
731
624
    /* Create the service browser */
732
 
    sb = avahi_s_service_browser_new(server, (AvahiIfIndex)if_index,
733
 
                                     AVAHI_PROTO_INET6,
734
 
                                     "_mandos._tcp", NULL, 0,
735
 
                                     browse_callback, server);
736
 
    if (!sb) {
737
 
        fprintf(stderr, "Failed to create service browser: %s\n",
738
 
                avahi_strerror(avahi_server_errno(server)));
 
625
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
 
626
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
739
627
        returncode = EXIT_FAILURE;
740
628
        goto exit;
741
629
    }
748
636
    
749
637
    avahi_simple_poll_loop(simple_poll);
750
638
    
751
 
 exit:
 
639
exit:
752
640
 
753
641
    if (debug){
754
642
      fprintf(stderr, "%s exiting\n", argv[0]);