/mandos/release

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

« back to all changes in this revision

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

  • Committer: Teddy Hogeborn
  • Date: 2014-07-25 23:16:04 UTC
  • mto: (237.7.272 trunk)
  • mto: This revision was merged to the branch mainline in revision 321.
  • Revision ID: teddy@recompile.se-20140725231604-f5c4f82rn2o5ll1k
Use the .items() method instead of .iteritems().

This is strictly not a Python 2.7 change, but Python 2.7 backported
the new .viewitems() from Python 3, and instead of changing .items()
to .viewitems() and later having to change them all into .items()
again in Python 3, I opted to just change all .iteritems() to .items()
so the code will work both now and with Python 3.  The slowdown with
Python 2 is not significant, and with Python 3 it will again be fast.

* mandos (Client.__init__): Use .items() instead of .iteritems().
  (DBusObjectWithProperties.Introspect): - '' -
  (alternate_dbus_interfaces/wrapper): - '' -
  (main): - '' -
* mandos-ctl (main): - '' -

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
 
180
185
  perror(print_text);
181
186
}
182
187
 
183
 
__attribute__((format (gnu_printf, 2, 3)))
 
188
__attribute__((format (gnu_printf, 2, 3), nonnull))
184
189
int fprintf_plus(FILE *stream, const char *format, ...){
185
190
  va_list ap;
186
191
  va_start (ap, format);
187
192
  
188
193
  TEMP_FAILURE_RETRY(fprintf(stream, "Mandos plugin %s: ",
189
194
                             program_invocation_short_name));
190
 
  return TEMP_FAILURE_RETRY(vfprintf(stream, format, ap));
 
195
  return (int)TEMP_FAILURE_RETRY(vfprintf(stream, format, ap));
191
196
}
192
197
 
193
198
/*
195
200
 * bytes. "buffer_capacity" is how much is currently allocated,
196
201
 * "buffer_length" is how much is already used.
197
202
 */
 
203
__attribute__((nonnull, warn_unused_result))
198
204
size_t incbuffer(char **buffer, size_t buffer_length,
199
205
                 size_t buffer_capacity){
200
206
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
201
 
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
202
 
    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;
203
213
      return 0;
204
214
    }
 
215
    *buffer = new_buf;
205
216
    buffer_capacity += BUFFER_SIZE;
206
217
  }
207
218
  return buffer_capacity;
208
219
}
209
220
 
210
221
/* Add server to set of servers to retry periodically */
 
222
__attribute__((nonnull, warn_unused_result))
211
223
bool add_server(const char *ip, in_port_t port, AvahiIfIndex if_index,
212
224
                int af, server **current_server){
213
225
  int ret;
222
234
                          .af = af };
223
235
  if(new_server->ip == NULL){
224
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);
225
252
    return false;
226
253
  }
227
254
  /* Special case of first server */
229
256
    new_server->next = new_server;
230
257
    new_server->prev = new_server;
231
258
    *current_server = new_server;
232
 
  /* Place the new server last in the list */
233
259
  } else {
 
260
    /* Place the new server last in the list */
234
261
    new_server->next = *current_server;
235
262
    new_server->prev = (*current_server)->prev;
236
263
    new_server->prev->next = new_server;
237
264
    (*current_server)->prev = new_server;
238
265
  }
239
 
  ret = clock_gettime(CLOCK_MONOTONIC, &(*current_server)->last_seen);
240
 
  if(ret == -1){
241
 
    perror_plus("clock_gettime");
242
 
    return false;
243
 
  }
244
266
  return true;
245
267
}
246
268
 
247
269
/* 
248
270
 * Initialize GPGME.
249
271
 */
250
 
