229
249
new_server->next = new_server;
230
250
new_server->prev = new_server;
231
251
*current_server = new_server;
232
/* Place the new server last in the list */
253
/* Place the new server last in the list */
234
254
new_server->next = *current_server;
235
255
new_server->prev = (*current_server)->prev;
236
256
new_server->prev->next = new_server;
237
257
(*current_server)->prev = new_server;
239
ret = clock_gettime(CLOCK_MONOTONIC, &(*current_server)->last_seen);
241
perror_plus("clock_gettime");
248
263
* Initialize GPGME.
250
static bool init_gpgme(const char *seckey, const char *pubkey,
251
const char *tempdir, mandos_context *mc){
265
__attribute__((nonnull, warn_unused_result))
266
static bool init_gpgme(const char * const seckey,
267
const char * const pubkey,
268
const char * const tempdir,
252
270
gpgme_error_t rc;
253
271
gpgme_engine_info_t engine_info;
256
274
* Helper function to insert pub and seckey to the engine keyring.
258
bool import_key(const char *filename){
276
bool import_key(const char * const filename){
261
279
gpgme_data_t pgp_data;
743
793
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
744
794
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
746
795
if(af == AF_INET6){
747
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
796
ret = getnameinfo((struct sockaddr *)&to,
797
sizeof(struct sockaddr_in6),
798
addrstr, sizeof(addrstr), NULL, 0,
750
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
801
ret = getnameinfo((struct sockaddr *)&to,
802
sizeof(struct sockaddr_in),
803
addrstr, sizeof(addrstr), NULL, 0,
754
perror_plus("inet_ntop");
756
if(strcmp(addrstr, ip) != 0){
757
fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
806
if(ret == EAI_SYSTEM){
807
perror_plus("getnameinfo");
808
} else if(ret != 0) {
809
fprintf_plus(stderr, "getnameinfo: %s", gai_strerror(ret));
810
} else if(strcmp(addrstr, ip) != 0){
811
fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
1420
1478
if(setuid(0) == -1){
1421
1479
ret_errno = errno;
1422
perror_plus("seteuid");
1424
1481
errno = old_errno;
1425
1482
return ret_errno;
1428
1485
/* Set effective user ID to unprivileged saved user ID */
1486
__attribute__((warn_unused_result))
1429
1487
error_t lower_privileges(void){
1430
1488
error_t old_errno = errno;
1431
1489
error_t ret_errno = 0;
1432
1490
if(seteuid(uid) == -1){
1433
1491
ret_errno = errno;
1434
perror_plus("seteuid");
1436
1493
errno = old_errno;
1437
1494
return ret_errno;
1440
1497
/* Lower privileges permanently */
1498
__attribute__((warn_unused_result))
1441
1499
error_t lower_privileges_permanently(void){
1442
1500
error_t old_errno = errno;
1443
1501
error_t ret_errno = 0;
1444
1502
if(setuid(uid) == -1){
1445
1503
ret_errno = errno;
1446
perror_plus("setuid");
1448
1505
errno = old_errno;
1449
1506
return ret_errno;
1452
bool run_network_hooks(const char *mode, const char *interface,
1509
__attribute__((nonnull))
1510
void run_network_hooks(const char *mode, const char *interface,
1453
1511
const float delay){
1454
struct dirent **direntries;
1512
struct dirent **direntries = NULL;
1513
if(hookdir_fd == -1){
1514
hookdir_fd = open(hookdir, O_RDONLY);
1515
if(hookdir_fd == -1){
1516
if(errno == ENOENT){
1518
fprintf_plus(stderr, "Network hook directory \"%s\" not"
1519
" found\n", hookdir);
1522
perror_plus("open");
1528
#if __GLIBC_PREREQ(2, 15)
1529
int numhooks = scandirat(hookdir_fd, ".", &direntries,
1530
runnable_hook, alphasort);
1531
#else /* not __GLIBC_PREREQ(2, 15) */
1532
int numhooks = scandir(hookdir, &direntries, runnable_hook,
1534
#endif /* not __GLIBC_PREREQ(2, 15) */
1535
#else /* not __GLIBC__ */
1536
int numhooks = scandir(hookdir, &direntries, runnable_hook,
1538
#endif /* not __GLIBC__ */
1540
perror_plus("scandir");
1455
1543
struct dirent *direntry;
1457
int numhooks = scandir(hookdir, &direntries, runnable_hook,
1460
if(errno == ENOENT){
1462
fprintf_plus(stderr, "Network hook directory \"%s\" not"
1463
" found\n", hookdir);
1466
perror_plus("scandir");
1545
int devnull = open("/dev/null", O_RDONLY);
1546
for(int i = 0; i < numhooks; i++){
1547
direntry = direntries[i];
1549
fprintf_plus(stderr, "Running network hook \"%s\"\n",
1469
int devnull = open("/dev/null", O_RDONLY);
1470
for(int i = 0; i < numhooks; i++){
1471
direntry = direntries[i];
1472
char *fullname = NULL;
1473
ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1552
pid_t hook_pid = fork();
1555
/* Raise privileges */
1556
errno = raise_privileges_permanently();
1558
perror_plus("Failed to raise privileges");
1565
perror_plus("setgid");
1568
/* Reset supplementary groups */
1570
ret = setgroups(0, NULL);
1572
perror_plus("setgroups");
1575
ret = dup2(devnull, STDIN_FILENO);
1577
perror_plus("dup2(devnull, STDIN_FILENO)");
1580
ret = close(devnull);
1582
perror_plus("close");
1585
ret = dup2(STDERR_FILENO, STDOUT_FILENO);
1587
perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
1590
ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
1592
perror_plus("setenv");
1595
ret = setenv("DEVICE", interface, 1);
1597
perror_plus("setenv");
1600
ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
1602
perror_plus("setenv");
1605
ret = setenv("MODE", mode, 1);
1607
perror_plus("setenv");
1611
ret = asprintf(&delaystring, "%f", (double)delay);
1475
1613
perror_plus("asprintf");
1479
fprintf_plus(stderr, "Running network hook \"%s\"\n",
1482
pid_t hook_pid = fork();
1485
/* Raise privileges */
1486
raise_privileges_permanently();
1491
perror_plus("setgid");
1493
/* Reset supplementary groups */
1495
ret = setgroups(0, NULL);
1497
perror_plus("setgroups");
1499
dup2(devnull, STDIN_FILENO);
1501
dup2(STDERR_FILENO, STDOUT_FILENO);
1502
ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
1504
perror_plus("setenv");
1507
ret = setenv("DEVICE", interface, 1);
1509
perror_plus("setenv");
1512
ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
1514
perror_plus("setenv");
1517
ret = setenv("MODE", mode, 1);
1519
perror_plus("setenv");
1523
ret = asprintf(&delaystring, "%f", delay);
1525
perror_plus("asprintf");
1528
ret = setenv("DELAY", delaystring, 1);
1531
perror_plus("setenv");
1616
ret = setenv("DELAY", delaystring, 1);
1534
1618
free(delaystring);
1535
if(connect_to != NULL){
1536
ret = setenv("CONNECT", connect_to, 1);
1538
perror_plus("setenv");
1542
if(execl(fullname, direntry->d_name, mode, NULL) == -1){
1543
perror_plus("execl");
1544
_exit(EXIT_FAILURE);
1619
perror_plus("setenv");
1623
if(connect_to != NULL){
1624
ret = setenv("CONNECT", connect_to, 1);
1626
perror_plus("setenv");
1630
int hook_fd = openat(hookdir_fd, direntry->d_name, O_RDONLY);
1632
perror_plus("openat");
1633
_exit(EXIT_FAILURE);
1635
if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
1636
perror_plus("close");
1637
_exit(EXIT_FAILURE);
1639
if(fexecve(hook_fd, (char *const []){ direntry->d_name, NULL },
1641
perror_plus("fexecve");
1642
_exit(EXIT_FAILURE);
1646
if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1647
perror_plus("waitpid");
1650
if(WIFEXITED(status)){
1651
if(WEXITSTATUS(status) != 0){
1652
fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1653
" with status %d\n", direntry->d_name,
1654
WEXITSTATUS(status));
1657
} else if(WIFSIGNALED(status)){
1658
fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1659
" signal %d\n", direntry->d_name,
1548
if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1549
perror_plus("waitpid");
1553
if(WIFEXITED(status)){
1554
if(WEXITSTATUS(status) != 0){
1555
fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1556
" with status %d\n", direntry->d_name,
1557
WEXITSTATUS(status));
1561
} else if(WIFSIGNALED(status)){
1562
fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1563
" signal %d\n", direntry->d_name,
1568
fprintf_plus(stderr, "Warning: network hook \"%s\""
1569
" crashed\n", direntry->d_name);
1576
fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1663
fprintf_plus(stderr, "Warning: network hook \"%s\""
1664
" crashed\n", direntry->d_name);
1669
fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1674
if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
1675
perror_plus("close");
1682
__attribute__((nonnull, warn_unused_result))
1585
1683
error_t bring_up_interface(const char *const interface,
1586
1684
const float delay){
1588
1685
error_t old_errno = errno;
1589
error_t ret_errno = 0;
1590
int ret, ret_setflags;
1591
1687
struct ifreq network;
1592
1688
unsigned int if_index = if_nametoindex(interface);
1593
1689
if(if_index == 0){
2150
2278
free(direntries);
2153
2283
fprintf_plus(stderr, "Could not find a network interface\n");
2154
2284
exitcode = EXIT_FAILURE;
2289
/* Bring up interfaces which are down, and remove any "none"s */
2291
char *interface = NULL;
2292
while((interface = argz_next(mc.interfaces, mc.interfaces_size,
2294
/* If interface name is "none", stop bringing up interfaces.
2295
Also remove all instances of "none" from the list */
2296
if(strcmp(interface, "none") == 0){
2297
argz_delete(&mc.interfaces, &mc.interfaces_size,
2300
while((interface = argz_next(mc.interfaces,
2301
mc.interfaces_size, interface))){
2302
if(strcmp(interface, "none") == 0){
2303
argz_delete(&mc.interfaces, &mc.interfaces_size,
2310
bool interface_was_up = interface_is_up(interface);
2311
errno = bring_up_interface(interface, delay);
2312
if(not interface_was_up){
2314
perror_plus("Failed to bring up interface");
2316
errno = argz_add(&interfaces_to_take_down,
2317
&interfaces_to_take_down_size,
2320
perror_plus("argz_add");
2325
if(debug and (interfaces_to_take_down == NULL)){
2326
fprintf_plus(stderr, "No interfaces were brought up\n");
2159
2330
/* If we only got one interface, explicitly use only that one */
2160
2331
if(argz_count(mc.interfaces, mc.interfaces_size) == 1){
2403
/* Re-raise priviliges */
2557
/* Re-raise privileges */
2407
/* Run network hooks */
2408
run_network_hooks("stop", interfaces_hooks != NULL ?
2409
interfaces_hooks : "", delay);
2411
/* Take down the network interfaces which were brought up */
2413
char *interface = NULL;
2414
while((interface=argz_next(interfaces_to_take_down,
2415
interfaces_to_take_down_size,
2417
ret_errno = take_down_interface(interface);
2420
perror_plus("Failed to take down interface");
2423
if(debug and (interfaces_to_take_down == NULL)){
2424
fprintf_plus(stderr, "No interfaces needed to be taken"
2429
lower_privileges_permanently();
2559
ret_errno = raise_privileges();
2562
perror_plus("Failed to raise privileges");
2565
/* Run network hooks */
2566
run_network_hooks("stop", interfaces_hooks != NULL ?
2567
interfaces_hooks : "", delay);
2569
/* Take down the network interfaces which were brought up */
2571
char *interface = NULL;
2572
while((interface=argz_next(interfaces_to_take_down,
2573
interfaces_to_take_down_size,
2575
ret_errno = take_down_interface(interface);
2578
perror_plus("Failed to take down interface");
2581
if(debug and (interfaces_to_take_down == NULL)){
2582
fprintf_plus(stderr, "No interfaces needed to be taken"
2588
ret_errno = lower_privileges_permanently();
2591
perror_plus("Failed to lower privileges permanently");
2432
2595
free(interfaces_to_take_down);
2433
2596
free(interfaces_hooks);
2435
2598
/* Removes the GPGME temp directory and all files inside */
2436
if(tempdir_created){
2599
if(tempdir != NULL){
2437
2600
struct dirent **direntries = NULL;
2438
struct dirent *direntry = NULL;
2439
int numentries = scandir(tempdir, &direntries, notdotentries,
2441
if (numentries > 0){
2442
for(int i = 0; i < numentries; i++){
2443
direntry = direntries[i];
2444
char *fullname = NULL;
2445
ret = asprintf(&fullname, "%s/%s", tempdir,
2448
perror_plus("asprintf");
2451
ret = remove(fullname);
2453
fprintf_plus(stderr, "remove(\"%s\"): %s\n", fullname,
2601
int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY |
2603
if(tempdir_fd == -1){
2604
perror_plus("open");
2607
#if __GLIBC_PREREQ(2, 15)
2608
int numentries = scandirat(tempdir_fd, ".", &direntries,
2609
notdotentries, alphasort);
2610
#else /* not __GLIBC_PREREQ(2, 15) */
2611
int numentries = scandir(tempdir, &direntries, notdotentries,
2613
#endif /* not __GLIBC_PREREQ(2, 15) */
2614
#else /* not __GLIBC__ */
2615
int numentries = scandir(tempdir, &direntries, notdotentries,
2617
#endif /* not __GLIBC__ */
2618
if(numentries >= 0){
2619
for(int i = 0; i < numentries; i++){
2620
ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
2622
fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
2623
" \"%s\", 0): %s\n", tempdir,
2624
direntries[i]->d_name, strerror(errno));
2628
/* need to clean even if 0 because man page doesn't specify */
2630
if(numentries == -1){
2631
perror_plus("scandir");
2633
ret = rmdir(tempdir);
2634
if(ret == -1 and errno != ENOENT){
2635
perror_plus("rmdir");
2460
/* need to clean even if 0 because man page doesn't specify */
2462
if (numentries == -1){
2463
perror_plus("scandir");
2465
ret = rmdir(tempdir);
2466
if(ret == -1 and errno != ENOENT){
2467
perror_plus("rmdir");
2638
TEMP_FAILURE_RETRY(close(tempdir_fd));