/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-08-03 01:09:36 UTC
  • mfrom: (24.1.9 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080803010936-ujme8tgxceszfbi1
* plugbasedclient.c (main): New "--userid" and "--groupid" options.
                            Take an additional non-option argument and
                            parse it as a plus-separated and -prefixed
                            list of additional options.

* plugins.d/mandosclient.c (DH_BITS): Replaced with
                                      "mandos_context.dh_bits".  All
                                      users changed.
  (certdir): Renamed to "keydir".  All users changed.
  (certfile): Renamed to "pubkeyfile".  All users changed.
  (certkey): Renamed to "seckeyfile".  All users changed.
  (encrypted_session): Replaced with "mandos_context".  All users
                       changed.
  (initgnutls): Take additional "session" and "dh_params" arguments.
                All callers changed.
  (start_mandos_communication): Take additional "mc" argument.  All
                                callers changed.  Print target IPv6
                                address if different than supplied
                                string.
  (simple_poll) Replaced with "mandos_context.simple_poll".  All users
                changed.
  (server): Replaced with "mandos_context.server".  All users changed.
  (main): Default interface to "eth0".  Rename "--certdir" to
          "--keydir", "--certkey" to "--seckey", and "--certfile" to
          "--pubkey".  New options "--dh-bits" and "--priority".  If
          the interface is not up, bring it up.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
***/
 
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
 */
19
30
 
 
31
/* Needed by GPGME, specifically gpgme_data_seek() */
20
32
#define _LARGEFILE_SOURCE
21
33
#define _FILE_OFFSET_BITS 64
22
34
 
25
37
#include <stdlib.h>
26
38
#include <time.h>
27
39
#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
28
42
 
29
43
#include <avahi-core/core.h>
30
44
#include <avahi-core/lookup.h>
34
48
#include <avahi-common/error.h>
35
49
 
36
50
//mandos client part
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 */
 
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 */
41
56
 
42
57
#include <unistd.h>             /* close() */
43
58
#include <netinet/in.h>
50
65
#include <errno.h>              /* perror() */
51
66
#include <gpgme.h>
52
67
 
 
68
// getopt_long
 
69
#include <getopt.h>
53
70
 
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"
59
71
#define BUFFER_SIZE 256
60
 
#define DH_BITS 1024
61
 
 
62
 
bool debug;
63
 
 
 
72
 
 
73
static const char *keydir = "/conf/conf.d/mandos";
 
74
static const char *pubkeyfile = "pubkey.txt";
 
75
static const char *seckeyfile = "seckey.txt";
 
76
 
 
77
bool debug = false;
 
78
 
 
79
/* Used for passing in values through all the callback functions */
64
80
typedef struct {
65
 
  gnutls_session_t session;
 
81
  AvahiSimplePoll *simple_poll;
 
82
  AvahiServer *server;
66
83
  gnutls_certificate_credentials_t cred;
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){
 
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){
72
91
  gpgme_data_t dh_crypto, dh_plain;
73
92
  gpgme_ctx_t ctx;
74
93
  gpgme_error_t rc;
75
94
  ssize_t ret;
76
 
  size_t new_packet_capacity = 0;
77
 
  size_t new_packet_length = 0;
 
95
  ssize_t new_packet_capacity = 0;
 
96
  ssize_t new_packet_length = 0;
78
97
  gpgme_engine_info_t engine_info;
79
98
 
80
99
  if (debug){
81
 
    fprintf(stderr, "Attempting to decrypt password from gpg packet\n");
 
100
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
82
101
  }
83
102
  
84
103
  /* Init GPGME */
85
104
  gpgme_check_version(NULL);
86
 
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
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
  }
87
111
  
88
112
  /* Set GPGME home directory */
89
113
  rc = gpgme_get_engine_info (&engine_info);
129
153
    return -1;
130
154
  }
131
155
  
132
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
156
  /* Decrypt data from the FILE pointer to the plaintext data
 
157
     buffer */
