/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-29 03:35:39 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080729033539-08zecoj3jwlkpjhw
* server.conf: New file.

* mandos-clients.conf: Renamed to clients.conf.

* Makefile (FORTIFY): New.
  (CFLAGS): Include $(FORTIFY).

* plugins.d/mandosclient.c (main): New "if_index" variable.  Bug fix:
                                   check if interface exists.  New
                                   "--connect" option.

* server.py (serviceInterface): Removed; replaced by
                                "AvahiService.interface".  All users
                                changed.
  (AvahiError, AvahiServiceError, AvahiGroupError): New exception
                                                    classes.
  (AvahiService): New class.
  (serviceName): Removed; replaced by "AvahiService.name".  All users
                 changed.
  (serviceType): Removed; replaced by "AvahiService.type".  All users
                 changed.
  (servicePort): Removed; replaced by "AvahiService.port".  All users
                 changed.
  (serviceTXT): Removed; replaced by "AvahiService.TXT".  All users
                changed.
  (domain): Removed; replaced by "AvahiService.domain".  All users
            changed.
  (host): Removed; replaced by "AvahiService.host".  All users
          changed.
  (rename_count): Removed; replaced by "AvahiService.rename_count" and
                 "AvahiService.max_renames".  All users changed.
  (Client.__init__): If no secret or secfile, raise TypeError instead
                     of RuntimeError.
  (Client.last_seen): Renamed to "Client.last_checked_ok".  All users
                      changed.
  (Client.stop, Client.stop_checker): Use "getattr" with default value
                                      instead of "hasattr".
  (Client.still_valid): Removed "now" argument.
  (Client.handle): Separate the "no client found" and "client invalid"
                   cases for clearer code.
  (IPv6_TCPServer.__init__): "options" argument replaced by
                             "settings".  All callers changed.
  (IPv6_TCPServer.options): Replaced by "IPv6_TCPServer.settings".
                            All users changed.
  (IPv6_TCPServer.server_bind): Use getattr instead of hasattr.
  (add_service): Removed; replaced by "AvahiService.add".  All callers
                 changed.
  (remove_service): Removed; replaced by "AvahiService.remove".  All
                    callers changed.
  (entry_group_state_changed): On entry group collision, call the new
                               AvahiService.rename method.  Raise
                               AvahiGroupError on group error.
  (if_nametoindex): Use ctypes.utils.find_library to locate the C
                    library.  Cache the result.  Loop on EINTR.
  (daemon): Use os.path.devnull to locate "/dev/null".
  (killme): Removed.  All callers changed to do "sys.exit()" instead,
            except where stated otherwise.
  (main): Removed "exitstatus".  Removed all default values from all
          non-bool options.  New option "--configdir".  New variables
          "server_defaults" and "server_settings", read from
          "%(configdir)s/server.conf".  Let any supplied command line
          options override server settings.   Variable "defaults"
          renamed to "client_defaults", which is read from
          "clients.conf" instead of "mandos-clients.conf".  New global
          AvahiService object "service" replaces old global variables.
          Catch AvahiError and exit with error if caught.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id$ */
2
 
 
3
 
/* PLEASE NOTE *
4
 
 * This file demonstrates how to use Avahi's core API, this is
5
 
 * the embeddable mDNS stack for embedded applications.
 
1
/*  -*- coding: utf-8 -*- */
 
2
/*
 
3
 * Mandos client - get and decrypt data from a Mandos server
6
4
 *
7
 
 * End user applications should *not* use this API and should use
8
 
 * the D-Bus or C APIs, please see
9
 
 * client-browse-services.c and glib-integration.c
10
 
 * 
11
 
 * I repeat, you probably do *not* want to use this example.
 
5
 * This program is partly derived from an example program for an Avahi
 
6
 * service browser, downloaded from
 
7
 * <http://avahi.org/browser/examples/core-browse-services.c>.  This
 
8
 * includes the following functions: "resolve_callback",
 
9
 * "browse_callback", and parts of "main".
 
10
 * 
 
11
 * Everything else is
 
12
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
13
 * 
 
14
 * This program is free software: you can redistribute it and/or
 
15
 * modify it under the terms of the GNU General Public License as
 
16
 * published by the Free Software Foundation, either version 3 of the
 
17
 * License, or (at your option) any later version.
 
18
 * 
 
19
 * This program is distributed in the hope that it will be useful, but
 
20
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
22
 * General Public License for more details.
 
23
 * 
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program.  If not, see
 
26
 * <http://www.gnu.org/licenses/>.
 
27
 * 
 
28
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
29
 * <https://www.fukt.bsnet.se/~teddy/>.
12
30
 */
