/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 Copyright © 2007-2008 Teddy Hogeborn and Björn
12
 
 * Påhlsson.
13
 
 * 
14
 
 * This program is free software: you can redistribute it and/or
15
 
 * modify it under the terms of the GNU General Public License as
16
 
 * published by the Free Software Foundation, either version 3 of the
17
 
 * License, or (at your option) any later version.
18
 
 * 
19
 
 * This program is distributed in the hope that it will be useful, but
20
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
21
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22
 
 * General Public License for more details.
23
 
 * 
24
 
 * You should have received a copy of the GNU General Public License
25
 
 * along with this program.  If not, see
26
 
 * <http://www.gnu.org/licenses/>.
27
 
 * 
28
 
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
29
 
 * <https://www.fukt.bsnet.se/~teddy/>.
 
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.
30
12
 */
31
13
 
32
 
#define _FORTIFY_SOURCE 2
 
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
***/
33
32
 
34
33
#define _LARGEFILE_SOURCE
35
34
#define _FILE_OFFSET_BITS 64
48
47
#include <avahi-common/error.h>
49
48
 
50
49
//mandos client part
51
 
#include <sys/types.h>          /* socket(), inet_pton() */
52
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
53
 
                                   struct in6_addr, inet_pton() */
54
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
55
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
 
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 */
56
54
 
57
55
#include <unistd.h>             /* close() */
58
56
#include <netinet/in.h>
65
63
#include <errno.h>              /* perror() */
66
64
#include <gpgme.h>
67
65
 
68
 
// getopt long
69
 
#include <getopt.h>
70
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"
71
72
#define BUFFER_SIZE 256
72
73
#define DH_BITS 1024
73
74
 
74
 
const char *certdir = "/conf/conf.d/cryptkeyreq/";
75
 
const char *certfile = "openpgp-client.txt";
76
 
const char *certkey = "openpgp-client-key.txt";
77
 
 
78
 
bool debug = false;
79
 
 
80
75
typedef struct {
81
76
  gnutls_session_t session;
82
77
  gnutls_certificate_credentials_t cred;
84
79
} encrypted_session;
85
80
 
86
81
 
87
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
 
                            char **new_packet, const char *homedir){
 
82
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
89
83
  gpgme_data_t dh_crypto, dh_plain;
90
84
  gpgme_ctx_t ctx;
91
85
  gpgme_error_t rc;
92
86
  ssize_t ret;
93
 
  ssize_t new_packet_capacity = 0;
94
 
  ssize_t new_packet_length = 0;
 
87
  size_t new_packet_capacity = 0;
 
88
  size_t new_packet_length = 0;
95
89
  gpgme_engine_info_t engine_info;
96
90
 
97
 
  if (debug){
98
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
99
 
  }
100
 
  
101
91
  /* Init GPGME */
102
92
  gpgme_check_version(NULL);
103
 
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
104
 
  if (rc != GPG_ERR_NO_ERROR){
105
 
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
106
 
            gpgme_strsource(rc), gpgme_strerror(rc));
107
 
    return -1;
108
 
  }
 
93
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
109
94
  
110
95
  /* Set GPGME home directory */
111
96
  rc = gpgme_get_engine_info (&engine_info);
151
136
    return -1;
152
137
  }
153
138
  
154
 
  /* Decrypt data from the FILE pointer to the plaintext data
155
 
     buffer */
 
139
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
156
140
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
157
141
  if (rc != GPG_ERR_NO_ERROR){
158
142
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
159
143
            gpgme_strsource(rc), gpgme_strerror(rc));
160
144
    return -1;
161
145
  }
162
 
 
163
 
  if(debug){
164
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
165
 
  }
166
 
 
167
 
  if (debug){
168
 
    gpgme_decrypt_result_t result;
169
 
    result = gpgme_op_decrypt_result(ctx);
170
 
    if (result == NULL){
171
 
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
172
 
    } else {
173
 
      fprintf(stderr, "Unsupported algorithm: %s\n",
174
 
              result->unsupported_algorithm);
175
 
      fprintf(stderr, "Wrong key usage: %d\n",
176
 
              result->wrong_key_usage);
177
 
      if(result->file_name != NULL){
178
 
        fprintf(stderr, "File name: %s\n", result->file_name);
179
 
      }
180
 
      gpgme_recipient_t recipient;
181
 
      recipient = result->recipients;
182
 
      if(recipient){
183
 
        while(recipient != NULL){
184
 
          fprintf(stderr, "Public key algorithm: %s\n",
185
 
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
186
 
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
187
 
          fprintf(stderr, "Secret key available: %s\n",
188
 
                  recipient->status == GPG_ERR_NO_SECKEY
189
 
                  ? "No" : "Yes");
190
 
          recipient = recipient->next;
191
 
        }
192
 
      }
193
 
    }
194
 
  }
195
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
 
196
167
  /* Delete the GPGME FILE pointer cryptotext data buffer */
197
168
  gpgme_data_release(dh_crypto);
198
169
  
199
170
  /* Seek back to the beginning of the GPGME plaintext data buffer */
200
 
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
 
171
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
201
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
 
                               unsigned int 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\n", ip);
366
 
  }
 
