/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/password-request.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-16 03:29:08 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080816032908-ihw7c05r2mnyk389
Add feature to specify custom environment variables for plugins.

* plugin-runner.c (plugin): New members "environ" and "envc" to
                            contain possible custom environment.
  (getplugin): Return NULL on failure instead of doing exit(); all
               callers changed.
  (add_to_char_array): New helper function for "add_argument" and
                       "add_environment".
  (addargument): Renamed to "add_argument".  Return bool.  Call
                 "add_to_char_array" to actually do things.
  (add_environment): New; analogous to "add_argument".
  (addcustomargument): Renamed to "add_to_argv" to avoid confusion
                       with "add_argument".
  (main): New options "--global-envs" and "--envs-for" to specify
          custom environment for plugins.  Print environment for
          plugins in debug mode.  Use asprintf instead of strcpy and
          strcat.  Use execve() for plugins with custom environments.
          Free environment for plugin when freeing plugin list.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Mandos-client - get and decrypt data from a Mandos server
 
3
 * Mandos client - get and decrypt data from a Mandos server
4
4
 *
5
5
 * This program is partly derived from an example program for an Avahi
6
6
 * service browser, downloaded from
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
11
 * Everything else is
12
 
 * Copyright © 2008,2009 Teddy Hogeborn
13
 
 * Copyright © 2008,2009 Björn Påhlsson
 
12
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
14
13
 * 
15
14
 * This program is free software: you can redistribute it and/or
16
15
 * modify it under the terms of the GNU General Public License as
36
35
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
37
36
 
38
37
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
39
 
                                   stdout, ferror(), sscanf */
 
38
                                   stdout, ferror() */
40
39
#include <stdint.h>             /* uint16_t, uint32_t */
41
40
#include <stddef.h>             /* NULL, size_t, ssize_t */
42
41
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
48
47
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
49
48
                                   sockaddr_in6, PF_INET6,
50
49
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
51
 
                                   uid_t, gid_t, open(), opendir(),
52
 
                                   DIR */
53
 
#include <sys/stat.h>           /* open() */
 
50
                                   uid_t, gid_t */
 
51
#include <inttypes.h>           /* PRIu16 */
54
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
55
53
                                   struct in6_addr, inet_pton(),
56
54
                                   connect() */
57
 
#include <fcntl.h>              /* open() */
58
 
#include <dirent.h>             /* opendir(), struct dirent, readdir()
59
 
                                 */
60
 
#include <inttypes.h>           /* PRIu16, intmax_t, SCNdMAX */
61
55
#include <assert.h>             /* assert() */
62
56
#include <errno.h>              /* perror(), errno */
63
57
#include <time.h>               /* time() */
64
58
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
65
59
                                   SIOCSIFFLAGS, if_indextoname(),
66
60
                                   if_nametoindex(), IF_NAMESIZE */
67
 
#include <netinet/in.h>
68
61
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
69
62
                                   getuid(), getgid(), setuid(),
70
63
                                   setgid() */
 
64
#include <netinet/in.h>
71
65
#include <arpa/inet.h>          /* inet_pton(), htons */
72
 
#include <iso646.h>             /* not, and, or */
 
66
#include <iso646.h>             /* not, and */
73
67
#include <argp.h>               /* struct argp_option, error_t, struct
74
68
                                   argp_state, struct argp,
75
69
                                   argp_parse(), ARGP_KEY_ARG,
92
86
                                   gnutls_*
93
87
                                   init_gnutls_session(),
94
88
                                   GNUTLS_* */
95
 
#include <gnutls/openpgp.h>
96
 
                          /* gnutls_certificate_set_openpgp_key_file(),
 
89
#include <gnutls/openpgp.h>     /* gnutls_certificate_set_openpgp_key_file(),
97
90
                                   GNUTLS_OPENPGP_FMT_BASE64 */
98
91
 
99
92
/* GPGME */
105
98
 
106
99
#define BUFFER_SIZE 256
107
100
 
108
 
#define PATHDIR "/conf/conf.d/mandos"
109
 
#define SECKEY "seckey.txt"
110
 
#define PUBKEY "pubkey.txt"
111
 
 
112
101
bool debug = false;
 
102
static const char *keydir = "/conf/conf.d/mandos";
113
103
static const char mandos_protocol_version[] = "1";
114
 
const char *argp_program_version = "mandos-client " VERSION;
 
104
const char *argp_program_version = "password-request 1.0";
115
105
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
116
106
 
117
107
/* Used for passing in values through the Avahi callback functions */
122
112
  unsigned int dh_bits;
123
113
  gnutls_dh_params_t dh_params;
124
114
  const char *priority;
125
 
  gpgme_ctx_t ctx;
126
115
} mandos_context;
127
116
 
128
117
/*
132
121
 */
