/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: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support:
Pluginbased client handler
rewritten Mandos client
       Avahi instead of udp server discovery
       openpgp encrypted key support
Passprompt stand alone application for direct console input
Added logging for Mandos server

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8 -*- */
2
 
/*
3
 
 * Mandos client - get and decrypt data from a Mandos server
 
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.
4
6
 *
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>.
 
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.
29
12
 */
30
13
 
31
 
/* Needed by GPGME, specifically gpgme_data_seek() */
 
14
/***
 
15
  This file is part of avahi.
 
16
 
 
17
  avahi is free software; you can redistribute it and/or modify it
 
18
  under the terms of the GNU Lesser General Public License as
 
19
  published by the Free Software Foundation; either version 2.1 of the
 
20
  License, or (at your option) any later version.
 
21
 
 
22
  avahi is distributed in the hope that it will be useful, but WITHOUT
 
23
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
24
  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
 
25
  Public License for more details.
 
26
 
 
27
  You should have received a copy of the GNU Lesser General Public
 
28
  License along with avahi; if not, write to the Free Software
 
29
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
30
  USA.
 
31
***/
 
32
 
32
33
#define _LARGEFILE_SOURCE
33
34
#define _FILE_OFFSET_BITS 64
34
35
 
46
47
#include <avahi-common/error.h>
47
48
 
48
49
//mandos client part
49
 
#include <sys/types.h>          /* socket(), inet_pton() */
50
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
51
 
                                   struct in6_addr, inet_pton() */
52
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
53
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
 
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 */
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>
68
66
 
 
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"
69
72
#define BUFFER_SIZE 256
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  */
 
73
#define DH_BITS 1024
 
74
 
80
75
typedef struct {
81
76
  gnutls_session_t session;
82
77
  gnutls_certificate_credentials_t cred;
84
79
} encrypted_session;
85
80
 
86
81
 
87
 
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
 
                                   char **new_packet,
89
 
                                   const char *homedir){
 
82
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
90
83
  gpgme_data_t dh_crypto, dh_plain;
91
84
  gpgme_ctx_t ctx;
92
85
  gpgme_error_t rc;
93
86
  ssize_t ret;
94
 
  ssize_t new_packet_capacity = 0;
95
 
  ssize_t new_packet_length = 0;
 
87
  size_t new_packet_capacity = 0;
 
88
  size_t new_packet_length = 0;
96
89
  gpgme_engine_info_t engine_info;
97
90
 
98
 
  if (debug){
99
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
100
 
  }
101
 
  
102
91
  /* Init GPGME */
103
92
  gpgme_check_version(NULL);
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
 
  }
 
93
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
110
94
  
111
95
  /* Set GPGME home directory */
112
96
  rc = gpgme_get_engine_info (&engine_info);
152
136
    return -1;
153
137
  }
154
138
  
155
 
  /* Decrypt data from the FILE pointer to the plaintext data
156
 
     buffer */
 
139
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
157
140
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
158
141
  if (rc != GPG_ERR_NO_ERROR){
159
142
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
160
143
            gpgme_strsource(rc), gpgme_strerror(rc));
161
144
    return -1;
162
145
  }
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
 
  }
196
146
  
 
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
 
197
167
  /* Delete the GPGME FILE pointer cryptotext data buffer */
198
168
  gpgme_data_release(dh_crypto);
199
169
  
200
170
  /* Seek back to the beginning of the GPGME plaintext data buffer */
201
 
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
202
 
    perror("pgpme_data_seek");
203
 
  }
204
 
  
 
171
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
172
 
205
173
  *new_packet = 0;
206
174
  while(true){
207
175
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
208
 
      *new_packet = realloc(*new_packet,
209
 
                            (unsigned int)new_packet_capacity
210
 
                            + BUFFER_SIZE);
 
176
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
211
177
      if (*new_packet == NULL){
212
178
        perror("realloc");
213
179
        return -1;
215
181
      new_packet_capacity += BUFFER_SIZE;
216
182
    }
217
183
    
218
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
219
 
                          BUFFER_SIZE);
 
