/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-01 06:56:27 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080801065627-2c7k4ydefjgacgnq
* plugins.d/plugbasedclient.c (set_cloexec_flag): New function.
  (main): Use the set_cloexec_flag function.  Move inserting of global
  arguments to before the fork.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id$ */
2
 
 
3
 
/* PLEASE NOTE *
4
 
 * This file demonstrates how to use Avahi's core API, this is
5
 
 * the embeddable mDNS stack for embedded applications.
 
1
/*  -*- coding: utf-8 -*- */
 
2
/*
 
3
 * Mandos client - get and decrypt data from a Mandos server
6
4
 *
7
 
 * End user applications should *not* use this API and should use
8
 
 * the D-Bus or C APIs, please see
9
 
 * client-browse-services.c and glib-integration.c
10
 
 * 
11
 
 * I repeat, you probably do *not* want to use this example.
 
5
 * This program is partly derived from an example program for an Avahi
 
6
 * service browser, downloaded from
 
7
 * <http://avahi.org/browser/examples/core-browse-services.c>.  This
 
8
 * includes the following functions: "resolve_callback",
 
9
 * "browse_callback", and parts of "main".
 
10
 * 
 
11
 * Everything else is
 
12
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
13
 * 
 
14
 * This program is free software: you can redistribute it and/or
 
15
 * modify it under the terms of the GNU General Public License as
 
16
 * published by the Free Software Foundation, either version 3 of the
 
17
 * License, or (at your option) any later version.
 
18
 * 
 
19
 * This program is distributed in the hope that it will be useful, but
 
20
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
22
 * General Public License for more details.
 
23
 * 
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program.  If not, see
 
26
 * <http://www.gnu.org/licenses/>.
 
27
 * 
 
28
 * Contact the authors at <mandos@fukt.bsnet.se>.
12
29
 */
13
30
 
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
 
 
 
31
/* Needed by GPGME, specifically gpgme_data_seek() */
33
32
#define _LARGEFILE_SOURCE
34
33
#define _FILE_OFFSET_BITS 64
35
34
 
47
46
#include <avahi-common/error.h>
48
47
 
49
48
//mandos client part
50
 
#include <sys/types.h>          /* socket(), setsockopt(), inet_pton() */
51
 
#include <sys/socket.h>         /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */
52
 
#include <gnutls/gnutls.h>      /* ALL GNUTLS STUFF */
53
 
#include <gnutls/openpgp.h>     /* gnutls with openpgp stuff */
 
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 */
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>
66
68
 
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"
72
69
#define BUFFER_SIZE 256
73
70
#define DH_BITS 1024
74
71
 
 
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
 
75
78
typedef struct {
76
79
  gnutls_session_t session;
77
80
  gnutls_certificate_credentials_t cred;
79
82
} encrypted_session;
80
83
 
81
84
 
82
 
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
 
85
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
86
                            char **new_packet, const char *homedir){
83
87
  gpgme_data_t dh_crypto, dh_plain;
84
88
  gpgme_ctx_t ctx;
85
89
  gpgme_error_t rc;
86
90
  ssize_t ret;
87
 
  size_t new_packet_capacity = 0;
88
 
  size_t new_packet_length = 0;
 
91
  ssize_t new_packet_capacity = 0;
 
92
  ssize_t new_packet_length = 0;
89
93
  gpgme_engine_info_t engine_info;
90
94
 
 
95
  if (debug){
 
96
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
97
  }
 
98
  
91
99
  /* Init GPGME */
92
100
  gpgme_check_version(NULL);
93
 
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
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
  }
94
107
  
95
108
  /* Set GPGME home directory */
96
109
  rc = gpgme_get_engine_info (&engine_info);
136
149
    return -1;
137
150
  }
138
151
  
139
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
152
  /* Decrypt data from the FILE pointer to the plaintext data
 
153
     buffer */
140
154
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
141
155
  if (rc != GPG_ERR_NO_ERROR){
142
156
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
143
157
            gpgme_strsource(rc), gpgme_strerror(rc));
144
158
    return -1;
145
159
  }
 
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
  }
146
193
  
147
 
/*   gpgme_decrypt_result_t result; */
148
 
/*   result = gpgme_op_decrypt_result(ctx); */
149
 
/*   fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm); */
150
 
/*   fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage); */
151
 
/*   if(result->file_name != NULL){ */
152
 
/*     fprintf(stderr, "File name: %s\n", result->file_name); */
153
 
/*   } */
154
 
/*   gpgme_recipient_t recipient; */
155
 
/*   recipient = result->recipients; */
156
 
/*   if(recipient){ */
157
 
