/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugins.d/mandos-client.c

  • Committer: Teddy Hogeborn
  • Date: 2009-08-30 03:10:29 UTC
  • Revision ID: teddy@fukt.bsnet.se-20090830031029-cj8po3rc4g1cux1d
* mandos: White-space fixes only.
* mandos-ctl: - '' -
* plugin-runner.c: - '' -
* plugins.d/askpass-fifo.c: - '' -
* plugins.d/mandos-client.c: - '' -
* plugins.d/password-prompt.c: - '' -

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 © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
12
 * Copyright © 2008,2009 Teddy Hogeborn
 
13
 * Copyright © 2008,2009 Björn Påhlsson
13
14
 * 
14
15
 * This program is free software: you can redistribute it and/or
15
16
 * modify it under the terms of the GNU General Public License as
29
30
 */
30
31
 
31
32
/* Needed by GPGME, specifically gpgme_data_seek() */
 
33
#ifndef _LARGEFILE_SOURCE
32
34
#define _LARGEFILE_SOURCE
 
35
#endif
 
36
#ifndef _FILE_OFFSET_BITS
33
37
#define _FILE_OFFSET_BITS 64
34
 
 
35
 
#include <stdio.h>
36
 
#include <assert.h>
37
 
#include <stdlib.h>
38
 
#include <time.h>
39
 
#include <net/if.h>             /* if_nametoindex */
40
 
#include <sys/ioctl.h>          /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
41
 
                                   SIOCSIFFLAGS */
 
38
#endif
 
39
 
 
40
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
 
41
 
 
42
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
 
43
                                   stdout, ferror(), remove() */
 
44
#include <stdint.h>             /* uint16_t, uint32_t */
 
45
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
 
47
                                   srand(), strtof() */
 
48
#include <stdbool.h>            /* bool, false, true */
 
49
#include <string.h>             /* memset(), strcmp(), strlen(),
 
50
                                   strerror(), asprintf(), strcpy() */
 
51
#include <sys/ioctl.h>          /* ioctl */
 
52
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
 
53
                                   sockaddr_in6, PF_INET6,
 
54
                                   SOCK_STREAM, uid_t, gid_t, open(),
 
55
                                   opendir(), DIR */
 
56
#include <sys/stat.h>           /* open() */
 
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
58
                                   inet_pton(), connect() */
 
59
#include <fcntl.h>              /* open() */
 
60
#include <dirent.h>             /* opendir(), struct dirent, readdir()
 
61
                                 */
 
62
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
 
63
                                   strtoimax() */
 
64
#include <assert.h>             /* assert() */
 
65
#include <errno.h>              /* perror(), errno */
 
66
#include <time.h>               /* nanosleep(), time() */
42
67
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
43
 
                                   SIOCSIFFLAGS */
44
 
 
 
68
                                   SIOCSIFFLAGS, if_indextoname(),
 
69
                                   if_nametoindex(), IF_NAMESIZE */
 
70
#include <netinet/in.h>         /* IN6_IS_ADDR_LINKLOCAL,
 
71
                                   INET_ADDRSTRLEN, INET6_ADDRSTRLEN
 
72
                                */
 
73
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
 
74
                                   getuid(), getgid(), setuid(),
 
75
                                   setgid() */
 
76
#include <arpa/inet.h>          /* inet_pton(), htons */
 
77
#include <iso646.h>             /* not, or, and */
 
78
#include <argp.h>               /* struct argp_option, error_t, struct
 
79
                                   argp_state, struct argp,
 
80
                                   argp_parse(), ARGP_KEY_ARG,
 
81
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
 
82
#include <signal.h>             /* sigemptyset(), sigaddset(),
 
83
                                   sigaction(), SIGTERM, sig_atomic_t,
 
84
                                   raise() */
 
85
 
 
86
#ifdef __linux__
 
87
#include <sys/klog.h>           /* klogctl() */
 
88
#endif  /* __linux__ */
 
89
 
 
90
/* Avahi */
 
91
/* All Avahi types, constants and functions
 
92
 Avahi*, avahi_*,
 
93
 AVAHI_* */
45
94
#include <avahi-core/core.h>
46
95
#include <avahi-core/lookup.h>
47
96
#include <avahi-core/log.h>
49
98
#include <avahi-common/malloc.h>
50
99
#include <avahi-common/error.h>
51
100
 
52
 
//mandos client part
53
 
#include <sys/types.h>          /* socket(), inet_pton() */
54
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
55
 
                                   struct in6_addr, inet_pton() */
56
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
57
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
58
 
 
59
 
#include <unistd.h>             /* close() */
60
 
#include <netinet/in.h>
61
 
#include <stdbool.h>            /* true */
62
 
#include <string.h>             /* memset */
63
 
#include <arpa/inet.h>          /* inet_pton() */
64
 
#include <iso646.h>             /* not */
65
 
 
66
 
// gpgme
67
 
#include <errno.h>              /* perror() */
68
 
#include <gpgme.h>
69
 
 
70
 
// getopt_long
71
 
#include <getopt.h>
 
101
/* GnuTLS */
 
102
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and
 
103
                                   functions:
 
104
                                   gnutls_*
 
105
                                   init_gnutls_session(),
 
106
                                   GNUTLS_* */
 
107
#include <gnutls/openpgp.h>
 
108
                          /* gnutls_certificate_set_openpgp_key_file(),
 
109
                                   GNUTLS_OPENPGP_FMT_BASE64 */
 
110
 
 
111
/* GPGME */
 
112
#include <gpgme.h>              /* All GPGME types, constants and
 
113
                                   functions:
 
114
                                   gpgme_*
 
115
                                   GPGME_PROTOCOL_OpenPGP,
 
116
                                   GPG_ERR_NO_* */
72
117
 
73
118
#define BUFFER_SIZE 256
74
119
 
75
 
static const char *keydir = "/conf/conf.d/mandos";
76
 
static const char *pubkeyfile = "pubkey.txt";
77
 
static const char *seckeyfile = "seckey.txt";
 
120
#define PATHDIR "/conf/conf.d/mandos"
 
121
#define SECKEY "seckey.txt"
 
122
#define PUBKEY "pubkey.txt"
78
123
 
79
124
bool debug = false;
 
125
static const char mandos_protocol_version[] = "1";
 
126
const char *argp_program_version = "mandos-client " VERSION;
 
127
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
80
128
 
81
 
/* Used for passing in values through all the callback functions */
 
129
/* Used for passing in values through the Avahi callback functions */
82
130
typedef struct {
83
131
  AvahiSimplePoll *simple_poll;
84
132
  AvahiServer *server;
85
133
  gnutls_certificate_credentials_t cred;
86
134
  unsigned int dh_bits;
 
135
  gnutls_dh_params_t dh_params;
87
136
  const char *priority;
 
137
  gpgme_ctx_t ctx;
88
138
} mandos_context;
89
139
 
 
140
/* global context so signal handler can reach it*/
 
141
mandos_context mc = { .simple_poll = NULL, .server = NULL,
 
142
                      .dh_bits = 1024, .priority = "SECURE256"
 
143
                      ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
144
 
 
145
/*
 
146
 * Make additional room in "buffer" for at least BUFFER_SIZE more
 
147
 * bytes. "buffer_capacity" is how much is currently allocated,
 
148
 * "buffer_length" is how much is already used.
 
149
 */
 
150
size_t incbuffer(char **buffer, size_t buffer_length,
 
151
                  size_t buffer_capacity){
 
152
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
 
153
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
 
154
    if(buffer == NULL){
 
155
      return 0;
 
156
    }
 
157
    buffer_capacity += BUFFER_SIZE;
 
158
  }
 
159
  return buffer_capacity;
 
160
}
 
161
 
90
162
/* 
91
 
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
92
 
 * Returns -1 on error
 
163
 * Initialize GPGME.
93
164
 */
94
 
