/mandos/trunk

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

« back to all changes in this revision

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

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

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
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(),
57
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
58
58
                                   inet_pton(), connect(),
59
59
                                   getnameinfo() */
60
 
#include <fcntl.h>              /* open() */
 
60
#include <fcntl.h>              /* open(), unlinkat() */
61
61
#include <dirent.h>             /* opendir(), struct dirent, readdir()
62
62
                                 */
63
63
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
73
73
                                */
74
74
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
75
75
                                   getuid(), getgid(), seteuid(),
76
 
                                   setgid(), pause(), _exit() */
 
76
                                   setgid(), pause(), _exit(),
 
77
                                   unlinkat() */
77
78
#include <arpa/inet.h>          /* inet_pton(), htons() */
78
79
#include <iso646.h>             /* not, or, and */
79
80
#include <argp.h>               /* struct argp_option, error_t, struct
141
142
static const char sys_class_net[] = "/sys/class/net";
142
143
char *connect_to = NULL;
143
144
const char *hookdir = HOOKDIR;
 
145
int hookdir_fd = -1;
144
146
uid_t uid = 65534;
145
147
gid_t gid = 65534;
146
148
 
232
234
                          .af = af };
233
235
  if(new_server->ip == NULL){
234
236
    perror_plus("strdup");
 
237
    free(new_server);
235
238
    return false;
236
239
  }
237
240
  ret = clock_gettime(CLOCK_MONOTONIC, &(new_server->last_seen));
238
241
  if(ret == -1){
239
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);
240
252
    return false;
241
253
  }
242
254
  /* Special case of first server */
1064
1076
     timed out */
1065
1077
  
1066
1078
  if(quit_now){
 
1079
    avahi_s_service_resolver_free(r);
1067
1080
    return;
1068
1081
  }
1069
1082
  
1345
1358
    return 0;
1346
1359
  }
1347
1360
  
1348
 
  char *fullname = NULL;
1349
 
  ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1350
 
  if(ret < 0){
1351
 
    perror_plus("asprintf");
1352
 
    return 0;
1353
 
  }
1354
 
  
1355
 
  ret = stat(fullname, &st);
 
1361
  ret = fstatat(hookdir_fd, direntry->d_name, &st, 0);
1356
1362
  if(ret == -1){
1357
1363
    if(debug){
1358
1364
      perror_plus("Could not stat hook");
1359
1365
    }
1360
1366
    return 0;
1361
1367
  }
1362
 
  free(fullname);
1363
1368
  if(not (S_ISREG(st.st_mode))){
1364
1369
    /* Not a regular file */
1365
1370
    if(debug){
1464
1469
  error_t ret_errno = 0;
1465
1470
  if(seteuid(0) == -1){
1466
1471
    ret_errno = errno;
1467
 
    perror_plus("seteuid");
1468
1472
  }
1469
1473
  errno = old_errno;
1470
1474
  return ret_errno;
1481
1485
  }
1482
1486
  if(setuid(0) == -1){
1483
1487
    ret_errno = errno;
1484
 
    perror_plus("seteuid");
1485
1488
  }
1486
1489
  errno = old_errno;
1487
1490
  return ret_errno;
1494
1497
  error_t ret_errno = 0;
1495
1498
  if(seteuid(uid) == -1){
1496
1499
    ret_errno = errno;
1497
 
    perror_plus("seteuid");
1498
1500
  }
1499
1501
  errno = old_errno;
1500
1502
  return ret_errno;
1507
1509
  error_t ret_errno = 0;
1508
1510
  if(setuid(uid) == -1){
1509
1511
    ret_errno = errno;
1510
 
    perror_plus("setuid");
1511
1512
  }
1512
1513
  errno = old_errno;
1513
1514
  return ret_errno;
1516
1517
__attribute__((nonnull))
1517
1518
void run_network_hooks(const char *mode, const char *interface,
1518
1519
                       const float delay){
1519
 
  struct dirent **direntries;
1520
 
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
1521
 
                         alphasort);
 
1520
  struct dirent **direntries = NULL;
 
1521
  if(hookdir_fd == -1){
 
1522
    hookdir_fd = open(hookdir, O_RDONLY);
 
1523
    if(hookdir_fd == -1){
 
1524
      if(errno == ENOENT){
 
1525
        if(debug){
 
1526
          fprintf_plus(stderr, "Network hook directory \"%s\" not"
 
1527
                       " found\n", hookdir);
 
1528
        }
 
1529
      } else {
 
1530
        perror_plus("open");
 
1531
      }
 
1532
      return;
 
1533
    }
 
1534
  }
 
1535
#ifdef __GLIBC__
 
1536
#if __GLIBC_PREREQ(2, 15)
 
1537
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
 
1538
                           runnable_hook, alphasort);
 
