/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: 2014-07-25 22:44:20 UTC
  • mto: This revision was merged to the branch mainline in revision 724.
  • Revision ID: teddy@recompile.se-20140725224420-4a5ct2ptt0hsc92z
Require Python 2.7.

This is in preparation for the eventual move to Python 3, which will
happen as soon as all Python modules required by Mandos are available.
The mandos-ctl and mandos-monitor programs are already portable
between Python 2.6 and Python 3 without changes; this change will
bring the requirement up to Python 2.7.

* INSTALL (Prerequisites/Libraries/Mandos Server): Document
                                                   requirement of
                                                   Python 2.7; remove
                                                   Python-argparse
                                                   which is in the
                                                   Python 2.7 standard
                                                   library.
* debian/control (Source: mandos/Build-Depends-Indep): Depend on
                                                       exactly the
                                                       python2.7
                                                       package and all
                                                       the Python 2.7
                                                       versions of the
                                                       python modules.
  (Package: mandos/Depends): - '' - but still depend on python (<=2.7)
                            and the generic versions of the Python
                            modules; this is for mandos-ctl and
                            mandos-monitor, both of which are
                            compatible with Python 3, and use
                            #!/usr/bin/python.
* mandos: Use #!/usr/bin/python2.7 instead of #!/usr/bin/python.

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-2012 Teddy Hogeborn
13
 
 * Copyright © 2008-2012 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() */
 
43
                                   stdout, ferror() */
44
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(),
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,
72
73
                                */
73
74
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
74
75
                                   getuid(), getgid(), seteuid(),
75
 
                                   setgid(), pause(), _exit() */
76
 
#include <arpa/inet.h>          /* inet_pton(), htons, inet_ntop() */
 
76
                                   setgid(), pause(), _exit(),
 
77
                                   unlinkat() */
 
78
#include <arpa/inet.h>          /* inet_pton(), htons() */
77
79
#include <iso646.h>             /* not, or, and */
78
80
#include <argp.h>               /* struct argp_option, error_t, struct
79
81
                                   argp_state, struct argp,
91
93
                                   argz_delete(), argz_append(),
92
94
                                   argz_stringify(), argz_add(),
93
95
                                   argz_count() */
 
96
#include <netdb.h>              /* getnameinfo(), NI_NUMERICHOST,
 
97
                                   EAI_SYSTEM, gai_strerror() */
94
98
 
95
99
#ifdef __linux__
96
100
#include <sys/klog.h>           /* klogctl() */
138
142
static const char sys_class_net[] = "/sys/class/net";
139
143
char *connect_to = NULL;
140
144
const char *hookdir = HOOKDIR;
 
145
int hookdir_fd = -1;
141
146
uid_t uid = 65534;
142
147
gid_t gid = 65534;
143
148
 
154
159
 
155
160
/* Used for passing in values through the Avahi callback functions */
156
161
typedef struct {
157
 
  AvahiSimplePoll *simple_poll;
158
162
  AvahiServer *server;
159
163
  gnutls_certificate_credentials_t cred;
160
164
  unsigned int dh_bits;
162
166
  const char *priority;
163
167
  gpgme_ctx_t ctx;
164
168
  server *current_server;
 
169
  char *interfaces;
 
170
  size_t interfaces_size;
165
171
} mandos_context;
166
172
 
167
 
/* global context so signal handler can reach it*/
168
 
mandos_context mc = { .simple_poll = NULL, .server = NULL,
169
 
                      .dh_bits = 1024, .priority = "SECURE256"
170
 
                      ":!CTYPE-X.509:+CTYPE-OPENPGP",
171
 
                      .current_server = NULL };
 
173
/* global so signal handler can reach it*/
 
174
AvahiSimplePoll *simple_poll;
172
175
 
173
176
sig_atomic_t quit_now = 0;
174
177
int signal_received = 0;
182
185
  perror(print_text);
183
186
}
184
187
 
185
 
__attribute__((format (gnu_printf, 2, 3)))
 
188
__attribute__((format (gnu_printf, 2, 3), nonnull))
186
189
int fprintf_plus(FILE *stream, const char *format, ...){
187
190
  va_list ap;
188
191
  va_start (ap, format);
189
192
  
190
193
  TEMP_FAILURE_RETRY(fprintf(stream, "Mandos plugin %s: ",
191
194
                             program_invocation_short_name));
192
 
  return TEMP_FAILURE_RETRY(vfprintf(stream, format, ap));
 
195
  return (int)TEMP_FAILURE_RETRY(vfprintf(stream, format, ap));
193
196
}
194
197
 
195
198
/*
197
200
 * bytes. "buffer_capacity" is how much is currently allocated,
198
201
 * "buffer_length" is how much is already used.
199
202
 */
 
203
__attribute__((nonnull, warn_unused_result))
200
204
size_t incbuffer(char **buffer, size_t buffer_length,
201
205
                 size_t buffer_capacity){
202
206
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
203
 
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
204
 
    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;
205
213
      return 0;
206
214
    }
 
215
    *buffer = new_buf;
207
216
    buffer_capacity += BUFFER_SIZE;
208
217
  }
209
218
  return buffer_capacity;
210
219
}
211
220
 
212
221
/* Add server to set of servers to retry periodically */
 
222
__attribute__((nonnull, warn_unused_result))
213
223
bool add_server(const char *ip, in_port_t port, AvahiIfIndex if_index,
214
 
                int af){
 
224
                int af, server **current_server){
215
225
  int ret;
216
226
  server *new_server = malloc(sizeof(server));
217
227
  if(new_server == NULL){
224
234
                          .af = af };
225
235
  if(new_server->ip == NULL){
226
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);
227
252
    return false;
228
253
  }
229
254
  /* Special case of first server */
230
 
  if (mc.current_server == NULL){
 
255
  if(*current_server == NULL){
231
256
    new_server->next = new_server;
232
257
    new_server->prev = new_server;
233
 
    mc.current_server = new_server;
234
 
  /* Place the new server last in the list */
 
258
    *current_server = new_server;
235
259
  } else {
236
 
    new_server->next = mc.current_server;
237
 
    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;
238
263
    new_server->prev->next = new_server;
239
 
    mc.current_server->prev = new_server;
240
 
  }
241
 
  ret = clock_gettime(CLOCK_MONOTONIC, &mc.current_server->last_seen);
242
 
  if(ret == -1){
243
 
    perror_plus("clock_gettime");
244
 
    return false;
 
264
    (*current_server)->prev = new_server;
245
265
  }
246
266
  return true;
247
267
}
249
269
/* 
250
270
 * Initialize GPGME.
251
271
 */
252
 
