/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:
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
233
234
                          .af = af };
234
235
  if(new_server->ip == NULL){
235
236
    perror_plus("strdup");
 
237
    free(new_server);
236
238
    return false;
237
239
  }
238
240
  ret = clock_gettime(CLOCK_MONOTONIC, &(new_server->last_seen));
239
241
  if(ret == -1){
240
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);
241
252
    return false;
242
253
  }
243
254
  /* Special case of first server */
1065
1076
     timed out */
1066
1077
  
1067
1078
  if(quit_now){
 
1079
    avahi_s_service_resolver_free(r);
1068
1080
    return;
1069
1081
  }
1070
1082
  
1346
1358
    return 0;
1347
1359
  }
1348
1360
  
1349
 
  char *fullname = NULL;
1350
 
  ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1351
 
  if(ret < 0){
1352
 
    perror_plus("asprintf");
1353
 
    return 0;
1354
 
  }
1355
 
  
1356
 
  ret = stat(fullname, &st);
 
1361
  ret = fstatat(hookdir_fd, direntry->d_name, &st, 0);
1357
1362
  if(ret == -1){
1358
1363
    if(debug){
1359
1364
      perror_plus("Could not stat hook");
1360
1365
    }
1361
1366
    return 0;
1362
1367
  }
1363
 
  free(fullname);
1364
1368
  if(not (S_ISREG(st.st_mode))){
1365
1369
    /* Not a regular file */
1366
1370
    if(debug){
1465
1469
  error_t ret_errno = 0;
1466
1470
  if(seteuid(0) == -1){
1467
1471
    ret_errno = errno;
1468
 
    perror_plus("seteuid");
1469
1472
  }
1470
1473
  errno = old_errno;
1471
1474
  return ret_errno;
1482
1485
  }
1483
1486
  if(setuid(0) == -1){
1484
1487
    ret_errno = errno;
1485
 
    perror_plus("seteuid");
1486
1488
  }
1487
1489
  errno = old_errno;
1488
1490
  return ret_errno;
1495
1497
  error_t ret_errno = 0;
1496
1498
  if(seteuid(uid) == -1){
1497
1499
    ret_errno = errno;
1498
 
    perror_plus("seteuid");
1499
1500
  }
1500
1501
  errno = old_errno;
1501
1502
  return ret_errno;
1508
1509
  error_t ret_errno = 0;
1509
1510
  if(setuid(uid) == -1){
1510
1511
    ret_errno = errno;
1511
 
    perror_plus("setuid");
1512
1512
  }
1513
1513
  errno = old_errno;
1514
1514
  return ret_errno;
1515
1515
}
1516
1516
 
1517
 
#ifndef O_CLOEXEC
1518
 
/*
1519
 
 * Based on the example in the GNU LibC manual chapter 13.13 "File
1520
 
 * Descriptor Flags".
1521
 
 | [[info:libc:Descriptor%20Flags][File Descriptor Flags]] |
1522
 
 */
1523
 
__attribute__((warn_unused_result))
1524
 
static int set_cloexec_flag(int fd){
1525
 
  int ret = (int)TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0));
1526
 
  /* If reading the flags failed, return error indication now. */
1527
 
  if(ret < 0){
1528
 
    return ret;
1529
 
  }
1530
 
  /* Store modified flag word in the descriptor. */
1531
 
  return (int)TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD,
1532
 
                                       ret | FD_CLOEXEC));
1533
 
}
1534
 
