/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugins.d/mandosclient.c

  • Committer: 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
 
37
38
#include <stdlib.h>
38
39
#include <time.h>
39
40
#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
42
41
 
43
42
#include <avahi-core/core.h>
44
43
#include <avahi-core/lookup.h>
48
47
#include <avahi-common/error.h>
49
48
 
50
49
//mandos client part
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 */
 
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 */
56
54
 
57
55
#include <unistd.h>             /* close() */
58
56
#include <netinet/in.h>
65
63
#include <errno.h>              /* perror() */
66
64
#include <gpgme.h>
67
65
 
68
 
// getopt long
69
 
#include <getopt.h>
70
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"
71
72
#define BUFFER_SIZE 256
72
73
#define DH_BITS 1024
73
74
 
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
 
 
80
75
typedef struct {
81
 
  AvahiSimplePoll *simple_poll;
82
 
  AvahiServer *server;
 
76
  gnutls_session_t session;
83
77
  gnutls_certificate_credentials_t cred;
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){
 
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){
91
83
  gpgme_data_t dh_crypto, dh_plain;
92
84
  gpgme_ctx_t ctx;
93
85
  gpgme_error_t rc;
94
86
  ssize_t ret;
95
 
  ssize_t new_packet_capacity = 0;
96
 
  ssize_t new_packet_length = 0;
 
87
  size_t new_packet_capacity = 0;
 
88
  size_t new_packet_length = 0;
97
89
  gpgme_engine_info_t engine_info;
98
90
 
99
 
  if (debug){
100
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
101
 
  }
102
 
  
103
91
  /* Init GPGME */
104
92
  gpgme_check_version(NULL);
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
 
  }
 
93
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
111
94
  
112
95
  /* Set GPGME home directory */
113
96
  rc = gpgme_get_engine_info (&engine_info);
153
136
    return -1;
154
137
  }
155
138
  
156
 
  /* Decrypt data from the FILE pointer to the plaintext data
157
 
     buffer */
 
139
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
158
140
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
159
141
  if (rc != GPG_ERR_NO_ERROR){
160
142
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
161
143
            gpgme_strsource(rc), gpgme_strerror(rc));
162
144
    return -1;
163
145
  }
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
 
  }
197
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
 
198
167
  /* Delete the GPGME FILE pointer cryptotext data buffer */
199
168
  gpgme_data_release(dh_crypto);
200
169
  
201
170
  /* Seek back to the beginning of the GPGME plaintext data buffer */
202
 
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
203
 
    perror("pgpme_data_seek");
204
 
  }
205
 
  
 
171
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
172
 
206
173
  *new_packet = 0;
207
174
  while(true){
208
175
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
209
 
      *new_packet = realloc(*new_packet,
210
 
                            (unsigned int)new_packet_capacity
211
 
                            + BUFFER_SIZE);
 
176
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
212
177
      if (*new_packet == NULL){
213
178
        perror("realloc");
214
179
        return -1;
216
181
      new_packet_capacity += BUFFER_SIZE;
217
182
    }
218
183
    
219
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
220
 
                          BUFFER_SIZE);
 
184
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
221
185
    /* Print the data, if any */
222
186
    if (ret == 0){
 
187
      /* If password is empty, then a incorrect error will be printed */
223
188
      break;
224
189
    }
225
190
    if(ret < 0){
229
194
    new_packet_length += ret;
230
195
  }
231
196
 
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 */
 
197
   /* Delete the GPGME plaintext data buffer */
241
198
  gpgme_data_release(dh_plain);
242
199
  return new_packet_length;
243
200
}
249
206
  return ret;
250
207
}
251
208
 
252
 