static bool init_gpgme(const char *seckey, const char *pubkey,
253
 
                       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){
254
277
  gpgme_error_t rc;
255
278
  gpgme_engine_info_t engine_info;
256
279
  
257
 
  
258
280
  /*
259
281
   * Helper function to insert pub and seckey to the engine keyring.
260
282
   */
261
 
  bool import_key(const char *filename){
 
283
  bool import_key(const char * const filename){
262
284
    int ret;
263
285
    int fd;
264
286
    gpgme_data_t pgp_data;
276
298
      return false;
277
299
    }
278
300
    
279
 
    rc = gpgme_op_import(mc.ctx, pgp_data);
 
301
    rc = gpgme_op_import(mc->ctx, pgp_data);
280
302
    if(rc != GPG_ERR_NO_ERROR){
281
303
      fprintf_plus(stderr, "bad gpgme_op_import: %s: %s\n",
282
304
                   gpgme_strsource(rc), gpgme_strerror(rc));
326
348
  }
327
349
  
328
350
  /* Create new GPGME "context" */
329
 
  rc = gpgme_new(&(mc.ctx));
 
351
  rc = gpgme_new(&(mc->ctx));
330
352
  if(rc != GPG_ERR_NO_ERROR){
331
353
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
332
354
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
345
367
 * Decrypt OpenPGP data.
346
368
 * Returns -1 on error
347
369
 */
 
370
__attribute__((nonnull, warn_unused_result))
348
371
static ssize_t pgp_packet_decrypt(const char *cryptotext,
349
372
                                  size_t crypto_size,
350
 
                                  char **plaintext){
 
373
                                  char **plaintext,
 
374
                                  mandos_context *mc){
351
375
  gpgme_data_t dh_crypto, dh_plain;
352
376
  gpgme_error_t rc;
353
377
  ssize_t ret;
379
403
  
380
404
  /* Decrypt data from the cryptotext data buffer to the plaintext
381
405
     data buffer */
382
 
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
406
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
383
407
  if(rc != GPG_ERR_NO_ERROR){
384
408
    fprintf_plus(stderr, "bad gpgme_op_decrypt: %s: %s\n",
385
409
                 gpgme_strsource(rc), gpgme_strerror(rc));
386
410
    plaintext_length = -1;
387
411
    if(debug){
388
412
      gpgme_decrypt_result_t result;
389
 
      result = gpgme_op_decrypt_result(mc.ctx);
 
413
      result = gpgme_op_decrypt_result(mc->ctx);
390
414
      if(result == NULL){
391
415
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
392
416
      } else {
469
493
  return plaintext_length;
470
494
}
471
495
 
472
 
static const char * safer_gnutls_strerror(int value){
 
496
__attribute__((warn_unused_result))
 
497
static const char *safer_gnutls_strerror(int value){
473
498
  const char *ret = gnutls_strerror(value);
474
499
  if(ret == NULL)
475
500
    ret = "(unknown)";
477
502
}
478
503
 
479
504
/* GnuTLS log function callback */
 
505
__attribute__((nonnull))
480
506
static void debuggnutls(__attribute__((unused)) int level,
481
507
                        const char* string){
482
508
  fprintf_plus(stderr, "GnuTLS: %s", string);
483
509
}
484
510
 
 
511
__attribute__((nonnull, warn_unused_result))
485
512
static int init_gnutls_global(const char *pubkeyfilename,
486
 
                              const char *seckeyfilename){
 
513
                              const char *seckeyfilename,
 
514
                              mandos_context *mc){
487
515
  int ret;
488
516
  
489
517
  if(debug){
506
534
  }
507
535
  
508
536
  /* OpenPGP credentials */
509
 
  ret = gnutls_certificate_allocate_credentials(&mc.cred);
 
537
  ret = gnutls_certificate_allocate_credentials(&mc->cred);
510
538
  if(ret != GNUTLS_E_SUCCESS){
511
539
    fprintf_plus(stderr, "GnuTLS memory error: %s\n",
512
540
                 safer_gnutls_strerror(ret));
522
550
  }
523
551
  
524
552
  ret = gnutls_certificate_set_openpgp_key_file
525
 
    (mc.cred, pubkeyfilename, seckeyfilename,
 
553
    (mc->cred, pubkeyfilename, seckeyfilename,
526
554
     GNUTLS_OPENPGP_FMT_BASE64);
527
555
  if(ret != GNUTLS_E_SUCCESS){
528
556
    fprintf_plus(stderr,
534
562
  }
535
563
  
536
564
  /* GnuTLS server initialization */
537
 
  ret = gnutls_dh_params_init(&mc.dh_params);
 
565
  ret = gnutls_dh_params_init(&mc->dh_params);
538
566
  if(ret != GNUTLS_E_SUCCESS){
539
567
    fprintf_plus(stderr, "Error in GnuTLS DH parameter"
540
568
                 " initialization: %s\n",
541
569
                 safer_gnutls_strerror(ret));
542
570
    goto globalfail;
543
571
  }
544
 
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
572
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
545
573
  if(ret != GNUTLS_E_SUCCESS){
546
574
    fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
547
575
                 safer_gnutls_strerror(ret));
548
576
    goto globalfail;
549
577
  }
550
578
  
551
 
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
579
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
552
580
  
553
581
  return 0;
554
582
  
555
583
 globalfail:
556
584
  
557
 
  gnutls_certificate_free_credentials(mc.cred);
 
585
  gnutls_certificate_free_credentials(mc->cred);
558
586
  gnutls_global_deinit();
559
 
  gnutls_dh_params_deinit(mc.dh_params);
 
587
  gnutls_dh_params_deinit(mc->dh_params);
560
588
  return -1;
561
589
}
562
590
 
563
 
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){
564
594
  int ret;
565
595
  /* GnuTLS session creation */
566
596
  do {
578
608
  {
579
609
    const char *err;
580
610
    do {
581
 
      ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
611
      ret = gnutls_priority_set_direct(*session, mc->priority, &err);
582
612
      if(quit_now){
583
613
        gnutls_deinit(*session);
584
614
        return -1;
595
625
  
596
626
  do {
597
627
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
598
 
                                 mc.cred);
 
628
                                 mc->cred);
599
629
    if(quit_now){
600
630
      gnutls_deinit(*session);
601
631
      return -1;
611
641
  /* ignore client certificate if any. */
612
642
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
613
643
  
614
 
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
 
644
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
615
645
  
616
646
  return 0;
617
647
}
621
651
                      __attribute__((unused)) const char *txt){}
622
652
 
623
653
/* Called when a Mandos server is found */
 
654
__attribute__((nonnull, warn_unused_result))
624
655
static int start_mandos_communication(const char *ip, in_port_t port,
625
656
                                      AvahiIfIndex if_index,
626
 
                                      int af){
 
657
                                      int af, mandos_context *mc){
627
658
  int ret, tcp_sd = -1;
628
659
  ssize_t sret;
629
 
  union {
630
 
    struct sockaddr_in in;
631
 
    struct sockaddr_in6 in6;
632
 
  } to;
 
660
  struct sockaddr_storage to;
633
661
  char *buffer = NULL;
634
662
  char *decrypted_buffer = NULL;
635
663
  size_t buffer_length = 0;
659
687
    return -1;
660
688
  }
661
689
  
662
 
  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);
663
723
  if(ret != 0){
664
724
    return -1;
665
725
  }
684
744
  
685
745
  memset(&to, 0, sizeof(to));
686
746
  if(af == AF_INET6){
687
 
    to.in6.sin6_family = (sa_family_t)af;
688
 
    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);
689
749
  } else {                      /* IPv4 */
690
 
    to.in.sin_family = (sa_family_t)af;
691
 
    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);
692
752
  }
693
753
  if(ret < 0 ){
694
754
    int e = errno;
703
763
    goto mandos_end;
704
764
  }
705
765
  if(af == AF_INET6){
706
 
    to.in6.sin6_port = htons(port);    
707
 
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
708
 
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
709
 
                                -Wunreachable-code*/
 
766
    ((struct sockaddr_in6 *)&to)->sin6_port = htons(port);
 
767
    if(IN6_IS_ADDR_LINKLOCAL
 
768
       (&((struct sockaddr_in6 *)&to)->sin6_addr)){
710
769
      if(if_index == AVAHI_IF_UNSPEC){
711
770
        fprintf_plus(stderr, "An IPv6 link-local address is"
712
771
                     " incomplete without a network interface\n");
714
773
        goto mandos_end;
715
774
      }
716
775
      /* Set the network interface number as scope */
717
 
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
776
      ((struct sockaddr_in6 *)&to)->sin6_scope_id = (uint32_t)if_index;
718
777
    }
719
778
  } else {
720
 
    to.in.sin_port = htons(port); /* Spurious warnings from
721
 
                                     -Wconversion and
722
 
                                     -Wunreachable-code */
 
779
    ((struct sockaddr_in *)&to)->sin_port = htons(port);
723
780
  }
724
781
  
725
782
  if(quit_now){
742
799
    }
743
800
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
744
801
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
745
 
    const char *pcret;
746
802
    if(af == AF_INET6){
747
 
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
748
 
                        sizeof(addrstr));
 
803
      ret = getnameinfo((struct sockaddr *)&to,
 
804
                        sizeof(struct sockaddr_in6),
 
805
                        addrstr, sizeof(addrstr), NULL, 0,
 
806
                        NI_NUMERICHOST);
749
807
    } else {
750
 
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
751
 
                        sizeof(addrstr));
 
808
      ret = getnameinfo((struct sockaddr *)&to,
 
809
                        sizeof(struct sockaddr_in),
 
810
                        addrstr, sizeof(addrstr), NULL, 0,
 
811
                        NI_NUMERICHOST);
752
812
    }
753
 
    if(pcret == NULL){
754
 
      perror_plus("inet_ntop");
755
 
    } else {
756
 
      if(strcmp(addrstr, ip) != 0){
757
 
        fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
758
 
      }
 
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);
759
819
    }
760
820
  }
761
821
  
765
825
  }
766
826
  
767
827
  if(af == AF_INET6){
768
 
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
828
    ret = connect(tcp_sd, (struct sockaddr *)&to,
 
829
                  sizeof(struct sockaddr_in6));
769
830
  } else {
770
 
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
831
    ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
832
                  sizeof(struct sockaddr_in));
771
833
  }
772
834
  if(ret < 0){
773
 
    if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
835
    if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
774
836
      int e = errno;
775
837
      perror_plus("connect");
776
838
      errno = e;
937
999
  if(buffer_length > 0){
938
1000
    ssize_t decrypted_buffer_size;
939
1001
    decrypted_buffer_size = pgp_packet_decrypt(buffer, buffer_length,
940
 
                                               &decrypted_buffer);
 
1002
                                               &decrypted_buffer, mc);
941
1003
    if(decrypted_buffer_size >= 0){
942
1004
      
943
1005
      written = 0;
991
1053
  return retval;
992
1054
}
993
1055
 
 
1056
__attribute__((nonnull))
994
1057
static void resolve_callback(AvahiSServiceResolver *r,
995
1058
                             AvahiIfIndex interface,
996
1059
                             AvahiProtocol proto,
1004
1067
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
1005
1068
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
1006
1069
                             flags,
1007
 
                             AVAHI_GCC_UNUSED void* userdata){
 
1070
                             void *mc){
1008
1071
  if(r == NULL){
1009
1072
    return;
1010
1073
  }
1013
1076
     timed out */
1014
1077
  
1015
1078
  if(quit_now){
 
1079
    avahi_s_service_resolver_free(r);
1016
1080
    return;
1017
1081
  }
1018
1082
  
1022
1086
    fprintf_plus(stderr, "(Avahi Resolver) Failed to resolve service "
1023
1087
                 "'%s' of type '%s' in domain '%s': %s\n", name, type,
1024
1088
                 domain,
1025
 
                 avahi_strerror(avahi_server_errno(mc.server)));
 
1089
                 avahi_strerror(avahi_server_errno
 
1090
                                (((mandos_context*)mc)->server)));
1026
1091
    break;
1027
1092
    
1028
1093
  case AVAHI_RESOLVER_FOUND:
1036
1101
      }
1037
1102
      int ret = start_mandos_communication(ip, (in_port_t)port,
1038
1103
                                           interface,
1039
 
                                           avahi_proto_to_af(proto));
 
1104
                                           avahi_proto_to_af(proto),
 
1105
                                           mc);
