/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugins.d/mandos-client.c

  • Committer: Teddy Hogeborn
  • Date: 2015-01-25 00:02:51 UTC
  • Revision ID: teddy@recompile.se-20150125000251-j2bw50gfq9smqyxe
mandos.xml (SEE ALSO): Update links.

Update link to GnuPG home page, change reference from TLS 1.1 to TLS
1.2, and change to latest RFC for using OpenPGP keys with TLS (and use
its correct title).

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
11
 * Everything else is
12
 
 * Copyright © 2008-2011 Teddy Hogeborn
13
 
 * Copyright © 2008-2011 Björn Påhlsson
 
12
 * Copyright © 2008-2014 Teddy Hogeborn
 
13
 * Copyright © 2008-2014 Björn Påhlsson
14
14
 * 
15
15
 * This program is free software: you can redistribute it and/or
16
16
 * modify it under the terms of the GNU General Public License as
32
32
/* Needed by GPGME, specifically gpgme_data_seek() */
33
33
#ifndef _LARGEFILE_SOURCE
34
34
#define _LARGEFILE_SOURCE
35
 
#endif
 
35
#endif  /* not _LARGEFILE_SOURCE */
36
36
#ifndef _FILE_OFFSET_BITS
37
37
#define _FILE_OFFSET_BITS 64
38
 
#endif
 
38
#endif  /* not _FILE_OFFSET_BITS */
39
39
 
40
40
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
41
41
 
42
42
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
43
 
                                   stdout, ferror(), remove() */
44
 
#include <stdint.h>             /* uint16_t, uint32_t */
 
43
                                   stdout, ferror() */
 
44
#include <stdint.h>             /* uint16_t, uint32_t, intptr_t */
45
45
#include <stddef.h>             /* NULL, size_t, ssize_t */
46
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
47
47
                                   strtof(), abort() */
55
55
                                   opendir(), DIR */
56
56
#include <sys/stat.h>           /* open(), S_ISREG */
57
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
58
 
                                   inet_pton(), connect() */
59
 
#include <fcntl.h>              /* open() */
 
58
                                   inet_pton(), connect(),
 
59
                                   getnameinfo() */
 
60
#include <fcntl.h>              /* open(), unlinkat() */
60
61
#include <dirent.h>             /* opendir(), struct dirent, readdir()
61
62
                                 */
62
63
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
63
64
                                   strtoimax() */
64
 
#include <assert.h>             /* assert() */
65
65
#include <errno.h>              /* perror(), errno,
66
66
                                   program_invocation_short_name */
67
67
#include <time.h>               /* nanosleep(), time(), sleep() */
73
73
                                */
74
74
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
75
75
                                   getuid(), getgid(), seteuid(),
76
 
                                   setgid(), pause(), _exit() */
77
 
#include <arpa/inet.h>          /* inet_pton(), htons, inet_ntop() */
 
76
                                   setgid(), pause(), _exit(),
 
77
                                   unlinkat() */
 
78
#include <arpa/inet.h>          /* inet_pton(), htons() */
78
79
#include <iso646.h>             /* not, or, and */
79
80
#include <argp.h>               /* struct argp_option, error_t, struct
80
81
                                   argp_state, struct argp,
88
89
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
89
90
                                   WEXITSTATUS(), WTERMSIG() */
90
91
#include <grp.h>                /* setgroups() */
 
92
#include <argz.h>               /* argz_add_sep(), argz_next(),
 
93
                                   argz_delete(), argz_append(),
 
94
                                   argz_stringify(), argz_add(),
 
95
                                   argz_count() */
 
96
#include <netdb.h>              /* getnameinfo(), NI_NUMERICHOST,
 
97
                                   EAI_SYSTEM, gai_strerror() */
91
98
 
92
99
#ifdef __linux__
93
100
#include <sys/klog.h>           /* klogctl() */
135
142
static const char sys_class_net[] = "/sys/class/net";
136
143
char *connect_to = NULL;
137
144
const char *hookdir = HOOKDIR;
 
145
int hookdir_fd = -1;
 
146
uid_t uid = 65534;
 
147
gid_t gid = 65534;
138
148
 
