/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

  • Committer: Teddy Hogeborn
  • Date: 2008-07-21 02:33:00 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080721023300-c4t0cq7sxit973py
* plugins.d/Makefile: Removed

* plugins.d/mandosclient.c (start_mandos_communcation): Bug fix: write
                                                        server IP
                                                        address to
                                                        "to" struct.

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