/mandos/release

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

« back to all changes in this revision

Viewing changes to plugins.d/password-request.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-18 03:50:28 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080818035028-su31apqs2pv2147v
* mandos-keygen.xml: Removed <?xml-stylesheet>.  New entity
                     "&OVERVIEW;" referring to "overview.xml".
  (PURPOSE, OVERVIEW): New sections, same as in mandos(8).
  (EXAMPLES): Renamed to "EXAMPLE", as per man-pages(7).

* mandos.xml (OPTIONS, CLIENTS): Slight wording change.

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
 
#define DH_BITS 1024
73
 
 
74
 
static const char *certdir = "/conf/conf.d/mandos";
75
 
static const char *certfile = "openpgp-client.txt";
76
 
static const char *certkey = "openpgp-client-key.txt";
77
100
 
78
101
bool debug = false;
 
102
static const char *keydir = "/conf/conf.d/mandos";
 
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>";
79
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){
258
 
  const char *err;
 
317
static int init_gnutls_global(mandos_context *mc,
 
318
                              const char *pubkeyfilename,
 
319
                              const char *seckeyfilename){
259
320
  int ret;
260
321
  
261
322
  if(debug){
262
323
    fprintf(stderr, "Initializing GnuTLS\n");
263
324
  }
264
 
 
265
 
  if ((ret = gnutls_global_init ())
266
 
      != GNUTLS_E_SUCCESS) {
267
 
    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));
268
330
    return -1;
269
331
  }
270
 
 
 
332
  
271
333
  if (debug){
 
334
    /* "Use a log level over 10 to enable all debugging options."
 
335
     * - GnuTLS manual
 
336
     */
272
337
    gnutls_global_set_log_level(11);
273
338
    gnutls_global_set_log_function(debuggnutls);
274
339
  }
275
340
  
276
 
  /* openpgp credentials */
277
 
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
278
 
      != GNUTLS_E_SUCCESS) {
279
 
    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 */
280
346
             safer_gnutls_strerror(ret));
 
347
    gnutls_global_deinit ();
281
348
    return -1;
282
349
  }
283
350
  
284
351
  if(debug){
285
352
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
286
 
            " and keyfile %s as GnuTLS credentials\n", certfile,
287
 
            certkey);
 
353
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
 
354
            seckeyfilename);
288
355
  }
289
356
  
290
357
  ret = gnutls_certificate_set_openpgp_key_file
291
 
    (es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
 
358
    (mc->cred, pubkeyfilename, seckeyfilename,
 
359
     GNUTLS_OPENPGP_FMT_BASE64);
292
360
  if (ret != GNUTLS_E_SUCCESS) {
293
 
    fprintf
294
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
295
 
       " '%s')\n",
296
 
       ret, certfile, certkey);
297
 
    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",
298
365
            safer_gnutls_strerror(ret));
299
 
    return -1;
300
 
  }
301
 
  
302
 
  //GnuTLS server initialization
303
 
  if ((ret = gnutls_dh_params_init (&es->dh_params))
304
 
      != GNUTLS_E_SUCCESS) {
305
 
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
306
 
             safer_gnutls_strerror(ret));
307
 
    return -1;
308
 
  }
309
 
  
310
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
311
 
      != GNUTLS_E_SUCCESS) {
312
 
    fprintf (stderr, "Error in prime generation: %s\n",
313
 
             safer_gnutls_strerror(ret));
314
 
    return -1;
315
 
  }
316
 
  
317
 
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
318
 
  
319
 
  // GnuTLS session creation
320
 
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
321
 
      != 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){
322
401
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
323
402
            safer_gnutls_strerror(ret));
324
403
  }
325
404
  
326
 
  if ((ret = gnutls_priority_set_direct (es->session, mc->priority, &err))
327
 
      != GNUTLS_E_SUCCESS) {
328
 
    fprintf(stderr, "Syntax error at: %s\n", err);
329
 
    fprintf(stderr, "GnuTLS error: %s\n",
330
 
            safer_gnutls_strerror(ret));
331
 
    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
    }
332
415
  }
333
416
  
