/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-06-02 10:33:04 UTC
  • Revision ID: teddy@fukt.bsnet.se-20090602103304-k6eokrft7wr00255
* plugins.d/mandos-client.c (pgp_packet_decrypt): Remove redundant
                                                 "if" statement.

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
25
26
 * along with this program.  If not, see
26
27
 * <http://www.gnu.org/licenses/>.
27
28
 * 
28
 
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
29
 
 * <https://www.fukt.bsnet.se/~teddy/>.
 
29
 * Contact the authors at <mandos@fukt.bsnet.se>.
30
30
 */
31
31
 
32
32
/* Needed by GPGME, specifically gpgme_data_seek() */
 
33
#ifndef _LARGEFILE_SOURCE
33
34
#define _LARGEFILE_SOURCE
 
35
#endif
 
36
#ifndef _FILE_OFFSET_BITS
34
37
#define _FILE_OFFSET_BITS 64
35
 
 
36
 
#include <stdio.h>
37
 
#include <assert.h>
38
 
#include <stdlib.h>
39
 
#include <time.h>
40
 
#include <net/if.h>             /* if_nametoindex */
41
 
 
 
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_* */
42
94
#include <avahi-core/core.h>
43
95
#include <avahi-core/lookup.h>
44
96
#include <avahi-core/log.h>
46
98
#include <avahi-common/malloc.h>
47
99
#include <avahi-common/error.h>
48
100
 
49
 
//mandos client part
50
 
#include <sys/types.h>          /* socket(), inet_pton() */
51
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
52
 
                                   struct in6_addr, inet_pton() */
53
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
54
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
55
 
 
56
 
#include <unistd.h>             /* close() */
57
 
#include <netinet/in.h>
58
 
#include <stdbool.h>            /* true */
59
 
#include <string.h>             /* memset */
60
 
#include <arpa/inet.h>          /* inet_pton() */
61
 
#include <iso646.h>             /* not */
62
 
 
63
 
// gpgme
64
 
#include <errno.h>              /* perror() */
65
 
#include <gpgme.h>
66
 
 
67
 
// getopt long
68
 
#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_* */
69
117
 
70
118
#define BUFFER_SIZE 256
71
 
#define DH_BITS 1024
72
119
 
73
 
const char *certdir = "/conf/conf.d/cryptkeyreq/";
74
 
const char *certfile = "openpgp-client.txt";
75
 
const char *certkey = "openpgp-client-key.txt";
 
120
#define PATHDIR "/conf/conf.d/mandos"
 
121
#define SECKEY "seckey.txt"
 
122
#define PUBKEY "pubkey.txt"
76
123
 
77
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>";
78
128
 
 
129
/* Used for passing in values through the Avahi callback functions */
79
130
typedef struct {
80
 
  gnutls_session_t session;
 
131
  AvahiSimplePoll *simple_poll;
 
132
  AvahiServer *server;
81
133
  gnutls_certificate_credentials_t cred;
 
134
  unsigned int dh_bits;
82
135
  gnutls_dh_params_t dh_params;
83
 
} encrypted_session;
84
 
 
85
 
 
86
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
87
 
                            char **new_packet, 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
 
249
 
void debuggnutls(__attribute__((unused)) int level,
250
 
                 const char* string){
251
 
  fprintf(stderr, "%s", string);
 
389
/* GnuTLS log function callback */
 
390
static void debuggnutls(__attribute__((unused)) int level,
 
391
                        const char* string){
 
392
  fprintf(stderr, "GnuTLS: %s", string);
252
393
}
253
394
 
254
 
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
 
348
 
void empty_log(__attribute__((unused)) AvahiLogLevel level,
349
 
               __attribute__((unused)) const char *txt){}
 
513
/* Avahi log function callback */
 
514
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
515
                      __attribute__((unused)) const char *txt){}
350
516
 
351
 
