/mandos/release

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

« back to all changes in this revision

Viewing changes to plugins.d/mandosclient.c

  • Committer: Teddy Hogeborn
  • Date: 2008-07-21 01:52:54 UTC
  • mfrom: (15.1.2 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080721015254-5ut0m7j1r4t5x7hj
Merge.

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