/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-08-02 14:33:47 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080802143347-u1m4zs1q0feu72ei
* TODO: Converted to org-mode style

* plugins.d/mandosclient.c (certdir): Changed to "/conf/conf.d/mandos/".
  (certdir, certfile, certkey, pgp_packet_decrypt, debuggnutls,
  initgnutls, empty_log, combinepath): Made static.
  (combinepath): Rewritten to only get the argument string lengths
                 once.  Do not print error message; leave that to
                 caller.  All callers changed.

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 <mandos@fukt.bsnet.se>.
12
29
 */
13
30
 
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
 
 
 
31
/* Needed by GPGME, specifically gpgme_data_seek() */
33
32
#define _LARGEFILE_SOURCE
34
33
#define _FILE_OFFSET_BITS 64
35
34
 
47
46
#include <avahi-common/error.h>
48
47
 
49
48
//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 */
 
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 */
54
54
 
55
55
#include <unistd.h>             /* close() */
56
56
#include <netinet/in.h>
63
63
#include <errno.h>              /* perror() */
64
64
#include <gpgme.h>
65
65
 
 
66
// getopt long
 
67
#include <getopt.h>
66
68
 
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
69
#define BUFFER_SIZE 256
73
70
#define DH_BITS 1024
74
71
 
 
72
static const char *certdir = "/conf/conf.d/mandos";
 
73
static const char *certfile = "openpgp-client.txt";
 
74
static const char *certkey = "openpgp-client-key.txt";
 
75
 
 
76
bool debug = false;
 
77
 
75
78
typedef struct {
76
79
  gnutls_session_t session;
77
80
  gnutls_certificate_credentials_t cred;
79
82
} encrypted_session;
80
83
 
81
84
 
82
 
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
 
85
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
86
                                   char **new_packet,
 
87
                                   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
static void debuggnutls(__attribute__((unused)) int level,
 
250
                        const char* string){
210
251
  fprintf(stderr, "%s", string);
211
252
}
212
253
 
213
 