int start_mandos_communication(const char *ip, uint16_t port,
352
 
                               AvahiIfIndex if_index){
 
517
/* Called when a Mandos server is found */
 
518
static int start_mandos_communication(const char *ip, uint16_t port,
 
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;
 
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");
628
873
    }
629
 
}
630
 
 
631
 
/* combinds file name and path and returns the malloced new string. som sane checks could/should be added */
632
 
const char *combinepath(const char *first, const char *second){
 
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;
633
898
  char *tmp;
634
 
  tmp = malloc(strlen(first) + strlen(second) + 2);
635
 
  if (tmp == NULL){
636
 
    perror("malloc");
637
 
    return NULL;
638
 
  }
639
 
  strcpy(tmp, first);
640
 
  if (first[0] != '\0' and first[strlen(first) - 1] != '/'){
641
 
    strcat(tmp, "/");
642
 
  }
643
 
  strcat(tmp, second);
644
 
  return tmp;
645
 
}
646
 
 
647
 
 
648
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
 
899
  int exitcode = EXIT_SUCCESS;
 
900
  const char *interface = "eth0";
 
901
  struct ifreq network;
 
902
  int sd;
 
903
  uid_t uid;
 
904
  gid_t gid;
 
905
  char *connect_to = NULL;
 
906
  char tempdir[] = "/tmp/mandosXXXXXX";
 
907
  bool tempdir_created = false;
 
908
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
909
  const char *seckey = PATHDIR "/" SECKEY;
 
910
  const char *pubkey = PATHDIR "/" PUBKEY;
 
911
  
 
912
  bool gnutls_initialized = false;
 
913
  bool gpgme_initialized = false;
 
914
  float delay = 2.5f;
 
915
  
 
916
  struct sigaction old_sigterm_action;
 
917
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
 
918
  
 
919
  {
 
920
    struct argp_option options[] = {
 
921
      { .name = "debug", .key = 128,
 
922
        .doc = "Debug mode", .group = 3 },
 
923
      { .name = "connect", .key = 'c',
 
924
        .arg = "ADDRESS:PORT",
 
925
        .doc = "Connect directly to a specific Mandos server",
 
926
        .group = 1 },
 
927
      { .name = "interface", .key = 'i',
 
928
        .arg = "NAME",
 
929
        .doc = "Network interface that will be used to search for"
 
930
        " Mandos servers",
 
931
        .group = 1 },
 
932
      { .name = "seckey", .key = 's',
 
933
        .arg = "FILE",
 
934
        .doc = "OpenPGP secret key file base name",
 
935
        .group = 1 },
 
936
      { .name = "pubkey", .key = 'p',
 
937
        .arg = "FILE",
 
938
        .doc = "OpenPGP public key file base name",
 
939
        .group = 2 },
 
940
      { .name = "dh-bits", .key = 129,
 
941
        .arg = "BITS",
 
942
        .doc = "Bit length of the prime number used in the"
 
943
        " Diffie-Hellman key exchange",
 
944
        .group = 2 },
 
945
      { .name = "priority", .key = 130,
 
946
        .arg = "STRING",
 
947
        .doc = "GnuTLS priority string for the TLS handshake",
 
948
        .group = 1 },
 
949
      { .name = "delay", .key = 131,
 
950
        .arg = "SECONDS",
 
951
        .doc = "Maximum delay to wait for interface startup",
 
952
        .group = 2 },
 
953
      { .name = NULL }
 
954
    };
 
955
    
 
956
    error_t parse_opt(int key, char *arg,
 
957
                      struct argp_state *state){
 
958
      switch(key){
 
959
      case 128:                 /* --debug */
 
960
        debug = true;
 
961
        break;
 
962
      case 'c':                 /* --connect */
 
963
        connect_to = arg;
 
964
        break;
 
965
      case 'i':                 /* --interface */
 
966
        interface = arg;
 
967
        break;
 
968
      case 's':                 /* --seckey */
 
969
        seckey = arg;
 
970
        break;
 
971
      case 'p':                 /* --pubkey */
 
972
        pubkey = arg;
 
973
        break;
 
974
      case 129:                 /* --dh-bits */
 
975
        errno = 0;
 
976
        tmpmax = strtoimax(arg, &tmp, 10);
 
977
        if(errno != 0 or tmp == arg or *tmp != '\0'
 
978
           or tmpmax != (typeof(mc.dh_bits))tmpmax){
 
979
          fprintf(stderr, "Bad number of DH bits\n");
 
980
          exit(EXIT_FAILURE);
 
981
        }
 
982
        mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
 
983
        break;
 
984
      case 130:                 /* --priority */
 
985
        mc.priority = arg;
 
986
        break;
 
987
      case 131:                 /* --delay */
 
988
        errno = 0;
 
989
        delay = strtof(arg, &tmp);
 
990
        if(errno != 0 or tmp == arg or *tmp != '\0'){
 
991
          fprintf(stderr, "Bad delay\n");
 
992
          exit(EXIT_FAILURE);
 
993
        }
 
994
        break;
 
995
      case ARGP_KEY_ARG:
 
996
        argp_usage(state);
 
997
      case ARGP_KEY_END:
 
998
        break;
 
999
      default:
 
1000
        return ARGP_ERR_UNKNOWN;
 
1001
      }
 
1002
      return 0;
 
1003
    }
 
1004
    
 
1005
    struct argp argp = { .options = options, .parser = parse_opt,
 
1006
                         .args_doc = "",
 
1007
                         .doc = "Mandos client -- Get and decrypt"
 
1008
                         " passwords from a Mandos server" };
 
1009
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
 
1010
    if(ret == ARGP_ERR_UNKNOWN){
 
1011
      fprintf(stderr, "Unknown error while parsing arguments\n");
 
1012
      exitcode = EXIT_FAILURE;
 
1013
      goto end;
 
1014
    }
 
1015
  }
 