static void debuggnutls(__attribute__((unused)) int level,
253
 
                        const char* string){
 
209
void debuggnutls(int level, const char* string){
254
210
  fprintf(stderr, "%s", string);
255
211
}
256
212
 
257
 
static int initgnutls(mandos_context *mc){
 
213
int initgnutls(encrypted_session *es){
258
214
  const char *err;
259
215
  int ret;
260
216
  
261
 
  if(debug){
262
 
    fprintf(stderr, "Initializing GnuTLS\n");
263
 
  }
264
 
 
265
217
  if ((ret = gnutls_global_init ())
266
218
      != GNUTLS_E_SUCCESS) {
267
219
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
268
220
    return -1;
269
221
  }
270
222
 
271
 
  if (debug){
272
 
    gnutls_global_set_log_level(11);
273
 
    gnutls_global_set_log_function(debuggnutls);
274
 
  }
275
 
  
 
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
 
276
228
  /* openpgp credentials */
277
229
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
278
230
      != GNUTLS_E_SUCCESS) {
279
 
    fprintf (stderr, "memory error: %s\n",
280
 
             safer_gnutls_strerror(ret));
 
231
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
281
232
    return -1;
282
233
  }
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
 
  
 
234
 
290
235
  ret = gnutls_certificate_set_openpgp_key_file
291
 
    (es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
 
236
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
292
237
  if (ret != GNUTLS_E_SUCCESS) {
293
238
    fprintf
294
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
295
 
       " '%s')\n",
296
 
       ret, certfile, certkey);
 
239
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
 
240
       ret, CERTFILE, KEYFILE);
297
241
    fprintf(stdout, "The Error is: %s\n",
298
242
            safer_gnutls_strerror(ret));
299
243
    return -1;
300
244
  }
301
 
  
302
 
  //GnuTLS server initialization
 
245
 
 
246
  //Gnutls server initialization
303
247
  if ((ret = gnutls_dh_params_init (&es->dh_params))
304
248
      != GNUTLS_E_SUCCESS) {
305
249
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
306
250
             safer_gnutls_strerror(ret));
307
251
    return -1;
308
252
  }
309
 
  
 
253
 
310
254
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
311
255
      != GNUTLS_E_SUCCESS) {
312
256
    fprintf (stderr, "Error in prime generation: %s\n",
313
257
             safer_gnutls_strerror(ret));
314
258
    return -1;
315
259
  }
316
 
  
 
260
 
317
261
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
318
 
  
319
 
  // GnuTLS session creation
 
262
 
 
263
  // Gnutls session creation
320
264
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
321
265
      != GNUTLS_E_SUCCESS){
322
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
 
266
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
323
267
            safer_gnutls_strerror(ret));
324
268
  }
325
 
  
326
 
  if ((ret = gnutls_priority_set_direct (es->session, mc->priority, &err))
 
269
 
 
270
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
327
271
      != GNUTLS_E_SUCCESS) {
328
272
    fprintf(stderr, "Syntax error at: %s\n", err);
329
 
    fprintf(stderr, "GnuTLS error: %s\n",
 
273
    fprintf(stderr, "Gnutls error: %s\n",
330
274
            safer_gnutls_strerror(ret));
331
275
    return -1;
332
276
  }
333
 
  
 
277
 
334
278
  if ((ret = gnutls_credentials_set
335
279
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
336
280
      != GNUTLS_E_SUCCESS) {
338
282
            safer_gnutls_strerror(ret));
339
283
    return -1;
340
284
  }
341
 
  
 
285
 
342
286
  /* ignore client certificate if any. */
343
 
  gnutls_certificate_server_set_request (es->session,
344
 
                                         GNUTLS_CERT_IGNORE);
 
287
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
345
288
  
346
289
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
347
290
  
348
291
  return 0;
349
292
}
350
293
 
351
 
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
352
 
                      __attribute__((unused)) const char *txt){}
 
294
void empty_log(AvahiLogLevel level, const char *txt){}
353
295
 
354
 
