/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/mandosclient.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-02 21:06:12 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080802210612-4c1waup4z0f66ya7
Non-tested commit for merge purposes.

* plugbasedclient.c (getplugin, addargument, set_cloexec): Made static.

* plugins.d/passprompt.c (termination_handler): Made static.

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