1539
#else  /* not __GLIBC_PREREQ(2, 15) */
 
1540
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
 
1541
                         alphasort);
 
1542
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
1543
#else   /* not __GLIBC__ */
 
1544
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
 
1545
                         alphasort);
 
1546
#endif  /* not __GLIBC__ */
1522
1547
  if(numhooks == -1){
1523
 
    if(errno == ENOENT){
1524
 
      if(debug){
1525
 
        fprintf_plus(stderr, "Network hook directory \"%s\" not"
1526
 
                     " found\n", hookdir);
1527
 
      }
1528
 
    } else {
1529
 
      perror_plus("scandir");
 
1548
    perror_plus("scandir");
 
1549
    return;
 
1550
  }
 
1551
  struct dirent *direntry;
 
1552
  int ret;
 
1553
  int devnull = open("/dev/null", O_RDONLY);
 
1554
  for(int i = 0; i < numhooks; i++){
 
1555
    direntry = direntries[i];
 
1556
    if(debug){
 
1557
      fprintf_plus(stderr, "Running network hook \"%s\"\n",
 
1558
                   direntry->d_name);
1530
1559
    }
1531
 
  } else {
1532
 
    struct dirent *direntry;
1533
 
    int ret;
1534
 
    int devnull = open("/dev/null", O_RDONLY);
1535
 
    for(int i = 0; i < numhooks; i++){
1536
 
      direntry = direntries[i];
1537
 
      char *fullname = NULL;
1538
 
      ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1539
 
      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){
1540
1621
        perror_plus("asprintf");
1541
 
        continue;
1542
 
      }
1543
 
      if(debug){
1544
 
        fprintf_plus(stderr, "Running network hook \"%s\"\n",
1545
 
                     direntry->d_name);
1546
 
      }
1547
 
      pid_t hook_pid = fork();
1548
 
      if(hook_pid == 0){
1549
 
        /* Child */
1550
 
        /* Raise privileges */
1551
 
        if(raise_privileges_permanently() != 0){
1552
 
          perror_plus("Failed to raise privileges");
1553
 
          _exit(EX_NOPERM);
1554
 
        }
1555
 
        /* Set group */
1556
 
        errno = 0;
1557
 
        ret = setgid(0);
1558
 
        if(ret == -1){
1559
 
          perror_plus("setgid");
1560
 
          _exit(EX_NOPERM);
1561
 
        }
1562
 
        /* Reset supplementary groups */
1563
 
        errno = 0;
1564
 
        ret = setgroups(0, NULL);
1565
 
        if(ret == -1){
1566
 
          perror_plus("setgroups");
1567
 
          _exit(EX_NOPERM);
1568
 
        }
1569
 
        ret = dup2(devnull, STDIN_FILENO);
1570
 
        if(ret == -1){
1571
 
          perror_plus("dup2(devnull, STDIN_FILENO)");
1572
 
          _exit(EX_OSERR);
1573
 
        }
1574
 
        ret = close(devnull);
1575
 
        if(ret == -1){
1576
 
          perror_plus("close");
1577
 
          _exit(EX_OSERR);
1578
 
        }
1579
 
        ret = dup2(STDERR_FILENO, STDOUT_FILENO);
1580
 
        if(ret == -1){
1581
 
          perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
1582
 
          _exit(EX_OSERR);
1583
 
        }
1584
 
        ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
1585
 
        if(ret == -1){
1586
 
          perror_plus("setenv");
1587
 
          _exit(EX_OSERR);
1588
 
        }
1589
 
        ret = setenv("DEVICE", interface, 1);
1590
 
        if(ret == -1){
1591
 
          perror_plus("setenv");
1592
 
          _exit(EX_OSERR);
1593
 
        }
1594
 
        ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
1595
 
        if(ret == -1){
1596
 
          perror_plus("setenv");
1597
 
          _exit(EX_OSERR);
1598
 
        }
1599
 
        ret = setenv("MODE", mode, 1);
1600
 
        if(ret == -1){
1601
 
          perror_plus("setenv");
1602
 
          _exit(EX_OSERR);
1603
 
        }
1604
 
        char *delaystring;
1605
 
        ret = asprintf(&delaystring, "%f", (double)delay);
1606
 
        if(ret == -1){
1607
 
          perror_plus("asprintf");
1608
 
          _exit(EX_OSERR);
1609
 
        }
1610
 
        ret = setenv("DELAY", delaystring, 1);
1611
 
        if(ret == -1){
1612
 
          free(delaystring);
1613
 
          perror_plus("setenv");
1614
 
          _exit(EX_OSERR);
1615
 
        }
 
1622
        _exit(EX_OSERR);
 
1623
      }
 
1624
      ret = setenv("DELAY", delaystring, 1);
 
1625
      if(ret == -1){
1616
1626
        free(delaystring);
1617
 
        if(connect_to != NULL){
1618
 
          ret = setenv("CONNECT", connect_to, 1);
1619
 
          if(ret == -1){
1620
 
            perror_plus("setenv");
1621
 
            _exit(EX_OSERR);
1622
 
          }
1623
 
        }
1624
 
        if(execl(fullname, direntry->d_name, mode, NULL) == -1){
1625
 
          perror_plus("execl");
1626
 
          _exit(EXIT_FAILURE);
1627
 
        }
 
1627
        perror_plus("setenv");
 
1628
        _exit(EX_OSERR);
 
1629
      }
 
1630
      free(delaystring);
 
1631
      if(connect_to != NULL){
 
1632
        ret = setenv("CONNECT", connect_to, 1);
 
1633
        if(ret == -1){
 
1634
          perror_plus("setenv");
 
1635
          _exit(EX_OSERR);
 
1636
        }
 
1637
      }
 
1638
      int hook_fd = openat(hookdir_fd, direntry->d_name, O_RDONLY);
 
1639
      if(hook_fd == -1){
 
1640
        perror_plus("openat");
 
1641
        _exit(EXIT_FAILURE);
 
1642
      }
 
1643
      if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1644
        perror_plus("close");
 
1645
        _exit(EXIT_FAILURE);
 
1646
      }
 
1647
      if(fexecve(hook_fd, (char *const []){ direntry->d_name, NULL },
 
1648
                 environ) == -1){
 
1649
        perror_plus("fexecve");
 
1650
        _exit(EXIT_FAILURE);
 
1651
      }
 
1652
    } else {
 
1653
      if(hook_pid == -1){
 
1654
        perror_plus("fork");
 
1655
        free(direntry);
 
1656
        continue;
 
1657
      }
 
1658
      int status;
 
1659
      if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
 
1660
        perror_plus("waitpid");
 
1661
        free(direntry);
 
1662
        continue;
 
1663
      }
 
