/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: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support:
Pluginbased client handler
rewritten Mandos client
       Avahi instead of udp server discovery
       openpgp encrypted key support
Passprompt stand alone application for direct console input
Added logging for Mandos server

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
 
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.
4
6
 *
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>.
 
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.
29
12
 */
30
13
 
31
 
/* Needed by GPGME, specifically gpgme_data_seek() */
 
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
33
#define _LARGEFILE_SOURCE
33
34
#define _FILE_OFFSET_BITS 64
34
35
 
46
47
#include <avahi-common/error.h>
47
48
 
48
49
//mandos client part
49
 
#include <sys/types.h>          /* socket(), inet_pton() */
50
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
51
 
                                   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(), 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 */
54
54
 
55
55
#include <unistd.h>             /* close() */
56
56
#include <netinet/in.h>
63
63
#include <errno.h>              /* perror() */
64
64
#include <gpgme.h>
65
65
 
66
 
// getopt long
67
 
#include <getopt.h>
68
66
 
 
67
#ifndef CERT_ROOT
 
68
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
 
69
#endif
 
70
#define CERTFILE CERT_ROOT "openpgp-client.txt"
 
71
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
69
72
#define BUFFER_SIZE 256
70
73
#define DH_BITS 1024
71
74
 
72
 
const char *certdir = "/conf/conf.d/cryptkeyreq/";
73
 
const char *certfile = "openpgp-client.txt";
74
 
const char *certkey = "openpgp-client-key.txt";
75
 
 
76
 
bool debug = false;
77
 
 
78
75
typedef struct {
79
76
  gnutls_session_t session;
80
77
  gnutls_certificate_credentials_t cred;
82
79
} encrypted_session;
83
80
 
84
81
 
85
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
86
 
                            char **new_packet, const char *homedir){
 
82
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
87
83
  gpgme_data_t dh_crypto, dh_plain;
88
84
  gpgme_ctx_t ctx;
89
85
  gpgme_error_t rc;
90
86
  ssize_t ret;
91
 
  ssize_t new_packet_capacity = 0;
92
 
  ssize_t new_packet_length = 0;
 
87
  size_t new_packet_capacity = 0;
 
88
  size_t new_packet_length = 0;
93
89
  gpgme_engine_info_t engine_info;
94
90
 
95
 
  if (debug){
96
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
97
 
  }
98
 
  
99
91
  /* Init GPGME */
100
92
  gpgme_check_version(NULL);
101
 
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
102
 
  if (rc != GPG_ERR_NO_ERROR){
103
 
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
104
 
            gpgme_strsource(rc), gpgme_strerror(rc));
105
 
    return -1;
106
 
  }
 
93
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
107
94
  
108
95
  /* Set GPGME home directory */
109
96
  rc = gpgme_get_engine_info (&engine_info);
149
136
    return -1;
150
137
  }
151
138
  
152
 
  /* Decrypt data from the FILE pointer to the plaintext data
153
 
     buffer */
 
139
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
154
140
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
155
141
  if (rc != GPG_ERR_NO_ERROR){
156
142
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
157
143
            gpgme_strsource(rc), gpgme_strerror(rc));
158
144
    return -1;
159
145
  }
160
 
 
161
 
  if(debug){
162
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
163
 
  }
164
 
 
165
 
  if (debug){
166
 
    gpgme_decrypt_result_t result;
167
 
    result = gpgme_op_decrypt_result(ctx);
168
 
    if (result == NULL){
169
 
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
170
 
    } else {
171
 
      fprintf(stderr, "Unsupported algorithm: %s\n",
172
 
              result->unsupported_algorithm);
173
 
      fprintf(stderr, "Wrong key usage: %d\n",
174
 
              result->wrong_key_usage);
175
 
      if(result->file_name != NULL){
176
 
        fprintf(stderr, "File name: %s\n", result->file_name);
177
 
      }
178
 
      gpgme_recipient_t recipient;
179
 
      recipient = result->recipients;
180
 
      if(recipient){
181
 
        while(recipient != NULL){
182
 
          fprintf(stderr, "Public key algorithm: %s\n",
183
 
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
184
 
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
185
 
          fprintf(stderr, "Secret key available: %s\n",
186
 
                  recipient->status == GPG_ERR_NO_SECKEY
187
 
                  ? "No" : "Yes");
188
 
          recipient = recipient->next;
189
 
        }
190
 
      }
191
 
    }
192
 
  }
193
146
  
 
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
 
194
167
  /* Delete the GPGME FILE pointer cryptotext data buffer */
195
168
  gpgme_data_release(dh_crypto);
196
169
  
197
170
  /* Seek back to the beginning of the GPGME plaintext data buffer */
198
 
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
199
 
    perror("pgpme_data_seek");
200
 
  }
