/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/password-request.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-22 00:16:20 UTC
  • mfrom: (24.1.57 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080822001620-vxpn1evy0t0kyvj0
* clients.conf ([DEFAULT]/checker): Update to new default value.

* mandos (Client.start_checker): Bug fix: OSError, not
                                 subprocess.OSError.
  (main): Use "fping -q -- %(host)s" instead of "fping -q --
          %%(host)s" as default value for "checker".  Always redirect
          stdin to be from /dev/null, even if in debug mode.

* mandos-clients.conf.xml (DESCRIPTION): Improved wording and refer to
                                         the EXPANSION section.
  (OPTIONS): Added synopsis and improved wording for "checker",
             "fingerprint", and "secret".  Refer to the RUNTIME
             EXPANSION section for the "checker" option.
  (EXAMPLE): Update to new default value for "checker".

* mandos-keygen (trap): Split lines and add "set +e".

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
#define _LARGEFILE_SOURCE
33
33
#define _FILE_OFFSET_BITS 64
34
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, SIOCSIFFLAGS
41
 
#include <net/if.h>             // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
42
 
 
 
35
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
 
36
 
 
37
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
 
38
                                   stdout, ferror() */
 
39
#include <stdint.h>             /* uint16_t, uint32_t */
 
40
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
41
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
 
42
                                   srand() */
 
43
#include <stdbool.h>            /* bool, true */
 
44
#include <string.h>             /* memset(), strcmp(), strlen(),
 
45
                                   strerror(), asprintf(), strcpy() */
 
46
#include <sys/ioctl.h>          /* ioctl */
 
47
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
 
48
                                   sockaddr_in6, PF_INET6,
 
49
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
 
50
                                   uid_t, gid_t */
 
51
#include <inttypes.h>           /* PRIu16 */
 
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
53
                                   struct in6_addr, inet_pton(),
 
54
                                   connect() */
 
55
#include <assert.h>             /* assert() */
 
56
#include <errno.h>              /* perror(), errno */
 
57
#include <time.h>               /* time() */
 
58
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
 
59
                                   SIOCSIFFLAGS, if_indextoname(),
 
60
                                   if_nametoindex(), IF_NAMESIZE */
 
61
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
 
62
                                   getuid(), getgid(), setuid(),
 
63
                                   setgid() */
 
64
#include <netinet/in.h>
 
65
#include <arpa/inet.h>          /* inet_pton(), htons */
 
66
#include <iso646.h>             /* not, and */
 
67
#include <argp.h>               /* struct argp_option, error_t, struct
 
68
                                   argp_state, struct argp,
 
69
                                   argp_parse(), ARGP_KEY_ARG,
 
70
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
 
71
 
 
72
/* Avahi */
 
73
/* All Avahi types, constants and functions
 
74
 Avahi*, avahi_*,
 
75
 AVAHI_* */
43
76
#include <avahi-core/core.h>
44
77
#include <avahi-core/lookup.h>
45
78
#include <avahi-core/log.h>
47
80
#include <avahi-common/malloc.h>
48
81
#include <avahi-common/error.h>
49
82
 
50
 
//mandos client part
51
 
#include <sys/types.h>          /* socket(), inet_pton() */
52
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
53
 
                                   struct in6_addr, inet_pton() */
54
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
55
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
56
 
 
57
 
#include <unistd.h>             /* close() */
58
 
#include <netinet/in.h>
59
 
#include <stdbool.h>            /* true */
60
 
#include <string.h>             /* memset */
61
 
#include <arpa/inet.h>          /* inet_pton() */
62
 
#include <iso646.h>             /* not */
63
 
 
64
 
// gpgme
65
 
#include <errno.h>              /* perror() */
66
 
#include <gpgme.h>
67
 
 
68
 
// getopt_long
69
 
#include <getopt.h>
 
83
/* GnuTLS */
 
84
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and
 
85
                                   functions:
 
86
                                   gnutls_*
 
87
                                   init_gnutls_session(),
 
88
                                   GNUTLS_* */
 
89
#include <gnutls/openpgp.h>     /* gnutls_certificate_set_openpgp_key_file(),
 
90
                                   GNUTLS_OPENPGP_FMT_BASE64 */
 
91
 
 
92
/* GPGME */
 
93
#include <gpgme.h>              /* All GPGME types, constants and
 
94
                                   functions:
 
95
                                   gpgme_*
 
96
                                   GPGME_PROTOCOL_OpenPGP,
 
97
                                   GPG_ERR_NO_* */
70
98
 
71
99
#define BUFFER_SIZE 256
72
100
 
 
101
bool debug = false;
73
102
static const char *keydir = "/conf/conf.d/mandos";
74
 
static const char *pubkeyfile = "pubkey.txt";
75
 
static const char *seckeyfile = "seckey.txt";
76
 
 
77
 
bool debug = false;
78
 
 
79
 
/* Used for passing in values through all the callback functions */
 
103
static const char mandos_protocol_version[] = "1";
 
104
const char *argp_program_version = "password-request 1.0";
 
105
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
106
 
 
107
/* Used for passing in values through the Avahi callback functions */
80
108
typedef struct {
81
109
  AvahiSimplePoll *simple_poll;
82
110
  AvahiServer *server;
83
111
  gnutls_certificate_credentials_t cred;
84
112
  unsigned int dh_bits;
 
113
  gnutls_dh_params_t dh_params;
85
114
  const char *priority;
86
115
} mandos_context;
87
116
 
88
 
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
89
 
                                   char **new_packet,
 
117
/*
 
118
 * Make room in "buffer" for at least BUFFER_SIZE additional bytes.
 
119
 * "buffer_capacity" is how much is currently allocated,
 
120
 * "buffer_length" is how much is already used.
 
121
 */
 
122
size_t adjustbuffer(char **buffer, size_t buffer_length,
 
123
                  size_t buffer_capacity){
 
124
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
 
125
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
 
126
    if (buffer == NULL){
 
127
      return 0;
 
128
    }
 
129
    buffer_capacity += BUFFER_SIZE;
 
130
  }
 
131
  return buffer_capacity;
 
132
}
 