static ssize_t pgp_packet_decrypt (const char *cryptotext,
95
 
                                   size_t crypto_size,
96
 
                                   char **plaintext,
97
 
                                   const char *homedir){
98
 
  gpgme_data_t dh_crypto, dh_plain;
99
 
  gpgme_ctx_t ctx;
 
165
static bool init_gpgme(const char *seckey,
 
166
                       const char *pubkey, const char *tempdir){
 
167
  int ret;
100
168
  gpgme_error_t rc;
101
 
  ssize_t ret;
102
 
  ssize_t plaintext_capacity = 0;
103
 
  ssize_t plaintext_length = 0;
104
169
  gpgme_engine_info_t engine_info;
105
170
  
106
 
  if (debug){
107
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
171
  
 
172
  /*
 
173
   * Helper function to insert pub and seckey to the engine keyring.
 
174
   */
 
175
  bool import_key(const char *filename){
 
176
    int fd;
 
177
    gpgme_data_t pgp_data;
 
178
    
 
179
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
 
180
    if(fd == -1){
 
181
      perror("open");
 
182
      return false;
 
183
    }
 
184
    
 
185
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
 
186
    if(rc != GPG_ERR_NO_ERROR){
 
187
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
 
188
              gpgme_strsource(rc), gpgme_strerror(rc));
 
189
      return false;
 
190
    }
 
191
    
 
192
    rc = gpgme_op_import(mc.ctx, pgp_data);
 
193
    if(rc != GPG_ERR_NO_ERROR){
 
194
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
 
195
              gpgme_strsource(rc), gpgme_strerror(rc));
 
196
      return false;
 
197
    }
 
198
    
 
199
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
 
200
    if(ret == -1){
 
201
      perror("close");
 
202
    }
 
203
    gpgme_data_release(pgp_data);
 
204
    return true;
 
205
  }
 
206
  
 
207
  if(debug){
 
208
    fprintf(stderr, "Initializing GPGME\n");
108
209
  }
109
210
  
110
211
  /* Init GPGME */
111
212
  gpgme_check_version(NULL);
112
213
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
113
 
  if (rc != GPG_ERR_NO_ERROR){
 
214
  if(rc != GPG_ERR_NO_ERROR){
114
215
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
115
216
            gpgme_strsource(rc), gpgme_strerror(rc));
116
 
    return -1;
 
217
    return false;
117
218
  }
118
219
  
119
 
  /* Set GPGME home directory for the OpenPGP engine only */
120
 
  rc = gpgme_get_engine_info (&engine_info);
121
 
  if (rc != GPG_ERR_NO_ERROR){
 
220
    /* Set GPGME home directory for the OpenPGP engine only */
 
221
  rc = gpgme_get_engine_info(&engine_info);
 
222
  if(rc != GPG_ERR_NO_ERROR){
122
223
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
123
224
            gpgme_strsource(rc), gpgme_strerror(rc));
124
 
    return -1;
 
225
    return false;
125
226
  }
126
227
  while(engine_info != NULL){
127
228
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
128
229
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
129
 
                            engine_info->file_name, homedir);
 
230
                            engine_info->file_name, tempdir);
130
231
      break;
131
232
    }
132
233
    engine_info = engine_info->next;
133
234
  }
134
235
  if(engine_info == NULL){
135
 
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
136
 
    return -1;
 
236
    fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
 
237
    return false;
 
238
  }
 
239
  
 
240
  /* Create new GPGME "context" */
 
241
  rc = gpgme_new(&(mc.ctx));
 
242
  if(rc != GPG_ERR_NO_ERROR){
 
243
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
 
244
            gpgme_strsource(rc), gpgme_strerror(rc));
 
245
    return false;
 
246
  }
 
247
  
 
248
  if(not import_key(pubkey) or not import_key(seckey)){
 
249
    return false;
 
250
  }
 
251
  
 
252
  return true;
 
253
}
 
254
 
 
255
/* 
 
256
 * Decrypt OpenPGP data.
 
257
 * Returns -1 on error
 
258
 */
 
259
static ssize_t pgp_packet_decrypt(const char *cryptotext,
 
260
                                  size_t crypto_size,
 
261
                                  char **plaintext){
 
262
  gpgme_data_t dh_crypto, dh_plain;
 
263
  gpgme_error_t rc;
 
264
  ssize_t ret;
 
265
  size_t plaintext_capacity = 0;
 
266
  ssize_t plaintext_length = 0;
 
267
  
 
268
  if(debug){
 
269
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
137
270
  }
138
271
  
139
272
  /* Create new GPGME data buffer from memory cryptotext */
140
273
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
141
274
                               0);
142
 
  if (rc != GPG_ERR_NO_ERROR){
 
275
  if(rc != GPG_ERR_NO_ERROR){
143
276
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
144
277
            gpgme_strsource(rc), gpgme_strerror(rc));
145
278
    return -1;
147
280
  
148
281
  /* Create new empty GPGME data buffer for the plaintext */
149
282
  rc = gpgme_data_new(&dh_plain);
150
 
  if (rc != GPG_ERR_NO_ERROR){
 
283
  if(rc != GPG_ERR_NO_ERROR){
151
284
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
152
285
            gpgme_strsource(rc), gpgme_strerror(rc));
153
286
    gpgme_data_release(dh_crypto);
154
287
    return -1;
155
288
  }
156
289
  
157
 
  /* Create new GPGME "context" */
158
 
  rc = gpgme_new(&ctx);
159
 
  if (rc != GPG_ERR_NO_ERROR){
160
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
161
 
            gpgme_strsource(rc), gpgme_strerror(rc));
162
 
    plaintext_length = -1;
163
 
    goto decrypt_end;
164
 
  }
165
 
  
166
290
  /* Decrypt data from the cryptotext data buffer to the plaintext
167
291
     data buffer */
168
 
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
169
 
  if (rc != GPG_ERR_NO_ERROR){
 
292
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
293
  if(rc != GPG_ERR_NO_ERROR){
170
294
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
171
295
            gpgme_strsource(rc), gpgme_strerror(rc));
172
296
    plaintext_length = -1;
173
 
    goto decrypt_end;
174
 
  }
175
 
  
176
 
  if(debug){
177
 
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
178
 
  }