13
31
 
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
/* Needed by GPGME, specifically gpgme_data_seek() */
33
33
#define _LARGEFILE_SOURCE
34
34
#define _FILE_OFFSET_BITS 64
35
35
 
47
47
#include <avahi-common/error.h>
48
48
 
49
49
//mandos client part
50
 
#include <sys/types.h>          /* socket(), setsockopt(), inet_pton() */
51
 
#include <sys/socket.h>         /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */
52
 
#include <gnutls/gnutls.h>      /* ALL GNUTLS STUFF */
53
 
#include <gnutls/openpgp.h>     /* gnutls with openpgp stuff */
 
50
#include <sys/types.h>          /* socket(), inet_pton() */
 
51
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
52
                                   struct in6_addr, inet_pton() */
 
53
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
 
54
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
54
55
 
55
56
#include <unistd.h>             /* close() */
56
57
#include <netinet/in.h>
63
64
#include <errno.h>              /* perror() */
64
65
#include <gpgme.h>
65
66
 
 
67
// getopt long
 
68
#include <getopt.h>
66
69
 
67
70
#ifndef CERT_ROOT
68
71
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
72
75
#define BUFFER_SIZE 256
73
76
#define DH_BITS 1024
74
77
 
 
78
bool debug = false;
 
79
 
75
80
typedef struct {
76
81
  gnutls_session_t session;
77
82
  gnutls_certificate_credentials_t cred;
79
84
} encrypted_session;
80
85
 
81
86
 
82
 
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
 
87
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
88
                            char **new_packet, const char *homedir){
83
89
  gpgme_data_t dh_crypto, dh_plain;
84
90
  gpgme_ctx_t ctx;
85
91
  gpgme_error_t rc;
86
92
  ssize_t ret;
87
 
  size_t new_packet_capacity = 0;
88
 
  size_t new_packet_length = 0;
 
93
  ssize_t new_packet_capacity = 0;
 
94
  ssize_t new_packet_length = 0;
89
95
  gpgme_engine_info_t engine_info;
90
96
 
 
97
  if (debug){
 
98
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
99
  }
 
100
  
91
101
  /* Init GPGME */
92
102
  gpgme_check_version(NULL);
93
103
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
136
146
    return -1;
137
147
  }
138
148
  
139
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
149
  /* Decrypt data from the FILE pointer to the plaintext data
 
150
     buffer */
140
151
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
141
152
  if (rc != GPG_ERR_NO_ERROR){
142
153
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
143
154
            gpgme_strsource(rc), gpgme_strerror(rc));
144
155
    return -1;
145
156
  }
 
157
 
 
158
  if(debug){
 
159
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
 
160
  }
 
161
 
 
162
  if (debug){
 
163
    gpgme_decrypt_result_t result;
 
164
    result = gpgme_op_decrypt_result(ctx);
 
165
    if (result == NULL){
 
166
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
167
    } else {
 
168
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
169
              result->unsupported_algorithm);
 
170
      fprintf(stderr, "Wrong key usage: %d\n",
 
171
              result->wrong_key_usage);
 
172
      if(result->file_name != NULL){
 
173
        fprintf(stderr, "File name: %s\n", result->file_name);
 
174
      }
 
175
      gpgme_recipient_t recipient;
 
176
      recipient = result->recipients;
 
177
      if(recipient){
 
178
        while(recipient != NULL){
 
179
          fprintf(stderr, "Public key algorithm: %s\n",
 
180
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
181
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
182
          fprintf(stderr, "Secret key available: %s\n",
 
183
                  recipient->status == GPG_ERR_NO_SECKEY
 
184
                  ? "No" : "Yes");
 
185
          recipient = recipient->next;
 
186
        }
 
187
      }
 
188
    }
 
189
  }
