/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

plugbasedclient
        Parse a single argument as a plus-separated list of options

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
***/
 
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 <mandos@fukt.bsnet.se>.
 
29
 */
19
30
 
 
31
/* Needed by GPGME, specifically gpgme_data_seek() */
20
32
#define _LARGEFILE_SOURCE
21
33
#define _FILE_OFFSET_BITS 64
22
34
 
25
37
#include <stdlib.h>
26
38
#include <time.h>
27
39
#include <net/if.h>             /* if_nametoindex */
 
40
#include <sys/ioctl.h>          // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
 
41
#include <net/if.h>             // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
28
42
 
29
43
#include <avahi-core/core.h>
30
44
#include <avahi-core/lookup.h>
34
48
#include <avahi-common/error.h>
35
49
 
36
50
//mandos client part
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 */
 
51
#include <sys/types.h>          /* socket(), inet_pton() */
 
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
53
                                   struct in6_addr, inet_pton() */
 
54
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
 
55
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
41
56
 
42
57
#include <unistd.h>             /* close() */
43
58
#include <netinet/in.h>
53
68
// getopt long
54
69
#include <getopt.h>
55
70
 
56
 
#ifndef CERT_ROOT
57
 
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
58
 
#endif
59
 
#define CERTFILE CERT_ROOT "openpgp-client.txt"
60
 
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
61
71
#define BUFFER_SIZE 256
62
72
#define DH_BITS 1024
63
73
 
 
74
static const char *certdir = "/conf/conf.d/mandos";
 
75
static const char *certfile = "openpgp-client.txt";
 
76
static const char *certkey = "openpgp-client-key.txt";
 
77
 
64
78
bool debug = false;
65
 
char *interface = "eth0";
66
79
 
67
80
typedef struct {
68
81
  gnutls_session_t session;
71
84
} encrypted_session;
72
85
 
73
86
 
74
 
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
 
87
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
88
                                   char **new_packet,
 
89
                                   const char *homedir){
75
90
  gpgme_data_t dh_crypto, dh_plain;
76
91
  gpgme_ctx_t ctx;
77
92
  gpgme_error_t rc;
78
93
  ssize_t ret;
79
 
  size_t new_packet_capacity = 0;
80
 
  size_t new_packet_length = 0;
 
94
  ssize_t new_packet_capacity = 0;
 
95
  ssize_t new_packet_length = 0;
81
96
  gpgme_engine_info_t engine_info;
82
97
 
83
98
  if (debug){
84
 
    fprintf(stderr, "Attempting to decrypt password from gpg packet\n");
 
99
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
85
100
  }
86
101
  
87
102
  /* Init GPGME */
88
103
  gpgme_check_version(NULL);
89
 
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
104
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
105
  if (rc != GPG_ERR_NO_ERROR){
 
106
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
 
107
            gpgme_strsource(rc), gpgme_strerror(rc));
 
108
    return -1;
 
109
  }
90
110
  
91
111
  /* Set GPGME home directory */
92
112
  rc = gpgme_get_engine_info (&engine_info);
132
152
    return -1;
133
153
  }
134
154
  
135
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
155
  /* Decrypt data from the FILE pointer to the plaintext data
 
156
     buffer */
136
157
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
137
158
  if (rc != GPG_ERR_NO_ERROR){
138
159
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
141
162
  }
142
163
 
143
164
  if(debug){
144
 
    fprintf(stderr, "decryption of gpg packet succeeded\n");
 
165
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
145
166
  }
146
167
 
147
168
  if (debug){
150
171
    if (result == NULL){
151
172
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
152
173
    } else {
153
 
      fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
154
 
      fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
 
174
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
175
              result->unsupported_algorithm);
 
176
      fprintf(stderr, "Wrong key usage: %d\n",
 
177
              result->wrong_key_usage);
155
178
      if(result->file_name != NULL){
156
179
        fprintf(stderr, "File name: %s\n", result->file_name);
157
180
      }
163
186
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
164
187
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
165
188
          fprintf(stderr, "Secret key available: %s\n",
166
 
                  recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
 
189
                  recipient->status == GPG_ERR_NO_SECKEY
 
190
                  ? "No" : "Yes");
167
191
          recipient = recipient->next;
168
192
        }
169
193
      }
174
198
  gpgme_data_release(dh_crypto);
175
199
  
176
200
  /* Seek back to the beginning of the GPGME plaintext data buffer */
177
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
178
 
 
 