static int start_mandos_communication(const char *ip, uint16_t port,
355
 
                                      AvahiIfIndex if_index,
356
 
                                      mandos_context *mc){
 
296
int start_mandos_communcation(char *ip, uint16_t port){
357
297
  int ret, tcp_sd;
358
298
  struct sockaddr_in6 to;
 
299
  struct in6_addr ip_addr;
359
300
  encrypted_session es;
360
301
  char *buffer = NULL;
361
302
  char *decrypted_buffer;
362
303
  size_t buffer_length = 0;
363
304
  size_t buffer_capacity = 0;
364
305
  ssize_t decrypted_buffer_size;
365
 
  size_t written = 0;
366
306
  int retval = 0;
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
 
  }
 
307
 
373
308
  
374
309
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
375
310
  if(tcp_sd < 0) {
376
311
    perror("socket");
377
312
    return -1;
378
313
  }
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);
 
314
  
 
315
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
 
316
  if(tcp_sd < 0) {
 
317
    perror("setsockopt bindtodevice");
 
318
    return -1;
389
319
  }
390
320
  
391
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
 
321
  memset(&to,0,sizeof(to));
392
322
  to.sin6_family = AF_INET6;
393
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
323
  ret = inet_pton(AF_INET6, ip, &ip_addr);
394
324
  if (ret < 0 ){
395
325
    perror("inet_pton");
396
326
    return -1;
399
329
    fprintf(stderr, "Bad address: %s\n", ip);
400
330
    return -1;
401
331
  }
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
 
  }
 
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
 
                                               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
 
      }
 
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);
535
418
  return retval;
536
419
}
537
420
 
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
 
 
 
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
}
649
505
 
650
506
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
651
507
    AvahiServerConfig config;
652
508
    AvahiSServiceBrowser *sb = NULL;
653
509
    int error;
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
 
    }
 
510
    int ret = 1;
728
511
 
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
 
    }
 
512
    avahi_set_log_function(empty_log);
794
513
    
795
514
    /* Initialize the psuedo-RNG */
796
 
    srand((unsigned int) time(NULL));
 
515
    srand(time(NULL));
797
516
 
798
517
    /* Allocate main loop object */
799
 
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
 
518
    if (!(simple_poll = avahi_simple_poll_new())) {
800
519
        fprintf(stderr, "Failed to create simple poll object.\n");
801
 
        returncode = EXIT_FAILURE;      
802
 
        goto exit;
 
520
        goto fail;
803
521
    }
804
522
 
805
523
    /* Do not publish any local records */
809
527
    config.publish_workstation = 0;
810
528
    config.publish_domain = 0;
811
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
    
812
535
    /* Allocate a new server */
813
 
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
814
 
                              &config, NULL, NULL, &error);
 
536
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
815
537
 
816
538
    /* Free the configuration data */
817
539
    avahi_server_config_free(&config);
818
540
 
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;
 
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;
825
545
    }
826
546
    
827
547
    /* Create the service browser */
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;
 
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;
837
551
    }
838
552
    
839
553
    /* Run the main loop */
840
 
 
841
 
    if (debug){
842
 
      fprintf(stderr, "Starting avahi loop search\n");
843
 
    }
844
 
    
845
554
    avahi_simple_poll_loop(simple_poll);
846
555
    
847
 
 exit:
848
 
 
849
 
    if (debug){
850
 
      fprintf(stderr, "%s exiting\n", argv[0]);
851
 
    }
 
556
    ret = 0;
 
557
    
 
558
fail:
852
559
    
853
560
    /* Cleanup things */
854
561
    if (sb)
855
562
        avahi_s_service_browser_free(sb);
856
563
    
857
 
    if (mc.server)
858
 
        avahi_server_free(mc.server);
 
564
    if (server)
 
565
        avahi_server_free(server);
859
566
 
860
567
    if (simple_poll)
861
568
        avahi_simple_poll_free(simple_poll);
862
 
    free(certfile);
863
 
    free(certkey);
864
 
    
865
 
    return returncode;
 
569
 
 
570
    return ret;
866
571
}