201
 
  
 
171
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
 
172
 
202
173
  *new_packet = 0;
203
174
  while(true){
204
175
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
205
 
      *new_packet = realloc(*new_packet,
206
 
                            (unsigned int)new_packet_capacity
207
 
                            + BUFFER_SIZE);
 
176
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
208
177
      if (*new_packet == NULL){
209
178
        perror("realloc");
210
179
        return -1;
212
181
      new_packet_capacity += BUFFER_SIZE;
213
182
    }
214
183
    
215
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
216
 
                          BUFFER_SIZE);
 
184
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
217
185
    /* Print the data, if any */
218
186
    if (ret == 0){
 
187
      /* If password is empty, then a incorrect error will be printed */
219
188
      break;
220
189
    }
221
190
    if(ret < 0){
225
194
    new_packet_length += ret;
226
195
  }
227
196
 
228
 
  /* FIXME: check characters before printing to screen so to not print
229
 
     terminal control characters */
230
 
  /*   if(debug){ */
231
 
  /*     fprintf(stderr, "decrypted password is: "); */
232
 
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
233
 
  /*     fprintf(stderr, "\n"); */
234
 
  /*   } */
235
 
  
236
 
  /* Delete the GPGME plaintext data buffer */
 
197
   /* Delete the GPGME plaintext data buffer */
237
198
  gpgme_data_release(dh_plain);
238
199
  return new_packet_length;
239
200
}
245
206
  return ret;
246
207
}
247
208
 
248
 
void debuggnutls(__attribute__((unused)) int level,
249
 
                 const char* string){
 
209
void debuggnutls(int level, const char* string){
250
210
  fprintf(stderr, "%s", string);
251
211
}
252
212
 
254
214
  const char *err;
255
215
  int ret;
256
216
  
257
 
  if(debug){
258
 
    fprintf(stderr, "Initializing GnuTLS\n");
259
 
  }
260
 
 
261
217
  if ((ret = gnutls_global_init ())
262
218
      != GNUTLS_E_SUCCESS) {
263
219
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
264
220
    return -1;
265
221
  }
266
222
 
267
 
  if (debug){
268
 
    gnutls_global_set_log_level(11);
269
 
    gnutls_global_set_log_function(debuggnutls);
270
 
  }
271
 
  
 
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
 
272
228
  /* openpgp credentials */
273
229
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
274
230
      != GNUTLS_E_SUCCESS) {
275
 
    fprintf (stderr, "memory error: %s\n",
276
 
             safer_gnutls_strerror(ret));
 
231
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
277
232
    return -1;
278
233
  }
279
 
  
280
 
  if(debug){
281
 
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
282
 
            " and keyfile %s as GnuTLS credentials\n", certfile,
283
 
            certkey);
284
 
  }
285
 
  
 
234
 
286
235
  ret = gnutls_certificate_set_openpgp_key_file
287
 
    (es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
 
236
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
288
237
  if (ret != GNUTLS_E_SUCCESS) {
289
238
    fprintf
290
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
291
 
       " '%s')\n",
292
 
       ret, certfile, certkey);
 
239
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
 
240
       ret, CERTFILE, KEYFILE);
293
241
    fprintf(stdout, "The Error is: %s\n",
294
242
            safer_gnutls_strerror(ret));
295
243
    return -1;
296
244
  }
297
 
  
298
 
  //GnuTLS server initialization
 
245
 
 
246
  //Gnutls server initialization