139
149
/* Doubly linked list that need to be circularly linked when used */
140
150
typedef struct server{
141
151
  const char *ip;
142
 
  uint16_t port;
 
152
  in_port_t port;
143
153
  AvahiIfIndex if_index;
144
154
  int af;
145
155
  struct timespec last_seen;
149
159
 
150
160
/* Used for passing in values through the Avahi callback functions */
151
161
typedef struct {
152
 
  AvahiSimplePoll *simple_poll;
153
162
  AvahiServer *server;
154
163
  gnutls_certificate_credentials_t cred;
155
164
  unsigned int dh_bits;
157
166
  const char *priority;
158
167
  gpgme_ctx_t ctx;
159
168
  server *current_server;
 
169
  char *interfaces;
 
170
  size_t interfaces_size;
160
171
} mandos_context;
161
172
 
162
 
/* global context so signal handler can reach it*/
163
 
mandos_context mc = { .simple_poll = NULL, .server = NULL,
164
 
                      .dh_bits = 1024, .priority = "SECURE256"
165
 
                      ":!CTYPE-X.509:+CTYPE-OPENPGP",
166
 
                      .current_server = NULL };
 
173
/* global so signal handler can reach it*/
 
174
AvahiSimplePoll *simple_poll;
167
175
 
168
176
sig_atomic_t quit_now = 0;
169
177
int signal_received = 0;
170
178
 
171
179
/* Function to use when printing errors */
172
180
void perror_plus(const char *print_text){
 
181
  int e = errno;
173
182
  fprintf(stderr, "Mandos plugin %s: ",
174
183
          program_invocation_short_name);
 
184
  errno = e;
175
185
  perror(print_text);
176
186
}
177
187
 
178
 
__attribute__((format (gnu_printf, 2, 3)))
 
188
__attribute__((format (gnu_printf, 2, 3), nonnull))
179
189
int fprintf_plus(FILE *stream, const char *format, ...){
180
190
  va_list ap;
181
191
  va_start (ap, format);
182
192
  
183
193
  TEMP_FAILURE_RETRY(fprintf(stream, "Mandos plugin %s: ",
184
194
                             program_invocation_short_name));
185
 
  return TEMP_FAILURE_RETRY(vfprintf(stream, format, ap));
 
195
  return (int)TEMP_FAILURE_RETRY(vfprintf(stream, format, ap));
186
196
}
187
197
 
188
198
/*
190
200
 * bytes. "buffer_capacity" is how much is currently allocated,
191
201
 * "buffer_length" is how much is already used.
192
202
 */
 
203
__attribute__((nonnull, warn_unused_result))
193
204
size_t incbuffer(char **buffer, size_t buffer_length,
194
205
                 size_t buffer_capacity){
195
206
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
196
 
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
197
 
    if(buffer == NULL){
 
207
    char *new_buf = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
 
208
    if(new_buf == NULL){
 
209
      int old_errno = errno;
 
210
      free(*buffer);
 
211
      errno = old_errno;
 
212
      *buffer = NULL;
198
213
      return 0;
199
214
    }
 
215
    *buffer = new_buf;
200
216
    buffer_capacity += BUFFER_SIZE;
201
217
  }
202
218
  return buffer_capacity;
203
219
}
204
220
 
205
221
/* Add server to set of servers to retry periodically */
206
 
bool add_server(const char *ip, uint16_t port, AvahiIfIndex if_index,
207
 
                int af){
 
222
__attribute__((nonnull, warn_unused_result))
 
223
bool add_server(const char *ip, in_port_t port, AvahiIfIndex if_index,
 
224
                int af, server **current_server){
208
225
  int ret;
209
226
  server *new_server = malloc(sizeof(server));
210
227
  if(new_server == NULL){
217
234
                          .af = af };
218
235
  if(new_server->ip == NULL){
219
236
    perror_plus("strdup");
 
237
    free(new_server);
 
238
    return false;
 
239
  }
 
240
  ret = clock_gettime(CLOCK_MONOTONIC, &(new_server->last_seen));
 
241
  if(ret == -1){
 
242
    perror_plus("clock_gettime");
 
243
#ifdef __GNUC__
 
244
#pragma GCC diagnostic push
 
245
#pragma GCC diagnostic ignored "-Wcast-qual"
 
246
#endif
 
247
    free((char *)(new_server->ip));
 
248
#ifdef __GNUC__
 
249
#pragma GCC diagnostic pop
 
250
#endif
 
251
    free(new_server);
220
252
    return false;
221
253
  }
222
254
  /* Special case of first server */
223
 
  if (mc.current_server == NULL){
 
255
  if(*current_server == NULL){
224
256
    new_server->next = new_server;
225
257
    new_server->prev = new_server;
226
 
    mc.current_server = new_server;
227
 
  /* Place the new server last in the list */
 
258
    *current_server = new_server;
228
259
  } else {
229
 
    new_server->next = mc.current_server;
230
 
    new_server->prev = mc.current_server->prev;
 
260
    /* Place the new server last in the list */
 
261
    new_server->next = *current_server;
 
262
    new_server->prev = (*current_server)->prev;
231
263
    new_server->prev->next = new_server;
232
 
    mc.current_server->prev = new_server;
233
 
  }
234
 
  ret = clock_gettime(CLOCK_MONOTONIC, &mc.current_server->last_seen);
235
 
  if(ret == -1){
236
 
    perror_plus("clock_gettime");
237
 
    return false;
 
264
    (*current_server)->prev = new_server;
238
265
  }
239
266
  return true;
240
267
}
242
269
/* 
243
270
 * Initialize GPGME.
244
271
 */
245
 
static bool init_gpgme(const char *seckey, const char *pubkey,
246
 
                       const char *tempdir){
 
272
__attribute__((nonnull, warn_unused_result))
 
273
static bool init_gpgme(const char * const seckey,
 
274
                       const char * const pubkey,
 
275
                       const char * const tempdir,
 
276
                       mandos_context *mc){
247
277
  gpgme_error_t rc;
248
278
  gpgme_engine_info_t engine_info;
249
279
  
250
 
  
251
280
  /*
252
281
   * Helper function to insert pub and seckey to the engine keyring.
253
282
   */
254
 
  bool import_key(const char *filename){
 
283
  bool import_key(const char * const filename){
255
284
    int ret;
256
285
    int fd;
257
286
    gpgme_data_t pgp_data;
269
298
      return false;
270
299
    }
271
300
    
272
 
    rc = gpgme_op_import(mc.ctx, pgp_data);
 
301
    rc = gpgme_op_import(mc->ctx, pgp_data);
273
302
    if(rc != GPG_ERR_NO_ERROR){
274
303
      fprintf_plus(stderr, "bad gpgme_op_import: %s: %s\n",
275
304
                   gpgme_strsource(rc), gpgme_strerror(rc));
319
348
  }
320
349
  
321
350
  /* Create new GPGME "context" */
322
 
  rc = gpgme_new(&(mc.ctx));
 
351
  rc = gpgme_new(&(mc->ctx));
323
352
  if(rc != GPG_ERR_NO_ERROR){
324
353
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
325
354
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
338
367
 * Decrypt OpenPGP data.
339
368
 * Returns -1 on error
340
369
 */
 
370
__attribute__((nonnull, warn_unused_result))
341
371
static ssize_t pgp_packet_decrypt(const char *cryptotext,
342
372
                                  size_t crypto_size,
343
 
                                  char **plaintext){
 
373
                                  char **plaintext,
 
374
                                  mandos_context *mc){
344
375
  gpgme_data_t dh_crypto, dh_plain;
345
376
  gpgme_error_t rc;
346
377
  ssize_t ret;
372
403
  
373
404
  /* Decrypt data from the cryptotext data buffer to the plaintext
374
405
     data buffer */
375
 
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
406
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
376
407
  if(rc != GPG_ERR_NO_ERROR){
377
408
    fprintf_plus(stderr, "bad gpgme_op_decrypt: %s: %s\n",
378
409
                 gpgme_strsource(rc), gpgme_strerror(rc));
379
410
    plaintext_length = -1;
380
411
    if(debug){
381
412
      gpgme_decrypt_result_t result;
382
 
      result = gpgme_op_decrypt_result(mc.ctx);
 
413
      result = gpgme_op_decrypt_result(mc->ctx);
383
414
      if(result == NULL){
384
415
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
385
416
      } else {
462
493
  return plaintext_length;
463
494
}
464
495
 
465
 
static const char * safer_gnutls_strerror(int value){
466
 
  const char *ret = gnutls_strerror(value); /* Spurious warning from
467
 
                                               -Wunreachable-code */
 
496
__attribute__((warn_unused_result))
 
497
static const char *safer_gnutls_strerror(int value){
 
498
  const char *ret = gnutls_strerror(value);
468
499
  if(ret == NULL)
469
500
    ret = "(unknown)";
470
501
  return ret;
471
502
}
472
503
 
473
504
/* GnuTLS log function callback */
 
505
__attribute__((nonnull))
474
506
static void debuggnutls(__attribute__((unused)) int level,
475
507
                        const char* string){
476
508
  fprintf_plus(stderr, "GnuTLS: %s", string);
477
509
}
478
510
 
 
511
__attribute__((nonnull, warn_unused_result))
479
512
static int init_gnutls_global(const char *pubkeyfilename,
480
 
                              const char *seckeyfilename){
 
513
                              const char *seckeyfilename,
 
514
                              mandos_context *mc){
481
515
  int ret;
482
516
  
483
517
  if(debug){
500
534
  }
501
535
  
502
536
  /* OpenPGP credentials */
503
 
  ret = gnutls_certificate_allocate_credentials(&mc.cred);
 
537
  ret = gnutls_certificate_allocate_credentials(&mc->cred);
504
538
  if(ret != GNUTLS_E_SUCCESS){
505
539
    fprintf_plus(stderr, "GnuTLS memory error: %s\n",
506
540
                 safer_gnutls_strerror(ret));
516
550
  }
517
551
  
518
552
  ret = gnutls_certificate_set_openpgp_key_file
519
 
    (mc.cred, pubkeyfilename, seckeyfilename,
 
553
    (mc->cred, pubkeyfilename, seckeyfilename,
520
554
     GNUTLS_OPENPGP_FMT_BASE64);
521
555
  if(ret != GNUTLS_E_SUCCESS){
522
556
    fprintf_plus(stderr,
528
562
  }
529
563
  
530
564
  /* GnuTLS server initialization */
531
 
  ret = gnutls_dh_params_init(&mc.dh_params);
 
565
  ret = gnutls_dh_params_init(&mc->dh_params);
532
566
  if(ret != GNUTLS_E_SUCCESS){
533
567
    fprintf_plus(stderr, "Error in GnuTLS DH parameter"
534
568
                 " initialization: %s\n",
535
569
                 safer_gnutls_strerror(ret));
536
570
    goto globalfail;
537
571
  }
538
 
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
572
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
539
573
  if(ret != GNUTLS_E_SUCCESS){
540
574
    fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
541
575
                 safer_gnutls_strerror(ret));
542
576
    goto globalfail;
543
577
  }
544
578
  
545
 
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
579
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
546
580
  
547
581
  return 0;
548
582
  
549
583
 globalfail:
550
584
  
551
 
  gnutls_certificate_free_credentials(mc.cred);
 
585
  gnutls_certificate_free_credentials(mc->cred);
552
586
  gnutls_global_deinit();
553
 
  gnutls_dh_params_deinit(mc.dh_params);
 
587
  gnutls_dh_params_deinit(mc->dh_params);
554
588
  return -1;
555
589
}
556
590
 
557
 
static int init_gnutls_session(gnutls_session_t *session){
 
591
__attribute__((nonnull, warn_unused_result))
 
592
static int init_gnutls_session(gnutls_session_t *session,
 
593
                               mandos_context *mc){
558
594
  int ret;
559
595
  /* GnuTLS session creation */
560
596
  do {
572
608
  {
573
609
    const char *err;
574
610
    do {
575
 
      ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
611
      ret = gnutls_priority_set_direct(*session, mc->priority, &err);
576
612
      if(quit_now){
577
613
        gnutls_deinit(*session);
578
614
        return -1;
589
625
  
590
626
  do {
591
627
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
592
 
                                 mc.cred);
 
628
                                 mc->cred);
593
629
    if(quit_now){
594
630
      gnutls_deinit(*session);
595
631
      return -1;
605
641
  /* ignore client certificate if any. */
606
642
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
607
643
  
608
 
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
 
644
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
609
645
  
610
646
  return 0;
611
647
}
615
651
                      __attribute__((unused)) const char *txt){}
616
652
 
617
653
/* Called when a Mandos server is found */
618
 
static int start_mandos_communication(const char *ip, uint16_t port,
 
654
__attribute__((nonnull, warn_unused_result))
 
655
static int start_mandos_communication(const char *ip, in_port_t port,
619
656
                                      AvahiIfIndex if_index,
620
 
                                      int af){
 
657
                                      int af, mandos_context *mc){
621
658
  int ret, tcp_sd = -1;
622
659
  ssize_t sret;
623
 
  union {
624
 
    struct sockaddr_in in;
625
 
    struct sockaddr_in6 in6;
626
 
  } to;
 
660
  struct sockaddr_storage to;
627
661
  char *buffer = NULL;
628
662
  char *decrypted_buffer = NULL;
629
663
  size_t buffer_length = 0;
653
687
    return -1;
654
688
  }
655
689
  
656
 
  ret = init_gnutls_session(&session);
 
690
  /* If the interface is specified and we have a list of interfaces */
 
691
  if(if_index != AVAHI_IF_UNSPEC and mc->interfaces != NULL){
 
692
    /* Check if the interface is one of the interfaces we are using */
 
693
    bool match = false;
 
694
    {
 
695
      char *interface = NULL;
 
696
      while((interface=argz_next(mc->interfaces, mc->interfaces_size,
 
697
                                 interface))){
 
698
        if(if_nametoindex(interface) == (unsigned int)if_index){
 
699
          match = true;
 
700
          break;
 
701
        }
 
702
      }
 
703
    }
 
704
    if(not match){
 
705
      /* This interface does not match any in the list, so we don't
 
706
         connect to the server */
 
707
      if(debug){
 
708
        char interface[IF_NAMESIZE];
 
709
        if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
710
          perror_plus("if_indextoname");
 
711
        } else {
 
712
          fprintf_plus(stderr, "Skipping server on non-used interface"
 
713
                       " \"%s\"\n",
 
714
                       if_indextoname((unsigned int)if_index,
 
715
                                      interface));
 
716
        }
 
717
      }
 
718
      return -1;
 
719
    }
 
720
  }
 
721
  
 
722
  ret = init_gnutls_session(&session, mc);
657
723
  if(ret != 0){
658
724
    return -1;
659
725
  }
660
726
  
661
727
  if(debug){
662
728
    fprintf_plus(stderr, "Setting up a TCP connection to %s, port %"
663
 
                 PRIu16 "\n", ip, port);
 
729
                 PRIuMAX "\n", ip, (uintmax_t)port);
664
730
  }
665
731
  
666
732
  tcp_sd = socket(pf, SOCK_STREAM, 0);
678
744
  
679
745
  memset(&to, 0, sizeof(to));
680
746
  if(af == AF_INET6){
681
 
    to.in6.sin6_family = (sa_family_t)af;
682
 
    ret = inet_pton(af, ip, &to.in6.sin6_addr);
 
747
    ((struct sockaddr_in6 *)&to)->sin6_family = (sa_family_t)af;
 
748
    ret = inet_pton(af, ip, &((struct sockaddr_in6 *)&to)->sin6_addr);
683
749
  } else {                      /* IPv4 */
684
 
    to.in.sin_family = (sa_family_t)af;
685
 
    ret = inet_pton(af, ip, &to.in.sin_addr);
 
750
    ((struct sockaddr_in *)&to)->sin_family = (sa_family_t)af;
 
751
    ret = inet_pton(af, ip, &((struct sockaddr_in *)&to)->sin_addr);
686
752
  }
687
753
  if(ret < 0 ){
688
754
    int e = errno;
697
763
    goto mandos_end;
698
764
  }
699
765
  if(af == AF_INET6){
700
 
    to.in6.sin6_port = htons(port); /* Spurious warnings from
701
 
                                       -Wconversion and
702
 
                                       -Wunreachable-code */
703
 
    
704
 
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
705
 
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
706
 
                                -Wunreachable-code*/
 
766
    ((struct sockaddr_in6 *)&to)->sin6_port = htons(port);
 
767
    if(IN6_IS_ADDR_LINKLOCAL
 
768
       (&((struct sockaddr_in6 *)&to)->sin6_addr)){
707
769
      if(if_index == AVAHI_IF_UNSPEC){
708
770
        fprintf_plus(stderr, "An IPv6 link-local address is"
709
771
                     " incomplete without a network interface\n");
711
773
        goto mandos_end;
712
774
      }
713
775
      /* Set the network interface number as scope */
714
 
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
776
      ((struct sockaddr_in6 *)&to)->sin6_scope_id = (uint32_t)if_index;
715
777
    }
716
778
  } else {
717
 
    to.in.sin_port = htons(port); /* Spurious warnings from
718
 
                                     -Wconversion and
719
 
                                     -Wunreachable-code */
 
779
    ((struct sockaddr_in *)&to)->sin_port = htons(port);
720
780
  }
721
781
  
722
782
  if(quit_now){
730
790
      if(if_indextoname((unsigned int)if_index, interface) == NULL){
731
791
        perror_plus("if_indextoname");
732
792
      } else {
733
 
        fprintf_plus(stderr, "Connection to: %s%%%s, port %" PRIu16
734
 
                     "\n", ip, interface, port);
 
793
        fprintf_plus(stderr, "Connection to: %s%%%s, port %" PRIuMAX
 
794
                     "\n", ip, interface, (uintmax_t)port);
735
795
      }
736
796
    } else {
737
 
      fprintf_plus(stderr, "Connection to: %s, port %" PRIu16 "\n",
738
 
                   ip, port);
 
797
      fprintf_plus(stderr, "Connection to: %s, port %" PRIuMAX "\n",
 
798
                   ip, (uintmax_t)port);
739
799
    }
740
800
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
741
801
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
742
 
    const char *pcret;
743
802
    if(af == AF_INET6){
744
 
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
745
 
                        sizeof(addrstr));
 
803
      ret = getnameinfo((struct sockaddr *)&to,
 
804
                        sizeof(struct sockaddr_in6),
 
805
                        addrstr, sizeof(addrstr), NULL, 0,
 
806
                        NI_NUMERICHOST);
746
807
    } else {
747
 
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
748
 
                        sizeof(addrstr));
 
808
      ret = getnameinfo((struct sockaddr *)&to,
 
809
                        sizeof(struct sockaddr_in),
 
810
                        addrstr, sizeof(addrstr), NULL, 0,
 
811
                        NI_NUMERICHOST);
749
812
    }
750
 
    if(pcret == NULL){
751
 
      perror_plus("inet_ntop");
752
 
    } else {
753
 
      if(strcmp(addrstr, ip) != 0){
754
 
        fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
755
 
      }
 
813
    if(ret == EAI_SYSTEM){
 
814
      perror_plus("getnameinfo");
 
815
    } else if(ret != 0) {
 
816
      fprintf_plus(stderr, "getnameinfo: %s", gai_strerror(ret));
 
817
    } else if(strcmp(addrstr, ip) != 0){
 
818
      fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
756
819
    }
757
820
  }
758
821
  
762
825
  }
763
826
  
764
827
  if(af == AF_INET6){
765
 
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
828
    ret = connect(tcp_sd, (struct sockaddr *)&to,
 
829
                  sizeof(struct sockaddr_in6));
766
830
  } else {
767
 
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
831
    ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
832
                  sizeof(struct sockaddr_in));
768
833
  }
769
834
  if(ret < 0){
770
 
    if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
835
    if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
771
836
      int e = errno;
772
837
      perror_plus("connect");
773
838
      errno = e;
819
884
    goto mandos_end;
820
885
  }
821
886
  
822
 
  /* Spurious warning from -Wint-to-pointer-cast */
823
 
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
887
  /* This casting via intptr_t is to eliminate warning about casting
 
888
     an int to a pointer type.  This is exactly how the GnuTLS Guile
 
889
     function "set-session-transport-fd!" does it. */
 
890
  gnutls_transport_set_ptr(session,
 
891
                           (gnutls_transport_ptr_t)(intptr_t)tcp_sd);
824
892
  
825
893
  if(quit_now){
826
894
    errno = EINTR;
931
999
  if(buffer_length > 0){
932
1000
    ssize_t decrypted_buffer_size;
933
1001
    decrypted_buffer_size = pgp_packet_decrypt(buffer, buffer_length,
934
 
                                               &decrypted_buffer);
 
1002
                                               &decrypted_buffer, mc);
935
1003
    if(decrypted_buffer_size >= 0){
936
1004
      
937
1005
      written = 0;
985
1053
  return retval;
986
1054
}
987
1055
 
 
1056
__attribute__((nonnull))
988
1057
static void resolve_callback(AvahiSServiceResolver *r,
989
1058
                             AvahiIfIndex interface,
990
1059
                             AvahiProtocol proto,
998
1067
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
999
1068
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
1000
1069
                             flags,
1001
 
                             AVAHI_GCC_UNUSED void* userdata){
1002
 
  assert(r);
 
1070
                             void *mc){
 
1071
  if(r == NULL){
 
1072
    return;
 
1073
  }
1003
1074
  
1004
1075
  /* Called whenever a service has been resolved successfully or
1005
1076
     timed out */
1006
1077
  
1007
1078
  if(quit_now){
 
1079
    avahi_s_service_resolver_free(r);
1008
1080
    return;
1009
1081
  }
1010
1082
  
1014
1086
    fprintf_plus(stderr, "(Avahi Resolver) Failed to resolve service "
1015
1087
                 "'%s' of type '%s' in domain '%s': %s\n", name, type,
1016
1088
                 domain,
1017
 
                 avahi_strerror(avahi_server_errno(mc.server)));
 
1089
                 avahi_strerror(avahi_server_errno
 
1090
                                (((mandos_context*)mc)->server)));
1018
1091
    break;
1019
1092
    
1020
1093
  case AVAHI_RESOLVER_FOUND:
1026
1099
                     PRIdMAX ") on port %" PRIu16 "\n", name,
1027
1100
                     host_name, ip, (intmax_t)interface, port);
1028
1101
      }
1029
 
      int ret = start_mandos_communication(ip, port, interface,
1030
 
                                           avahi_proto_to_af(proto));
 
1102
      int ret = start_mandos_communication(ip, (in_port_t)port,
 
1103
                                           interface,
 
1104
                                           avahi_proto_to_af(proto),
 
1105
                                           mc);
1031
1106
      if(ret == 0){
1032
 
        avahi_simple_poll_quit(mc.simple_poll);
 
1107
        avahi_simple_poll_quit(simple_poll);
1033
1108
      } else {
1034
 
        if(not add_server(ip, port, interface,
1035
 
                          avahi_proto_to_af(proto))){
 
1109
        if(not add_server(ip, (in_port_t)port, interface,
 
1110
                          avahi_proto_to_af(proto),
 
1111
                          &((mandos_context*)mc)->current_server)){
1036
1112
          fprintf_plus(stderr, "Failed to add server \"%s\" to server"
1037
1113
                       " list\n", name);
1038
1114
        }
1051
1127
                            const char *domain,
1052
1128
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
1053
1129
                            flags,
1054
 
                            AVAHI_GCC_UNUSED void* userdata){
1055
 
  assert(b);
 
1130
                            void *mc){
 
1131
  if(b == NULL){
 
1132
    return;
 
1133
  }
1056
1134
  
1057
1135
  /* Called whenever a new services becomes available on the LAN or
1058
1136
     is removed from the LAN */
1066
1144
  case AVAHI_BROWSER_FAILURE:
1067
1145
    
1068
1146
    fprintf_plus(stderr, "(Avahi browser) %s\n",
1069
 
                 avahi_strerror(avahi_server_errno(mc.server)));
1070
 
    avahi_simple_poll_quit(mc.simple_poll);
 
1147
                 avahi_strerror(avahi_server_errno
 
1148
                                (((mandos_context*)mc)->server)));
 
1149
    avahi_simple_poll_quit(simple_poll);
1071
1150
    return;
1072
1151
    
1073
1152
  case AVAHI_BROWSER_NEW:
1076
1155
       the callback function is called the Avahi server will free the
1077
1156
       resolver for us. */
1078
1157
    
1079
 
    if(avahi_s_service_resolver_new(mc.server, interface, protocol,
1080
 
                                    name, type, domain, protocol, 0,
1081
 
                                    resolve_callback, NULL) == NULL)
 
1158
    if(avahi_s_service_resolver_new(((mandos_context*)mc)->server,
 
1159
                                    interface, protocol, name, type,
 
1160
                                    domain, protocol, 0,
 
1161
                                    resolve_callback, mc) == NULL)
1082
1162
      fprintf_plus(stderr, "Avahi: Failed to resolve service '%s':"
1083
1163
                   " %s\n", name,
1084
 
                   avahi_strerror(avahi_server_errno(mc.server)));
 
1164
                   avahi_strerror(avahi_server_errno
 
1165
                                  (((mandos_context*)mc)->server)));
1085
1166
    break;
1086
1167
    
1087
1168
  case AVAHI_BROWSER_REMOVE:
1106
1187
  signal_received = sig;
1107
1188
  int old_errno = errno;
1108
1189
  /* set main loop to exit */
1109
 
  if(mc.simple_poll != NULL){
1110
 
    avahi_simple_poll_quit(mc.simple_poll);
 
1190
  if(simple_poll != NULL){
 
1191
    avahi_simple_poll_quit(simple_poll);
1111
1192
  }
1112
1193
  errno = old_errno;
1113
1194
}
1114
1195
 
 
1196
__attribute__((nonnull, warn_unused_result))
1115
1197
bool get_flags(const char *ifname, struct ifreq *ifr){
1116
1198
  int ret;
 
1199
  error_t ret_errno;
1117
1200
  
1118
1201
  int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1119
1202
  if(s < 0){
 
1203
    ret_errno = errno;
1120
1204
    perror_plus("socket");
 
1205
    errno = ret_errno;
1121
1206
    return false;
1122
1207
  }
1123
1208
  strcpy(ifr->ifr_name, ifname);
1124
1209
  ret = ioctl(s, SIOCGIFFLAGS, ifr);
1125
1210
  if(ret == -1){
1126
1211
    if(debug){
 
1212
      ret_errno = errno;
1127
1213
      perror_plus("ioctl SIOCGIFFLAGS");
 
1214
      errno = ret_errno;
1128
1215
    }
1129
1216
    return false;
1130
1217
  }
1131
1218
  return true;
1132
1219
}
1133
1220
 
 
1221
__attribute__((nonnull, warn_unused_result))
1134
1222
bool good_flags(const char *ifname, const struct ifreq *ifr){
1135
1223
  
1136
1224
  /* Reject the loopback device */
1178
1266
 * corresponds to an acceptable network device.
1179
1267
 * (This function is passed to scandir(3) as a filter function.)
1180
1268
 */
 
1269
__attribute__((nonnull, warn_unused_result))
1181
1270
int good_interface(const struct dirent *if_entry){
1182
1271
  if(if_entry->d_name[0] == '.'){
1183
1272
    return 0;
1199
1288
}
1200
1289
 
1201
1290
/* 
1202
 
 * This function determines if a directory entry in /sys/class/net
1203
 
 * corresponds to an acceptable network device which is up.
1204
 
 * (This function is passed to scandir(3) as a filter function.)
1205
 
 */
1206
 
int up_interface(const struct dirent *if_entry){
1207
 
  if(if_entry->d_name[0] == '.'){
1208
 
    return 0;
1209
 
  }
1210
 
  
1211
 
  struct ifreq ifr;
1212
 
  if(not get_flags(if_entry->d_name, &ifr)){
1213
 
    if(debug){
1214
 
      fprintf_plus(stderr, "Failed to get flags for interface "
1215
 
                   "\"%s\"\n", if_entry->d_name);
1216
 
    }
1217
 
    return 0;
1218
 
  }
1219
 
  
1220
 
  /* Reject down interfaces */
1221
 
  if(not (ifr.ifr_flags & IFF_UP)){
1222
 
    if(debug){
1223
 
      fprintf_plus(stderr, "Rejecting down interface \"%s\"\n",
1224
 
                   if_entry->d_name);
1225
 
    }
1226
 
    return 0;
1227
 
  }
1228
 
  
1229
 
  /* Reject non-running interfaces */
1230
 
  if(not (ifr.ifr_flags & IFF_RUNNING)){
1231
 
    if(debug){
1232
 
      fprintf_plus(stderr, "Rejecting non-running interface \"%s\"\n",
1233
 
                   if_entry->d_name);
1234
 
    }
1235
 
    return 0;
1236
 
  }
1237
 
  
1238
 
  if(not good_flags(if_entry->d_name, &ifr)){
1239
 
    return 0;
1240
 
  }
1241
 
  return 1;
1242
 
}
1243
 
 
 
1291
 * This function determines if a network interface is up.
 
1292
 */
 
1293
__attribute__((nonnull, warn_unused_result))
 
1294
bool interface_is_up(const char *interface){
 
1295
  struct ifreq ifr;
 
1296
  if(not get_flags(interface, &ifr)){
 
1297
    if(debug){
 
1298
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1299
                   "\"%s\"\n", interface);
 
1300
    }
 
1301
    return false;
 
1302
  }
 
1303
  
 
1304
  return (bool)(ifr.ifr_flags & IFF_UP);
 
1305
}
 
1306
 
 
1307
/* 
 
1308
 * This function determines if a network interface is running
 
1309
 */
 
1310
__attribute__((nonnull, warn_unused_result))
 
1311
bool interface_is_running(const char *interface){
 
1312
  struct ifreq ifr;
 
1313
  if(not get_flags(interface, &ifr)){
 
1314
    if(debug){
 
1315
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1316
                   "\"%s\"\n", interface);
 
1317
    }
 
1318
    return false;
 
1319
  }
 
1320
  
 
1321
  return (bool)(ifr.ifr_flags & IFF_RUNNING);
 
1322
}
 
1323
 
 
1324
__attribute__((nonnull, pure, warn_unused_result))
1244
1325
int notdotentries(const struct dirent *direntry){
1245
1326
  /* Skip "." and ".." */
1246
1327
  if(direntry->d_name[0] == '.'
1253
1334
}
1254
1335
 
1255
1336
/* Is this directory entry a runnable program? */
 
1337
__attribute__((nonnull, warn_unused_result))
1256
1338
int runnable_hook(const struct dirent *direntry){
1257
1339
  int ret;
1258
1340
  size_t sret;
1266
1348
  sret = strspn(direntry->d_name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1267
1349
                "abcdefghijklmnopqrstuvwxyz"
1268
1350
                "0123456789"
1269
 
                "_-");
 
1351
                "_.-");
1270
1352
  if((direntry->d_name)[sret] != '\0'){
1271
1353
    /* Contains non-allowed characters */
1272
1354
    if(debug){
1276
1358
    return 0;
1277
1359
  }
1278
1360
  
1279
 
  char *fullname = NULL;
1280
 
  ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1281
 
  if(ret < 0){
1282
 
    perror_plus("asprintf");
1283
 
    return 0;
1284
 
  }
1285
 
  
1286
 
  ret = stat(fullname, &st);
 
1361
  ret = fstatat(hookdir_fd, direntry->d_name, &st, 0);
1287
1362
  if(ret == -1){
1288
1363
    if(debug){
1289
1364
      perror_plus("Could not stat hook");
1313
1388
  return 1;
1314
1389
}
1315
1390
 
1316
 
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval){
 
1391
__attribute__((nonnull, warn_unused_result))
 
1392
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval,
 
1393
                            mandos_context *mc){
1317
1394
  int ret;
1318
1395
  struct timespec now;
1319
1396
  struct timespec waited_time;
1320
1397
  intmax_t block_time;
1321
1398
  
1322
1399
  while(true){
1323
 
    if(mc.current_server == NULL){
1324
 
      if (debug){
 
1400
    if(mc->current_server == NULL){
 
1401
      if(debug){
1325
1402
        fprintf_plus(stderr, "Wait until first server is found."
1326
1403
                     " No timeout!\n");
1327
1404
      }
1328
1405
      ret = avahi_simple_poll_iterate(s, -1);
1329
1406
    } else {
1330
 
      if (debug){
 
1407
      if(debug){
1331
1408
        fprintf_plus(stderr, "Check current_server if we should run"
1332
1409
                     " it, or wait\n");
1333
1410
      }
1340
1417
      /* Calculating in ms how long time between now and server
1341
1418
         who we visted longest time ago. Now - last seen.  */
1342
1419
      waited_time.tv_sec = (now.tv_sec
1343
 
                            - mc.current_server->last_seen.tv_sec);
 
1420
                            - mc->current_server->last_seen.tv_sec);
1344
1421
      waited_time.tv_nsec = (now.tv_nsec
1345
 
                             - mc.current_server->last_seen.tv_nsec);
 
1422
                             - mc->current_server->last_seen.tv_nsec);
1346
1423
      /* total time is 10s/10,000ms.
1347
1424
         Converting to s from ms by dividing by 1,000,
1348
1425
         and ns to ms by dividing by 1,000,000. */
1350
1427
                     - ((intmax_t)waited_time.tv_sec * 1000))
1351
1428
                    - ((intmax_t)waited_time.tv_nsec / 1000000));
1352
1429
      
1353
 
      if (debug){
 
1430
      if(debug){
1354
1431
        fprintf_plus(stderr, "Blocking for %" PRIdMAX " ms\n",
1355
1432
                     block_time);
1356
1433
      }
1357
1434
      
1358
1435
      if(block_time <= 0){
1359
 
        ret = start_mandos_communication(mc.current_server->ip,
1360
 
                                         mc.current_server->port,
1361
 
                                         mc.current_server->if_index,
1362
 
                                         mc.current_server->af);
 
1436
        ret = start_mandos_communication(mc->current_server->ip,
 
1437
                                         mc->current_server->port,
 
1438
                                         mc->current_server->if_index,
 
1439
                                         mc->current_server->af, mc);
1363
1440
        if(ret == 0){
1364
 
          avahi_simple_poll_quit(mc.simple_poll);
 
1441
          avahi_simple_poll_quit(s);
1365
1442
          return 0;
1366
1443
        }
1367
1444
        ret = clock_gettime(CLOCK_MONOTONIC,
1368
 
                            &mc.current_server->last_seen);
 
1445
                            &mc->current_server->last_seen);
1369
1446
        if(ret == -1){
1370
1447
          perror_plus("clock_gettime");
1371
1448
          return -1;
1372
1449
        }
1373
 
        mc.current_server = mc.current_server->next;
 
1450
        mc->current_server = mc->current_server->next;
1374
1451
        block_time = 0;         /* Call avahi to find new Mandos
1375
1452
                                   servers, but don't block */
1376
1453
      }
1378
1455
      ret = avahi_simple_poll_iterate(s, (int)block_time);
1379
1456
    }
1380
1457
    if(ret != 0){
1381
 
      if (ret > 0 or errno != EINTR){
 
1458
      if(ret > 0 or errno != EINTR){
1382
1459
        return (ret != 1) ? ret : 0;
1383
1460
      }
1384
1461
    }
1385
1462
  }
1386
1463
}
1387
1464
 
1388
 
bool run_network_hooks(const char *mode, const char *interface,
 
1465
/* Set effective uid to 0, return errno */
 
1466
__attribute__((warn_unused_result))
 
1467
error_t raise_privileges(void){
 
1468
  error_t old_errno = errno;
 
1469
  error_t ret_errno = 0;
 
1470
  if(seteuid(0) == -1){
 
1471
    ret_errno = errno;
 
1472
  }
 
1473
  errno = old_errno;
 
1474
  return ret_errno;
 
1475
}
 
1476
 
 
1477
/* Set effective and real user ID to 0.  Return errno. */
 
1478
__attribute__((warn_unused_result))
 
1479
error_t raise_privileges_permanently(void){
 
1480
  error_t old_errno = errno;
 
1481
  error_t ret_errno = raise_privileges();
 
1482
  if(ret_errno != 0){
 
1483
    errno = old_errno;
 
1484
    return ret_errno;
 
1485
  }
 
1486
  if(setuid(0) == -1){
 
1487
    ret_errno = errno;
 
1488
  }
 
1489
  errno = old_errno;
 
1490
  return ret_errno;
 
1491
}
 
1492
 
 
1493
/* Set effective user ID to unprivileged saved user ID */
 
1494
__attribute__((warn_unused_result))
 
1495
error_t lower_privileges(void){
 
1496
  error_t old_errno = errno;
 
1497
  error_t ret_errno = 0;
 
1498
  if(seteuid(uid) == -1){
 
1499
    ret_errno = errno;
 
1500
  }
 
1501
  errno = old_errno;
 
1502
  return ret_errno;
 
1503
}
 
1504
 
 
1505
/* Lower privileges permanently */
 
1506
__attribute__((warn_unused_result))
 
1507
error_t lower_privileges_permanently(void){
 
1508
  error_t old_errno = errno;
 
1509
  error_t ret_errno = 0;
 
1510
  if(setuid(uid) == -1){
 
1511
    ret_errno = errno;
 
1512
  }
 
1513
  errno = old_errno;
 
1514
  return ret_errno;
 
1515
}
 
1516
 
 
1517
__attribute__((nonnull))
 
1518
void run_network_hooks(const char *mode, const char *interface,
1389
1519
                       const float delay){
1390
 
  struct dirent **direntries;
1391
 
  struct dirent *direntry;
1392
 
  int ret;
1393
 
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
1394
 
                         alphasort);
 
1520
  struct dirent **direntries = NULL;
 
1521
  if(hookdir_fd == -1){
 
1522
    hookdir_fd = open(hookdir, O_RDONLY);
 
1523
    if(hookdir_fd == -1){
 
1524
      if(errno == ENOENT){
 
1525
        if(debug){
 
1526
          fprintf_plus(stderr, "Network hook directory \"%s\" not"
 
1527
                       " found\n", hookdir);
 
1528
        }
 
1529
      } else {
 
1530
        perror_plus("open");
 
1531
      }
 
1532
      return;
 
1533
    }
 
1534
  }
 
1535
#ifdef __GLIBC__
 
1536
#if __GLIBC_PREREQ(2, 15)
 
1537
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
 
1538
                           runnable_hook, alphasort);
 
1539
#else  /* not __GLIBC_PREREQ(2, 15) */
 
1540
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
 
1541
                         alphasort);
 
1542
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
1543
#else   /* not __GLIBC__ */
 
1544
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
 
1545
                         alphasort);
 
1546
#endif  /* not __GLIBC__ */
1395
1547
  if(numhooks == -1){
1396
1548
    perror_plus("scandir");
1397
 
  } else {
1398
 
    int devnull = open("/dev/null", O_RDONLY);
1399
 
    for(int i = 0; i < numhooks; i++){
1400
 
      direntry = direntries[i];
1401
 
      char *fullname = NULL;
1402
 
      ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1403
 
      if(ret < 0){
 
1549
    return;
 
1550
  }
 
1551
  struct dirent *direntry;
 
1552
  int ret;
 
1553
  int devnull = open("/dev/null", O_RDONLY);
 
1554
  for(int i = 0; i < numhooks; i++){
 
1555
    direntry = direntries[i];
 
1556
    if(debug){
 
1557
      fprintf_plus(stderr, "Running network hook \"%s\"\n",
 
1558
                   direntry->d_name);
 
1559
    }
 
1560
    pid_t hook_pid = fork();
 
1561
    if(hook_pid == 0){
 
1562
      /* Child */
 
1563
      /* Raise privileges */
 
1564
      errno = raise_privileges_permanently();
 
1565
      if(errno != 0){
 
1566
        perror_plus("Failed to raise privileges");
 
1567
        _exit(EX_NOPERM);
 
1568
      }
 
1569
      /* Set group */
 
1570
      errno = 0;
 
1571
      ret = setgid(0);
 
1572
      if(ret == -1){
 
1573
        perror_plus("setgid");
 
1574
        _exit(EX_NOPERM);
 
1575
      }
 
1576
      /* Reset supplementary groups */
 
1577
      errno = 0;
 
1578
      ret = setgroups(0, NULL);
 
1579
      if(ret == -1){
 
1580
        perror_plus("setgroups");
 
1581
        _exit(EX_NOPERM);
 
1582
      }
 
1583
      ret = dup2(devnull, STDIN_FILENO);
 
1584
      if(ret == -1){
 
1585
        perror_plus("dup2(devnull, STDIN_FILENO)");
 
1586
        _exit(EX_OSERR);
 
1587
      }
 
1588
      ret = close(devnull);
 
1589
      if(ret == -1){
 
1590
        perror_plus("close");
 
1591
        _exit(EX_OSERR);
 
1592
      }
 
1593
      ret = dup2(STDERR_FILENO, STDOUT_FILENO);
 
1594
      if(ret == -1){
 
1595
        perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
 
1596
        _exit(EX_OSERR);
 
1597
      }
 
1598
      ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
 
1599
      if(ret == -1){
 
1600
        perror_plus("setenv");
 
1601
        _exit(EX_OSERR);
 
1602
      }
 
1603
      ret = setenv("DEVICE", interface, 1);
 
1604
      if(ret == -1){
 
1605
        perror_plus("setenv");
 
1606
        _exit(EX_OSERR);
 
1607
      }
 
1608
      ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
 
1609
      if(ret == -1){
 
1610
        perror_plus("setenv");
 
1611
        _exit(EX_OSERR);
 
1612
      }
 
1613
      ret = setenv("MODE", mode, 1);
 
1614
      if(ret == -1){
 
1615
        perror_plus("setenv");
 
1616
        _exit(EX_OSERR);
 
1617
      }
 
1618
      char *delaystring;
 
1619
      ret = asprintf(&delaystring, "%f", (double)delay);
 
1620
      if(ret == -1){
1404
1621
        perror_plus("asprintf");
1405
 
        continue;
1406
 
      }
1407
 
      if(debug){
1408
 
        fprintf_plus(stderr, "Running network hook \"%s\"\n",
1409
 
                     direntry->d_name);
1410
 
      }
1411
 
      pid_t hook_pid = fork();
1412
 
      if(hook_pid == 0){
1413
 
        /* Child */
1414
 
        /* Raise privileges */
1415
 
        errno = 0;
1416
 
        ret = seteuid(0);
1417
 
        if(ret == -1){
1418
 
          perror_plus("seteuid");
1419
 
        }
1420
 
        /* Raise privileges even more */
1421
 
        errno = 0;
1422
 
        ret = setuid(0);
1423
 
        if(ret == -1){
1424
 
          perror_plus("setuid");
1425
 
        }
1426
 
        /* Set group */
1427
 
        errno = 0;
1428
 
        ret = setgid(0);
1429
 
        if(ret == -1){
1430
 
          perror_plus("setgid");
1431
 
        }
1432
 
        /* Reset supplementary groups */
1433
 
        errno = 0;
1434
 
        ret = setgroups(0, NULL);
1435
 
        if(ret == -1){
1436
 
          perror_plus("setgroups");
1437
 
        }
1438
 
        dup2(devnull, STDIN_FILENO);
1439
 
        close(devnull);
1440
 
        dup2(STDERR_FILENO, STDOUT_FILENO);
1441
 
        ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
1442
 
        if(ret == -1){
1443
 
          perror_plus("setenv");
1444
 
          _exit(EX_OSERR);
1445
 
        }
1446
 
        ret = setenv("DEVICE", interface, 1);
1447
 
        if(ret == -1){
1448
 
          perror_plus("setenv");
1449
 
          _exit(EX_OSERR);
1450
 
        }
1451
 
        ret = setenv("VERBOSE", debug ? "1" : "0", 1);
1452
 
        if(ret == -1){
1453
 
          perror_plus("setenv");
1454
 
          _exit(EX_OSERR);
1455
 
        }
1456
 
        ret = setenv("MODE", mode, 1);
1457
 
        if(ret == -1){
1458
 
          perror_plus("setenv");
1459
 
          _exit(EX_OSERR);
1460
 
        }
1461
 
        char *delaystring;
1462
 
        ret = asprintf(&delaystring, "%f", delay);
1463
 
        if(ret == -1){
1464
 
          perror_plus("asprintf");
1465
 
          _exit(EX_OSERR);
1466
 
        }
1467
 
        ret = setenv("DELAY", delaystring, 1);
1468
 
        if(ret == -1){
1469
 
          free(delaystring);
1470
 
          perror_plus("setenv");
1471
 
          _exit(EX_OSERR);
1472
 
        }
 
1622
        _exit(EX_OSERR);
 
1623
      }
 
1624
      ret = setenv("DELAY", delaystring, 1);
 
1625
      if(ret == -1){
1473
1626
        free(delaystring);
1474
 
        if(execl(fullname, direntry->d_name, mode, NULL) == -1){
1475
 
          perror_plus("execl");
1476
 
          _exit(EXIT_FAILURE);
1477
 
        }
1478
 
      } else {
1479
 
        int status;
1480
 
        if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1481
 
          perror_plus("waitpid");
1482
 
          free(fullname);
1483
 
          continue;
1484
 
        }
1485
 
        if(WIFEXITED(status)){
1486
 
          if(WEXITSTATUS(status) != 0){
1487
 
            fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1488
 
                         " with status %d\n", direntry->d_name,
1489
 
                         WEXITSTATUS(status));
1490
 
            free(fullname);
1491
 
            continue;
1492
 
          }
1493
 
        } else if(WIFSIGNALED(status)){
1494
 
          fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1495
 
                       " signal %d\n", direntry->d_name,
1496
 
                       WTERMSIG(status));
1497
 
          free(fullname);
1498
 
          continue;
1499
 
        } else {
1500
 
          fprintf_plus(stderr, "Warning: network hook \"%s\""
1501
 
                       " crashed\n", direntry->d_name);
1502
 
          free(fullname);
1503
 
          continue;
1504
 
        }
1505
 
      }
1506
 
      free(fullname);
1507
 
      if(debug){
1508
 
        fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1509
 
                     direntry->d_name);
1510
 
      }
1511
 
    }
1512
 
    close(devnull);
1513
 
  }
1514
 
  return true;
 
1627
        perror_plus("setenv");
 
1628
        _exit(EX_OSERR);
 
1629
      }
 
1630
      free(delaystring);
 
1631
      if(connect_to != NULL){
 
1632
        ret = setenv("CONNECT", connect_to, 1);
 
1633
        if(ret == -1){
 
1634
          perror_plus("setenv");
 
1635
          _exit(EX_OSERR);
 
1636
        }
 
1637
      }
 
1638
      int hook_fd = openat(hookdir_fd, direntry->d_name, O_RDONLY);
 
1639
      if(hook_fd == -1){
 
1640
        perror_plus("openat");
 
1641
        _exit(EXIT_FAILURE);
 
1642
      }
 
1643
      if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1644
        perror_plus("close");
 
1645
        _exit(EXIT_FAILURE);
 
1646
      }
 
1647
      if(fexecve(hook_fd, (char *const []){ direntry->d_name, NULL },
 
1648
                 environ) == -1){
 
1649
        perror_plus("fexecve");
 
1650
        _exit(EXIT_FAILURE);
 
1651
      }
 
1652
    } else {
 
1653
      if(hook_pid == -1){
 
1654
        perror_plus("fork");
 
1655
        free(direntry);
 
1656
        continue;
 
1657
      }
 
1658
      int status;
 
1659
      if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
 
1660
        perror_plus("waitpid");
 
1661
        free(direntry);
 
1662
        continue;
 
1663
      }
 
1664
      if(WIFEXITED(status)){
 
1665
        if(WEXITSTATUS(status) != 0){
 
1666
          fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
 
1667
                       " with status %d\n", direntry->d_name,
 
1668
                       WEXITSTATUS(status));
 
1669
          free(direntry);
 
1670
          continue;
 
1671
        }
 
1672
      } else if(WIFSIGNALED(status)){
 
1673
        fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
 
1674
                     " signal %d\n", direntry->d_name,
 
1675
                     WTERMSIG(status));
 
1676
        free(direntry);
 
1677
        continue;
 
1678
      } else {
 
1679
        fprintf_plus(stderr, "Warning: network hook \"%s\""
 
1680
                     " crashed\n", direntry->d_name);
 
1681
        free(direntry);
 
1682
        continue;
 
1683
      }
 
1684
    }
 
1685
    if(debug){
 
1686
      fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
 
1687
                   direntry->d_name);
 
1688
    }
 
1689
    free(direntry);
 
1690
  }
 