static bool init_gpgme(const char *seckey, const char *pubkey,
251
 
                       const char *tempdir, mandos_context *mc){
 
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){
252
277
  gpgme_error_t rc;
253
278
  gpgme_engine_info_t engine_info;
254
279
  
255
280
  /*
256
281
   * Helper function to insert pub and seckey to the engine keyring.
257
282
   */
258
 
  bool import_key(const char *filename){
 
283
  bool import_key(const char * const filename){
259
284
    int ret;
260
285
    int fd;
261
286
    gpgme_data_t pgp_data;
342
367
 * Decrypt OpenPGP data.
343
368
 * Returns -1 on error
344
369
 */
 
370
__attribute__((nonnull, warn_unused_result))
345
371
static ssize_t pgp_packet_decrypt(const char *cryptotext,
346
372
                                  size_t crypto_size,
347
373
                                  char **plaintext,
467
493
  return plaintext_length;
468
494
}
469
495
 
470
 
static const char * safer_gnutls_strerror(int value){
 
496
__attribute__((warn_unused_result))
 
497
static const char *safer_gnutls_strerror(int value){
471
498
  const char *ret = gnutls_strerror(value);
472
499
  if(ret == NULL)
473
500
    ret = "(unknown)";
475
502
}
476
503
 
477
504
/* GnuTLS log function callback */
 
505
__attribute__((nonnull))
478
506
static void debuggnutls(__attribute__((unused)) int level,
479
507
                        const char* string){
480
508
  fprintf_plus(stderr, "GnuTLS: %s", string);
481
509
}
482
510
 
 
511
__attribute__((nonnull, warn_unused_result))
483
512
static int init_gnutls_global(const char *pubkeyfilename,
484
513
                              const char *seckeyfilename,
485
514
                              mandos_context *mc){
559
588
  return -1;
560
589
}
561
590
 
 
591
__attribute__((nonnull, warn_unused_result))
562
592
static int init_gnutls_session(gnutls_session_t *session,
563
593
                               mandos_context *mc){
564
594
  int ret;
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
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
  
 
690
  /* If the interface is specified and we have a list of interfaces */
662
691
  if(if_index != AVAHI_IF_UNSPEC and mc->interfaces != NULL){
663
692
    /* Check if the interface is one of the interfaces we are using */
664
693
    bool match = false;
673
702
      }
674
703
    }
675
704
    if(not match){
 
705
      /* This interface does not match any in the list, so we don't
 
706
         connect to the server */
676
707
      if(debug){
677
708
        char interface[IF_NAMESIZE];
678
709
        if(if_indextoname((unsigned int)if_index, interface) == NULL){
713
744
  
714
745
  memset(&to, 0, sizeof(to));
715
746
  if(af == AF_INET6){
716
 
    to.in6.sin6_family = (sa_family_t)af;
717
 
    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);
718
749
  } else {                      /* IPv4 */
719
 
    to.in.sin_family = (sa_family_t)af;
720
 
    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);
721
752
  }
722
753
  if(ret < 0 ){
723
754
    int e = errno;
732
763
    goto mandos_end;
733
764
  }
734
765
  if(af == AF_INET6){
735
 
    to.in6.sin6_port = htons(port);    
736
 
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
737
 
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
738
 
                                -Wunreachable-code*/
 
766
    ((struct sockaddr_in6 *)&to)->sin6_port = htons(port);
 
767
    if(IN6_IS_ADDR_LINKLOCAL
 
768
       (&((struct sockaddr_in6 *)&to)->sin6_addr)){
739
769
      if(if_index == AVAHI_IF_UNSPEC){
740
770
        fprintf_plus(stderr, "An IPv6 link-local address is"
741
771
                     " incomplete without a network interface\n");
743
773
        goto mandos_end;
744
774
      }
745
775
      /* Set the network interface number as scope */
746
 
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
776
      ((struct sockaddr_in6 *)&to)->sin6_scope_id = (uint32_t)if_index;
747
777
    }
748
778
  } else {
749
 
    to.in.sin_port = htons(port); /* Spurious warnings from
750
 
                                     -Wconversion and
751
 
                                     -Wunreachable-code */
 
779
    ((struct sockaddr_in *)&to)->sin_port = htons(port);
752
780
  }
753
781
  
754
782
  if(quit_now){
771
799
    }
772
800
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
773
801
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
774
 
    const char *pcret;
775
802
    if(af == AF_INET6){
776
 
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
777
 
                        sizeof(addrstr));
 
803
      ret = getnameinfo((struct sockaddr *)&to,
 
804
                        sizeof(struct sockaddr_in6),
 
805
                        addrstr, sizeof(addrstr), NULL, 0,
 
806
                        NI_NUMERICHOST);
778
807
    } else {
779
 
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
780
 
                        sizeof(addrstr));
 
808
      ret = getnameinfo((struct sockaddr *)&to,
 
809
                        sizeof(struct sockaddr_in),
 
810
                        addrstr, sizeof(addrstr), NULL, 0,
 
811
                        NI_NUMERICHOST);
781
812
    }
782
 
    if(pcret == NULL){
783
 
      perror_plus("inet_ntop");
784
 
    } else {
785
 
      if(strcmp(addrstr, ip) != 0){
786
 
        fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
787
 
      }
 
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);
788
819
    }
789
820
  }
790
821
  
794
825
  }
795
826
  
796
827
  if(af == AF_INET6){
797
 
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
828
    ret = connect(tcp_sd, (struct sockaddr *)&to,
 
829
                  sizeof(struct sockaddr_in6));
798
830
  } else {
799
 
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
831
    ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
832
                  sizeof(struct sockaddr_in));
800
833
  }