334
 
  if ((ret = gnutls_credentials_set
335
 
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
336
 
      != GNUTLS_E_SUCCESS) {
337
 
    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",
338
421
            safer_gnutls_strerror(ret));
 
422
    gnutls_deinit (*session);
339
423
    return -1;
340
424
  }
341
425
  
342
426
  /* ignore client certificate if any. */
343
 
  gnutls_certificate_server_set_request (es->session,
 
427
  gnutls_certificate_server_set_request (*session,
344
428
                                         GNUTLS_CERT_IGNORE);
345
429
  
346
 
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
 
430
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
347
431
  
348
432
  return 0;
349
433
}
350
434
 
 
435
/* Avahi log function callback */
351
436
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
352
437
                      __attribute__((unused)) const char *txt){}
353
438
 
 
439
/* Called when a Mandos server is found */
354
440
static int start_mandos_communication(const char *ip, uint16_t port,
355
441
                                      AvahiIfIndex if_index,
356
442
                                      mandos_context *mc){
357
443
  int ret, tcp_sd;
358
 
  struct sockaddr_in6 to;
359
 
  encrypted_session es;
 
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];
 
453
  gnutls_session_t session;
 
454
  
 
455
  ret = init_gnutls_session (mc, &session);
 
456
  if (ret != 0){
 
457
    return -1;
 
458
  }
368
459
  
369
460
  if(debug){
370
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
371
 
            ip, port);
 
461
    fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16
 
462
            "\n", ip, port);
372
463
  }
373
464
  
374
465
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
379
470
 
380
471
  if(debug){
381
472
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
382
 
      if(debug){
383
 
        perror("if_indextoname");
384
 
      }
 
473
      perror("if_indextoname");
385
474
      return -1;
386
475
    }
387
 
    
388
476
    fprintf(stderr, "Binding to interface %s\n", interface);
389
477
  }
390
478
  
391
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
392
 
  to.sin6_family = AF_INET6;
393
 
  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);
394
484
  if (ret < 0 ){
395
485
    perror("inet_pton");
396
486
    return -1;
397
 
  }  
 
487
  }
398
488
  if(ret == 0){
399
489
    fprintf(stderr, "Bad address: %s\n", ip);
400
490
    return -1;
401
491
  }
402
 
  to.sin6_port = htons(port);   /* Spurious warning */
 
492
  to.in6.sin6_port = htons(port); /* Spurious warning */
403
493
  
404
 
  to.sin6_scope_id = (uint32_t)if_index;
 
494
  to.in6.sin6_scope_id = (uint32_t)if_index;
405
495
  
406
496
  if(debug){
407
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
408
 
/*     char addrstr[INET6_ADDRSTRLEN]; */
409
 
/*     if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
410
 
/*               sizeof(addrstr)) == NULL){ */
411
 
/*       perror("inet_ntop"); */
412
 
/*     } else { */
413
 
/*       fprintf(stderr, "Really connecting to: %s, port %d\n", */
414
 
/*            addrstr, ntohs(to.sin6_port)); */
415
 
/*     } */
 
497
    fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
498
            port);
 
499
    char addrstr[INET6_ADDRSTRLEN] = "";
 
500
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
 
501
                 sizeof(addrstr)) == NULL){
 
502
      perror("inet_ntop");
 
503
    } else {
 
504
      if(strcmp(addrstr, ip) != 0){
 
505
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
 
506
      }
 
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 (&es);
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
    }
428
538
  }
429
 
  
430
 
  gnutls_transport_set_ptr (es.session,
431
 
                            (gnutls_transport_ptr_t) tcp_sd);
432
 
  
 
539
 
433
540
  if(debug){
434
541
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
435
542
  }
436
543
  
437
 
  ret = gnutls_handshake (es.session);
 
544
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
 
