/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-02 21:06:12 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080802210612-4c1waup4z0f66ya7
Non-tested commit for merge purposes.

* plugbasedclient.c (getplugin, addargument, set_cloexec): Made static.

* plugins.d/passprompt.c (termination_handler): Made static.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***
2
 
  This file is part of avahi.
3
 
 
4
 
  avahi is free software; you can redistribute it and/or modify it
5
 
  under the terms of the GNU Lesser General Public License as
6
 
  published by the Free Software Foundation; either version 2.1 of the
7
 
  License, or (at your option) any later version.
8
 
 
9
 
  avahi is distributed in the hope that it will be useful, but WITHOUT
10
 
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11
 
  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12
 
  Public License for more details.
13
 
 
14
 
  You should have received a copy of the GNU Lesser General Public
15
 
  License along with avahi; if not, write to the Free Software
16
 
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17
 
  USA.
18
 
***/
 
1
/*  -*- coding: utf-8 -*- */
 
2
/*
 
3
 * Mandos client - get and decrypt data from a Mandos server
 
4
 *
 
5
 * This program is partly derived from an example program for an Avahi
 
6
 * service browser, downloaded from
 
7
 * <http://avahi.org/browser/examples/core-browse-services.c>.  This
 
8
 * includes the following functions: "resolve_callback",
 
9
 * "browse_callback", and parts of "main".
 
10
 * 
 
11
 * Everything else is
 
12
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
13
 * 
 
14
 * This program is free software: you can redistribute it and/or
 
15
 * modify it under the terms of the GNU General Public License as
 
16
 * published by the Free Software Foundation, either version 3 of the
 
17
 * License, or (at your option) any later version.
 
18
 * 
 
19
 * This program is distributed in the hope that it will be useful, but
 
20
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
22
 * General Public License for more details.
 
23
 * 
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program.  If not, see
 
26
 * <http://www.gnu.org/licenses/>.
 
27
 * 
 
28
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
29
 */
19
30
 
 
31
/* Needed by GPGME, specifically gpgme_data_seek() */
20
32
#define _LARGEFILE_SOURCE
21
33
#define _FILE_OFFSET_BITS 64
22
34
 
34
46
#include <avahi-common/error.h>
35
47
 
36
48
//mandos client part
37
 
#include <sys/types.h>          /* socket(), setsockopt(), inet_pton() */
38
 
#include <sys/socket.h>         /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */
39
 
#include <gnutls/gnutls.h>      /* ALL GNUTLS STUFF */
40
 
#include <gnutls/openpgp.h>     /* gnutls with openpgp stuff */
 
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 */
41
54
 
42
55
#include <unistd.h>             /* close() */
43
56
#include <netinet/in.h>
50
63
#include <errno.h>              /* perror() */
51
64
#include <gpgme.h>
52
65
 
 
66
// getopt_long
 
67
#include <getopt.h>
53
68
 
54
 
#ifndef CERT_ROOT
55
 
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
56
 
#endif
57
 
#define CERTFILE CERT_ROOT "openpgp-client.txt"
58
 
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
59
69
#define BUFFER_SIZE 256
60
 
#define DH_BITS 1024
 
70
 
 
71
static int dh_bits = 1024;
 
72
 
 
73
static const char *keydir = "/conf/conf.d/mandos";
 
74
static const char *pubkeyfile = "pubkey.txt";
 
75
static const char *seckeyfile = "seckey.txt";
61
76
 
62
77
bool debug = false;
63
78
 
 
79
/* Used for  */
64
80
typedef struct {
65
81
  gnutls_session_t session;
66
82
  gnutls_certificate_credentials_t cred;
68
84
} encrypted_session;
69
85
 
70
86
 
71
 
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
 
87
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
88
                                   char **new_packet,
 
89
                                   const char *homedir){
72
90
  gpgme_data_t dh_crypto, dh_plain;
73
91
  gpgme_ctx_t ctx;
74
92
  gpgme_error_t rc;
75
93
  ssize_t ret;
76
 
  size_t new_packet_capacity = 0;
77
 
  size_t new_packet_length = 0;
 
94
  ssize_t new_packet_capacity = 0;
 
95
  ssize_t new_packet_length = 0;
78
96
  gpgme_engine_info_t engine_info;
79
97
 
80
98
  if (debug){
81
 
    fprintf(stderr, "Attempting to decrypt password from gpg packet\n");
 
99
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
82
100
  }
83
101
  
84
102
  /* Init GPGME */
85
103
  gpgme_check_version(NULL);
86
 
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
104
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
105
  if (rc != GPG_ERR_NO_ERROR){
 
106
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
 
107
            gpgme_strsource(rc), gpgme_strerror(rc));
 
108
    return -1;
 
109
  }