#endif  /* not O_CLOEXEC */
1535
 
 
1536
1517
__attribute__((nonnull))
1537
1518
void run_network_hooks(const char *mode, const char *interface,
1538
1519
                       const float delay){
1539
 
  struct dirent **direntries;
 
1520
  struct dirent **direntries = NULL;
1540
1521
  if(hookdir_fd == -1){
1541
 
    hookdir_fd = open(hookdir, O_RDONLY |
1542
 
#ifdef O_CLOEXEC
1543
 
                      O_CLOEXEC
1544
 
#else  /* not O_CLOEXEC */
1545
 
                      0
1546
 
#endif  /* not O_CLOEXEC */
1547
 
                      );
 
1522
    hookdir_fd = open(hookdir, O_RDONLY);
1548
1523
    if(hookdir_fd == -1){
1549
1524
      if(errno == ENOENT){
1550
1525
        if(debug){
1556
1531
      }
1557
1532
      return;
1558
1533
    }
1559
 
#ifndef O_CLOEXEC
1560
 
    if(set_cloexec_flag(hookdir_fd) < 0){
1561
 
      perror_plus("set_cloexec_flag");
1562
 
      if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
1563
 
        perror_plus("close");
1564
 
      } else {
1565
 
        hookdir_fd = -1;
1566
 
      }
1567
 
      return;
1568
 
    }
1569
 
#endif  /* not O_CLOEXEC */
1570
1534
  }
1571
1535
#ifdef __GLIBC__
1572
1536
#if __GLIBC_PREREQ(2, 15)
1589
1553
  int devnull = open("/dev/null", O_RDONLY);
1590
1554
  for(int i = 0; i < numhooks; i++){
1591
1555
    direntry = direntries[i];
1592
 
    char *fullname = NULL;
1593
 
    ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1594
 
    if(ret < 0){
1595
 
      perror_plus("asprintf");
1596
 
      continue;
1597
 
    }
1598
1556
    if(debug){
1599
1557
      fprintf_plus(stderr, "Running network hook \"%s\"\n",
1600
1558
                   direntry->d_name);
1603
1561
    if(hook_pid == 0){
1604
1562
      /* Child */
1605
1563
      /* Raise privileges */
1606
 
      if(raise_privileges_permanently() != 0){
 
1564
      errno = raise_privileges_permanently();
 
1565
      if(errno != 0){
1607
1566
        perror_plus("Failed to raise privileges");
1608
1567
        _exit(EX_NOPERM);
1609
1568
      }
1676
1635
          _exit(EX_OSERR);
1677
1636
        }
1678
1637
      }
1679
 
      if(execl(fullname, direntry->d_name, mode, NULL) == -1){
1680
 
        perror_plus("execl");
 
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");
1681
1650
        _exit(EXIT_FAILURE);
1682
1651
      }
1683
1652
    } else {
 
1653
      if(hook_pid == -1){
 
1654
        perror_plus("fork");
 
1655
        free(direntry);
 
1656
        continue;
 
1657
      }
1684
1658
      int status;
1685
1659
      if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1686
1660
        perror_plus("waitpid");
1687
 
        free(fullname);
 
1661
        free(direntry);
1688
1662
        continue;
1689
1663
      }
1690
1664
      if(WIFEXITED(status)){
1692
1666
          fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1693
1667
                       " with status %d\n", direntry->d_name,
1694
1668
                       WEXITSTATUS(status));
1695
 
          free(fullname);
 
1669
          free(direntry);
1696
1670
          continue;
1697
1671
        }
1698
1672
      } else if(WIFSIGNALED(status)){
1699
1673
        fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1700
1674
                     " signal %d\n", direntry->d_name,
1701
1675
                     WTERMSIG(status));
1702
 
        free(fullname);
 
1676
        free(direntry);
1703
1677
        continue;
1704
1678
      } else {
1705
1679
        fprintf_plus(stderr, "Warning: network hook \"%s\""
1706
1680
                     " crashed\n", direntry->d_name);
1707
 
        free(fullname);
 
1681
        free(direntry);
1708
1682
        continue;
1709
1683
      }
1710
1684
    }
1711
 
    free(fullname);
1712
1685
    if(debug){
1713
1686
      fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1714
1687
                   direntry->d_name);
1715
1688
    }
 
1689
    free(direntry);
1716
1690
  }
 
1691
  free(direntries);
1717
1692
  if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
1718
1693
    perror_plus("close");