146
190
  
147
 
/*   gpgme_decrypt_result_t result; */
148
 
/*   result = gpgme_op_decrypt_result(ctx); */
149
 
/*   fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm); */
150
 
/*   fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage); */
151
 
/*   if(result->file_name != NULL){ */
152
 
/*     fprintf(stderr, "File name: %s\n", result->file_name); */
153
 
/*   } */
154
 
/*   gpgme_recipient_t recipient; */
155
 
/*   recipient = result->recipients; */
156
 
/*   if(recipient){ */
157
 
/*     while(recipient != NULL){ */
158
 
/*       fprintf(stderr, "Public key algorithm: %s\n", */
159
 
/*            gpgme_pubkey_algo_name(recipient->pubkey_algo)); */
160
 
/*       fprintf(stderr, "Key ID: %s\n", recipient->keyid); */
161
 
/*       fprintf(stderr, "Secret key available: %s\n", */
162
 
/*            recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes"); */
163
 
/*       recipient = recipient->next; */
164
 
/*     } */
165
 
/*   } */
166
 
 
167
191
  /* Delete the GPGME FILE pointer cryptotext data buffer */
168
192
  gpgme_data_release(dh_crypto);
169
193
  
170
194
  /* Seek back to the beginning of the GPGME plaintext data buffer */
171
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
195
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
172
196
 
173
197
  *new_packet = 0;
174
198
  while(true){
175
199
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
176
 
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
 
200
      *new_packet = realloc(*new_packet,
 
201
                            (unsigned int)new_packet_capacity
 
202
                            + BUFFER_SIZE);
177
203
      if (*new_packet == NULL){
178
204
        perror("realloc");
179
205
        return -1;
181
207
      new_packet_capacity += BUFFER_SIZE;
182
208
    }
183
209
    
184
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
 
210
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
211
                          BUFFER_SIZE);
185
212
    /* Print the data, if any */
186
213
    if (ret == 0){
187
 
      /* If password is empty, then a incorrect error will be printed */
188
214
      break;
189
215
    }
190
216
    if(ret < 0){
194
220
    new_packet_length += ret;
195
221
  }
196
222
 
197
 
   /* Delete the GPGME plaintext data buffer */
 
223
  /* FIXME: check characters before printing to screen so to not print
 
224
     terminal control characters */
 
225
  /*   if(debug){ */
 
226
  /*     fprintf(stderr, "decrypted password is: "); */
 
227
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
 
228
  /*     fprintf(stderr, "\n"); */
 
229
  /*   } */
 
230
  
 
231
  /* Delete the GPGME plaintext data buffer */
198
232
  gpgme_data_release(dh_plain);
199
233
  return new_packet_length;
200
234
}
206
240
  return ret;
207
241
}
208
242
 
209
 
void debuggnutls(int level, const char* string){
 
243
void debuggnutls(__attribute__((unused)) int level,
 
244
                 const char* string){
210
245
  fprintf(stderr, "%s", string);
211
246
}
212
247
 
214
249
  const char *err;
215
250
  int ret;
216
251
  
 
252
  if(debug){
 
253
    fprintf(stderr, "Initializing GnuTLS\n");
 
254
  }
 
255
  
217
256
  if ((ret = gnutls_global_init ())
218
257
      != GNUTLS_E_SUCCESS) {
219
258
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
220
259
    return -1;
221
260
  }
222
261
 
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
 
 
 
262
  if (debug){
 
263
    gnutls_global_set_log_level(11);
 
264
    gnutls_global_set_log_function(debuggnutls);
 
265
  }
 
266
  
228
267
  /* openpgp credentials */
229
268
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
230
269
      != GNUTLS_E_SUCCESS) {
231
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
270
    fprintf (stderr, "memory error: %s\n",
 
271
             safer_gnutls_strerror(ret));
232
272
    return -1;
233
273
  }
234
 
 
 
274
  
 
275
  if(debug){
 
276
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
277
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
 
278
            KEYFILE);
 
279
  }
 
280
  
235
281
  ret = gnutls_certificate_set_openpgp_key_file
