/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-29 05:53:59 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080829055359-wkdasnyxtylmnxus
* mandos.xml (EXAMPLE): Replaced all occurences of command name with
                        "&COMMANDNAME;".

* plugins.d/password-prompt.c (main): Improved some documentation
                                      strings.  Do perror() of
                                      tcgetattr() fails.  Add debug
                                      output if interrupted by signal.
                                      Loop over write() instead of
                                      using fwrite() when outputting
                                      password.  Add debug output if
                                      getline() returns 0, unless it
                                      was caused by a signal.  Add
                                      exit status code to debug
                                      output.

* plugins.d/password-prompt.xml: Changed all single quotes to double
                                 quotes for consistency.  Removed
                                 <?xml-stylesheet>.
  (ENTITY TIMESTAMP): New.  Automatically updated by Emacs time-stamp
                      by using Emacs local variables.
  (/refentry/refentryinfo/title): Changed to "Mandos Manual".
  (/refentry/refentryinfo/productname): Changed to "Mandos".
  (/refentry/refentryinfo/date): New; set to "&TIMESTAMP;".
  (/refentry/refentryinfo/copyright): Split copyright holders.
  (/refentry/refnamediv/refpurpose): Improved wording.
  (SYNOPSIS): Fix to use correct markup.  Add short options.
  (DESCRIPTION, OPTIONS): Improved wording.
  (OPTIONS): Improved wording.  Use more correct markup.  Document
             short options.
  (EXIT STATUS): Add text.
  (ENVIRONMENT): Document use of "cryptsource" and "crypttarget".
  (FILES): REMOVED.
  (BUGS): Add text.
  (EXAMPLE): Added some examples.
  (SECURITY): Added text.
  (SEE ALSO): Remove reference to mandos(8).  Add reference to
              crypttab(5).

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