1691
  free(direntries);
 
1692
  if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1693
    perror_plus("close");
 
1694
  } else {
 
1695
    hookdir_fd = -1;
 
1696
  }
 
1697
  close(devnull);
 
1698
}
 
1699
 
 
1700
__attribute__((nonnull, warn_unused_result))
 
1701
error_t bring_up_interface(const char *const interface,
 
1702
                           const float delay){
 
1703
  error_t old_errno = errno;
 
1704
  int ret;
 
1705
  struct ifreq network;
 
1706
  unsigned int if_index = if_nametoindex(interface);
 
1707
  if(if_index == 0){
 
1708
    fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
 
1709
    errno = old_errno;
 
1710
    return ENXIO;
 
1711
  }
 
1712
  
 
1713
  if(quit_now){
 
1714
    errno = old_errno;
 
1715
    return EINTR;
 
1716
  }
 
1717
  
 
1718
  if(not interface_is_up(interface)){
 
1719
    error_t ret_errno = 0, ioctl_errno = 0;
 
1720
    if(not get_flags(interface, &network)){
 
1721
      ret_errno = errno;
 
1722
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1723
                   "\"%s\"\n", interface);
 
1724
      errno = old_errno;
 
1725
      return ret_errno;
 
1726
    }
 
1727
    network.ifr_flags |= IFF_UP; /* set flag */
 
1728
    
 
1729
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1730
    if(sd == -1){
 
1731
      ret_errno = errno;
 
1732
      perror_plus("socket");
 
1733
      errno = old_errno;
 
1734
      return ret_errno;
 
1735
    }
 
1736
    
 
1737
    if(quit_now){
 
1738
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1739
      if(ret == -1){
 
1740
        perror_plus("close");
 
1741
      }
 
1742
      errno = old_errno;
 
1743
      return EINTR;
 
1744
    }
 
1745
    
 
1746
    if(debug){
 
1747
      fprintf_plus(stderr, "Bringing up interface \"%s\"\n",
 
1748
                   interface);
 
1749
    }
 
1750
    
 
1751
    /* Raise privileges */
 
1752
    ret_errno = raise_privileges();
 
1753
    if(ret_errno != 0){
 
1754
      errno = ret_errno;
 
1755
      perror_plus("Failed to raise privileges");
 
1756
    }
 
1757
    
 
1758
#ifdef __linux__
 
1759
    int ret_linux;
 
1760
    bool restore_loglevel = false;
 
1761
    if(ret_errno == 0){
 
1762
      /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1763
         messages about the network interface to mess up the prompt */
 
1764
      ret_linux = klogctl(8, NULL, 5);
 
1765
      if(ret_linux == -1){
 
1766
        perror_plus("klogctl");
 
1767
      } else {
 
1768
        restore_loglevel = true;
 
1769
      }
 
1770
    }
 
1771
#endif  /* __linux__ */
 
1772
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1773
    ioctl_errno = errno;
 
1774
#ifdef __linux__
 
1775
    if(restore_loglevel){
 
1776
      ret_linux = klogctl(7, NULL, 0);
 
1777
      if(ret_linux == -1){
 
1778
        perror_plus("klogctl");
 
1779
      }
 
1780
    }
 
1781
#endif  /* __linux__ */
 
1782
    
 
1783
    /* If raise_privileges() succeeded above */
 
1784
    if(ret_errno == 0){
 
1785
      /* Lower privileges */
 
1786
      ret_errno = lower_privileges();
 
1787
      if(ret_errno != 0){
 
1788
        errno = ret_errno;
 
1789
        perror_plus("Failed to lower privileges");
 
1790
      }
 
1791
    }
 
1792
    
 
1793
    /* Close the socket */
 
1794
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1795
    if(ret == -1){
 
1796
      perror_plus("close");
 
1797
    }
 
1798
    
 
1799
    if(ret_setflags == -1){
 
1800
      errno = ioctl_errno;
 
1801
      perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
 
1802
      errno = old_errno;
 
1803
      return ioctl_errno;
 
1804
    }
 
1805
  } else if(debug){
 
1806
    fprintf_plus(stderr, "Interface \"%s\" is already up; good\n",
 
1807
                 interface);
 
1808
  }
 
