/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)
1597
1561
    if(hook_pid == 0){
1598
1562
      /* Child */
1599
1563
      /* Raise privileges */
1600
 
      if(raise_privileges_permanently() != 0){
 
1564
      errno = raise_privileges_permanently();
 
1565
      if(errno != 0){
1601
1566
        perror_plus("Failed to raise privileges");
1602
1567
        _exit(EX_NOPERM);
1603
1568
      }
1670
1635
          _exit(EX_OSERR);
1671
1636
        }
1672
1637
      }
1673
 
      if(fexecve(hookdir_fd, (char *const [])
1674
 
                 { direntry->d_name, NULL }, environ) == -1){
 
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){
1675
1649
        perror_plus("fexecve");
1676
1650
        _exit(EXIT_FAILURE);
1677
1651
      }
1678
1652
    } else {
 
1653
      if(hook_pid == -1){
 
1654
        perror_plus("fork");
 
1655
        free(direntry);
 
1656
        continue;
 
1657
      }
1679
1658
      int status;
1680
1659
      if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1681
1660
        perror_plus("waitpid");
 
1661
        free(direntry);
1682
1662
        continue;
1683
1663
      }
1684
1664
      if(WIFEXITED(status)){
1686
1666
          fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1687
1667
                       " with status %d\n", direntry->d_name,
1688
1668
                       WEXITSTATUS(status));
 
1669
          free(direntry);
1689
1670
          continue;
1690
1671
        }
1691
1672
      } else if(WIFSIGNALED(status)){
1692
1673
        fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1693
1674
                     " signal %d\n", direntry->d_name,
1694
1675
                     WTERMSIG(status));
 
1676
        free(direntry);
1695
1677
        continue;
1696
1678
      } else {
1697
1679
        fprintf_plus(stderr, "Warning: network hook \"%s\""
1698
1680
                     " crashed\n", direntry->d_name);
 
1681
        free(direntry);
1699
1682
        continue;
1700
1683
      }
1701
1684
    }
1703
1686
      fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1704
1687
                   direntry->d_name);
1705
1688
    }
 
1689
    free(direntry);
1706
1690
  }
 
1691
  free(direntries);
1707
1692
  if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
1708
1693
    perror_plus("close");
1709
1694
  } else {
1766
1751
    /* Raise privileges */
1767
1752
    ret_errno = raise_privileges();
1768
1753
    if(ret_errno != 0){
 
1754
      errno = ret_errno;
1769
1755
      perror_plus("Failed to raise privileges");
1770
1756
    }
1771
1757
    
1875
1861
    /* Raise privileges */
1876
1862
    ret_errno = raise_privileges();
1877
1863
    if(ret_errno != 0){
 
1864
      errno = ret_errno;
1878
1865
      perror_plus("Failed to raise privileges");
1879
1866
    }
1880
1867
    
2287
2274
  
2288
2275
  /* If no interfaces were specified, make a list */
2289
2276
  if(mc.interfaces == NULL){
2290
 
    struct dirent **direntries;
 
2277
    struct dirent **direntries = NULL;
2291
2278
    /* Look for any good interfaces */
2292
2279
    ret = scandir(sys_class_net, &direntries, good_interface,
2293
2280
                  alphasort);
2299
2286
        if(ret_errno != 0){
2300
2287
          errno = ret_errno;
2301
2288
          perror_plus("argz_add");
 
2289
          free(direntries[i]);
2302
2290
          continue;
2303
2291
        }
2304
2292
        if(debug){
2305
2293
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
2306
2294
                       direntries[i]->d_name);
2307
2295
        }
 
2296
        free(direntries[i]);
2308
2297
      }
2309
2298
      free(direntries);
2310
2299
    } else {
2311
 
      free(direntries);
 
2300
      if(ret == 0){
 
2301
        free(direntries);
 
2302
      }
2312
2303
      fprintf_plus(stderr, "Could not find a network interface\n");
2313
2304
      exitcode = EXIT_FAILURE;
2314
2305
      goto end;
2578
2569
    mc.current_server->prev->next = NULL;
2579
2570
    while(mc.current_server != NULL){
2580
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
2581
2580
      free(mc.current_server);
2582
2581
      mc.current_server = next;
2583
2582
    }
2587
2586
  {
2588
2587
    ret_errno = raise_privileges();
2589
2588
    if(ret_errno != 0){
 
2589
      errno = ret_errno;
2590
2590
      perror_plus("Failed to raise privileges");
2591
2591
    } else {
2592
2592
      
2615
2615
    
2616
2616
    ret_errno = lower_privileges_permanently();
2617
2617
    if(ret_errno != 0){
 
2618
      errno = ret_errno;
2618
2619
      perror_plus("Failed to lower privileges permanently");
2619
2620
    }
2620
2621
  }
2625
2626
  /* Removes the GPGME temp directory and all files inside */
2626
2627
  if(tempdir != NULL){
2627
2628
    struct dirent **direntries = NULL;
2628
 
    struct dirent *direntry = NULL;
2629
 
    int numentries = scandir(tempdir, &direntries, notdotentries,
2630
 
                             alphasort);
2631
 
    if(numentries > 0){
2632
 
      for(int i = 0; i < numentries; i++){
2633
 
        direntry = direntries[i];
2634
 
        char *fullname = NULL;
2635
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
2636
 
                       direntry->d_name);
2637
 
        if(ret < 0){
2638
 
          perror_plus("asprintf");
2639
 
          continue;
2640
 
        }
2641
 
        ret = remove(fullname);
2642
 
        if(ret == -1){
2643
 
          fprintf_plus(stderr, "remove(\"%s\"): %s\n", fullname,
2644
 
                       strerror(errno));
2645
 
        }
2646
 
        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
        }
2647
2666
      }
2648
 
    }
2649
 
    
2650
 
    /* need to clean even if 0 because man page doesn't specify */
2651
 
    free(direntries);
2652
 
    if(numentries == -1){
2653
 
      perror_plus("scandir");
2654
 
    }
2655
 
    ret = rmdir(tempdir);
2656
 
    if(ret == -1 and errno != ENOENT){
2657
 
      perror_plus("rmdir");
 
2667
      TEMP_FAILURE_RETRY(close(tempdir_fd));
2658
2668
    }
2659
2669
  }
2660
2670