236
282
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
237
283
  if (ret != GNUTLS_E_SUCCESS) {
238
284
    fprintf
239
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
 
285
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
286
       " '%s')\n",
240
287
       ret, CERTFILE, KEYFILE);
241
288
    fprintf(stdout, "The Error is: %s\n",
242
289
            safer_gnutls_strerror(ret));
243
290
    return -1;
244
291
  }
245
 
 
246
 
  //Gnutls server initialization
 
292
  
 
293
  //GnuTLS server initialization
247
294
  if ((ret = gnutls_dh_params_init (&es->dh_params))
248
295
      != GNUTLS_E_SUCCESS) {
249
296
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
250
297
             safer_gnutls_strerror(ret));
251
298
    return -1;
252
299
  }
253
 
 
 
300
  
254
301
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
255
302
      != GNUTLS_E_SUCCESS) {
256
303
    fprintf (stderr, "Error in prime generation: %s\n",
257
304
             safer_gnutls_strerror(ret));
258
305
    return -1;
259
306
  }
260
 
 
 
307
  
261
308
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
262
 
 
263
 
  // Gnutls session creation
 
309
  
 
310
  // GnuTLS session creation
264
311
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
265
312
      != GNUTLS_E_SUCCESS){
266
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
313
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
267
314
            safer_gnutls_strerror(ret));
268
315
  }
269
 
 
 
316
  
270
317
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
271
318
      != GNUTLS_E_SUCCESS) {
272
319
    fprintf(stderr, "Syntax error at: %s\n", err);
273
 
    fprintf(stderr, "Gnutls error: %s\n",
 
320
    fprintf(stderr, "GnuTLS error: %s\n",
274
321
            safer_gnutls_strerror(ret));
275
322
    return -1;
276
323
  }
277
 
 
 
324
  
278
325
  if ((ret = gnutls_credentials_set
279
326
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
280
327
      != GNUTLS_E_SUCCESS) {
282
329
            safer_gnutls_strerror(ret));
283
330
    return -1;
284
331
  }
285
 
 
 
332
  
286
333
  /* ignore client certificate if any. */
287
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
334
  gnutls_certificate_server_set_request (es->session,
 
335
                                         GNUTLS_CERT_IGNORE);
288
336
  
289
337
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
290
338
  
291
339
  return 0;
292
340
}
293
341
 
294
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
342
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
343
               __attribute__((unused)) const char *txt){}
295
344
 
296
 