1809
  
 
1810
  /* Sleep checking until interface is running.
 
1811
     Check every 0.25s, up to total time of delay */
 
1812
  for(int i=0; i < delay * 4; i++){
 
1813
    if(interface_is_running(interface)){
 
1814
      break;
 
1815
    }
 
1816
    struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1817
    ret = nanosleep(&sleeptime, NULL);
 
1818
    if(ret == -1 and errno != EINTR){
 
1819
      perror_plus("nanosleep");
 
1820
    }
 
1821
  }
 
1822
  
 
1823
  errno = old_errno;
 
1824
  return 0;
 
1825
}
 
1826
 
 
1827
__attribute__((nonnull, warn_unused_result))
 
1828
error_t take_down_interface(const char *const interface){
 
1829
  error_t old_errno = errno;
 
1830
  struct ifreq network;
 
1831
  unsigned int if_index = if_nametoindex(interface);
 
1832
  if(if_index == 0){
 
1833
    fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
 
1834
    errno = old_errno;
 
1835
    return ENXIO;
 
1836
  }
 
1837
  if(interface_is_up(interface)){
 
1838
    error_t ret_errno = 0, ioctl_errno = 0;
 
1839
    if(not get_flags(interface, &network) and debug){
 
1840
      ret_errno = errno;
 
1841
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1842
                   "\"%s\"\n", interface);
 
1843
      errno = old_errno;
 
1844
      return ret_errno;
 
1845
    }
 
1846
    network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
 
1847
    
 
1848
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1849
    if(sd == -1){
 
1850
      ret_errno = errno;
 
1851
      perror_plus("socket");
 
1852
      errno = old_errno;
 
1853
      return ret_errno;
 
1854
    }
 
1855
    
 
1856
    if(debug){
 
1857
      fprintf_plus(stderr, "Taking down interface \"%s\"\n",
 
1858
                   interface);
 
1859
    }
 
1860
    
 
1861
    /* Raise privileges */
 
1862
    ret_errno = raise_privileges();
 
1863
    if(ret_errno != 0){
 
1864
      errno = ret_errno;
 
1865
      perror_plus("Failed to raise privileges");
 
1866
    }
 
1867
    
 
1868
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1869
    ioctl_errno = errno;
 
1870
    
 
1871
    /* If raise_privileges() succeeded above */
 
1872
    if(ret_errno == 0){
 
1873
      /* Lower privileges */
 
1874
      ret_errno = lower_privileges();
 
1875
      if(ret_errno != 0){
 
1876
        errno = ret_errno;
 
1877
        perror_plus("Failed to lower privileges");
 
1878
      }
 
1879
    }
 
1880
    
 
1881
    /* Close the socket */
 
1882
    int ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1883
    if(ret == -1){
 
1884
      perror_plus("close");
 
1885
    }
 
1886
    
 
1887
    if(ret_setflags == -1){
 
1888
      errno = ioctl_errno;
 
1889
      perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
 
1890
      errno = old_errno;
 
1891
      return ioctl_errno;
 
1892
    }
 
1893
  } else if(debug){
 
1894
    fprintf_plus(stderr, "Interface \"%s\" is already down; odd\n",
 
1895
                 interface);
 
1896
  }
 