133
 
 
134
/* 
 
135
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
 
136
 * Returns -1 on error
 
137
 */
 
138
static ssize_t pgp_packet_decrypt (const char *cryptotext,
 
139
                                   size_t crypto_size,
 
140
                                   char **plaintext,
90
141
                                   const char *homedir){
91
142
  gpgme_data_t dh_crypto, dh_plain;
92
143
  gpgme_ctx_t ctx;
93
144
  gpgme_error_t rc;
94
145
  ssize_t ret;
95
 
  ssize_t new_packet_capacity = 0;
96
 
  ssize_t new_packet_length = 0;
 
146
  size_t plaintext_capacity = 0;
 
147
  ssize_t plaintext_length = 0;
97
148
  gpgme_engine_info_t engine_info;
98
 
 
 
149
  
99
150
  if (debug){
100
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
151
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
101
152
  }
102
153
  
103
154
  /* Init GPGME */
109
160
    return -1;
110
161
  }
111
162
  
112
 
  /* Set GPGME home directory */
 
163
  /* Set GPGME home directory for the OpenPGP engine only */
113
164
  rc = gpgme_get_engine_info (&engine_info);
114
165
  if (rc != GPG_ERR_NO_ERROR){
115
166
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
125
176
    engine_info = engine_info->next;
126
177
  }
127
178
  if(engine_info == NULL){
128
 
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
 
179
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
129
180
    return -1;
130
181
  }
131
182
  
132
 
  /* Create new GPGME data buffer from packet buffer */
133
 
  rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
 
183
  /* Create new GPGME data buffer from memory cryptotext */
 
184
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
 
185
                               0);
134
186
  if (rc != GPG_ERR_NO_ERROR){
135
187
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
136
188
            gpgme_strsource(rc), gpgme_strerror(rc));
142
194
  if (rc != GPG_ERR_NO_ERROR){
143
195
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
144
196
            gpgme_strsource(rc), gpgme_strerror(rc));
 
197
    gpgme_data_release(dh_crypto);
145
198
    return -1;
146
199
  }
147
200
  
150
203
  if (rc != GPG_ERR_NO_ERROR){
151
204
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
152
205
            gpgme_strsource(rc), gpgme_strerror(rc));
153
 
    return -1;
 
206
    plaintext_length = -1;
 
207
    goto decrypt_end;
154
208
  }
155
209
  
156
 
  /* Decrypt data from the FILE pointer to the plaintext data
157
 
     buffer */
 
210
  /* Decrypt data from the cryptotext data buffer to the plaintext
 
211
     data buffer */
158
212
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
159
213
  if (rc != GPG_ERR_NO_ERROR){
160
214
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
161
215
            gpgme_strsource(rc), gpgme_strerror(rc));
162
 
    return -1;
 
216
    plaintext_length = -1;
 
217
    goto decrypt_end;
163
218
  }
164
 
 
 
219
  
165
220
  if(debug){
166
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
 
221
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
167
222
  }
168
 
 
 
223
  
169
224
  if (debug){
170
225
    gpgme_decrypt_result_t result;
171
226
    result = gpgme_op_decrypt_result(ctx);
174
229
    } else {
175
230
      fprintf(stderr, "Unsupported algorithm: %s\n",
176
231
              result->unsupported_algorithm);
177
 
      fprintf(stderr, "Wrong key usage: %d\n",
 
232
      fprintf(stderr, "Wrong key usage: %u\n",
178
233
              result->wrong_key_usage);
179
234
      if(result->file_name != NULL){
180
235
        fprintf(stderr, "File name: %s\n", result->file_name);
195
250
    }
196
251
  }
197
252
  
198
 
  /* Delete the GPGME FILE pointer cryptotext data buffer */
199
 
  gpgme_data_release(dh_crypto);
200
 
  
201
253
  /* Seek back to the beginning of the GPGME plaintext data buffer */
202
254
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
203
255
    perror("pgpme_data_seek");
 
256
    plaintext_length = -1;
 
257
    goto decrypt_end;
204
258
  }
205
259
  
206
 
  *new_packet = 0;
 
260
  *plaintext = NULL;
207
261
  while(true){
208
 
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
209
 
      *new_packet = realloc(*new_packet,
210
 
                            (unsigned int)new_packet_capacity
211
 
                            + BUFFER_SIZE);
212
 
      if (*new_packet == NULL){
213
 
        perror("realloc");
214
 
        return -1;
215
 
      }
216
 
      new_packet_capacity += BUFFER_SIZE;
 
262
    plaintext_capacity = adjustbuffer(plaintext,
 
263
                                      (size_t)plaintext_length,
 
264
                                      plaintext_capacity);
 
265
    if (plaintext_capacity == 0){
 
266
        perror("adjustbuffer");
 
267
        plaintext_length = -1;
 
268
        goto decrypt_end;
217
269
    }
218
270
    
219
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
271
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
220
272
                          BUFFER_SIZE);
221
273
    /* Print the data, if any */
222
274
    if (ret == 0){
 
275
      /* EOF */
223
276
      break;
224
277
    }
225
278
    if(ret < 0){
226
279
      perror("gpgme_data_read");
227
 
      return -1;
 
280
      plaintext_length = -1;
 
281
      goto decrypt_end;
228
282
    }
229
 
    new_packet_length += ret;
 
283
    plaintext_length += ret;
230
284
  }
231
285
 
232
 
  /* FIXME: check characters before printing to screen so to not print
233
 
     terminal control characters */
234
 
  /*   if(debug){ */
235
 
  /*     fprintf(stderr, "decrypted password is: "); */
236
 
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
237
 
  /*     fprintf(stderr, "\n"); */
238
 
  /*   } */
 
286
  if(debug){
 
287
    fprintf(stderr, "Decrypted password is: ");
 
288
    for(ssize_t i = 0; i < plaintext_length; i++){
 
289
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
 
290
    }
 
291
    fprintf(stderr, "\n");
 
292
  }
 
293
  
 
294
 decrypt_end:
 