201
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
 
202
    perror("pgpme_data_seek");
 
203
  }
 
204
  
179
205
  *new_packet = 0;
180
206
  while(true){
181
207
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
182
 
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
 
208
      *new_packet = realloc(*new_packet,
 
209
                            (unsigned int)new_packet_capacity
 
210
                            + BUFFER_SIZE);
183
211
      if (*new_packet == NULL){
184
212
        perror("realloc");
185
213
        return -1;
187
215
      new_packet_capacity += BUFFER_SIZE;
188
216
    }
189
217
    
190
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
 
218
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
219
                          BUFFER_SIZE);
191
220
    /* Print the data, if any */
192
221
    if (ret == 0){
193
 
      /* If password is empty, then a incorrect error will be printed */
194
222
      break;
195
223
    }
196
224
    if(ret < 0){
220
248
  return ret;
221
249
}
222
250
 
223
 
void debuggnutls(int level, const char* string){
 
251
static void debuggnutls(__attribute__((unused)) int level,
 
252
                        const char* string){
224
253
  fprintf(stderr, "%s", string);
225
254
}
226
255
 
227
 
int initgnutls(encrypted_session *es){
 
256
static int initgnutls(encrypted_session *es){
228
257
  const char *err;
229
258
  int ret;
230
 
 
 
259
  
231
260
  if(debug){
232
 
    fprintf(stderr, "Initializing gnutls\n");
 
261
    fprintf(stderr, "Initializing GnuTLS\n");
233
262
  }
234
263
 
235
 
  
236
264
  if ((ret = gnutls_global_init ())
237
265
      != GNUTLS_E_SUCCESS) {
238
266
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
244
272
    gnutls_global_set_log_function(debuggnutls);
245
273
  }
246
274
  
247
 
 
248
275
  /* openpgp credentials */
249
276
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
250
277
      != GNUTLS_E_SUCCESS) {
251
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
278
    fprintf (stderr, "memory error: %s\n",
 
279
             safer_gnutls_strerror(ret));
252
280
    return -1;
253
281
  }
254
 
 
 
282
  
255
283
  if(debug){
256
 
    fprintf(stderr, "Attempting to use openpgp certificate %s"
257
 
            " and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
 
284
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
285
            " and keyfile %s as GnuTLS credentials\n", certfile,
 
286
            certkey);
258
287
  }
259
 
 
 
288
  
260
289
  ret = gnutls_certificate_set_openpgp_key_file
261
 
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
 
290
    (es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
262
291
  if (ret != GNUTLS_E_SUCCESS) {
263
292
    fprintf
264
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
265
 
       ret, CERTFILE, KEYFILE);
 
293
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
294
       " '%s')\n",
 
295
       ret, certfile, certkey);
266
296
    fprintf(stdout, "The Error is: %s\n",
267
297
            safer_gnutls_strerror(ret));
268
298
    return -1;
269
299
  }
270
 
 
271
 
  //Gnutls server initialization
 
300
  
 
301
  //GnuTLS server initialization
272
302
  if ((ret = gnutls_dh_params_init (&es->dh_params))
273
303
      != GNUTLS_E_SUCCESS) {
274
304
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
275
305
             safer_gnutls_strerror(ret));
276
306
    return -1;
277
307
  }
278
 
 
 
308
  
279
309
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
280
310
      != GNUTLS_E_SUCCESS) {
281
311
    fprintf (stderr, "Error in prime generation: %s\n",
282
312
             safer_gnutls_strerror(ret));
283
313
    return -1;
284
314
  }
285
 
 
 
315
  
286
316
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
287
 
 
288
 
  // Gnutls session creation
 
317
  
 
318
  // GnuTLS session creation
289
319
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
290
320
      != GNUTLS_E_SUCCESS){
291
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
321
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
292
322
            safer_gnutls_strerror(ret));
293
323
  }
294
 
 
 
324
  
295
325
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
296
326
      != GNUTLS_E_SUCCESS) {
297
327
    fprintf(stderr, "Syntax error at: %s\n", err);
298
 
    fprintf(stderr, "Gnutls error: %s\n",
 
328
    fprintf(stderr, "GnuTLS error: %s\n",
299
329
            safer_gnutls_strerror(ret));
300
330
    return -1;
301
331
  }
302
 
 
 
332
  
303
333
  if ((ret = gnutls_credentials_set
304
334
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
305
335
      != GNUTLS_E_SUCCESS) {
307
337
            safer_gnutls_strerror(ret));
308
338
    return -1;
309
339
  }
310
 
 
 
340
  
311
341
  /* ignore client certificate if any. */
312
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
342
  gnutls_certificate_server_set_request (es->session,
 
343
                                         GNUTLS_CERT_IGNORE);
313
344
  
314
345
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
315
346
  
316
347
  return 0;
317
348
}
318
349
 