int start_mandos_communcation(char *ip, uint16_t port){
 
345
int start_mandos_communication(const char *ip, uint16_t port,
 
346
                               unsigned int if_index){
297
347
  int ret, tcp_sd;
298
348
  struct sockaddr_in6 to;
299
 
  struct in6_addr ip_addr;
300
349
  encrypted_session es;
301
350
  char *buffer = NULL;
302
351
  char *decrypted_buffer;
303
352
  size_t buffer_length = 0;
304
353
  size_t buffer_capacity = 0;
305
354
  ssize_t decrypted_buffer_size;
 
355
  size_t written = 0;
306
356
  int retval = 0;
307
 
 
 
357
  char interface[IF_NAMESIZE];
 
358
  
 
359
  if(debug){
 
360
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
 
361
            ip, port);
 
362
  }
308
363
  
309
364
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
310
365
  if(tcp_sd < 0) {
312
367
    return -1;
313
368
  }
314
369
  
315
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
316
 
  if(tcp_sd < 0) {
317
 
    perror("setsockopt bindtodevice");
 
370
  if(if_indextoname(if_index, interface) == NULL){
 
371
    if(debug){
 
372
      perror("if_indextoname");
 
373
    }
318
374
    return -1;
319
375
  }
320
376
  
321
 
  memset(&to,0,sizeof(to));
 
377
  if(debug){
 
378
    fprintf(stderr, "Binding to interface %s\n", interface);
 
379
  }
 
380
  
 
381
  memset(&to,0,sizeof(to));     /* Spurious warning */
322
382
  to.sin6_family = AF_INET6;
323
 
  ret = inet_pton(AF_INET6, ip, &ip_addr);
 
383
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
324
384
  if (ret < 0 ){
325
385
    perror("inet_pton");
326
386
    return -1;
329
389
    fprintf(stderr, "Bad address: %s\n", ip);
330
390
    return -1;
331
391
  }
332
 
  to.sin6_port = htons(port);
333
 
  to.sin6_scope_id = if_nametoindex("eth0");
 
392
  to.sin6_port = htons(port);   /* Spurious warning */
 
393
  
 
394
  to.sin6_scope_id = (uint32_t)if_index;
 
395
  
 
396
  if(debug){
 
397
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
 
398
/*     char addrstr[INET6_ADDRSTRLEN]; */
 
399
/*     if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
 
400
/*               sizeof(addrstr)) == NULL){ */
 
401
/*       perror("inet_ntop"); */
 
402
/*     } else { */
 
403
/*       fprintf(stderr, "Really connecting to: %s, port %d\n", */
 
404
/*            addrstr, ntohs(to.sin6_port)); */
 
405
/*     } */
 
406
  }
334
407
  
335
408
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
336
409
  if (ret < 0){
343
416
    retval = -1;
344
417
    return -1;
345
418
  }
346
 
    
347
 
  
348
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
349
 
 
 
419
  
 
420
  gnutls_transport_set_ptr (es.session,
 
421
                            (gnutls_transport_ptr_t) tcp_sd);
 
422
  
 
423
  if(debug){
 
424
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
425
  }
 
426
  
350
427
  ret = gnutls_handshake (es.session);
351
428
  
352
429
  if (ret != GNUTLS_E_SUCCESS){
353
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
354
 
    gnutls_perror (ret);
 
430
    if(debug){
 
431
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
432
      gnutls_perror (ret);
 
433
    }
355
434
    retval = -1;
356
435
    goto exit;
357
436
  }
 
437
  
 
438
  //Retrieve OpenPGP packet that contains the wanted password
 
439
  
 
440
  if(debug){
 
441
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
442
            ip);
 
443
  }
358
444
 
359
 
  //retrive password
360
445
  while(true){
361
446
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
362
447
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
387
472
        }
388
473
        break;
389
474
      default:
390
 
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
475
        fprintf(stderr, "Unknown error while reading data from"
 
476
                " encrypted session with mandos server\n");
391
477
        retval = -1;
392
478
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
393
479
        goto exit;
394
480
      }
395
481
    } else {
396
 
      buffer_length += ret;
 
482
      buffer_length += (size_t) ret;
397
483
    }
398
484
  }
399
 
 
 
485
  
400
486
  if (buffer_length > 0){
401
 
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
 
487
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
488
                                               buffer_length,
 
489
                                               &decrypted_buffer,
 
490
                                               CERT_ROOT);
 
491
    if (decrypted_buffer_size >= 0){
 
492
      while(written < (size_t) decrypted_buffer_size){
 
493
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
494
                           (size_t)decrypted_buffer_size - written,
 
495
                           stdout);
 
496
        if(ret == 0 and ferror(stdout)){
 
497
          if(debug){
 
498
            fprintf(stderr, "Error writing encrypted data: %s\n",
 
499
                    strerror(errno));
 
500
          }
 
501
          retval = -1;
 
502
          break;
 
503
        }
 
504
        written += (size_t)ret;
 
505
      }
 
506
      free(decrypted_buffer);
 
507
    } else {
402
508
      retval = -1;
403
 
    } else {
404
 
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
405
 
      free(decrypted_buffer);
406
509
    }
407
510
  }
408
511
 
 
512
  //shutdown procedure
 
513
 
 
514
  if(debug){
 
515
    fprintf(stderr, "Closing TLS session\n");
 
516
  }
 
517
 
409
518
  free(buffer);
410
 
 
411
 
  //shutdown procedure
412
519
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
413
520
 exit:
414
521
  close(tcp_sd);
423
530
 
424
531
static void resolve_callback(
425
532
    AvahiSServiceResolver *r,
426
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
533
    AvahiIfIndex interface,
427
534
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
428
535
    AvahiResolverEvent event,
429
536
    const char *name,
432
539
    const char *host_name,
433
540
    const AvahiAddress *address,
434
541
    uint16_t port,
435
 
    AvahiStringList *txt,
436
 
    AvahiLookupResultFlags flags,
 
542
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
543
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
437
544
    AVAHI_GCC_UNUSED void* userdata) {
438
545
    
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
 
        }
 