133
158
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
134
159
  if (rc != GPG_ERR_NO_ERROR){
135
160
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
138
163
  }
139
164
 
140
165
  if(debug){
141
 
    fprintf(stderr, "decryption of gpg packet succeeded\n");
 
166
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
142
167
  }
143
168
 
144
169
  if (debug){
147
172
    if (result == NULL){
148
173
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
149
174
    } else {
150
 
      fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
151
 
      fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
 
175
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
176
              result->unsupported_algorithm);
 
177
      fprintf(stderr, "Wrong key usage: %d\n",
 
178
              result->wrong_key_usage);
152
179
      if(result->file_name != NULL){
153
180
        fprintf(stderr, "File name: %s\n", result->file_name);
154
181
      }
160
187
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
161
188
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
162
189
          fprintf(stderr, "Secret key available: %s\n",
163
 
                  recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
 
190
                  recipient->status == GPG_ERR_NO_SECKEY
 
191
                  ? "No" : "Yes");
164
192
          recipient = recipient->next;
165
193
        }
166
194
      }
171
199
  gpgme_data_release(dh_crypto);
172
200
  
173
201
  /* Seek back to the beginning of the GPGME plaintext data buffer */
174
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
175
 
 
 
202
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
 
203
    perror("pgpme_data_seek");
 
204
  }
 
205
  
176
206
  *new_packet = 0;
177
207
  while(true){
178
208
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
179
 
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
 
209
      *new_packet = realloc(*new_packet,
 
210
                            (unsigned int)new_packet_capacity
 
211
                            + BUFFER_SIZE);
180
212
      if (*new_packet == NULL){
181
213
        perror("realloc");
182
214
        return -1;
184
216
      new_packet_capacity += BUFFER_SIZE;
185
217
    }
186
218
    
187
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
 
219
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
220
                          BUFFER_SIZE);
188
221
    /* Print the data, if any */
189
222
    if (ret == 0){
190
 
      /* If password is empty, then a incorrect error will be printed */
191
223
      break;
192
224
    }
193
225
    if(ret < 0){
197
229
    new_packet_length += ret;
198
230
  }
199
231
 
200
 
  if(debug){
201
 
    fprintf(stderr, "decrypted password is: %s\n", *new_packet);
202
 
  }
203
 
 
204
 
   /* Delete the GPGME plaintext data buffer */
 
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 */
205
241
  gpgme_data_release(dh_plain);
206
242
  return new_packet_length;
207
243
}
213
249
  return ret;
214
250
}
215
251
 
216
 
void debuggnutls(int level, const char* string){
 
252
static void debuggnutls(__attribute__((unused)) int level,
 
253
                        const char* string){
217
254
  fprintf(stderr, "%s", string);
218
255
}
219
256
 
220
 
int initgnutls(encrypted_session *es){
 
257
static int initgnutls(mandos_context *mc, gnutls_session_t *session,
 
258
                      gnutls_dh_params_t *dh_params){
221
259
  const char *err;
222
260
  int ret;
223
 
 
 
261
  
224
262
  if(debug){
225
 
    fprintf(stderr, "Initializing gnutls\n");
 
263
    fprintf(stderr, "Initializing GnuTLS\n");
226
264
  }
227
265
 
228
 
  
229
266
  if ((ret = gnutls_global_init ())
230
267
      != GNUTLS_E_SUCCESS) {
231
268
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
232
269
    return -1;
233
270
  }
234
 
 
 
271
  
235
272
  if (debug){
236
273
    gnutls_global_set_log_level(11);
237
274
    gnutls_global_set_log_function(debuggnutls);
238
275
  }
239
276
  
240
 
 
241
277
  /* openpgp credentials */
242
 
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
 
278
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
243
279
      != GNUTLS_E_SUCCESS) {
244
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
280
    fprintf (stderr, "memory error: %s\n",
 
281
             safer_gnutls_strerror(ret));
245
282
    return -1;
246
283
  }
247
 
 
 
284
  
248
285
  if(debug){
249
 
    fprintf(stderr, "Attempting to use openpgp certificate %s"
250
 
            " and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
 
286
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
287
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
 
288
            seckeyfile);
251
289
  }
252
 
 
 
290
  
253
291
  ret = gnutls_certificate_set_openpgp_key_file
254
 
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
 
292
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
255
293
  if (ret != GNUTLS_E_SUCCESS) {
256
294
    fprintf
257
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
258
 
       ret, CERTFILE, KEYFILE);
 
295
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
296
       " '%s')\n",
 
297
       ret, pubkeyfile, seckeyfile);
259
298
    fprintf(stdout, "The Error is: %s\n",
260
299
            safer_gnutls_strerror(ret));
261
300
    return -1;
262
301
  }