801
834
  if(ret < 0){
802
 
    if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
835
    if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
803
836
      int e = errno;
804
837
      perror_plus("connect");
805
838
      errno = e;
1020
1053
  return retval;
1021
1054
}
1022
1055
 
 
1056
__attribute__((nonnull))
1023
1057
static void resolve_callback(AvahiSServiceResolver *r,
1024
1058
                             AvahiIfIndex interface,
1025
1059
                             AvahiProtocol proto,
1033
1067
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
1034
1068
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
1035
1069
                             flags,
1036
 
                             void* mc){
 
1070
                             void *mc){
1037
1071
  if(r == NULL){
1038
1072
    return;
1039
1073
  }
1042
1076
     timed out */
1043
1077
  
1044
1078
  if(quit_now){
 
1079
    avahi_s_service_resolver_free(r);
1045
1080
    return;
1046
1081
  }
1047
1082
  
1092
1127
                            const char *domain,
1093
1128
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
1094
1129
                            flags,
1095
 
                            void* mc){
 
1130
                            void *mc){
1096
1131
  if(b == NULL){
1097
1132
    return;
1098
1133
  }
1158
1193
  errno = old_errno;
1159
1194
}
1160
1195
 
 
1196
__attribute__((nonnull, warn_unused_result))
1161
1197
bool get_flags(const char *ifname, struct ifreq *ifr){
1162
1198
  int ret;
1163
1199
  error_t ret_errno;
1182
1218
  return true;
1183
1219
}
1184
1220
 
 
1221
__attribute__((nonnull, warn_unused_result))
1185
1222
bool good_flags(const char *ifname, const struct ifreq *ifr){
1186
1223
  
1187
1224
  /* Reject the loopback device */
1229
1266
 * corresponds to an acceptable network device.
1230
1267
 * (This function is passed to scandir(3) as a filter function.)
1231
1268
 */
 
1269
__attribute__((nonnull, warn_unused_result))
1232
1270
int good_interface(const struct dirent *if_entry){
1233
1271
  if(if_entry->d_name[0] == '.'){
1234
1272
    return 0;
1252
1290
/* 
1253
1291
 * This function determines if a network interface is up.
1254
1292
 */
 
1293
__attribute__((nonnull, warn_unused_result))
1255
1294
bool interface_is_up(const char *interface){
1256
1295
  struct ifreq ifr;
1257
1296
  if(not get_flags(interface, &ifr)){
1268
1307
/* 
1269
1308
 * This function determines if a network interface is running
1270
1309
 */
 
1310
__attribute__((nonnull, warn_unused_result))
1271
1311
bool interface_is_running(const char *interface){
1272
1312
  struct ifreq ifr;
1273
1313
  if(not get_flags(interface, &ifr)){
1281
1321
  return (bool)(ifr.ifr_flags & IFF_RUNNING);
1282
1322
}
1283
1323
 
 
1324
__attribute__((nonnull, pure, warn_unused_result))
1284
1325
int notdotentries(const struct dirent *direntry){
1285
1326
  /* Skip "." and ".." */
1286
1327
  if(direntry->d_name[0] == '.'
1293
1334
}
1294
1335
 
1295
1336
/* Is this directory entry a runnable program? */
 
1337
__attribute__((nonnull, warn_unused_result))
1296
1338
int runnable_hook(const struct dirent *direntry){
1297
1339
  int ret;
1298
1340
  size_t sret;
1306
1348
  sret = strspn(direntry->d_name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1307
1349
                "abcdefghijklmnopqrstuvwxyz"
1308
1350
                "0123456789"
1309
 
                "_-");
 
1351
                "_.-");
1310
1352
  if((direntry->d_name)[sret] != '\0'){
1311
1353
    /* Contains non-allowed characters */
1312
1354
    if(debug){
1316
1358
    return 0;
1317
1359
  }
1318
1360
  
1319
 
  char *fullname = NULL;
1320
 
  ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1321
 
  if(ret < 0){
1322
 
    perror_plus("asprintf");
1323
 
    return 0;
1324
 
  }
1325
 
  
1326
 
  ret = stat(fullname, &st);
 
1361
  ret = fstatat(hookdir_fd, direntry->d_name, &st, 0);
1327
1362
  if(ret == -1){
1328
1363
    if(debug){
1329
1364
      perror_plus("Could not stat hook");
1353
1388
  return 1;
1354
1389
}
1355
1390
 
 
1391
__attribute__((nonnull, warn_unused_result))
1356
1392
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval,
1357
1393
                            mandos_context *mc){
1358
1394
  int ret;
1362
1398
  
1363
1399
  while(true){
1364
1400
    if(mc->current_server == NULL){
1365
 
      if (debug){
 
1401
      if(debug){
1366
1402
        fprintf_plus(stderr, "Wait until first server is found."
1367
1403
                     " No timeout!\n");
1368
1404
      }
1369
1405
      ret = avahi_simple_poll_iterate(s, -1);
1370
1406
    } else {
1371
 
      if (debug){
 
1407
      if(debug){
1372
1408
        fprintf_plus(stderr, "Check current_server if we should run"
1373
1409
                     " it, or wait\n");
1374
1410
      }
1391
1427
                     - ((intmax_t)waited_time.tv_sec * 1000))
1392
1428
                    - ((intmax_t)waited_time.tv_nsec / 1000000));
1393
1429
      
1394
 
      if (debug){
 
1430
      if(debug){
1395
1431
        fprintf_plus(stderr, "Blocking for %" PRIdMAX " ms\n",
1396
1432
                     block_time);
1397
1433
      }
1419
1455
      ret = avahi_simple_poll_iterate(s, (int)block_time);
1420
1456
    }
1421
1457
    if(ret != 0){
1422
 
      if (ret > 0 or errno != EINTR){
 
1458
      if(ret > 0 or errno != EINTR){
1423
1459
        return (ret != 1) ? ret : 0;
1424
1460
      }
1425
1461
    }
1427
1463
}
1428
1464
 
1429
1465
/* Set effective uid to 0, return errno */
 
1466
__attribute__((warn_unused_result))
1430
1467
error_t raise_privileges(void){
1431
1468
  error_t old_errno = errno;
1432
1469
  error_t ret_errno = 0;
1433
1470
  if(seteuid(0) == -1){
1434
1471
    ret_errno = errno;
1435
 
    perror_plus("seteuid");
1436
1472
  }
1437
1473
  errno = old_errno;
1438
1474
  return ret_errno;
1439
1475
}
1440
1476
 
1441
1477
/* Set effective and real user ID to 0.  Return errno. */
 
1478
__attribute__((warn_unused_result))
1442
1479
error_t raise_privileges_permanently(void){
1443
1480
  error_t old_errno = errno;
1444
1481
  error_t ret_errno = raise_privileges();
1448
1485
  }
1449
1486
  if(setuid(0) == -1){
1450
1487
    ret_errno = errno;
1451
 
    perror_plus("seteuid");
1452
1488
  }
1453
1489
  errno = old_errno;
1454
1490
  return ret_errno;
1455
1491
}
1456
1492
 
1457
1493
/* Set effective user ID to unprivileged saved user ID */
 
1494
__attribute__((warn_unused_result))
1458
1495
error_t lower_privileges(void){
1459
1496
  error_t old_errno = errno;
1460
1497
  error_t ret_errno = 0;
1461
1498
  if(seteuid(uid) == -1){
1462
1499
    ret_errno = errno;
1463
 
    perror_plus("seteuid");
1464
1500
  }
1465
1501
  errno = old_errno;
1466
1502
  return ret_errno;
1467
1503
}
1468
1504
 
1469
1505
/* Lower privileges permanently */
 
1506
__attribute__((warn_unused_result))
1470
1507
error_t lower_privileges_permanently(void){
1471
1508
  error_t old_errno = errno;
1472
1509
  error_t ret_errno = 0;
1473
1510
  if(setuid(uid) == -1){
1474
1511
    ret_errno = errno;
1475
 
    perror_plus("setuid");
1476
1512
  }
1477
1513
  errno = old_errno;
1478
1514
  return ret_errno;
1479
1515
}
1480
1516
 
1481
 
bool run_network_hooks(const char *mode, const char *interface,
 
1517
__attribute__((nonnull))
 
1518
void run_network_hooks(const char *mode, const char *interface,
1482
1519
                       const float delay){
1483
 
  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
  }
1484
1551
  struct dirent *direntry;
1485
1552
  int ret;
1486
 
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
1487
 
                         alphasort);
1488
 
  if(numhooks == -1){
1489
 
    if(errno == ENOENT){
1490
 
      if(debug){
1491
 
        fprintf_plus(stderr, "Network hook directory \"%s\" not"
1492
 
                     " found\n", hookdir);
1493
 
      }
1494
 
    } else {
1495
 
      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);
1496
1559
    }
1497
 
  } else {
1498
 
    int devnull = open("/dev/null", O_RDONLY);
1499
 
    for(int i = 0; i < numhooks; i++){
1500
 
      direntry = direntries[i];
1501
 
      char *fullname = NULL;
1502
 
      ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1503
 
      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){
1504
1621
        perror_plus("asprintf");
1505
 
        continue;
1506
 
      }
1507
 
      if(debug){
1508
 
        fprintf_plus(stderr, "Running network hook \"%s\"\n",
1509
 
                     direntry->d_name);
1510
 
      }
1511
 
      pid_t hook_pid = fork();
1512
 
      if(hook_pid == 0){
1513
 
        /* Child */
1514
 
        /* Raise privileges */
1515
 
        raise_privileges_permanently();
1516
 
        /* Set group */
1517
 
        errno = 0;
1518
 
        ret = setgid(0);
1519
 
        if(ret == -1){
1520
 
          perror_plus("setgid");
1521
 
        }
1522
 
        /* Reset supplementary groups */
1523
 
        errno = 0;
1524
 
        ret = setgroups(0, NULL);
1525
 
        if(ret == -1){
1526
 
          perror_plus("setgroups");
1527
 
        }
1528
 
        dup2(devnull, STDIN_FILENO);
1529
 
        close(devnull);
1530
 
        dup2(STDERR_FILENO, STDOUT_FILENO);
1531
 
        ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
1532
 
        if(ret == -1){
1533
 
          perror_plus("setenv");
1534
 
          _exit(EX_OSERR);
1535
 
        }
1536
 
        ret = setenv("DEVICE", interface, 1);
1537
 
        if(ret == -1){
1538
 
          perror_plus("setenv");
1539
 
          _exit(EX_OSERR);
1540
 
        }
1541
 
        ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
1542
 
        if(ret == -1){
1543
 
          perror_plus("setenv");
1544
 
          _exit(EX_OSERR);
1545
 
        }
1546
 
        ret = setenv("MODE", mode, 1);
1547
 
        if(ret == -1){
1548
 
          perror_plus("setenv");
1549
 
          _exit(EX_OSERR);
1550
 
        }
1551
 
        char *delaystring;
1552
 
        ret = asprintf(&delaystring, "%f", delay);
1553
 
        if(ret == -1){
1554
 
          perror_plus("asprintf");
1555
 
          _exit(EX_OSERR);
1556
 
        }
1557
 
        ret = setenv("DELAY", delaystring, 1);
1558
 
        if(ret == -1){
1559
 
          free(delaystring);
1560
 
          perror_plus("setenv");
1561
 
          _exit(EX_OSERR);
1562
 
        }
 
1622
        _exit(EX_OSERR);
 
1623
      }
 
1624
      ret = setenv("DELAY", delaystring, 1);
 
1625
      if(ret == -1){
1563
1626
        free(delaystring);
1564
 
        if(connect_to != NULL){
1565
 
          ret = setenv("CONNECT", connect_to, 1);
1566
 
          if(ret == -1){
1567
 
            perror_plus("setenv");
1568
 
            _exit(EX_OSERR);
1569
 
          }
1570
 
        }
1571
 
        if(execl(fullname, direntry->d_name, mode, NULL) == -1){
1572
 
          perror_plus("execl");
1573
 
          _exit(EXIT_FAILURE);
1574
 
        }
 
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;
1575
1673
      } else {
1576
 
        int status;
1577
 
        if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1578
 
          perror_plus("waitpid");
1579
 
          free(fullname);
1580
 
          continue;
1581
 
        }
1582
 
        if(WIFEXITED(status)){
1583
 
          if(WEXITSTATUS(status) != 0){
1584
 
            fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1585
 
                         " with status %d\n", direntry->d_name,
1586
 
                         WEXITSTATUS(status));
1587
 
            free(fullname);
1588
 
            continue;
1589
 
          }
1590
 
        } else if(WIFSIGNALED(status)){
1591
 
          fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1592
 
                       " signal %d\n", direntry->d_name,
1593
 
                       WTERMSIG(status));
1594
 
          free(fullname);
1595
 
          continue;
1596
 
        } else {
1597
 
          fprintf_plus(stderr, "Warning: network hook \"%s\""
1598
 
                       " crashed\n", direntry->d_name);
1599
 
          free(fullname);
1600
 
          continue;
1601
 
        }
1602
 
      }
1603
 
      free(fullname);
1604
 
      if(debug){
1605
 
        fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1606
 
                     direntry->d_name);
1607
 
      }
1608
 
    }
1609
 
    close(devnull);
1610
 
  }
1611
 
  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);
1612
1693
}
1613
1694
 
 
1695
__attribute__((nonnull, warn_unused_result))
1614
1696
error_t bring_up_interface(const char *const interface,
1615
1697
                           const float delay){
1616
 
  int sd = -1;
1617
1698
  error_t old_errno = errno;
1618
 
  error_t ret_errno = 0;
1619
 
  int ret, ret_setflags;
 
1699
  int ret;
1620
1700
  struct ifreq network;
1621
1701
  unsigned int if_index = if_nametoindex(interface);
1622
1702
  if(if_index == 0){
1631
1711
  }
1632
1712
  
1633
1713
  if(not interface_is_up(interface)){
1634
 
    if(not get_flags(interface, &network) and debug){
 
1714
    error_t ret_errno = 0, ioctl_errno = 0;
 
1715
    if(not get_flags(interface, &network)){
1635
1716
      ret_errno = errno;
1636
1717
      fprintf_plus(stderr, "Failed to get flags for interface "
1637
1718
                   "\"%s\"\n", interface);
 
1719
      errno = old_errno;
1638
1720
      return ret_errno;
1639
1721
    }
1640
 
    network.ifr_flags |= IFF_UP;
 
1722
    network.ifr_flags |= IFF_UP; /* set flag */
1641
1723
    
1642
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1643
 
    if(sd < 0){
 
1724
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1725
    if(sd == -1){
1644
1726
      ret_errno = errno;
1645
1727
      perror_plus("socket");
1646
1728
      errno = old_errno;
1647
1729
      return ret_errno;
1648
1730
    }
1649
 
  
 
1731
    
1650
1732
    if(quit_now){
1651
 
      close(sd);
 
1733
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1734
      if(ret == -1){
 
1735
        perror_plus("close");
 
1736
      }
1652
1737
      errno = old_errno;
1653
1738
      return EINTR;
1654
1739
    }
1658
1743
                   interface);
1659
1744
    }
1660
1745
    
1661
 
    /* Raise priviliges */
1662
 
    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
    }
1663
1752
    
1664
1753
#ifdef __linux__
1665
 
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1666
 
       messages about the network interface to mess up the prompt */
1667
 
    int ret_linux = klogctl(8, NULL, 5);
1668
 
    bool restore_loglevel = true;
1669
 
    if(ret_linux == -1){
1670
 
      restore_loglevel = false;
1671
 
      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
      }
1672
1765
    }
1673
1766
#endif  /* __linux__ */
1674
 
    ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
1675
 
    ret_errno = errno;
 
1767
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1768
    ioctl_errno = errno;
1676
1769
#ifdef __linux__
1677
1770
    if(restore_loglevel){
1678
1771
      ret_linux = klogctl(7, NULL, 0);
1682
1775
    }
1683
1776
#endif  /* __linux__ */
1684
1777
    
1685
 
    /* Lower privileges */
1686
 
    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
    }
1687
1787
    
1688
1788
    /* Close the socket */
1689
1789
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
1692
1792
    }