1016
  
 
1017
  if(not debug){
 
1018
    avahi_set_log_function(empty_log);
 
1019
  }
 
1020
  
 
1021
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
 
1022
     from the signal handler */
 
1023
  /* Initialize the pseudo-RNG for Avahi */
 
1024
  srand((unsigned int) time(NULL));
 
1025
  mc.simple_poll = avahi_simple_poll_new();
 
1026
  if(mc.simple_poll == NULL){
 
1027
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
 
1028
    exitcode = EXIT_FAILURE;
 
1029
    goto end;
 
1030
  }
 
1031
  
 
1032
  sigemptyset(&sigterm_action.sa_mask);
 
1033
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
 
1034
  if(ret == -1){
 
1035
    perror("sigaddset");
 
1036
    exitcode = EXIT_FAILURE;
 
1037
    goto end;
 
1038
  }
 
1039
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
 
1040
  if(ret == -1){
 
1041
    perror("sigaddset");
 
1042
    exitcode = EXIT_FAILURE;
 
1043
    goto end;
 
1044
  }
 
1045
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
 
1046
  if(ret == -1){
 
1047
    perror("sigaddset");
 
1048
    exitcode = EXIT_FAILURE;
 
1049
    goto end;
 
1050
  }
 
1051
  ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
 
1052
  if(ret == -1){
 
1053
    perror("sigaction");
 
1054
    exitcode = EXIT_FAILURE;
 
1055
    goto end;
 
1056
  }  
 
1057
  
 
1058
  /* If the interface is down, bring it up */
 