319
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
350
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
351
                      __attribute__((unused)) const char *txt){}
320
352
 
321
 
int start_mandos_communication(char *ip, uint16_t port){
 
353
static int start_mandos_communication(const char *ip, uint16_t port,
 
354
                                      AvahiIfIndex if_index){
322
355
  int ret, tcp_sd;
323
356
  struct sockaddr_in6 to;
324
357
  encrypted_session es;
327
360
  size_t buffer_length = 0;
328
361
  size_t buffer_capacity = 0;
329
362
  ssize_t decrypted_buffer_size;
 
363
  size_t written = 0;
330
364
  int retval = 0;
331
 
 
 
365
  char interface[IF_NAMESIZE];
 
366
  
332
367
  if(debug){
333
 
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
 
368
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
 
369
            ip, port);
334
370
  }
335
371
  
336
372
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
340
376
  }
341
377
 
342
378
  if(debug){
 
379
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
380
      if(debug){
 
381
        perror("if_indextoname");
 
382
      }
 
383
      return -1;
 
384
    }
 
385
    
343
386
    fprintf(stderr, "Binding to interface %s\n", interface);
344
387
  }
345
 
 
346
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
347
 
  if(tcp_sd < 0) {
348
 
    perror("setsockopt bindtodevice");
349
 
    return -1;
350
 
  }
351
388
  
352
 
  memset(&to,0,sizeof(to));
 
389
  memset(&to,0,sizeof(to));     /* Spurious warning */
353
390
  to.sin6_family = AF_INET6;
354
391
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
355
392
  if (ret < 0 ){
360
397
    fprintf(stderr, "Bad address: %s\n", ip);
361
398
    return -1;
362
399
  }
363
 
  to.sin6_port = htons(port);
364
 
  to.sin6_scope_id = if_nametoindex(interface);
365
 
 
 
400
  to.sin6_port = htons(port);   /* Spurious warning */
 
401
  
 
402
  to.sin6_scope_id = (uint32_t)if_index;
 
403
  
366
404
  if(debug){
367
 
    fprintf(stderr, "Connection to: %s\n", ip);
 
405
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
 
406
/*     char addrstr[INET6_ADDRSTRLEN]; */
 
407
/*     if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
 
408
/*               sizeof(addrstr)) == NULL){ */
 
409
/*       perror("inet_ntop"); */
 
410
/*     } else { */
 
411
/*       fprintf(stderr, "Really connecting to: %s, port %d\n", */
 
412
/*            addrstr, ntohs(to.sin6_port)); */
 
413
/*     } */
368
414
  }
369
415
  
370
416
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
378
424
    retval = -1;
379
425
    return -1;
380
426
  }
381
 
    
382
 
  
383
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
384
 
 
 
427
  
 
428
  gnutls_transport_set_ptr (es.session,
 
429
                            (gnutls_transport_ptr_t) tcp_sd);
 
430
  
385
431
  if(debug){
386
 
    fprintf(stderr, "Establishing tls session with %s\n", ip);
 
432
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
387
433
  }
388
 
 
389
434
  
390
435
  ret = gnutls_handshake (es.session);
391
436
  
392
437
  if (ret != GNUTLS_E_SUCCESS){
393
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
394
 
    gnutls_perror (ret);
 
438
    if(debug){
 
439
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
440
      gnutls_perror (ret);
 
441
    }
395
442
    retval = -1;
396
443
    goto exit;
397
444
  }
398
 
 
399
 
  //Retrieve gpg packet that contains the wanted password
400
 
 
 
445
  
 
446
  //Retrieve OpenPGP packet that contains the wanted password
 
447
  
401
448
  if(debug){
402
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
 
449
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
450
            ip);
403
451
  }
404
452
 
405
453
  while(true){
432
480
        }
433
481
        break;
434
482
      default:
435
 
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
483
        fprintf(stderr, "Unknown error while reading data from"
 
484
                " encrypted session with mandos server\n");
436
485
        retval = -1;
437
486
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
438
487
        goto exit;
439
488
      }
