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