133
122
size_t adjustbuffer(char **buffer, size_t buffer_length,
134
123
                  size_t buffer_capacity){
135
 
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
 
124
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
136
125
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
137
 
    if(buffer == NULL){
 
126
    if (buffer == NULL){
138
127
      return 0;
139
128
    }
140
129
    buffer_capacity += BUFFER_SIZE;
143
132
}
144
133
 
145
134
/* 
146
 
 * Initialize GPGME.
 
135
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
 
136
 * Returns -1 on error
147
137
 */
148
 
static bool init_gpgme(mandos_context *mc, const char *seckey,
149
 
                       const char *pubkey, const char *tempdir){
150
 
  int ret;
 
138
static ssize_t pgp_packet_decrypt (const char *cryptotext,
 
139
                                   size_t crypto_size,
 
140
                                   char **plaintext,
 
141
                                   const char *homedir){
 
142
  gpgme_data_t dh_crypto, dh_plain;
 
143
  gpgme_ctx_t ctx;
151
144
  gpgme_error_t rc;
 
145
  ssize_t ret;
 
146
  size_t plaintext_capacity = 0;
 
147
  ssize_t plaintext_length = 0;
152
148
  gpgme_engine_info_t engine_info;
153
149
  
154
 
  
155
 
  /*
156
 
   * Helper function to insert pub and seckey to the enigne keyring.
157
 
   */
158
 
  bool import_key(const char *filename){
159
 
    int fd;
160
 
    gpgme_data_t pgp_data;
161
 
    
162
 
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
163
 
    if(fd == -1){
164
 
      perror("open");
165
 
      return false;
166
 
    }
167
 
    
168
 
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
169
 
    if(rc != GPG_ERR_NO_ERROR){
170
 
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
171
 
              gpgme_strsource(rc), gpgme_strerror(rc));
172
 
      return false;
173
 
    }
174
 
    
175
 
    rc = gpgme_op_import(mc->ctx, pgp_data);
176
 
    if(rc != GPG_ERR_NO_ERROR){
177
 
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
178
 
              gpgme_strsource(rc), gpgme_strerror(rc));
179
 
      return false;
180
 
    }
181
 
    
182
 
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
183
 
    if(ret == -1){
184
 
      perror("close");
185
 
    }
186
 
    gpgme_data_release(pgp_data);
187
 
    return true;
188
 
  }
189
 
  
190
 
  if(debug){
191
 
    fprintf(stderr, "Initialize gpgme\n");
 
150
  if (debug){
 
151
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
192
152
  }
193
153
  
194
154
  /* Init GPGME */
195
155
  gpgme_check_version(NULL);
196
156
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
197
 
  if(rc != GPG_ERR_NO_ERROR){
 
157
  if (rc != GPG_ERR_NO_ERROR){
198
158
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
199
159
            gpgme_strsource(rc), gpgme_strerror(rc));
200
 
    return false;
 
160
    return -1;
201
161
  }
202
162
  
203
 
    /* Set GPGME home directory for the OpenPGP engine only */
204
 
  rc = gpgme_get_engine_info(&engine_info);
205
 
  if(rc != GPG_ERR_NO_ERROR){
 
163
  /* Set GPGME home directory for the OpenPGP engine only */
 
164
  rc = gpgme_get_engine_info (&engine_info);
 
165
  if (rc != GPG_ERR_NO_ERROR){
206
166
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
207
167
            gpgme_strsource(rc), gpgme_strerror(rc));
208
 
    return false;
 
168
    return -1;
209
169
  }
210
170
  while(engine_info != NULL){
211
171
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
212
172
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
213
 
                            engine_info->file_name, tempdir);
 
173
                            engine_info->file_name, homedir);
214
174
      break;
215
175
    }
216
176
    engine_info = engine_info->next;
217
177
  }
218
178
  if(engine_info == NULL){
219
 
    fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
220
 
    return false;
221
 
  }
222
 
  
223
 
  /* Create new GPGME "context" */
224
 
  rc = gpgme_new(&(mc->ctx));
225
 
  if(rc != GPG_ERR_NO_ERROR){
226
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
227
 
            gpgme_strsource(rc), gpgme_strerror(rc));
228
 
    return false;
229
 
  }
230
 
  
231
 
  if(not import_key(pubkey) or not import_key(seckey)){
232
 
    return false;
233
 
  }
234
 
  
235
 
  return true; 
236
 
}
237
 
 
238
 
/* 
239
 
 * Decrypt OpenPGP data.
240
 
 * Returns -1 on error
241
 
 */
242
 
static ssize_t pgp_packet_decrypt(const mandos_context *mc,
243
 
                                  const char *cryptotext,
244
 
                                  size_t crypto_size,
245
 
                                  char **plaintext){
246
 
  gpgme_data_t dh_crypto, dh_plain;
247
 
  gpgme_error_t rc;
248
 
  ssize_t ret;
249
 
  size_t plaintext_capacity = 0;
250
 
  ssize_t plaintext_length = 0;
251
 
  
252
 
  if(debug){
253
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
179
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
 
180
    return -1;
254
181
  }
255
182
  
256
183
  /* Create new GPGME data buffer from memory cryptotext */
257
184
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
258
185
                               0);
259
 
  if(rc != GPG_ERR_NO_ERROR){
 
186
  if (rc != GPG_ERR_NO_ERROR){
260
187
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
261
188
            gpgme_strsource(rc), gpgme_strerror(rc));
262
189
    return -1;
264
191
  
265
192
  /* Create new empty GPGME data buffer for the plaintext */
266
193
  rc = gpgme_data_new(&dh_plain);
267
 
  if(rc != GPG_ERR_NO_ERROR){
 
194
  if (rc != GPG_ERR_NO_ERROR){
268
195
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
269
196
            gpgme_strsource(rc), gpgme_strerror(rc));
270
197
    gpgme_data_release(dh_crypto);
271
198
    return -1;
272
199
  }
273
200
  
 
201
  /* Create new GPGME "context" */
 
202
  rc = gpgme_new(&ctx);
 
203
  if (rc != GPG_ERR_NO_ERROR){
 
204
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
 
205
            gpgme_strsource(rc), gpgme_strerror(rc));
 
206
    plaintext_length = -1;
 
207
    goto decrypt_end;
 
208
  }
 
209
  
274
210
  /* Decrypt data from the cryptotext data buffer to the plaintext
275
211
     data buffer */