307
 
367
308
  
368
309
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
369
310
  if(tcp_sd < 0) {
371
312
    return -1;
372
313
  }
373
314
  
374
 
  if(if_indextoname(if_index, interface) == NULL){
375
 
    if(debug){
376
 
      perror("if_indextoname");
377
 
    }
 
315
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
 
316
  if(tcp_sd < 0) {
 
317
    perror("setsockopt bindtodevice");
378
318
    return -1;
379
319
  }
380
320
  
381
 
  if(debug){
382
 
    fprintf(stderr, "Binding to interface %s\n", interface);
383
 
  }
384
 
  
385
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
 
321
  memset(&to,0,sizeof(to));
386
322
  to.sin6_family = AF_INET6;
387
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
323
  ret = inet_pton(AF_INET6, ip, &ip_addr);
388
324
  if (ret < 0 ){
389
325
    perror("inet_pton");
390
326
    return -1;
393
329
    fprintf(stderr, "Bad address: %s\n", ip);
394
330
    return -1;
395
331
  }
396
 
  to.sin6_port = htons(port);   /* Spurious warning */
397
 
  
398
 
  to.sin6_scope_id = (uint32_t)if_index;
399
 
  
400
 
  if(debug){
401
 
    fprintf(stderr, "Connection to: %s\n", ip);
402
 
  }
 
332
  to.sin6_port = htons(port);
 
333
  to.sin6_scope_id = if_nametoindex("eth0");
403
334
  
404
335
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
405
336
  if (ret < 0){
412
343
    retval = -1;
413
344
    return -1;
414
345
  }
415
 
  
416
 
  gnutls_transport_set_ptr (es.session,
417
 
                            (gnutls_transport_ptr_t) tcp_sd);
418
 
  
419
 
  if(debug){
420
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
421
 
  }
422
 
  
 
346
    
 
347
  
 
348
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
 
349
 
423
350
  ret = gnutls_handshake (es.session);
424
351
  
425
352
  if (ret != GNUTLS_E_SUCCESS){
426
 
    if(debug){
427
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
428
 
      gnutls_perror (ret);
429
 
    }
 
353
    fprintf(stderr, "\n*** Handshake failed ***\n");
 
354
    gnutls_perror (ret);
430
355
    retval = -1;
431
356
    goto exit;
432
357
  }
433
 
  
434
 
  //Retrieve OpenPGP packet that contains the wanted password
435
 
  
436
 
  if(debug){
437
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
438
 
            ip);
439
 
  }
440
358
 
 
359
  //retrive password
441
360
  while(true){
442
361
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
443
362
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
468
387
        }
469
388
        break;
470
389
      default:
471
 
        fprintf(stderr, "Unknown error while reading data from"
472
 
                " encrypted session with mandos server\n");
 
390
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
473
391
        retval = -1;
474
392
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
475
393
        goto exit;
476
394
      }
477
395
    } else {
478
 
      buffer_length += (size_t) ret;
 
396
      buffer_length += ret;
479
397
    }
480
398
  }
481
 
  
 
399
 
482
400
  if (buffer_length > 0){
483
 
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
484
 
                                               buffer_length,
485
 
                                               &decrypted_buffer,
486
 
                                               certdir);
487
 
    if (decrypted_buffer_size >= 0){
488
 
      while(written < decrypted_buffer_size){
489
 
        ret = (int)fwrite (decrypted_buffer + written, 1,
490
 
                           (size_t)decrypted_buffer_size - written,
491
 
                           stdout);
492
 
        if(ret == 0 and ferror(stdout)){
493
 
          if(debug){
494
 
            fprintf(stderr, "Error writing encrypted data: %s\n",
495
 
                    strerror(errno));
496
 
          }
497
 
          retval = -1;
498
 
          break;
499
 
        }
500
 
        written += (size_t)ret;
501
 
      }
 
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);
502
405
      free(decrypted_buffer);