545
 
 
546
  do{
 
547
    ret = gnutls_handshake (session);
 
548
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
438
549
  
439
550
  if (ret != GNUTLS_E_SUCCESS){
440
551
    if(debug){
441
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
552
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
442
553
      gnutls_perror (ret);
443
554
    }
444
555
    retval = -1;
445
 
    goto exit;
 
556
    goto mandos_end;
446
557
  }
447
558
  
448
 
  //Retrieve OpenPGP packet that contains the wanted password
 
559
  /* Read OpenPGP packet that contains the wanted password */
449
560
  
450
561
  if(debug){
451
562
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
453
564
  }
454
565
 
455
566
  while(true){
456
 
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
457
 
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
458
 
      if (buffer == NULL){
459
 
        perror("realloc");
460
 
        goto exit;
461
 
      }
462
 
      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;
463
573
    }
464
574
    
465
 
    ret = gnutls_record_recv
466
 
      (es.session, buffer+buffer_length, BUFFER_SIZE);
 
575
    ret = gnutls_record_recv(session, buffer+buffer_length,
 
576
                             BUFFER_SIZE);
467
577
    if (ret == 0){
468
578
      break;
469
579
    }
473
583
      case GNUTLS_E_AGAIN:
474
584
        break;
475
585
      case GNUTLS_E_REHANDSHAKE:
476
 
        ret = gnutls_handshake (es.session);
 
586
        do{
 
587
          ret = gnutls_handshake (session);
 
588
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
477
589
        if (ret < 0){
478
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
 
590
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
479
591
          gnutls_perror (ret);
480
592
          retval = -1;
481
 
          goto exit;
 
593
          goto mandos_end;
482
594
        }
483
595
        break;
484
596
      default:
485
597
        fprintf(stderr, "Unknown error while reading data from"
486
 
                " encrypted session with mandos server\n");
 
598
                " encrypted session with Mandos server\n");
487
599
        retval = -1;
488
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
489
 
        goto exit;
 
600
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
601
        goto mandos_end;
490
602
      }
491
603
    } else {
492
604
      buffer_length += (size_t) ret;
493
605
    }
494
606
  }
495
607
  
 
608
  if(debug){
 
609
    fprintf(stderr, "Closing TLS session\n");
 
610
  }
 
611
  
 
612
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
613
  
496
614
  if (buffer_length > 0){
497
615
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
498
616
                                               buffer_length,
499
617
                                               &decrypted_buffer,
500
 
                                               certdir);
 
618
                                               keydir);
501
619
    if (decrypted_buffer_size >= 0){
 
620
      written = 0;
502
621
      while(written < (size_t) decrypted_buffer_size){
503
622
        ret = (int)fwrite (decrypted_buffer + written, 1,
504
623
                           (size_t)decrypted_buffer_size - written,
518
637
      retval = -1;
519
638
    }
520
639
  }
521
 
 
522
 
  //shutdown procedure
523
 
 
524
 
  if(debug){
525
 
    fprintf(stderr, "Closing TLS session\n");
526
 
  }
527
 
 
 
640
  
 
641
  /* Shutdown procedure */
 
642
  
 
643
 mandos_end:
528
644
  free(buffer);
529
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
530
 
 exit:
531
645
  close(tcp_sd);
532
 
  gnutls_deinit (es.session);
533
 
  gnutls_certificate_free_credentials (es.cred);
534
 
  gnutls_global_deinit ();
 
646
  gnutls_deinit (session);
535
647
  return retval;
536
648
}
537
649
 
538
 
static void resolve_callback( AvahiSServiceResolver *r,
539
 
                              AvahiIfIndex interface,
540
 
                              AVAHI_GCC_UNUSED AvahiProtocol protocol,
541
 
                              AvahiResolverEvent event,
542
 
                              const char *name,
543
 
                              const char *type,
544
 
                              const char *domain,
545
 
                              const char *host_name,
546
 
                              const AvahiAddress *address,
547
 
                              uint16_t port,
548
 
                              AVAHI_GCC_UNUSED AvahiStringList *txt,
549
 
                              AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
550
 
                              AVAHI_GCC_UNUSED void* userdata) {
 
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) {
551
664
  mandos_context *mc = userdata;
552
 
  assert(r);                    /* Spurious warning */
 
665
  assert(r);
553
666
  
554
667
  /* Called whenever a service has been resolved successfully or
555
668
     timed out */
557
670
  switch (event) {
558
671
  default:
559
672
  case AVAHI_RESOLVER_FAILURE:
560
 
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
561
 
            " type '%s' in domain '%s': %s\n", name, type, domain,
 
673
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
 
674
            " of type '%s' in domain '%s': %s\n", name, type, domain,
562
675
            avahi_strerror(avahi_server_errno(mc->server)));
563
676
    break;
564
677
    
567
680
      char ip[AVAHI_ADDRESS_STR_MAX];
568
681
      avahi_address_snprint(ip, sizeof(ip), address);
569
682
      if(debug){
570
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
571
 
                " 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);
572
686
      }
573
687
      int ret = start_mandos_communication(ip, port, interface, mc);
574
688
      if (ret == 0){
575
 
        exit(EXIT_SUCCESS);
 
689
        avahi_simple_poll_quit(mc->simple_poll);
576
690
      }
577
691
    }