1897
  
 
1898
  errno = old_errno;
 
1899
  return 0;
1515
1900
}
1516
1901
 
1517
1902
int main(int argc, char *argv[]){
 
1903
  mandos_context mc = { .server = NULL, .dh_bits = 1024,
 
1904
                        .priority = "SECURE256:!CTYPE-X.509:"
 
1905
                        "+CTYPE-OPENPGP", .current_server = NULL,
 
1906
                        .interfaces = NULL, .interfaces_size = 0 };
1518
1907
  AvahiSServiceBrowser *sb = NULL;
1519
 
  int error;
 
1908
  error_t ret_errno;
1520
1909
  int ret;
1521
1910
  intmax_t tmpmax;
1522
1911
  char *tmp;
1523
1912
  int exitcode = EXIT_SUCCESS;
1524
 
  const char *interface = "";
1525
 
  struct ifreq network;
1526
 
  int sd = -1;
1527
 
  bool take_down_interface = false;
1528
 
  uid_t uid;
1529
 
  gid_t gid;
1530
 
  char tempdir[] = "/tmp/mandosXXXXXX";
1531
 
  bool tempdir_created = false;
 
1913
  char *interfaces_to_take_down = NULL;
 
1914
  size_t interfaces_to_take_down_size = 0;
 
1915
  char run_tempdir[] = "/run/tmp/mandosXXXXXX";
 
1916
  char old_tempdir[] = "/tmp/mandosXXXXXX";
 
1917
  char *tempdir = NULL;
1532
1918
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1533
1919
  const char *seckey = PATHDIR "/" SECKEY;
1534
1920
  const char *pubkey = PATHDIR "/" PUBKEY;
 
1921
  char *interfaces_hooks = NULL;
1535
1922
  
1536
1923
  bool gnutls_initialized = false;
1537
1924
  bool gpgme_initialized = false;
1599
1986
        .group = 2 },