87
110
  
88
111
  /* Set GPGME home directory */
89
112
  rc = gpgme_get_engine_info (&engine_info);
129
152
    return -1;
130
153
  }
131
154
  
132
 
  /* Decrypt data from the FILE pointer to the plaintext data buffer */
 
155
  /* Decrypt data from the FILE pointer to the plaintext data
 
156
     buffer */
133
157
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
134
158
  if (rc != GPG_ERR_NO_ERROR){
135
159
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
138
162
  }
139
163
 
140
164
  if(debug){
141
 
    fprintf(stderr, "decryption of gpg packet succeeded\n");
 
165
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
142
166
  }
143
167
 
144
168
  if (debug){
147
171
    if (result == NULL){
148
172
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
149
173
    } else {
150
 
      fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
151
 
      fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
 
174
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
175
              result->unsupported_algorithm);
 
176
      fprintf(stderr, "Wrong key usage: %d\n",
 
177
              result->wrong_key_usage);
152
178
      if(result->file_name != NULL){
153
179
        fprintf(stderr, "File name: %s\n", result->file_name);
154
180
      }
160
186
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
161
187
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
162
188
          fprintf(stderr, "Secret key available: %s\n",
163
 
                  recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
 
189
                  recipient->status == GPG_ERR_NO_SECKEY
 
190
                  ? "No" : "Yes");
164
191
          recipient = recipient->next;
165
192
        }
166
193
      }
171
198
  gpgme_data_release(dh_crypto);
172
199
  
173
200
  /* Seek back to the beginning of the GPGME plaintext data buffer */
174
 
  gpgme_data_seek(dh_plain, 0, SEEK_SET);
175
 
 
 
201
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
 
202
    perror("pgpme_data_seek");
 
203
  }
 
204
  
176
205
  *new_packet = 0;
177
206
  while(true){
178
207
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
179
 
      *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
 
208
      *new_packet = realloc(*new_packet,
 
209
                            (unsigned int)new_packet_capacity
 
210
                            + BUFFER_SIZE);
180
211
      if (*new_packet == NULL){
181
212
        perror("realloc");
182
213
        return -1;
184
215
      new_packet_capacity += BUFFER_SIZE;
185
216
    }
186
217
    
187
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
 
218
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
219
                          BUFFER_SIZE);
188
220
    /* Print the data, if any */
189
221
    if (ret == 0){
190
 
      /* If password is empty, then a incorrect error will be printed */
191
222
      break;
192
223
    }
193
224
    if(ret < 0){
197
228
    new_packet_length += ret;
198
229
  }
199
230
 
200
 
  if(debug){
201
 
    fprintf(stderr, "decrypted password is: %s\n", *new_packet);
202
 
  }
203
 
 
204
 
   /* Delete the GPGME plaintext data buffer */
 
231
  /* FIXME: check characters before printing to screen so to not print
 
232
     terminal control characters */
 
233
  /*   if(debug){ */
 
234
  /*     fprintf(stderr, "decrypted password is: "); */
 
235
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
 
236
  /*     fprintf(stderr, "\n"); */
 
237
  /*   } */
 
238
  
 
239
  /* Delete the GPGME plaintext data buffer */
205
240
  gpgme_data_release(dh_plain);
206
241
  return new_packet_length;
207
242
}
213
248
  return ret;
214
249
}
215
250
 
216
 