/*     while(recipient != NULL){ */
158
 
/*       fprintf(stderr, "Public key algorithm: %s\n", */
159
 
/*            gpgme_pubkey_algo_name(recipient->pubkey_algo)); */
160
 
/*       fprintf(stderr, "Key ID: %s\n", recipient->keyid); */
161
 
/*       fprintf(stderr, "Secret key available: %s\n", */
162
 
/*            recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes"); */
163
 
/*       recipient = recipient->next; */
164
 
/*     } */
165
 
/*   } */
166
 
 
167
194
  /* Delete the GPGME FILE pointer cryptotext data buffer */
168
195
  gpgme_data_release(dh_crypto);
169
196
  
170
197
  /* Seek back to the beginning of the GPGME plaintext data buffer */
171
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
172
 
 
 
198
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
 
199
    perror("pgpme_data_seek");
 
200
  }
 
201
  
173
202
  *new_packet = 0;
174
203
  while(true){
175
204
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
176
 
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
 
205
      *new_packet = realloc(*new_packet,
 
206
                            (unsigned int)new_packet_capacity
 
207
                            + BUFFER_SIZE);
177
208
      if (*new_packet == NULL){
178
209
        perror("realloc");
179
210
        return -1;
181
212
      new_packet_capacity += BUFFER_SIZE;
182
213
    }
183
214
    
184
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
 
215
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
216
                          BUFFER_SIZE);
185
217
    /* Print the data, if any */
186
218
    if (ret == 0){
187
 
      /* If password is empty, then a incorrect error will be printed */
188
219
      break;
189
220
    }
190
221
    if(ret < 0){
194
225
    new_packet_length += ret;
195
226
  }
196
227
 
197
 
   /* Delete the GPGME plaintext data buffer */
 
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 */
198
237
  gpgme_data_release(dh_plain);
199
238
  return new_packet_length;
200
239
}
206
245
  return ret;
207
246
}
208
247
 
209
 
void debuggnutls(int level, const char* string){
 
248
void debuggnutls(__attribute__((unused)) int level,
 
249
                 const char* string){
210
250
  fprintf(stderr, "%s", string);
211
251
}
212
252
 
214
254
  const char *err;
215
255
  int ret;
216
256
  
 
257
  if(debug){
 
258
    fprintf(stderr, "Initializing GnuTLS\n");
 
259
  }
 
260
 
217
261
  if ((ret = gnutls_global_init ())
218
262
      != GNUTLS_E_SUCCESS) {
219
263
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
220
264
    return -1;
221
265
  }
222
266
 
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
 
 
 
267
  if (debug){
 
268
    gnutls_global_set_log_level(11);
 
269
    gnutls_global_set_log_function(debuggnutls);
 
270
  }
 
271
  
228
272
  /* openpgp credentials */
229
273
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
230
274
      != GNUTLS_E_SUCCESS) {
231
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
275
    fprintf (stderr, "memory error: %s\n",
 
276
             safer_gnutls_strerror(ret));
232
277
    return -1;
233
278
  }
234
 
 
 
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
  
235
286
  ret = gnutls_certificate_set_openpgp_key_file
236
 
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
 
287
    (es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
237
288
  if (ret != GNUTLS_E_SUCCESS) {
238
289
    fprintf
239
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
240
 
       ret, CERTFILE, KEYFILE);
 
290
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
291
       " '%s')\n",
 
292
       ret, certfile, certkey);
241
293
    fprintf(stdout, "The Error is: %s\n",
242
294
            safer_gnutls_strerror(ret));
243
295
    return -1;
244
296
  }
245
 
 
246
 
  //Gnutls server initialization
 
297
  
 
298
  //GnuTLS server initialization
247
299
  if ((ret = gnutls_dh_params_init (&es->dh_params))
248
300
      != GNUTLS_E_SUCCESS) {
249
301
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
250
302
             safer_gnutls_strerror(ret));
251
303
    return -1;
252
304
  }
253
 
 
 
305
  
254
306
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
255
307
      != GNUTLS_E_SUCCESS) {
256
308
    fprintf (stderr, "Error in prime generation: %s\n",
257
309
             safer_gnutls_strerror(ret));
258
310
    return -1;
259
311
  }
260
 
 
 
312
  
261
313
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
262
 
 
263
 
  // Gnutls session creation
 
314
  
 
315
  // GnuTLS session creation
264
316
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
265
317
      != GNUTLS_E_SUCCESS){
266
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
318
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
267
319
            safer_gnutls_strerror(ret));
268
320
  }
269
 
 
 
321
  