546
  assert(r);                    /* Spurious warning */
 
547
  
 
548
  /* Called whenever a service has been resolved successfully or
 
549
     timed out */
 
550
  
 
551
  switch (event) {
 
552
  default:
 
553
  case AVAHI_RESOLVER_FAILURE:
 
554
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
 
555
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
556
            avahi_strerror(avahi_server_errno(server)));
 
557
    break;
 
558
    
 
559
  case AVAHI_RESOLVER_FOUND:
 
560
    {
 
561
      char ip[AVAHI_ADDRESS_STR_MAX];
 
562
      avahi_address_snprint(ip, sizeof(ip), address);
 
563
      if(debug){
 
564
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
 
565
                " port %d\n", name, host_name, ip, port);
 
566
      }
 
567
      int ret = start_mandos_communication(ip, port,
 
568
                                           (unsigned int) interface);
 
569
      if (ret == 0){
 
570
        exit(EXIT_SUCCESS);
 
571
      }
458
572
    }
459
 
    avahi_s_service_resolver_free(r);
 
573
  }
 
574
  avahi_s_service_resolver_free(r);
460
575
}
461
576
 
462
577
static void browse_callback(
471
586
    void* userdata) {
472
587
    
473
588
    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
 
 
 
589
    assert(b);                  /* Spurious warning */
 
590
    
 
591
    /* Called whenever a new services becomes available on the LAN or
 
592
       is removed from the LAN */
 
593
    
478
594
    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;
 
595
    default:
 
596
    case AVAHI_BROWSER_FAILURE:
 
597
      
 
598
      fprintf(stderr, "(Browser) %s\n",
 
599
              avahi_strerror(avahi_server_errno(server)));
 
600
      avahi_simple_poll_quit(simple_poll);
 
601
      return;
 
602
      
 
603
    case AVAHI_BROWSER_NEW:
 
604
      /* We ignore the returned resolver object. In the callback
 
605
         function we free it. If the server is terminated before
 
606
         the callback function is called the server will free
 
607
         the resolver for us. */
 
608
      
 
609
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
 
610
                                         type, domain,
 
611
                                         AVAHI_PROTO_INET6, 0,
 
612
                                         resolve_callback, s)))
 
613
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
 
614
                avahi_strerror(avahi_server_errno(s)));
 
615
      break;
 
616
      
 
617
    case AVAHI_BROWSER_REMOVE:
 
618
      break;
 
619
      
 
620
    case AVAHI_BROWSER_ALL_FOR_NOW:
 
621
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
622
      break;
503
623
    }
504
624
}
505
625
 
507
627
    AvahiServerConfig config;
508
628
    AvahiSServiceBrowser *sb = NULL;
509
629
    int error;
510
 
    int ret = 1;
511
 
 
512
 
    avahi_set_log_function(empty_log);
 
630
    int ret;
 
631
    int returncode = EXIT_SUCCESS;
 
632
    const char *interface = "eth0";
 
633
    unsigned int if_index;
 
634
    char *connect_to = NULL;
 
635
    
 
636
    while (true){
 
637
      static struct option long_options[] = {
 
638
        {"debug", no_argument, (int *)&debug, 1},
 
639
        {"connect", required_argument, 0, 'c'},
 
640
        {"interface", required_argument, 0, 'i'},
 
641
        {0, 0, 0, 0} };
 
642
      
 
643
      int option_index = 0;
 
644
      ret = getopt_long (argc, argv, "i:", long_options,
 
645
                         &option_index);
 
646
      
 
647
      if (ret == -1){
 
648
        break;
 
649
      }
 
650
      
 
651
      switch(ret){
 
652
      case 0:
 
653
        break;
 
654
      case 'i':
 
655
        interface = optarg;
 
656
        break;
 
657
      case 'c':
 
658
        connect_to = optarg;
 
659
        break;
 
660
      default:
 
661
        exit(EXIT_FAILURE);
 
662
      }
 
663
    }
 