void debuggnutls(int level, const char* string){
 
251
static void debuggnutls(__attribute__((unused)) int level,
 
252
                        const char* string){
217
253
  fprintf(stderr, "%s", string);
218
254
}
219
255
 
220
 
int initgnutls(encrypted_session *es){
 
256
static int initgnutls(encrypted_session *es){
221
257
  const char *err;
222
258
  int ret;
223
 
 
 
259
  
224
260
  if(debug){
225
 
    fprintf(stderr, "Initializing gnutls\n");
 
261
    fprintf(stderr, "Initializing GnuTLS\n");
226
262
  }
227
263
 
228
 
  
229
264
  if ((ret = gnutls_global_init ())
230
265
      != GNUTLS_E_SUCCESS) {
231
266
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
237
272
    gnutls_global_set_log_function(debuggnutls);
238
273
  }
239
274
  
240
 
 
241
275
  /* openpgp credentials */
242
276
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
243
277
      != GNUTLS_E_SUCCESS) {
244
 
    fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
 
278
    fprintf (stderr, "memory error: %s\n",
 
279
             safer_gnutls_strerror(ret));
245
280
    return -1;
246
281
  }
247
 
 
 
282
  
248
283
  if(debug){
249
 
    fprintf(stderr, "Attempting to use openpgp certificate %s"
250
 
            " and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
 
284
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
285
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
 
286
            seckeyfile);
251
287
  }
252
 
 
 
288
  
253
289
  ret = gnutls_certificate_set_openpgp_key_file
254
 
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
 
290
    (es->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
255
291
  if (ret != GNUTLS_E_SUCCESS) {
256
292
    fprintf
257
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
258
 
       ret, CERTFILE, KEYFILE);
 
293
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
294
       " '%s')\n",
 
295
       ret, pubkeyfile, seckeyfile);
259
296
    fprintf(stdout, "The Error is: %s\n",
260
297
            safer_gnutls_strerror(ret));
261
298
    return -1;
262
299
  }
263
 
 
264
 
  //Gnutls server initialization
 
300
  
 
301
  //GnuTLS server initialization
265
302
  if ((ret = gnutls_dh_params_init (&es->dh_params))
266
303
      != GNUTLS_E_SUCCESS) {
267
304
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
268
305
             safer_gnutls_strerror(ret));
269
306
    return -1;
270
307
  }
271
 
 
272
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
 
308
  
 
309
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, dh_bits))
273
310
      != GNUTLS_E_SUCCESS) {
274
311
    fprintf (stderr, "Error in prime generation: %s\n",
275
312
             safer_gnutls_strerror(ret));
276
313
    return -1;
277
314
  }
278
 
 
 
315
  
279
316
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
280
 
 
281
 
  // Gnutls session creation
 
317
  
 
318
  // GnuTLS session creation
282
319
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
283
320
      != GNUTLS_E_SUCCESS){
284
 
    fprintf(stderr, "Error in gnutls session initialization: %s\n",
 
321
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
285
322
            safer_gnutls_strerror(ret));
286
323
  }
287
 
 
 
324
  
288
325
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
289
326
      != GNUTLS_E_SUCCESS) {
290
327
    fprintf(stderr, "Syntax error at: %s\n", err);
291
 
    fprintf(stderr, "Gnutls error: %s\n",
 
328
    fprintf(stderr, "GnuTLS error: %s\n",
292
329
            safer_gnutls_strerror(ret));
293
330
    return -1;
294
331
  }
295
 
 
 
332
  
296
333
  if ((ret = gnutls_credentials_set
297
334
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
298
335
      != GNUTLS_E_SUCCESS) {
300
337
            safer_gnutls_strerror(ret));
301
338
    return -1;
302
339
  }
303
 
 
 
340
  
304
341
  /* ignore client certificate if any. */
305
 
  gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
 
342
  gnutls_certificate_server_set_request (es->session,
 
343
                                         GNUTLS_CERT_IGNORE);
306
344
  
307
 
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
 
345
  gnutls_dh_set_prime_bits (es->session, dh_bits);
308
346
  
309
347
  return 0;
310
348
}
311
349
 
312
 
void empty_log(AvahiLogLevel level, const char *txt){}
 
350
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
351
                      __attribute__((unused)) const char *txt){}
313
352
 
314
 
int start_mandos_communcation(char *ip, uint16_t port){
 
353
static int start_mandos_communication(const char *ip, uint16_t port,
 
354
                                      AvahiIfIndex if_index){
315
355
  int ret, tcp_sd;
316
356
  struct sockaddr_in6 to;
317
357
  encrypted_session es;
320
360
  size_t buffer_length = 0;
321
361
  size_t buffer_capacity = 0;
322
362
  ssize_t decrypted_buffer_size;
 
363
  size_t written = 0;
323
364
  int retval = 0;
324
 
  const char interface[] = "eth0";
325
 
 
 
365
  char interface[IF_NAMESIZE];
 
366
  
326
367
  if(debug){
327
 
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
 
368
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
 
369
            ip, port);
328
370
  }
329
371
  
330
372
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
332
374
    perror("socket");
333
375
    return -1;
334
376
  }