184
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
220
185
    /* Print the data, if any */
221
186
    if (ret == 0){
 
187
      /* If password is empty, then a incorrect error will be printed */
222
188
      break;
223
189
    }
224
190
    if(ret < 0){
228
194
    new_packet_length += ret;
229
195
  }
230
196
 
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 */
 
197
   /* Delete the GPGME plaintext data buffer */
240
198
  gpgme_data_release(dh_plain);
241
199
  return new_packet_length;
242
200
}
248
206
  return ret;
249
207
}
250
208
 
251
 
static void debuggnutls(__attribute__((unused)) int level,
252
 
                        const char* string){
 
209
void debuggnutls(int level, const char* string){
253
210
  fprintf(stderr, "%s", string);
254
211
}
255
212
 
256
 
static int initgnutls(encrypted_session *es){
 
213
int initgnutls(encrypted_session *es){
257
214
  const char *err;
258
215
  int ret;
259
216
  
260
 
  if(debug){
261
 
    fprintf(stderr, "Initializing GnuTLS\n");
262
 
  }
263
 
 
264
217
  if ((ret = gnutls_global_init ())
265
218
      != GNUTLS_E_SUCCESS) {
266
219
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
267
220
    return -1;
268
221
  }
269
222
 
270
 
  if (debug){
271
 
    gnutls_global_set_log_level(11);
272
 
    gnutls_global_set_log_function(debuggnutls);
273
 
  }
274
 
  
 
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
 
275
228
  /* openpgp credentials */
276
229
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
277
230
      != GNUTLS_E_SUCCESS) {
278
 
    fprintf (stderr, "memory error: %s\n",
279
 
             safer_gnutls_strerror(ret));
 
231
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
280
232
    return -1;
281
233
  }
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
 
  
 
234
 
289
235
  ret = gnutls_certificate_set_openpgp_key_file
290
 
    (es->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
236
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
291
237
  if (ret != GNUTLS_E_SUCCESS) {
292
238
    fprintf
293
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
294
 
       " '%s')\n",
295
 
       ret, pubkeyfile, seckeyfile);
 
239
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
 
240
       ret, CERTFILE, KEYFILE);
296
241
    fprintf(stdout, "The Error is: %s\n",
297
242
            safer_gnutls_strerror(ret));
298
243
    return -1;
299
244
  }
300
 
  
301
 
  //GnuTLS server initialization
 
245
 
 
246
  //Gnutls server initialization
302
247
  if ((ret = gnutls_dh_params_init (&es->dh_params))
303
248
      != GNUTLS_E_SUCCESS) {
304
249
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
305
250
             safer_gnutls_strerror(ret));
306
251
    return -1;
307
252
  }
308
 
  
309
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, dh_bits))
 
253
 
 
254
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
310
255
      != GNUTLS_E_SUCCESS) {
311
256
    fprintf (stderr, "Error in prime generation: %s\n",
312
257
             safer_gnutls_strerror(ret));
313
258
    return -1;
314
259
  }
315
 
  
 
260
 
316
261
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
317
 
  
318
 
  // GnuTLS session creation
 
262
 
 
263
  // Gnutls session creation
319
264
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
320
265
      != GNUTLS_E_SUCCESS){
321
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
 
266
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
322
267
            safer_gnutls_strerror(ret));
323
268
  }
324
 
  
 
269
 