1693
1793
    
1694
1794
    if(ret_setflags == -1){
1695
 
      errno = ret_errno;
 
1795
      errno = ioctl_errno;
1696
1796
      perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1697
1797
      errno = old_errno;
1698
 
      return ret_errno;
 
1798
      return ioctl_errno;
1699
1799
    }
1700
1800
  } else if(debug){
1701
1801
    fprintf_plus(stderr, "Interface \"%s\" is already up; good\n",
1719
1819
  return 0;
1720
1820
}
1721
1821
 
 
1822
__attribute__((nonnull, warn_unused_result))
1722
1823
error_t take_down_interface(const char *const interface){
1723
 
  int sd = -1;
1724
1824
  error_t old_errno = errno;
1725
 
  error_t ret_errno = 0;
1726
 
  int ret, ret_setflags;
1727
1825
  struct ifreq network;
1728
1826
  unsigned int if_index = if_nametoindex(interface);
1729
1827
  if(if_index == 0){
1732
1830
    return ENXIO;
1733
1831
  }
1734
1832
  if(interface_is_up(interface)){
 
1833
    error_t ret_errno = 0, ioctl_errno = 0;
1735
1834
    if(not get_flags(interface, &network) and debug){
1736
1835
      ret_errno = errno;
1737
1836
      fprintf_plus(stderr, "Failed to get flags for interface "
1738
1837
                   "\"%s\"\n", interface);
 
1838
      errno = old_errno;
1739
1839
      return ret_errno;
1740
1840
    }
1741
1841
    network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1742
1842
    
1743
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1744
 
    if(sd < 0){
 
1843
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1844
    if(sd == -1){
1745
1845
      ret_errno = errno;
1746
1846
      perror_plus("socket");
1747
1847
      errno = old_errno;
1753
1853
                   interface);
1754
1854
    }
1755
1855
    
1756
 
    /* Raise priviliges */
1757
 
    raise_privileges();
1758
 
    
1759
 
    ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
1760
 
    ret_errno = errno;
1761
 
    
1762
 
    /* Lower privileges */
1763
 
    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
    }
1764
1875
    
1765
1876
    /* Close the socket */
1766
 
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1877
    int ret = (int)TEMP_FAILURE_RETRY(close(sd));
1767
1878
    if(ret == -1){
1768
1879
      perror_plus("close");
1769
1880
    }
1770
1881
    
1771
1882
    if(ret_setflags == -1){
1772
 
      errno = ret_errno;
 
1883
      errno = ioctl_errno;
1773
1884
      perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
1774
1885
      errno = old_errno;
1775
 
      return ret_errno;
 
1886
      return ioctl_errno;
1776
1887
    }
1777
1888
  } else if(debug){
1778
1889
    fprintf_plus(stderr, "Interface \"%s\" is already down; odd\n",
1786
1897
int main(int argc, char *argv[]){
1787
1898
  mandos_context mc = { .server = NULL, .dh_bits = 1024,
1788
1899
                        .priority = "SECURE256:!CTYPE-X.509:"
1789
 
                        "+CTYPE-OPENPGP", .current_server = NULL, 
 
1900
                        "+CTYPE-OPENPGP", .current_server = NULL,
1790
1901
                        .interfaces = NULL, .interfaces_size = 0 };
1791
1902
  AvahiSServiceBrowser *sb = NULL;
1792
1903
  error_t ret_errno;
1796
1907
  int exitcode = EXIT_SUCCESS;
1797
1908
  char *interfaces_to_take_down = NULL;
1798
1909
  size_t interfaces_to_take_down_size = 0;
1799
 
  char tempdir[] = "/tmp/mandosXXXXXX";
1800
 
  bool tempdir_created = false;
 
1910
  char run_tempdir[] = "/run/tmp/mandosXXXXXX";
 
1911
  char old_tempdir[] = "/tmp/mandosXXXXXX";
 
1912
  char *tempdir = NULL;
1801
1913
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1802
1914
  const char *seckey = PATHDIR "/" SECKEY;
1803
1915
  const char *pubkey = PATHDIR "/" PUBKEY;
1804
1916
  char *interfaces_hooks = NULL;
1805
 
  size_t interfaces_hooks_size = 0;
1806
1917
  
1807
1918
  bool gnutls_initialized = false;
1808
1919
  bool gpgme_initialized = false;
1986
2097
    /* Work around Debian bug #633582:
1987
2098
       <http://bugs.debian.org/633582> */
1988
2099
    
1989
 
    /* Re-raise priviliges */
1990
 
    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 {
1991
2106
      struct stat st;
1992
2107
      
1993
2108
      if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
2033
2148
      }
2034
2149
    
2035
2150
      /* Lower privileges */
2036
 
      lower_privileges();
 
2151
      ret_errno = lower_privileges();
 
2152
      if(ret_errno != 0){
 
2153
        errno = ret_errno;
 
2154
        perror_plus("Failed to lower privileges");
 
2155
      }
2037
2156
    }
2038
2157
  }
2039
2158
  
2063
2182
        goto end;
2064
2183
      }
2065
2184
      memcpy(interfaces_hooks, mc.interfaces, mc.interfaces_size);
2066
 
      interfaces_hooks_size = mc.interfaces_size;
2067
 
      argz_stringify(interfaces_hooks, interfaces_hooks_size,
2068
 
                     (int)',');
2069
 
    }