1664
      if(WIFEXITED(status)){
 
1665
        if(WEXITSTATUS(status) != 0){
 
1666
          fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
 
1667
                       " with status %d\n", direntry->d_name,
 
1668
                       WEXITSTATUS(status));
 
1669
          free(direntry);
 
1670
          continue;
 
1671
        }
 
1672
      } else if(WIFSIGNALED(status)){
 
1673
        fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
 
1674
                     " signal %d\n", direntry->d_name,
 
1675
                     WTERMSIG(status));
 
1676
        free(direntry);
 
1677
        continue;
1628
1678
      } else {
1629
 
        int status;
1630
 
        if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1631
 
          perror_plus("waitpid");
1632
 
          free(fullname);
1633
 
          continue;
1634
 
        }
1635
 
        if(WIFEXITED(status)){
1636
 
          if(WEXITSTATUS(status) != 0){
1637
 
            fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1638
 
                         " with status %d\n", direntry->d_name,
1639
 
                         WEXITSTATUS(status));
1640
 
            free(fullname);
1641
 
            continue;
1642
 
          }
1643
 
        } else if(WIFSIGNALED(status)){
1644
 
          fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1645
 
                       " signal %d\n", direntry->d_name,
1646
 
                       WTERMSIG(status));
1647
 
          free(fullname);
