/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: Teddy Hogeborn
  • Date: 2008-07-21 02:33:00 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080721023300-c4t0cq7sxit973py
* plugins.d/Makefile: Removed

* plugins.d/mandosclient.c (start_mandos_communcation): Bug fix: write
                                                        server IP
                                                        address to
                                                        "to" struct.

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