263
 
 
264
 
  //Gnutls server initialization
265
 
  if ((ret = gnutls_dh_params_init (&es->dh_params))
 
302
  
 
303
  //GnuTLS server initialization
 
304
  if ((ret = gnutls_dh_params_init(dh_params))
266
305
      != GNUTLS_E_SUCCESS) {
267
306
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
268
307
             safer_gnutls_strerror(ret));
269
308
    return -1;
270
309
  }
271
 
 
272
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
 
310
  
 
311
  if ((ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits))
273
312
      != GNUTLS_E_SUCCESS) {
274
313
    fprintf (stderr, "Error in prime generation: %s\n",
275
314
             safer_gnutls_strerror(ret));
276
315
    return -1;
277
316
  }
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))
 
317
  
 
318
  gnutls_certificate_set_dh_params(mc->cred, *dh_params);
 
319
  
 
320
  // GnuTLS session creation
 
321
  if ((ret = gnutls_init(session, GNUTLS_SERVER))
283
322
      != GNUTLS_E_SUCCESS){
284
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
323
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
285
324
            safer_gnutls_strerror(ret));
286
325
  }
287
 
 
288
 
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
 
326
  
 
327
  if ((ret = gnutls_priority_set_direct(*session, mc->priority, &err))
289
328
      != GNUTLS_E_SUCCESS) {
290
329
    fprintf(stderr, "Syntax error at: %s\n", err);
291
 
    fprintf(stderr, "Gnutls error: %s\n",
 
330
    fprintf(stderr, "GnuTLS error: %s\n",
292
331
            safer_gnutls_strerror(ret));
293
332
    return -1;
294
333
  }
295
 
 
296
 
  if ((ret = gnutls_credentials_set
297
 
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
 
334
  
 
335
  if ((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
336
                                    mc->cred))
298
337
      != GNUTLS_E_SUCCESS) {
299
338
    fprintf(stderr, "Error setting a credentials set: %s\n",
300
339
            safer_gnutls_strerror(ret));
301
340
    return -1;
302
341
  }
303
 
 
 
342
  
304
343
  /* ignore client certificate if any. */
305
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
344
  gnutls_certificate_server_set_request (*session,
 
345
                                         GNUTLS_CERT_IGNORE);
306
346
  
307
 
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
 
347
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
308
348
  
309
349
  return 0;
310
350
}
311
351
 
312
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
352
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
353
                      __attribute__((unused)) const char *txt){}
313
354
 
314
 
int start_mandos_communcation(char *ip, uint16_t port){
 
355
static int start_mandos_communication(const char *ip, uint16_t port,
 
356
                                      AvahiIfIndex if_index,
 
357
                                      mandos_context *mc){
315
358
  int ret, tcp_sd;
316
359
  struct sockaddr_in6 to;
317
 
  struct in6_addr ip_addr;
318
 
  encrypted_session es;
319
360
  char *buffer = NULL;
320
361
  char *decrypted_buffer;
321
362
  size_t buffer_length = 0;
322
363
  size_t buffer_capacity = 0;
323
364
  ssize_t decrypted_buffer_size;
 
365
  size_t written = 0;
324
366
  int retval = 0;
325
 
  const char interface[] = "eth0";
326
 
 
 
367
  char interface[IF_NAMESIZE];
 
368
  gnutls_session_t session;
 
369
  gnutls_dh_params_t dh_params;
 
370
  
327
371
  if(debug){
328
 
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
 
372
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
 
373
            ip, port);
329
374
  }
330
375
  
331
376
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
335
380
  }