1059
  if(interface[0] != '\0'){
 
1060
#ifdef __linux__
 
1061
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1062
       messages to mess up the prompt */
 
1063
    ret = klogctl(8, NULL, 5);
 
1064
    bool restore_loglevel = true;
 
1065
    if(ret == -1){
 
1066
      restore_loglevel = false;
 
1067
      perror("klogctl");
 
1068
    }
 
1069
#endif  /* __linux__ */
 
1070
    
 
1071
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1072
    if(sd < 0){
 
1073
      perror("socket");
 
1074
      exitcode = EXIT_FAILURE;
 
1075
#ifdef __linux__
 
1076
      if(restore_loglevel){
 
1077
        ret = klogctl(7, NULL, 0);
 
1078
        if(ret == -1){
 
1079
          perror("klogctl");
 
1080
        }
 
1081
      }
 
1082
#endif  /* __linux__ */
 
1083
      goto end;
 
1084
    }
 
1085
    strcpy(network.ifr_name, interface);
 
1086
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1087
    if(ret == -1){
 
1088
      perror("ioctl SIOCGIFFLAGS");
 
1089
#ifdef __linux__
 
1090
      if(restore_loglevel){
 
1091
        ret = klogctl(7, NULL, 0);
 
1092
        if(ret == -1){
 
1093
          perror("klogctl");
 
1094
        }
 
1095
      }
 
1096
#endif  /* __linux__ */
 
1097
      exitcode = EXIT_FAILURE;
 
1098
      goto end;
 
1099
    }
 
1100
    if((network.ifr_flags & IFF_UP) == 0){
 
1101
      network.ifr_flags |= IFF_UP;
 
1102
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
1103
      if(ret == -1){
 
1104
        perror("ioctl SIOCSIFFLAGS");
 
1105
        exitcode = EXIT_FAILURE;
 
1106
#ifdef __linux__
 
1107
        if(restore_loglevel){
 
1108
          ret = klogctl(7, NULL, 0);
 
1109
          if(ret == -1){
 
1110
            perror("klogctl");
 
1111
          }
 
1112
        }
 
1113
#endif  /* __linux__ */
 
1114
        goto end;
 
1115
      }
 
1116
    }
 
1117
    /* sleep checking until interface is running */
 
1118
    for(int i=0; i < delay * 4; i++){
 
1119
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1120
      if(ret == -1){
 
1121
        perror("ioctl SIOCGIFFLAGS");
 
1122
      } else if(network.ifr_flags & IFF_RUNNING){
 
1123
        break;
 
1124
      }
 
1125
      struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1126
      ret = nanosleep(&sleeptime, NULL);
 
1127
      if(ret == -1 and errno != EINTR){
 
1128
        perror("nanosleep");
 
1129
      }
 
1130
    }
 
1131
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1132
    if(ret == -1){
 
1133
      perror("close");
 
1134
    }
 
1135
#ifdef __linux__
 
1136
    if(restore_loglevel){
 
1137
      /* Restores kernel loglevel to default */
 
1138
      ret = klogctl(7, NULL, 0);
 
1139
      if(ret == -1){
 
1140
        perror("klogctl");
 
1141
      }
 
1142
    }
 
1143
#endif  /* __linux__ */
 
1144
  }
 
1145
  
 
1146
  uid = getuid();
 
1147
  gid = getgid();
 
1148
  
 
1149
  errno = 0;
 
1150
  setgid(gid);
 
1151
  if(ret == -1){
 
1152
    perror("setgid");
 
1153
  }
 
1154
  
 
1155
  ret = setuid(uid);
 
1156
  if(ret == -1){
 
1157
    perror("setuid");
 
1158
  }
 
1159
  
 
1160
  ret = init_gnutls_global(pubkey, seckey);
 
1161
  if(ret == -1){
 
1162
    fprintf(stderr, "init_gnutls_global failed\n");
 
1163
    exitcode = EXIT_FAILURE;
 
1164
    goto end;
 
1165
  } else {
 
1166
    gnutls_initialized = true;
 
1167
  }
 
1168
  
 
1169
  if(mkdtemp(tempdir) == NULL){
 
1170
    perror("mkdtemp");
 
1171
    goto end;
 
1172
  }
 
1173
  tempdir_created = true;
 
1174
  
 
1175
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
1176
    fprintf(stderr, "init_gpgme failed\n");
 
1177
    exitcode = EXIT_FAILURE;
 
1178
    goto end;
 
1179
  } else {
 
1180
    gpgme_initialized = true;
 
1181
  }
 
