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