1040
1106
      if(ret == 0){
1041
 
        avahi_simple_poll_quit(mc.simple_poll);
 
1107
        avahi_simple_poll_quit(simple_poll);
1042
1108
      } else {
1043
1109
        if(not add_server(ip, (in_port_t)port, interface,
1044
 
                          avahi_proto_to_af(proto))){
 
1110
                          avahi_proto_to_af(proto),
 
1111
                          &((mandos_context*)mc)->current_server)){
1045
1112
          fprintf_plus(stderr, "Failed to add server \"%s\" to server"
1046
1113
                       " list\n", name);
1047
1114
        }
1060
1127
                            const char *domain,
1061
1128
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
1062
1129
                            flags,
1063
 
                            AVAHI_GCC_UNUSED void* userdata){
 
1130
                            void *mc){
1064
1131
  if(b == NULL){
1065
1132
    return;
1066
1133
  }
1077
1144
  case AVAHI_BROWSER_FAILURE:
1078
1145
    
1079
1146
    fprintf_plus(stderr, "(Avahi browser) %s\n",
1080
 
                 avahi_strerror(avahi_server_errno(mc.server)));
1081
 
    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);
1082
1150
    return;
1083
1151
    
1084
1152
  case AVAHI_BROWSER_NEW:
1087
1155
       the callback function is called the Avahi server will free the
1088
1156
       resolver for us. */
1089
1157
    
1090
 
    if(avahi_s_service_resolver_new(mc.server, interface, protocol,
1091
 
                                    name, type, domain, protocol, 0,
1092
 
                                    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)
1093
1162
      fprintf_plus(stderr, "Avahi: Failed to resolve service '%s':"
1094
1163
                   " %s\n", name,
1095
 
                   avahi_strerror(avahi_server_errno(mc.server)));
 
1164
                   avahi_strerror(avahi_server_errno
 
1165
                                  (((mandos_context*)mc)->server)));
1096
1166
    break;
1097
1167
    
1098
1168
  case AVAHI_BROWSER_REMOVE:
1117
1187
  signal_received = sig;
1118
1188
  int old_errno = errno;
1119
1189
  /* set main loop to exit */