179
 
  
180
 
  if (debug){
181
 
    gpgme_decrypt_result_t result;
182
 
    result = gpgme_op_decrypt_result(ctx);
183
 
    if (result == NULL){
184
 
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
185
 
    } else {
186
 
      fprintf(stderr, "Unsupported algorithm: %s\n",
187
 
              result->unsupported_algorithm);
188
 
      fprintf(stderr, "Wrong key usage: %d\n",
189
 
              result->wrong_key_usage);
190
 
      if(result->file_name != NULL){
191
 
        fprintf(stderr, "File name: %s\n", result->file_name);
192
 
      }
193
 
      gpgme_recipient_t recipient;
194
 
      recipient = result->recipients;
195
 
      if(recipient){
 
297
    if(debug){
 
298
      gpgme_decrypt_result_t result;
 
299
      result = gpgme_op_decrypt_result(mc.ctx);
 
300
      if(result == NULL){
 
301
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
302
      } else {
 
303
        fprintf(stderr, "Unsupported algorithm: %s\n",
 
304
                result->unsupported_algorithm);
 
305
        fprintf(stderr, "Wrong key usage: %u\n",
 
306
                result->wrong_key_usage);
 
307
        if(result->file_name != NULL){
 
308
          fprintf(stderr, "File name: %s\n", result->file_name);
 
309
        }
 
310
        gpgme_recipient_t recipient;
 
311
        recipient = result->recipients;
196
312
        while(recipient != NULL){
197
313
          fprintf(stderr, "Public key algorithm: %s\n",
198
314
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
204
320
        }
205
321
      }
206
322
    }
 
323
    goto decrypt_end;
 
324
  }
 
325
  
 
326
  if(debug){
 
327
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
207
328
  }
208
329
  
209
330
  /* Seek back to the beginning of the GPGME plaintext data buffer */
210
 
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
211
 
    perror("pgpme_data_seek");
 
331
  if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
 
332
    perror("gpgme_data_seek");
212
333
    plaintext_length = -1;
213
334
    goto decrypt_end;
214
335
  }
215
336
  
216
337
  *plaintext = NULL;
217
338
  while(true){
218
 
    if (plaintext_length + BUFFER_SIZE > plaintext_capacity){
219
 
      *plaintext = realloc(*plaintext,
220
 
                            (unsigned int)plaintext_capacity
221
 
                            + BUFFER_SIZE);
222
 
      if (*plaintext == NULL){
223
 
        perror("realloc");
 
339
    plaintext_capacity = incbuffer(plaintext,
 
340
                                      (size_t)plaintext_length,
 
341
                                      plaintext_capacity);
 
342
    if(plaintext_capacity == 0){
 
343
        perror("incbuffer");
224
344
        plaintext_length = -1;
225
345
        goto decrypt_end;
226
 
      }
227
 
      plaintext_capacity += BUFFER_SIZE;
228
346
    }
229
347
    
230
348
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
231
349
                          BUFFER_SIZE);
232
350
    /* Print the data, if any */
233
 
    if (ret == 0){
 
351
    if(ret == 0){
234
352
      /* EOF */
235
353
      break;
236
354
    }
241
359
    }
242
360
    plaintext_length += ret;
243
361
  }
244
 
 
 
362
  
245
363
  if(debug){
246
364
    fprintf(stderr, "Decrypted password is: ");
247
 
    for(size_t i = 0; i < plaintext_length; i++){
 
365
    for(ssize_t i = 0; i < plaintext_length; i++){
248
366
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
249
367
    }
250
368
    fprintf(stderr, "\n");
260
378
  return plaintext_length;
261
379
}
262
380
 
263
 
static const char * safer_gnutls_strerror (int value) {
264
 
  const char *ret = gnutls_strerror (value);
265
 
  if (ret == NULL)
 
381
static const char * safer_gnutls_strerror(int value){
 
382
  const char *ret = gnutls_strerror(value); /* Spurious warning from
 
383
                                               -Wunreachable-code */
 
384
  if(ret == NULL)
266
385
    ret = "(unknown)";
267
386
  return ret;
268
387
}
269
388
 
 
389
/* GnuTLS log function callback */
270
390
static void debuggnutls(__attribute__((unused)) int level,
271
391
                        const char* string){
272
 
  fprintf(stderr, "%s", string);
 
392
  fprintf(stderr, "GnuTLS: %s", string);
273
393
}
274
394
 
275
 
static int initgnutls(mandos_context *mc, gnutls_session_t *session,
276
 
                      gnutls_dh_params_t *dh_params){
277
 
  const char *err;
 
395
static int init_gnutls_global(const char *pubkeyfilename,
 
396
                              const char *seckeyfilename){
278
397
  int ret;
279
398
  
280
399
  if(debug){
281
400
    fprintf(stderr, "Initializing GnuTLS\n");
282
401
  }
283
 
 
284
 
  if ((ret = gnutls_global_init ())
285
 
      != GNUTLS_E_SUCCESS) {
286
 
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
 
402
  
 
403
  ret = gnutls_global_init();
 
404
  if(ret != GNUTLS_E_SUCCESS){
 
405
    fprintf(stderr, "GnuTLS global_init: %s\n",
 
406
            safer_gnutls_strerror(ret));
287
407
    return -1;
288
408
  }
289
409
  
290
 
  if (debug){
 
410
  if(debug){
 
411
    /* "Use a log level over 10 to enable all debugging options."
 
412
     * - GnuTLS manual
 
413
     */
291
414
    gnutls_global_set_log_level(11);
292
415
    gnutls_global_set_log_function(debuggnutls);
293
416
  }
294
417
  
295
 
  /* openpgp credentials */
296
 
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
297
 
      != GNUTLS_E_SUCCESS) {
298
 
    fprintf (stderr, "memory error: %s\n",
299
 
             safer_gnutls_strerror(ret));
 
418
  /* OpenPGP credentials */
 
419
  gnutls_certificate_allocate_credentials(&mc.cred);
 
420
  if(ret != GNUTLS_E_SUCCESS){
 
421
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
 
422
                                                    from
 
423
                                                    -Wunreachable-code
 
424
                                                 */
 
425
            safer_gnutls_strerror(ret));
 
426
    gnutls_global_deinit();
300
427
    return -1;
301
428
  }
302
429
  
303
430
  if(debug){
304
 
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
305
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
306
 
            seckeyfile);
 
431
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
 
432
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
 
433
            seckeyfilename);
307
434
  }
308
435
  
309
436
  ret = gnutls_certificate_set_openpgp_key_file
310
 
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
311
 
  if (ret != GNUTLS_E_SUCCESS) {
312
 
    fprintf
313
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
314
 
       " '%s')\n",
315
 
       ret, pubkeyfile, seckeyfile);
316
 
    fprintf(stdout, "The Error is: %s\n",
317
 
            safer_gnutls_strerror(ret));
318
 
    return -1;
319
 
  }
320
 
  
321
 
  //GnuTLS server initialization
322
 
  if ((ret = gnutls_dh_params_init(dh_params))
323
 
      != GNUTLS_E_SUCCESS) {
324
 
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
325
 
             safer_gnutls_strerror(ret));
326
 
    return -1;
327
 
  }
328
 
  
329
 
  if ((ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits))
330
 
      != GNUTLS_E_SUCCESS) {
331
 
    fprintf (stderr, "Error in prime generation: %s\n",
332
 
             safer_gnutls_strerror(ret));
333
 
    return -1;
334
 
  }
335
 
  
336
 
  gnutls_certificate_set_dh_params(mc->cred, *dh_params);
337
 
  
338
 
  // GnuTLS session creation
339
 
  if ((ret = gnutls_init(session, GNUTLS_SERVER))
340
 
      != GNUTLS_E_SUCCESS){
 
437
    (mc.cred, pubkeyfilename, seckeyfilename,
 
438
     GNUTLS_OPENPGP_FMT_BASE64);
 
439
  if(ret != GNUTLS_E_SUCCESS){
 
440
    fprintf(stderr,
 
441
            "Error[%d] while reading the OpenPGP key pair ('%s',"
 
442
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
 
443
    fprintf(stderr, "The GnuTLS error is: %s\n",
 
444
            safer_gnutls_strerror(ret));
 
445
    goto globalfail;
 
446
  }
 
447
  
 
448
  /* GnuTLS server initialization */
 
449
  ret = gnutls_dh_params_init(&mc.dh_params);
 
450
  if(ret != GNUTLS_E_SUCCESS){
 
451
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
 
452
            " %s\n", safer_gnutls_strerror(ret));
 
453
    goto globalfail;
 
454
  }
 
455
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
456
  if(ret != GNUTLS_E_SUCCESS){
 
457
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
 
458
            safer_gnutls_strerror(ret));
 
459
    goto globalfail;
 
460
  }
 
461
  
 
462
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
463
  
 
464
  return 0;
 
465
  
 
466
 globalfail:
 
467
  
 
468
  gnutls_certificate_free_credentials(mc.cred);
 
469
  gnutls_global_deinit();
 
470
  gnutls_dh_params_deinit(mc.dh_params);
 
471
  return -1;
 
472
}
 
473
 
 
474
static int init_gnutls_session(gnutls_session_t *session){
 
475
  int ret;
 
476
  /* GnuTLS session creation */
 
477
  ret = gnutls_init(session, GNUTLS_SERVER);
 
478
  if(ret != GNUTLS_E_SUCCESS){
341
479
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
342
480
            safer_gnutls_strerror(ret));
343
481
  }
344
482
  
345
 
  if ((ret = gnutls_priority_set_direct(*session, mc->priority, &err))
346
 
      != GNUTLS_E_SUCCESS) {
347
 
    fprintf(stderr, "Syntax error at: %s\n", err);
348
 
    fprintf(stderr, "GnuTLS error: %s\n",
349
 
            safer_gnutls_strerror(ret));
350
 
    return -1;
 
483
  {
 
484
    const char *err;
 
485
    ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
486
    if(ret != GNUTLS_E_SUCCESS){
 
487
      fprintf(stderr, "Syntax error at: %s\n", err);
 
488
      fprintf(stderr, "GnuTLS error: %s\n",
 
489
              safer_gnutls_strerror(ret));
 
490
      gnutls_deinit(*session);
 
491
      return -1;
 
492
    }
351
493
  }
352
494
  
353
 
  if ((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
354
 
                                    mc->cred))
355
 
      != GNUTLS_E_SUCCESS) {
356
 
    fprintf(stderr, "Error setting a credentials set: %s\n",
 
495
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
496
                               mc.cred);
 
497
  if(ret != GNUTLS_E_SUCCESS){
 
498
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
357
499
            safer_gnutls_strerror(ret));
 
500
    gnutls_deinit(*session);
358
501
    return -1;
359
502
  }
360
503
  
361
504
  /* ignore client certificate if any. */
362
 
  gnutls_certificate_server_set_request (*session,
363
 
                                         GNUTLS_CERT_IGNORE);
 
505
  gnutls_certificate_server_set_request(*session,
 
506
                                        GNUTLS_CERT_IGNORE);
364
507
  
365
 
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
 
508
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
366
509
  
367
510
  return 0;
368
511
}
369
512
 
 
513
/* Avahi log function callback */
370
514
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
371
515
                      __attribute__((unused)) const char *txt){}
372
516
 
 
517
sig_atomic_t quit_now = 0;
 
518
int signal_received = 0;
 
519
 
 
520
/* Called when a Mandos server is found */
373
521
static int start_mandos_communication(const char *ip, uint16_t port,
374
522
                                      AvahiIfIndex if_index,
375
 
                                      mandos_context *mc){
 
523
                                      int af){
376
524
  int ret, tcp_sd;
377
 
  struct sockaddr_in6 to;
 
525
  ssize_t sret;
 
526
  union {
 
527
    struct sockaddr_in in;
 
528
    struct sockaddr_in6 in6;
 
529
  } to;
378
530
  char *buffer = NULL;
379
531
  char *decrypted_buffer;
380
532
  size_t buffer_length = 0;
381
533
  size_t buffer_capacity = 0;
382
534
  ssize_t decrypted_buffer_size;
383
 
  size_t written = 0;
 
535
  size_t written;
384
536
  int retval = 0;
385
 
  char interface[IF_NAMESIZE];
386
537
  gnutls_session_t session;
387
 
  gnutls_dh_params_t dh_params;
 
538
  int pf;                       /* Protocol family */
 
539
  
 
540
  switch(af){
 
541
  case AF_INET6:
 
542
    pf = PF_INET6;
 
543
    break;
 
544
  case AF_INET:
 
545
    pf = PF_INET;
 
546
    break;
 
547
  default:
 
548
    fprintf(stderr, "Bad address family: %d\n", af);
 
549
    return -1;
 
550
  }
 
551
  
 
552
  ret = init_gnutls_session(&session);
 
553
  if(ret != 0){
 
554
    return -1;
 
555
  }
388
556
  
389
557
  if(debug){
390
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
391
 
            ip, port);
 
558
    fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
 
559
            "\n", ip, port);
