/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

merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
 * includes the following functions: "resolve_callback",
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
 
 * Everything else is
12
 
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
11
 * Everything else is Copyright © 2007-2008 Teddy Hogeborn and Björn
 
12
 * Påhlsson.
13
13
 * 
14
14
 * This program is free software: you can redistribute it and/or
15
15
 * modify it under the terms of the GNU General Public License as
25
25
 * along with this program.  If not, see
26
26
 * <http://www.gnu.org/licenses/>.
27
27
 * 
28
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
28
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
29
 * <https://www.fukt.bsnet.se/~teddy/>.
29
30
 */
30
31
 
31
 
/* Needed by GPGME, specifically gpgme_data_seek() */
 
32
#define _FORTIFY_SOURCE 2
 
33
 
32
34
#define _LARGEFILE_SOURCE
33
35
#define _FILE_OFFSET_BITS 64
34
36
 
37
39
#include <stdlib.h>
38
40
#include <time.h>
39
41
#include <net/if.h>             /* if_nametoindex */
40
 
#include <sys/ioctl.h>          /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
41
 
                                   SIOCSIFFLAGS */
42
 
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
43
 
                                   SIOCSIFFLAGS */
44
42
 
45
43
#include <avahi-core/core.h>
46
44
#include <avahi-core/lookup.h>
49
47
#include <avahi-common/malloc.h>
50
48
#include <avahi-common/error.h>
51
49
 
52
 
/* Mandos client part */
 
50
//mandos client part
53
51
#include <sys/types.h>          /* socket(), inet_pton() */
54
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
55
53
                                   struct in6_addr, inet_pton() */
62
60
#include <string.h>             /* memset */
63
61
#include <arpa/inet.h>          /* inet_pton() */
64
62
#include <iso646.h>             /* not */
65
 
#include <net/if.h>             /* IF_NAMESIZE */
66
63
 
67
 
/* GPGME */
 
64
// gpgme
68
65
#include <errno.h>              /* perror() */
69
66
#include <gpgme.h>
70
67
 
71
 
/* getopt_long */
 
68
// getopt long
72
69
#include <getopt.h>
73
70
 
 
71
#ifndef CERT_ROOT
 
72
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
 
73
#endif
 
74
#define CERTFILE CERT_ROOT "openpgp-client.txt"
 
75
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
74
76
#define BUFFER_SIZE 256
75
 
 
76
 
static const char *keydir = "/conf/conf.d/mandos";
77
 
static const char *pubkeyfile = "pubkey.txt";
78
 
static const char *seckeyfile = "seckey.txt";
 
77
#define DH_BITS 1024
79
78
 
80
79
bool debug = false;
81
80
 
82
 
/* Used for passing in values through all the callback functions */
83
81
typedef struct {
84
 
  AvahiSimplePoll *simple_poll;
85
 
  AvahiServer *server;
 
82
  gnutls_session_t session;
86
83
  gnutls_certificate_credentials_t cred;
87
 
  unsigned int dh_bits;
88
 
  const char *priority;
89
 
} mandos_context;
90
 
 
91
 
/* 
92
 
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
93
 
 * Returns -1 on error
94
 
 */
95
 
static ssize_t pgp_packet_decrypt (const char *cryptotext,
96
 
                                   size_t crypto_size,
97
 
                                   char **plaintext,
98
 
                                   const char *homedir){
 
84
  gnutls_dh_params_t dh_params;
 
85
} encrypted_session;
 
86
 
 
87
 
 
88
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
89
                            char **new_packet, const char *homedir){
99
90
  gpgme_data_t dh_crypto, dh_plain;
100
91
  gpgme_ctx_t ctx;
101
92
  gpgme_error_t rc;
102
93
  ssize_t ret;
103
 
  size_t plaintext_capacity = 0;
104
 
  ssize_t plaintext_length = 0;
 
94
  ssize_t new_packet_capacity = 0;
 
95
  ssize_t new_packet_length = 0;
105
96
  gpgme_engine_info_t engine_info;
106
 
  
 
97
 
107
98
  if (debug){
108
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
99
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
109
100
  }
110
101
  
111
102
  /* Init GPGME */
112
103
  gpgme_check_version(NULL);
113
 
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
114
 
  if (rc != GPG_ERR_NO_ERROR){
115
 
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
116
 
            gpgme_strsource(rc), gpgme_strerror(rc));
117
 
    return -1;
118
 
  }
 
104
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
119
105
  
120
 
  /* Set GPGME home directory for the OpenPGP engine only */
 
106
  /* Set GPGME home directory */
121
107
  rc = gpgme_get_engine_info (&engine_info);
122
108
  if (rc != GPG_ERR_NO_ERROR){
123
109
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
133
119
    engine_info = engine_info->next;
134
120
  }
135
121
  if(engine_info == NULL){
136
 
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
 
122
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
137
123
    return -1;
138
124
  }
139
125
  
140
 
  /* Create new GPGME data buffer from memory cryptotext */
141
 
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
142
 
                               0);
 
126
  /* Create new GPGME data buffer from packet buffer */
 
127
  rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