1120
 
  if(mc.simple_poll != NULL){
1121
 
    avahi_simple_poll_quit(mc.simple_poll);
 
1190
  if(simple_poll != NULL){
 
1191
    avahi_simple_poll_quit(simple_poll);
1122
1192
  }
1123
1193
  errno = old_errno;
1124
1194
}
1125
1195
 
 
1196
__attribute__((nonnull, warn_unused_result))
1126
1197
bool get_flags(const char *ifname, struct ifreq *ifr){
1127
1198
  int ret;
1128
1199
  error_t ret_errno;
1147
1218
  return true;
1148
1219
}
1149
1220
 
 
1221
__attribute__((nonnull, warn_unused_result))
1150
1222
bool good_flags(const char *ifname, const struct ifreq *ifr){
1151
1223
  
1152
1224
  /* Reject the loopback device */
1194
1266
 * corresponds to an acceptable network device.
1195
1267
 * (This function is passed to scandir(3) as a filter function.)
1196
1268
 */
 
1269
__attribute__((nonnull, warn_unused_result))
1197
1270
int good_interface(const struct dirent *if_entry){
1198
1271
  if(if_entry->d_name[0] == '.'){
1199
1272
    return 0;
1217
1290
/* 
1218
1291
 * This function determines if a network interface is up.
1219
1292
 */
 
1293
__attribute__((nonnull, warn_unused_result))
1220
1294
bool interface_is_up(const char *interface){
1221
1295
  struct ifreq ifr;
1222
1296
  if(not get_flags(interface, &ifr)){
1233
1307
/* 
1234
1308
 * This function determines if a network interface is running
1235
1309
 */
 
1310
__attribute__((nonnull, warn_unused_result))
1236
1311
bool interface_is_running(const char *interface){
1237
1312
  struct ifreq ifr;
1238
1313
  if(not get_flags(interface, &ifr)){
1246
1321
  return (bool)(ifr.ifr_flags & IFF_RUNNING);
1247
1322
}
1248
1323
 
 
1324
__attribute__((nonnull, pure, warn_unused_result))
1249
1325
int notdotentries(const struct dirent *direntry){
1250
1326
  /* Skip "." and ".." */
1251
1327
  if(direntry->d_name[0] == '.'
1258
1334
}
1259
1335
 
1260
1336
/* Is this directory entry a runnable program? */
 
1337
__attribute__((nonnull, warn_unused_result))
1261
1338
int runnable_hook(const struct dirent *direntry){
1262
1339
  int ret;
1263
1340
  size_t sret;
1271
1348
  sret = strspn(direntry->d_name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1272
1349
                "abcdefghijklmnopqrstuvwxyz"
1273
1350
                "0123456789"
1274
 
                "_-");
 
1351
                "_.-");
1275
1352
  if((direntry->d_name)[sret] != '\0'){
1276
1353
    /* Contains non-allowed characters */
1277
1354
    if(debug){
1281
1358
    return 0;
1282
1359
  }
1283
1360
  
1284
 
  char *fullname = NULL;
1285
 
  ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1286
 
  if(ret < 0){
1287
 
    perror_plus("asprintf");
1288
 
    return 0;
1289
 
  }
1290
 
  
1291
 
  ret = stat(fullname, &st);
 
1361
  ret = fstatat(hookdir_fd, direntry->d_name, &st, 0);
1292
1362
  if(ret == -1){
1293
1363
    if(debug){
1294
1364
      perror_plus("Could not stat hook");
1318
1388
  return 1;
1319
1389
}
1320
1390
 
1321
 
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){
1322
1394
  int ret;
1323
1395
  struct timespec now;
1324
1396
  struct timespec waited_time;
1325
1397
  intmax_t block_time;
1326
1398
  
1327
1399
  while(true){
1328
 
    if(mc.current_server == NULL){
1329
 
      if (debug){
 
1400
    if(mc->current_server == NULL){
 
1401
      if(debug){
1330
1402
        fprintf_plus(stderr, "Wait until first server is found."
1331
1403
                     " No timeout!\n");
1332
1404
      }
1333
1405
      ret = avahi_simple_poll_iterate(s, -1);
1334
1406
    } else {
1335
 
      if (debug){
 
1407
      if(debug){
1336
1408
        fprintf_plus(stderr, "Check current_server if we should run"
1337
1409
                     " it, or wait\n");
1338
1410
      }
1345
1417
      /* Calculating in ms how long time between now and server
1346
1418
         who we visted longest time ago. Now - last seen.  */
1347
1419
      waited_time.tv_sec = (now.tv_sec
1348
 
                            - mc.current_server->last_seen.tv_sec);
 
1420
                            - mc->current_server->last_seen.tv_sec);
1349
1421
      waited_time.tv_nsec = (now.tv_nsec
1350
 
                             - mc.current_server->last_seen.tv_nsec);
 
1422
                             - mc->current_server->last_seen.tv_nsec);
1351
1423
      /* total time is 10s/10,000ms.
1352
1424
         Converting to s from ms by dividing by 1,000,
1353
1425
         and ns to ms by dividing by 1,000,000. */
1355
1427
                     - ((intmax_t)waited_time.tv_sec * 1000))
1356
1428
                    - ((intmax_t)waited_time.tv_nsec / 1000000));
1357
1429
      
1358
 
      if (debug){
 
1430
      if(debug){
1359
1431
        fprintf_plus(stderr, "Blocking for %" PRIdMAX " ms\n",
1360
1432
                     block_time);
1361
1433
      }
1362
1434
      
1363
1435
      if(block_time <= 0){
1364
 
        ret = start_mandos_communication(mc.current_server->ip,
1365
 
                                         mc.current_server->port,
1366
 
                                         mc.current_server->if_index,
1367
 
                                         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);
1368
1440
        if(ret == 0){
1369
 
          avahi_simple_poll_quit(mc.simple_poll);
 
1441
          avahi_simple_poll_quit(s);
1370
1442
          return 0;
1371
1443
        }
1372
1444
        ret = clock_gettime(CLOCK_MONOTONIC,
1373
 
                            &mc.current_server->last_seen);
 
1445
                            &mc->current_server->last_seen);
1374
1446
        if(ret == -1){
1375
1447
          perror_plus("clock_gettime");
1376
1448
          return -1;
1377
1449
        }
1378
 
        mc.current_server = mc.current_server->next;
 
1450
        mc->current_server = mc->current_server->next;
1379
1451
        block_time = 0;         /* Call avahi to find new Mandos
1380
1452
                                   servers, but don't block */
1381
1453
      }
1383
1455
      ret = avahi_simple_poll_iterate(s, (int)block_time);
1384
1456
    }
1385
1457
    if(ret != 0){
1386
 
      if (ret > 0 or errno != EINTR){
 
1458
      if(ret > 0 or errno != EINTR){
1387
1459
        return (ret != 1) ? ret : 0;
1388
1460
      }
1389
1461
    }
1391
1463
}
1392
1464
 
1393
1465
/* Set effective uid to 0, return errno */
 
1466
__attribute__((warn_unused_result))
1394
1467
error_t raise_privileges(void){
1395
1468
  error_t old_errno = errno;
1396
1469
  error_t ret_errno = 0;
1397
1470
  if(seteuid(0) == -1){
1398
1471
    ret_errno = errno;
1399
 
    perror_plus("seteuid");
1400
1472
  }
1401
1473
  errno = old_errno;
1402
1474
  return ret_errno;
1403
1475
}
1404
1476
 
1405
1477
/* Set effective and real user ID to 0.  Return errno. */
 
1478
__attribute__((warn_unused_result))
1406
1479
error_t raise_privileges_permanently(void){
1407
1480
  error_t old_errno = errno;
1408
1481
  error_t ret_errno = raise_privileges();
1412
1485
  }
1413
1486
  if(setuid(0) == -1){
1414
1487
    ret_errno = errno;
1415
 
    perror_plus("seteuid");
1416
1488
  }
1417
1489
  errno = old_errno;
1418
1490
  return ret_errno;
1419
1491
}
1420
1492
 
1421
1493
/* Set effective user ID to unprivileged saved user ID */
 
1494
__attribute__((warn_unused_result))
1422
1495
error_t lower_privileges(void){
1423
1496
  error_t old_errno = errno;
1424
1497
  error_t ret_errno = 0;
1425
1498
  if(seteuid(uid) == -1){
1426
1499
    ret_errno = errno;
1427
 
    perror_plus("seteuid");
1428
1500
  }
1429
1501
  errno = old_errno;
1430
1502
  return ret_errno;
1431
1503
}
1432
1504
 
1433
1505
/* Lower privileges permanently */
 
1506
__attribute__((warn_unused_result))
1434
1507
error_t lower_privileges_permanently(void){
1435
1508
  error_t old_errno = errno;
1436
1509
  error_t ret_errno = 0;
1437
1510
  if(setuid(uid) == -1){
1438
1511
    ret_errno = errno;
1439
 
    perror_plus("setuid");
1440
1512
  }
1441
1513
  errno = old_errno;
1442
1514
  return ret_errno;
1443
1515
}
1444
1516
 
1445
 
bool run_network_hooks(const char *mode, const char *interface,
 
1517
__attribute__((nonnull))
 
1518
void run_network_hooks(const char *mode, const char *interface,
1446
1519
                       const float delay){
1447
 
  struct dirent **direntries;
 
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__ */
 
1547
  if(numhooks == -1){
 
1548
    perror_plus("scandir");
 
1549
    return;
 
1550
  }
1448
1551
  struct dirent *direntry;
1449
1552
  int ret;
1450
 
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
1451
 
                         alphasort);
1452
 
  if(numhooks == -1){
1453
 
    if(errno == ENOENT){
1454
 
      if(debug){
1455
 
        fprintf_plus(stderr, "Network hook directory \"%s\" not"
1456
 
                     " found\n", hookdir);
1457
 
      }
1458
 
    } else {
1459
 
      perror_plus("scandir");
 
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);
1460
1559
    }
1461
 
  } else {
1462
 
    int devnull = open("/dev/null", O_RDONLY);
1463
 
    for(int i = 0; i < numhooks; i++){
1464
 
      direntry = direntries[i];
1465
 
      char *fullname = NULL;
1466
 
      ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1467
 
      if(ret < 0){
 
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){
1468
1621
        perror_plus("asprintf");
1469
 
        continue;
1470
 
      }
1471
 
      if(debug){
1472
 
        fprintf_plus(stderr, "Running network hook \"%s\"\n",
1473
 
                     direntry->d_name);
1474
 
      }
1475
 
      pid_t hook_pid = fork();
1476
 
      if(hook_pid == 0){
1477
 
        /* Child */
1478
 
        /* Raise privileges */
1479
 
        raise_privileges_permanently();
1480
 
        /* Set group */
1481
 
        errno = 0;
1482
 
        ret = setgid(0);
1483
 
        if(ret == -1){
1484
 
          perror_plus("setgid");
1485
 
        }
1486
 
        /* Reset supplementary groups */
1487
 
        errno = 0;
1488
 
        ret = setgroups(0, NULL);
1489
 
        if(ret == -1){
1490
 
          perror_plus("setgroups");
1491
 
        }
1492
 
        dup2(devnull, STDIN_FILENO);
1493
 
        close(devnull);
1494
 
        dup2(STDERR_FILENO, STDOUT_FILENO);
1495
 
        ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
1496
 
        if(ret == -1){
1497
 
          perror_plus("setenv");
1498
 
          _exit(EX_OSERR);
1499
 
        }
1500
 
        ret = setenv("DEVICE", interface, 1);
1501
 
        if(ret == -1){
1502
 
          perror_plus("setenv");
1503
 
          _exit(EX_OSERR);
1504
 
        }
1505
 
        ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
1506
 
        if(ret == -1){
1507
 
          perror_plus("setenv");
1508
 
          _exit(EX_OSERR);
1509
 
        }
1510
 
        ret = setenv("MODE", mode, 1);
1511
 
        if(ret == -1){
1512
 
          perror_plus("setenv");
1513
 
          _exit(EX_OSERR);
1514
 
        }
1515
 
        char *delaystring;
1516
 
        ret = asprintf(&delaystring, "%f", delay);
1517
 
        if(ret == -1){
1518
 
          perror_plus("asprintf");
1519
 
          _exit(EX_OSERR);
1520
 
        }
1521
 
        ret = setenv("DELAY", delaystring, 1);
1522
 
        if(ret == -1){
1523
 
          free(delaystring);
1524
 
          perror_plus("setenv");
1525
 
          _exit(EX_OSERR);
1526
 
        }
 
1622
        _exit(EX_OSERR);
 
1623
      }
 
1624
      ret = setenv("DELAY", delaystring, 1);
 
1625
      if(ret == -1){
1527
1626
        free(delaystring);
1528
 
        if(connect_to != NULL){
1529
 
          ret = setenv("CONNECT", connect_to, 1);
1530
 
          if(ret == -1){
1531
 
            perror_plus("setenv");
1532
 
            _exit(EX_OSERR);
1533
 
          }
1534
 
        }
1535
 
        if(execl(fullname, direntry->d_name, mode, NULL) == -1){
1536
 
          perror_plus("execl");
1537
 
          _exit(EXIT_FAILURE);
1538
 
        }
 
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
      int status;
 
1654
      if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
 
1655
        perror_plus("waitpid");
 
1656
        free(direntry);
 
1657
        continue;
 
1658
      }
 
1659
      if(WIFEXITED(status)){
 
1660
        if(WEXITSTATUS(status) != 0){
 
1661
          fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
 
1662
                       " with status %d\n", direntry->d_name,
 
1663
                       WEXITSTATUS(status));
 
1664
          free(direntry);
 
1665
          continue;
 
1666
        }
 
1667
      } else if(WIFSIGNALED(status)){
 
1668
        fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
 
1669
                     " signal %d\n", direntry->d_name,
 
1670
                     WTERMSIG(status));
 
1671
        free(direntry);
 
1672
        continue;
1539
1673
      } else {
1540
 
        int status;
1541
 
        if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1542
 
          perror_plus("waitpid");
1543
 
          free(fullname);
1544
 
          continue;
1545
 
        }
1546
 
        if(WIFEXITED(status)){
1547
 
          if(WEXITSTATUS(status) != 0){
1548
 
            fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1549
 
                         " with status %d\n", direntry->d_name,
1550
 
                         WEXITSTATUS(status));
1551
 
            free(fullname);
1552
 
            continue;
1553
 
          }
1554
 
        } else if(WIFSIGNALED(status)){
1555
 
          fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1556
 
                       " signal %d\n", direntry->d_name,
1557
 
                       WTERMSIG(status));
1558
 
          free(fullname);
1559
 
          continue;
1560
 
        } else {
1561
 
          fprintf_plus(stderr, "Warning: network hook \"%s\""
1562
 
                       " crashed\n", direntry->d_name);
1563
 
          free(fullname);
1564
 
          continue;
1565
 
        }
1566
 
      }
1567
 
      free(fullname);
1568
 
      if(debug){
1569
 
        fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1570
 
                     direntry->d_name);
1571
 
      }
1572
 
    }
1573
 
    close(devnull);
1574
 
  }
1575
 
  return true;
 
1674
        fprintf_plus(stderr, "Warning: network hook \"%s\""
 
1675
                     " crashed\n", direntry->d_name);
 
1676
        free(direntry);
 
1677
        continue;
 
1678
      }
 
1679
    }
 
