/mandos/release

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

« back to all changes in this revision

Viewing changes to plugins.d/mandosclient.c

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

Show diffs side-by-side

added added

removed removed

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