1719
1694
  } else {
1776
1751
    /* Raise privileges */
1777
1752
    ret_errno = raise_privileges();
1778
1753
    if(ret_errno != 0){
 
1754
      errno = ret_errno;
1779
1755
      perror_plus("Failed to raise privileges");
1780
1756
    }
1781
1757
    
1885
1861
    /* Raise privileges */
1886
1862
    ret_errno = raise_privileges();
1887
1863
    if(ret_errno != 0){
 
1864
      errno = ret_errno;
1888
1865
      perror_plus("Failed to raise privileges");
1889
1866
    }
1890
1867
    
2297
2274
  
2298
2275
  /* If no interfaces were specified, make a list */
2299
2276
  if(mc.interfaces == NULL){
2300
 
    struct dirent **direntries;
 
2277
    struct dirent **direntries = NULL;
2301
2278
    /* Look for any good interfaces */
2302
2279
    ret = scandir(sys_class_net, &direntries, good_interface,
2303
2280
                  alphasort);
2309
2286
        if(ret_errno != 0){
2310
2287
          errno = ret_errno;
2311
2288
          perror_plus("argz_add");
 
2289
          free(direntries[i]);
2312
2290
          continue;
2313
2291
        }
2314
2292
        if(debug){
2315
2293
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
2316
2294
                       direntries[i]->d_name);
2317
2295
        }
 
2296
        free(direntries[i]);
2318
2297
      }
2319
2298
      free(direntries);
2320
2299
    } else {
2321
 
      free(direntries);
 
2300
      if(ret == 0){
 
2301
        free(direntries);
 
2302
      }
2322
2303
      fprintf_plus(stderr, "Could not find a network interface\n");
2323
2304
      exitcode = EXIT_FAILURE;
2324
2305
      goto end;
2588
2569
    mc.current_server->prev->next = NULL;
2589
2570
    while(mc.current_server != NULL){
2590
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
2591
2580
      free(mc.current_server);
2592
2581
      mc.current_server = next;
2593
2582
    }
2597
2586
  {
2598
2587
    ret_errno = raise_privileges();
2599
2588
    if(ret_errno != 0){
 
2589
      errno = ret_errno;
2600
2590
      perror_plus("Failed to raise privileges");
2601
2591
    } else {
2602
2592
      
2625
2615
    
2626
2616
    ret_errno = lower_privileges_permanently();
2627
2617
    if(ret_errno != 0){
 
2618
      errno = ret_errno;
2628
2619
      perror_plus("Failed to lower privileges permanently");
2629
2620
    }
2630
2621
  }
2635
2626
  /* Removes the GPGME temp directory and all files inside */
2636
2627
  if(tempdir != NULL){
2637
2628
    struct dirent **direntries = NULL;
2638
 
    struct dirent *direntry = NULL;
2639
 
    int numentries = scandir(tempdir, &direntries, notdotentries,
2640
 
                             alphasort);
2641
 
    if(numentries > 0){
2642
 
      for(int i = 0; i < numentries; i++){
2643
 
        direntry = direntries[i];
2644
 
        char *fullname = NULL;
2645
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
2646
 
                       direntry->d_name);
2647
 
        if(ret < 0){
2648
 
          perror_plus("asprintf");
2649
 
          continue;
2650
 
        }
2651
 
        ret = remove(fullname);
2652
 
        if(ret == -1){
2653
 
          fprintf_plus(stderr, "remove(\"%s\"): %s\n", fullname,
2654
 
                       strerror(errno));
2655
 
        }
2656
 
        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
        }
2657
2666
      }
2658
 
    }
2659
 
    
2660
 
    /* need to clean even if 0 because man page doesn't specify */
2661
 
    free(direntries);
2662
 
    if(numentries == -1){
2663
 
      perror_plus("scandir");
2664
 
    }
2665
 
    ret = rmdir(tempdir);
2666
 
    if(ret == -1 and errno != ENOENT){
2667
 
      perror_plus("rmdir");
 
2667
      TEMP_FAILURE_RETRY(close(tempdir_fd));
2668
2668
    }
2669
2669
  }
2670
2670