/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

not working midwork...

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