143
128
  if (rc != GPG_ERR_NO_ERROR){
144
129
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
145
130
            gpgme_strsource(rc), gpgme_strerror(rc));
151
136
  if (rc != GPG_ERR_NO_ERROR){
152
137
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
153
138
            gpgme_strsource(rc), gpgme_strerror(rc));
154
 
    gpgme_data_release(dh_crypto);
155
139
    return -1;
156
140
  }
157
141
  
160
144
  if (rc != GPG_ERR_NO_ERROR){
161
145
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
162
146
            gpgme_strsource(rc), gpgme_strerror(rc));
163
 
    plaintext_length = -1;
164
 
    goto decrypt_end;
 
147
    return -1;
165
148
  }
166
149
  
167
 
  /* Decrypt data from the cryptotext data buffer to the plaintext
168
 
     data buffer */
 
150
  /* Decrypt data from the FILE pointer to the plaintext data
 
151
     buffer */
169
152
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
170
153
  if (rc != GPG_ERR_NO_ERROR){
171
154
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
172
155
            gpgme_strsource(rc), gpgme_strerror(rc));
173
 
    plaintext_length = -1;
174
 
    goto decrypt_end;
 
156
    return -1;
175
157
  }
176
 
  
 
158
 
177
159
  if(debug){
178
 
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
 
160
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
179
161
  }
180
 
  
 
162
 
181
163
  if (debug){
182
164
    gpgme_decrypt_result_t result;
183
165
    result = gpgme_op_decrypt_result(ctx);
207
189
    }
208
190
  }
209
191
  
 
192
  /* Delete the GPGME FILE pointer cryptotext data buffer */
 
193
  gpgme_data_release(dh_crypto);
 
194
  
210
195
  /* Seek back to the beginning of the GPGME plaintext data buffer */
211
 
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
212
 
    perror("pgpme_data_seek");
213
 
    plaintext_length = -1;
214
 
    goto decrypt_end;
215
 
  }
216
 
  
217
 
  *plaintext = NULL;
 
196
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
 
197
 
 
198
  *new_packet = 0;
218
199
  while(true){
219
 
    if (plaintext_length + BUFFER_SIZE
220
 
        > (ssize_t) plaintext_capacity){
221
 
      *plaintext = realloc(*plaintext, plaintext_capacity
 
200
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
 
201
      *new_packet = realloc(*new_packet,
 
202
                            (unsigned int)new_packet_capacity
222
203
                            + BUFFER_SIZE);
223
 
      if (*plaintext == NULL){
 
204
      if (*new_packet == NULL){
224
205
        perror("realloc");
225
 
        plaintext_length = -1;
226
 
        goto decrypt_end;
 
206
        return -1;
227
207
      }
228
 
      plaintext_capacity += BUFFER_SIZE;
 
208
      new_packet_capacity += BUFFER_SIZE;
229
209
    }
230
210
    
231
 
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
 
211
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
232
212
                          BUFFER_SIZE);
233
213
    /* Print the data, if any */
234
214
    if (ret == 0){
235
 
      /* EOF */
236
215
      break;
237
216
    }
238
217
    if(ret < 0){
239
218
      perror("gpgme_data_read");
240
 
      plaintext_length = -1;
241
 
      goto decrypt_end;
 
219
      return -1;
242
220
    }
243
 
    plaintext_length += ret;
 
221
    new_packet_length += ret;
244
222
  }
245
223
 
246
 
  if(debug){
247
 
    fprintf(stderr, "Decrypted password is: ");
248
 
    for(ssize_t i = 0; i < plaintext_length; i++){
249
 
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
250
 
    }
251
 
    fprintf(stderr, "\n");
252
 
  }
253
 
  
254
 
 decrypt_end:
255
 
  
256
 
  /* Delete the GPGME cryptotext data buffer */
257
 
  gpgme_data_release(dh_crypto);
 
224
  /* FIXME: check characters before printing to screen so to not print
 
225
     terminal control characters */
 
226
  /*   if(debug){ */
 
227
  /*     fprintf(stderr, "decrypted password is: "); */
 
228
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
 
229
  /*     fprintf(stderr, "\n"); */
 
230
  /*   } */
258
231
  
259
232
  /* Delete the GPGME plaintext data buffer */
260
233
  gpgme_data_release(dh_plain);
261
 
  return plaintext_length;
 
234
  return new_packet_length;
262
235
}
263
236
 
264
237
static const char * safer_gnutls_strerror (int value) {
268
241
  return ret;
269
242
}
270
243
 
271
 
/* GnuTLS log function callback */
272
 