440
489
    } else {
441
 
      buffer_length += ret;
 
490
      buffer_length += (size_t) ret;
442
491
    }
443
492
  }
444
493
  
445
494
  if (buffer_length > 0){
446
 
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
447
 
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
 
495
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
496
                                               buffer_length,
 
497
                                               &decrypted_buffer,
 
498
                                               certdir);
 
499
    if (decrypted_buffer_size >= 0){
 
500
      while(written < (size_t) decrypted_buffer_size){
 
501
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
502
                           (size_t)decrypted_buffer_size - written,
 
503
                           stdout);
 
504
        if(ret == 0 and ferror(stdout)){
 
505
          if(debug){
 
506
            fprintf(stderr, "Error writing encrypted data: %s\n",
 
507
                    strerror(errno));
 
508
          }
 
509
          retval = -1;
 
510
          break;
 
511
        }
 
512
        written += (size_t)ret;
 
513
      }
448
514
      free(decrypted_buffer);
449
515
    } else {
450
516
      retval = -1;
454
520
  //shutdown procedure
455
521
 
456
522
  if(debug){
457
 
    fprintf(stderr, "Closing tls session\n");
 
523
    fprintf(stderr, "Closing TLS session\n");
458
524
  }
459
525
 
460
526
  free(buffer);
472
538
 
473
539
static void resolve_callback(
474
540
    AvahiSServiceResolver *r,
475
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
541
    AvahiIfIndex interface,
476
542
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
477
543
    AvahiResolverEvent event,
478
544
    const char *name,
481
547
    const char *host_name,
482
548
    const AvahiAddress *address,
483
549
    uint16_t port,
484
 
    AvahiStringList *txt,
485
 
    AvahiLookupResultFlags flags,
 
550
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
551
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
486
552
    AVAHI_GCC_UNUSED void* userdata) {
487
553
    
488
 
    assert(r);
489
 
 
490
 
    /* Called whenever a service has been resolved successfully or timed out */
491
 
 
492
 
    switch (event) {
493
 
        case AVAHI_RESOLVER_FAILURE:
494
 
            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)));
495
 
            break;
496
 
 
497
 
        case AVAHI_RESOLVER_FOUND: {
498
 
          char ip[AVAHI_ADDRESS_STR_MAX];
499
 
            avahi_address_snprint(ip, sizeof(ip), address);
500
 
            if(debug){
501
 
              fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
502
 
            }
503
 
            int ret = start_mandos_communication(ip, port);
504
 
            if (ret == 0){
505
 
              exit(EXIT_SUCCESS);
506
 
            } else {
507
 
              exit(EXIT_FAILURE);
508
 
            }
509
 
        }
 
554
  assert(r);                    /* Spurious warning */
 
555
  
 
556
  /* Called whenever a service has been resolved successfully or
 
557
     timed out */
 
558
  
 
559
  switch (event) {
 
560
  default:
 
561
  case AVAHI_RESOLVER_FAILURE:
 
562
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
 
563
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
564
            avahi_strerror(avahi_server_errno(server)));
 
565
    break;
 
566
    
 
567
  case AVAHI_RESOLVER_FOUND:
 
568
    {
 
569
      char ip[AVAHI_ADDRESS_STR_MAX];
 
570
      avahi_address_snprint(ip, sizeof(ip), address);
 
571
      if(debug){
 
572
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
 
573
                " port %d\n", name, host_name, ip, port);
 
574
      }
 
575
      int ret = start_mandos_communication(ip, port, interface);
 
576
      if (ret == 0){
 
577
        exit(EXIT_SUCCESS);
 
578
      }
510
579
    }
511
 
    avahi_s_service_resolver_free(r);
 
580
  }
 
581
  avahi_s_service_resolver_free(r);
512
582
}
513
583
 