336
381
 
337
382
  if(debug){
 
383
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
384
      perror("if_indextoname");
 
385
      return -1;
 
386
    }
338
387
    fprintf(stderr, "Binding to interface %s\n", interface);
339
388
  }
340
 
 
341
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
342
 
  if(tcp_sd < 0) {
343
 
    perror("setsockopt bindtodevice");
344
 
    return -1;
345
 
  }
346
389
  
347
 
  memset(&to,0,sizeof(to));
 
390
  memset(&to,0,sizeof(to));     /* Spurious warning */
348
391
  to.sin6_family = AF_INET6;
349
 
  ret = inet_pton(AF_INET6, ip, &ip_addr);
 
392
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
350
393
  if (ret < 0 ){
351
394
    perror("inet_pton");
352
395
    return -1;
353
 
  }  
 
396
  }
354
397
  if(ret == 0){
355
398
    fprintf(stderr, "Bad address: %s\n", ip);
356
399
    return -1;
357
400
  }
358
 
  to.sin6_port = htons(port);
359
 
  to.sin6_scope_id = if_nametoindex(interface);
360
 
 
 
401
  to.sin6_port = htons(port);   /* Spurious warning */
 
402
  
 
403
  to.sin6_scope_id = (uint32_t)if_index;
 
404
  
361
405
  if(debug){
362
 
    fprintf(stderr, "Connection to: %s\n", ip);
 
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
    }
363
416
  }
364
417
  
365
418
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
368
421
    return -1;
369
422
  }
370
423
  
371
 
  ret = initgnutls (&es);
 
424
  ret = initgnutls (mc, &session, &dh_params);
372
425
  if (ret != 0){
373
426
    retval = -1;
374
427
    return -1;
375
428
  }
376
 
    
377
 
  
378
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
379
 
 
 
429
  
 
430
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
 
431
  
380
432
  if(debug){
381
 
    fprintf(stderr, "Establishing tls session with %s\n", ip);
 
433
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
382
434
  }
383
 
 
384
435
  
385
 
  ret = gnutls_handshake (es.session);
 
436
  ret = gnutls_handshake (session);
386
437
  
387
438
  if (ret != GNUTLS_E_SUCCESS){
388
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
389
 
    gnutls_perror (ret);
 
439
    if(debug){
 
440
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
441
      gnutls_perror (ret);
 
442
    }
390
443
    retval = -1;
391
444
    goto exit;
392
445
  }
393
 
 
394
 
  //Retrieve gpg packet that contains the wanted password
395
 
 
 
446
  
 
447
  //Retrieve OpenPGP packet that contains the wanted password
 
448
  
396
449
  if(debug){
397
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
 
450
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
451
            ip);
398
452
  }
399
453
 
400
454
  while(true){
407
461
      buffer_capacity += BUFFER_SIZE;
408
462
    }
409
463
    
410
 
    ret = gnutls_record_recv
411
 
      (es.session, buffer+buffer_length, BUFFER_SIZE);
 
464
    ret = gnutls_record_recv(session, buffer+buffer_length,
 
465
                             BUFFER_SIZE);
412
466
    if (ret == 0){
413
467
      break;
414
468
    }
418
472
      case GNUTLS_E_AGAIN:
419
473
        break;
420
474
      case GNUTLS_E_REHANDSHAKE:
421
 
        ret = gnutls_handshake (es.session);
 
475
        ret = gnutls_handshake (session);
422
476
        if (ret < 0){
423
477
          fprintf(stderr, "\n*** Handshake failed ***\n");
424
478
          gnutls_perror (ret);
427
481
        }