299
247
  if ((ret = gnutls_dh_params_init (&es->dh_params))
300
248
      != GNUTLS_E_SUCCESS) {
301
249
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
302
250
             safer_gnutls_strerror(ret));
303
251
    return -1;
304
252
  }
305
 
  
 
253
 
306
254
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
307
255
      != GNUTLS_E_SUCCESS) {
308
256
    fprintf (stderr, "Error in prime generation: %s\n",
309
257
             safer_gnutls_strerror(ret));
310
258
    return -1;
311
259
  }
312
 
  
 
260
 
313
261
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
314
 
  
315
 
  // GnuTLS session creation
 
262
 
 
263
  // Gnutls session creation
316
264
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
317
265
      != GNUTLS_E_SUCCESS){
318
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
 
266
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
319
267
            safer_gnutls_strerror(ret));
320
268
  }
321
 
  
 
269
 
322
270
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
323
271
      != GNUTLS_E_SUCCESS) {
324
272
    fprintf(stderr, "Syntax error at: %s\n", err);
325
 
    fprintf(stderr, "GnuTLS error: %s\n",
 
273
    fprintf(stderr, "Gnutls error: %s\n",
326
274
            safer_gnutls_strerror(ret));
327
275
    return -1;
328
276
  }
329
 
  
 
277
 
330
278
  if ((ret = gnutls_credentials_set
331
279
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
332
280
      != GNUTLS_E_SUCCESS) {
334
282
            safer_gnutls_strerror(ret));
335
283
    return -1;
336
284
  }
337
 
  
 
285
 
338
286
  /* ignore client certificate if any. */
339
 
  gnutls_certificate_server_set_request (es->session,
340
 
                                         GNUTLS_CERT_IGNORE);
 
287
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
341
288
  
342
289
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
343
290
  
344
291
  return 0;
345
292
}
346
293
 
347
 
void empty_log(__attribute__((unused)) AvahiLogLevel level,
348
 
               __attribute__((unused)) const char *txt){}
 
294
void empty_log(AvahiLogLevel level, const char *txt){}
349
295
 
350
 
int start_mandos_communication(const char *ip, uint16_t port,
351
 
                               AvahiIfIndex if_index){
 
296
int start_mandos_communcation(char *ip, uint16_t port){
352
297
  int ret, tcp_sd;
353
298
  struct sockaddr_in6 to;
 
299
  struct in6_addr ip_addr;
354
300
  encrypted_session es;
355
301
  char *buffer = NULL;
356
302
  char *decrypted_buffer;
357
303
  size_t buffer_length = 0;
358
304
  size_t buffer_capacity = 0;
359
305
  ssize_t decrypted_buffer_size;
360
 
  size_t written = 0;
361
306
  int retval = 0;
362
 
  char interface[IF_NAMESIZE];
363
 
  
364
 
  if(debug){
365
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
366
 
            ip, port);
367
 
  }
 
307
 
368
308
  
369
309
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
370
310
  if(tcp_sd < 0) {
372
312
    return -1;
373
313
  }
374
314
  
375
 
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
376
 
    if(debug){
377
 
      perror("if_indextoname");
378
 
    }
 
315
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
 
316
  if(tcp_sd < 0) {
 
317
    perror("setsockopt bindtodevice");
379
318
    return -1;
380
319
  }
381
320
  
382
 
  if(debug){
383
 
    fprintf(stderr, "Binding to interface %s\n", interface);
384
 
  }
385
 
  
386
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
 
321
  memset(&to,0,sizeof(to));
387
322
  to.sin6_family = AF_INET6;
388
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
323
  ret = inet_pton(AF_INET6, ip, &ip_addr);
389
324
  if (ret < 0 ){
390
325
    perror("inet_pton");
391
326
    return -1;
394
329
    fprintf(stderr, "Bad address: %s\n", ip);
395
330
    return -1;
396
331
  }
397
 
  to.sin6_port = htons(port);   /* Spurious warning */
398
 
  
399
 
  to.sin6_scope_id = (uint32_t)if_index;
400
 
  
401
 
  if(debug){
402
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
403
 
/*     char addrstr[INET6_ADDRSTRLEN]; */
404
 
/*     if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
405
 
/*               sizeof(addrstr)) == NULL){ */
406
 
/*       perror("inet_ntop"); */
407
 
/*     } else { */
408
 
/*       fprintf(stderr, "Really connecting to: %s, port %d\n", */
409
 
/*            addrstr, ntohs(to.sin6_port)); */
410
 
/*     } */
411
 
  }
 
332
  to.sin6_port = htons(port);
 
333
  to.sin6_scope_id = if_nametoindex("eth0");
412
334
  
413
335
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
414
336
  if (ret < 0){
421
343
    retval = -1;
422
344
    return -1;
423
345
  }
424
 
  
425
 
  gnutls_transport_set_ptr (es.session,
426
 
                            (gnutls_transport_ptr_t) tcp_sd);
427
 
  
428
 
  if(debug){
429
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
430
 
  }
431
 
  
 
346
    
 
347
  
 
348
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
 
349
 
432
350
  ret = gnutls_handshake (es.session);
433
351
  
434
352
  if (ret != GNUTLS_E_SUCCESS){
435
 
    if(debug){
436
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
437
 
      gnutls_perror (ret);
438
 
    }
 
353
    fprintf(stderr, "\n*** Handshake failed ***\n");
 
354
    gnutls_perror (ret);
439
355
    retval = -1;
440
356
    goto exit;
441
357
  }
442
 
  
443
 
  //Retrieve OpenPGP packet that contains the wanted password
444
 
  
445
 
  if(debug){
446
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
447
 
            ip);
448
 
  }