276
 
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
277
 
  if(rc != GPG_ERR_NO_ERROR){
 
212
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
 
213
  if (rc != GPG_ERR_NO_ERROR){
278
214
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
279
215
            gpgme_strsource(rc), gpgme_strerror(rc));
280
216
    plaintext_length = -1;
281
 
    if(debug){
282
 
      gpgme_decrypt_result_t result;
283
 
      result = gpgme_op_decrypt_result(mc->ctx);
284
 
      if(result == NULL){
285
 
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
286
 
      } else {
287
 
        fprintf(stderr, "Unsupported algorithm: %s\n",
288
 
                result->unsupported_algorithm);
289
 
        fprintf(stderr, "Wrong key usage: %u\n",
290
 
                result->wrong_key_usage);
291
 
        if(result->file_name != NULL){
292
 
          fprintf(stderr, "File name: %s\n", result->file_name);
293
 
        }
294
 
        gpgme_recipient_t recipient;
295
 
        recipient = result->recipients;
296
 
        if(recipient){
297
 
          while(recipient != NULL){
298
 
            fprintf(stderr, "Public key algorithm: %s\n",
299
 
                    gpgme_pubkey_algo_name(recipient->pubkey_algo));
300
 
            fprintf(stderr, "Key ID: %s\n", recipient->keyid);
301
 
            fprintf(stderr, "Secret key available: %s\n",
302
 
                    recipient->status == GPG_ERR_NO_SECKEY
303
 
                    ? "No" : "Yes");
304
 
            recipient = recipient->next;
305
 
          }
306
 
        }
307
 
      }
308
 
    }
309
217
    goto decrypt_end;
310
218
  }
311
219
  
313
221
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
314
222
  }
315
223
  
 
224
  if (debug){
 
225
    gpgme_decrypt_result_t result;
 
226
    result = gpgme_op_decrypt_result(ctx);
 
227
    if (result == NULL){
 
228
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
229
    } else {
 
230
      fprintf(stderr, "Unsupported algorithm: %s\n",
 
231
              result->unsupported_algorithm);
 
232
      fprintf(stderr, "Wrong key usage: %u\n",
 
233
              result->wrong_key_usage);
 
234
      if(result->file_name != NULL){
 
235
        fprintf(stderr, "File name: %s\n", result->file_name);
 
236
      }
 
237
      gpgme_recipient_t recipient;
 
238
      recipient = result->recipients;
 
239
      if(recipient){
 
240
        while(recipient != NULL){
 
241
          fprintf(stderr, "Public key algorithm: %s\n",
 
242
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
243
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
244
          fprintf(stderr, "Secret key available: %s\n",
 
245
                  recipient->status == GPG_ERR_NO_SECKEY
 
246
                  ? "No" : "Yes");
 
247
          recipient = recipient->next;
 
248
        }
 
249
      }
 
250
    }
 
251
  }
 
252
  
316
253
  /* Seek back to the beginning of the GPGME plaintext data buffer */
317
 
  if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
318
 
    perror("gpgme_data_seek");
 
254
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
 
255
    perror("pgpme_data_seek");
319
256
    plaintext_length = -1;
320
257
    goto decrypt_end;
321
258
  }
325
262
    plaintext_capacity = adjustbuffer(plaintext,
326
263
                                      (size_t)plaintext_length,
327
264
                                      plaintext_capacity);
328
 
    if(plaintext_capacity == 0){
 
265
    if (plaintext_capacity == 0){
329
266
        perror("adjustbuffer");
330
267
        plaintext_length = -1;
331
268
        goto decrypt_end;
334
271
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
335
272
                          BUFFER_SIZE);
336
273
    /* Print the data, if any */
337
 
    if(ret == 0){
 
274
    if (ret == 0){
338
275
      /* EOF */
339
276
      break;
340
277
    }
345
282
    }
346
283
    plaintext_length += ret;
347
284
  }
348
 
  
 
285
 