1182
  
 
1183
  if(interface[0] != '\0'){
 
1184
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
1185
    if(if_index == 0){
 
1186
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
1187
      exitcode = EXIT_FAILURE;
 
1188
      goto end;
 
1189
    }
 
1190
  }
 
1191
  
 
1192
  if(connect_to != NULL){
 
1193
    /* Connect directly, do not use Zeroconf */
 
1194
    /* (Mainly meant for debugging) */
 
1195
    char *address = strrchr(connect_to, ':');
 
1196
    if(address == NULL){
 
1197
      fprintf(stderr, "No colon in address\n");
 
1198
      exitcode = EXIT_FAILURE;
 
1199
      goto end;
 
1200
    }
 
1201
    uint16_t port;
 
1202
    errno = 0;
 
1203
    tmpmax = strtoimax(address+1, &tmp, 10);
 
1204
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
 
1205
       or tmpmax != (uint16_t)tmpmax){
 
1206
      fprintf(stderr, "Bad port number\n");
 
1207
      exitcode = EXIT_FAILURE;
 
1208
      goto end;
 
1209
    }
 
1210
    port = (uint16_t)tmpmax;
 
1211
    *address = '\0';
 
1212
    address = connect_to;
 
1213
    /* Colon in address indicates IPv6 */
 
1214
    int af;
 
1215
    if(strchr(address, ':') != NULL){
 
1216
      af = AF_INET6;
 
1217
    } else {
 
1218
      af = AF_INET;
 
1219
    }
 
1220
    ret = start_mandos_communication(address, port, if_index, af);
 
1221
    if(ret < 0){
 
1222
      exitcode = EXIT_FAILURE;
 
1223
    } else {
 
1224
      exitcode = EXIT_SUCCESS;
 
1225
    }
 
1226
    goto end;
 
1227
  }
 
1228
    
 
1229
  {
649
1230
    AvahiServerConfig config;
650
 
    AvahiSServiceBrowser *sb = NULL;
651
 
    int error;
652
 
    int ret;
653
 
    int returncode = EXIT_SUCCESS;
654
 
    const char *interface = NULL;
655
 
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
656
 
    char *connect_to = NULL;
657
 
    
658
 
    while (true){
659
 
      static struct option long_options[] = {
660
 
        {"debug", no_argument, (int *)&debug, 1},
661
 
        {"connect", required_argument, 0, 'C'},
662
 
        {"interface", required_argument, 0, 'i'},
663
 
        {"certdir", required_argument, 0, 'd'},
664
 
        {"certkey", required_argument, 0, 'c'},
665
 
        {"certfile", required_argument, 0, 'k'},
666
 
        {0, 0, 0, 0} };
667
 
      
668
 
      int option_index = 0;
669
 
      ret = getopt_long (argc, argv, "i:", long_options,
670
 
                         &option_index);
671
 
      
672
 
      if (ret == -1){
673
 
        break;
674
 
      }
675
 
      
676
 
      switch(ret){
677
 
      case 0:
678
 
        break;
679
 
      case 'i':
680
 
        interface = optarg;
681
 
        break;
682
 
      case 'C':
683
 
        connect_to = optarg;
684
 
        break;
685
 
      case 'd':
686
 
        certdir = optarg;
687
 
        break;
688
 
      case 'c':
689
 
        certfile = optarg;
690
 
        break;
691
 
      case 'k':
692
 
        certkey = optarg;
693
 
        break;
694
 
      default:
695
 
        exit(EXIT_FAILURE);
696
 
      }
697
 
    }
698
 
 
699
 
    certfile = combinepath(certdir, certfile);
700
 
    if (certfile == NULL){
701
 
      goto exit;
702
 
    }
703
 
    
704
 
    if(interface != NULL){
705
 
      if_index = (AvahiIfIndex) if_nametoindex(interface);
706
 
      if(if_index == 0){
707
 
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
708
 
        exit(EXIT_FAILURE);
709
 
      }
710
 
    }
711
 
    
712
 
    if(connect_to != NULL){
713
 
      /* Connect directly, do not use Zeroconf */
714
 
      /* (Mainly meant for debugging) */
715
 
      char *address = strrchr(connect_to, ':');
716
 
      if(address == NULL){
717
 
        fprintf(stderr, "No colon in address\n");
718
 
        exit(EXIT_FAILURE);
719
 
      }
720
 
      errno = 0;
721
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
722
 
      if(errno){
723
 
        perror("Bad port number");
724
 
        exit(EXIT_FAILURE);
725
 
      }
726
 
      *address = '\0';
727
 
      address = connect_to;
728
 
      ret = start_mandos_communication(address, port, if_index);
729
 
      if(ret < 0){
730
 
        exit(EXIT_FAILURE);
731
 
      } else {
732
 
        exit(EXIT_SUCCESS);
733
 
      }
734
 
    }
735
 
    
736
 
    certkey = combinepath(certdir, certkey);
737
 
    if (certkey == NULL){
738
 
      goto exit;
739
 
    }
740
 
    
741
 
    if (not debug){
742
 
      avahi_set_log_function(empty_log);
743
 
    }
744
 
    
745
 
    /* Initialize the psuedo-RNG */
746
 
    srand((unsigned int) time(NULL));
747
 
 
748
 
    /* Allocate main loop object */
749
 
    if (!(simple_poll = avahi_simple_poll_new())) {
750
 
        fprintf(stderr, "Failed to create simple poll object.\n");
751
 
        
752
 
        goto exit;
753
 
    }
754
 
 
755
 
    /* Do not publish any local records */
 
1231
    /* Do not publish any local Zeroconf records */
756
1232
    avahi_server_config_init(&config);
757
1233
    config.publish_hinfo = 0;
758
1234
    config.publish_addresses = 0;
759
1235
    config.publish_workstation = 0;
760
1236
    config.publish_domain = 0;
761
 
 
 
1237
    
762
1238
    /* Allocate a new server */
763
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
764
 
                              &config, NULL, NULL, &error);