1600
1987
      { .name = "retry", .key = 132,
1601
1988
        .arg = "SECONDS",
1602
 
        .doc = "Retry interval used when denied by the mandos server",
 
1989
        .doc = "Retry interval used when denied by the Mandos server",
1603
1990
        .group = 2 },
1604
1991
      { .name = "network-hook-dir", .key = 133,
1605
1992
        .arg = "DIR",
1628
2015
        connect_to = arg;
1629
2016
        break;
1630
2017
      case 'i':                 /* --interface */
1631
 
        interface = arg;
 
2018
        ret_errno = argz_add_sep(&mc.interfaces, &mc.interfaces_size,
 
2019
                                 arg, (int)',');
 
2020
        if(ret_errno != 0){
 
2021
          argp_error(state, "%s", strerror(ret_errno));
 
2022
        }
1632
2023
        break;
1633
2024
      case 's':                 /* --seckey */
1634
2025
        seckey = arg;
1711
2102
    /* Work around Debian bug #633582:
1712
2103
       <http://bugs.debian.org/633582> */
1713
2104
    
1714
 
    /* Re-raise priviliges */
1715
 
    errno = 0;
1716
 
    ret = seteuid(0);
1717
 
    if(ret == -1){
1718
 
      perror_plus("seteuid");
 
2105
    /* Re-raise privileges */
 
2106
    ret_errno = raise_privileges();
 
2107
    if(ret_errno != 0){
 
2108
      errno = ret_errno;
 
2109
      perror_plus("Failed to raise privileges");
1719
2110
    } else {
1720
2111
      struct stat st;
1721
2112
      
1762
2153
      }
1763
2154
    
1764
2155
      /* Lower privileges */
1765
 
      errno = 0;
1766
 
      ret = seteuid(uid);
1767
 
      if(ret == -1){
1768
 
        perror_plus("seteuid");
 
2156
      ret_errno = lower_privileges();
 
2157
      if(ret_errno != 0){
 
2158
        errno = ret_errno;
 
2159
        perror_plus("Failed to lower privileges");
 
2160
      }
 
2161
    }
 
2162
  }
 
2163
  
 
2164
  /* Remove invalid interface names (except "none") */
 
2165
  {
 
2166
    char *interface = NULL;
 
2167
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
 
2168
                                 interface))){
 
2169
      if(strcmp(interface, "none") != 0
 
2170
         and if_nametoindex(interface) == 0){
 
2171
        if(interface[0] != '\0'){
 
2172
          fprintf_plus(stderr, "Not using nonexisting interface"
 
2173
                       " \"%s\"\n", interface);
 
2174
        }
 
2175
        argz_delete(&mc.interfaces, &mc.interfaces_size, interface);
 
2176
        interface = NULL;
1769
2177
      }
1770
2178
    }
1771
2179
  }
1772
2180
  
1773
2181
  /* Run network hooks */
