/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-11 20:16:35 UTC
  • mfrom: (24.1.45 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080811201635-1vor0gz43trtily1
Merge.

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