/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-07-12 20:15:29 UTC
  • Revision ID: teddy@fukt.bsnet.se-20090712201529-mtsc3hjyfm5wlk1r
* mandos (ClientHandler.handle): Also pass client address in
                                "NOTFOUND" message.

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