295
  
 
296
  /* Delete the GPGME cryptotext data buffer */
 
297
  gpgme_data_release(dh_crypto);
239
298
  
240
299
  /* Delete the GPGME plaintext data buffer */
241
300
  gpgme_data_release(dh_plain);
242
 
  return new_packet_length;
 
301
  return plaintext_length;
243
302
}
244
303
 
245
304
static const char * safer_gnutls_strerror (int value) {
246
 
  const char *ret = gnutls_strerror (value);
 
305
  const char *ret = gnutls_strerror (value); /* Spurious warning */
247
306
  if (ret == NULL)
248
307
    ret = "(unknown)";
249
308
  return ret;
250
309
}
251
310
 
 
311
/* GnuTLS log function callback */
252
312
static void debuggnutls(__attribute__((unused)) int level,
253
313
                        const char* string){
254
 
  fprintf(stderr, "%s", string);
 
314
  fprintf(stderr, "GnuTLS: %s", string);
255
315
}
256
316
 
257
 
static int initgnutls(mandos_context *mc, gnutls_session_t *session,
258
 
                      gnutls_dh_params_t *dh_params){
259
 
  const char *err;
 
317
static int init_gnutls_global(mandos_context *mc,
 
318
                              const char *pubkeyfilename,
 
319
                              const char *seckeyfilename){
260
320
  int ret;
261
321
  
262
322
  if(debug){
263
323
    fprintf(stderr, "Initializing GnuTLS\n");
264
324
  }
265
 
 
266
 
  if ((ret = gnutls_global_init ())
267
 
      != GNUTLS_E_SUCCESS) {
268
 
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
 
325
  
 
326
  ret = gnutls_global_init();
 
327
  if (ret != GNUTLS_E_SUCCESS) {
 
328
    fprintf (stderr, "GnuTLS global_init: %s\n",
 
329
             safer_gnutls_strerror(ret));
269
330
    return -1;
270
331
  }
271
332
  
272
333
  if (debug){
 
334
    /* "Use a log level over 10 to enable all debugging options."
 
335
     * - GnuTLS manual
 
336
     */
273
337
    gnutls_global_set_log_level(11);
274
338
    gnutls_global_set_log_function(debuggnutls);
275
339
  }
276
340
  
277
 
  /* openpgp credentials */
278
 
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
279
 
      != GNUTLS_E_SUCCESS) {
280
 
    fprintf (stderr, "memory error: %s\n",
 
341
  /* OpenPGP credentials */
 
342
  gnutls_certificate_allocate_credentials(&mc->cred);
 
343
  if (ret != GNUTLS_E_SUCCESS){
 
344
    fprintf (stderr, "GnuTLS memory error: %s\n", /* Spurious
 
345
                                                     warning */
281
346
             safer_gnutls_strerror(ret));
 
347
    gnutls_global_deinit ();
282
348
    return -1;
283
349
  }
284
350
  
285
351
  if(debug){
286
352
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
287
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
288
 
            seckeyfile);
 
353
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
 
354
            seckeyfilename);
289
355
  }
290
356
  
291
357
  ret = gnutls_certificate_set_openpgp_key_file
292
 
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
358
    (mc->cred, pubkeyfilename, seckeyfilename,
 
359
     GNUTLS_OPENPGP_FMT_BASE64);
293
360
  if (ret != GNUTLS_E_SUCCESS) {
294
 
    fprintf
295
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
296
 
       " '%s')\n",
297
 
       ret, pubkeyfile, seckeyfile);
298
 
    fprintf(stdout, "The Error is: %s\n",
 
361
    fprintf(stderr,
 
362
            "Error[%d] while reading the OpenPGP key pair ('%s',"
 
363
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
 
364
    fprintf(stdout, "The GnuTLS error is: %s\n",
299
365
            safer_gnutls_strerror(ret));
300
 
    return -1;
301
 
  }
302
 
  
303
 
  //GnuTLS server initialization
304
 
  if ((ret = gnutls_dh_params_init(dh_params))
305
 
      != GNUTLS_E_SUCCESS) {
306
 
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
307
 
             safer_gnutls_strerror(ret));
308
 
    return -1;
309
 
  }
310
 
  
311
 
  if ((ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits))
312
 
      != GNUTLS_E_SUCCESS) {
313
 
    fprintf (stderr, "Error in prime generation: %s\n",
314
 
             safer_gnutls_strerror(ret));
315
 
    return -1;
316
 
  }
317
 
  
318
 
  gnutls_certificate_set_dh_params(mc->cred, *dh_params);
319
 
  
320
 
  // GnuTLS session creation
321
 
  if ((ret = gnutls_init(session, GNUTLS_SERVER))
322
 
      != GNUTLS_E_SUCCESS){
 
366
    goto globalfail;
 
367
  }
 
368
  
 
369
  /* GnuTLS server initialization */
 
370
  ret = gnutls_dh_params_init(&mc->dh_params);
 
371
  if (ret != GNUTLS_E_SUCCESS) {
 
372
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
 
373
             " %s\n", safer_gnutls_strerror(ret));
 
374
    goto globalfail;
 
375
  }
 
376
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
377
  if (ret != GNUTLS_E_SUCCESS) {
 
378
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
 
379
             safer_gnutls_strerror(ret));
 
380
    goto globalfail;
 
381
  }
 
382
  
 
383
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
 
384
 
 
385
  return 0;
 
386
 
 
387
 globalfail:
 
388
 
 
389
  gnutls_certificate_free_credentials(mc->cred);
 
390
  gnutls_global_deinit();
 
391
  return -1;
 
392
 
 
393
}
 
394
 
 
395
static int init_gnutls_session(mandos_context *mc,
 
396
                               gnutls_session_t *session){
 
397
  int ret;
 
398
  /* GnuTLS session creation */
 
399
  ret = gnutls_init(session, GNUTLS_SERVER);
 
400
  if (ret != GNUTLS_E_SUCCESS){
323
401
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
324
402
            safer_gnutls_strerror(ret));
325
403
  }
326
404
  