514
584
static void browse_callback(
523
593
    void* userdata) {
524
594
    
525
595
    AvahiServer *s = userdata;
526
 
    assert(b);
527
 
 
528
 
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
529
 
 
 
596
    assert(b);                  /* Spurious warning */
 
597
    
 
598
    /* Called whenever a new services becomes available on the LAN or
 
599
       is removed from the LAN */
 
600
    
530
601
    switch (event) {
531
 
 
532
 
        case AVAHI_BROWSER_FAILURE:
533
 
            
534
 
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
535
 
            avahi_simple_poll_quit(simple_poll);
536
 
            return;
537
 
 
538
 
        case AVAHI_BROWSER_NEW:
539
 
            /* We ignore the returned resolver object. In the callback
540
 
               function we free it. If the server is terminated before
541
 
               the callback function is called the server will free
542
 
               the resolver for us. */
543
 
            
544
 
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
545
 
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
546
 
            
547
 
            break;
548
 
 
549
 
        case AVAHI_BROWSER_REMOVE:
550
 
            break;
551
 
 
552
 
        case AVAHI_BROWSER_ALL_FOR_NOW:
553
 
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
554
 
            break;
 
602
    default:
 
603
    case AVAHI_BROWSER_FAILURE:
 
604
      
 
605
      fprintf(stderr, "(Browser) %s\n",
 
606
              avahi_strerror(avahi_server_errno(server)));
 
607
      avahi_simple_poll_quit(simple_poll);
 
608
      return;
 
609
      
 
610
    case AVAHI_BROWSER_NEW:
 
611
      /* We ignore the returned resolver object. In the callback
 
612
         function we free it. If the server is terminated before
 
613
         the callback function is called the server will free
 
614
         the resolver for us. */
 
615
      
 
616
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
 
617
                                         type, domain,
 
618
                                         AVAHI_PROTO_INET6, 0,
 
619
                                         resolve_callback, s)))
 
620
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
 
621
                avahi_strerror(avahi_server_errno(s)));
 
622
      break;
 
623
      
 
624
    case AVAHI_BROWSER_REMOVE:
 
625
      break;
 
626
      
 
627
    case AVAHI_BROWSER_ALL_FOR_NOW:
 
628
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
629
      break;
555
630
    }
556
631
}
557
632
 
 
633
/* Combines file name and path and returns the malloced new
 
634
   string. some sane checks could/should be added */
 
635
static const char *combinepath(const char *first, const char *second){
 
636
  size_t f_len = strlen(first);
 
637
  size_t s_len = strlen(second);
 
638
  char *tmp = malloc(f_len + s_len + 2);
 
639
  if (tmp == NULL){
 
640
    return NULL;
 
641
  }
 
642
  if(f_len > 0){
 
643
    memcpy(tmp, first, f_len);
 
644
  }
 
645
  tmp[f_len] = '/';
 
646
  if(s_len > 0){
 
647
    memcpy(tmp + f_len + 1, second, s_len);
 
648
  }
 
649
  tmp[f_len + 1 + s_len] = '\0';
 
650
  return tmp;
 
651
}
 
652
 
 
653
 
558
654
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
559
655
    AvahiServerConfig config;
560
656
    AvahiSServiceBrowser *sb = NULL;
561
657
    int error;
562
658
    int ret;
563
659
    int returncode = EXIT_SUCCESS;
564
 
 
 
660
    const char *interface = "eth0";
 
661
    struct ifreq network;
 
662
    int sd;
 
663
    char *connect_to = NULL;
 
664
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
665
    
565
666
    while (true){
566
667
      static struct option long_options[] = {
567
668
        {"debug", no_argument, (int *)&debug, 1},
 
669
        {"connect", required_argument, 0, 'C'},
568
670
        {"interface", required_argument, 0, 'i'},
 
671
        {"certdir", required_argument, 0, 'd'},
 
672
        {"certkey", required_argument, 0, 'c'},
 
673
        {"certfile", required_argument, 0, 'k'},
569
674
        {0, 0, 0, 0} };
570
 
 
 
675
      
571
676
      int option_index = 0;
572
 
      ret = getopt_long (argc, argv, "i:", long_options, &option_index);
573
 
 
 
677
      ret = getopt_long (argc, argv, "i:", long_options,
 
678
                         &option_index);
 
679
      
574
680
      if (ret == -1){
575
681
        break;
576
682
      }
581
687
      case 'i':
582
688
        interface = optarg;
583
689
        break;
 
690
      case 'C':
 
691
        connect_to = optarg;
 
692
        break;
 
693
      case 'd':
 
694
        certdir = optarg;
 
695
        break;
 
696
      case 'c':
 
697
        certfile = optarg;
 
698
        break;
 
699
      case 'k':
 
700
        certkey = optarg;
 
701
        break;
584
702
      default:
585
703
        exit(EXIT_FAILURE);
586
704
      }
587
705
    }
588
706
    
 
707
    certfile = combinepath(certdir, certfile);
 
708
    if (certfile == NULL){
 
709
      perror("combinepath");
 
710
      returncode = EXIT_FAILURE;
 
711
      goto exit;
 
712
    }
 