335
 
 
 
377
  
 
378
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
379
    if(debug){
 
380
      perror("if_indextoname");
 
381
    }
 
382
    return -1;
 
383
  }
 
384
  
336
385
  if(debug){
337
386
    fprintf(stderr, "Binding to interface %s\n", interface);
338
387
  }
339
 
 
340
 
  ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
341
 
  if(tcp_sd < 0) {
342
 
    perror("setsockopt bindtodevice");
343
 
    return -1;
344
 
  }
345
388
  
346
 
  memset(&to,0,sizeof(to));
 
389
  memset(&to,0,sizeof(to));     /* Spurious warning */
347
390
  to.sin6_family = AF_INET6;
348
391
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
349
392
  if (ret < 0 ){
354
397
    fprintf(stderr, "Bad address: %s\n", ip);
355
398
    return -1;
356
399
  }
357
 
  to.sin6_port = htons(port);
358
 
  to.sin6_scope_id = if_nametoindex(interface);
359
 
 
 
400
  to.sin6_port = htons(port);   /* Spurious warning */
 
401
  
 
402
  to.sin6_scope_id = (uint32_t)if_index;
 
403
  
360
404
  if(debug){
361
 
    fprintf(stderr, "Connection to: %s\n", ip);
 
405
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
 
406
    char addrstr[INET6_ADDRSTRLEN] = "";
 
407
    if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
 
408
                 sizeof(addrstr)) == NULL){
 
409
      perror("inet_ntop");
 
410
    } else {
 
411
      if(strcmp(addrstr, ip) != 0){
 
412
        fprintf(stderr, "Canonical address form: %s\n",
 
413
                addrstr, ntohs(to.sin6_port));
 
414
      }
 
415
    }
362
416
  }
363
417
  
364
418
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
372
426
    retval = -1;
373
427
    return -1;
374
428
  }
375
 
    
376
 
  
377
 
  gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
378
 
 
 
429
  
 
430
  gnutls_transport_set_ptr (es.session,
 
431
                            (gnutls_transport_ptr_t) tcp_sd);
 
432
  
379
433
  if(debug){
380
 
    fprintf(stderr, "Establishing tls session with %s\n", ip);
 
434
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
381
435
  }
382
 
 
383
436
  
384
437
  ret = gnutls_handshake (es.session);
385
438
  
386
439
  if (ret != GNUTLS_E_SUCCESS){
387
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
388
 
    gnutls_perror (ret);
 
440
    if(debug){
 
441
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
442
      gnutls_perror (ret);
 
443
    }
389
444
    retval = -1;
390
445
    goto exit;
391
446
  }
392
 
 
393
 
  //Retrieve gpg packet that contains the wanted password
394
 
 
 
447
  
 
448
  //Retrieve OpenPGP packet that contains the wanted password
 
449
  
395
450
  if(debug){
396
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
 
451
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
452
            ip);
397
453
  }
398
454
 
399
455
  while(true){
426
482
        }
427
483
        break;
428
484
      default:
429
 
        fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
 
485
        fprintf(stderr, "Unknown error while reading data from"
 
486
                " encrypted session with mandos server\n");
430
487
        retval = -1;
431
488
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
432
489
        goto exit;
433
490
      }
434
491
    } else {
435
 
      buffer_length += ret;
 
492
      buffer_length += (size_t) ret;
436
493
    }
437
494
  }
438
495
  
439
496
  if (buffer_length > 0){
440
 
    if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
441
 
      fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
 
497
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
498
                                               buffer_length,
 
499
                                               &decrypted_buffer,
 
500
                                               keydir);
 
501
    if (decrypted_buffer_size >= 0){
 
502
      while(written < (size_t) decrypted_buffer_size){
 
503
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
504
                           (size_t)decrypted_buffer_size - written,
 
505
                           stdout);
 
506
        if(ret == 0 and ferror(stdout)){
 
507
          if(debug){
 
508
            fprintf(stderr, "Error writing encrypted data: %s\n",
 
509
                    strerror(errno));
 
510
          }
 
511
          retval = -1;
 
512
          break;
 
513
        }
 
514
        written += (size_t)ret;
 
515
      }
