/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/mandosclient.c

  • Committer: Teddy Hogeborn
  • Date: 2008-07-22 01:59:47 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080722015947-y7o6keji020nvrhw
* Makefile (OPTIMIZE): New; optimize for size.
  (CFLAGS): Use $(OPTIMIZE).

Show diffs side-by-side

added added

removed removed

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