578
692
  }
586
700
                             const char *name,
587
701
                             const char *type,
588
702
                             const char *domain,
589
 
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
703
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
704
                             flags,
590
705
                             void* userdata) {
591
706
  mandos_context *mc = userdata;
592
 
  assert(b);                    /* Spurious warning */
 
707
  assert(b);
593
708
  
594
709
  /* Called whenever a new services becomes available on the LAN or
595
710
     is removed from the LAN */
597
712
  switch (event) {
598
713
  default:
599
714
  case AVAHI_BROWSER_FAILURE:
600
 
      
601
 
    fprintf(stderr, "(Browser) %s\n",
 
715
    
 
716
    fprintf(stderr, "(Avahi browser) %s\n",
602
717
            avahi_strerror(avahi_server_errno(mc->server)));
603
718
    avahi_simple_poll_quit(mc->simple_poll);
604
719
    return;
605
 
      
 
720
    
606
721
  case AVAHI_BROWSER_NEW:
607
 
    /* We ignore the returned resolver object. In the callback
608
 
       function we free it. If the server is terminated before
609
 
       the callback function is called the server will free
610
 
       the resolver for us. */
611
 
      
612
 
    if (!(avahi_s_service_resolver_new(mc->server, interface, protocol, name,
613
 
                                       type, domain,
 
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. */
 
726
    
 
727
    if (!(avahi_s_service_resolver_new(mc->server, interface,
 
728
                                       protocol, name, type, domain,
614
729
                                       AVAHI_PROTO_INET6, 0,
615
730
                                       resolve_callback, mc)))
616
 
      fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
617
 
              avahi_strerror(avahi_server_errno(s)));
 
731
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
 
732
              name, avahi_strerror(avahi_server_errno(mc->server)));
618
733
    break;
619
 
      
 
734
    
620
735
  case AVAHI_BROWSER_REMOVE:
621
736
    break;
622
 
      
 
737
    
623
738
  case AVAHI_BROWSER_ALL_FOR_NOW:
624
739
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
740
    if(debug){
 
741
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
742
    }
625
743
    break;
626
744
  }
627
745
}
628
746
 
629
747
/* Combines file name and path and returns the malloced new
630
748
   string. some sane checks could/should be added */
631
 
static const char *combinepath(const char *first, const char *second){
632
 
  size_t f_len = strlen(first);
633
 
  size_t s_len = strlen(second);
634
 
  char *tmp = malloc(f_len + s_len + 2);
635
 
  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){
636
753
    return NULL;
637
754
  }
638
 
  if(f_len > 0){
639
 
    memcpy(tmp, first, f_len);
640
 
  }
641
 
  tmp[f_len] = '/';
642
 
  if(s_len > 0){
643
 
    memcpy(tmp + f_len + 1, second, s_len);
644
 
  }
645
 
  tmp[f_len + 1 + s_len] = '\0';
646
755
  return tmp;
647
756
}
648
757
 
649
758
 
650
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
651
 
    AvahiServerConfig config;
 
759
int main(int argc, char *argv[]){
652
760
    AvahiSServiceBrowser *sb = NULL;
653
761
    int error;
654
762
    int ret;
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
 
                          .dh_bits = 2048, .priority = "SECURE256"};
 
776
                          .dh_bits = 1024, .priority = "SECURE256"};
 
777
    bool gnutls_initalized = false;
663
778
    