449
358
 
 
359
  //retrive password
450
360
  while(true){
451
361
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
452
362
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
477
387
        }
478
388
        break;
479
389
      default:
480
 
        fprintf(stderr, "Unknown error while reading data from"
481
 
                " encrypted session with mandos server\n");
 
390
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
482
391
        retval = -1;
483
392
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
484
393
        goto exit;
485
394
      }
486
395
    } else {
487
 
      buffer_length += (size_t) ret;
 
396
      buffer_length += ret;
488
397
    }
489
398
  }
490
 
  
 
399
 
491
400
  if (buffer_length > 0){
492
 
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
493
 
                                               buffer_length,
494
 
                                               &decrypted_buffer,
495
 
                                               certdir);
496
 
    if (decrypted_buffer_size >= 0){
497
 
      while(written < (size_t) decrypted_buffer_size){
498
 
        ret = (int)fwrite (decrypted_buffer + written, 1,
499
 
                           (size_t)decrypted_buffer_size - written,
500
 
                           stdout);
501
 
        if(ret == 0 and ferror(stdout)){
502
 
          if(debug){
503
 
            fprintf(stderr, "Error writing encrypted data: %s\n",
504
 
                    strerror(errno));
505
 
          }
506
 
          retval = -1;
507
 
          break;
508
 
        }
509
 
        written += (size_t)ret;
510
 
      }
 
401
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
 
402
      retval = -1;
 
403
    } else {
 
404
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
511
405
      free(decrypted_buffer);
512
 
    } else {
513
 
      retval = -1;
514
406
    }
515
407
  }
516
408
 
 
409
  free(buffer);
 
410
 
517
411
  //shutdown procedure
518
 
 
519
 
  if(debug){
520
 
    fprintf(stderr, "Closing TLS session\n");
521
 
  }
522
 
 
523
 
  free(buffer);
524
412
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
525
413
 exit:
526
414
  close(tcp_sd);
535
423
 
536
424
static void resolve_callback(
537
425
    AvahiSServiceResolver *r,
538
 
    AvahiIfIndex interface,
 
426
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
539
427
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
540
428
    AvahiResolverEvent event,
541
429
    const char *name,
544
432
    const char *host_name,
545
433
    const AvahiAddress *address,
546
434
    uint16_t port,
547
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
548
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
435
    AvahiStringList *txt,
 
436
    AvahiLookupResultFlags flags,
549
437
    AVAHI_GCC_UNUSED void* userdata) {
550
438
    
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(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);
573
 
      if (ret == 0){
574
 
        exit(EXIT_SUCCESS);
575
 
      }
 
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
        }
576
458
    }
577
 
  }
578
 
  avahi_s_service_resolver_free(r);
 