442
516
      free(decrypted_buffer);
443
517
    } else {
444
518
      retval = -1;
448
522
  //shutdown procedure
449
523
 
450
524
  if(debug){
451
 
    fprintf(stderr, "Closing tls session\n");
 
525
    fprintf(stderr, "Closing TLS session\n");
452
526
  }
453
527
 
454
528
  free(buffer);
466
540
 
467
541
static void resolve_callback(
468
542
    AvahiSServiceResolver *r,
469
 
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
543
    AvahiIfIndex interface,
470
544
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
471
545
    AvahiResolverEvent event,
472
546
    const char *name,
475
549
    const char *host_name,
476
550
    const AvahiAddress *address,
477
551
    uint16_t port,
478
 
    AvahiStringList *txt,
479
 
    AvahiLookupResultFlags flags,
 
552
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
553
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
480
554
    AVAHI_GCC_UNUSED void* userdata) {
481
555
    
482
 
    assert(r);
483
 
 
484
 
    /* Called whenever a service has been resolved successfully or timed out */
485
 
 
486
 
    switch (event) {
487
 
        case AVAHI_RESOLVER_FAILURE:
488
 
            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)));
489
 
            break;
490
 
 
491
 
        case AVAHI_RESOLVER_FOUND: {
492
 
          char ip[AVAHI_ADDRESS_STR_MAX];
493
 
            avahi_address_snprint(ip, sizeof(ip), address);
494
 
            if(debug){
495
 
              fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
496
 
            }
497
 
            int ret = start_mandos_communcation(ip, port);
498
 
            if (ret == 0){
499
 
              exit(EXIT_SUCCESS);
500
 
            } else {
501
 
              exit(EXIT_FAILURE);
502
 
            }
503
 
        }
 
556
  assert(r);                    /* Spurious warning */
 
557
  
 
558
  /* Called whenever a service has been resolved successfully or
 
559
     timed out */
 
560
  
 
561
  switch (event) {
 
562
  default:
 
563
  case AVAHI_RESOLVER_FAILURE:
 
564
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
 
565
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
566
            avahi_strerror(avahi_server_errno(server)));
 
567
    break;
 
568
    
 
569
  case AVAHI_RESOLVER_FOUND:
 
570
    {
 
571
      char ip[AVAHI_ADDRESS_STR_MAX];
 
572
      avahi_address_snprint(ip, sizeof(ip), address);
 
573
      if(debug){
 
574
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
 
575
                " port %d\n", name, host_name, ip, port);
 
576
      }
 
577
      int ret = start_mandos_communication(ip, port, interface);
 
578
      if (ret == 0){
 
579
        exit(EXIT_SUCCESS);
 
580
      }
504
581
    }
505
 
    avahi_s_service_resolver_free(r);
 
582
  }
 
583
  avahi_s_service_resolver_free(r);
506
584
}
507
585
 
508
586
static void browse_callback(
517
595
    void* userdata) {
518
596
    
519
597
    AvahiServer *s = userdata;
520
 
    assert(b);
521
 
 
522
 
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
523
 
 
 
598
    assert(b);                  /* Spurious warning */
 
599
    
 
600
    /* Called whenever a new services becomes available on the LAN or
 
601
       is removed from the LAN */
 
602
    
524
603
    switch (event) {
525
 
 
526
 
        case AVAHI_BROWSER_FAILURE:
527
 
            
528
 
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
529
 
            avahi_simple_poll_quit(simple_poll);
530
 
            return;
531
 
 
532
 
        case AVAHI_BROWSER_NEW:
533
 
            /* We ignore the returned resolver object. In the callback
534
 
               function we free it. If the server is terminated before
535
 
               the callback function is called the server will free
536
 
               the resolver for us. */
537
 
            
538
 
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
539
 
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
540
 
            
541
 
            break;
542
 
 
543
 
        case AVAHI_BROWSER_REMOVE:
544
 
            break;
545
 
 
546
 
        case AVAHI_BROWSER_ALL_FOR_NOW:
547
 
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
548
 
            break;
 
604
    default:
 
605
    case AVAHI_BROWSER_FAILURE:
 
606
      
 
607
      fprintf(stderr, "(Browser) %s\n",
 
608
              avahi_strerror(avahi_server_errno(server)));
 
609
      avahi_simple_poll_quit(simple_poll);
 
610
      return;
 
611
      
 
612
    case AVAHI_BROWSER_NEW:
 
613
      /* We ignore the returned resolver object. In the callback
 
614
         function we free it. If the server is terminated before
 
615
         the callback function is called the server will free
 
616
         the resolver for us. */
 
617
      
 
618
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
 
619
                                         type, domain,
 
620
                                         AVAHI_PROTO_INET6, 0,
 
621
                                         resolve_callback, s)))
 