327
 
  if ((ret = gnutls_priority_set_direct(*session, mc->priority, &err))
328
 
      != GNUTLS_E_SUCCESS) {
329
 
    fprintf(stderr, "Syntax error at: %s\n", err);
330
 
    fprintf(stderr, "GnuTLS error: %s\n",
331
 
            safer_gnutls_strerror(ret));
332
 
    return -1;
 
405
  {
 
406
    const char *err;
 
407
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
 
408
    if (ret != GNUTLS_E_SUCCESS) {
 
409
      fprintf(stderr, "Syntax error at: %s\n", err);
 
410
      fprintf(stderr, "GnuTLS error: %s\n",
 
411
              safer_gnutls_strerror(ret));
 
412
      gnutls_deinit (*session);
 
413
      return -1;
 
414
    }
333
415
  }
334
416
  
335
 
  if ((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
336
 
                                    mc->cred))
337
 
      != GNUTLS_E_SUCCESS) {
338
 
    fprintf(stderr, "Error setting a credentials set: %s\n",
 
417
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
418
                               mc->cred);
 
419
  if (ret != GNUTLS_E_SUCCESS) {
 
420
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
339
421
            safer_gnutls_strerror(ret));
 
422
    gnutls_deinit (*session);
340
423
    return -1;
341
424
  }
342
425
  
349
432
  return 0;
350
433
}
351
434
 
 
435
/* Avahi log function callback */
352
436
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
353
437
                      __attribute__((unused)) const char *txt){}
354
438
 
 
439
/* Called when a Mandos server is found */
355
440
static int start_mandos_communication(const char *ip, uint16_t port,
356
441
                                      AvahiIfIndex if_index,
357
442
                                      mandos_context *mc){
358
443
  int ret, tcp_sd;
359
 
  struct sockaddr_in6 to;
 
444
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
360
445
  char *buffer = NULL;
361
446
  char *decrypted_buffer;
362
447
  size_t buffer_length = 0;
363
448
  size_t buffer_capacity = 0;
364
449
  ssize_t decrypted_buffer_size;
365
 
  size_t written = 0;
 
450
  size_t written;
366
451
  int retval = 0;
367
452
  char interface[IF_NAMESIZE];
368
453
  gnutls_session_t session;
369
 
  gnutls_dh_params_t dh_params;
 
454
  
 
455
  ret = init_gnutls_session (mc, &session);
 
456
  if (ret != 0){
 
457
    return -1;
 
458
  }
370
459
  
371
460
  if(debug){
372
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
373
 
            ip, port);
 
461
    fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16
 
462
            "\n", ip, port);
374
463
  }
375
464
  
376
465
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
387
476
    fprintf(stderr, "Binding to interface %s\n", interface);
388
477
  }
389
478
  
390
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
391
 
  to.sin6_family = AF_INET6;
392
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
479
  memset(&to, 0, sizeof(to));
 
480
  to.in6.sin6_family = AF_INET6;
 
481
  /* It would be nice to have a way to detect if we were passed an
 
482
     IPv4 address here.   Now we assume an IPv6 address. */
 
483
  ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
393
484
  if (ret < 0 ){
394
485
    perror("inet_pton");
395
486
    return -1;
398
489
    fprintf(stderr, "Bad address: %s\n", ip);
399
490
    return -1;
400
491
  }
401
 
  to.sin6_port = htons(port);   /* Spurious warning */
 
492
  to.in6.sin6_port = htons(port); /* Spurious warning */
402
493
  
403
 
  to.sin6_scope_id = (uint32_t)if_index;
 
494
  to.in6.sin6_scope_id = (uint32_t)if_index;
404
495
  
405
496
  if(debug){
406
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
 
497
    fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
498
            port);
407
499
    char addrstr[INET6_ADDRSTRLEN] = "";
408
 
    if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
 
500
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
409
501
                 sizeof(addrstr)) == NULL){
410
502
      perror("inet_ntop");
411
503
    } else {
415
507
    }
416
508
  }
417
509
  
418
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
 
510
  ret = connect(tcp_sd, &to.in, sizeof(to));
419
511
  if (ret < 0){
420
512
    perror("connect");
421
513
    return -1;
422
514
  }
423
 
  
424
 
  ret = initgnutls (mc, &session, &dh_params);
425
 
  if (ret != 0){
426
 
    retval = -1;
427
 
    return -1;
 
515
 
 
516
  const char *out = mandos_protocol_version;
 
517
  written = 0;
 
518
  while (true){
 
519
    size_t out_size = strlen(out);
 
520
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
521
                                   out_size - written));
 
522
    if (ret == -1){
 
523
      perror("write");
 
524
      retval = -1;
 
525
      goto mandos_end;
 
526
    }
 
527
    written += (size_t)ret;
 
528
    if(written < out_size){
 
529
      continue;
 
530
    } else {
 
531
      if (out == mandos_protocol_version){
 
532
        written = 0;
 
533
        out = "\r\n";
 
534
      } else {
 
535
        break;
 
536
      }
 
537
    }
 
538
  }
 
539
 
 
540
  if(debug){
 
541
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
428
542
  }
429
543
  
430
544
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
431
 
  
432
 
  if(debug){
433
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
434
 
  }
435
 
  
436
 
  ret = gnutls_handshake (session);
 