392
560
  }
393
561
  
394
 
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
395
 
  if(tcp_sd < 0) {
 
562
  tcp_sd = socket(pf, SOCK_STREAM, 0);
 
563
  if(tcp_sd < 0){
396
564
    perror("socket");
397
565
    return -1;
398
566
  }
399
 
 
400
 
  if(debug){
401
 
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
402
 
      perror("if_indextoname");
403
 
      return -1;
404
 
    }
405
 
    fprintf(stderr, "Binding to interface %s\n", interface);
406
 
  }
407
567
  
408
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
409
 
  to.sin6_family = AF_INET6;
410
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
411
 
  if (ret < 0 ){
 
568
  memset(&to, 0, sizeof(to));
 
569
  if(af == AF_INET6){
 
570
    to.in6.sin6_family = (sa_family_t)af;
 
571
    ret = inet_pton(af, ip, &to.in6.sin6_addr);
 
572
  } else {                      /* IPv4 */
 
573
    to.in.sin_family = (sa_family_t)af;
 
574
    ret = inet_pton(af, ip, &to.in.sin_addr);
 
575
  }
 
576
  if(ret < 0 ){
412
577
    perror("inet_pton");
413
578
    return -1;
414
579
  }
416
581
    fprintf(stderr, "Bad address: %s\n", ip);
417
582
    return -1;
418
583
  }
419
 
  to.sin6_port = htons(port);   /* Spurious warning */
420
 
  
421
 
  to.sin6_scope_id = (uint32_t)if_index;
 
584
  if(af == AF_INET6){
 
585
    to.in6.sin6_port = htons(port); /* Spurious warnings from
 
586
                                       -Wconversion and
 
587
                                       -Wunreachable-code */
 
588
    
 
589
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
 
590
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
 
591
                              -Wunreachable-code*/
 
592
      if(if_index == AVAHI_IF_UNSPEC){
 
593
        fprintf(stderr, "An IPv6 link-local address is incomplete"
 
594
                " without a network interface\n");
 
595
        return -1;
 
596
      }
 
597
      /* Set the network interface number as scope */
 
598
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
599
    }
 
600
  } else {
 
601
    to.in.sin_port = htons(port); /* Spurious warnings from
 
602
                                     -Wconversion and
 
603
                                     -Wunreachable-code */
 
604
  }
422
605
  
423
606
  if(debug){
424
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
425
 
    char addrstr[INET6_ADDRSTRLEN] = "";
426
 
    if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
427
 
                 sizeof(addrstr)) == NULL){
 
607
    if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
 
608
      char interface[IF_NAMESIZE];
 
609
      if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
610
        perror("if_indextoname");
 
611
      } else {
 
612
        fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
 
613
                ip, interface, port);
 
614
      }
 
615
    } else {
 
616
      fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
617
              port);
 
618
    }
 
619
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
 
620
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
 
621
    const char *pcret;
 
622
    if(af == AF_INET6){
 
623
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
 
624
                        sizeof(addrstr));
 
625
    } else {
 
626
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
 
627
                        sizeof(addrstr));
 
628
    }
 
629
    if(pcret == NULL){
428
630
      perror("inet_ntop");
429
631
    } else {
430
632
      if(strcmp(addrstr, ip) != 0){
433
635
    }
434
636
  }
435
637
  
436
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
437
 
  if (ret < 0){
 
638
  if(af == AF_INET6){
 
639
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
640
  } else {
 
641
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
642
  }
 
643
  if(ret < 0){
438
644
    perror("connect");
439
645
    return -1;
440
646
  }
441
647
  
442
 
  ret = initgnutls (mc, &session, &dh_params);
443
 
  if (ret != 0){
444
 
    retval = -1;
445
 
    return -1;
 
648
  const char *out = mandos_protocol_version;
 
649
  written = 0;
 
650
  while(true){
 
651
    size_t out_size = strlen(out);
 
652
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
653
                                   out_size - written));
 
654
    if(ret == -1){
 
655
      perror("write");
 
656
      retval = -1;
 
657
      goto mandos_end;
 
658
    }
 
659
    written += (size_t)ret;
 
660
    if(written < out_size){
 
661
      continue;
 
662
    } else {
 
663
      if(out == mandos_protocol_version){
 
664
        written = 0;
 
665
        out = "\r\n";
 
666
      } else {
 
667
        break;
 
668
      }
 
669
    }
446
670
  }
447
671
  
448
 
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
449
 
  
450
672
  if(debug){
451
673
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
452
674
  }
453
675
  
454
 
  ret = gnutls_handshake (session);