2070
 
    if(not run_network_hooks("start", interfaces_hooks != NULL ?
2071
 
                             interfaces_hooks : "", delay)){
2072
 
      goto end;
2073
 
    }
 
2185
      argz_stringify(interfaces_hooks, mc.interfaces_size, (int)',');
 
2186
    }
 
2187
    run_network_hooks("start", interfaces_hooks != NULL ?
 
2188
                      interfaces_hooks : "", delay);
2074
2189
  }
2075
2190
  
2076
2191
  if(not debug){
2154
2269
  
2155
2270
  /* If no interfaces were specified, make a list */
2156
2271
  if(mc.interfaces == NULL){
2157
 
    struct dirent **direntries;
 
2272
    struct dirent **direntries = NULL;
2158
2273
    /* Look for any good interfaces */
2159
2274
    ret = scandir(sys_class_net, &direntries, good_interface,
2160
2275
                  alphasort);
2164
2279
        ret_errno = argz_add(&mc.interfaces, &mc.interfaces_size,
2165
2280
                             direntries[i]->d_name);
2166
2281
        if(ret_errno != 0){
 
2282
          errno = ret_errno;
2167
2283
          perror_plus("argz_add");
 
2284
          free(direntries[i]);
2168
2285
          continue;
2169
2286
        }
2170
2287
        if(debug){
2171
2288
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
2172
2289
                       direntries[i]->d_name);
2173
2290
        }
 
2291
        free(direntries[i]);
2174
2292
      }