int initgnutls(encrypted_session *es){
 
254
static int initgnutls(encrypted_session *es){
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
static 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
static 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
/* Combines file name and path and returns the malloced new
 
632
   string. some sane checks could/should be added */
 
633
static const char *combinepath(const char *first, const char *second){
 
634
  size_t f_len = strlen(first);
 
635
  size_t s_len = strlen(second);
 
636
  char *tmp = malloc(f_len + s_len + 2);
 
637
  if (tmp == NULL){
 
638
    return NULL;
 
639
  }
 
640
  if(f_len > 0){
 
641
    memcpy(tmp, first, f_len);
 
642
  }
 
643
  tmp[f_len] = '/';
 
644
  if(s_len > 0){
 
645
    memcpy(tmp + f_len + 1, second, s_len);
 
646
  }
 
647
  tmp[f_len + 1 + s_len] = '\0';
 
648
  return tmp;
 
649
}
 
650
 
 
651
 
506
652
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
507
653
    AvahiServerConfig config;
508
654
    AvahiSServiceBrowser *sb = NULL;
509
655
    int error;
510
 
    int ret = 1;
511
 
 
512
 
    avahi_set_log_function(empty_log);
 
656
    int ret;
 
657
    int returncode = EXIT_SUCCESS;
 
658
    const char *interface = NULL;
 
659
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
660
    char *connect_to = NULL;
 
661
    
 
662
    while (true){
 
663
      static struct option long_options[] = {
 
664
        {"debug", no_argument, (int *)&debug, 1},
 
665
        {"connect", required_argument, 0, 'C'},
 
666
        {"interface", required_argument, 0, 'i'},
 
667
        {"certdir", required_argument, 0, 'd'},
 
668
        {"certkey", required_argument, 0, 'c'},
 
669
        {"certfile", required_argument, 0, 'k'},
 
670
        {0, 0, 0, 0} };
 
671
      
 
672
      int option_index = 0;
 
673
      ret = getopt_long (argc, argv, "i:", long_options,
 
674
                         &option_index);
 
675
      
 
676
      if (ret == -1){
 
677
        break;
 
678
      }
 
679
      
 
680
      switch(ret){
 
681
      case 0:
 
682
        break;
 
683
      case 'i':
 
684
        interface = optarg;
 
685
        break;
 
686
      case 'C':
 
687
        connect_to = optarg;
 
688
        break;
 
689
      case 'd':
 
690
        certdir = optarg;
 
691
        break;
 
692
      case 'c':
 
693
        certfile = optarg;
 
694
        break;
 
695
      case 'k':
 
696
        certkey = optarg;
 
697
        break;
 
698
      default:
 
699
        exit(EXIT_FAILURE);
 
700
      }
 
701
    }
 
702
    
 
703
    certfile = combinepath(certdir, certfile);
 
704
    if (certfile == NULL){
 
705
      perror("combinepath");
 
706
      goto exit;
 
707
    }
 
708
    
 
709
    if(interface != NULL){
 
710
      if_index = (AvahiIfIndex) if_nametoindex(interface);
 
711
      if(if_index == 0){
 
712
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
713
        exit(EXIT_FAILURE);
 
714
      }
 
715
    }
 
716
    
 
717
    if(connect_to != NULL){
 
718
      /* Connect directly, do not use Zeroconf */
 
719
      /* (Mainly meant for debugging) */
 
720
      char *address = strrchr(connect_to, ':');
 
721
      if(address == NULL){
 
722
        fprintf(stderr, "No colon in address\n");
 
723
        exit(EXIT_FAILURE);
 
724
      }
 
725
      errno = 0;
 
726
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
727
      if(errno){
 
728
        perror("Bad port number");
 
729
        exit(EXIT_FAILURE);
 
730
      }
 
731
      *address = '\0';
 
732
      address = connect_to;
 
733
      ret = start_mandos_communication(address, port, if_index);
 
734
      if(ret < 0){
 
735
        exit(EXIT_FAILURE);
 
736
      } else {
 
737
        exit(EXIT_SUCCESS);
 
738
      }
 
739
    }
 
740
    
 
741
    certkey = combinepath(certdir, certkey);
 
742
    if (certkey == NULL){
 
743
      perror("combinepath");
 
744
      goto exit;
 
745
    }
 
746
    
 
747
    if (not debug){
 
748
      avahi_set_log_function(empty_log);
 
749
    }
513
750
    
514
751
    /* Initialize the psuedo-RNG */
515
 
    srand(time(NULL));
 
752
    srand((unsigned int) time(NULL));
516
753
 
517
754
    /* Allocate main loop object */
518
755
    if (!(simple_poll = avahi_simple_poll_new())) {
519
756
        fprintf(stderr, "Failed to create simple poll object.\n");
520
 
        goto fail;
 
757
        
 
758
        goto exit;
521
759
    }
522
760
 
523
761
    /* Do not publish any local records */
527
765
    config.publish_workstation = 0;
528
766
    config.publish_domain = 0;
529
767
 
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
768
    /* Allocate a new server */
536
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
769
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
770
                              &config, NULL, NULL, &error);
537
771
 
538
772
    /* Free the configuration data */
539
773
    avahi_server_config_free(&config);
540
774
 
541
 
    /* Check wether creating the server object succeeded */
 
775
    /* Check if creating the server object succeeded */
542
776
    if (!server) {
543
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
544
 
        goto fail;
 
777
        fprintf(stderr, "Failed to create server: %s\n",
 
778
                avahi_strerror(error));
 
779
        returncode = EXIT_FAILURE;
 
780
        goto exit;
545
781
    }
546
782
    
547
783
    /* 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;
 
784
    sb = avahi_s_service_browser_new(server, if_index,
 
785
                                     AVAHI_PROTO_INET6,
 
786
                                     "_mandos._tcp", NULL, 0,
 
787
                                     browse_callback, server);
 
788
    if (!sb) {
 
789
        fprintf(stderr, "Failed to create service browser: %s\n",
 
790
                avahi_strerror(avahi_server_errno(server)));
 
791
        returncode = EXIT_FAILURE;
 
792
        goto exit;
551
793
    }
552
794
    
553
795
    /* Run the main loop */
 
796
 
 
797
    if (debug){
 
798
      fprintf(stderr, "Starting avahi loop search\n");
 
799
    }
 
800
    
554
801
    avahi_simple_poll_loop(simple_poll);
555
802
    
556
 
    ret = 0;
557
 
    
558
 
fail:
 
803
 exit:
 
804
 
 
805
    if (debug){
 
806
      fprintf(stderr, "%s exiting\n", argv[0]);
 
807
    }
559
808
    
560
809
    /* Cleanup things */
561
810
    if (sb)
566
815
 
567
816
    if (simple_poll)
568
817
        avahi_simple_poll_free(simple_poll);
569
 
 
570
 
    return ret;
 
818
    free(certfile);
 
819
    free(certkey);
 
820
    
 
821
    return returncode;
571
822
}