/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-30 02:11:33 UTC
  • mto: (237.7.1 mandos) (24.1.154 mandos)
  • mto: This revision was merged to the branch mainline in revision 30.
  • Revision ID: belorn@braxen-20080730021133-q341llq93r328q5b
Added optional parameters certdir, certkey and certfile that can be iven at start in the command line.

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