/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-31 19:51:44 UTC
  • mfrom: (24.1.5 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080731195144-yb37wz2sr1e6b3m4
Merge.

Show diffs side-by-side

added added

removed removed

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