545
 
 
546
  do{
 
547
    ret = gnutls_handshake (session);
 
548
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
437
549
  
438
550
  if (ret != GNUTLS_E_SUCCESS){
439
551
    if(debug){
440
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
552
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
441
553
      gnutls_perror (ret);
442
554
    }
443
555
    retval = -1;
444
 
    goto exit;
 
556
    goto mandos_end;
445
557
  }
446
558
  
447
 
  //Retrieve OpenPGP packet that contains the wanted password
 
559
  /* Read OpenPGP packet that contains the wanted password */
448
560
  
449
561
  if(debug){
450
562
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
452
564
  }
453
565
 
454
566
  while(true){
455
 
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
456
 
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
457
 
      if (buffer == NULL){
458
 
        perror("realloc");
459
 
        goto exit;
460
 
      }
461
 
      buffer_capacity += BUFFER_SIZE;
 
567
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
 
568
                                   buffer_capacity);
 
569
    if (buffer_capacity == 0){
 
570
      perror("adjustbuffer");
 
571
      retval = -1;
 
572
      goto mandos_end;
462
573
    }
463
574
    
464
575
    ret = gnutls_record_recv(session, buffer+buffer_length,
472
583
      case GNUTLS_E_AGAIN:
473
584
        break;
474
585
      case GNUTLS_E_REHANDSHAKE:
475
 
        ret = gnutls_handshake (session);
 
586
        do{
 
587
          ret = gnutls_handshake (session);
 
588
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
476
589
        if (ret < 0){
477
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
 
590
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
478
591
          gnutls_perror (ret);
479
592
          retval = -1;
480
 
          goto exit;
 
593
          goto mandos_end;
481
594
        }
482
595
        break;
483
596
      default:
484
597
        fprintf(stderr, "Unknown error while reading data from"
485
 
                " encrypted session with mandos server\n");
 
598
                " encrypted session with Mandos server\n");
486
599
        retval = -1;
487
600
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
488
 
        goto exit;
 
601
        goto mandos_end;
489
602
      }
490
603
    } else {
491
604
      buffer_length += (size_t) ret;
492
605
    }
493
606
  }
494
607
  
 
608
  if(debug){
 
609
    fprintf(stderr, "Closing TLS session\n");
 
610
  }
 
611
  
 
612
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
613
  
495
614
  if (buffer_length > 0){
496
615
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
497
616
                                               buffer_length,
498
617
                                               &decrypted_buffer,
499
618
                                               keydir);
500
619
    if (decrypted_buffer_size >= 0){
 
620
      written = 0;
501
621
      while(written < (size_t) decrypted_buffer_size){
502
622
        ret = (int)fwrite (decrypted_buffer + written, 1,
503
623
                           (size_t)decrypted_buffer_size - written,
517
637
      retval = -1;
518
638
    }
519
639
  }
520
 
 
521
 
  //shutdown procedure
522
 
 
523
 
  if(debug){
524
 
    fprintf(stderr, "Closing TLS session\n");
525
 
  }
526
 
 
 
640
  
 
641
  /* Shutdown procedure */
 
642
  
 
643
 mandos_end:
527
644
  free(buffer);
528
 
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
529
 
 exit:
530
645
  close(tcp_sd);
531
646
  gnutls_deinit (session);
532
 
  gnutls_certificate_free_credentials (mc->cred);
533
 
  gnutls_global_deinit ();
534
647
  return retval;
535
648
}
536
649
 
537
 
static void resolve_callback( AvahiSServiceResolver *r,
538
 
                              AvahiIfIndex interface,
539
 
                              AVAHI_GCC_UNUSED AvahiProtocol protocol,
540
 
                              AvahiResolverEvent event,
541
 
                              const char *name,
542
 
                              const char *type,
543
 
                              const char *domain,
544
 
                              const char *host_name,
545
 
                              const AvahiAddress *address,
546
 
                              uint16_t port,
547
 
                              AVAHI_GCC_UNUSED AvahiStringList *txt,
548
 
                              AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
549
 
                              void* userdata) {
 
650
static void resolve_callback(AvahiSServiceResolver *r,
 
651
                             AvahiIfIndex interface,
 
652
                             AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
653
                             AvahiResolverEvent event,
 
654
                             const char *name,
 
655
                             const char *type,
 
656
                             const char *domain,
 
657
                             const char *host_name,
 
658
                             const AvahiAddress *address,
 
659
                             uint16_t port,
 
660
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
 
661
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
662
                             flags,
 
663
                             void* userdata) {
550
664
  mandos_context *mc = userdata;
551
 
  assert(r);                    /* Spurious warning */
 
665
  assert(r);
552
666
  
553
667
  /* Called whenever a service has been resolved successfully or
554
668
     timed out */
556
670
  switch (event) {
557
671
  default:
558
672
  case AVAHI_RESOLVER_FAILURE:
559
 
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
560
 
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
673
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
 
674
            " of type '%s' in domain '%s': %s\n", name, type, domain,
561
675
            avahi_strerror(avahi_server_errno(mc->server)));
562
676
    break;
563
677
    
566
680
      char ip[AVAHI_ADDRESS_STR_MAX];
567
681
      avahi_address_snprint(ip, sizeof(ip), address);
568
682
      if(debug){
569
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
570
 
                " port %d\n", name, host_name, ip, port);
 
683
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
 
684
                PRIu16 ") on port %d\n", name, host_name, ip,
 
685
                interface, port);
571
686
      }
572
687
      int ret = start_mandos_communication(ip, port, interface, mc);
573
688
      if (ret == 0){
574
 
        exit(EXIT_SUCCESS);
 
689
        avahi_simple_poll_quit(mc->simple_poll);
575
690
      }
576
691
    }
577
692
  }
585
700
                             const char *name,
586
701
                             const char *type,
587
702
                             const char *domain,
588
 
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
703
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
704
                             flags,