1774
 
  if(not run_network_hooks("start", interface, delay)){
1775
 
    goto end;
 
2182
  {
 
2183
    if(mc.interfaces != NULL){
 
2184
      interfaces_hooks = malloc(mc.interfaces_size);
 
2185
      if(interfaces_hooks == NULL){
 
2186
        perror_plus("malloc");
 
2187
        goto end;
 
2188
      }
 
2189
      memcpy(interfaces_hooks, mc.interfaces, mc.interfaces_size);
 
2190
      argz_stringify(interfaces_hooks, mc.interfaces_size, (int)',');
 
2191
    }
 
2192
    run_network_hooks("start", interfaces_hooks != NULL ?
 
2193
                      interfaces_hooks : "", delay);
1776
2194
  }
1777
2195
  
1778
2196
  if(not debug){
1779
2197
    avahi_set_log_function(empty_log);
1780
2198
  }
1781
2199
  
1782
 
  if(interface[0] == '\0'){
1783
 
    struct dirent **direntries;
1784
 
    /* First look for interfaces that are up */
1785
 
    ret = scandir(sys_class_net, &direntries, up_interface,
1786
 
                  alphasort);
1787
 
    if(ret == 0){
1788
 
      /* No up interfaces, look for any good interfaces */
1789
 
      free(direntries);
1790
 
      ret = scandir(sys_class_net, &direntries, good_interface,
1791
 
                    alphasort);
1792
 
    }
1793
 
    if(ret >= 1){
1794
 
      /* Pick the first interface returned */
1795
 
      interface = strdup(direntries[0]->d_name);
1796
 
      if(debug){
1797
 
        fprintf_plus(stderr, "Using interface \"%s\"\n", interface);
1798
 
      }
1799
 
      if(interface == NULL){
1800
 
        perror_plus("malloc");
1801
 
        free(direntries);
1802
 
        exitcode = EXIT_FAILURE;
1803
 
        goto end;
1804
 
      }
1805
 
      free(direntries);
1806
 
    } else {
1807
 
      free(direntries);
1808
 
      fprintf_plus(stderr, "Could not find a network interface\n");
1809
 
      exitcode = EXIT_FAILURE;
1810
 
      goto end;
1811
 
    }
1812
 
  }
1813
 
  
1814
2200
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
1815
2201
     from the signal handler */
1816
2202
  /* Initialize the pseudo-RNG for Avahi */
1817
2203
  srand((unsigned int) time(NULL));
1818
 
  mc.simple_poll = avahi_simple_poll_new();
1819
 
  if(mc.simple_poll == NULL){
 
2204
  simple_poll = avahi_simple_poll_new();
 
2205
  if(simple_poll == NULL){
1820
2206
    fprintf_plus(stderr,
1821
2207
                 "Avahi: Failed to create simple poll object.\n");
1822
2208
    exitcode = EX_UNAVAILABLE;
1886
2272
    }
1887
2273
  }
1888
2274
  
1889
 
  /* If the interface is down, bring it up */
1890
 
  if(strcmp(interface, "none") != 0){
1891
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1892
 
    if(if_index == 0){
1893
 
      fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
1894
 
      exitcode = EX_UNAVAILABLE;
1895
 
      goto end;
1896
 
    }
1897
 
    
1898
 
    if(quit_now){
1899
 
      goto end;
1900
 
    }
1901
 
    
1902
 
    /* Re-raise priviliges */
1903
 
    errno = 0;
1904
 
    ret = seteuid(0);
1905
 
    if(ret == -1){
1906
 
      perror_plus("seteuid");
1907
 
    }
1908
 
    
1909
 
#ifdef __linux__
1910
 
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1911
 
       messages about the network interface to mess up the prompt */
1912
 
    ret = klogctl(8, NULL, 5);
1913
 
    bool restore_loglevel = true;
1914
 
    if(ret == -1){
1915
 
      restore_loglevel = false;
1916
 
      perror_plus("klogctl");
1917
 
    }
1918
 
#endif  /* __linux__ */
1919
 
    
1920
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1921
 
    if(sd < 0){
1922
 
      perror_plus("socket");
1923
 
      exitcode = EX_OSERR;
1924
 
#ifdef __linux__
1925
 
      if(restore_loglevel){
1926
 
        ret = klogctl(7, NULL, 0);
1927
 
        if(ret == -1){
1928
 
          perror_plus("klogctl");
1929
 
        }
1930
 
      }
1931
 
#endif  /* __linux__ */
1932
 
      /* Lower privileges */
1933
 
      errno = 0;
1934
 
      ret = seteuid(uid);
1935
 
      if(ret == -1){
1936
 
        perror_plus("seteuid");
1937
 
      }
1938
 
      goto end;
1939
 
    }
1940
 
    strcpy(network.ifr_name, interface);
1941
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
1942
 
    if(ret == -1){
1943
 
      perror_plus("ioctl SIOCGIFFLAGS");
1944
 
#ifdef __linux__
1945
 
      if(restore_loglevel){
1946
 
        ret = klogctl(7, NULL, 0);
1947
 
        if(ret == -1){
1948
 
          perror_plus("klogctl");
1949
 
        }
1950
 
      }
1951
 
#endif  /* __linux__ */
1952
 
      exitcode = EX_OSERR;
1953
 
      /* Lower privileges */
1954
 
      errno = 0;
1955
 
      ret = seteuid(uid);
1956
 
      if(ret == -1){
1957
 
        perror_plus("seteuid");
1958
 
      }
1959
 
      goto end;
1960
 
    }
1961
 
    if((network.ifr_flags & IFF_UP) == 0){
1962
 
      network.ifr_flags |= IFF_UP;
1963
 
      take_down_interface = true;
1964
 
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
1965
 
      if(ret == -1){
1966
 
        take_down_interface = false;
1967
 
        perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1968
 
        exitcode = EX_OSERR;
1969
 
#ifdef __linux__
1970
 
        if(restore_loglevel){
1971
 
          ret = klogctl(7, NULL, 0);
1972
 
          if(ret == -1){
1973
 
            perror_plus("klogctl");
 
2275
  /* If no interfaces were specified, make a list */
 
2276
  if(mc.interfaces == NULL){
 
2277
    struct dirent **direntries = NULL;
 
2278
    /* Look for any good interfaces */
 
2279
    ret = scandir(sys_class_net, &direntries, good_interface,
 
2280
                  alphasort);
 
2281
    if(ret >= 1){
 
2282
      /* Add all found interfaces to interfaces list */
 
2283
      for(int i = 0; i < ret; ++i){
 
2284
        ret_errno = argz_add(&mc.interfaces, &mc.interfaces_size,
 
2285
                             direntries[i]->d_name);
 
2286
        if(ret_errno != 0){
 
2287
          errno = ret_errno;
 
2288
          perror_plus("argz_add");
 
2289
          free(direntries[i]);
 
2290
          continue;
 
2291
        }
 
2292
        if(debug){
 
2293
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
 
2294
                       direntries[i]->d_name);
 
2295
        }
 
2296
        free(direntries[i]);
 
2297
      }
 
2298
      free(direntries);
 
2299
    } else {
 
2300
      if(ret == 0){
 
2301
        free(direntries);
 
2302
      }
 
2303
      fprintf_plus(stderr, "Could not find a network interface\n");
 
2304
      exitcode = EXIT_FAILURE;
 
2305
      goto end;
 
2306
    }
 
2307
  }
 
2308
  
 
2309
  /* Bring up interfaces which are down, and remove any "none"s */
 
2310
  {
 
2311
    char *interface = NULL;
 
2312
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
 
2313
                                 interface))){
 
2314
      /* If interface name is "none", stop bringing up interfaces.
 
2315
         Also remove all instances of "none" from the list */
 
2316
      if(strcmp(interface, "none") == 0){
 
2317
        argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2318
                    interface);
 
2319
        interface = NULL;
 
2320
        while((interface = argz_next(mc.interfaces,
 
2321
                                     mc.interfaces_size, interface))){
 
2322
          if(strcmp(interface, "none") == 0){
 
2323
            argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2324
                        interface);
 
2325
            interface = NULL;
1974
2326
          }
1975
2327
        }
1976
 
#endif  /* __linux__ */
1977
 
        /* Lower privileges */
1978
 
        errno = 0;
1979
 
        ret = seteuid(uid);
1980
 
        if(ret == -1){
1981
 
          perror_plus("seteuid");
1982
 
        }
1983
 
        goto end;
1984
 
      }
1985
 
    }
1986
 
    /* Sleep checking until interface is running.
1987
 
       Check every 0.25s, up to total time of delay */
1988
 
    for(int i=0; i < delay * 4; i++){
1989
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1990
 
      if(ret == -1){
1991
 
        perror_plus("ioctl SIOCGIFFLAGS");
1992
 
      } else if(network.ifr_flags & IFF_RUNNING){
1993
2328
        break;
1994
2329
      }
1995
 
      struct timespec sleeptime = { .tv_nsec = 250000000 };
1996
 
      ret = nanosleep(&sleeptime, NULL);
1997
 
      if(ret == -1 and errno != EINTR){
1998
 
        perror_plus("nanosleep");
1999
 
      }
2000
 
    }
2001
 
    if(not take_down_interface){
2002
 
      /* We won't need the socket anymore */
2003
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
2004
 
      if(ret == -1){
2005
 
        perror_plus("close");
2006
 
      }
2007
 
    }
2008
 
#ifdef __linux__
2009
 
    if(restore_loglevel){
2010
 
      /* Restores kernel loglevel to default */
2011
 
      ret = klogctl(7, NULL, 0);
2012
 
      if(ret == -1){
2013
 
        perror_plus("klogctl");
2014
 
      }
2015
 
    }
2016
 
#endif  /* __linux__ */
2017
 
    /* Lower privileges */
2018
 
    errno = 0;
2019
 
    /* Lower privileges */
2020
 
    ret = seteuid(uid);
2021
 
    if(ret == -1){
2022
 
      perror_plus("seteuid");
2023
 
    }
 
2330
      bool interface_was_up = interface_is_up(interface);
 
2331
      errno = bring_up_interface(interface, delay);
 
2332
      if(not interface_was_up){
 
2333
        if(errno != 0){
 
2334
          perror_plus("Failed to bring up interface");
 
2335
        } else {
 
2336
          errno = argz_add(&interfaces_to_take_down,
 
2337
                           &interfaces_to_take_down_size,
 
2338
                           interface);
 
2339
          if(errno != 0){
 
2340
            perror_plus("argz_add");
 
2341
          }
 
2342
        }
 
2343
      }
 
2344
    }
 
2345
    if(debug and (interfaces_to_take_down == NULL)){
 
2346
      fprintf_plus(stderr, "No interfaces were brought up\n");
 
2347
    }
 
2348
  }
 
2349
  
 
2350
  /* If we only got one interface, explicitly use only that one */
 
2351
  if(argz_count(mc.interfaces, mc.interfaces_size) == 1){
 
2352
    if(debug){
 
2353
      fprintf_plus(stderr, "Using only interface \"%s\"\n",
 
2354
                   mc.interfaces);
 
2355
    }
 
2356
    if_index = (AvahiIfIndex)if_nametoindex(mc.interfaces);
2024
2357
  }
2025
2358
  
2026
2359
  if(quit_now){
2027
2360
    goto end;
2028
2361
  }
2029
2362
  
2030
 
  ret = init_gnutls_global(pubkey, seckey);
 
2363
  ret = init_gnutls_global(pubkey, seckey, &mc);
2031
2364
  if(ret == -1){
2032
2365
    fprintf_plus(stderr, "init_gnutls_global failed\n");
2033
2366
    exitcode = EX_UNAVAILABLE;
2040
2373
    goto end;
2041
2374
  }
2042
2375
  
2043
 
  if(mkdtemp(tempdir) == NULL){
 
2376
  /* Try /run/tmp before /tmp */
 
2377
  tempdir = mkdtemp(run_tempdir);
 
2378
  if(tempdir == NULL and errno == ENOENT){
 
2379
      if(debug){
 
2380
        fprintf_plus(stderr, "Tempdir %s did not work, trying %s\n",
 
2381
                     run_tempdir, old_tempdir);
 
2382
      }
 
2383
      tempdir = mkdtemp(old_tempdir);
 
2384
  }
 
2385
  if(tempdir == NULL){
2044
2386
    perror_plus("mkdtemp");
2045
2387
    goto end;
2046
2388
  }
2047
 
  tempdir_created = true;
2048
2389
  
2049
2390
  if(quit_now){
2050
2391
    goto end;
2051
2392
  }
2052
2393
  
2053
 
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
2394
  if(not init_gpgme(pubkey, seckey, tempdir, &mc)){
2054
2395
    fprintf_plus(stderr, "init_gpgme failed\n");
2055
2396
    exitcode = EX_UNAVAILABLE;
2056
2397
    goto end;
2066
2407
    /* Connect directly, do not use Zeroconf */
2067
2408
    /* (Mainly meant for debugging) */
2068
2409
    char *address = strrchr(connect_to, ':');
 
2410
    
2069
2411
    if(address == NULL){
2070
2412
      fprintf_plus(stderr, "No colon in address\n");
2071
2413
      exitcode = EX_USAGE;
2076
2418
      goto end;
2077
2419
    }
2078
2420
    
2079
 
    uint16_t port;
 
2421
    in_port_t port;
2080
2422
    errno = 0;
2081
2423
    tmpmax = strtoimax(address+1, &tmp, 10);
2082
2424
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
2083
 
       or tmpmax != (uint16_t)tmpmax){
 
2425
       or tmpmax != (in_port_t)tmpmax){
2084
2426
      fprintf_plus(stderr, "Bad port number\n");
2085
2427
      exitcode = EX_USAGE;
2086
2428
      goto end;
2087
2429
    }
2088
 
  
 
2430
    
2089
2431
    if(quit_now){
2090
2432
      goto end;
2091
2433
    }
2092
2434
    
2093
 
    port = (uint16_t)tmpmax;
 
2435
    port = (in_port_t)tmpmax;
2094
2436
    *address = '\0';
2095
2437
    /* Colon in address indicates IPv6 */
2096
2438
    int af;
2112
2454
    }