static void debuggnutls(__attribute__((unused)) int level,
273
 
                        const char* string){
274
 
  fprintf(stderr, "GnuTLS: %s", string);
 
244
void debuggnutls(__attribute__((unused)) int level,
 
245
                 const char* string){
 
246
  fprintf(stderr, "%s", string);
275
247
}
276
248
 
277
 
static int initgnutls(mandos_context *mc, gnutls_session_t *session,
278
 
                      gnutls_dh_params_t *dh_params){
 
249
int initgnutls(encrypted_session *es){
 
250
  const char *err;
279
251
  int ret;
280
252
  
281
253
  if(debug){
282
254
    fprintf(stderr, "Initializing GnuTLS\n");
283
255
  }
284
 
 
 
256
  
285
257
  if ((ret = gnutls_global_init ())
286
258
      != GNUTLS_E_SUCCESS) {
287
 
    fprintf (stderr, "GnuTLS global_init: %s\n",
288
 
             safer_gnutls_strerror(ret));
 
259
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
289
260
    return -1;
290
261
  }
291
 
  
 
262
 
292
263
  if (debug){
293
 
    /* "Use a log level over 10 to enable all debugging options."
294
 
     * - GnuTLS manual
295
 
     */
296
264
    gnutls_global_set_log_level(11);
297
265
    gnutls_global_set_log_function(debuggnutls);
298
266
  }
299
267
  
300
 
  /* OpenPGP credentials */
301
 
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
 
268
  /* openpgp credentials */
 
269
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
302
270
      != GNUTLS_E_SUCCESS) {
303
 
    fprintf (stderr, "GnuTLS memory error: %s\n",
 
271
    fprintf (stderr, "memory error: %s\n",
304
272
             safer_gnutls_strerror(ret));
305
273
    return -1;
306
274
  }
307
275
  
308
276
  if(debug){
309
277
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
310
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
311
 
            seckeyfile);
 
278
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
 
279
            KEYFILE);
312
280
  }
313
281
  
314
282
  ret = gnutls_certificate_set_openpgp_key_file
315
 
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
283
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
316
284
  if (ret != GNUTLS_E_SUCCESS) {
317
 
    fprintf(stderr,
318
 
            "Error[%d] while reading the OpenPGP key pair ('%s',"
319
 
            " '%s')\n", ret, pubkeyfile, seckeyfile);
320
 
    fprintf(stdout, "The GnuTLS error is: %s\n",
 
285
    fprintf
 
286
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
287
       " '%s')\n",
 
288
       ret, CERTFILE, KEYFILE);
 
289
    fprintf(stdout, "The Error is: %s\n",
321
290
            safer_gnutls_strerror(ret));
322
291
    return -1;
323
292
  }
324
293
  
325
 
  /* GnuTLS server initialization */
326
 
  ret = gnutls_dh_params_init(dh_params);
327
 
  if (ret != GNUTLS_E_SUCCESS) {
328
 
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
329
 
             " %s\n", safer_gnutls_strerror(ret));
330
 
    return -1;
331
 
  }
332
 
  ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits);
333
 
  if (ret != GNUTLS_E_SUCCESS) {
334
 
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
335
 
             safer_gnutls_strerror(ret));
336
 
    return -1;
337
 
  }
338
 
  
339
 
  gnutls_certificate_set_dh_params(mc->cred, *dh_params);
340
 
  
341
 
  /* GnuTLS session creation */
342
 
  ret = gnutls_init(session, GNUTLS_SERVER);
343
 
  if (ret != GNUTLS_E_SUCCESS){
 
294
  //GnuTLS server initialization
 
295
  if ((ret = gnutls_dh_params_init (&es->dh_params))
 
296
      != GNUTLS_E_SUCCESS) {
 
297
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
 
298
             safer_gnutls_strerror(ret));
 
299
    return -1;
 
300
  }
 
301
  
 
302
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
 
303
      != GNUTLS_E_SUCCESS) {
 
304
    fprintf (stderr, "Error in prime generation: %s\n",
 
305
             safer_gnutls_strerror(ret));
 
306
    return -1;
 
307
  }
 
308
  
 
309
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
 
310
  
 
311
  // GnuTLS session creation
 
312
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
 
313
      != GNUTLS_E_SUCCESS){
344
314
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
345
315
            safer_gnutls_strerror(ret));
346
316
  }
347
317
  
348
 
  {
349
 
    const char *err;
350
 
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
351
 
    if (ret != GNUTLS_E_SUCCESS) {
352
 
      fprintf(stderr, "Syntax error at: %s\n", err);
353
 
      fprintf(stderr, "GnuTLS error: %s\n",
354
 
              safer_gnutls_strerror(ret));
355
 
      return -1;
356
 
    }
 
318
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
 
319
      != GNUTLS_E_SUCCESS) {
 
320
    fprintf(stderr, "Syntax error at: %s\n", err);
 
321
    fprintf(stderr, "GnuTLS error: %s\n",
 
322
            safer_gnutls_strerror(ret));
 
323
    return -1;
357
324
  }
358
325
  
359
 
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
360
 
                               mc->cred);
361
 
  if (ret != GNUTLS_E_SUCCESS) {
362
 
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
 
326
  if ((ret = gnutls_credentials_set
 
327
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
 
328
      != GNUTLS_E_SUCCESS) {
 
329
    fprintf(stderr, "Error setting a credentials set: %s\n",
363
330
            safer_gnutls_strerror(ret));
364
331
    return -1;
365
332
  }
366
333
  
367
334
  /* ignore client certificate if any. */
368
 
  gnutls_certificate_server_set_request (*session,
 
335
  gnutls_certificate_server_set_request (es->session,
369
336
                                         GNUTLS_CERT_IGNORE);
370
337
  
371
 
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
 
338
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
372
339
  
373
340
  return 0;
374
341
}
375
342
 
376
 
/* Avahi log function callback */
377
 
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
378
 
                      __attribute__((unused)) const char *txt){}
 
343
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
344
               __attribute__((unused)) const char *txt){}
