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