622
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
 
623
                avahi_strerror(avahi_server_errno(s)));
 
624
      break;
 
625
      
 
626
    case AVAHI_BROWSER_REMOVE:
 
627
      break;
 
628
      
 
629
    case AVAHI_BROWSER_ALL_FOR_NOW:
 
630
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
631
      break;
549
632
    }
550
633
}
551
634
 
 
635
/* Combines file name and path and returns the malloced new
 
636
   string. some sane checks could/should be added */
 
637
static const char *combinepath(const char *first, const char *second){
 
638
  size_t f_len = strlen(first);
 
639
  size_t s_len = strlen(second);
 
640
  char *tmp = malloc(f_len + s_len + 2);
 
641
  if (tmp == NULL){
 
642
    return NULL;
 
643
  }
 
644
  if(f_len > 0){
 
645
    memcpy(tmp, first, f_len);
 
646
  }
 
647
  tmp[f_len] = '/';
 
648
  if(s_len > 0){
 
649
    memcpy(tmp + f_len + 1, second, s_len);
 
650
  }
 
651
  tmp[f_len + 1 + s_len] = '\0';
 
652
  return tmp;
 
653
}
 
654
 
 
655
 
552
656
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
553
657
    AvahiServerConfig config;
554
658
    AvahiSServiceBrowser *sb = NULL;
555
 
    const char db[] = "--debug";
556
659
    int error;
557
 
    int ret = 1;
 
660
    int ret;
 
661
    int debug_int = 0;
558
662
    int returncode = EXIT_SUCCESS;
559
 
    char *basename = rindex(argv[0], '/');
560
 
    if(basename == NULL){
561
 
      basename = argv[0];
562
 
    } else {
563
 
      basename++;
564
 
    }
565
 
    
566
 
    char *program_name = malloc(strlen(basename) + sizeof(db));
567
 
 
568
 
    if (program_name == NULL){
569
 
      perror("argv[0]");
570
 
      return EXIT_FAILURE;
571
 
    }
572
 
    
573
 
    program_name[0] = '\0';
574
 
    
575
 
    for (int i = 1; i < argc; i++){
576
 
      if (not strncmp(argv[i], db, 5)){
577
 
          strcat(strcat(strcat(program_name, db ), "="), basename);
578
 
          if(not strcmp(argv[i], db) or not strcmp(argv[i], program_name)){
579
 
            debug = true;
580
 
          }
581
 
        }
582
 
    }
583
 
    free(program_name);
584
 
 
 
663
    const char *interface = NULL;
 
664
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
665
    char *connect_to = NULL;
 
666
    
 
667
    debug_int = debug ? 1 : 0;
 
668
    while (true){
 
669
      static struct option long_options[] = {
 
670
        {"debug", no_argument, &debug_int, 1},
 
671
        {"connect", required_argument, NULL, 'C'},
 
672
        {"interface", required_argument, NULL, 'i'},
 
673
        {"keydir", required_argument, NULL, 'd'},
 
674
        {"seckey", required_argument, NULL, 'c'},
 
675
        {"pubkey", required_argument, NULL, 'k'},
 
676
        {"dh-bits", required_argument, NULL, 'D'},
 
677
        {0, 0, 0, 0} };
 
678
      
 
679
      int option_index = 0;
 
680
      ret = getopt_long (argc, argv, "i:", long_options,
 
681
                         &option_index);
 
682
      
 
683
      if (ret == -1){
 
684
        break;
 
685
      }
 
686
      
 
687
      switch(ret){
 
688
      case 0:
 
689
        break;
 
690
      case 'i':
 
691
        interface = optarg;
 
692
        break;
 
693
      case 'C':
 
694
        connect_to = optarg;
 
695
        break;
 
696
      case 'd':
 
697
        keydir = optarg;
 
698
        break;
 
699
      case 'c':
 
700
        pubkeyfile = optarg;
 
701
        break;
 
702
      case 'k':
 
703
        seckeyfile = optarg;
 
704
        break;
 
705
      case 'D':
 
706
        dh_bits = atoi(optarg);
 
707
        break;
 
708
      case '?':
 
709
        break
 
710
      default:
 
711
        exit(EXIT_FAILURE);
 
712
      }
 
713
    }
 