2113
2455
    
2114
2456
    while(not quit_now){
2115
 
      ret = start_mandos_communication(address, port, if_index, af);
 
2457
      ret = start_mandos_communication(address, port, if_index, af,
 
2458
                                       &mc);
2116
2459
      if(quit_now or ret == 0){
2117
2460
        break;
2118
2461
      }
2120
2463
        fprintf_plus(stderr, "Retrying in %d seconds\n",
2121
2464
                     (int)retry_interval);
2122
2465
      }
2123
 
      sleep((int)retry_interval);
 
2466
      sleep((unsigned int)retry_interval);
2124
2467
    }
2125
2468
    
2126
 
    if (not quit_now){
 
2469
    if(not quit_now){
2127
2470
      exitcode = EXIT_SUCCESS;
2128
2471
    }
2129
2472
    
2144
2487
    config.publish_domain = 0;
2145
2488
    
2146
2489
    /* Allocate a new server */
2147
 
    mc.server = avahi_server_new(avahi_simple_poll_get
2148
 
                                 (mc.simple_poll), &config, NULL,
2149
 
                                 NULL, &error);
 
2490
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
2491
                                 &config, NULL, NULL, &ret_errno);
2150
2492
    
2151
2493
    /* Free the Avahi configuration data */
2152
2494
    avahi_server_config_free(&config);
2155
2497
  /* Check if creating the Avahi server object succeeded */
2156
2498
  if(mc.server == NULL){
2157
2499
    fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
2158
 
                 avahi_strerror(error));
 
2500
                 avahi_strerror(ret_errno));
2159
2501
    exitcode = EX_UNAVAILABLE;
2160
2502
    goto end;
2161
2503
  }
2167
2509
  /* Create the Avahi service browser */
2168
2510
  sb = avahi_s_service_browser_new(mc.server, if_index,
2169
2511
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
2170
 
                                   NULL, 0, browse_callback, NULL);
 
2512
                                   NULL, 0, browse_callback,
 
2513
                                   (void *)&mc);
2171
2514
  if(sb == NULL){
2172
2515
    fprintf_plus(stderr, "Failed to create service browser: %s\n",
2173
2516
                 avahi_strerror(avahi_server_errno(mc.server)));
2184
2527
  if(debug){
2185
2528
    fprintf_plus(stderr, "Starting Avahi loop search\n");
2186
2529
  }
2187
 
 
2188
 
  ret = avahi_loop_with_timeout(mc.simple_poll,
2189
 
                                (int)(retry_interval * 1000));
 
2530
  
 
2531
  ret = avahi_loop_with_timeout(simple_poll,
 
2532
                                (int)(retry_interval * 1000), &mc);
2190
2533
  if(debug){
2191
2534
    fprintf_plus(stderr, "avahi_loop_with_timeout exited %s\n",
2192
2535
                 (ret == 0) ? "successfully" : "with error");
2199
2542
  }
2200
2543
  
2201
2544
  /* Cleanup things */
 
2545
  free(mc.interfaces);
 
2546
  
2202
2547
  if(sb != NULL)
2203
2548
    avahi_s_service_browser_free(sb);
2204
2549
  
2205
2550
  if(mc.server != NULL)
2206
2551
    avahi_server_free(mc.server);
2207
2552
  
2208
 
  if(mc.simple_poll != NULL)
2209
 
    avahi_simple_poll_free(mc.simple_poll);
 
2553
  if(simple_poll != NULL)
 
2554
    avahi_simple_poll_free(simple_poll);
2210
2555
  
2211
2556
  if(gnutls_initialized){
2212
2557
    gnutls_certificate_free_credentials(mc.cred);
2224
2569
    mc.current_server->prev->next = NULL;
2225
2570
    while(mc.current_server != NULL){
2226
2571
      server *next = mc.current_server->next;
 
2572
#ifdef __GNUC__
 
2573
#pragma GCC diagnostic push
 
2574
#pragma GCC diagnostic ignored "-Wcast-qual"
 
2575
#endif
 
2576
      free((char *)(mc.current_server->ip));
 
2577
#ifdef __GNUC__
 
2578
#pragma GCC diagnostic pop
 
2579
#endif
2227
2580
      free(mc.current_server);
2228
2581
      mc.current_server = next;
2229
2582
    }
2230
2583
  }
2231
2584
  
2232
 
  /* Run network hooks */
2233
 
  run_network_hooks("stop", interface, delay);
2234
 
  
2235
 
  /* Re-raise priviliges */
 
2585
  /* Re-raise privileges */
2236
2586
  {
2237
 
    errno = 0;
2238
 
    ret = seteuid(0);
2239
 
    if(ret == -1){
2240
 
      perror_plus("seteuid");
 
2587
    ret_errno = raise_privileges();
 
2588
    if(ret_errno != 0){
 
2589
      errno = ret_errno;
 
2590
      perror_plus("Failed to raise privileges");
 
2591
    } else {
 
2592
      
 
2593
      /* Run network hooks */
 
2594
      run_network_hooks("stop", interfaces_hooks != NULL ?
 
2595
                        interfaces_hooks : "", delay);
 
2596
      
 
2597
      /* Take down the network interfaces which were brought up */
 
2598
      {
 
2599
        char *interface = NULL;
 
2600
        while((interface=argz_next(interfaces_to_take_down,
 
2601
                                   interfaces_to_take_down_size,
 
2602
                                   interface))){
 
2603
          ret_errno = take_down_interface(interface);
 
2604
          if(ret_errno != 0){
 
2605
            errno = ret_errno;
 
2606
            perror_plus("Failed to take down interface");
 
2607
          }
 
2608
        }
 
2609
        if(debug and (interfaces_to_take_down == NULL)){
 
2610
          fprintf_plus(stderr, "No interfaces needed to be taken"
 
2611
                       " down\n");
 
2612
        }
 
2613
      }
2241
2614
    }
2242
2615
    
2243
 
    /* Take down the network interface */
2244
 
    if(take_down_interface and geteuid() == 0){
2245
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
2246
 
      if(ret == -1){
2247
 
        perror_plus("ioctl SIOCGIFFLAGS");
2248
 
      } else if(network.ifr_flags & IFF_UP){
2249
 
        network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
2250
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
2251
 
        if(ret == -1){
2252
 
          perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
2253
 
        }
2254
 
      }
2255
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
2256
 
      if(ret == -1){
2257
 
        perror_plus("close");
2258
 
      }
 
2616
    ret_errno = lower_privileges_permanently();
 
2617
    if(ret_errno != 0){
 
2618
      errno = ret_errno;
 
2619
      perror_plus("Failed to lower privileges permanently");
2259
2620
    }
2260
2621
  }
2261
 
  /* Lower privileges permanently */
2262
 
  errno = 0;
2263
 
  ret = setuid(uid);
2264
 
  if(ret == -1){
2265
 
    perror_plus("setuid");
2266
 
  }
 
2622
  
 
2623
  free(interfaces_to_take_down);
 
2624
  free(interfaces_hooks);
2267
2625
  
2268
2626
  /* Removes the GPGME temp directory and all files inside */
2269
 
  if(tempdir_created){
 
2627
  if(tempdir != NULL){
2270
2628
    struct dirent **direntries = NULL;
2271
 
    struct dirent *direntry = NULL;
2272
 
    int numentries = scandir(tempdir, &direntries, notdotentries,
2273
 
                             alphasort);
2274
 
    if (numentries > 0){
2275
 
      for(int i = 0; i < numentries; i++){
2276
 
        direntry = direntries[i];
2277
 
        char *fullname = NULL;
2278
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
2279
 
                       direntry->d_name);
2280
 
        if(ret < 0){
2281
 
          perror_plus("asprintf");
2282
 
          continue;
2283
 
        }
2284
 
        ret = remove(fullname);
2285
 
        if(ret == -1){
2286
 
          fprintf_plus(stderr, "remove(\"%s\"): %s\n", fullname,
2287
 
                       strerror(errno));
2288
 
        }
2289
 
        free(fullname);
 
2629
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY |
 
2630
                                                  O_NOFOLLOW));
 
2631
    if(tempdir_fd == -1){
 
2632
      perror_plus("open");
 
2633
    } else {
 
2634
#ifdef __GLIBC__
 
2635
#if __GLIBC_PREREQ(2, 15)
 
2636
      int numentries = scandirat(tempdir_fd, ".", &direntries,
 
2637
                                 notdotentries, alphasort);
 
2638
#else  /* not __GLIBC_PREREQ(2, 15) */
 
2639
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2640
                               alphasort);
 
2641
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
2642
#else   /* not __GLIBC__ */
 
2643
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2644
                               alphasort);
 
2645
#endif  /* not __GLIBC__ */
 
2646
      if(numentries >= 0){
 
2647
        for(int i = 0; i < numentries; i++){
 
2648
          ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
 
2649
          if(ret == -1){
 
2650
            fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
 
2651
                         " \"%s\", 0): %s\n", tempdir,
 
2652
                         direntries[i]->d_name, strerror(errno));
 
2653
          }
 
2654
          free(direntries[i]);
 
2655
        }
 
2656
        
 
2657
        /* need to clean even if 0 because man page doesn't specify */
 
2658
        free(direntries);
 
2659
        if(numentries == -1){
 
2660
          perror_plus("scandir");
 
2661
        }
 
2662
        ret = rmdir(tempdir);
 
2663
        if(ret == -1 and errno != ENOENT){
 
2664
          perror_plus("rmdir");
 
2665
        }
2290
2666
      }
2291
 
    }
2292
 
 
2293
 
    /* need to clean even if 0 because man page doesn't specify */
2294
 
    free(direntries);
2295
 
    if (numentries == -1){
2296
 
      perror_plus("scandir");
2297
 
    }
2298
 
    ret = rmdir(tempdir);
2299
 
    if(ret == -1 and errno != ENOENT){
2300
 
      perror_plus("rmdir");
 
2667
      TEMP_FAILURE_RETRY(close(tempdir_fd));
2301
2668
    }
2302
2669
  }
2303
2670