589
705
                             void* userdata) {
590
706
  mandos_context *mc = userdata;
591
 
  assert(b);                    /* Spurious warning */
 
707
  assert(b);
592
708
  
593
709
  /* Called whenever a new services becomes available on the LAN or
594
710
     is removed from the LAN */
597
713
  default:
598
714
  case AVAHI_BROWSER_FAILURE:
599
715
    
600
 
    fprintf(stderr, "(Browser) %s\n",
 
716
    fprintf(stderr, "(Avahi browser) %s\n",
601
717
            avahi_strerror(avahi_server_errno(mc->server)));
602
718
    avahi_simple_poll_quit(mc->simple_poll);
603
719
    return;
604
720
    
605
721
  case AVAHI_BROWSER_NEW:
606
 
    /* We ignore the returned resolver object. In the callback
607
 
       function we free it. If the server is terminated before
608
 
       the callback function is called the server will free
609
 
       the resolver for us. */
 
722
    /* We ignore the returned Avahi resolver object. In the callback
 
723
       function we free it. If the Avahi server is terminated before
 
724
       the callback function is called the Avahi server will free the
 
725
       resolver for us. */
610
726
    
611
 
    if (!(avahi_s_service_resolver_new(mc->server, interface, protocol, name,
612
 
                                       type, domain,
 
727
    if (!(avahi_s_service_resolver_new(mc->server, interface,
 
728
                                       protocol, name, type, domain,
613
729
                                       AVAHI_PROTO_INET6, 0,
614
730
                                       resolve_callback, mc)))
615
 
      fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
616
 
              avahi_strerror(avahi_server_errno(mc->server)));
 
731
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
 
732
              name, avahi_strerror(avahi_server_errno(mc->server)));
617
733
    break;
618
734
    
619
735
  case AVAHI_BROWSER_REMOVE:
621
737
    
622
738
  case AVAHI_BROWSER_ALL_FOR_NOW:
623
739
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
740
    if(debug){
 
741
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
742
    }
624
743
    break;
625
744
  }
626
745
}
627
746
 
628
747
/* Combines file name and path and returns the malloced new
629
748
   string. some sane checks could/should be added */
630
 
static const char *combinepath(const char *first, const char *second){
631
 
  size_t f_len = strlen(first);
632
 
  size_t s_len = strlen(second);
633
 
  char *tmp = malloc(f_len + s_len + 2);
634
 
  if (tmp == NULL){
 
749
static char *combinepath(const char *first, const char *second){
 
750
  char *tmp;
 
751
  int ret = asprintf(&tmp, "%s/%s", first, second);
 
752
  if(ret < 0){
635
753
    return NULL;
636
754
  }
637
 
  if(f_len > 0){
638
 
    memcpy(tmp, first, f_len);  /* Spurious warning */
639
 
  }
640
 
  tmp[f_len] = '/';
641
 
  if(s_len > 0){
642
 
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
643
 
  }
644
 
  tmp[f_len + 1 + s_len] = '\0';
645
755
  return tmp;
646
756
}
647
757
 
648
758
 
649
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
650
 
    AvahiServerConfig config;
 
759
int main(int argc, char *argv[]){
651
760
    AvahiSServiceBrowser *sb = NULL;
652
761
    int error;
653
762
    int ret;
654
 
    int debug_int;
655
 
    int returncode = EXIT_SUCCESS;
 
763
    int exitcode = EXIT_SUCCESS;
656
764
    const char *interface = "eth0";
657
765
    struct ifreq network;
658
766
    int sd;
 
767
    uid_t uid;
 
768
    gid_t gid;
659
769
    char *connect_to = NULL;
660
770
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
771
    char *pubkeyfilename = NULL;
 
772
    char *seckeyfilename = NULL;
 
773
    const char *pubkeyname = "pubkey.txt";
 
774
    const char *seckeyname = "seckey.txt";
661
775
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
662
776
                          .dh_bits = 1024, .priority = "SECURE256"};
663
 
    
664
 
    debug_int = debug ? 1 : 0;
665
 
    while (true){
666
 
      struct option long_options[] = {
667
 
        {"debug", no_argument, &debug_int, 1},
668
 
        {"connect", required_argument, NULL, 'c'},
669
 
        {"interface", required_argument, NULL, 'i'},
670
 
        {"keydir", required_argument, NULL, 'd'},
671
 
        {"seckey", required_argument, NULL, 's'},
672
 
        {"pubkey", required_argument, NULL, 'p'},
673
 
        {"dh-bits", required_argument, NULL, 'D'},
674
 
        {"priority", required_argument, NULL, 'P'},
675
 
        {0, 0, 0, 0} };
676
 
      
677
 
      int option_index = 0;
678
 
      ret = getopt_long (argc, argv, "i:", long_options,
679
 
                         &option_index);
680
 
      
681
 
      if (ret == -1){
682
 
        break;
683
 
      }
684
 
      
685
 
      switch(ret){
686
 
      case 0:
687
 
        break;
688
 
      case 'i':
689
 
        interface = optarg;
690
 
        break;
691
 
      case 'c':
692
 
        connect_to = optarg;
693
 
        break;
694
 
      case 'd':
695
 
        keydir = optarg;
696
 
        break;
697
 
      case 'p':
698
 
        pubkeyfile = optarg;
699
 
        break;
700
 
      case 's':
701
 
        seckeyfile = optarg;
702
 
        break;
703
 
      case 'D':
704
 
        errno = 0;
705
 
        mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
706
 
        if (errno){
707
 
          perror("strtol");
708
 
          exit(EXIT_FAILURE);
709
 
        }
710
 
        break;
711
 
      case 'P':
712
 
        mc.priority = optarg;
713
 
        break;
714
 
      case '?':
715
 
      default:
716
 
        exit(EXIT_FAILURE);
717
 
      }
718
 
    }
719
 
    debug = debug_int ? true : false;
720
 
    
721
 
    pubkeyfile = combinepath(keydir, pubkeyfile);
722
 
    if (pubkeyfile == NULL){
723
 
      perror("combinepath");
724
 
      returncode = EXIT_FAILURE;
725
 
      goto exit;
726
 
    }
727
 
    
728
 
    seckeyfile = combinepath(keydir, seckeyfile);
729
 
    if (seckeyfile == NULL){
730
 
      perror("combinepath");
731
 
      goto exit;
 
777
    bool gnutls_initalized = false;
 
778
    
 
779
    {
 
780
      struct argp_option options[] = {
 
781
        { .name = "debug", .key = 128,
 
782
          .doc = "Debug mode", .group = 3 },
 
783
        { .name = "connect", .key = 'c',
 
784
          .arg = "IP",
 
785
          .doc = "Connect directly to a sepcified mandos server",
 
786
          .group = 1 },
 
787
        { .name = "interface", .key = 'i',
 
788
          .arg = "INTERFACE",
 
789
          .doc = "Interface that Avahi will conntect through",
 
790
          .group = 1 },
 
791
        { .name = "keydir", .key = 'd',
 
792
          .arg = "KEYDIR",
 
793
          .doc = "Directory where the openpgp keyring is",
 
794
          .group = 1 },
 
795
        { .name = "seckey", .key = 's',
 
796
          .arg = "SECKEY",
 
797
          .doc = "Secret openpgp key for gnutls authentication",
 
798
          .group = 1 },
 
799
        { .name = "pubkey", .key = 'p',
 
800
          .arg = "PUBKEY",
 
801
          .doc = "Public openpgp key for gnutls authentication",
 
802
          .group = 2 },
 
803
        { .name = "dh-bits", .key = 129,
 
804
          .arg = "BITS",
 
805
          .doc = "dh-bits to use in gnutls communication",
 
806
          .group = 2 },
 
807
        { .name = "priority", .key = 130,
 
808
          .arg = "PRIORITY",
 
809
          .doc = "GNUTLS priority", .group = 1 },
 
810
        { .name = NULL }
 
811
      };
 
812
 
 
813
      
 
814
      error_t parse_opt (int key, char *arg,
 
815
                         struct argp_state *state) {
 
816
        /* Get the INPUT argument from `argp_parse', which we know is
 
817
           a pointer to our plugin list pointer. */
 
818
        switch (key) {
 
819
        case 128:
 
820
          debug = true;
 
821
          break;
 
822
        case 'c':
 
823
          connect_to = arg;
 
824
          break;
 
825
        case 'i':
 
826
          interface = arg;
 
827
          break;
 
828
        case 'd':
 
829
          keydir = arg;
 
830
          break;
 
831
        case 's':
 
832
          seckeyname = arg;
 
833
          break;
 
834
        case 'p':
 
835
          pubkeyname = arg;
 
836
          break;
 
837
        case 129:
 
838
          errno = 0;
 
839
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
840
          if (errno){
 
841
            perror("strtol");
 
842
            exit(EXIT_FAILURE);
 
843
          }
 
844
          break;
 
845
        case 130:
 
846
          mc.priority = arg;
 
847
          break;
 
848
        case ARGP_KEY_ARG:
 
849
          argp_usage (state);
 
850
        case ARGP_KEY_END:
 
851
          break;
 
852
        default:
 
853
          return ARGP_ERR_UNKNOWN;
 
854
        }
 
855
        return 0;
 
856
      }
 
857
 
 
858
      struct argp argp = { .options = options, .parser = parse_opt,
 
859
                           .args_doc = "",
 
860
                           .doc = "Mandos client -- Get and decrypt"
 
861
                           " passwords from mandos server" };
 
862
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
863
      if (ret == ARGP_ERR_UNKNOWN){
 
864
        fprintf(stderr, "Unknown error while parsing arguments\n");
 
865
        exitcode = EXIT_FAILURE;
 
866
        goto end;
 
867
      }
 
868
    }
 
869
      
 
870
    pubkeyfilename = combinepath(keydir, pubkeyname);
 
871
    if (pubkeyfilename == NULL){
 
872
      perror("combinepath");
 
873
      exitcode = EXIT_FAILURE;
 
874
      goto end;
 
875
    }
 
876
    
 
877
    seckeyfilename = combinepath(keydir, seckeyname);
 
878
    if (seckeyfilename == NULL){
 
879
      perror("combinepath");
 
880
      exitcode = EXIT_FAILURE;
 
881
      goto end;
 
882
    }
 
883
 
 
884
    ret = init_gnutls_global(&mc, pubkeyfilename, seckeyfilename);
 
885
    if (ret == -1){
 
886
      fprintf(stderr, "init_gnutls_global failed\n");
 
887
      exitcode = EXIT_FAILURE;
 
888
      goto end;
 
889
    } else {
 
890
      gnutls_initalized = true;
 
891
    }
 
892
    
 
893
    /* If the interface is down, bring it up */
 
894
    {
 
895
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
896
      if(sd < 0) {
 
897
        perror("socket");
 
898
        exitcode = EXIT_FAILURE;
 
899
        goto end;
 
900
      }
 
901
      strcpy(network.ifr_name, interface);
 
902
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
903
      if(ret == -1){
 
904
        perror("ioctl SIOCGIFFLAGS");
 
905
        exitcode = EXIT_FAILURE;
 
906
        goto end;
 
907
      }
 
908
      if((network.ifr_flags & IFF_UP) == 0){
 
909
        network.ifr_flags |= IFF_UP;
 
910
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
911
        if(ret == -1){
 
912
          perror("ioctl SIOCSIFFLAGS");
 
913
          exitcode = EXIT_FAILURE;
 
914
          goto end;
 
915
        }
 
916
      }
 
917
      close(sd);
 
918
    }
 
919
    
 
920
    uid = getuid();
 
921
    gid = getgid();
 
922
    
 
923
    ret = setuid(uid);
 
924
    if (ret == -1){
 
925
      perror("setuid");
 
926
    }
 
927
    
 
928
    setgid(gid);
 
929
    if (ret == -1){
 
930
      perror("setgid");
732
931
    }
733
932
    
734
933
    if_index = (AvahiIfIndex) if_nametoindex(interface);
743
942
      char *address = strrchr(connect_to, ':');
744
943
      if(address == NULL){
745
944
        fprintf(stderr, "No colon in address\n");
746
 
        exit(EXIT_FAILURE);
 
945
        exitcode = EXIT_FAILURE;
 
946
        goto end;
747
947
      }
748
948
      errno = 0;
749
949
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
750
950
      if(errno){
751
951
        perror("Bad port number");
752
 
        exit(EXIT_FAILURE);
 
952
        exitcode = EXIT_FAILURE;
 
953
        goto end;
753
954
      }
754
955
      *address = '\0';
755
956
      address = connect_to;
756
957
      ret = start_mandos_communication(address, port, if_index, &mc);
757
958
      if(ret < 0){
758
 
        exit(EXIT_FAILURE);
 
959
        exitcode = EXIT_FAILURE;
759
960
      } else {
760
 
        exit(EXIT_SUCCESS);
761
 
      }
762
 
    }
763
 
    
764
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
765
 
    if(sd < 0) {
766
 
      perror("socket");
767
 
      returncode = EXIT_FAILURE;
768
 
      goto exit;
769
 
    }
770
 
    strcpy(network.ifr_name, interface); /* Spurious warning */
771
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
772
 
    if(ret == -1){
773
 
      
774
 
      perror("ioctl SIOCGIFFLAGS");
775
 
      returncode = EXIT_FAILURE;
776
 
      goto exit;
777
 
    }
778
 
    if((network.ifr_flags & IFF_UP) == 0){
779
 
      network.ifr_flags |= IFF_UP;
780
 
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
781
 
      if(ret == -1){
782
 
        perror("ioctl SIOCSIFFLAGS");
783
 
        returncode = EXIT_FAILURE;
784
 
        goto exit;
785
 
      }
786
 
    }
787
 
    close(sd);
 
961
        exitcode = EXIT_SUCCESS;
 
962
      }
 
963
      goto end;
 
964
    }
788
965
    
789
966
    if (not debug){
790
967
      avahi_set_log_function(empty_log);
791
968
    }
792
969
    
793
 
    /* Initialize the psuedo-RNG */
 
970
    /* Initialize the pseudo-RNG for Avahi */
794
971
    srand((unsigned int) time(NULL));
795
 
 
796
 
    /* Allocate main loop object */
797
 
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
798
 
        fprintf(stderr, "Failed to create simple poll object.\n");
799
 
        returncode = EXIT_FAILURE;
800
 
        goto exit;
801
 
    }