459
    avahi_s_service_resolver_free(r);
579
460
}
580
461
 
581
462
static void browse_callback(
590
471
    void* userdata) {
591
472
    
592
473
    AvahiServer *s = userdata;
593
 
    assert(b);                  /* Spurious warning */
594
 
    
595
 
    /* Called whenever a new services becomes available on the LAN or
596
 
       is removed from the LAN */
597
 
    
 
474
    assert(b);
 
475
 
 
476
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
 
477
 
598
478
    switch (event) {
599
 
    default:
600
 
    case AVAHI_BROWSER_FAILURE:
601
 
      
602
 
      fprintf(stderr, "(Browser) %s\n",
603
 
              avahi_strerror(avahi_server_errno(server)));
604
 
      avahi_simple_poll_quit(simple_poll);
605
 
      return;
606
 
      
607
 
    case AVAHI_BROWSER_NEW:
608
 
      /* We ignore the returned resolver object. In the callback
609
 
         function we free it. If the server is terminated before
610
 
         the callback function is called the server will free
611
 
         the resolver for us. */
612
 
      
613
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
614
 
                                         type, domain,
615
 
                                         AVAHI_PROTO_INET6, 0,
616
 
                                         resolve_callback, s)))
617
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
618
 
                avahi_strerror(avahi_server_errno(s)));
619
 
      break;
620
 
      
621
 
    case AVAHI_BROWSER_REMOVE:
622
 
      break;
623
 
      
624
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
625
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
626
 
      break;
 
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;
627
503
    }
628
504
}
629
505
 
630
 
/* combinds file name and path and returns the malloced new string. som sane checks could/should be added */
631
 
const char *combinepath(const char *first, const char *second){
632
 
  char *tmp;
633
 
  tmp = malloc(strlen(first) + strlen(second) + 2);
634
 
  if (tmp == NULL){
635
 
    perror("malloc");
636
 
    return NULL;
637
 
  }
638
 
  strcpy(tmp, first);
639
 
  if (first[0] != '\0' and first[strlen(first) - 1] != '/'){
640
 
    strcat(tmp, "/");
641
 
  }
642
 
  strcat(tmp, second);
643
 
  return tmp;
644
 
}
645
 
 
646
 
 
647
506
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
648
507
    AvahiServerConfig config;
649
508
    AvahiSServiceBrowser *sb = NULL;
650
509
    int error;
651
 
    int ret;
652
 
    int returncode = EXIT_SUCCESS;
653
 
    const char *interface = NULL;
654
 
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
655
 
    char *connect_to = NULL;
656
 
    
657
 
    while (true){
658
 
      static struct option long_options[] = {
659
 
        {"debug", no_argument, (int *)&debug, 1},
660
 
        {"connect", required_argument, 0, 'C'},
661
 
        {"interface", required_argument, 0, 'i'},
662
 
        {"certdir", required_argument, 0, 'd'},
663
 
        {"certkey", required_argument, 0, 'c'},
664
 
        {"certfile", required_argument, 0, 'k'},
665
 
        {0, 0, 0, 0} };
666
 
      
667
 
      int option_index = 0;
668
 
      ret = getopt_long (argc, argv, "i:", long_options,
669
 
                         &option_index);
670
 
      
671
 
      if (ret == -1){
672
 
        break;
673
 
      }
674
 
      
675
 
      switch(ret){
676
 
      case 0:
677
 
        break;
678
 
      case 'i':
679
 
        interface = optarg;
680
 
        break;
681
 
      case 'C':
682
 
        connect_to = optarg;
683
 
        break;
684
 
      case 'd':
685
 
        certdir = optarg;
686
 
        break;
687
 
      case 'c':
688
 
        certfile = optarg;
689
 
        break;
690
 
      case 'k':
691
 
        certkey = optarg;
692
 
        break;
693
 
      default:
694
 
        exit(EXIT_FAILURE);
695
 
      }
696
 
    }
 
510
    int ret = 1;
697
511
 
698
 
    certfile = combinepath(certdir, certfile);
699
 
    if (certfile == NULL){
700
 
      goto exit;
701
 
    }