379
345
 
380
 
/* Called when a Mandos server is found */
381
 
static int start_mandos_communication(const char *ip, uint16_t port,
382
 
                                      AvahiIfIndex if_index,
383
 
                                      mandos_context *mc){
 
346
int start_mandos_communication(const char *ip, uint16_t port,
 
347
                               unsigned int if_index){
384
348
  int ret, tcp_sd;
385
349
  struct sockaddr_in6 to;
 
350
  encrypted_session es;
386
351
  char *buffer = NULL;
387
352
  char *decrypted_buffer;
388
353
  size_t buffer_length = 0;
391
356
  size_t written = 0;
392
357
  int retval = 0;
393
358
  char interface[IF_NAMESIZE];
394
 
  gnutls_session_t session;
395
 
  gnutls_dh_params_t dh_params;
396
 
  
397
 
  ret = initgnutls (mc, &session, &dh_params);
398
 
  if (ret != 0){
399
 
    return -1;
400
 
  }
401
359
  
402
360
  if(debug){
403
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
404
 
            ip, port);
 
361
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
405
362
  }
406
363
  
407
364
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
409
366
    perror("socket");
410
367
    return -1;
411
368
  }
412
 
 
413
 
  if(debug){
414
 
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
369
  
 
370
  if(if_indextoname(if_index, interface) == NULL){
 
371
    if(debug){
415
372
      perror("if_indextoname");
416
 
      return -1;
417
373
    }
 
374
    return -1;
 
375
  }
 
376
  
 
377
  if(debug){
418
378
    fprintf(stderr, "Binding to interface %s\n", interface);
419
379
  }
420
380
  
421
381
  memset(&to,0,sizeof(to));     /* Spurious warning */
422
382
  to.sin6_family = AF_INET6;
423
 
  /* It would be nice to have a way to detect if we were passed an
424
 
     IPv4 address here.   Now we assume an IPv6 address. */
425
383
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
426
384
  if (ret < 0 ){
427
385
    perror("inet_pton");
428
386
    return -1;
429
 
  }
 
387
  }  
430
388
  if(ret == 0){
431
389
    fprintf(stderr, "Bad address: %s\n", ip);
432
390
    return -1;
436
394
  to.sin6_scope_id = (uint32_t)if_index;
437
395
  
438
396
  if(debug){
439
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
440
 
    char addrstr[INET6_ADDRSTRLEN] = "";
441
 
    if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
442
 
                 sizeof(addrstr)) == NULL){
443
 
      perror("inet_ntop");
444
 
    } else {
445
 
      if(strcmp(addrstr, ip) != 0){
446
 
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
447
 
      }
448
 
    }
 
397
    fprintf(stderr, "Connection to: %s\n", ip);
449
398
  }
450
399
  
451
400
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
454
403
    return -1;
455
404
  }
456
405
  
 
406
  ret = initgnutls (&es);
 
407
  if (ret != 0){
 
408
    retval = -1;
 
409
    return -1;
 
410
  }
 
411
  
 
412
  gnutls_transport_set_ptr (es.session,
 
413
                            (gnutls_transport_ptr_t) tcp_sd);
 
414
  
457
415
  if(debug){
458
416
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
459
417
  }
460
418
  
461
 
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
462
 
  
463
 
  ret = gnutls_handshake (session);
 
419
  ret = gnutls_handshake (es.session);
464
420
  
465
421
  if (ret != GNUTLS_E_SUCCESS){
466
422
    if(debug){
467
 
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
423
      fprintf(stderr, "\n*** Handshake failed ***\n");
468
424
      gnutls_perror (ret);
469
425
    }
470
426
    retval = -1;
471
 
    goto mandos_end;
 
427
    goto exit;
472
428
  }
473
429
  
474
 
  /* Read OpenPGP packet that contains the wanted password */
 
430
  //Retrieve OpenPGP packet that contains the wanted password
475
431
  
476
432
  if(debug){
477
433
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
483
439
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
484
440
      if (buffer == NULL){
485
441
        perror("realloc");
486
 
        retval = -1;
487
 
        goto mandos_end;
 
442
        goto exit;
488
443
      }
489
444
      buffer_capacity += BUFFER_SIZE;
490
445
    }
491
446
    
492
 
    ret = gnutls_record_recv(session, buffer+buffer_length,
493
 
                             BUFFER_SIZE);
 
447
    ret = gnutls_record_recv
 
448
      (es.session, buffer+buffer_length, BUFFER_SIZE);
494
449
    if (ret == 0){
495
450
      break;
496
451
    }
500
455
      case GNUTLS_E_AGAIN:
501
456
        break;
502
457
      case GNUTLS_E_REHANDSHAKE:
503
 
        ret = gnutls_handshake (session);
 
458
        ret = gnutls_handshake (es.session);