1648
 
          continue;
1649
 
        } else {
1650
 
          fprintf_plus(stderr, "Warning: network hook \"%s\""
1651
 
                       " crashed\n", direntry->d_name);
1652
 
          free(fullname);
1653
 
          continue;
1654
 
        }
1655
 
      }
1656
 
      free(fullname);
1657
 
      if(debug){
1658
 
        fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1659
 
                     direntry->d_name);
1660
 
      }
1661
 
    }
1662
 
    close(devnull);
1663
 
  }
 
1679
        fprintf_plus(stderr, "Warning: network hook \"%s\""
 
1680
                     " crashed\n", direntry->d_name);
 
1681
        free(direntry);
 
1682
        continue;
 
1683
      }
 
1684
    }
 
1685
    if(debug){
 
1686
      fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
 
1687
                   direntry->d_name);
 
1688
    }
 
1689
    free(direntry);
 
1690
  }
 
1691
  free(direntries);
 
1692
  if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1693
    perror_plus("close");
 
1694
  } else {
 
1695
    hookdir_fd = -1;
 
1696
  }
 
1697
  close(devnull);
1664
1698
}
1665
1699
 
1666
1700
__attribute__((nonnull, warn_unused_result))
1717
1751
    /* Raise privileges */
1718
1752
    ret_errno = raise_privileges();
1719
1753
    if(ret_errno != 0){
 
1754
      errno = ret_errno;
1720
1755
      perror_plus("Failed to raise privileges");
1721
1756
    }
1722
1757
    
1826
1861
    /* Raise privileges */
1827
1862
    ret_errno = raise_privileges();
1828
1863
    if(ret_errno != 0){
 
1864
      errno = ret_errno;
1829
1865
      perror_plus("Failed to raise privileges");
1830
1866
    }
1831
1867
    
2238
2274
  
2239
2275
  /* If no interfaces were specified, make a list */
2240
2276
  if(mc.interfaces == NULL){
2241
 
    struct dirent **direntries;
 
2277
    struct dirent **direntries = NULL;
2242
2278
    /* Look for any good interfaces */
2243
2279
    ret = scandir(sys_class_net, &direntries, good_interface,
2244
2280
                  alphasort);
2250
2286
        if(ret_errno != 0){
2251
2287
          errno = ret_errno;
2252
2288
          perror_plus("argz_add");
 
2289
          free(direntries[i]);
2253
2290
          continue;
2254
2291
        }
2255
2292
        if(debug){
2256
2293
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
2257
2294
                       direntries[i]->d_name);
2258
2295
        }
 
2296
        free(direntries[i]);
2259
2297
      }
2260
2298
      free(direntries);