802
 
 
803
 
    /* Do not publish any local records */
804
 
    avahi_server_config_init(&config);
805
 
    config.publish_hinfo = 0;
806
 
    config.publish_addresses = 0;
807
 
    config.publish_workstation = 0;
808
 
    config.publish_domain = 0;
809
 
 
810
 
    /* Allocate a new server */
811
 
    mc.server=avahi_server_new(avahi_simple_poll_get(mc.simple_poll),
812
 
                               &config, NULL, NULL, &error);
813
 
    
814
 
    /* Free the configuration data */
815
 
    avahi_server_config_free(&config);
816
 
    
817
 
    /* Check if creating the server object succeeded */
818
 
    if (!mc.server) {
819
 
        fprintf(stderr, "Failed to create server: %s\n",
 
972
    
 
973
    /* Allocate main Avahi loop object */
 
974
    mc.simple_poll = avahi_simple_poll_new();
 
975
    if (mc.simple_poll == NULL) {
 
976
        fprintf(stderr, "Avahi: Failed to create simple poll"
 
977
                " object.\n");
 
978
        exitcode = EXIT_FAILURE;
 
979
        goto end;
 
980
    }
 
981
 
 
982
    {
 
983
      AvahiServerConfig config;
 
984
      /* Do not publish any local Zeroconf records */
 
985
      avahi_server_config_init(&config);
 
986
      config.publish_hinfo = 0;
 
987
      config.publish_addresses = 0;
 
988
      config.publish_workstation = 0;
 
989
      config.publish_domain = 0;
 
990
 
 
991
      /* Allocate a new server */
 
992
      mc.server = avahi_server_new(avahi_simple_poll_get
 
993
                                   (mc.simple_poll), &config, NULL,
 
994
                                   NULL, &error);
 
995
    
 
996
      /* Free the Avahi configuration data */
 
997
      avahi_server_config_free(&config);
 
998
    }
 
999
    
 
1000
    /* Check if creating the Avahi server object succeeded */
 
1001
    if (mc.server == NULL) {
 
1002
        fprintf(stderr, "Failed to create Avahi server: %s\n",
820
1003
                avahi_strerror(error));
821
 
        returncode = EXIT_FAILURE;
822
 
        goto exit;
 
1004
        exitcode = EXIT_FAILURE;
 
1005
        goto end;
823
1006
    }
824
1007
    
825
 
    /* Create the service browser */
 
1008
    /* Create the Avahi service browser */
826
1009
    sb = avahi_s_service_browser_new(mc.server, if_index,
827
1010
                                     AVAHI_PROTO_INET6,
828
1011
                                     "_mandos._tcp", NULL, 0,
829
1012
                                     browse_callback, &mc);
830
 
    if (!sb) {
 
1013
    if (sb == NULL) {
831
1014
        fprintf(stderr, "Failed to create service browser: %s\n",
832
1015
                avahi_strerror(avahi_server_errno(mc.server)));
833
 
        returncode = EXIT_FAILURE;
834
 
        goto exit;
 
1016
        exitcode = EXIT_FAILURE;
 
1017
        goto end;
835
1018
    }
836
1019
    
837
1020
    /* Run the main loop */
838
1021
 
839
1022
    if (debug){
840
 
      fprintf(stderr, "Starting avahi loop search\n");
 
1023
      fprintf(stderr, "Starting Avahi loop search\n");
841
1024
    }
842
1025
    
843
1026
    avahi_simple_poll_loop(mc.simple_poll);
844
1027
    
845
 
 exit:
 
1028
 end:
846
1029
 
847
1030
    if (debug){
848
1031
      fprintf(stderr, "%s exiting\n", argv[0]);
849
1032
    }
850
1033
    
851
1034
    /* Cleanup things */
852
 
    if (sb)
 
1035
    if (sb != NULL)
853
1036
        avahi_s_service_browser_free(sb);
854
1037
    
855
 
    if (mc.server)
 
1038
    if (mc.server != NULL)
856
1039
        avahi_server_free(mc.server);
857
1040
 
858
 
    if (mc.simple_poll)
 
1041
    if (mc.simple_poll != NULL)
859
1042
        avahi_simple_poll_free(mc.simple_poll);
860
 
    free(pubkeyfile);
861
 
    free(seckeyfile);
 
1043
    free(pubkeyfilename);
 
1044
    free(seckeyfilename);
 
1045
 
 
1046
    if (gnutls_initalized){
 
1047
      gnutls_certificate_free_credentials(mc.cred);
 
1048
      gnutls_global_deinit ();
 
1049
    }
862
1050
    
863
 
    return returncode;
 
1051
    return exitcode;
864
1052
}