713
 
 
714
    certkey = combinepath(certdir, certkey);
 
715
    if (certkey == NULL){
 
716
      perror("combinepath");
 
717
      returncode = EXIT_FAILURE;
 
718
      goto exit;
 
719
    }
 
720
    
 
721
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
722
    if(if_index == 0){
 
723
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
724
      exit(EXIT_FAILURE);
 
725
    }
 
726
    
 
727
    if(connect_to != NULL){
 
728
      /* Connect directly, do not use Zeroconf */
 
729
      /* (Mainly meant for debugging) */
 
730
      char *address = strrchr(connect_to, ':');
 
731
      if(address == NULL){
 
732
        fprintf(stderr, "No colon in address\n");
 
733
        exit(EXIT_FAILURE);
 
734
      }
 
735
      errno = 0;
 
736
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
737
      if(errno){
 
738
        perror("Bad port number");
 
739
        exit(EXIT_FAILURE);
 
740
      }
 
741
      *address = '\0';
 
742
      address = connect_to;
 
743
      ret = start_mandos_communication(address, port, if_index);
 
744
      if(ret < 0){
 
745
        exit(EXIT_FAILURE);
 
746
      } else {
 
747
        exit(EXIT_SUCCESS);
 
748
      }
 
749
    }
 
750
    
 
751
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
752
    if(sd < 0) {
 
753
      perror("socket");
 
754
      returncode = EXIT_FAILURE;
 
755
      goto exit;
 
756
    }
 
757
    strcpy(network.ifr_name, interface);    
 
758
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
759
    if(ret == -1){
 
760
      
 
761
      perror("ioctl SIOCGIFFLAGS");
 
762
      returncode = EXIT_FAILURE;
 
763
      goto exit;
 
764
    }
 
765
    if((network.ifr_flags & IFF_UP) == 0){
 
766
      network.ifr_flags |= IFF_UP;
 
767
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
768
      if(ret == -1){
 
769
        perror("ioctl SIOCSIFFLAGS");
 
770
        returncode = EXIT_FAILURE;
 
771
        goto exit;
 
772
      }
 
773
    }
 
774
    close(sd);
 
775
    
589
776
    if (not debug){
590
777
      avahi_set_log_function(empty_log);
591
778
    }
592
779
    
593
780
    /* Initialize the psuedo-RNG */
594
 
    srand(time(NULL));
 
781
    srand((unsigned int) time(NULL));
595
782
 
596
783
    /* Allocate main loop object */
597
784
    if (!(simple_poll = avahi_simple_poll_new())) {
598
785
        fprintf(stderr, "Failed to create simple poll object.\n");
599
 
        
 
786
        returncode = EXIT_FAILURE;      
600
787
        goto exit;
601
788
    }
602
789
 
608
795
    config.publish_domain = 0;
609
796
 
610
797
    /* Allocate a new server */
611
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
798
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
799
                              &config, NULL, NULL, &error);
612
800
 
613
801
    /* Free the configuration data */
614
802
    avahi_server_config_free(&config);
615
803
 
616
804
    /* Check if creating the server object succeeded */
617
805
    if (!server) {
618
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
806
        fprintf(stderr, "Failed to create server: %s\n",
 
807
                avahi_strerror(error));
619
808
        returncode = EXIT_FAILURE;
620
809
        goto exit;
621
810
    }
622
811
    
623
812
    /* Create the service browser */
624
 
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
625
 
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
 
813
    sb = avahi_s_service_browser_new(server, if_index,
 
814
                                     AVAHI_PROTO_INET6,
 
815
                                     "_mandos._tcp", NULL, 0,
 
816
                                     browse_callback, server);
 
817
    if (!sb) {
 
818
        fprintf(stderr, "Failed to create service browser: %s\n",
 
819
                avahi_strerror(avahi_server_errno(server)));
626
820
        returncode = EXIT_FAILURE;
627
821
        goto exit;
628
822
    }
635
829
    
636
830
    avahi_simple_poll_loop(simple_poll);
637
831
    
638
 
exit:
 
832
 exit:
639
833
 
640
834
    if (debug){
641
835
      fprintf(stderr, "%s exiting\n", argv[0]);
650
844
 
651
845
    if (simple_poll)
652
846
        avahi_simple_poll_free(simple_poll);
653
 
 
 
847
    free(certfile);
 
848
    free(certkey);
 
849
    
654
850
    return returncode;
655
851
}