504
459
        if (ret < 0){
505
 
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
460
          fprintf(stderr, "\n*** Handshake failed ***\n");
506
461
          gnutls_perror (ret);
507
462
          retval = -1;
508
 
          goto mandos_end;
 
463
          goto exit;
509
464
        }
510
465
        break;
511
466
      default:
512
467
        fprintf(stderr, "Unknown error while reading data from"
513
 
                " encrypted session with Mandos server\n");
 
468
                " encrypted session with mandos server\n");
514
469
        retval = -1;
515
 
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
516
 
        goto mandos_end;
 
470
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
471
        goto exit;
517
472
      }
518
473
    } else {
519
474
      buffer_length += (size_t) ret;
520
475
    }
521
476
  }
522
477
  
523
 
  if(debug){
524
 
    fprintf(stderr, "Closing TLS session\n");
525
 
  }
526
 
  
527
 
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
528
 
  
529
478
  if (buffer_length > 0){
530
479
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
531
480
                                               buffer_length,
532
481
                                               &decrypted_buffer,
533
 
                                               keydir);
 
482
                                               CERT_ROOT);
534
483
    if (decrypted_buffer_size >= 0){
535
 
      while(written < (size_t) decrypted_buffer_size){
 
484
      while(written < decrypted_buffer_size){
536
485
        ret = (int)fwrite (decrypted_buffer + written, 1,
537
486
                           (size_t)decrypted_buffer_size - written,
538
487
                           stdout);
551
500
      retval = -1;
552
501
    }
553
502
  }
554
 
  
555
 
  /* Shutdown procedure */
556
 
  
557
 
 mandos_end:
 
503
 
 
504
  //shutdown procedure
 
505
 
 
506
  if(debug){
 
507
    fprintf(stderr, "Closing TLS session\n");
 
508
  }
 
509
 
558
510
  free(buffer);
 
511
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
512
 exit:
559
513
  close(tcp_sd);
560
 
  gnutls_deinit (session);
561
 
  gnutls_certificate_free_credentials (mc->cred);
 
514
  gnutls_deinit (es.session);
 
515
  gnutls_certificate_free_credentials (es.cred);
562
516
  gnutls_global_deinit ();
563
517
  return retval;
564
518
}
565
519
 
566
 
