/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: Teddy Hogeborn
  • Date: 2008-07-21 04:42:08 UTC
  • mfrom: (15.1.3 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080721044208-y8v1sjmvalfiehrv
Merge.

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