765
 
 
766
 
    /* Free the configuration data */
 
1239
    mc.server = avahi_server_new(avahi_simple_poll_get
 
1240
                                 (mc.simple_poll), &config, NULL,
 
1241
                                 NULL, &error);
 
1242
    
 
1243
    /* Free the Avahi configuration data */
767
1244
    avahi_server_config_free(&config);
768
 
 
769
 
    /* Check if creating the server object succeeded */
770
 
    if (!server) {
771
 
        fprintf(stderr, "Failed to create server: %s\n",
772
 
                avahi_strerror(error));
773
 
        returncode = EXIT_FAILURE;
774
 
        goto exit;
775
 
    }
776
 
    
777
 
    /* Create the service browser */
778
 
    sb = avahi_s_service_browser_new(server, if_index,
779
 
                                     AVAHI_PROTO_INET6,
780
 
                                     "_mandos._tcp", NULL, 0,
781
 
                                     browse_callback, server);
782
 
    if (!sb) {
783
 
        fprintf(stderr, "Failed to create service browser: %s\n",
784
 
                avahi_strerror(avahi_server_errno(server)));
785
 
        returncode = EXIT_FAILURE;
786
 
        goto exit;
787
 
    }
788
 
    
789
 
    /* Run the main loop */
790
 
 
791
 
    if (debug){
792
 
      fprintf(stderr, "Starting avahi loop search\n");
793
 
    }
794
 
    
795
 
    avahi_simple_poll_loop(simple_poll);
796
 
    
797
 
 exit:
798
 
 
799
 
    if (debug){
800
 
      fprintf(stderr, "%s exiting\n", argv[0]);
801
 
    }
802
 
    
803
 
    /* Cleanup things */
804
 
    if (sb)
805
 
        avahi_s_service_browser_free(sb);
806
 
    
807
 
    if (server)
808
 
        avahi_server_free(server);
809
 
 
810
 
    if (simple_poll)
811
 
        avahi_simple_poll_free(simple_poll);
812
 
    free(certfile);