702
 
    
703
 
    if(interface != NULL){
704
 
      if_index = (AvahiIfIndex) if_nametoindex(interface);
705
 
      if(if_index == 0){
706
 
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
707
 
        exit(EXIT_FAILURE);
708
 
      }
709
 
    }
710
 
    
711
 
    if(connect_to != NULL){
712
 
      /* Connect directly, do not use Zeroconf */
713
 
      /* (Mainly meant for debugging) */
714
 
      char *address = strrchr(connect_to, ':');
715
 
      if(address == NULL){
716
 
        fprintf(stderr, "No colon in address\n");
717
 
        exit(EXIT_FAILURE);
718
 
      }
719
 
      errno = 0;
720
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
721
 
      if(errno){
722
 
        perror("Bad port number");
723
 
        exit(EXIT_FAILURE);
724
 
      }
725
 
      *address = '\0';
726
 
      address = connect_to;
727
 
      ret = start_mandos_communication(address, port, if_index);
728
 
      if(ret < 0){
729
 
        exit(EXIT_FAILURE);
730
 
      } else {
731
 
        exit(EXIT_SUCCESS);
732
 
      }
733
 
    }
734
 
    
735
 
    certkey = combinepath(certdir, certkey);
736
 
    if (certkey == NULL){
737
 
      goto exit;
738
 
    }
739
 
    
740
 
    if (not debug){
741
 
      avahi_set_log_function(empty_log);
742
 
    }
 
512
    avahi_set_log_function(empty_log);
743
513
    
744
514
    /* Initialize the psuedo-RNG */
745
 
    srand((unsigned int) time(NULL));
 
515
    srand(time(NULL));
746
516
 
747
517
    /* Allocate main loop object */
748
518
    if (!(simple_poll = avahi_simple_poll_new())) {
749
519
        fprintf(stderr, "Failed to create simple poll object.\n");
750
 
        
751
 
        goto exit;
 
520
        goto fail;
752
521
    }
753
522
 
754
523
    /* Do not publish any local records */
758
527
    config.publish_workstation = 0;
759
528
    config.publish_domain = 0;
760
529
 
 
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
    
761
535
    /* Allocate a new server */
762
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
763
 
                              &config, NULL, NULL, &error);
 
536
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
764
537
 
765
538
    /* Free the configuration data */
766
539
    avahi_server_config_free(&config);
767
540
 
768
 
    /* Check if creating the server object succeeded */
 
541
    /* Check wether creating the server object succeeded */
769
542
    if (!server) {
770
 
        fprintf(stderr, "Failed to create server: %s\n",
771
 
                avahi_strerror(error));
772
 
        returncode = EXIT_FAILURE;
773
 
        goto exit;
 
543
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
544
        goto fail;
774
545
    }
775
546
    
776
547
    /* Create the service browser */
777
 
    sb = avahi_s_service_browser_new(server, if_index,
778
 
                                     AVAHI_PROTO_INET6,
779
 
                                     "_mandos._tcp", NULL, 0,
780
 
                                     browse_callback, server);
781
 
    if (!sb) {
782
 
        fprintf(stderr, "Failed to create service browser: %s\n",
783
 
                avahi_strerror(avahi_server_errno(server)));
784
 
        returncode = EXIT_FAILURE;
785
 
        goto exit;
 
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;
786
551
    }
787
552
    
788
553
    /* Run the main loop */
789
 
 
790
 
    if (debug){
791
 
      fprintf(stderr, "Starting avahi loop search\n");
792
 
    }
793
 
    
794
554
    avahi_simple_poll_loop(simple_poll);
795
555
    
796
 
 exit:
797
 
 
798
 
    if (debug){
799
 
      fprintf(stderr, "%s exiting\n", argv[0]);
800
 
    }
 
556
    ret = 0;
 
557
    
 
558
fail:
801
559
    
802
560
    /* Cleanup things */
803
561
    if (sb)
808
566
 
809
567
    if (simple_poll)
810
568
        avahi_simple_poll_free(simple_poll);
811
 
    free(certfile);
812
 
    free(certkey);
813
 
    
814
 
    return returncode;
 
569
 
 
570
    return ret;
815
571
}