349
286
  if(debug){
350
287
    fprintf(stderr, "Decrypted password is: ");
351
288
    for(ssize_t i = 0; i < plaintext_length; i++){
364
301
  return plaintext_length;
365
302
}
366
303
 
367
 
static const char * safer_gnutls_strerror(int value) {
368
 
  const char *ret = gnutls_strerror(value); /* Spurious warning from
369
 
                                               -Wunreachable-code */
370
 
  if(ret == NULL)
 
304
static const char * safer_gnutls_strerror (int value) {
 
305
  const char *ret = gnutls_strerror (value);
 
306
  if (ret == NULL)
371
307
    ret = "(unknown)";
372
308
  return ret;
373
309
}
388
324
  }
389
325
  
390
326
  ret = gnutls_global_init();
391
 
  if(ret != GNUTLS_E_SUCCESS) {
392
 
    fprintf(stderr, "GnuTLS global_init: %s\n",
393
 
            safer_gnutls_strerror(ret));
 
327
  if (ret != GNUTLS_E_SUCCESS) {
 
328
    fprintf (stderr, "GnuTLS global_init: %s\n",
 
329
             safer_gnutls_strerror(ret));
394
330
    return -1;
395
331
  }
396
332
  
397
 
  if(debug){
 
333
  if (debug){
398
334
    /* "Use a log level over 10 to enable all debugging options."
399
335
     * - GnuTLS manual
400
336
     */
404
340
  
405
341
  /* OpenPGP credentials */
406
342
  gnutls_certificate_allocate_credentials(&mc->cred);
407
 
  if(ret != GNUTLS_E_SUCCESS){
408
 
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
409
 
                                                  * from
410
 
                                                  * -Wunreachable-code
411
 
                                                  */
412
 
            safer_gnutls_strerror(ret));
413
 
    gnutls_global_deinit();
 
343
  if (ret != GNUTLS_E_SUCCESS){
 
344
    fprintf (stderr, "GnuTLS memory error: %s\n",
 
345
             safer_gnutls_strerror(ret));
 
346
    gnutls_global_deinit ();
414
347
    return -1;
415
348
  }
416
349
  
417
350
  if(debug){
418
 
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
419
 
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
 
351
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
352
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
420
353
            seckeyfilename);
421
354
  }
422
355
  
423
356
  ret = gnutls_certificate_set_openpgp_key_file
424
357
    (mc->cred, pubkeyfilename, seckeyfilename,
425
358
     GNUTLS_OPENPGP_FMT_BASE64);
426
 
  if(ret != GNUTLS_E_SUCCESS) {
 
359
  if (ret != GNUTLS_E_SUCCESS) {
427
360
    fprintf(stderr,
428
361
            "Error[%d] while reading the OpenPGP key pair ('%s',"
429
362
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
430
 
    fprintf(stderr, "The GnuTLS error is: %s\n",
 
363
    fprintf(stdout, "The GnuTLS error is: %s\n",
431
364
            safer_gnutls_strerror(ret));
432
365
    goto globalfail;
433
366
  }
434
367
  
435
368
  /* GnuTLS server initialization */
436
369
  ret = gnutls_dh_params_init(&mc->dh_params);
437
 
  if(ret != GNUTLS_E_SUCCESS) {
438
 
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
439
 
            " %s\n", safer_gnutls_strerror(ret));
 
370
  if (ret != GNUTLS_E_SUCCESS) {
 
371
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
 
372
             " %s\n", safer_gnutls_strerror(ret));
440
373
    goto globalfail;
441
374
  }
442
375
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
443
 
  if(ret != GNUTLS_E_SUCCESS) {
444
 
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
445
 
            safer_gnutls_strerror(ret));
 
376
  if (ret != GNUTLS_E_SUCCESS) {
 
377
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
 
378
             safer_gnutls_strerror(ret));
446
379
    goto globalfail;
447
380
  }
448
381
  
449
382
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
450
 
  
 
383
 
451
384
  return 0;
452
 
  
 
385
 
453
386
 globalfail:
454
 
  
 
387
 
455
388
  gnutls_certificate_free_credentials(mc->cred);
456
389
  gnutls_global_deinit();
457
 
  gnutls_dh_params_deinit(mc->dh_params);
458
390
  return -1;
 
391
 
459
392
}
460
393
 
461
394
static int init_gnutls_session(mandos_context *mc,
463
396
  int ret;
464
397
  /* GnuTLS session creation */
465
398
  ret = gnutls_init(session, GNUTLS_SERVER);
466
 
  if(ret != GNUTLS_E_SUCCESS){
 
399
  if (ret != GNUTLS_E_SUCCESS){
467
400
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
468
401
            safer_gnutls_strerror(ret));
469
402
  }
471
404
  {
472
405
    const char *err;
473
406
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
474
 
    if(ret != GNUTLS_E_SUCCESS) {
 
407
    if (ret != GNUTLS_E_SUCCESS) {
475
408
      fprintf(stderr, "Syntax error at: %s\n", err);
476
409
      fprintf(stderr, "GnuTLS error: %s\n",
477
410
              safer_gnutls_strerror(ret));
478
 
      gnutls_deinit(*session);
 
411
      gnutls_deinit (*session);
479
412
      return -1;
480
413
    }
481
414
  }
482
415
  
483
416
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
484
417
                               mc->cred);
485
 
  if(ret != GNUTLS_E_SUCCESS) {
 
418
  if (ret != GNUTLS_E_SUCCESS) {
486
419
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
487
420
            safer_gnutls_strerror(ret));
488
 
    gnutls_deinit(*session);
 
421
    gnutls_deinit (*session);
489
422
    return -1;
490
423
  }
491
424
  
492
425
  /* ignore client certificate if any. */
493
 
  gnutls_certificate_server_set_request(*session,
494
 
                                        GNUTLS_CERT_IGNORE);
 
426
  gnutls_certificate_server_set_request (*session,
 
427
                                         GNUTLS_CERT_IGNORE);
495
428
  
496
 
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
 
429
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
497
430
  
498
431
  return 0;
499
432
}
507
440
                                      AvahiIfIndex if_index,
508
441
                                      mandos_context *mc){
509
442
  int ret, tcp_sd;
510
 
  ssize_t sret;
511
443
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
512
444
  char *buffer = NULL;
513
445
  char *decrypted_buffer;
519
451
  char interface[IF_NAMESIZE];
520
452
  gnutls_session_t session;
521
453
  
522
 
  ret = init_gnutls_session(mc, &session);
523
 
  if(ret != 0){
 
454
  ret = init_gnutls_session (mc, &session);
 
455
  if (ret != 0){
524
456
    return -1;
525
457
  }
526
458
  
534
466
    perror("socket");
535
467
    return -1;
536
468
  }
537
 
  
 
469
 
538
470
  if(debug){
539
471
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
540
472
      perror("if_indextoname");
543
475
    fprintf(stderr, "Binding to interface %s\n", interface);
544
476
  }
545
477
  
546
 
  memset(&to, 0, sizeof(to));
 
478
  memset(&to, 0, sizeof(to));   /* Spurious warning */
547
479
  to.in6.sin6_family = AF_INET6;
548
480
  /* It would be nice to have a way to detect if we were passed an
549
481
     IPv4 address here.   Now we assume an IPv6 address. */
550
482
  ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
551
 
  if(ret < 0 ){
 
483
  if (ret < 0 ){
552
484
    perror("inet_pton");
553
485
    return -1;
554
486
  }
556
488
    fprintf(stderr, "Bad address: %s\n", ip);
557
489
    return -1;
558
490
  }
559
 
  to.in6.sin6_port = htons(port); /* Spurious warnings from
560
 
                                     -Wconversion and
561
 
                                     -Wunreachable-code */
 
491
  to.in6.sin6_port = htons(port); /* Spurious warning */
562
492
  
563
493
  to.in6.sin6_scope_id = (uint32_t)if_index;
564
494
  
577
507
  }
578
508
  
579
509
  ret = connect(tcp_sd, &to.in, sizeof(to));
580
 
  if(ret < 0){
 
510
  if (ret < 0){
581
511
    perror("connect");
582
512
    return -1;
583
513
  }
584
 
  
 
514
 
585
515
  const char *out = mandos_protocol_version;
586
516
  written = 0;
587
 
  while(true){
 
517
  while (true){
588
518
    size_t out_size = strlen(out);
589
 
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
519
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
590
520
                                   out_size - written));
591
 
    if(ret == -1){
 
521
    if (ret == -1){
592
522
      perror("write");
593
523
      retval = -1;
594
524
      goto mandos_end;
597
527
    if(written < out_size){
598
528
      continue;
599
529
    } else {
600
 
      if(out == mandos_protocol_version){
 
530
      if (out == mandos_protocol_version){
601
531
        written = 0;
602
532
        out = "\r\n";
603
533
      } else {
605
535
      }
606
536
    }
607
537
  }
608
 
  
 
538
 
609
539
  if(debug){
610
540
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
611
541
  }
612
542
  
613
 
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
614
 
  
 
543
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
 
544
 
615
545
  do{
616
 
    ret = gnutls_handshake(session);
 
546
    ret = gnutls_handshake (session);
617
547
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
618
548
  
619
 
  if(ret != GNUTLS_E_SUCCESS){
 
549
  if (ret != GNUTLS_E_SUCCESS){
620
550
    if(debug){
621
551
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
622
 
      gnutls_perror(ret);
 
552
      gnutls_perror (ret);
623
553
    }
624
554
    retval = -1;
625
555
    goto mandos_end;
631
561
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
632
562
            ip);
633
563
  }
634
 
  
 
564
 
635
565
  while(true){
636
566
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
637
567
                                   buffer_capacity);
638
 
    if(buffer_capacity == 0){
 
568
    if (buffer_capacity == 0){
639
569
      perror("adjustbuffer");
640
570
      retval = -1;
641
571
      goto mandos_end;
642
572
    }
643
573
    
644
 
    sret = gnutls_record_recv(session, buffer+buffer_length,
645
 
                              BUFFER_SIZE);
646
 
    if(sret == 0){
 
574
    ret = gnutls_record_recv(session, buffer+buffer_length,
 
575
                             BUFFER_SIZE);
 
576
    if (ret == 0){
647
577
      break;
648
578
    }
649
 
    if(sret < 0){
650
 
      switch(sret){
 
579
    if (ret < 0){
 
580
      switch(ret){
651
581
      case GNUTLS_E_INTERRUPTED:
652
582
      case GNUTLS_E_AGAIN:
653
583
        break;
654
584
      case GNUTLS_E_REHANDSHAKE:
655
585
        do{
656
 
          ret = gnutls_handshake(session);
 
586
          ret = gnutls_handshake (session);
657
587
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
658
 
        if(ret < 0){
 
588
        if (ret < 0){
659
589
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
660
 
          gnutls_perror(ret);
 
590
          gnutls_perror (ret);
661
591
          retval = -1;
662
592
          goto mandos_end;
663
593
        }
666
596
        fprintf(stderr, "Unknown error while reading data from"
667
597
                " encrypted session with Mandos server\n");
668
598
        retval = -1;
669
 
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
599
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
670
600
        goto mandos_end;
671
601
      }
672
602
    } else {
673
 
      buffer_length += (size_t) sret;
 
603
      buffer_length += (size_t) ret;
674
604
    }
675
605
  }
676
606
  
678
608
    fprintf(stderr, "Closing TLS session\n");
679
609
  }
680
610
  
681
 
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
611
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
682
612
  
683
 
  if(buffer_length > 0){
684
 
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
 
613
  if (buffer_length > 0){
 
614
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
685
615
                                               buffer_length,
686
 
                                               &decrypted_buffer);
687
 
    if(decrypted_buffer_size >= 0){
 
616
                                               &decrypted_buffer,
 
617
                                               keydir);
 
618
    if (decrypted_buffer_size >= 0){
688
619
      written = 0;
689
620
      while(written < (size_t) decrypted_buffer_size){
690
 
        ret = (int)fwrite(decrypted_buffer + written, 1,
691
 
                          (size_t)decrypted_buffer_size - written,
692
 
                          stdout);
 
621
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
622
                           (size_t)decrypted_buffer_size - written,
 
623
                           stdout);
693
624
        if(ret == 0 and ferror(stdout)){
694
625
          if(debug){
695
626
            fprintf(stderr, "Error writing encrypted data: %s\n",
704
635
    } else {
705
636
      retval = -1;
706
637
    }
707
 
  } else {
708
 
    retval = -1;
709
638
  }
710
639
  
711
640
  /* Shutdown procedure */
712
641
  
713
642
 mandos_end:
714
643
  free(buffer);
715
 
  ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
716
 
  if(ret == -1){
717
 
    perror("close");
718
 
  }
719
 
  gnutls_deinit(session);
 
644
  close(tcp_sd);
 
645
  gnutls_deinit (session);
720
646
  return retval;
721
647
}
722
648
 
735
661
                             flags,
736
662
                             void* userdata) {
737
663
  mandos_context *mc = userdata;
738
 
  assert(r);
 
664
  assert(r);                    /* Spurious warning */
739
665
  
740
666
  /* Called whenever a service has been resolved successfully or
741
667
     timed out */
742
668
  
743
 
  switch(event) {
 
669
  switch (event) {
744
670
  default:
745
671
  case AVAHI_RESOLVER_FAILURE:
746
672
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
754
680
      avahi_address_snprint(ip, sizeof(ip), address);
755
681
      if(debug){
756
682
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
757
 
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
758
 
                ip, (intmax_t)interface, port);
 
683
                PRIu16 ") on port %d\n", name, host_name, ip,
 
684
                interface, port);
759
685
      }
760
686
      int ret = start_mandos_communication(ip, port, interface, mc);
761
 
      if(ret == 0){
 
687
      if (ret == 0){
762
688
        avahi_simple_poll_quit(mc->simple_poll);
763
689
      }
764
690
    }
777
703
                             flags,
778
704
                             void* userdata) {
779
705
  mandos_context *mc = userdata;
780
 
  assert(b);
 
706
  assert(b);                    /* Spurious warning */
781
707
  
782
708
  /* Called whenever a new services becomes available on the LAN or
783
709
     is removed from the LAN */
784
710
  
785
 
  switch(event) {
 
711
  switch (event) {
786
712
  default:
787
713
  case AVAHI_BROWSER_FAILURE:
788
714
    
797
723
       the callback function is called the Avahi server will free the
798
724
       resolver for us. */
799
725
    
800
 
    if(!(avahi_s_service_resolver_new(mc->server, interface,
 
726
    if (!(avahi_s_service_resolver_new(mc->server, interface,
801
727
                                       protocol, name, type, domain,
802
728
                                       AVAHI_PROTO_INET6, 0,
803
729
                                       resolve_callback, mc)))
817
743
  }
818
744
}
819
745
 
 
746
/* Combines file name and path and returns the malloced new
 
747
   string. some sane checks could/should be added */
 
748
static char *combinepath(const char *first, const char *second){
 
749
  char *tmp;
 
750
  int ret = asprintf(&tmp, "%s/%s", first, second);
 
751
  if(ret < 0){
 
752
    return NULL;
 
753
  }
 
754
  return tmp;
 
755
}
 
756
 
 
757
 
820
758
int main(int argc, char *argv[]){
821
759
    AvahiSServiceBrowser *sb = NULL;
822
760
    int error;
823
761
    int ret;
824
 
    intmax_t tmpmax;
825
 
    int numchars;
826
762
    int exitcode = EXIT_SUCCESS;
827
763
    const char *interface = "eth0";
828
764
    struct ifreq network;
830
766
    uid_t uid;
831
767
    gid_t gid;
832
768
    char *connect_to = NULL;
833
 
    char tempdir[] = "/tmp/mandosXXXXXX";
834
769
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
835
 
    const char *seckey = PATHDIR "/" SECKEY;
836
 
    const char *pubkey = PATHDIR "/" PUBKEY;
837
 
    
 
770
    char *pubkeyfilename = NULL;
 
771
    char *seckeyfilename = NULL;
 
772
    const char *pubkeyname = "pubkey.txt";
 
773
    const char *seckeyname = "seckey.txt";
838
774
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
839
 
                          .dh_bits = 1024, .priority = "SECURE256"
840
 
                          ":!CTYPE-X.509:+CTYPE-OPENPGP" };
841
 
    bool gnutls_initialized = false;
842
 
    bool gpgme_initialized = false;
 
775
                          .dh_bits = 1024, .priority = "SECURE256"};
 
776
    bool gnutls_initalized = false;
843
777
    
844
778
    {
845
779
      struct argp_option options[] = {
846
780
        { .name = "debug", .key = 128,
847
781
          .doc = "Debug mode", .group = 3 },
848
782
        { .name = "connect", .key = 'c',
849
 
          .arg = "ADDRESS:PORT",
850
 
          .doc = "Connect directly to a specific Mandos server",
 
783
          .arg = "IP",
 
784
          .doc = "Connect directly to a sepcified mandos server",
851
785
          .group = 1 },
852
786
        { .name = "interface", .key = 'i',
853
 
          .arg = "NAME",
854
 
          .doc = "Interface that will be used to search for Mandos"
855
 
          " servers",
 
787
          .arg = "INTERFACE",
 
788
          .doc = "Interface that Avahi will conntect through",
 
789
          .group = 1 },
 
790
        { .name = "keydir", .key = 'd',
 
791
          .arg = "KEYDIR",
 
792
          .doc = "Directory where the openpgp keyring is",
856
793
          .group = 1 },
857
794
        { .name = "seckey", .key = 's',
858
 
          .arg = "FILE",
859
 
          .doc = "OpenPGP secret key file base name",
 
795
          .arg = "SECKEY",
 
796
          .doc = "Secret openpgp key for gnutls authentication",
860
797
          .group = 1 },
861
798
        { .name = "pubkey", .key = 'p',
862
 
          .arg = "FILE",
863
 
          .doc = "OpenPGP public key file base name",
 
799
          .arg = "PUBKEY",
 
800
          .doc = "Public openpgp key for gnutls authentication",
864
801
          .group = 2 },
865
802
        { .name = "dh-bits", .key = 129,
866
803
          .arg = "BITS",
867
 
          .doc = "Bit length of the prime number used in the"
868
 
          " Diffie-Hellman key exchange",
 
804
          .doc = "dh-bits to use in gnutls communication",
869
805
          .group = 2 },
870
806
        { .name = "priority", .key = 130,
871
 
          .arg = "STRING",
872
 
          .doc = "GnuTLS priority string for the TLS handshake",
873
 
          .group = 1 },
 
807
          .arg = "PRIORITY",
 
808
          .doc = "GNUTLS priority", .group = 1 },
874
809
        { .name = NULL }
875
810
      };
 
811
 
876
812
      
877
 
      error_t parse_opt(int key, char *arg,
878
 
                        struct argp_state *state) {
879
 
        switch(key) {
880
 
        case 128:               /* --debug */
 
813
      error_t parse_opt (int key, char *arg,
 
814
                         struct argp_state *state) {
 
815
        /* Get the INPUT argument from `argp_parse', which we know is
 
816
           a pointer to our plugin list pointer. */
 
817
        switch (key) {
 
818
        case 128:
881
819
          debug = true;
882
820
          break;
883
 
        case 'c':               /* --connect */
 
821
        case 'c':
884
822
          connect_to = arg;
885
823
          break;
886
 
        case 'i':               /* --interface */
 
824
        case 'i':
887
825
          interface = arg;
888
826
          break;
889
 
        case 's':               /* --seckey */
890
 
          seckey = arg;
891
 
          break;
892
 
        case 'p':               /* --pubkey */
893
 
          pubkey = arg;
894
 
          break;
895
 
        case 129:               /* --dh-bits */
896
 
          ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
897
 
          if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
898
 
             or arg[numchars] != '\0'){
899
 
            fprintf(stderr, "Bad number of DH bits\n");
 
827
        case 'd':
 
828
          keydir = arg;
 
829
          break;
 
830
        case 's':
 
831
          seckeyname = arg;
 
832
          break;
 
833
        case 'p':
 
834
          pubkeyname = arg;
 
835
          break;
 
836
        case 129:
 
837
          errno = 0;
 
838
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
839
          if (errno){
 
840
            perror("strtol");
900
841
            exit(EXIT_FAILURE);
901
842
          }
902
 
          mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
903
843
          break;
904
 
        case 130:               /* --priority */
 
844
        case 130:
905
845
          mc.priority = arg;
906
846
          break;
907
847
        case ARGP_KEY_ARG:
908
 
          argp_usage(state);
 
848
          argp_usage (state);
909
849
        case ARGP_KEY_END:
910
850
          break;
911
851
        default:
913
853
        }
914
854
        return 0;
915
855
      }
916
 
      
 
856
 
917
857
      struct argp argp = { .options = options, .parser = parse_opt,
918
858
                           .args_doc = "",
919
859
                           .doc = "Mandos client -- Get and decrypt"
920
 
                           " passwords from a Mandos server" };
921
 
      ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
922
 
      if(ret == ARGP_ERR_UNKNOWN){
 
860
                           " passwords from mandos server" };
 
861
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
862
      if (ret == ARGP_ERR_UNKNOWN){
923
863
        fprintf(stderr, "Unknown error while parsing arguments\n");
924
864
        exitcode = EXIT_FAILURE;
925
865
        goto end;
926
866
      }
927
867
    }
 
868
      
 
869
    pubkeyfilename = combinepath(keydir, pubkeyname);
 
870
    if (pubkeyfilename == NULL){
 
871
      perror("combinepath");
 
872
      exitcode = EXIT_FAILURE;
 
873
      goto end;
 
874
    }
 
875
    
 
876
    seckeyfilename = combinepath(keydir, seckeyname);
 
877
    if (seckeyfilename == NULL){
 
878
      perror("combinepath");
 
879
      exitcode = EXIT_FAILURE;
 
880
      goto end;
 
881
    }
 
882
 
 
883
    ret = init_gnutls_global(&mc, pubkeyfilename, seckeyfilename);
 
884
    if (ret == -1){
 
885
      fprintf(stderr, "init_gnutls_global failed\n");
 
886
      exitcode = EXIT_FAILURE;
 
887
      goto end;
 
888
    } else {
 
889
      gnutls_initalized = true;
 
890
    }
928
891
    
929
892
    /* If the interface is down, bring it up */
930
893
    {
934
897
        exitcode = EXIT_FAILURE;
935
898
        goto end;
936
899
      }
937
 
      strcpy(network.ifr_name, interface);
 
900
      strcpy(network.ifr_name, interface); /* Spurious warning */
938
901
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
939
902
      if(ret == -1){
940
903
        perror("ioctl SIOCGIFFLAGS");
950
913
          goto end;
951
914
        }
952
915
      }
953
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
954
 
      if(ret == -1){
955
 
        perror("close");
956
 
      }
 
916
      close(sd);
957
917
    }
958
918
    
959
919
    uid = getuid();
960
920
    gid = getgid();
961
921
    
962
922
    ret = setuid(uid);
963
 
    if(ret == -1){
 
923
    if (ret == -1){
964
924
      perror("setuid");
965
925
    }
966
926
    
967
927
    setgid(gid);
968
 
    if(ret == -1){
 
928
    if (ret == -1){
969
929
      perror("setgid");
970
930
    }
971
931
    
972
 
    ret = init_gnutls_global(&mc, pubkey, seckey);
973
 
    if(ret == -1){
974
 
      fprintf(stderr, "init_gnutls_global failed\n");
975
 
      exitcode = EXIT_FAILURE;
976
 
      goto end;
977
 
    } else {
978
 
      gnutls_initialized = true;
979
 
    }
980
 
    
981
 
    if(mkdtemp(tempdir) == NULL){
982
 
      perror("mkdtemp");
983
 
      tempdir[0] = '\0';
984
 
      goto end;
985
 
    }
986
 
    
987
 
    if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
988
 
      fprintf(stderr, "init_gpgme failed\n");
989
 
      exitcode = EXIT_FAILURE;
990
 
      goto end;
991
 
    } else {
992
 
      gpgme_initialized = true;
993
 
    }
994
 
    
995
932
    if_index = (AvahiIfIndex) if_nametoindex(interface);
996
933
    if(if_index == 0){
997
934
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1007
944
        exitcode = EXIT_FAILURE;
1008
945
        goto end;
1009
946
      }
1010
 
      uint16_t port;
1011
 
      ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
1012
 
      if(ret < 1 or tmpmax != (uint16_t)tmpmax
1013
 
         or address[numchars+1] != '\0'){
1014
 
        fprintf(stderr, "Bad port number\n");
 
947
      errno = 0;
 
948
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
949
      if(errno){
 
950
        perror("Bad port number");
1015
951
        exitcode = EXIT_FAILURE;
1016
952
        goto end;
1017
953
      }
1018
 
      port = (uint16_t)tmpmax;
1019
954
      *address = '\0';
1020
955
      address = connect_to;
1021
956
      ret = start_mandos_communication(address, port, if_index, &mc);
1027
962
      goto end;
1028
963
    }
1029
964
    
1030
 
    if(not debug){
 
965
    if (not debug){
1031
966
      avahi_set_log_function(empty_log);
1032
967
    }
1033
968
    
1036
971
    
1037
972
    /* Allocate main Avahi loop object */
1038
973
    mc.simple_poll = avahi_simple_poll_new();
1039
 
    if(mc.simple_poll == NULL) {
 
974
    if (mc.simple_poll == NULL) {
1040
975
        fprintf(stderr, "Avahi: Failed to create simple poll"
1041
976
                " object.\n");
1042
977
        exitcode = EXIT_FAILURE;
1043
978
        goto end;
1044
979
    }
1045
 
    
 
980
 
1046
981
    {
1047
982
      AvahiServerConfig config;
1048
983
      /* Do not publish any local Zeroconf records */
1051
986
      config.publish_addresses = 0;
1052
987
      config.publish_workstation = 0;
1053
988
      config.publish_domain = 0;
1054
 
      
 
989
 
1055
990
      /* Allocate a new server */
1056
991
      mc.server = avahi_server_new(avahi_simple_poll_get
1057
992
                                   (mc.simple_poll), &config, NULL,
1058
993
                                   NULL, &error);
1059
 
      
 
994
    
1060
995
      /* Free the Avahi configuration data */
1061
996
      avahi_server_config_free(&config);
1062
997
    }
1063
998
    
1064
999
    /* Check if creating the Avahi server object succeeded */
1065
 
    if(mc.server == NULL) {
 
1000
    if (mc.server == NULL) {
1066
1001
        fprintf(stderr, "Failed to create Avahi server: %s\n",
1067
1002
                avahi_strerror(error));
1068
1003
        exitcode = EXIT_FAILURE;
1074
1009
                                     AVAHI_PROTO_INET6,
1075
1010
                                     "_mandos._tcp", NULL, 0,
1076
1011
                                     browse_callback, &mc);
1077
 
    if(sb == NULL) {
 
1012
    if (sb == NULL) {
1078
1013
        fprintf(stderr, "Failed to create service browser: %s\n",
1079
1014
                avahi_strerror(avahi_server_errno(mc.server)));
1080
1015
        exitcode = EXIT_FAILURE;
1082
1017
    }
1083
1018
    
1084
1019
    /* Run the main loop */
1085
 
    
1086
 
    if(debug){
 
1020
 
 
1021
    if (debug){
1087
1022
      fprintf(stderr, "Starting Avahi loop search\n");
1088
1023
    }
1089
1024
    
1090
1025
    avahi_simple_poll_loop(mc.simple_poll);
1091
1026
    
1092
1027
 end:
1093
 
    
1094
 
    if(debug){
 
1028
 
 
1029
    if (debug){
1095
1030
      fprintf(stderr, "%s exiting\n", argv[0]);
1096
1031
    }
1097
1032
    
1098
1033
    /* Cleanup things */
1099
 
    if(sb != NULL)
 
1034
    if (sb != NULL)
1100
1035
        avahi_s_service_browser_free(sb);
1101
1036
    
1102
 
    if(mc.server != NULL)
 
1037
    if (mc.server != NULL)
1103
1038
        avahi_server_free(mc.server);
1104
 
    
1105
 
    if(mc.simple_poll != NULL)
 
1039
 
 
1040
    if (mc.simple_poll != NULL)
1106
1041
        avahi_simple_poll_free(mc.simple_poll);
1107
 
    
1108
 
    if(gnutls_initialized){
 
1042
    free(pubkeyfilename);
 
1043
    free(seckeyfilename);
 
1044
 
 
1045
    if (gnutls_initalized){
1109
1046
      gnutls_certificate_free_credentials(mc.cred);
1110
 
      gnutls_global_deinit();
1111
 
      gnutls_dh_params_deinit(mc.dh_params);
1112
 
    }
1113
 
    
1114
 
    if(gpgme_initialized){
1115
 
      gpgme_release(mc.ctx);
1116
 
    }
1117
 
    
1118
 
    /* Removes the temp directory used by GPGME */
1119
 
    if(tempdir[0] != '\0'){
1120
 
      DIR *d;
1121
 
      struct dirent *direntry;
1122
 
      d = opendir(tempdir);
1123
 
      if(d == NULL){
1124
 
        if(errno != ENOENT){
1125
 
          perror("opendir");
1126
 
        }
1127
 
      } else {
1128
 
        while(true){
1129
 
          direntry = readdir(d);
1130
 
          if(direntry == NULL){
1131
 
            break;
1132
 
          }
1133
 
          if(direntry->d_type == DT_REG){
1134
 
            char *fullname = NULL;
1135
 
            ret = asprintf(&fullname, "%s/%s", tempdir,
1136
 
                           direntry->d_name);
1137
 
            if(ret < 0){
1138
 
              perror("asprintf");
1139
 
              continue;
1140
 
            }
1141
 
            ret = unlink(fullname);
1142
 
            if(ret == -1){
1143
 
              fprintf(stderr, "unlink(\"%s\"): %s",
1144
 
                      fullname, strerror(errno));
1145
 
            }
1146
 
            free(fullname);
1147
 
          }
1148
 
        }
1149
 
        closedir(d);
1150
 
      }
1151
 
      ret = rmdir(tempdir);
1152
 
      if(ret == -1 and errno != ENOENT){
1153
 
        perror("rmdir");
1154
 
      }
1155
 
    }
1156
 
          
 
1047
      gnutls_global_deinit ();
 
1048
    }
 
1049
    
1157
1050
    return exitcode;
1158
1051
}