2175
2293
      free(direntries);
2176
2294
    } else {
2177
 
      free(direntries);
 
2295
      if(ret == 0){
 
2296
        free(direntries);
 
2297
      }
2178
2298
      fprintf_plus(stderr, "Could not find a network interface\n");
2179
2299
      exitcode = EXIT_FAILURE;
2180
2300
      goto end;
2181
2301
    }
2182
2302
  }
2183
2303
  
2184
 
  /* Bring up interfaces which are down */
 
2304
  /* Bring up interfaces which are down, and remove any "none"s */
2185
2305
  {
2186
2306
    char *interface = NULL;
2187
2307
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
2203
2323
        break;
2204
2324
      }
2205
2325
      bool interface_was_up = interface_is_up(interface);
2206
 
      ret = bring_up_interface(interface, delay);
 
2326
      errno = bring_up_interface(interface, delay);
2207
2327
      if(not interface_was_up){
2208
 
        if(ret != 0){
2209
 
          errno = ret;
 
2328
        if(errno != 0){
2210
2329
          perror_plus("Failed to bring up interface");
2211
2330
        } else {
2212
 
          ret_errno = argz_add(&interfaces_to_take_down,
2213
 
                               &interfaces_to_take_down_size,
2214
 
                               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
          }
2215
2337
        }
2216
2338
      }
2217
2339
    }