503
 
    } else {
504
 
      retval = -1;
505
406
    }
506
407
  }
507
408
 
 
409
  free(buffer);
 
410
 
508
411
  //shutdown procedure
509
 
 
510
 
  if(debug){
511
 
    fprintf(stderr, "Closing TLS session\n");
512
 
  }
513
 
 
514
 
  free(buffer);
515
412
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
516
413
 exit:
517
414
  close(tcp_sd);
526
423
 
527
424
static void resolve_callback(
528
425
    AvahiSServiceResolver *r,
529
 
    AvahiIfIndex interface,
 
426
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
530
427
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
531
428
    AvahiResolverEvent event,
532
429
    const char *name,
535
432
    const char *host_name,
536
433
    const AvahiAddress *address,
537
434
    uint16_t port,
538
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
539
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
435
    AvahiStringList *txt,
 
436
    AvahiLookupResultFlags flags,
540
437
    AVAHI_GCC_UNUSED void* userdata) {
541
438
    
542
 
  assert(r);                    /* Spurious warning */
543
 
  
544
 
  /* Called whenever a service has been resolved successfully or
545
 
     timed out */
546
 
  
547
 
  switch (event) {
548
 
  default:
549
 
  case AVAHI_RESOLVER_FAILURE:
550
 
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
551
 
            " type '%s' in domain '%s': %s\n", name, type, domain,
552
 
            avahi_strerror(avahi_server_errno(server)));
553
 
    break;
554
 
    
555
 
  case AVAHI_RESOLVER_FOUND:
556
 
    {
557
 
      char ip[AVAHI_ADDRESS_STR_MAX];
558
 
      avahi_address_snprint(ip, sizeof(ip), address);
559
 
      if(debug){
560
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
561
 
                " port %d\n", name, host_name, ip, port);
562
 
      }
563
 
      int ret = start_mandos_communication(ip, port,
564
 
                                           (unsigned int) interface);
565
 
      if (ret == 0){
566
 
        exit(EXIT_SUCCESS);
567
 
      }
 
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
        }
568
458
    }
569
 
  }
570
 
  avahi_s_service_resolver_free(r);
 
459
    avahi_s_service_resolver_free(r);
571
460
}
572
461
 
573
462
static void browse_callback(
582
471
    void* userdata) {
583
472
    
584
473
    AvahiServer *s = userdata;
585
 
    assert(b);                  /* Spurious warning */
586
 
    
587
 
    /* Called whenever a new services becomes available on the LAN or
588
 
       is removed from the LAN */
589
 
    
 
474
    assert(b);
 
475
 
 
476
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
 
477
 
590
478
    switch (event) {
591
 
    default:
592
 
    case AVAHI_BROWSER_FAILURE:
593
 
      
594
 
      fprintf(stderr, "(Browser) %s\n",
595
 
              avahi_strerror(avahi_server_errno(server)));
596
 
      avahi_simple_poll_quit(simple_poll);
597
 
      return;
598
 
      
599
 
    case AVAHI_BROWSER_NEW:
600
 
      /* We ignore the returned resolver object. In the callback
601
 
         function we free it. If the server is terminated before
602
 
         the callback function is called the server will free
603
 
         the resolver for us. */
604
 
      
605
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
606
 
                                         type, domain,
607
 
                                         AVAHI_PROTO_INET6, 0,
608
 
                                         resolve_callback, s)))
609
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
610
 
                avahi_strerror(avahi_server_errno(s)));
611
 
      break;
612
 
      
613
 
    case AVAHI_BROWSER_REMOVE:
614
 
      break;
615
 
      
616
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
617
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
618
 
      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;
619
503
    }
620
504
}
621
505
 
622
 
/* combinds two strings and returns the malloced new string. som sane checks could/should be added */
623
 
const char *combinestrings(const char *first, const char *second){
624
 
  char *tmp;
625
 
  tmp = malloc(strlen(first) + strlen(second));
626
 
  if (tmp == NULL){
627
 
    perror("malloc");
628
 
    return NULL;
629
 
  }
630
 
  strcpy(tmp, first);
631
 
  strcat(tmp, second);
632
 
  return tmp;
633
 
}
634
 
 
635
 
 
636
506
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
637
507
    AvahiServerConfig config;
638
508
    AvahiSServiceBrowser *sb = NULL;
639
509
    int error;
640
 
    int ret;