270
322
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
271
323
      != GNUTLS_E_SUCCESS) {
272
324
    fprintf(stderr, "Syntax error at: %s\n", err);
273
 
    fprintf(stderr, "Gnutls error: %s\n",
 
325
    fprintf(stderr, "GnuTLS error: %s\n",
274
326
            safer_gnutls_strerror(ret));
275
327
    return -1;
276
328
  }
277
 
 
 
329
  
278
330
  if ((ret = gnutls_credentials_set
279
331
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
280
332
      != GNUTLS_E_SUCCESS) {
282
334
            safer_gnutls_strerror(ret));
283
335
    return -1;
284
336
  }
285
 
 
 
337
  
286
338
  /* ignore client certificate if any. */
287
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
339
  gnutls_certificate_server_set_request (es->session,
 
340
                                         GNUTLS_CERT_IGNORE);
288
341
  
289
342
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
290
343
  
291
344
  return 0;
292
345
}
293
346
 
294
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
347
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
348
               __attribute__((unused)) const char *txt){}
295
349
 
296
 
int start_mandos_communcation(char *ip, uint16_t port){
 
350
int start_mandos_communication(const char *ip, uint16_t port,
 
351
                               AvahiIfIndex if_index){
297
352
  int ret, tcp_sd;
298
353
  struct sockaddr_in6 to;
299
 
  struct in6_addr ip_addr;
300
354
  encrypted_session es;
301
355
  char *buffer = NULL;
302
356
  char *decrypted_buffer;
303
357
  size_t buffer_length = 0;
304
358
  size_t buffer_capacity = 0;
305
359
  ssize_t decrypted_buffer_size;
 
360
  size_t written = 0;
306
361
  int retval = 0;
307
 
 
 
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
  }
308
368
  
309
369
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
310
370
  if(tcp_sd < 0) {
312
372
    return -1;
313
373
  }
314
374
  
315
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
316
 
  if(tcp_sd < 0) {
317
 
    perror("setsockopt bindtodevice");
 
375
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
376
    if(debug){
 
377
      perror("if_indextoname");
 
378
    }
318
379
    return -1;
319
380
  }
320
381
  
321
 
  memset(&to,0,sizeof(to));
 
382
  if(debug){
 
383
    fprintf(stderr, "Binding to interface %s\n", interface);
 
384
  }
 
385
  
 
386
  memset(&to,0,sizeof(to));     /* Spurious warning */
322
387
  to.sin6_family = AF_INET6;
323
 
  ret = inet_pton(AF_INET6, ip, &ip_addr);
 
388
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
324
389
  if (ret < 0 ){
325
390
    perror("inet_pton");
326
391
    return -1;
329
394
    fprintf(stderr, "Bad address: %s\n", ip);
330
395
    return -1;
331
396
  }
332
 
  to.sin6_port = htons(port);
333
 
  to.sin6_scope_id = if_nametoindex("eth0");
 
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
  }
334
412
  
335
413
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
336
414
  if (ret < 0){
343
421
    retval = -1;
344
422
    return -1;
345
423
  }
346
 
    
347
 
  
348
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
349
 
 
 
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
  
350
432
  ret = gnutls_handshake (es.session);
351
433
  
352
434
  if (ret != GNUTLS_E_SUCCESS){
353
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
354
 
    gnutls_perror (ret);
 
435
    if(debug){
 
436
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
437
      gnutls_perror (ret);
 
438
    }
355
439
    retval = -1;
356
440
    goto exit;
357
441
  }
 
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
  }
358
449
 
359
 
  //retrive password
360
450
  while(true){
361
451
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
362
452
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
387
477
        }
388
478
        break;
389
479
      default:
390
 
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
480
        fprintf(stderr, "Unknown error while reading data from"
 
481
                " encrypted session with mandos server\n");
391
482
        retval = -1;
392
483
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
393
484
        goto exit;
394
485
      }
395
486
    } else {
396
 
      buffer_length += ret;
 
487
      buffer_length += (size_t) ret;
397
488
    }
398
489
  }
399
 
 
 
490
  
400
491
  if (buffer_length > 0){
401
 
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 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
      }
 
511
      free(decrypted_buffer);
 
512
    } else {
402
513
      retval = -1;
403
 
    } else {
404
 
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
405
 
      free(decrypted_buffer);
406
514
    }
407
515
  }
408
516
 
 
517
  //shutdown procedure
 
518
 
 
519
  if(debug){
 
520
    fprintf(stderr, "Closing TLS session\n");
 
521
  }
 
522
 
409
523
  free(buffer);
410
 
 
411
 
  //shutdown procedure
412
524
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
413
525
 exit:
414
526
  close(tcp_sd);
423
535
 