325
270
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
326
271
      != GNUTLS_E_SUCCESS) {
327
272
    fprintf(stderr, "Syntax error at: %s\n", err);
328
 
    fprintf(stderr, "GnuTLS error: %s\n",
 
273
    fprintf(stderr, "Gnutls error: %s\n",
329
274
            safer_gnutls_strerror(ret));
330
275
    return -1;
331
276
  }
332
 
  
 
277
 
333
278
  if ((ret = gnutls_credentials_set
334
279
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
335
280
      != GNUTLS_E_SUCCESS) {
337
282
            safer_gnutls_strerror(ret));
338
283
    return -1;
339
284
  }
340
 
  
 
285
 
341
286
  /* ignore client certificate if any. */
342
 
  gnutls_certificate_server_set_request (es->session,
343
 
                                         GNUTLS_CERT_IGNORE);
 
287
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
344
288
  
345
 
  gnutls_dh_set_prime_bits (es->session, dh_bits);
 
289
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
346
290
  
347
291
  return 0;
348
292
}
349
293
 
350
 
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
351
 
                      __attribute__((unused)) const char *txt){}
 
294
void empty_log(AvahiLogLevel level, const char *txt){}
352
295
 
353
 
static int start_mandos_communication(const char *ip, uint16_t port,
354
 
                                      AvahiIfIndex if_index){
 
296
int start_mandos_communcation(char *ip, uint16_t port){
355
297
  int ret, tcp_sd;
356
298
  struct sockaddr_in6 to;
 
299
  struct in6_addr ip_addr;
357
300
  encrypted_session es;
358
301
  char *buffer = NULL;
359
302
  char *decrypted_buffer;
360
303
  size_t buffer_length = 0;
361
304
  size_t buffer_capacity = 0;
362
305
  ssize_t decrypted_buffer_size;
363
 
  size_t written = 0;
364
306
  int retval = 0;
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
 
  }
 
307
 
371
308
  
372
309
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
373
310
  if(tcp_sd < 0) {
375
312
    return -1;
376
313
  }
377
314
  
378
 
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
379
 
    if(debug){
380
 
      perror("if_indextoname");
381
 
    }
 
315
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
 
316
  if(tcp_sd < 0) {
 
317
    perror("setsockopt bindtodevice");
382
318
    return -1;
383
319
  }
384
320
  
385
 
  if(debug){
386
 
    fprintf(stderr, "Binding to interface %s\n", interface);
387
 
  }
388
 
  
389
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
 
321
  memset(&to,0,sizeof(to));
390
322
  to.sin6_family = AF_INET6;
391
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
323
  ret = inet_pton(AF_INET6, ip, &ip_addr);
392
324
  if (ret < 0 ){
393
325
    perror("inet_pton");
394
326
    return -1;
397
329
    fprintf(stderr, "Bad address: %s\n", ip);
398
330
    return -1;
399
331
  }
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
 
  }
 
332
  to.sin6_port = htons(port);
 
333
  to.sin6_scope_id = if_nametoindex("eth0");
417
334
  
418
335
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
419
336
  if (ret < 0){
426
343
    retval = -1;
427
344
    return -1;
428
345
  }
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
 
  
 
346
    
 
347
  
 
348
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
 
349
 
437
350
  ret = gnutls_handshake (es.session);
438
351
  
439
352
  if (ret != GNUTLS_E_SUCCESS){
440
 
    if(debug){
441
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
442
 
      gnutls_perror (ret);
443
 
    }
 
353
    fprintf(stderr, "\n*** Handshake failed ***\n");
 
354
    gnutls_perror (ret);
444
355
    retval = -1;
445
356
    goto exit;
446
357
  }
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
 
  }
454
358
 
 
359
  //retrive password
455
360
  while(true){
456
361
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
457
362
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
482
387
        }
483
388
        break;
484
389
      default:
485
 
        fprintf(stderr, "Unknown error while reading data from"
486
 
                " encrypted session with mandos server\n");
 
390
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
487
391
        retval = -1;
488
392
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
489
393
        goto exit;
490
394
      }
491
395
    } else {
492
 
      buffer_length += (size_t) ret;
 
396
      buffer_length += ret;
493
397
    }
494
398
  }
495
 
  
 
399
 
496
400
  if (buffer_length > 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
 
      }
 
401
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
 
402
      retval = -1;
 
403
    } else {
 
404
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
516
405
      free(decrypted_buffer);
517
 
    } else {
518
 
      retval = -1;
519
406
    }