641
 
    int returncode = EXIT_SUCCESS;
642
 
    const char *interface = "eth0";
643
 
    
644
 
    while (true){
645
 
      static struct option long_options[] = {
646
 
        {"debug", no_argument, (int *)&debug, 1},
647
 
        {"interface", required_argument, 0, 'i'},
648
 
        {"certdir", required_argument, 0, 'd'},
649
 
        {"certkey", required_argument, 0, 'c'},
650
 
        {"certfile", required_argument, 0, 'k'},
651
 
        {0, 0, 0, 0} };
652
 
      
653
 
      int option_index = 0;
654
 
      ret = getopt_long (argc, argv, "i:", long_options,
655
 
                         &option_index);
656
 
      
657
 
      if (ret == -1){
658
 
        break;
659
 
      }
660
 
      
661
 
      switch(ret){
662
 
      case 0:
663
 
        break;
664
 
      case 'i':
665
 
        interface = optarg;
666
 
        break;
667
 
      case 'd':
668
 
        certdir = optarg;
669
 
        break;
670
 
      case 'c':
671
 
        certfile = optarg;
672
 
        break;
673
 
      case 'k':
674
 
        certkey = optarg;
675
 
        break;
676
 
      default:
677
 
        exit(EXIT_FAILURE);
678
 
      }
679
 
    }
 
510
    int ret = 1;
680
511
 
681
 
    certfile = combinestrings(certdir, certfile);
682
 
    if (certfile == NULL){
683
 
      goto exit;
684
 
    }
685
 
    
686
 
    certkey = combinestrings(certdir, certkey);
687
 
    if (certkey == NULL){
688
 
      goto exit;
689
 
    }
690
 
        
691
 
    if (not debug){
692
 
      avahi_set_log_function(empty_log);
693
 
    }
 
512
    avahi_set_log_function(empty_log);
694
513
    
695
514
    /* Initialize the psuedo-RNG */
696
 
    srand((unsigned int) time(NULL));
 
515
    srand(time(NULL));
697
516
 
698
517
    /* Allocate main loop object */
699
518
    if (!(simple_poll = avahi_simple_poll_new())) {
700
519
        fprintf(stderr, "Failed to create simple poll object.\n");
701
 
        
702
 
        goto exit;
 
520
        goto fail;
703
521
    }
704
522
 
705
523
    /* Do not publish any local records */
709
527
    config.publish_workstation = 0;
710
528
    config.publish_domain = 0;
711
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
    
712
535
    /* Allocate a new server */
713
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
714
 
                              &config, NULL, NULL, &error);
 
536
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
715
537
 
716
538
    /* Free the configuration data */
717
539
    avahi_server_config_free(&config);
718
540
 
719
 
    /* Check if creating the server object succeeded */
 
541
    /* Check wether creating the server object succeeded */
720
542
    if (!server) {
721
 
        fprintf(stderr, "Failed to create server: %s\n",
722
 
                avahi_strerror(error));
723
 
        returncode = EXIT_FAILURE;
724
 
        goto exit;
 
543
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
544
        goto fail;
725
545
    }
726
546
    
727
547
    /* Create the service browser */
728
 
    sb = avahi_s_service_browser_new(server,
729
 
                                     (AvahiIfIndex)
730
 
                                     if_nametoindex(interface),
731
 
                                     AVAHI_PROTO_INET6,
732
 
                                     "_mandos._tcp", NULL, 0,
733
 
                                     browse_callback, server);
734
 
    if (!sb) {
735
 
        fprintf(stderr, "Failed to create service browser: %s\n",
736
 
                avahi_strerror(avahi_server_errno(server)));
737
 
        returncode = EXIT_FAILURE;
738
 
        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;
739
551
    }
740
552
    
741
553
    /* Run the main loop */
742
 
 
743
 
    if (debug){
744
 
      fprintf(stderr, "Starting avahi loop search\n");
745
 
    }
746
 
    
747
554
    avahi_simple_poll_loop(simple_poll);
748
555
    
749
 
 exit:
750
 
 
751
 
    if (debug){
752
 
      fprintf(stderr, "%s exiting\n", argv[0]);
753
 
    }
 
556
    ret = 0;
 
557
    
 
558
fail:
754
559
    
755
560
    /* Cleanup things */
756
561
    if (sb)
762
567
    if (simple_poll)
763
568
        avahi_simple_poll_free(simple_poll);
764
569
 
765
 
    return returncode;
 
570
    return ret;
766
571
}