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