2261
2299
    } else {
2262
 
      free(direntries);
 
2300
      if(ret == 0){
 
2301
        free(direntries);
 
2302
      }
2263
2303
      fprintf_plus(stderr, "Could not find a network interface\n");
2264
2304
      exitcode = EXIT_FAILURE;
2265
2305
      goto end;
2529
2569
    mc.current_server->prev->next = NULL;
2530
2570
    while(mc.current_server != NULL){
2531
2571
      server *next = mc.current_server->next;
 
2572
#ifdef __GNUC__
 
2573
#pragma GCC diagnostic push
 
2574
#pragma GCC diagnostic ignored "-Wcast-qual"
 
2575
#endif
 
2576
      free((char *)(mc.current_server->ip));
 
2577
#ifdef __GNUC__
 
2578
#pragma GCC diagnostic pop
 
2579
#endif
2532
2580
      free(mc.current_server);
2533
2581
      mc.current_server = next;
2534
2582
    }
2538
2586
  {
2539
2587
    ret_errno = raise_privileges();
2540
2588
    if(ret_errno != 0){
 
2589
      errno = ret_errno;
2541
2590
      perror_plus("Failed to raise privileges");
2542
2591
    } else {
2543
2592
      
2566
2615
    
2567
2616
    ret_errno = lower_privileges_permanently();
2568
2617
    if(ret_errno != 0){
 
2618
      errno = ret_errno;
2569
2619
      perror_plus("Failed to lower privileges permanently");
2570
2620
    }
2571
2621
  }
2576
2626
  /* Removes the GPGME temp directory and all files inside */
2577
2627
  if(tempdir != NULL){
2578
2628
    struct dirent **direntries = NULL;
2579
 
    struct dirent *direntry = NULL;
2580
 
    int numentries = scandir(tempdir, &direntries, notdotentries,
2581
 
                             alphasort);
2582
 
    if(numentries > 0){
2583
 
      for(int i = 0; i < numentries; i++){
2584
 
        direntry = direntries[i];
2585
 
        char *fullname = NULL;
2586
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
2587
 
                       direntry->d_name);
2588
 
        if(ret < 0){
2589
 
          perror_plus("asprintf");
2590
 
          continue;
2591
 
        }
2592
 
        ret = remove(fullname);
2593
 
        if(ret == -1){
2594
 
          fprintf_plus(stderr, "remove(\"%s\"): %s\n", fullname,
2595
 
                       strerror(errno));
2596
 
        }
2597
 
        free(fullname);
 
2629
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY |
 
2630
                                                  O_NOFOLLOW));
 
2631
    if(tempdir_fd == -1){
 
2632
      perror_plus("open");
 
2633
    } else {
 
2634
#ifdef __GLIBC__
 
2635
#if __GLIBC_PREREQ(2, 15)
 
2636
      int numentries = scandirat(tempdir_fd, ".", &direntries,
 
2637
                                 notdotentries, alphasort);
 
2638
#else  /* not __GLIBC_PREREQ(2, 15) */
 
2639
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2640
                               alphasort);
 
2641
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
2642
#else   /* not __GLIBC__ */
 
2643
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2644
                               alphasort);
 
2645
#endif  /* not __GLIBC__ */
 
2646
      if(numentries >= 0){
 
2647
        for(int i = 0; i < numentries; i++){
 
2648
          ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
 
2649
          if(ret == -1){
 
2650
            fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
 
2651
                         " \"%s\", 0): %s\n", tempdir,
 
2652
                         direntries[i]->d_name, strerror(errno));
 
2653
          }
 
2654
          free(direntries[i]);
 
2655
        }
 
2656
        
 
2657
        /* need to clean even if 0 because man page doesn't specify */
 
2658
        free(direntries);
 
2659
        if(numentries == -1){
 
2660
          perror_plus("scandir");
 
2661
        }
 
2662
        ret = rmdir(tempdir);
 
2663
        if(ret == -1 and errno != ENOENT){
 
2664
          perror_plus("rmdir");
 
2665
        }
2598
2666
      }
2599
 
    }
2600
 
    
2601
 
    /* need to clean even if 0 because man page doesn't specify */
2602
 
    free(direntries);
2603
 
    if(numentries == -1){
2604
 
      perror_plus("scandir");
2605
 
    }
2606
 
    ret = rmdir(tempdir);
2607
 
    if(ret == -1 and errno != ENOENT){
2608
 
      perror_plus("rmdir");
 
2667
      TEMP_FAILURE_RETRY(close(tempdir_fd));
2609
2668
    }
2610
2669
  }
2611
2670