static void resolve_callback(AvahiSServiceResolver *r,
567
 
                             AvahiIfIndex interface,
568
 
                             AVAHI_GCC_UNUSED AvahiProtocol protocol,
569
 
                             AvahiResolverEvent event,
570
 
                             const char *name,
571
 
                             const char *type,
572
 
                             const char *domain,
573
 
                             const char *host_name,
574
 
                             const AvahiAddress *address,
575
 
                             uint16_t port,
576
 
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
577
 
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
578
 
                             flags,
579
 
                             void* userdata) {
580
 
  mandos_context *mc = userdata;
 
520
static AvahiSimplePoll *simple_poll = NULL;
 
521
static AvahiServer *server = NULL;
 
522
 
 
523
static void resolve_callback(
 
524
    AvahiSServiceResolver *r,
 
525
    AvahiIfIndex interface,
 
526
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
527
    AvahiResolverEvent event,
 
528
    const char *name,
 
529
    const char *type,
 
530
    const char *domain,
 
531
    const char *host_name,
 
532
    const AvahiAddress *address,
 
533
    uint16_t port,
 
534
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
535
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
536
    AVAHI_GCC_UNUSED void* userdata) {
 
537
    
581
538
  assert(r);                    /* Spurious warning */
582
539
  
583
540
  /* Called whenever a service has been resolved successfully or
586
543
  switch (event) {
587
544
  default:
588
545
  case AVAHI_RESOLVER_FAILURE:
589
 
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
590
 
            " of type '%s' in domain '%s': %s\n", name, type, domain,
591
 
            avahi_strerror(avahi_server_errno(mc->server)));
 
546
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
 
547
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
548
            avahi_strerror(avahi_server_errno(server)));
592
549
    break;
593
550
    
594
551
  case AVAHI_RESOLVER_FOUND:
596
553
      char ip[AVAHI_ADDRESS_STR_MAX];
597
554
      avahi_address_snprint(ip, sizeof(ip), address);
598
555
      if(debug){
599
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %d) on"
600
 
                " port %d\n", name, host_name, ip, interface, port);
 
556
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
 
557
                " port %d\n", name, host_name, ip, port);
601
558
      }
602
 
      int ret = start_mandos_communication(ip, port, interface, mc);
 
559
      int ret = start_mandos_communication(ip, port,
 
560
                                           (unsigned int) interface);
603
561
      if (ret == 0){
604
562
        exit(EXIT_SUCCESS);
605
563
      }
608
566
  avahi_s_service_resolver_free(r);
609
567
}
610
568
 
611
 
static void browse_callback( AvahiSServiceBrowser *b,
612
 
                             AvahiIfIndex interface,
613
 
                             AvahiProtocol protocol,
614
 
                             AvahiBrowserEvent event,
615
 
                             const char *name,
616
 
                             const char *type,
617
 
                             const char *domain,
618
 
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
619
 
                             flags,
620
 
                             void* userdata) {
621
 
  mandos_context *mc = userdata;
622
 
  assert(b);                    /* Spurious warning */
623
 
  
624
 
  /* Called whenever a new services becomes available on the LAN or
625
 
     is removed from the LAN */
626
 
  
627
 
  switch (event) {
628
 
  default:
629
 
  case AVAHI_BROWSER_FAILURE:
630
 
    
631
 
    fprintf(stderr, "(Avahi browser) %s\n",
632
 
            avahi_strerror(avahi_server_errno(mc->server)));
633
 
    avahi_simple_poll_quit(mc->simple_poll);
634
 
    return;
635
 
    
636
 
  case AVAHI_BROWSER_NEW:
637
 
    /* We ignore the returned Avahi resolver object. In the callback
638
 
       function we free it. If the Avahi server is terminated before
639
 
       the callback function is called the Avahi server will free the
640
 
       resolver for us. */
641
 
    
642
 
    if (!(avahi_s_service_resolver_new(mc->server, interface,
643
 
                                       protocol, name, type, domain,
644
 
                                       AVAHI_PROTO_INET6, 0,
645
 
                                       resolve_callback, mc)))
646
 
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
647
 
              name, avahi_strerror(avahi_server_errno(mc->server)));
648
 
    break;
649
 
    
650
 
  case AVAHI_BROWSER_REMOVE:
651
 
    break;
652
 
    
653
 
  case AVAHI_BROWSER_ALL_FOR_NOW:
654
 
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
655
 
    if(debug){
656
 
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
569
static void browse_callback(
 
570
    AvahiSServiceBrowser *b,
 
571
    AvahiIfIndex interface,
 
572
    AvahiProtocol protocol,
 
573
    AvahiBrowserEvent event,
 
574
    const char *name,
 
575
    const char *type,
 
576
    const char *domain,
 
577
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
578
    void* userdata) {
 
579
    
 
580
    AvahiServer *s = userdata;
 
581
    assert(b);                  /* Spurious warning */
 
582
    
 
583
    /* Called whenever a new services becomes available on the LAN or
 
584
       is removed from the LAN */
 
585
    
 
586
    switch (event) {
 
587
    default:
 
588
    case AVAHI_BROWSER_FAILURE:
 
589
      
 
590
      fprintf(stderr, "(Browser) %s\n",
 
591
              avahi_strerror(avahi_server_errno(server)));
 
592
      avahi_simple_poll_quit(simple_poll);
 
593
      return;
 
594
      
 
595
    case AVAHI_BROWSER_NEW:
 
596
      /* We ignore the returned resolver object. In the callback
 
597
         function we free it. If the server is terminated before
 
598
         the callback function is called the server will free
 
599
         the resolver for us. */
 
600
      
 
601
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
 
602
                                         type, domain,
 
603
                                         AVAHI_PROTO_INET6, 0,
 
604
                                         resolve_callback, s)))
 
605
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
 
606
                avahi_strerror(avahi_server_errno(s)));
 
607
      break;
 
608
      
 
609
    case AVAHI_BROWSER_REMOVE:
 
610
      break;
 
611
      
 
612
    case AVAHI_BROWSER_ALL_FOR_NOW:
 
613
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
614
      break;
657
615
    }
658
 
    break;
659
 
  }
660
 
}
661
 
 
662
 
/* Combines file name and path and returns the malloced new
663
 
   string. some sane checks could/should be added */
664
 
static const char *combinepath(const char *first, const char *second){
665
 
  size_t f_len = strlen(first);
666
 
  size_t s_len = strlen(second);
667
 
  char *tmp = malloc(f_len + s_len + 2);
668
 
  if (tmp == NULL){
669
 
    return NULL;
670
 
  }
671
 
  if(f_len > 0){
672
 
    memcpy(tmp, first, f_len);  /* Spurious warning */
673
 
  }
674
 
  tmp[f_len] = '/';
675
 
  if(s_len > 0){
676
 
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
677
 
  }
678
 
  tmp[f_len + 1 + s_len] = '\0';
679
 
  return tmp;
680
 
}
681
 
 
682
 
 
683
 
int main(int argc, char *argv[]){
 
616
}
 
617
 
 
618
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
 
619
    AvahiServerConfig config;
684
620
    AvahiSServiceBrowser *sb = NULL;
685
621
    int error;
686
622
    int ret;
687
 
    int exitcode = EXIT_SUCCESS;
 
623
    int returncode = EXIT_SUCCESS;
688
624
    const char *interface = "eth0";
689
 
    struct ifreq network;
690
 
    int sd;
691
 
    char *connect_to = NULL;
692
 
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
693
 
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
694
 
                          .dh_bits = 1024, .priority = "SECURE256"};