714
    debug = debug_int ? true : false;
 
715
    
 
716
    pubkeyfile = combinepath(keydir, pubkeyfile);
 
717
    if (pubkeyfile == NULL){
 
718
      perror("combinepath");
 
719
      goto exit;
 
720
    }
 
721
    
 
722
    if(interface != NULL){
 
723
      if_index = (AvahiIfIndex) if_nametoindex(interface);
 
724
      if(if_index == 0){
 
725
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
726
        exit(EXIT_FAILURE);
 
727
      }
 
728
    }
 
729
    
 
730
    if(connect_to != NULL){
 
731
      /* Connect directly, do not use Zeroconf */
 
732
      /* (Mainly meant for debugging) */
 
733
      char *address = strrchr(connect_to, ':');
 
734
      if(address == NULL){
 
735
        fprintf(stderr, "No colon in address\n");
 
736
        exit(EXIT_FAILURE);
 
737
      }
 
738
      errno = 0;
 
739
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
740
      if(errno){
 
741
        perror("Bad port number");
 
742
        exit(EXIT_FAILURE);
 
743
      }
 
744
      *address = '\0';
 
745
      address = connect_to;
 
746
      ret = start_mandos_communication(address, port, if_index);
 
747
      if(ret < 0){
 
748
        exit(EXIT_FAILURE);
 
749
      } else {
 
750
        exit(EXIT_SUCCESS);
 
751
      }
 
752
    }
 
753
    
 
754
    seckeyfile = combinepath(keydir, seckeyfile);
 
755
    if (seckeyfile == NULL){
 
756
      perror("combinepath");
 
757
      goto exit;
 
758
    }
 
759
    
585
760
    if (not debug){
586
761
      avahi_set_log_function(empty_log);
587
762
    }
588
763
    
589
764
    /* Initialize the psuedo-RNG */
590
 
    srand(time(NULL));
 
765
    srand((unsigned int) time(NULL));
591
766
 
592
767
    /* Allocate main loop object */
593
768
    if (!(simple_poll = avahi_simple_poll_new())) {
604
779
    config.publish_domain = 0;
605
780
 
606
781
    /* Allocate a new server */
607
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
782
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
783
                              &config, NULL, NULL, &error);
608
784
 
609
785
    /* Free the configuration data */
610
786
    avahi_server_config_free(&config);
611
787
 
612
788
    /* Check if creating the server object succeeded */
613
789
    if (!server) {
614
 
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
790
        fprintf(stderr, "Failed to create server: %s\n",
 
791
                avahi_strerror(error));
615
792
        returncode = EXIT_FAILURE;
616
793
        goto exit;
617
794
    }
618
795
    
619
796
    /* Create the service browser */
620
 
    if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
621
 
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
 
797
    sb = avahi_s_service_browser_new(server, if_index,
 
798
                                     AVAHI_PROTO_INET6,
 
799
                                     "_mandos._tcp", NULL, 0,
 
800
                                     browse_callback, server);
 
801
    if (!sb) {
 
802
        fprintf(stderr, "Failed to create service browser: %s\n",
 
803
                avahi_strerror(avahi_server_errno(server)));
622
804
        returncode = EXIT_FAILURE;
623
805
        goto exit;
624
806
    }
631
813
    
632
814
    avahi_simple_poll_loop(simple_poll);
633
815
    
634
 
exit:
 
816
 exit:
635
817
 
636
818
    if (debug){
637
819
      fprintf(stderr, "%s exiting\n", argv[0]);
646
828
 
647
829
    if (simple_poll)
648
830
        avahi_simple_poll_free(simple_poll);
649
 
 
650
 
    return ret;
 
831
    free(pubkeyfile);
 
832
    free(seckeyfile);
 
833
    
 
834
    return returncode;
651
835
}