2246
2368
    goto end;
2247
2369
  }
2248
2370
  
2249
 
  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){
2250
2381
    perror_plus("mkdtemp");
2251
2382
    goto end;
2252
2383
  }
2253
 
  tempdir_created = true;
2254
2384
  
2255
2385
  if(quit_now){
2256
2386
    goto end;
2328
2458
        fprintf_plus(stderr, "Retrying in %d seconds\n",
2329
2459
                     (int)retry_interval);
2330
2460
      }
2331
 
      sleep((int)retry_interval);
 
2461
      sleep((unsigned int)retry_interval);
2332
2462
    }
2333
2463
    
2334
 
    if (not quit_now){
 
2464
    if(not quit_now){
2335
2465
      exitcode = EXIT_SUCCESS;
2336
2466
    }
2337
2467
    
2392
2522
  if(debug){
2393
2523
    fprintf_plus(stderr, "Starting Avahi loop search\n");
2394
2524
  }
2395
 
 
 
2525
  
2396
2526
  ret = avahi_loop_with_timeout(simple_poll,
2397
2527
                                (int)(retry_interval * 1000), &mc);
2398
2528
  if(debug){
2434
2564
    mc.current_server->prev->next = NULL;
2435
2565
    while(mc.current_server != NULL){
2436
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
2437
2575
      free(mc.current_server);
2438
2576
      mc.current_server = next;
2439
2577
    }
2440
2578
  }
2441
2579
  
2442
 
  /* Re-raise priviliges */
 
2580
  /* Re-raise privileges */
2443
2581
  {
2444
 
    raise_privileges();
2445
 
    
2446
 
    /* Run network hooks */
2447
 
    run_network_hooks("stop", interfaces_hooks != NULL ?
2448
 
                      interfaces_hooks : "", delay);
2449
 
    
2450
 
    /* Take down the network interfaces which were brought up */
2451
 
    {
2452
 
      char *interface = NULL;
2453
 
      while((interface=argz_next(interfaces_to_take_down,
2454
 
                                 interfaces_to_take_down_size,
2455
 
                                 interface))){
2456
 
        ret_errno = take_down_interface(interface);
2457
 
        if(ret_errno != 0){
2458
 
          errno = ret_errno;
2459
 
          perror_plus("Failed to take down interface");
2460
 
        }
2461
 
      }
2462
 
      if(debug and (interfaces_to_take_down == NULL)){
2463
 
        fprintf_plus(stderr, "No interfaces needed to be taken"
2464
 
                     " down\n");
2465
 
      }
2466
 
    }
2467
 
    
2468
 
    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
    }
2469
2616
  }