664
 
    while (true){
665
 
      static struct option long_options[] = {
666
 
        {"debug", no_argument, (int *)&debug, 1},
667
 
        {"connect", required_argument, 0, 'C'},
668
 
        {"interface", required_argument, 0, 'i'},
669
 
        {"certdir", required_argument, 0, 'd'},
670
 
        {"certkey", required_argument, 0, 'c'},
671
 
        {"certfile", required_argument, 0, 'k'},
672
 
        {"dh_bits", required_argument, 0, 'D'},
673
 
        {"priority", required_argument, 0, 'p'},
674
 
        {0, 0, 0, 0} };
675
 
      
676
 
      int option_index = 0;
677
 
      ret = getopt_long (argc, argv, "i:", long_options,
678
 
                         &option_index);
679
 
      
680
 
      if (ret == -1){
681
 
        break;
682
 
      }
683
 
      
684
 
      switch(ret){
685
 
      case 0:
686
 
        break;
687
 
      case 'i':
688
 
        interface = optarg;
689
 
        break;
690
 
      case 'C':
691
 
        connect_to = optarg;
692
 
        break;
693
 
      case 'd':
694
 
        certdir = optarg;
695
 
        break;
696
 
      case 'c':
697
 
        certfile = optarg;
698
 
        break;
699
 
      case 'k':
700
 
        certkey = optarg;
701
 
        break;
702
 
      case 'D':
703
 
        {
704
 
          long int tmp;
 
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:
705
838
          errno = 0;
706
 
          tmp = strtol(optarg, NULL, 10);
707
 
          if (errno == ERANGE){
 
839
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
840
          if (errno){
708
841
            perror("strtol");
709
842
            exit(EXIT_FAILURE);
710
843
          }
711
 
          mc.dh_bits = tmp;
712
 
        }
713
 
        break;
714
 
      case 'p':
715
 
        mc.priority = optarg;
716
 
        break;
717
 
      default:
718
 
        exit(EXIT_FAILURE);
719
 
      }
720
 
    }
721
 
    
722
 
    certfile = combinepath(certdir, certfile);
723
 
    if (certfile == NULL){
724
 
      perror("combinepath");
725
 
      returncode = EXIT_FAILURE;
726
 
      goto exit;
727
 
    }
728
 
 
729
 
    certkey = combinepath(certdir, certkey);
730
 
    if (certkey == NULL){
731
 
      perror("combinepath");
732
 
      returncode = EXIT_FAILURE;
733
 
      goto exit;
 
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");
734
931
    }
735
932
    
736
933
    if_index = (AvahiIfIndex) if_nametoindex(interface);
745
942
      char *address = strrchr(connect_to, ':');
746
943
      if(address == NULL){
747
944
        fprintf(stderr, "No colon in address\n");
748
 
        exit(EXIT_FAILURE);
 
945
        exitcode = EXIT_FAILURE;
 
946
        goto end;
749
947
      }
750
948
      errno = 0;
751
949
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
752
950
      if(errno){
753
951
        perror("Bad port number");
754
 
        exit(EXIT_FAILURE);
 
952
        exitcode = EXIT_FAILURE;
 
953
        goto end;
755
954
      }
756
955
      *address = '\0';
757
956
      address = connect_to;
758
 
      ret = start_mandos_communication(address, port, if_index);
 
957
      ret = start_mandos_communication(address, port, if_index, &mc);
759
958
      if(ret < 0){
760
 
        exit(EXIT_FAILURE);
 
959
        exitcode = EXIT_FAILURE;
761
960
      } else {
762
 
        exit(EXIT_SUCCESS);
763
 
      }
764
 
    }
765
 
    
766
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
767
 
    if(sd < 0) {
768
 
      perror("socket");
769
 
      returncode = EXIT_FAILURE;
770
 
      goto exit;
771
 
    }
772
 
    strcpy(network.ifr_name, interface);    
773
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
774
 
    if(ret == -1){
775
 
      
776
 
      perror("ioctl SIOCGIFFLAGS");
777
 
      returncode = EXIT_FAILURE;
778
 
      goto exit;
779
 
    }
780
 
    if((network.ifr_flags & IFF_UP) == 0){
781
 
      network.ifr_flags |= IFF_UP;
782
 
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
783
 
      if(ret == -1){
784
 
        perror("ioctl SIOCSIFFLAGS");
785
 
        returncode = EXIT_FAILURE;
786
 
        goto exit;
787
 
      }
788
 
    }