695
 
    
696
 
    {
697
 
      /* Temporary int to get the address of for getopt_long */
698
 
      int debug_int = debug ? 1 : 0;
699
 
      while (true){
700
 
        struct option long_options[] = {
701
 
          {"debug", no_argument, &debug_int, 1},
702
 
          {"connect", required_argument, NULL, 'c'},
703
 
          {"interface", required_argument, NULL, 'i'},
704
 
          {"keydir", required_argument, NULL, 'd'},
705
 
          {"seckey", required_argument, NULL, 's'},
706
 
          {"pubkey", required_argument, NULL, 'p'},
707
 
          {"dh-bits", required_argument, NULL, 'D'},
708
 
          {"priority", required_argument, NULL, 'P'},
709
 
          {0, 0, 0, 0} };
710
 
      
711
 
        int option_index = 0;
712
 
        ret = getopt_long (argc, argv, "i:", long_options,
713
 
                           &option_index);
714
 
      
715
 
        if (ret == -1){
716
 
          break;
717
 
        }
718
 
      
719
 
        switch(ret){
720
 
        case 0:
721
 
          break;
722
 
        case 'i':
723
 
          interface = optarg;
724
 
          break;
725
 
        case 'c':
726
 
          connect_to = optarg;
727
 
          break;
728
 
        case 'd':
729
 
          keydir = optarg;
730
 
          break;
731
 
        case 'p':
732
 
          pubkeyfile = optarg;
733
 
          break;
734
 
        case 's':
735
 
          seckeyfile = optarg;
736
 
          break;
737
 
        case 'D':
738
 
          errno = 0;
739
 
          mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
740
 
          if (errno){
741
 
            perror("strtol");
742
 
            exit(EXIT_FAILURE);
743
 
          }
744
 
          break;
745
 
        case 'P':
746
 
          mc.priority = optarg;
747
 
          break;
748
 
        case '?':
749
 
        default:
750
 
          /* getopt_long() has already printed a message about the
751
 
             unrcognized option, so just exit. */
752
 
          exit(EXIT_FAILURE);
753
 
        }
754
 
      }
755
 
      /* Set the global debug flag from the temporary int */
756
 
      debug = debug_int ? true : false;
757
 
    }
758
 
    
759
 
    pubkeyfile = combinepath(keydir, pubkeyfile);
760
 
    if (pubkeyfile == NULL){
761
 
      perror("combinepath");
762
 
      exitcode = EXIT_FAILURE;
763
 
      goto end;
764
 
    }
765
 
    
766
 
    seckeyfile = combinepath(keydir, seckeyfile);
767
 
    if (seckeyfile == NULL){
768
 
      perror("combinepath");
769
 
      goto end;
770
 
    }
771
 
    
772
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
773
 
    if(if_index == 0){
774
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
775
 
      exit(EXIT_FAILURE);
776
 
    }
777
 
    
778
 
    if(connect_to != NULL){
779
 
      /* Connect directly, do not use Zeroconf */
780
 
      /* (Mainly meant for debugging) */
781
 
      char *address = strrchr(connect_to, ':');
782
 
      if(address == NULL){
783
 
        fprintf(stderr, "No colon in address\n");
784
 
        exit(EXIT_FAILURE);
785
 
      }
786
 
      errno = 0;
787
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
788
 
      if(errno){
789
 
        perror("Bad port number");
790
 
        exit(EXIT_FAILURE);
791
 
      }
792
 
      *address = '\0';
793
 
      address = connect_to;
794
 
      ret = start_mandos_communication(address, port, if_index, &mc);
795
 
      if(ret < 0){
796
 
        exit(EXIT_FAILURE);
797
 
      } else {
798
 
        exit(EXIT_SUCCESS);
799
 
      }
800
 
    }
801
 
    
802
 
    /* If the interface is down, bring it up */