2470
2617
  
2471
2618
  free(interfaces_to_take_down);
2472
2619
  free(interfaces_hooks);
2473
2620
  
2474
2621
  /* Removes the GPGME temp directory and all files inside */
2475
 
  if(tempdir_created){
 
2622
  if(tempdir != NULL){
2476
2623
    struct dirent **direntries = NULL;
2477
 
    struct dirent *direntry = NULL;
2478
 
    int numentries = scandir(tempdir, &direntries, notdotentries,
2479
 
                             alphasort);
2480
 
    if (numentries > 0){
2481
 
      for(int i = 0; i < numentries; i++){
2482
 
        direntry = direntries[i];
2483
 
        char *fullname = NULL;
2484
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
2485
 
                       direntry->d_name);
2486
 
        if(ret < 0){
2487
 
          perror_plus("asprintf");
2488
 
          continue;
2489
 
        }
2490
 
        ret = remove(fullname);
2491
 
        if(ret == -1){
2492
 
          fprintf_plus(stderr, "remove(\"%s\"): %s\n", fullname,
2493
 
                       strerror(errno));
2494
 
        }
2495
 
        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
        }
2496
2661
      }
2497
 
    }
2498
 
 
2499
 
    /* need to clean even if 0 because man page doesn't specify */
2500
 
    free(direntries);
2501
 
    if (numentries == -1){
2502
 
      perror_plus("scandir");
2503
 
    }
2504
 
    ret = rmdir(tempdir);
2505
 
    if(ret == -1 and errno != ENOENT){
2506
 
      perror_plus("rmdir");
 
2662
      TEMP_FAILURE_RETRY(close(tempdir_fd));
2507
2663
    }
2508
2664
  }
2509
2665