/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-09-17 04:16:32 UTC
  • Revision ID: teddy@fukt.bsnet.se-20090917041632-7m1rm83pxguw5zw7
* plugins.d/usplash.c (main): Bug fix: only close FIFO if opened.

Show diffs side-by-side

added added

removed removed

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