424
536
static void resolve_callback(
425
537
    AvahiSServiceResolver *r,
426
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
538
    AvahiIfIndex interface,
427
539
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
428
540
    AvahiResolverEvent event,
429
541
    const char *name,
432
544
    const char *host_name,
433
545
    const AvahiAddress *address,
434
546
    uint16_t port,
435
 
    AvahiStringList *txt,
436
 
    AvahiLookupResultFlags flags,
 
547
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
548
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
437
549
    AVAHI_GCC_UNUSED void* userdata) {
438
550
    
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
 
        }
 
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
      }
458
576
    }
459
 
    avahi_s_service_resolver_free(r);
 
577
  }
 
578
  avahi_s_service_resolver_free(r);
460
579
}
461
580
 
462
581
static void browse_callback(
471
590
    void* userdata) {
472
591
    
473
592
    AvahiServer *s = userdata;
474
 
    assert(b);
475
 
 
476
 
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
477
 
 
 
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
    
478
598
    switch (event) {
479
 
 
480
 
        case AVAHI_BROWSER_FAILURE:
481
 
            
482
 
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
483
 
            avahi_simple_poll_quit(simple_poll);
484
 
            return;
485
 
 
486
 
        case AVAHI_BROWSER_NEW:
487
 
            /* We ignore the returned resolver object. In the callback
488
 
               function we free it. If the server is terminated before
489
 
               the callback function is called the server will free
490
 
               the resolver for us. */
491
 
            
492
 
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
493
 
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
494
 
            
495
 
            break;
496
 
 
497
 
        case AVAHI_BROWSER_REMOVE:
498
 
            break;
499
 
 
500
 
        case AVAHI_BROWSER_ALL_FOR_NOW:
501
 
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
502
 
            break;
 
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;
503
627
    }
504
628
}
505
629
 
 
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
 
506
647
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
507
648
    AvahiServerConfig config;
508
649
    AvahiSServiceBrowser *sb = NULL;
509
650
    int error;
510
 
    int ret = 1;
 
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
    }
511
697
 
512
 
    avahi_set_log_function(empty_log);
 
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
    }
513
743
    
514
744
    /* Initialize the psuedo-RNG */
515
 
    srand(time(NULL));
 
745
    srand((unsigned int) time(NULL));
516
746
 
517
747
    /* Allocate main loop object */
518
748
    if (!(simple_poll = avahi_simple_poll_new())) {
519
749
        fprintf(stderr, "Failed to create simple poll object.\n");
520
 
        goto fail;
 
750
        
 
751
        goto exit;
521
752
    }
522
753
 
523
754
    /* Do not publish any local records */
527
758
    config.publish_workstation = 0;
528
759
    config.publish_domain = 0;
529
760
 
530
 
/*     /\* Set a unicast DNS server for wide area DNS-SD *\/ */
531
 
/*     avahi_address_parse("193.11.177.11", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]); */
532
 
/*     config.n_wide_area_servers = 1; */
533
 
/*     config.enable_wide_area = 1; */
534
 
    
535
761
    /* Allocate a new server */
536
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
762
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
763
                              &config, NULL, NULL, &error);
537
764
 
538
765
    /* Free the configuration data */
539
766
    avahi_server_config_free(&config);
540
767
 
541
 
    /* Check wether creating the server object succeeded */
 
768
    /* Check if creating the server object succeeded */
542
769
    if (!server) {
543
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
544
 
        goto fail;
 
770
        fprintf(stderr, "Failed to create server: %s\n",
 
771
                avahi_strerror(error));
 
772
        returncode = EXIT_FAILURE;
 
773
        goto exit;
545
774
    }
546
775
    
547
776
    /* Create the service browser */
548
 
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
549
 
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
550
 
        goto fail;
 
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;
551
786
    }
552
787
    
553
788
    /* Run the main loop */
 
789
 
 
790
    if (debug){
 
791
      fprintf(stderr, "Starting avahi loop search\n");
 
792
    }
 
793
    
554
794
    avahi_simple_poll_loop(simple_poll);
555
795
    
556
 
    ret = 0;
557
 
    
558
 
fail:
 
796
 exit:
 
797
 
 
798
    if (debug){
 
799
      fprintf(stderr, "%s exiting\n", argv[0]);
 
800
    }
559
801
    
560
802
    /* Cleanup things */
561
803
    if (sb)
566
808
 
567
809
    if (simple_poll)
568
810
        avahi_simple_poll_free(simple_poll);
569
 
 
570
 
    return ret;
 
811
    free(certfile);
 
812
    free(certkey);
 
813
    
 
814
    return returncode;
571
815
}