664
    
 
665
    if_index = if_nametoindex(interface);
 
666
    if(if_index == 0){
 
667
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
668
      exit(EXIT_FAILURE);
 
669
    }
 
670
    
 
671
    if(connect_to != NULL){
 
672
      /* Connect directly, do not use Zeroconf */
 
673
      /* (Mainly meant for debugging) */
 
674
      char *address = strrchr(connect_to, ':');
 
675
      if(address == NULL){
 
676
        fprintf(stderr, "No colon in address\n");
 
677
        exit(EXIT_FAILURE);
 
678
      }
 
679
      errno = 0;
 
680
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
681
      if(errno){
 
682
        perror("Bad port number");
 
683
        exit(EXIT_FAILURE);
 
684
      }
 
685
      *address = '\0';
 
686
      address = connect_to;
 
687
      ret = start_mandos_communication(address, port, if_index);
 
688
      if(ret < 0){
 
689
        exit(EXIT_FAILURE);
 
690
      } else {
 
691
        exit(EXIT_SUCCESS);
 
692
      }
 
693
    }
 
694
    
 
695
    if (not debug){
 
696
      avahi_set_log_function(empty_log);
 
697
    }
513
698
    
514
699
    /* Initialize the psuedo-RNG */
515
 
    srand(time(NULL));
 
700
    srand((unsigned int) time(NULL));
516
701
 
517
702
    /* Allocate main loop object */
518
703
    if (!(simple_poll = avahi_simple_poll_new())) {
519
704
        fprintf(stderr, "Failed to create simple poll object.\n");
520
 
        goto fail;
 
705
        
 
706
        goto exit;
521
707
    }
522
708
 
523
709
    /* Do not publish any local records */
527
713
    config.publish_workstation = 0;
528
714
    config.publish_domain = 0;
529
715
 
530
 
/*     /\* Set a unicast DNS server for wide area DNS-SD *\/ */
531
 
/*     avahi_address_parse("193.11.177.11", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]); */
532
 
/*     config.n_wide_area_servers = 1; */
533
 
/*     config.enable_wide_area = 1; */
534
 
    
535
716
    /* Allocate a new server */
536
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
717
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
718
                              &config, NULL, NULL, &error);
537
719
 
538
720
    /* Free the configuration data */
539
721
    avahi_server_config_free(&config);
540
722
 
541
 
    /* Check wether creating the server object succeeded */
 
723
    /* Check if creating the server object succeeded */
542
724
    if (!server) {
543
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
544
 
        goto fail;
 
725
        fprintf(stderr, "Failed to create server: %s\n",
 
726
                avahi_strerror(error));
 
727
        returncode = EXIT_FAILURE;
 
728
        goto exit;
545
729
    }
546
730
    
547
731
    /* Create the service browser */
548
 
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
549
 
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
550
 
        goto fail;
 
732
    sb = avahi_s_service_browser_new(server, (AvahiIfIndex)if_index,
 
733
                                     AVAHI_PROTO_INET6,
 
734
                                     "_mandos._tcp", NULL, 0,
 
735
                                     browse_callback, server);
 
736
    if (!sb) {
 
737
        fprintf(stderr, "Failed to create service browser: %s\n",
 
738
                avahi_strerror(avahi_server_errno(server)));
 
739
        returncode = EXIT_FAILURE;
 
740
        goto exit;
551
741
    }
552
742
    
553
743
    /* Run the main loop */
 
744
 
 
745
    if (debug){
 
746
      fprintf(stderr, "Starting avahi loop search\n");
 
747
    }
 
748
    
554
749
    avahi_simple_poll_loop(simple_poll);
555
750
    
556
 
    ret = 0;
557
 
    
558
 
fail:
 
751
 exit:
 
752
 
 
753
    if (debug){
 
754
      fprintf(stderr, "%s exiting\n", argv[0]);
 
755
    }
559
756
    
560
757
    /* Cleanup things */
561
758
    if (sb)
567
764
    if (simple_poll)
568
765
        avahi_simple_poll_free(simple_poll);
569
766
 
570
 
    return ret;
 
767
    return returncode;
571
768
}