803
 
    {
804
 
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
805
 
      if(sd < 0) {
806
 
        perror("socket");
807
 
        exitcode = EXIT_FAILURE;
808
 
        goto end;
809
 
      }
810
 
      strcpy(network.ifr_name, interface); /* Spurious warning */
811
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
812
 
      if(ret == -1){
813
 
        perror("ioctl SIOCGIFFLAGS");
814
 
        exitcode = EXIT_FAILURE;
815
 
        goto end;
816
 
      }
817
 
      if((network.ifr_flags & IFF_UP) == 0){
818
 
        network.ifr_flags |= IFF_UP;
819
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
820
 
        if(ret == -1){
821
 
          perror("ioctl SIOCSIFFLAGS");
822
 
          exitcode = EXIT_FAILURE;
823
 
          goto end;
824
 
        }
825
 
      }
826
 
      close(sd);
 
625
    
 
626
    while (true){
 
627
      static struct option long_options[] = {
 
628
        {"debug", no_argument, (int *)&debug, 1},
 
629
        {"interface", required_argument, 0, 'i'},
 
630
        {0, 0, 0, 0} };
 
631
      
 
632
      int option_index = 0;
 
633
      ret = getopt_long (argc, argv, "i:", long_options,
 
634
                         &option_index);
 
635
      
 
636
      if (ret == -1){
 
637
        break;
 
638
      }
 
639
      
 
640
      switch(ret){
 
641
      case 0:
 
642
        break;
 
643
      case 'i':
 
644
        interface = optarg;
 
645
        break;
 
646
      default:
 
647
        exit(EXIT_FAILURE);
 
648
      }
827
649
    }
828
650
    
829
651
    if (not debug){
830
652
      avahi_set_log_function(empty_log);
831
653
    }
832
654
    
833
 
    /* Initialize the pseudo-RNG for Avahi */
 
655
    /* Initialize the psuedo-RNG */
834
656
    srand((unsigned int) time(NULL));
835
 
    
836
 
    /* Allocate main Avahi loop object */
837
 
    mc.simple_poll = avahi_simple_poll_new();
838
 
    if (mc.simple_poll == NULL) {
839
 
        fprintf(stderr, "Avahi: Failed to create simple poll"
840
 
                " object.\n");
841
 
        exitcode = EXIT_FAILURE;
842
 
        goto end;
843
 
    }
844
 
 
845
 
    {
846
 
      AvahiServerConfig config;
847
 
      /* Do not publish any local Zeroconf records */
848
 
      avahi_server_config_init(&config);
849
 
      config.publish_hinfo = 0;
850
 
      config.publish_addresses = 0;
851
 
      config.publish_workstation = 0;
852
 
      config.publish_domain = 0;
853
 
 
854
 
      /* Allocate a new server */
855
 
      mc.server = avahi_server_new(avahi_simple_poll_get
856
 
                                   (mc.simple_poll), &config, NULL,
857
 
                                   NULL, &error);
858
 
    
859
 
      /* Free the Avahi configuration data */
860
 
      avahi_server_config_free(&config);
861
 
    }
862
 
    
863
 
    /* Check if creating the Avahi server object succeeded */
864
 
    if (mc.server == NULL) {
865
 
        fprintf(stderr, "Failed to create Avahi server: %s\n",
 
657
 
 
658
    /* Allocate main loop object */
 
659
    if (!(simple_poll = avahi_simple_poll_new())) {
 
660
        fprintf(stderr, "Failed to create simple poll object.\n");
 
661
        
 
662
        goto exit;
 
663
    }
 
664
 
 
665
    /* Do not publish any local records */
 
666
    avahi_server_config_init(&config);
 
667
    config.publish_hinfo = 0;
 
668
    config.publish_addresses = 0;
 
669
    config.publish_workstation = 0;
 
670
    config.publish_domain = 0;
 
671
 
 
672
    /* Allocate a new server */
 
673
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
674
                              &config, NULL, NULL, &error);
 
675
 
 
676
    /* Free the configuration data */
 
677
    avahi_server_config_free(&config);
 
678
 
 
679
    /* Check if creating the server object succeeded */
 
680
    if (!server) {
 
681
        fprintf(stderr, "Failed to create server: %s\n",
866
682
                avahi_strerror(error));
867
 
        exitcode = EXIT_FAILURE;
868
 
        goto end;
 
683
        returncode = EXIT_FAILURE;
 
684
        goto exit;
869
685
    }
870
686
    
871
 
    /* Create the Avahi service browser */
872
 
    sb = avahi_s_service_browser_new(mc.server, if_index,
 
687
    /* Create the service browser */
 
688
    sb = avahi_s_service_browser_new(server,
 
689
                                     (AvahiIfIndex)
 
690
                                     if_nametoindex(interface),
873
691
                                     AVAHI_PROTO_INET6,
874
692
                                     "_mandos._tcp", NULL, 0,
875
 
                                     browse_callback, &mc);
876
 
    if (sb == NULL) {
 
693
                                     browse_callback, server);
 
694
    if (!sb) {
877
695
        fprintf(stderr, "Failed to create service browser: %s\n",
878
 
                avahi_strerror(avahi_server_errno(mc.server)));
879
 
        exitcode = EXIT_FAILURE;
880
 
        goto end;
 
696
                avahi_strerror(avahi_server_errno(server)));
 
697
        returncode = EXIT_FAILURE;
 
698
        goto exit;
881
699
    }
882
700
    
883
701
    /* Run the main loop */
884
702
 
885
703
    if (debug){
886
 
      fprintf(stderr, "Starting Avahi loop search\n");
 
704
      fprintf(stderr, "Starting avahi loop search\n");
887
705
    }
888
706
    
889
 
    avahi_simple_poll_loop(mc.simple_poll);
 
707
    avahi_simple_poll_loop(simple_poll);
890
708
    
891
 
 end:
 
709
 exit:
892
710
 
893
711
    if (debug){
894
712
      fprintf(stderr, "%s exiting\n", argv[0]);
895
713
    }
896
714
    
897
715
    /* Cleanup things */
898
 
    if (sb != NULL)
 
716
    if (sb)
899
717
        avahi_s_service_browser_free(sb);
900
718
    
901
 
    if (mc.server != NULL)
902
 
        avahi_server_free(mc.server);
903
 
 
904
 
    if (mc.simple_poll != NULL)
905
 
        avahi_simple_poll_free(mc.simple_poll);
906
 
    free(pubkeyfile);
907
 
    free(seckeyfile);
908
 
    
909
 
    return exitcode;
 
719
    if (server)
 
720
        avahi_server_free(server);
 
721
 
 
722
    if (simple_poll)
 
723
        avahi_simple_poll_free(simple_poll);
 
724
 
 
725
    return returncode;
910
726
}