813
 
    free(certkey);
814
 
    
815
 
    return returncode;
 
1245
  }
 
1246
  
 
1247
  /* Check if creating the Avahi server object succeeded */
 
1248
  if(mc.server == NULL){
 
1249
    fprintf(stderr, "Failed to create Avahi server: %s\n",
 
1250
            avahi_strerror(error));
 
1251
    exitcode = EXIT_FAILURE;
 
1252
    goto end;
 
1253
  }
 
1254
  
 
1255
  /* Create the Avahi service browser */
 
1256
  sb = avahi_s_service_browser_new(mc.server, if_index,
 
1257
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
 
1258
                                   NULL, 0, browse_callback, NULL);
 
1259
  if(sb == NULL){
 
1260
    fprintf(stderr, "Failed to create service browser: %s\n",
 
1261
            avahi_strerror(avahi_server_errno(mc.server)));
 
1262
    exitcode = EXIT_FAILURE;
 
1263
    goto end;
 
1264
  }
 
1265
  
 
1266
  /* Run the main loop */
 
1267
  
 
1268
  if(debug){
 
1269
    fprintf(stderr, "Starting Avahi loop search\n");
 
1270
  }
 
1271
  
 
1272
  avahi_simple_poll_loop(mc.simple_poll);
 
1273
  
 
1274
 end:
 
1275
  
 
1276
  if(debug){
 
1277
    fprintf(stderr, "%s exiting\n", argv[0]);
 
1278
  }
 
1279
  
 
1280
  /* Cleanup things */
 
1281
  if(sb != NULL)
 
1282
    avahi_s_service_browser_free(sb);
 
1283
  
 
1284
  if(mc.server != NULL)
 
1285
    avahi_server_free(mc.server);
 
1286
  
 
1287
  if(mc.simple_poll != NULL)
 
1288
    avahi_simple_poll_free(mc.simple_poll);
 
1289
  
 
1290
  if(gnutls_initialized){
 
1291
    gnutls_certificate_free_credentials(mc.cred);
 
1292
    gnutls_global_deinit();
 
1293
    gnutls_dh_params_deinit(mc.dh_params);
 
1294
  }
 
1295
  
 
1296
  if(gpgme_initialized){
 
1297
    gpgme_release(mc.ctx);
 
1298
  }
 
1299
  
 
1300
  /* Removes the temp directory used by GPGME */
 
1301
  if(tempdir_created){
 
1302
    DIR *d;
 
1303
    struct dirent *direntry;
 
1304
    d = opendir(tempdir);
 
1305
    if(d == NULL){
 
1306
      if(errno != ENOENT){
 
1307
        perror("opendir");
 
1308
      }
 
1309
    } else {
 
1310
      while(true){
 
1311
        direntry = readdir(d);
 
1312
        if(direntry == NULL){
 
1313
          break;
 
1314
        }
 
1315
        /* Skip "." and ".." */
 
1316
        if(direntry->d_name[0] == '.'
 
1317
           and (direntry->d_name[1] == '\0'
 
1318
                or (direntry->d_name[1] == '.'
 
1319
                    and direntry->d_name[2] == '\0'))){
 
1320
          continue;
 
1321
        }
 
1322
        char *fullname = NULL;
 
1323
        ret = asprintf(&fullname, "%s/%s", tempdir,
 
1324
                       direntry->d_name);
 
1325
        if(ret < 0){
 
1326
          perror("asprintf");
 
1327
          continue;
 
1328
        }
 
1329
        ret = remove(fullname);
 
1330
        if(ret == -1){
 
1331
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
 
1332
                  strerror(errno));
 
1333
        }
 
1334
        free(fullname);
 
1335
      }
 
1336
      closedir(d);
 
1337
    }
 
1338
    ret = rmdir(tempdir);
 
1339
    if(ret == -1 and errno != ENOENT){
 
1340
      perror("rmdir");
 
1341
    }
 
1342
  }
 
1343
  
 
1344
  return exitcode;
816
1345
}