428
482
        break;
429
483
      default:
430
 
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
484
        fprintf(stderr, "Unknown error while reading data from"
 
485
                " encrypted session with mandos server\n");
431
486
        retval = -1;
432
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
487
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
433
488
        goto exit;
434
489
      }
435
490
    } else {
436
 
      buffer_length += ret;
 
491
      buffer_length += (size_t) ret;
437
492
    }
438
493
  }
439
494
  
440
495
  if (buffer_length > 0){
441
 
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
442
 
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
 
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
      }
443
515
      free(decrypted_buffer);
444
516
    } else {
445
517
      retval = -1;
449
521
  //shutdown procedure
450
522
 
451
523
  if(debug){
452
 
    fprintf(stderr, "Closing tls session\n");
 
524
    fprintf(stderr, "Closing TLS session\n");
453
525
  }
454
526
 
455
527
  free(buffer);
456
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
528
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
457
529
 exit:
458
530
  close(tcp_sd);
459
 
  gnutls_deinit (es.session);
460
 
  gnutls_certificate_free_credentials (es.cred);
 
531
  gnutls_deinit (session);
 
532
  gnutls_certificate_free_credentials (mc->cred);
461
533
  gnutls_global_deinit ();
462
534
  return retval;
463
535
}
464
536
 
465
 
static AvahiSimplePoll *simple_poll = NULL;
466
 
static AvahiServer *server = NULL;
467
 
 
468
 
static void resolve_callback(
469
 
    AvahiSServiceResolver *r,
470
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
471
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
472
 
    AvahiResolverEvent event,
473
 
    const char *name,
474
 
    const char *type,
475
 
    const char *domain,
476
 
    const char *host_name,
477
 
    const AvahiAddress *address,
478
 
    uint16_t port,
479
 
    AvahiStringList *txt,
480
 
    AvahiLookupResultFlags flags,
481
 
    AVAHI_GCC_UNUSED void* userdata) {
482
 
    
483
 
    assert(r);
484
 
 
485
 
    /* Called whenever a service has been resolved successfully or timed out */
486
 
 
487
 
    switch (event) {
488
 
        case AVAHI_RESOLVER_FAILURE:
489
 
            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)));
490
 
            break;
491
 
 
492
 
        case AVAHI_RESOLVER_FOUND: {
493
 
          char ip[AVAHI_ADDRESS_STR_MAX];
494
 
            avahi_address_snprint(ip, sizeof(ip), address);
495
 
            if(debug){
496
 
              fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
497
 
            }
498
 
            int ret = start_mandos_communcation(ip, port);
499
 
            if (ret == 0){
500
 
              exit(EXIT_SUCCESS);
501
 
            } else {
502
 
              exit(EXIT_FAILURE);
503
 
            }
504
 
        }
505
 
    }
506
 
    avahi_s_service_resolver_free(r);
507
 
}
508
 
 
509
 
static void browse_callback(
510
 
    AvahiSServiceBrowser *b,
511
 
    AvahiIfIndex interface,
512
 
    AvahiProtocol protocol,
513
 
    AvahiBrowserEvent event,
514
 
    const char *name,
515
 
    const char *type,
516
 
    const char *domain,
517
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
518
 
    void* userdata) {
519
 
    
520
 
    AvahiServer *s = userdata;
521
 
    assert(b);
522
 
 
523
 
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
524
 
 
525
 
    switch (event) {
526
 
 
527
 
        case AVAHI_BROWSER_FAILURE:
528
 
            
529
 
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
530
 
            avahi_simple_poll_quit(simple_poll);
531
 
            return;
532
 
 
533
 
        case AVAHI_BROWSER_NEW:
534
 
            /* We ignore the returned resolver object. In the callback
535
 
               function we free it. If the server is terminated before
536
 
               the callback function is called the server will free
537
 
               the resolver for us. */
538
 
            
539
 
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
540
 
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
541
 
            
542
 
            break;
543
 
 
544
 
        case AVAHI_BROWSER_REMOVE:
545
 
            break;
546
 
 
547
 
        case AVAHI_BROWSER_ALL_FOR_NOW:
548
 
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
549
 
            break;
550
 
    }
551
 
}
 
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
 