520
407
  }
521
408
 
 
409
  free(buffer);
 
410
 
522
411
  //shutdown procedure
523
 
 
524
 
  if(debug){
525
 
    fprintf(stderr, "Closing TLS session\n");
526
 
  }
527
 
 
528
 
  free(buffer);
529
412
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
530
413
 exit:
531
414
  close(tcp_sd);
540
423
 
541
424
static void resolve_callback(
542
425
    AvahiSServiceResolver *r,
543
 
    AvahiIfIndex interface,
 
426
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
544
427
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
545
428
    AvahiResolverEvent event,
546
429
    const char *name,
549
432
    const char *host_name,
550
433
    const AvahiAddress *address,
551
434
    uint16_t port,
552
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
553
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
435
    AvahiStringList *txt,
 
436
    AvahiLookupResultFlags flags,
554
437
    AVAHI_GCC_UNUSED void* userdata) {
555
438
    
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
 
      }
 
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
        }
581
458
    }
582
 
  }
583
 
  avahi_s_service_resolver_free(r);
 
459
    avahi_s_service_resolver_free(r);
584
460
}
585
461
 
586
462
static void browse_callback(
595
471
    void* userdata) {
596
472
    
597
473
    AvahiServer *s = userdata;
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
 
    
 
474
    assert(b);
 
475
 
 
476
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
 
477
 
603
478
    switch (event) {
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;
 
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;
632
503
    }
633
504
}
634
505
 
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
 
 
656
506
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
657
507
    AvahiServerConfig config;
658
508
    AvahiSServiceBrowser *sb = NULL;
659
509
    int error;
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
 
    }
 
510
    int ret = 1;
 
511
 
 
512
    avahi_set_log_function(empty_log);
763
513
    
764
514
    /* Initialize the psuedo-RNG */
765
 
    srand((unsigned int) time(NULL));
 
515
    srand(time(NULL));
766
516
 
767
517
    /* Allocate main loop object */
768
518
    if (!(simple_poll = avahi_simple_poll_new())) {
769
519
        fprintf(stderr, "Failed to create simple poll object.\n");
770
 
        
771
 
        goto exit;
 
520
        goto fail;
772
521
    }
773
522
 
774
523
    /* Do not publish any local records */
778
527
    config.publish_workstation = 0;
779
528
    config.publish_domain = 0;
780
529
 
 
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
    
781
535
    /* Allocate a new server */
782
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
783
 
                              &config, NULL, NULL, &error);
 
536
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
784
537
 
785
538
    /* Free the configuration data */
786
539
    avahi_server_config_free(&config);
787
540
 
788
 
    /* Check if creating the server object succeeded */
 
541
    /* Check wether creating the server object succeeded */
789
542
    if (!server) {
790
 
        fprintf(stderr, "Failed to create server: %s\n",
791
 
                avahi_strerror(error));
792
 
        returncode = EXIT_FAILURE;
793
 
        goto exit;
 
543
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
544
        goto fail;
794
545
    }
795
546
    
796
547
    /* Create the service browser */
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;
 
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;
806
551
    }
807
552
    
808
553
    /* Run the main loop */
809
 
 
810
 
    if (debug){
811
 
      fprintf(stderr, "Starting avahi loop search\n");
812
 
    }
813
 
    
814
554
    avahi_simple_poll_loop(simple_poll);
815
555
    
816
 
 exit:
817
 
 
818
 
    if (debug){
819
 
      fprintf(stderr, "%s exiting\n", argv[0]);
820
 
    }
 
556
    ret = 0;
 
557
    
 
558
fail:
821
559
    
822
560
    /* Cleanup things */
823
561
    if (sb)
828
566
 
829
567
    if (simple_poll)
830
568
        avahi_simple_poll_free(simple_poll);
831
 
    free(pubkeyfile);
832
 
    free(seckeyfile);
833
 
    
834
 
    return returncode;
 
569
 
 
570
    return ret;
835
571
}