1680
    if(debug){
 
1681
      fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
 
1682
                   direntry->d_name);
 
1683
    }
 
1684
    free(direntry);
 
1685
  }
 
1686
  free(direntries);
 
1687
  if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1688
    perror_plus("close");
 
1689
  } else {
 
1690
    hookdir_fd = -1;
 
1691
  }
 
1692
  close(devnull);
1576
1693
}
1577
1694
 
 
1695
__attribute__((nonnull, warn_unused_result))
1578
1696
error_t bring_up_interface(const char *const interface,
1579
1697
                           const float delay){
1580
 
  int sd = -1;
1581
1698
  error_t old_errno = errno;
1582
 
  error_t ret_errno = 0;
1583
 
  int ret, ret_setflags;
 
1699
  int ret;
1584
1700
  struct ifreq network;
1585
1701
  unsigned int if_index = if_nametoindex(interface);
1586
1702
  if(if_index == 0){
1595
1711
  }
1596
1712
  
1597
1713
  if(not interface_is_up(interface)){
1598
 
    if(not get_flags(interface, &network) and debug){
 
1714
    error_t ret_errno = 0, ioctl_errno = 0;
 
1715
    if(not get_flags(interface, &network)){
1599
1716
      ret_errno = errno;
1600
1717
      fprintf_plus(stderr, "Failed to get flags for interface "
1601
1718
                   "\"%s\"\n", interface);
 
1719
      errno = old_errno;
1602
1720
      return ret_errno;
1603
1721
    }
1604
 
    network.ifr_flags |= IFF_UP;
 
1722
    network.ifr_flags |= IFF_UP; /* set flag */
1605
1723
    
1606
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1607
 
    if(sd < 0){
 
1724
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1725
    if(sd == -1){
1608
1726
      ret_errno = errno;
1609
1727
      perror_plus("socket");
1610
1728
      errno = old_errno;
1611
1729
      return ret_errno;
1612
1730
    }
1613
 
  
 
1731
    
1614
1732
    if(quit_now){
1615
 
      close(sd);
 
1733
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1734
      if(ret == -1){
 
1735
        perror_plus("close");
 
1736
      }
1616
1737
      errno = old_errno;
1617
1738
      return EINTR;
1618
1739
    }
1622
1743
                   interface);
1623
1744
    }
1624
1745
    
1625
 
    /* Raise priviliges */
1626
 
    raise_privileges();
 
1746
    /* Raise privileges */
 
1747
    ret_errno = raise_privileges();
 
1748
    if(ret_errno != 0){
 
1749
      errno = ret_errno;
 
1750
      perror_plus("Failed to raise privileges");
 
1751
    }
1627
1752
    
1628
1753
#ifdef __linux__
1629
 
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1630
 
       messages about the network interface to mess up the prompt */
1631
 
    int ret_linux = klogctl(8, NULL, 5);
1632
 
    bool restore_loglevel = true;
1633
 
    if(ret_linux == -1){
1634
 
      restore_loglevel = false;
1635
 
      perror_plus("klogctl");
 
1754
    int ret_linux;
 
1755
    bool restore_loglevel = false;
 
1756
    if(ret_errno == 0){
 
1757
      /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1758
         messages about the network interface to mess up the prompt */
 
1759
      ret_linux = klogctl(8, NULL, 5);
 
1760
      if(ret_linux == -1){
 
1761
        perror_plus("klogctl");
 
1762
      } else {
 
1763
        restore_loglevel = true;
 
1764
      }
1636
1765
    }
1637
1766
#endif  /* __linux__ */
1638
 
    ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
1639
 
    ret_errno = errno;
 
1767
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1768
    ioctl_errno = errno;
1640
1769
#ifdef __linux__
1641
1770
    if(restore_loglevel){
1642
1771
      ret_linux = klogctl(7, NULL, 0);
1646
1775
    }
1647
1776
#endif  /* __linux__ */
1648
1777
    
1649
 
    /* Lower privileges */
1650
 
    lower_privileges();
 
1778
    /* If raise_privileges() succeeded above */
 
1779
    if(ret_errno == 0){
 
1780
      /* Lower privileges */
 
1781
      ret_errno = lower_privileges();
 
1782
      if(ret_errno != 0){
 
1783
        errno = ret_errno;
 
1784
        perror_plus("Failed to lower privileges");
 
1785
      }
 
1786
    }
1651
1787
    
1652
1788
    /* Close the socket */
1653
1789
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
1656
1792
    }
1657
1793
    
1658
1794
    if(ret_setflags == -1){
1659
 
      errno = ret_errno;
 
1795
      errno = ioctl_errno;
1660
1796
      perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1661
1797
      errno = old_errno;
1662
 
      return ret_errno;
 
1798
      return ioctl_errno;
1663
1799
    }
1664
1800
  } else if(debug){
1665
1801
    fprintf_plus(stderr, "Interface \"%s\" is already up; good\n",
1683
1819
  return 0;
1684
1820
}
1685
1821
 
 
1822
__attribute__((nonnull, warn_unused_result))
1686
1823
error_t take_down_interface(const char *const interface){
1687
 
  int sd = -1;
1688
1824
  error_t old_errno = errno;
1689
 
  error_t ret_errno = 0;
1690
 
  int ret, ret_setflags;
1691
1825
  struct ifreq network;
1692
1826
  unsigned int if_index = if_nametoindex(interface);
1693
1827
  if(if_index == 0){
1696
1830
    return ENXIO;
1697
1831
  }
1698
1832
  if(interface_is_up(interface)){
 
1833
    error_t ret_errno = 0, ioctl_errno = 0;
1699
1834
    if(not get_flags(interface, &network) and debug){
1700
1835
      ret_errno = errno;
1701
1836
      fprintf_plus(stderr, "Failed to get flags for interface "
1702
1837
                   "\"%s\"\n", interface);
 
1838
      errno = old_errno;
1703
1839
      return ret_errno;
1704
1840
    }
1705
1841
    network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1706
1842
    
1707
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1708
 
    if(sd < 0){
 
1843
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1844
    if(sd == -1){
1709
1845
      ret_errno = errno;
1710
1846
      perror_plus("socket");
1711
1847
      errno = old_errno;
1717
1853
                   interface);
1718
1854
    }
1719
1855
    
1720
 
    /* Raise priviliges */
1721
 
    raise_privileges();
1722
 
    
1723
 
    ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
1724
 
    ret_errno = errno;
1725
 
    
1726
 
    /* Lower privileges */
1727
 
    lower_privileges();
 
1856
    /* Raise privileges */
 
1857
    ret_errno = raise_privileges();
 
1858
    if(ret_errno != 0){
 
1859
      errno = ret_errno;
 
1860
      perror_plus("Failed to raise privileges");
 
1861
    }
 
1862
    
 
1863
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1864
    ioctl_errno = errno;
 
1865
    
 
1866
    /* If raise_privileges() succeeded above */
 
1867
    if(ret_errno == 0){
 
1868
      /* Lower privileges */
 
1869
      ret_errno = lower_privileges();
 
1870
      if(ret_errno != 0){
 
1871
        errno = ret_errno;
 
1872
        perror_plus("Failed to lower privileges");
 
1873
      }
 
1874
    }
1728
1875
    
1729
1876
    /* Close the socket */
1730
 
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1877
    int ret = (int)TEMP_FAILURE_RETRY(close(sd));
1731
1878
    if(ret == -1){
1732
1879
      perror_plus("close");
1733
1880
    }
1734
1881
    
1735
1882
    if(ret_setflags == -1){
1736
 
      errno = ret_errno;
 
1883
      errno = ioctl_errno;
1737
1884
      perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
1738
1885
      errno = old_errno;
1739
 
      return ret_errno;
 
1886
      return ioctl_errno;
1740
1887
    }
1741
1888
  } else if(debug){
1742
1889
    fprintf_plus(stderr, "Interface \"%s\" is already down; odd\n",
1748
1895
}
1749
1896
 
1750
1897
int main(int argc, char *argv[]){
 
1898
  mandos_context mc = { .server = NULL, .dh_bits = 1024,
 
1899
                        .priority = "SECURE256:!CTYPE-X.509:"
 
1900
                        "+CTYPE-OPENPGP", .current_server = NULL,
 
1901
                        .interfaces = NULL, .interfaces_size = 0 };
1751
1902
  AvahiSServiceBrowser *sb = NULL;
1752
1903
  error_t ret_errno;
1753
1904
  int ret;
1754
1905
  intmax_t tmpmax;
1755
1906
  char *tmp;
1756
1907
  int exitcode = EXIT_SUCCESS;
1757
 
  char *interfaces = NULL;
1758
 
  size_t interfaces_size = 0;
1759
1908
  char *interfaces_to_take_down = NULL;
1760
1909
  size_t interfaces_to_take_down_size = 0;
1761
 
  char tempdir[] = "/tmp/mandosXXXXXX";
1762
 
  bool tempdir_created = false;
 
1910
  char run_tempdir[] = "/run/tmp/mandosXXXXXX";
 
1911
  char old_tempdir[] = "/tmp/mandosXXXXXX";
 
1912
  char *tempdir = NULL;
1763
1913
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1764
1914
  const char *seckey = PATHDIR "/" SECKEY;
1765
1915
  const char *pubkey = PATHDIR "/" PUBKEY;
1766
1916
  char *interfaces_hooks = NULL;
1767
 
  size_t interfaces_hooks_size = 0;
1768
1917
  
1769
1918
  bool gnutls_initialized = false;
1770
1919
  bool gpgme_initialized = false;
1861
2010
        connect_to = arg;
1862
2011
        break;
1863
2012
      case 'i':                 /* --interface */
1864
 
        ret_errno = argz_add_sep(&interfaces, &interfaces_size, arg,
1865
 
                                 (int)',');
 
2013
        ret_errno = argz_add_sep(&mc.interfaces, &mc.interfaces_size,
 
2014
                                 arg, (int)',');
1866
2015
        if(ret_errno != 0){
1867
2016
          argp_error(state, "%s", strerror(ret_errno));
1868
2017
        }
1948
2097
    /* Work around Debian bug #633582:
1949
2098
       <http://bugs.debian.org/633582> */
1950
2099
    
1951
 
    /* Re-raise priviliges */
1952
 
    if(raise_privileges() == 0){
 
2100
    /* Re-raise privileges */
 
2101
    ret_errno = raise_privileges();
 
2102
    if(ret_errno != 0){
 
2103
      errno = ret_errno;
 
2104
      perror_plus("Failed to raise privileges");
 
2105
    } else {
1953
2106
      struct stat st;
1954
2107
      
1955
2108
      if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
1995
2148
      }
1996
2149
    
1997
2150
      /* Lower privileges */
1998
 
      errno = 0;
1999
 
      ret = seteuid(uid);
2000
 
      if(ret == -1){
2001
 
        perror_plus("seteuid");
 
2151
      ret_errno = lower_privileges();
 
2152
      if(ret_errno != 0){
 
2153
        errno = ret_errno;
 
2154
        perror_plus("Failed to lower privileges");
2002
2155
      }
2003
2156
    }
2004
2157
  }
2005
2158
  
2006
 
  /* Remove empty interface names */
 
2159
  /* Remove invalid interface names (except "none") */
2007
2160
  {
2008
2161
    char *interface = NULL;
2009
 
    while((interface = argz_next(interfaces, interfaces_size,
 
2162
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
2010
2163
                                 interface))){
2011
 
      if(if_nametoindex(interface) == 0){
2012
 
        if(interface[0] != '\0' and strcmp(interface, "none") != 0){
 
2164
      if(strcmp(interface, "none") != 0
 
2165
         and if_nametoindex(interface) == 0){
 
2166
        if(interface[0] != '\0'){
2013
2167
          fprintf_plus(stderr, "Not using nonexisting interface"
2014
2168
                       " \"%s\"\n", interface);
2015
2169
        }
2016
 
        argz_delete(&interfaces, &interfaces_size, interface);
 
2170
        argz_delete(&mc.interfaces, &mc.interfaces_size, interface);
2017
2171
        interface = NULL;
2018
2172
      }
2019
2173
    }
2021
2175
  
2022
2176
  /* Run network hooks */
2023
2177
  {
2024
 
    ret_errno = argz_append(&interfaces_hooks, &interfaces_hooks_size,
2025
 
                            interfaces, interfaces_size);
2026
 
    if(ret_errno != 0){
2027
 
      errno = ret_errno;
2028
 
      perror_plus("argz_append");
2029
 
      goto end;
2030
 
    }
2031
 
    argz_stringify(interfaces_hooks, interfaces_hooks_size, (int)',');
2032
 
    if(not run_network_hooks("start", interfaces_hooks, delay)){
2033
 
      goto end;
2034
 
    }
 
2178
    if(mc.interfaces != NULL){
 
2179
      interfaces_hooks = malloc(mc.interfaces_size);
 
2180
      if(interfaces_hooks == NULL){
 
2181
        perror_plus("malloc");
 
2182
        goto end;
 
2183
      }
 
2184
      memcpy(interfaces_hooks, mc.interfaces, mc.interfaces_size);
 
2185
      argz_stringify(interfaces_hooks, mc.interfaces_size, (int)',');
 
2186
    }
 
2187
    run_network_hooks("start", interfaces_hooks != NULL ?
 
2188
                      interfaces_hooks : "", delay);
2035
2189
  }
2036
2190
  
2037
2191
  if(not debug){
2042
2196
     from the signal handler */
2043
2197
  /* Initialize the pseudo-RNG for Avahi */
2044
2198
  srand((unsigned int) time(NULL));
2045
 
  mc.simple_poll = avahi_simple_poll_new();
2046
 
  if(mc.simple_poll == NULL){
 
2199
  simple_poll = avahi_simple_poll_new();
 
2200
  if(simple_poll == NULL){
2047
2201
    fprintf_plus(stderr,
2048
2202
                 "Avahi: Failed to create simple poll object.\n");
2049
2203
    exitcode = EX_UNAVAILABLE;
2114
2268
  }
2115
2269
  
2116
2270
  /* If no interfaces were specified, make a list */
2117
 
  if(interfaces == NULL){
2118
 
    struct dirent **direntries;
 
2271
  if(mc.interfaces == NULL){
 
2272
    struct dirent **direntries = NULL;
2119
2273
    /* Look for any good interfaces */
2120
2274
    ret = scandir(sys_class_net, &direntries, good_interface,
2121
2275
                  alphasort);
2122
2276
    if(ret >= 1){
2123
2277
      /* Add all found interfaces to interfaces list */
2124
2278
      for(int i = 0; i < ret; ++i){
2125
 
        ret_errno = argz_add(&interfaces, &interfaces_size,
 
2279
        ret_errno = argz_add(&mc.interfaces, &mc.interfaces_size,
2126
2280
                             direntries[i]->d_name);
2127
2281
        if(ret_errno != 0){
 
2282
          errno = ret_errno;
2128
2283
          perror_plus("argz_add");
 
2284
          free(direntries[i]);
2129
2285
          continue;
2130
2286
        }
2131
2287
        if(debug){
2132
2288
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
2133
2289
                       direntries[i]->d_name);
2134
2290
        }
 
2291
        free(direntries[i]);
2135
2292
      }
2136
2293
      free(direntries);
2137
2294
    } else {
2138
 
      free(direntries);
 
2295
      if(ret == 0){
 
2296
        free(direntries);
 
2297
      }
2139
2298
      fprintf_plus(stderr, "Could not find a network interface\n");
2140
2299
      exitcode = EXIT_FAILURE;
2141
2300
      goto end;
2142
2301
    }
2143
2302
  }
2144
2303
  
2145
 
  /* If we only got one interface, explicitly use only that one */
2146
 
  if(argz_count(interfaces, interfaces_size) == 1){
2147
 
    if(debug){
2148
 
      fprintf_plus(stderr, "Using only interface \"%s\"\n",
2149
 
                   interfaces);
2150
 
    }
2151
 
    if_index = (AvahiIfIndex)if_nametoindex(interfaces);
2152
 
  }
2153
 
  
2154
 
  /* Bring up interfaces which are down */
2155
 
  if(not (argz_count(interfaces, interfaces_size) == 1
2156
 
          and strcmp(interfaces, "none") == 0)){
 
2304
  /* Bring up interfaces which are down, and remove any "none"s */
 
2305
  {
2157
2306
    char *interface = NULL;
2158
 
    while((interface = argz_next(interfaces, interfaces_size,
 
2307
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
2159
2308
                                 interface))){
 
2309
      /* If interface name is "none", stop bringing up interfaces.
 
2310
         Also remove all instances of "none" from the list */
 
2311
      if(strcmp(interface, "none") == 0){
 
2312
        argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2313
                    interface);
 
2314
        interface = NULL;
 
2315
        while((interface = argz_next(mc.interfaces,
 
2316
                                     mc.interfaces_size, interface))){
 
2317
          if(strcmp(interface, "none") == 0){
 
2318
            argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2319
                        interface);
 
2320
            interface = NULL;
 
2321
          }
 
2322
        }
 
2323
        break;
 
2324
      }
2160
2325
      bool interface_was_up = interface_is_up(interface);
2161
 
      ret = bring_up_interface(interface, delay);
 
2326
      errno = bring_up_interface(interface, delay);
2162
2327
      if(not interface_was_up){
2163
 
        if(ret != 0){
2164
 
          errno = ret;
 
2328
        if(errno != 0){
2165
2329
          perror_plus("Failed to bring up interface");
2166
2330
        } else {
2167
 
          ret_errno = argz_add(&interfaces_to_take_down,
2168
 
                               &interfaces_to_take_down_size,
2169
 
                               interface);
 
2331
          errno = argz_add(&interfaces_to_take_down,
 
2332
                           &interfaces_to_take_down_size,
 
2333
                           interface);
 
2334
          if(errno != 0){
 
2335
            perror_plus("argz_add");
 
2336
          }
2170
2337
        }
2171
2338
      }
2172
2339
    }
2173
 
    free(interfaces);
2174
 
    interfaces = NULL;
2175
 
    interfaces_size = 0;
2176
2340
    if(debug and (interfaces_to_take_down == NULL)){
2177
2341
      fprintf_plus(stderr, "No interfaces were brought up\n");
2178
2342
    }
2179
2343
  }
2180
2344
  
 
2345
  /* If we only got one interface, explicitly use only that one */
 
2346
  if(argz_count(mc.interfaces, mc.interfaces_size) == 1){
 
2347
    if(debug){
 
2348
      fprintf_plus(stderr, "Using only interface \"%s\"\n",
 
2349
                   mc.interfaces);
 
2350
    }
 
2351
    if_index = (AvahiIfIndex)if_nametoindex(mc.interfaces);
 
2352
  }
 
2353
  
2181
2354
  if(quit_now){
2182
2355
    goto end;
2183
2356
  }
2184
2357
  
2185
 
  ret = init_gnutls_global(pubkey, seckey);
 
2358
  ret = init_gnutls_global(pubkey, seckey, &mc);
2186
2359
  if(ret == -1){
2187
2360
    fprintf_plus(stderr, "init_gnutls_global failed\n");
2188
2361
    exitcode = EX_UNAVAILABLE;
2195
2368
    goto end;
2196
2369
  }
2197
2370
  
2198
 
  if(mkdtemp(tempdir) == NULL){
 
2371
  /* Try /run/tmp before /tmp */
 
2372
  tempdir = mkdtemp(run_tempdir);
 
2373
  if(tempdir == NULL and errno == ENOENT){
 
2374
      if(debug){
 
2375
        fprintf_plus(stderr, "Tempdir %s did not work, trying %s\n",
 
2376
                     run_tempdir, old_tempdir);
 
2377
      }
 
2378
      tempdir = mkdtemp(old_tempdir);
 
2379
  }
 
2380
  if(tempdir == NULL){
2199
2381
    perror_plus("mkdtemp");
2200
2382
    goto end;
2201
2383
  }
2202
 
  tempdir_created = true;
2203
2384
  
2204
2385
  if(quit_now){
2205
2386
    goto end;
2206
2387
  }
2207
2388
  
2208
 
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
2389
  if(not init_gpgme(pubkey, seckey, tempdir, &mc)){
2209
2390
    fprintf_plus(stderr, "init_gpgme failed\n");
2210
2391
    exitcode = EX_UNAVAILABLE;
2211
2392
    goto end;
2241
2422
      exitcode = EX_USAGE;
2242
2423
      goto end;
2243
2424
    }
2244
 
  
 
2425
    
2245
2426
    if(quit_now){
2246
2427
      goto end;
2247
2428
    }
2268
2449
    }
2269
2450
    
2270
2451
    while(not quit_now){
2271
 
      ret = start_mandos_communication(address, port, if_index, af);
 
2452
      ret = start_mandos_communication(address, port, if_index, af,
 
2453
                                       &mc);
2272
2454
      if(quit_now or ret == 0){
2273
2455
        break;
2274
2456
      }
2276
2458
        fprintf_plus(stderr, "Retrying in %d seconds\n",
2277
2459
                     (int)retry_interval);
2278
2460
      }
2279
 
      sleep((int)retry_interval);
 
2461
      sleep((unsigned int)retry_interval);
2280
2462
    }
2281
2463
    
2282
 
    if (not quit_now){
 
2464
    if(not quit_now){
2283
2465
      exitcode = EXIT_SUCCESS;
2284
2466
    }
2285
2467
    
2300
2482
    config.publish_domain = 0;
2301
2483
    
2302
2484
    /* Allocate a new server */
2303
 
    mc.server = avahi_server_new(avahi_simple_poll_get
2304
 
                                 (mc.simple_poll), &config, NULL,
2305
 
                                 NULL, &ret_errno);
 
2485
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
2486
                                 &config, NULL, NULL, &ret_errno);
2306
2487
    
2307
2488
    /* Free the Avahi configuration data */
2308
2489
    avahi_server_config_free(&config);
2323
2504
  /* Create the Avahi service browser */
2324
2505
  sb = avahi_s_service_browser_new(mc.server, if_index,
2325
2506
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
2326
 
                                   NULL, 0, browse_callback, NULL);
 
2507
                                   NULL, 0, browse_callback,
 
2508
                                   (void *)&mc);
2327
2509
  if(sb == NULL){
2328
2510
    fprintf_plus(stderr, "Failed to create service browser: %s\n",
2329
2511
                 avahi_strerror(avahi_server_errno(mc.server)));
2340
2522
  if(debug){
2341
2523
    fprintf_plus(stderr, "Starting Avahi loop search\n");
2342
2524
  }
2343
 
 
2344
 
  ret = avahi_loop_with_timeout(mc.simple_poll,
2345
 
                                (int)(retry_interval * 1000));
 
2525
  
 
2526
  ret = avahi_loop_with_timeout(simple_poll,
 
2527
                                (int)(retry_interval * 1000), &mc);
2346
2528
  if(debug){
2347
2529
    fprintf_plus(stderr, "avahi_loop_with_timeout exited %s\n",
2348
2530
                 (ret == 0) ? "successfully" : "with error");
2355
2537
  }
2356
2538
  
2357
2539
  /* Cleanup things */
 
2540
  free(mc.interfaces);
 
2541
  
2358
2542
  if(sb != NULL)
2359
2543
    avahi_s_service_browser_free(sb);
2360
2544
  
2361
2545
  if(mc.server != NULL)
2362
2546
    avahi_server_free(mc.server);
2363
2547
  
2364
 
  if(mc.simple_poll != NULL)
2365
 
    avahi_simple_poll_free(mc.simple_poll);
 
2548
  if(simple_poll != NULL)
 
2549
    avahi_simple_poll_free(simple_poll);
2366
2550
  
2367
2551
  if(gnutls_initialized){
2368
2552
    gnutls_certificate_free_credentials(mc.cred);
2380
2564
    mc.current_server->prev->next = NULL;
2381
2565
    while(mc.current_server != NULL){
2382
2566
      server *next = mc.current_server->next;
 
2567
#ifdef __GNUC__
 
2568
#pragma GCC diagnostic push
 
2569
#pragma GCC diagnostic ignored "-Wcast-qual"
 
2570
#endif
 
2571
      free((char *)(mc.current_server->ip));
 
2572
#ifdef __GNUC__
 
2573
#pragma GCC diagnostic pop
 
2574
#endif
2383
2575
      free(mc.current_server);
2384
2576
      mc.current_server = next;
2385
2577
    }
2386
2578
  }
2387
2579
  
2388
 
  /* Re-raise priviliges */
 
2580
  /* Re-raise privileges */
2389
2581
  {
2390
 
    raise_privileges();
2391
 
    
2392
 
    /* Run network hooks */
2393
 
    run_network_hooks("stop", interfaces_hooks, delay);
2394
 
    
2395
 
    /* Take down the network interfaces which were brought up */
2396
 
    {
2397
 
      char *interface = NULL;
2398
 
      while((interface=argz_next(interfaces_to_take_down,
2399
 
                                 interfaces_to_take_down_size,
2400
 
                                 interface))){
2401
 
        ret_errno = take_down_interface(interface);
2402
 
        if(ret_errno != 0){
2403
 
          errno = ret_errno;
2404
 
          perror_plus("Failed to take down interface");
2405
 
        }
2406
 
      }
2407
 
      if(debug and (interfaces_to_take_down == NULL)){
2408
 
        fprintf_plus(stderr, "No interfaces needed to be taken"
2409
 
                     " down\n");
2410
 
      }
2411
 
    }
2412
 
    
2413
 
    lower_privileges_permanently();
 
2582
    ret_errno = raise_privileges();
 
2583
    if(ret_errno != 0){
 
2584
      errno = ret_errno;
 
2585
      perror_plus("Failed to raise privileges");
 
2586
    } else {
 
2587
      
 
2588
      /* Run network hooks */
 
2589
      run_network_hooks("stop", interfaces_hooks != NULL ?
 
2590
                        interfaces_hooks : "", delay);
 
2591
      
 
2592
      /* Take down the network interfaces which were brought up */
 
2593
      {
 
2594
        char *interface = NULL;
 
2595
        while((interface=argz_next(interfaces_to_take_down,
 
2596
                                   interfaces_to_take_down_size,
 
2597
                                   interface))){
 
2598
          ret_errno = take_down_interface(interface);
 
2599
          if(ret_errno != 0){
 
2600
            errno = ret_errno;
 
2601
            perror_plus("Failed to take down interface");
 
2602
          }
 
2603
        }
 
2604
        if(debug and (interfaces_to_take_down == NULL)){
 
2605
          fprintf_plus(stderr, "No interfaces needed to be taken"
 
2606
                       " down\n");
 
2607
        }
 
2608
      }
 
2609
    }
 
2610
    
 
2611
    ret_errno = lower_privileges_permanently();
 
2612
    if(ret_errno != 0){
 
2613
      errno = ret_errno;
 
2614
      perror_plus("Failed to lower privileges permanently");
 
2615
    }
2414
2616
  }
2415
2617
  
2416
2618
  free(interfaces_to_take_down);
2417
2619
  free(interfaces_hooks);
2418
2620
  
2419
2621
  /* Removes the GPGME temp directory and all files inside */
2420
 
  if(tempdir_created){
 
2622
  if(tempdir != NULL){
2421
2623
    struct dirent **direntries = NULL;
2422
 
    struct dirent *direntry = NULL;
2423
 
    int numentries = scandir(tempdir, &direntries, notdotentries,
2424
 
                             alphasort);
2425
 
    if (numentries > 0){
2426
 
      for(int i = 0; i < numentries; i++){
2427
 
        direntry = direntries[i];
2428
 
        char *fullname = NULL;
2429
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
2430
 
                       direntry->d_name);
2431
 
        if(ret < 0){
2432
 
          perror_plus("asprintf");
2433
 
          continue;
2434
 
        }
2435
 
        ret = remove(fullname);
2436
 
        if(ret == -1){
2437
 
          fprintf_plus(stderr, "remove(\"%s\"): %s\n", fullname,
2438
 
                       strerror(errno));
2439
 
        }
2440
 
        free(fullname);
 
2624
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY |
 
2625
                                                  O_NOFOLLOW));
 
2626
    if(tempdir_fd == -1){
 
2627
      perror_plus("open");
 
2628
    } else {
 
2629
#ifdef __GLIBC__
 
2630
#if __GLIBC_PREREQ(2, 15)
 
2631
      int numentries = scandirat(tempdir_fd, ".", &direntries,
 
2632
                                 notdotentries, alphasort);
 
2633
#else  /* not __GLIBC_PREREQ(2, 15) */
 
2634
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2635
                               alphasort);
 
2636
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
2637
#else   /* not __GLIBC__ */
 
2638
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2639
                               alphasort);
 
2640
#endif  /* not __GLIBC__ */
 
2641
      if(numentries >= 0){
 
2642
        for(int i = 0; i < numentries; i++){
 
2643
          ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
 
2644
          if(ret == -1){
 
2645
            fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
 
2646
                         " \"%s\", 0): %s\n", tempdir,
 
2647
                         direntries[i]->d_name, strerror(errno));
 
2648
          }
 
2649
          free(direntries[i]);
 
2650
        }
 
2651
        
 
2652
        /* need to clean even if 0 because man page doesn't specify */
 
2653
        free(direntries);
 
2654
        if(numentries == -1){
 
2655
          perror_plus("scandir");
 
2656
        }
 
2657
        ret = rmdir(tempdir);
 
2658
        if(ret == -1 and errno != ENOENT){
 
2659
          perror_plus("rmdir");
 
2660
        }
2441
2661
      }
2442
 
    }
2443
 
 
2444
 
    /* need to clean even if 0 because man page doesn't specify */
2445
 
    free(direntries);
2446
 
    if (numentries == -1){
2447
 
      perror_plus("scandir");
2448
 
    }
2449
 
    ret = rmdir(tempdir);
2450
 
    if(ret == -1 and errno != ENOENT){
2451
 
      perror_plus("rmdir");
 
2662
      TEMP_FAILURE_RETRY(close(tempdir_fd));
2452
2663
    }
2453
2664
  }
2454
2665