552
648
 
553
649
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
554
650
    AvahiServerConfig config;
555
651
    AvahiSServiceBrowser *sb = NULL;
556
 
    const char db[] = "--debug";
557
652
    int error;
558
 
    int ret = 1;
 
653
    int ret;
 
654
    int debug_int;
559
655
    int returncode = EXIT_SUCCESS;
560
 
    char *basename = rindex(argv[0], '/');
561
 
    if(basename == NULL){
562
 
      basename = argv[0];
563
 
    } else {
564
 
      basename++;
565
 
    }
566
 
    
567
 
    char *program_name = malloc(strlen(basename) + sizeof(db));
568
 
 
569
 
    if (program_name == NULL){
570
 
      perror("argv[0]");
571
 
      return EXIT_FAILURE;
572
 
    }
573
 
    
574
 
    program_name[0] = '\0';
575
 
    
576
 
    for (int i = 1; i < argc; i++){
577
 
      if (not strncmp(argv[i], db, 5)){
578
 
          strcat(strcat(strcat(program_name, db ), "="), basename);
579
 
          if(not strcmp(argv[i], db) or not strcmp(argv[i], program_name)){
580
 
            debug = true;
581
 
          }
 
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);
582
709
        }
583
 
    }
584
 
    free(program_name);
585
 
 
 
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
    
586
789
    if (not debug){
587
790
      avahi_set_log_function(empty_log);
588
791
    }
589
792
    
590
793
    /* Initialize the psuedo-RNG */
591
 
    srand(time(NULL));
 
794
    srand((unsigned int) time(NULL));
592
795
 
593
796
    /* Allocate main loop object */
594
 
    if (!(simple_poll = avahi_simple_poll_new())) {
 
797
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
595
798
        fprintf(stderr, "Failed to create simple poll object.\n");
596
 
        
 
799
        returncode = EXIT_FAILURE;
597
800
        goto exit;
598
801
    }
599
802
 
605
808
    config.publish_domain = 0;
606
809
 
607
810
    /* Allocate a new server */
608
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
609
 
 
 
811
    mc.server=avahi_server_new(avahi_simple_poll_get(mc.simple_poll),
 
812
                               &config, NULL, NULL, &error);
 
813
    
610
814
    /* Free the configuration data */
611
815
    avahi_server_config_free(&config);
612
 
 
 
816
    
613
817
    /* Check if creating the server object succeeded */
614
 
    if (!server) {
615
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
818
    if (!mc.server) {
 
819
        fprintf(stderr, "Failed to create server: %s\n",
 
820
                avahi_strerror(error));
616
821
        returncode = EXIT_FAILURE;
617
822
        goto exit;
618
823
    }
619
824
    
620
825
    /* Create the service browser */
621
 
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
622
 
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
 
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)));
623
833
        returncode = EXIT_FAILURE;
624
834
        goto exit;
625
835
    }
630
840
      fprintf(stderr, "Starting avahi loop search\n");
631
841
    }
632
842
    
633
 
    avahi_simple_poll_loop(simple_poll);
 
843
    avahi_simple_poll_loop(mc.simple_poll);
634
844
    
635
 
exit:
 
845
 exit:
636
846
 
637
847
    if (debug){
638
848
      fprintf(stderr, "%s exiting\n", argv[0]);
642
852
    if (sb)
643
853
        avahi_s_service_browser_free(sb);
644
854
    
645
 
    if (server)
646
 
        avahi_server_free(server);
647
 
 
648
 
    if (simple_poll)
649
 
        avahi_simple_poll_free(simple_poll);
650
 
 
651
 
    return ret;
 
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;
652
864
}