455
 
  
456
 
  if (ret != GNUTLS_E_SUCCESS){
 
676
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
677
  
 
678
  do{
 
679
    ret = gnutls_handshake(session);
 
680
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
681
  
 
682
  if(ret != GNUTLS_E_SUCCESS){
457
683
    if(debug){
458
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
459
 
      gnutls_perror (ret);
 
684
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
685
      gnutls_perror(ret);
460
686
    }
461
687
    retval = -1;
462
 
    goto exit;
 
688
    goto mandos_end;
463
689
  }
464
690
  
465
 
  //Retrieve OpenPGP packet that contains the wanted password
 
691
  /* Read OpenPGP packet that contains the wanted password */
466
692
  
467
693
  if(debug){
468
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
694
    fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
469
695
            ip);
470
696
  }
471
 
 
 
697
  
472
698
  while(true){
473
 
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
474
 
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
475
 
      if (buffer == NULL){
476
 
        perror("realloc");
477
 
        goto exit;
478
 
      }
479
 
      buffer_capacity += BUFFER_SIZE;
 
699
    buffer_capacity = incbuffer(&buffer, buffer_length,
 
700
                                   buffer_capacity);
 
701
    if(buffer_capacity == 0){
 
702
      perror("incbuffer");
 
703
      retval = -1;
 
704
      goto mandos_end;
480
705
    }
481
706
    
482
 
    ret = gnutls_record_recv(session, buffer+buffer_length,
483
 
                             BUFFER_SIZE);
484
 
    if (ret == 0){
 
707
    sret = gnutls_record_recv(session, buffer+buffer_length,
 
708
                              BUFFER_SIZE);
 
709
    if(sret == 0){
485
710
      break;
486
711
    }
487
 
    if (ret < 0){
488
 
      switch(ret){
 
712
    if(sret < 0){
 
713
      switch(sret){
489
714
      case GNUTLS_E_INTERRUPTED:
490
715
      case GNUTLS_E_AGAIN:
491
716
        break;
492
717
      case GNUTLS_E_REHANDSHAKE:
493
 
        ret = gnutls_handshake (session);
494
 
        if (ret < 0){
495
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
496
 
          gnutls_perror (ret);
 
718
        do{
 
719
          ret = gnutls_handshake(session);
 
720
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
721
        if(ret < 0){
 
722
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
723
          gnutls_perror(ret);
497
724
          retval = -1;
498
 
          goto exit;
 
725
          goto mandos_end;
499
726
        }
500
727
        break;
501
728
      default:
502
729
        fprintf(stderr, "Unknown error while reading data from"
503
 
                " encrypted session with mandos server\n");
 
730
                " encrypted session with Mandos server\n");
504
731
        retval = -1;
505
 
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
506
 
        goto exit;
 
732
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
733
        goto mandos_end;
507
734
      }
508
735
    } else {
509
 
      buffer_length += (size_t) ret;
 
736
      buffer_length += (size_t) sret;
510
737
    }
511
738
  }
512
739
  
513
 
  if (buffer_length > 0){
 
740
  if(debug){
 
741
    fprintf(stderr, "Closing TLS session\n");
 
742
  }
 
743
  
 
744
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
745
  
 
746
  if(buffer_length > 0){
514
747
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
515
748
                                               buffer_length,
516
 
                                               &decrypted_buffer,
517
 
                                               keydir);
518
 
    if (decrypted_buffer_size >= 0){
 
749
                                               &decrypted_buffer);
 
750
    if(decrypted_buffer_size >= 0){
 
751
      written = 0;
519
752
      while(written < (size_t) decrypted_buffer_size){
520
 
        ret = (int)fwrite (decrypted_buffer + written, 1,
521
 
                           (size_t)decrypted_buffer_size - written,
522
 
                           stdout);
 
753
        ret = (int)fwrite(decrypted_buffer + written, 1,
 
754
                          (size_t)decrypted_buffer_size - written,
 
755
                          stdout);
523
756
        if(ret == 0 and ferror(stdout)){
524
757
          if(debug){
525
758
            fprintf(stderr, "Error writing encrypted data: %s\n",
534
767
    } else {
535
768
      retval = -1;
536
769
    }
537
 
  }
538
 
 
539
 
  //shutdown procedure
540
 
 
541
 
  if(debug){
542
 
    fprintf(stderr, "Closing TLS session\n");
543
 
  }
544
 
 
 
770
  } else {
 
771
    retval = -1;
 
772
  }
 
773
  
 
774
  /* Shutdown procedure */
 
775
  
 
776
 mandos_end:
545
777
  free(buffer);
546
 
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
547
 
 exit:
548
 
  close(tcp_sd);
549
 
  gnutls_deinit (session);
550
 
  gnutls_certificate_free_credentials (mc->cred);
551
 
  gnutls_global_deinit ();
 
778
  ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
 
779
  if(ret == -1){
 
780
    perror("close");
 
781
  }
 
782
  gnutls_deinit(session);
552
783
  return retval;
553
784
}
554
785
 
555
786
static void resolve_callback(AvahiSServiceResolver *r,
556
787
                             AvahiIfIndex interface,
557
 
                             AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
788
                             AvahiProtocol proto,
558
789
                             AvahiResolverEvent event,
559
790
                             const char *name,
560
791
                             const char *type,
565
796
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
566
797
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
567
798
                             flags,
568
 
                             void* userdata) {
569
 
  mandos_context *mc = userdata;
570
 
  assert(r);                    /* Spurious warning */
 
799
                             AVAHI_GCC_UNUSED void* userdata){
 
800
  assert(r);
571
801
  
572
802
  /* Called whenever a service has been resolved successfully or
573
803
     timed out */
574
804
  
575
 
  switch (event) {
 
805
  if(quit_now){
 
806
    return;
 
807
  }
 
808
  
 
809
  switch(event){
576
810
  default:
577
811
  case AVAHI_RESOLVER_FAILURE:
578
 
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
579
 
            " type '%s' in domain '%s': %s\n", name, type, domain,
580
 
            avahi_strerror(avahi_server_errno(mc->server)));
 
812
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
 
813
            " of type '%s' in domain '%s': %s\n", name, type, domain,
 
814
            avahi_strerror(avahi_server_errno(mc.server)));
581
815
    break;
582
816
    
583
817
  case AVAHI_RESOLVER_FOUND:
585
819
      char ip[AVAHI_ADDRESS_STR_MAX];
586
820
      avahi_address_snprint(ip, sizeof(ip), address);
587
821
      if(debug){
588
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
589
 
                " port %d\n", name, host_name, ip, port);
 
822
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
 
823
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
 
824
                ip, (intmax_t)interface, port);
590
825
      }
591
 
      int ret = start_mandos_communication(ip, port, interface, mc);
592
 
      if (ret == 0){
593
 
        exit(EXIT_SUCCESS);
 
826
      int ret = start_mandos_communication(ip, port, interface,
 
827
                                           avahi_proto_to_af(proto));
 
828
      if(ret == 0){
 
829
        avahi_simple_poll_quit(mc.simple_poll);
594
830
      }
595
831
    }
596
832
  }
597
833
  avahi_s_service_resolver_free(r);
598
834
}
599
835
 
600
 
static void browse_callback( AvahiSServiceBrowser *b,
601
 
                             AvahiIfIndex interface,
602
 
                             AvahiProtocol protocol,
603
 
                             AvahiBrowserEvent event,
604
 
                             const char *name,
605
 
                             const char *type,
606
 
                             const char *domain,
607
 
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
608
 
                             flags,
609
 
                             void* userdata) {
610
 
  mandos_context *mc = userdata;
611
 
  assert(b);                    /* Spurious warning */
 
836
static void browse_callback(AvahiSServiceBrowser *b,
 
837
                            AvahiIfIndex interface,
 
838
                            AvahiProtocol protocol,
 
839
                            AvahiBrowserEvent event,
 
840
                            const char *name,
 
841
                            const char *type,
 
842
                            const char *domain,
 
843
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
844
                            flags,
 
845
                            AVAHI_GCC_UNUSED void* userdata){
 
846
  assert(b);
612
847
  
613
848
  /* Called whenever a new services becomes available on the LAN or
614
849
     is removed from the LAN */
615
850
  
616
 
  switch (event) {
 
851
  switch(event){
617
852
  default:
618
853
  case AVAHI_BROWSER_FAILURE:
619
854
    
620
 
    fprintf(stderr, "(Browser) %s\n",
621
 
            avahi_strerror(avahi_server_errno(mc->server)));
622
 
    avahi_simple_poll_quit(mc->simple_poll);
 
855
    fprintf(stderr, "(Avahi browser) %s\n",
 
856
            avahi_strerror(avahi_server_errno(mc.server)));
 
857
    avahi_simple_poll_quit(mc.simple_poll);
623
858
    return;
624
859
    
625
860
  case AVAHI_BROWSER_NEW:
626
 
    /* We ignore the returned resolver object. In the callback
627
 
       function we free it. If the server is terminated before
628
 
       the callback function is called the server will free
629
 
       the resolver for us. */
 
861
    /* We ignore the returned Avahi resolver object. In the callback
 
862
       function we free it. If the Avahi server is terminated before
 
863
       the callback function is called the Avahi server will free the
 
864
       resolver for us. */
630
865
    
631
 
    if (!(avahi_s_service_resolver_new(mc->server, interface,
632
 
                                       protocol, name, type, domain,
633
 
                                       AVAHI_PROTO_INET6, 0,
634
 
                                       resolve_callback, mc)))
635
 
      fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
636
 
              avahi_strerror(avahi_server_errno(mc->server)));
 
866
    if(avahi_s_service_resolver_new(mc.server, interface, protocol,
 
867
                                    name, type, domain, protocol, 0,
 
868
                                    resolve_callback, NULL) == NULL)
 
869
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
 
870
              name, avahi_strerror(avahi_server_errno(mc.server)));
637
871
    break;
638
872
    
639
873
  case AVAHI_BROWSER_REMOVE:
641
875
    
642
876
  case AVAHI_BROWSER_ALL_FOR_NOW:
643
877
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
878
    if(debug){
 
879
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
880
    }
644
881
    break;
645
882
  }
646
883
}
647
884
 
648
 
/* Combines file name and path and returns the malloced new
649
 
   string. some sane checks could/should be added */
650
 
static const char *combinepath(const char *first, const char *second){
651
 
  size_t f_len = strlen(first);
652
 
  size_t s_len = strlen(second);
653
 
  char *tmp = malloc(f_len + s_len + 2);
654
 
  if (tmp == NULL){
655
 
    return NULL;
656
 
  }
657
 
  if(f_len > 0){
658
 
    memcpy(tmp, first, f_len);  /* Spurious warning */
659
 
  }
660
 
  tmp[f_len] = '/';
661
 
  if(s_len > 0){
662
 
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
663
 
  }
664
 
  tmp[f_len + 1 + s_len] = '\0';
665
 
  return tmp;
 
885
/* stop main loop after sigterm has been called */
 
886
static void handle_sigterm(int sig){
 
887
  if(quit_now){
 
888
    return;
 
889
  }
 
890
  quit_now = 1;
 
891
  signal_received = sig;
 
892
  int old_errno = errno;
 
893
  if(mc.simple_poll != NULL){
 
894
    avahi_simple_poll_quit(mc.simple_poll);
 
895
  }
 
896
  errno = old_errno;
666
897
}
667
898
 
668
 
 
669
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
670
 
    AvahiServerConfig config;
671
 
    AvahiSServiceBrowser *sb = NULL;
672
 
    int error;
673
 
    int ret;
674
 
    int debug_int;
675
 
    int returncode = EXIT_SUCCESS;
676
 
    const char *interface = "eth0";
677
 
    struct ifreq network;
678
 
    int sd;
679
 
    char *connect_to = NULL;
680
 
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
681
 
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
682
 
                          .dh_bits = 1024, .priority = "SECURE256"};
 
899
int main(int argc, char *argv[]){
 
900
  AvahiSServiceBrowser *sb = NULL;
 
901
  int error;
 
902
  int ret;
 
903
  intmax_t tmpmax;
 
904
  char *tmp;
 
905
  int exitcode = EXIT_SUCCESS;
 
906
  const char *interface = "eth0";
 
907
  struct ifreq network;
 
908
  int sd = -1;
 
909
  bool take_down_interface = false;
 
910
  uid_t uid;
 
911
  gid_t gid;
 
912
  char *connect_to = NULL;
 
913
  char tempdir[] = "/tmp/mandosXXXXXX";
 
914
  bool tempdir_created = false;
 
915
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
916
  const char *seckey = PATHDIR "/" SECKEY;
 
917
  const char *pubkey = PATHDIR "/" PUBKEY;
 
918
  
 
919
  bool gnutls_initialized = false;
 
920
  bool gpgme_initialized = false;
 
921
  float delay = 2.5f;
 
922
  
 
923
  struct sigaction old_sigterm_action;
 
924
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
 
925
  
 
926
  {
 
927
    struct argp_option options[] = {
 
928
      { .name = "debug", .key = 128,
 
929
        .doc = "Debug mode", .group = 3 },
 
930
      { .name = "connect", .key = 'c',
 
931
        .arg = "ADDRESS:PORT",
 
932
        .doc = "Connect directly to a specific Mandos server",
 
933
        .group = 1 },
 
934
      { .name = "interface", .key = 'i',
 
935
        .arg = "NAME",
 
936
        .doc = "Network interface that will be used to search for"
 
937
        " Mandos servers",
 
938
        .group = 1 },
 
939
      { .name = "seckey", .key = 's',
 
940
        .arg = "FILE",
 
941
        .doc = "OpenPGP secret key file base name",
 
942
        .group = 1 },
 
943
      { .name = "pubkey", .key = 'p',
 
944
        .arg = "FILE",
 
945
        .doc = "OpenPGP public key file base name",
 
946
        .group = 2 },
 
947
      { .name = "dh-bits", .key = 129,
 
948
        .arg = "BITS",
 
949
        .doc = "Bit length of the prime number used in the"
 
950
        " Diffie-Hellman key exchange",
 
951
        .group = 2 },
 
952
      { .name = "priority", .key = 130,
 
953
        .arg = "STRING",
 
954
        .doc = "GnuTLS priority string for the TLS handshake",
 
955
        .group = 1 },
 
956
      { .name = "delay", .key = 131,
 
957
        .arg = "SECONDS",
 
958
        .doc = "Maximum delay to wait for interface startup",
 
959
        .group = 2 },
 
960
      { .name = NULL }
 
961
    };
683
962
    
684
 
    debug_int = debug ? 1 : 0;
685
 
    while (true){
686
 
      struct option long_options[] = {
687
 
        {"debug", no_argument, &debug_int, 1},
688
 
        {"connect", required_argument, NULL, 'c'},
689
 
        {"interface", required_argument, NULL, 'i'},
690
 
        {"keydir", required_argument, NULL, 'd'},
691
 
        {"seckey", required_argument, NULL, 's'},
692
 
        {"pubkey", required_argument, NULL, 'p'},
693
 
        {"dh-bits", required_argument, NULL, 'D'},
694
 
        {"priority", required_argument, NULL, 'P'},
695
 
        {0, 0, 0, 0} };
696
 
      
697
 
      int option_index = 0;
698
 
      ret = getopt_long (argc, argv, "i:", long_options,
699
 
                         &option_index);
700
 
      
701
 
      if (ret == -1){
702
 
        break;
703
 
      }
704
 
      
705
 
      switch(ret){
706
 
      case 0:
707
 
        break;
708
 
      case 'i':
709
 
        interface = optarg;
710
 
        break;
711
 
      case 'c':
712
 
        connect_to = optarg;
713
 
        break;
714
 
      case 'd':
715
 
        keydir = optarg;
716
 
        break;
717
 
      case 'p':
718
 
        pubkeyfile = optarg;
719
 
        break;
720
 
      case 's':
721
 
        seckeyfile = optarg;
722
 
        break;
723
 
      case 'D':
724
 
        errno = 0;
725
 
        mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
726
 
        if (errno){
727
 
          perror("strtol");
728
 
          exit(EXIT_FAILURE);
729
 
        }
730
 
        break;
731
 
      case 'P':
732
 
        mc.priority = optarg;
733
 
        break;
734
 
      case '?':
 
963
    error_t parse_opt(int key, char *arg,
 
964
                      struct argp_state *state){
 
965
      switch(key){
 
966
      case 128:                 /* --debug */
 
967
        debug = true;
 
968
        break;
 
969
      case 'c':                 /* --connect */
 
970
        connect_to = arg;
 
971
        break;
 
972
      case 'i':                 /* --interface */
 
973
        interface = arg;
 
974
        break;
 
975
      case 's':                 /* --seckey */
 
976
        seckey = arg;
 
977
        break;
 
978
      case 'p':                 /* --pubkey */
 
979
        pubkey = arg;
 
980
        break;
 
981
      case 129:                 /* --dh-bits */
 
982
        errno = 0;
 
983
        tmpmax = strtoimax(arg, &tmp, 10);
 
984
        if(errno != 0 or tmp == arg or *tmp != '\0'
 
985
           or tmpmax != (typeof(mc.dh_bits))tmpmax){
 
986
          fprintf(stderr, "Bad number of DH bits\n");
 
987
          exit(EXIT_FAILURE);
 
988
        }
 
989
        mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
 
990
        break;
 
991
      case 130:                 /* --priority */
 
992
        mc.priority = arg;
 
993
        break;
 
994
      case 131:                 /* --delay */
 
995
        errno = 0;
 
996
        delay = strtof(arg, &tmp);
 
997
        if(errno != 0 or tmp == arg or *tmp != '\0'){
 
998
          fprintf(stderr, "Bad delay\n");
 
999
          exit(EXIT_FAILURE);
 
1000
        }
 
1001
        break;
 
1002
      case ARGP_KEY_ARG:
 
1003
        argp_usage(state);
 
1004
      case ARGP_KEY_END:
 
1005
        break;
735
1006
      default:
736
 
        exit(EXIT_FAILURE);
 
1007
        return ARGP_ERR_UNKNOWN;
737
1008
      }
738
 
    }
739
 
    debug = debug_int ? true : false;
740
 
    
741
 
    pubkeyfile = combinepath(keydir, pubkeyfile);
742
 
    if (pubkeyfile == NULL){
743
 
      perror("combinepath");
744
 
      returncode = EXIT_FAILURE;
745
 
      goto exit;
746
 
    }
747
 
    
748
 
    seckeyfile = combinepath(keydir, seckeyfile);
749
 
    if (seckeyfile == NULL){
750
 
      perror("combinepath");
751
 
      goto exit;
752
 
    }
753
 
    
 
1009
      return 0;
 
1010
    }
 
1011
    
 
1012
    struct argp argp = { .options = options, .parser = parse_opt,
 
1013
                         .args_doc = "",
 
1014
                         .doc = "Mandos client -- Get and decrypt"
 
1015
                         " passwords from a Mandos server" };
 
1016
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
 
1017
    if(ret == ARGP_ERR_UNKNOWN){
 
1018
      fprintf(stderr, "Unknown error while parsing arguments\n");
 
1019
      exitcode = EXIT_FAILURE;
 
1020
      goto end;
 
1021
    }
 
1022
  }
 
1023
  
 
1024
  if(not debug){
 
1025
    avahi_set_log_function(empty_log);
 
1026
  }
 
1027
  
 
1028
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
 
1029
     from the signal handler */
 
1030
  /* Initialize the pseudo-RNG for Avahi */
 
1031
  srand((unsigned int) time(NULL));
 
1032
  mc.simple_poll = avahi_simple_poll_new();
 
1033
  if(mc.simple_poll == NULL){
 
1034
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
 
1035
    exitcode = EXIT_FAILURE;
 
1036
    goto end;
 
1037
  }
 
1038
  
 
1039
  sigemptyset(&sigterm_action.sa_mask);
 
1040
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
 
1041
  if(ret == -1){
 
1042
    perror("sigaddset");
 
1043
    exitcode = EXIT_FAILURE;
 
1044
    goto end;
 
1045
  }
 
1046
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
 
1047
  if(ret == -1){
 
1048
    perror("sigaddset");
 
1049
    exitcode = EXIT_FAILURE;
 
1050
    goto end;
 
1051
  }
 
1052
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
 
1053
  if(ret == -1){
 
1054
    perror("sigaddset");
 
1055
    exitcode = EXIT_FAILURE;
 
1056
    goto end;
 
1057
  }
 
1058
  ret = sigaction(SIGINT, &sigterm_action, &old_sigterm_action);
 
1059
  if(ret == -1){
 
1060
    perror("sigaction");
 
1061
    exitcode = EXIT_FAILURE;
 
1062
    goto end;
 
1063
  }
 
1064
  ret = sigaction(SIGHUP, &sigterm_action, NULL);
 
1065
  if(ret == -1){
 
1066
    perror("sigaction");
 
1067
    exitcode = EXIT_FAILURE;
 
1068
    goto end;
 
1069
  }
 
1070
  ret = sigaction(SIGTERM, &sigterm_action, NULL);
 
1071
  if(ret == -1){
 
1072
    perror("sigaction");
 
1073
    exitcode = EXIT_FAILURE;
 
1074
    goto end;
 
1075
  }
 
1076
  
 
1077
  /* If the interface is down, bring it up */
 
1078
  if(interface[0] != '\0'){
754
1079
    if_index = (AvahiIfIndex) if_nametoindex(interface);
755
1080
    if(if_index == 0){
756
1081
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
757
 
      exit(EXIT_FAILURE);
758
 
    }
759
 
    
760
 
    if(connect_to != NULL){
761
 
      /* Connect directly, do not use Zeroconf */
762
 
      /* (Mainly meant for debugging) */
763
 
      char *address = strrchr(connect_to, ':');
764
 
      if(address == NULL){
765
 
        fprintf(stderr, "No colon in address\n");
766
 
        exit(EXIT_FAILURE);
767
 
      }
768
 
      errno = 0;
769
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
770
 
      if(errno){
771
 
        perror("Bad port number");
772
 
        exit(EXIT_FAILURE);
773
 
      }
774
 
      *address = '\0';
775
 
      address = connect_to;
776
 
      ret = start_mandos_communication(address, port, if_index, &mc);
777
 
      if(ret < 0){
778
 
        exit(EXIT_FAILURE);
779
 
      } else {
780
 
        exit(EXIT_SUCCESS);
781
 
      }
782
 
    }
 
1082
      exitcode = EXIT_FAILURE;
 
1083
      goto end;
 
1084
    }
 
1085
    
 
1086
    if(quit_now){
 
1087
      goto end;
 
1088
    }
 
1089
    
 
1090
#ifdef __linux__
 
1091
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1092
       messages to mess up the prompt */
 
1093
    ret = klogctl(8, NULL, 5);
 
1094
    bool restore_loglevel = true;
 
1095
    if(ret == -1){
 
1096
      restore_loglevel = false;
 
1097
      perror("klogctl");
 
1098
    }
 
1099
#endif  /* __linux__ */
783
1100
    
784
1101
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
785
 
    if(sd < 0) {
 
1102
    if(sd < 0){
786
1103
      perror("socket");
787
 
      returncode = EXIT_FAILURE;
788
 
      goto exit;
 
1104
      exitcode = EXIT_FAILURE;
 
1105
#ifdef __linux__
 
1106
      if(restore_loglevel){
 
1107
        ret = klogctl(7, NULL, 0);
 
1108
        if(ret == -1){
 
1109
          perror("klogctl");
 
1110
        }
 
1111
      }
 
1112
#endif  /* __linux__ */
 
1113
      goto end;
789
1114
    }
790
 
    strcpy(network.ifr_name, interface); /* Spurious warning */
 
1115
    strcpy(network.ifr_name, interface);
791
1116
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
792
1117
    if(ret == -1){
793
 
      
794
1118
      perror("ioctl SIOCGIFFLAGS");
795
 
      returncode = EXIT_FAILURE;
796
 
      goto exit;
 
1119
#ifdef __linux__
 
1120
      if(restore_loglevel){
 
1121
        ret = klogctl(7, NULL, 0);
 
1122
        if(ret == -1){
 
1123
          perror("klogctl");
 
1124
        }
 
1125
      }
 
1126
#endif  /* __linux__ */
 
1127
      exitcode = EXIT_FAILURE;
 
1128
      goto end;
797
1129
    }
798
1130
    if((network.ifr_flags & IFF_UP) == 0){
799
1131
      network.ifr_flags |= IFF_UP;
 
1132
      take_down_interface = true;
800
1133
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
801
1134
      if(ret == -1){
 
1135
        take_down_interface = false;
802
1136
        perror("ioctl SIOCSIFFLAGS");
803
 
        returncode = EXIT_FAILURE;
804
 
        goto exit;
805
 
      }
806
 
    }
807
 
    close(sd);
808
 
    
809
 
    if (not debug){
810
 
      avahi_set_log_function(empty_log);
811
 
    }
812
 
    
813
 
    /* Initialize the psuedo-RNG */
814
 
    srand((unsigned int) time(NULL));
815
 
 
816
 
    /* Allocate main loop object */
817
 
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
818
 
        fprintf(stderr, "Failed to create simple poll object.\n");
819
 
        returncode = EXIT_FAILURE;
820
 
        goto exit;
821
 
    }
822
 
 
823
 
    /* Do not publish any local records */
 
1137
        exitcode = EXIT_FAILURE;
 
1138
#ifdef __linux__
 
1139
        if(restore_loglevel){
 
1140
          ret = klogctl(7, NULL, 0);
 
1141
          if(ret == -1){
 
1142
            perror("klogctl");
 
1143
          }
 
1144
        }
 
1145
#endif  /* __linux__ */
 
1146
        goto end;
 
1147
      }
 
1148
    }
 
1149
    /* sleep checking until interface is running */
 
1150
    for(int i=0; i < delay * 4; i++){
 
1151
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1152
      if(ret == -1){
 
1153
        perror("ioctl SIOCGIFFLAGS");
 
1154
      } else if(network.ifr_flags & IFF_RUNNING){
 
1155
        break;
 
1156
      }
 
1157
      struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1158
      ret = nanosleep(&sleeptime, NULL);
 
1159
      if(ret == -1 and errno != EINTR){
 
1160
        perror("nanosleep");
 
1161
      }
 
1162
    }
 
1163
    if(not take_down_interface){
 
1164
      /* We won't need the socket anymore */
 
1165
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1166
      if(ret == -1){
 
1167
        perror("close");
 
1168
      }
 
1169
    }
 
1170
#ifdef __linux__
 
1171
    if(restore_loglevel){
 
1172
      /* Restores kernel loglevel to default */
 
1173
      ret = klogctl(7, NULL, 0);
 
1174
      if(ret == -1){
 
1175
        perror("klogctl");
 
1176
      }
 
1177
    }
 
1178
#endif  /* __linux__ */
 
1179
  }
 
1180
  
 
1181
  if(quit_now){
 
1182
    goto end;
 
1183
  }
 
1184
  
 
1185
  uid = getuid();
 
1186
  gid = getgid();
 
1187
  
 
1188
  errno = 0;
 
1189
  setgid(gid);
 
1190
  if(ret == -1){
 
1191
    perror("setgid");
 
1192
  }
 
1193
  
 
1194
  ret = setuid(uid);
 
1195
  if(ret == -1){
 
1196
    perror("setuid");
 
1197
  }
 
1198
  
 
1199
  if(quit_now){
 
1200
    goto end;
 
1201
  }
 
1202
  
 
1203
  ret = init_gnutls_global(pubkey, seckey);
 
1204
  if(ret == -1){
 
1205
    fprintf(stderr, "init_gnutls_global failed\n");
 
1206
    exitcode = EXIT_FAILURE;
 
1207
    goto end;
 
1208
  } else {
 
1209
    gnutls_initialized = true;
 
1210
  }
 
1211
  
 
1212
  if(quit_now){
 
1213
    goto end;
 
1214
  }
 
1215
  
 
1216
  tempdir_created = true;
 
1217
  if(mkdtemp(tempdir) == NULL){
 
1218
    tempdir_created = false;
 
1219
    perror("mkdtemp");
 
1220
    goto end;
 
1221
  }
 
1222
  
 
1223
  if(quit_now){
 
1224
    goto end;
 
1225
  }
 
1226
  
 
1227
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
1228
    fprintf(stderr, "init_gpgme failed\n");
 
1229
    exitcode = EXIT_FAILURE;
 
1230
    goto end;
 
1231
  } else {
 
1232
    gpgme_initialized = true;
 
1233
  }
 
1234
  
 
1235
  if(quit_now){
 
1236
    goto end;
 
1237
  }
 
1238
  
 
1239
  if(connect_to != NULL){
 
1240
    /* Connect directly, do not use Zeroconf */
 
1241
    /* (Mainly meant for debugging) */
 
1242
    char *address = strrchr(connect_to, ':');
 
1243
    if(address == NULL){
 
1244
      fprintf(stderr, "No colon in address\n");
 
1245
      exitcode = EXIT_FAILURE;
 
1246
      goto end;
 
1247
    }
 
1248
    
 
1249
    if(quit_now){
 
1250
      goto end;
 
1251
    }
 
1252
    
 
1253
    uint16_t port;
 
1254
    errno = 0;
 
1255
    tmpmax = strtoimax(address+1, &tmp, 10);
 
1256
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
 
1257
       or tmpmax != (uint16_t)tmpmax){
 
1258
      fprintf(stderr, "Bad port number\n");
 
1259
      exitcode = EXIT_FAILURE;
 
1260
      goto end;
 
1261
    }
 
1262
  
 
1263
    if(quit_now){
 
1264
      goto end;
 
1265
    }
 
1266
    
 
1267
    port = (uint16_t)tmpmax;
 
1268
    *address = '\0';
 
1269
    address = connect_to;
 
1270
    /* Colon in address indicates IPv6 */
 
1271
    int af;
 
1272
    if(strchr(address, ':') != NULL){
 
1273
      af = AF_INET6;
 
1274
    } else {
 
1275
      af = AF_INET;
 
1276
    }
 
1277
    
 
1278
    if(quit_now){
 
1279
      goto end;
 
1280
    }
 
1281
    
 
1282
    ret = start_mandos_communication(address, port, if_index, af);
 
1283
    if(ret < 0){
 
1284
      exitcode = EXIT_FAILURE;
 
1285
    } else {
 
1286
      exitcode = EXIT_SUCCESS;
 
1287
    }
 
1288
    goto end;
 
1289
  }
 
1290
  
 
1291
  if(quit_now){
 
1292
    goto end;
 
1293
  }
 
1294
  
 
1295
  {
 
1296
    AvahiServerConfig config;
 
1297
    /* Do not publish any local Zeroconf records */
824
1298
    avahi_server_config_init(&config);
825
1299
    config.publish_hinfo = 0;
826
1300
    config.publish_addresses = 0;
827
1301
    config.publish_workstation = 0;
828
1302
    config.publish_domain = 0;
829
 
 
 
1303
    
830
1304
    /* Allocate a new server */
831
 
    mc.server=avahi_server_new(avahi_simple_poll_get(mc.simple_poll),
832
 
                               &config, NULL, NULL, &error);
 
1305
    mc.server = avahi_server_new(avahi_simple_poll_get
 
1306
                                 (mc.simple_poll), &config, NULL,
 
1307
                                 NULL, &error);
833
1308
    
834
 
    /* Free the configuration data */
 
1309
    /* Free the Avahi configuration data */
835
1310
    avahi_server_config_free(&config);
836
 
    
837
 
    /* Check if creating the server object succeeded */
838
 
    if (!mc.server) {
839
 
        fprintf(stderr, "Failed to create server: %s\n",
840
 
                avahi_strerror(error));
841
 
        returncode = EXIT_FAILURE;
842
 
        goto exit;
843
 
    }
844
 
    
845
 
    /* Create the service browser */
846
 
    sb = avahi_s_service_browser_new(mc.server, if_index,
847
 
                                     AVAHI_PROTO_INET6,
848
 
                                     "_mandos._tcp", NULL, 0,
849
 
                                     browse_callback, &mc);
850
 
    if (!sb) {
851
 
        fprintf(stderr, "Failed to create service browser: %s\n",
852
 
                avahi_strerror(avahi_server_errno(mc.server)));
853
 
        returncode = EXIT_FAILURE;
854
 
        goto exit;
855
 
    }
856
 
    
857
 
    /* Run the main loop */
858
 
 
859
 
    if (debug){
860
 
      fprintf(stderr, "Starting avahi loop search\n");
861
 
    }
862
 
    
863
 
    avahi_simple_poll_loop(mc.simple_poll);
864
 
    
865
 
 exit:
866
 
 
867
 
    if (debug){
868
 
      fprintf(stderr, "%s exiting\n", argv[0]);
869
 
    }
870
 
    
871
 
    /* Cleanup things */
872
 
    if (sb)
873
 
        avahi_s_service_browser_free(sb);
874
 
    
875
 
    if (mc.server)
876
 
        avahi_server_free(mc.server);
877
 
 
878
 
    if (mc.simple_poll)
879
 
        avahi_simple_poll_free(mc.simple_poll);
880
 
    free(pubkeyfile);
881
 
    free(seckeyfile);
882
 
    
883
 
    return returncode;
 
1311
  }
 
1312
  
 
1313
  /* Check if creating the Avahi server object succeeded */
 
1314
  if(mc.server == NULL){
 
1315
    fprintf(stderr, "Failed to create Avahi server: %s\n",
 
1316
            avahi_strerror(error));
 
1317
    exitcode = EXIT_FAILURE;
 
1318
    goto end;
 
1319
  }
 
1320
  
 
1321
  if(quit_now){
 
1322
    goto end;
 
1323
  }
 
1324
  
 
1325
  /* Create the Avahi service browser */
 
1326
  sb = avahi_s_service_browser_new(mc.server, if_index,
 
1327
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
 
1328
                                   NULL, 0, browse_callback, NULL);
 
1329
  if(sb == NULL){
 
1330
    fprintf(stderr, "Failed to create service browser: %s\n",
 
1331
            avahi_strerror(avahi_server_errno(mc.server)));
 
1332
    exitcode = EXIT_FAILURE;
 
1333
    goto end;
 
1334
  }
 
1335
  
 
1336
  if(quit_now){
 
1337
    goto end;
 
1338
  }
 
1339
  
 
1340
  /* Run the main loop */
 
1341
  
 
1342
  if(debug){
 
1343
    fprintf(stderr, "Starting Avahi loop search\n");
 
1344
  }
 
1345
  
 
1346
  avahi_simple_poll_loop(mc.simple_poll);
 
1347
  
 
1348
 end:
 
1349
  
 
1350
  if(debug){
 
1351
    fprintf(stderr, "%s exiting\n", argv[0]);
 
1352
  }
 
1353
  
 
1354
  /* Cleanup things */
 
1355
  if(sb != NULL)
 
1356
    avahi_s_service_browser_free(sb);
 
1357
  
 
1358
  if(mc.server != NULL)
 
1359
    avahi_server_free(mc.server);
 
1360
  
 
1361
  if(mc.simple_poll != NULL)
 
1362
    avahi_simple_poll_free(mc.simple_poll);
 
1363
  
 
1364
  if(gnutls_initialized){
 
1365
    gnutls_certificate_free_credentials(mc.cred);
 
1366
    gnutls_global_deinit();
 
1367
    gnutls_dh_params_deinit(mc.dh_params);
 
1368
  }
 
1369
  
 
1370
  if(gpgme_initialized){
 
1371
    gpgme_release(mc.ctx);
 
1372
  }
 
1373
  
 
1374
  /* Take down the network interface */
 
1375
  if(take_down_interface){
 
1376
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1377
    if(ret == -1){
 
1378
      perror("ioctl SIOCGIFFLAGS");
 
1379
    } else if(network.ifr_flags & IFF_UP) {
 
1380
      network.ifr_flags &= ~IFF_UP; /* clear flag */
 
1381
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
1382
      if(ret == -1){
 
1383
        perror("ioctl SIOCSIFFLAGS");
 
1384
      }
 
1385
    }
 
1386
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1387
    if(ret == -1){
 
1388
      perror("close");
 
1389
    }
 
1390
  }
 
1391
  
 
1392
  /* Removes the temp directory used by GPGME */
 
1393
  if(tempdir_created){
 
1394
    DIR *d;
 
1395
    struct dirent *direntry;
 
1396
    d = opendir(tempdir);
 
1397
    if(d == NULL){
 
1398
      if(errno != ENOENT){
 
1399
        perror("opendir");
 
1400
      }
 
1401
    } else {
 
1402
      while(true){
 
1403
        direntry = readdir(d);
 
1404
        if(direntry == NULL){
 
1405
          break;
 
1406
        }
 
1407
        /* Skip "." and ".." */
 
1408
        if(direntry->d_name[0] == '.'
 
1409
           and (direntry->d_name[1] == '\0'
 
1410
                or (direntry->d_name[1] == '.'
 
1411
                    and direntry->d_name[2] == '\0'))){
 
1412
          continue;
 
1413
        }
 
1414
        char *fullname = NULL;
 
1415
        ret = asprintf(&fullname, "%s/%s", tempdir,
 
1416
                       direntry->d_name);
 
1417
        if(ret < 0){
 
1418
          perror("asprintf");
 
1419
          continue;
 
1420
        }
 
1421
        ret = remove(fullname);
 
1422
        if(ret == -1){
 
1423
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
 
1424
                  strerror(errno));
 
1425
        }
 
1426
        free(fullname);
 
1427
      }
 
1428
      closedir(d);
 
1429
    }
 
1430
    ret = rmdir(tempdir);
 
1431
    if(ret == -1 and errno != ENOENT){
 
1432
      perror("rmdir");
 
1433
    }
 
1434
  }
 
1435
  
 
1436
  if(quit_now){
 
1437
    ret = sigaction(signal_received, &old_sigterm_action, NULL);
 
1438
    if(ret == -1){
 
1439
      perror("sigaction");
 
1440
    }
 
1441
    raise(signal_received);
 
1442
  }
 
1443
  
 
1444
  return exitcode;
884
1445
}