789
 
    close(sd);
 
961
        exitcode = EXIT_SUCCESS;
 
962
      }
 
963
      goto end;
 
964
    }
790
965
    
791
966
    if (not debug){
792
967
      avahi_set_log_function(empty_log);
793
968
    }
794
969
    
795
 
    /* Initialize the psuedo-RNG */
 
970
    /* Initialize the pseudo-RNG for Avahi */
796
971
    srand((unsigned int) time(NULL));
797
 
 
798
 
    /* Allocate main loop object */
799
 
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
800
 
        fprintf(stderr, "Failed to create simple poll object.\n");
801
 
        returncode = EXIT_FAILURE;      
802
 
        goto exit;
803
 
    }
804
 
 
805
 
    /* Do not publish any local records */
806
 
    avahi_server_config_init(&config);
807
 
    config.publish_hinfo = 0;
808
 
    config.publish_addresses = 0;
809
 
    config.publish_workstation = 0;
810
 
    config.publish_domain = 0;
811
 
 
812
 
    /* Allocate a new server */
813
 
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
814
 
                              &config, NULL, NULL, &error);
815
 
 
816
 
    /* Free the configuration data */
817
 
    avahi_server_config_free(&config);
818
 
 
819
 
    /* Check if creating the server object succeeded */
820
 
    if (!mc.server) {
821
 
        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",
822
1003
                avahi_strerror(error));
823
 
        returncode = EXIT_FAILURE;
824
 
        goto exit;
 
1004
        exitcode = EXIT_FAILURE;
 
1005
        goto end;
825
1006
    }
826
1007
    
827
 
    /* Create the service browser */
 
1008
    /* Create the Avahi service browser */
828
1009
    sb = avahi_s_service_browser_new(mc.server, if_index,
829
1010
                                     AVAHI_PROTO_INET6,
830
1011
                                     "_mandos._tcp", NULL, 0,
831
1012
                                     browse_callback, &mc);
832
 
    if (!sb) {
 
1013
    if (sb == NULL) {
833
1014
        fprintf(stderr, "Failed to create service browser: %s\n",
834
1015
                avahi_strerror(avahi_server_errno(mc.server)));
835
 
        returncode = EXIT_FAILURE;
836
 
        goto exit;
 
1016
        exitcode = EXIT_FAILURE;
 
1017
        goto end;
837
1018
    }
838
1019
    
839
1020
    /* Run the main loop */
840
1021
 
841
1022
    if (debug){
842
 
      fprintf(stderr, "Starting avahi loop search\n");
 
1023
      fprintf(stderr, "Starting Avahi loop search\n");
843
1024
    }
844
1025
    
845
 
    avahi_simple_poll_loop(simple_poll);
 
1026
    avahi_simple_poll_loop(mc.simple_poll);
846
1027
    
847
 
 exit:
 
1028
 end:
848
1029
 
849
1030
    if (debug){
850
1031
      fprintf(stderr, "%s exiting\n", argv[0]);
851
1032
    }
852
1033
    
853
1034
    /* Cleanup things */
854
 
    if (sb)
 
1035
    if (sb != NULL)
855
1036
        avahi_s_service_browser_free(sb);
856
1037
    
857
 
    if (mc.server)
 
1038
    if (mc.server != NULL)
858
1039
        avahi_server_free(mc.server);
859
1040
 
860
 
    if (simple_poll)
861
 
        avahi_simple_poll_free(simple_poll);
862
 
    free(certfile);
863
 
    free(certkey);
 
1041
    if (mc.simple_poll != NULL)
 
1042
        avahi_simple_poll_free(mc.simple_poll);
 
1043
    free(pubkeyfilename);
 
1044
    free(seckeyfilename);
 
1045
 
 
1046
    if (gnutls_initalized){
 
1047
      gnutls_certificate_free_credentials(mc.cred);
 
1048
      gnutls_global_deinit ();
 
1049
    }
864
1050
    
865
 
    return returncode;
 
1051
    return exitcode;
866
1052
}