/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 dracut-module/password-agent.c

  • Committer: Teddy Hogeborn
  • Date: 2024-11-17 18:43:11 UTC
  • mto: This revision was merged to the branch mainline in revision 412.
  • Revision ID: teddy@recompile.se-20241117184311-ox25kvngy62h209g
Debian package: Avoid suggesting a C compiler unnecessarily

The list of suggested packages, meant to enable the "mandos" program
to find the correct value of SO_BINDTODEVICE by using a C compiler,
are not necessary when Python 3.3 or later is used, since it has the
SO_BINDTODEVICE constant defined in the "socket" module.  Also, Python
2.6 or older has the same constant in the old "IN" module.  Therefore,
we should suggest these Python versions as alternatives to a C
compiler, so that a C compiler is not installed unnecessarily.

debian/control (Package: mandos/Suggests): Add "python3 (>= 3.3)" and
"python (<= 2.6)" as alternatives to "libc6-dev | libc-dev" and
"c-compiler".

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c; coding: utf-8; after-save-hook: (lambda () (let* ((find-build-directory (lambda (try-directory &optional base-directory) (let ((base-directory (or base-directory try-directory))) (cond ((equal try-directory "/") base-directory) ((file-readable-p (concat (file-name-as-directory try-directory) "Makefile")) try-directory) ((funcall find-build-directory (directory-file-name (file-name-directory try-directory)) base-directory)))))) (build-directory (funcall find-build-directory (buffer-file-name))) (local-build-directory (if (fboundp 'file-local-name) (file-local-name build-directory) (or (file-remote-p build-directory 'localname) build-directory))) (command (file-relative-name (file-name-sans-extension (buffer-file-name)) build-directory))) (pcase (progn (if (get-buffer "*Test*") (kill-buffer "*Test*")) (process-file-shell-command (let ((qbdir (shell-quote-argument local-build-directory)) (qcmd (shell-quote-argument command))) (format "cd %s && CFLAGS=-Werror make --silent %s && %s --test --verbose" qbdir qcmd qcmd)) nil "*Test*")) (0 (let ((w (get-buffer-window "*Test*"))) (if w (delete-window w)))) (_ (with-current-buffer "*Test*" (compilation-mode) (cd-absolute build-directory)) (display-buffer "*Test*" '(display-buffer-in-side-window)))))); -*- */
 
1
/* -*- coding: utf-8; lexical-binding: t -*- */
2
2
/*
3
3
 * Mandos password agent - Simple password agent to run Mandos client
4
4
 *
5
 
 * Copyright © 2019 Teddy Hogeborn
6
 
 * Copyright © 2019 Björn Påhlsson
 
5
 * Copyright © 2019-2022 Teddy Hogeborn
 
6
 * Copyright © 2019-2022 Björn Påhlsson
7
7
 * 
8
8
 * This file is part of Mandos.
9
9
 * 
23
23
 * Contact the authors at <mandos@recompile.se>.
24
24
 */
25
25
 
26
 
#define _GNU_SOURCE
27
 
#include <inttypes.h>           /* uintmax_t, PRIuMAX, PRIdMAX,
28
 
                                   intmax_t, uint32_t, SCNx32,
29
 
                                   SCNuMAX, SCNxMAX */
30
 
#include <stddef.h>             /* size_t */
 
26
#define _GNU_SOURCE             /* pipe2(), O_CLOEXEC, setresgid(),
 
27
                                   setresuid(), asprintf(), getline(),
 
28
                                   basename() */
 
29
#include <inttypes.h>           /* uintmax_t, strtoumax(), PRIuMAX,
 
30
                                   PRIdMAX, intmax_t, uint32_t,
 
31
                                   SCNx32, SCNuMAX, SCNxMAX */
 
32
#include <stddef.h>             /* size_t, NULL */
31
33
#include <sys/types.h>          /* pid_t, uid_t, gid_t, getuid(),
32
34
                                   getpid() */
33
35
#include <stdbool.h>            /* bool, true, false */
40
42
                                   NSIG, sigismember(), SA_ONSTACK,
41
43
                                   SIG_DFL, SIG_IGN, SIGINT, SIGQUIT,
42
44
                                   SIGHUP, SIGSTOP, SIG_UNBLOCK */
 
45
#include <unistd.h>             /* uid_t, gid_t, close(), pipe2(),
 
46
                                   fork(), _exit(), dup2(),
 
47
                                   STDOUT_FILENO, setresgid(),
 
48
                                   setresuid(), execv(), ssize_t,
 
49
                                   read(), dup3(), getuid(), dup(),
 
50
                                   STDERR_FILENO, pause(), write(),
 
51
                                   rmdir(), unlink(), getpid() */
43
52
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
44
 
                                   malloc(), free(), strtoumax(),
45
 
                                   realloc(), setenv(), calloc(),
46
 
                                   mkdtemp(), mkostemp() */
 
53
                                   malloc(), free(), realloc(),
 
54
                                   setenv(), calloc(), mkdtemp(),
 
55
                                   mkostemp() */
47
56
#include <iso646.h>             /* not, or, and, xor */
48
57
#include <error.h>              /* error() */
49
58
#include <sysexits.h>           /* EX_USAGE, EX_OSERR, EX_OSFILE */
57
66
#include <string.h>             /* strdup(), memcpy(),
58
67
                                   explicit_bzero(), memset(),
59
68
                                   strcmp(), strlen(), strncpy(),
60
 
                                   memcmp(), basename() */
 
69
                                   memcmp(), basename(), strerror() */
61
70
#include <argz.h>               /* argz_create(), argz_count(),
62
71
                                   argz_extract(), argz_next(),
63
72
                                   argz_add() */
73
82
                                   ARGP_ERR_UNKNOWN, ARGP_KEY_ARGS,
74
83
                                   struct argp, argp_parse(),
75
84
                                   ARGP_NO_EXIT */
76
 
#include <stdint.h>             /* SIZE_MAX */
77
 
#include <unistd.h>             /* uid_t, gid_t, close(), pipe2(),
78
 
                                   fork(), _exit(), dup2(),
79
 
                                   STDOUT_FILENO, setresgid(),
80
 
                                   setresuid(), execv(), ssize_t,
81
 
                                   read(), dup3(), getuid(), dup(),
82
 
                                   STDERR_FILENO, pause(), write(),
83
 
                                   rmdir(), unlink(), getpid() */
 
85
#include <stdint.h>             /* SIZE_MAX, uint32_t */
84
86
#include <sys/mman.h>           /* munlock(), mlock() */
85
87
#include <fcntl.h>              /* O_CLOEXEC, O_NONBLOCK, fcntl(),
86
88
                                   F_GETFD, F_GETFL, FD_CLOEXEC,
110
112
                        g_assert_null(), g_assert_false(),
111
113
                        g_assert_cmpint(), g_assert_cmpuint(),
112
114
                        g_test_skip(), g_assert_cmpstr(),
113
 
                        g_test_init(), g_test_add(), g_test_run(),
114
 
                        GOptionContext, g_option_context_new(),
 
115
                        g_test_message(), g_test_init(), g_test_add(),
 
116
                        g_test_run(), GOptionContext,
 
117
                        g_option_context_new(),
115
118
                        g_option_context_set_help_enabled(), FALSE,
116
119
                        g_option_context_set_ignore_unknown_options(),
117
120
                        gboolean, GOptionEntry, G_OPTION_ARG_NONE,
1095
1098
  } ievent_buffer;
1096
1099
  struct inotify_event *const ievent = &ievent_buffer.event;
1097
1100
 
 
1101
#if defined(__GNUC__) and __GNUC__ >= 7
 
1102
#pragma GCC diagnostic push
 
1103
  /* ievent is pointing into a struct which is of sufficient size */
 
1104
#pragma GCC diagnostic ignored "-Wstringop-overflow"
 
1105
#endif
1098
1106
  const ssize_t read_length = read(fd, ievent, ievent_size);
 
1107
#if defined(__GNUC__) and __GNUC__ >= 7
 
1108
#pragma GCC diagnostic pop
 
1109
#endif
1099
1110
  if(read_length == 0){ /* EOF */
1100
1111
    error(0, 0, "Got EOF from inotify fd for directory %s", filename);
1101
1112
    *quit_now = true;
1193
1204
  bool *const password_is_read = task.password_is_read;
1194
1205
 
1195
1206
  /* We use the GLib "Key-value file parser" functions to parse the
1196
 
     question file.  See <https://www.freedesktop.org/wiki/Software
1197
 
     /systemd/PasswordAgents/> for specification of contents */
 
1207
     question file.  See <https://systemd.io/PASSWORD_AGENTS/> for
 
1208
     specification of contents */
1198
1209
  __attribute__((nonnull))
1199
1210
    void cleanup_g_key_file(GKeyFile **key_file){
1200
1211
    if(*key_file != NULL){
1477
1488
    if(send_buffer == NULL){
1478
1489
      error(0, errno, "Failed to allocate send_buffer");
1479
1490
    } else {
 
1491
#if defined(__GNUC__) and __GNUC__ >= 5
 
1492
#pragma GCC diagnostic push
 
1493
  /* mlock() does not access the memory */
 
1494
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
 
1495
#endif
1480
1496
      if(mlock(send_buffer, send_buffer_length) != 0){
 
1497
#if defined(__GNUC__) and __GNUC__ >= 5
 
1498
#pragma GCC diagnostic pop
 
1499
#endif
1481
1500
        /* Warn but do not treat as fatal error */
1482
1501
        if(errno != EPERM and errno != ENOMEM){
1483
1502
          error(0, errno, "Failed to lock memory for password"
1490
1509
         not. You may but don't have to include a final NUL byte in
1491
1510
         your message.
1492
1511
 
1493
 
         — <https://www.freedesktop.org/wiki/Software/systemd/
1494
 
         PasswordAgents/> (Wed 08 Oct 2014 02:14:28 AM UTC)
 
1512
         — <https://systemd.io/PASSWORD_AGENTS/> (Tue, 15 Sep 2020
 
1513
         14:24:20 GMT)
1495
1514
      */
1496
1515
      send_buffer[0] = '+';     /* Prefix with "+" */
1497
1516
      /* Always add an extra NUL */
1502
1521
      errno = 0;
1503
1522
      ssize_t ssret = send(fd, send_buffer, send_buffer_length,
1504
1523
                           MSG_NOSIGNAL);
1505
 
      const error_t saved_errno = errno;
 
1524
      const error_t saved_errno = (ssret < 0) ? errno : 0;
1506
1525
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 25)
1507
1526
      explicit_bzero(send_buffer, send_buffer_length);
1508
1527
#else
1526
1545
          /* Retry, below */
1527
1546
          break;
1528
1547
        case EMSGSIZE:
1529
 
          error(0, 0, "Password of size %" PRIuMAX " is too big",
1530
 
                (uintmax_t)password->length);
 
1548
          error(0, saved_errno, "Password of size %" PRIuMAX
 
1549
                " is too big", (uintmax_t)password->length);
1531
1550
#if __GNUC__ < 7
1532
1551
          /* FALLTHROUGH */
1533
1552
#else
1535
1554
#endif
1536
1555
        case 0:
1537
1556
          if(ssret >= 0 and ssret < (ssize_t)send_buffer_length){
1538
 
            error(0, 0, "Password only partially sent to socket");
 
1557
            error(0, 0, "Password only partially sent to socket %s: %"
 
1558
                  PRIuMAX " out of %" PRIuMAX " bytes sent", filename,
 
1559
                  (uintmax_t)ssret, (uintmax_t)send_buffer_length);
1539
1560
          }
1540
1561
#if __GNUC__ < 7
1541
1562
          /* FALLTHROUGH */
2648
2669
  bool password_is_read = false;
2649
2670
  const char helper_directory[] = "/nonexistent";
2650
2671
  const char *const argv[] = { "/bin/sh", "-c",
2651
 
    "echo -n ${MANDOSPLUGINHELPERDIR}", NULL };
 
2672
    "printf %s \"${MANDOSPLUGINHELPERDIR}\"", NULL };
2652
2673
 
2653
2674
  const bool success = start_mandos_client(queue, epoll_fd,
2654
2675
                                           &mandos_client_exited,
4177
4198
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4178
4199
  const size_t ievent_size = (sizeof(struct inotify_event)
4179
4200
                              + sizeof(dummy_file_name));
 
4201
#if defined(__GNUC__) and __GNUC__ >= 11
 
4202
#pragma GCC diagnostic push
 
4203
  /* ievent is pointing into a struct which is of sufficient size */
 
4204
#pragma GCC diagnostic ignored "-Wstringop-overread"
 
4205
#endif
4180
4206
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4181
4207
                  ==, ievent_size);
 
4208
#if defined(__GNUC__) and __GNUC__ >= 11
 
4209
#pragma GCC diagnostic pop
 
4210
#endif
4182
4211
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4183
4212
 
4184
4213
  bool quit_now = false;
4272
4301
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4273
4302
  const size_t ievent_size = (sizeof(struct inotify_event)
4274
4303
                              + sizeof(dummy_file_name));
 
4304
#if defined(__GNUC__) and __GNUC__ >= 11
 
4305
#pragma GCC diagnostic push
 
4306
  /* ievent is pointing into a struct which is of sufficient size */
 
4307
#pragma GCC diagnostic ignored "-Wstringop-overread"
 
4308
#endif
4275
4309
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4276
4310
                  ==, ievent_size);
 
4311
#if defined(__GNUC__) and __GNUC__ >= 11
 
4312
#pragma GCC diagnostic pop
 
4313
#endif
4277
4314
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4278
4315
 
4279
4316
  bool quit_now = false;
4369
4406
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4370
4407
  const size_t ievent_size = (sizeof(struct inotify_event)
4371
4408
                              + sizeof(dummy_file_name));
 
4409
#if defined(__GNUC__) and __GNUC__ >= 11
 
4410
#pragma GCC diagnostic push
 
4411
  /* ievent is pointing into a struct which is of sufficient size */
 
4412
#pragma GCC diagnostic ignored "-Wstringop-overread"
 
4413
#endif
4372
4414
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4373
4415
                  ==, ievent_size);
 
4416
#if defined(__GNUC__) and __GNUC__ >= 11
 
4417
#pragma GCC diagnostic pop
 
4418
#endif
4374
4419
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4375
4420
 
4376
4421
  bool quit_now = false;
4454
4499
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4455
4500
  const size_t ievent_size = (sizeof(struct inotify_event)
4456
4501
                              + sizeof(dummy_file_name));
 
4502
#if defined(__GNUC__) and __GNUC__ >= 11
 
4503
#pragma GCC diagnostic push
 
4504
  /* ievent is pointing into a struct which is of sufficient size */
 
4505
#pragma GCC diagnostic ignored "-Wstringop-overread"
 
4506
#endif
4457
4507
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4458
4508
                  ==, ievent_size);
 
4509
#if defined(__GNUC__) and __GNUC__ >= 11
 
4510
#pragma GCC diagnostic pop
 
4511
#endif
4459
4512
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4460
4513
 
4461
4514
  bool quit_now = false;
4538
4591
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4539
4592
  const size_t ievent_size = (sizeof(struct inotify_event)
4540
4593
                              + sizeof(dummy_file_name));
 
4594
#if defined(__GNUC__) and __GNUC__ >= 11
 
4595
#pragma GCC diagnostic push
 
4596
  /* ievent is pointing into a struct which is of sufficient size */
 
4597
#pragma GCC diagnostic ignored "-Wstringop-overread"
 
4598
#endif
4541
4599
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4542
4600
                  ==, ievent_size);
 
4601
#if defined(__GNUC__) and __GNUC__ >= 11
 
4602
#pragma GCC diagnostic pop
 
4603
#endif
4543
4604
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4544
4605
 
4545
4606
  bool quit_now = false;
4614
4675
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4615
4676
  const size_t ievent_size = (sizeof(struct inotify_event)
4616
4677
                              + sizeof(dummy_file_name));
 
4678
#if defined(__GNUC__) and __GNUC__ >= 11
 
4679
#pragma GCC diagnostic push
 
4680
  /* ievent is pointing into a struct which is of sufficient size */
 
4681
#pragma GCC diagnostic ignored "-Wstringop-overread"
 
4682
#endif
4617
4683
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4618
4684
                  ==, ievent_size);
 
4685
#if defined(__GNUC__) and __GNUC__ >= 11
 
4686
#pragma GCC diagnostic pop
 
4687
#endif
4619
4688
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4620
4689
 
4621
4690
  bool quit_now = false;
4693
4762
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4694
4763
  const size_t ievent_size = (sizeof(struct inotify_event)
4695
4764
                              + sizeof(dummy_file_name));
 
4765
#if defined(__GNUC__) and __GNUC__ >= 11
 
4766
#pragma GCC diagnostic push
 
4767
  /* ievent is pointing into a struct which is of sufficient size */
 
4768
#pragma GCC diagnostic ignored "-Wstringop-overread"
 
4769
#endif
4696
4770
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4697
4771
                  ==, ievent_size);
 
4772
#if defined(__GNUC__) and __GNUC__ >= 11
 
4773
#pragma GCC diagnostic pop
 
4774
#endif
4698
4775
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4699
4776
 
4700
4777
  bool quit_now = false;
4778
4855
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4779
4856
  const size_t ievent_size = (sizeof(struct inotify_event)
4780
4857
                              + sizeof(dummy_file_name));
 
4858
#if defined(__GNUC__) and __GNUC__ >= 11
 
4859
#pragma GCC diagnostic push
 
4860
  /* ievent is pointing into a struct which is of sufficient size */
 
4861
#pragma GCC diagnostic ignored "-Wstringop-overread"
 
4862
#endif
4781
4863
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4782
4864
                  ==, ievent_size);
 
4865
#if defined(__GNUC__) and __GNUC__ >= 11
 
4866
#pragma GCC diagnostic pop
 
4867
#endif
4783
4868
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4784
4869
 
4785
4870
  bool quit_now = false;
5807
5892
  char write_data[PIPE_BUF];
5808
5893
  {
5809
5894
    /* Construct test password buffer */
5810
 
    /* Start with + since that is what the real procotol uses */
 
5895
    /* Start with + since that is what the real protocol uses */
5811
5896
    write_data[0] = '+';
5812
5897
    /* Set a special character at string end just to mark the end */
5813
5898
    write_data[sizeof(write_data)-2] = 'y';
5958
6043
                                           test_fixture *fixture,
5959
6044
                                           __attribute__((unused))
5960
6045
                                           gconstpointer user_data){
5961
 
#ifndef __amd64__
5962
 
  g_test_skip("Skipping EMSGSIZE test on non-AMD64 platform");
5963
 
#else
5964
6046
  __attribute__((cleanup(cleanup_close)))
5965
6047
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
5966
6048
  g_assert_cmpint(epoll_fd, >=, 0);
5968
6050
  char *const filename = strdup("/nonexistent/socket");
5969
6051
  __attribute__((cleanup(string_set_clear)))
5970
6052
    string_set cancelled_filenames = {};
5971
 
  const size_t oversized = 1024*1024; /* Limit seems to be 212960 */
5972
 
  __attribute__((cleanup(cleanup_buffer)))
5973
 
    buffer password = {
5974
 
    .data=malloc(oversized),
5975
 
    .length=oversized,
5976
 
    .allocated=oversized,
 
6053
  int socketfds[2];
 
6054
 
 
6055
  /* Find a message size which triggers EMSGSIZE */
 
6056
  __attribute__((cleanup(cleanup_string)))
 
6057
    char *message_buffer = NULL;
 
6058
  size_t message_size = PIPE_BUF + 1;
 
6059
  for(ssize_t ssret = 0; ssret >= 0; message_size += 1024){
 
6060
    if(message_size >= 1024*1024*1024){ /* 1 GiB */
 
6061
      g_test_skip("Skipping EMSGSIZE test: Will not try 1GiB");
 
6062
      return;
 
6063
    }
 
6064
    message_buffer = realloc(message_buffer, message_size);
 
6065
    if(message_buffer == NULL){
 
6066
      g_test_skip("Skipping EMSGSIZE test");
 
6067
      g_test_message("Failed to malloc() %" PRIuMAX " bytes",
 
6068
                     (uintmax_t)message_size);
 
6069
      return;
 
6070
    }
 
6071
    /* Fill buffer with 'x' */
 
6072
    memset(message_buffer, 'x', message_size);
 
6073
    /* Create a new socketpair for each message size to avoid having
 
6074
       to empty the pipe by reading the message to a separate buffer
 
6075
    */
 
6076
    g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
 
6077
                               | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
 
6078
                               socketfds), ==, 0);
 
6079
    ssret = send(socketfds[1], message_buffer, message_size,
 
6080
                 MSG_NOSIGNAL);
 
6081
    error_t saved_errno = errno;
 
6082
    g_assert_cmpint(close(socketfds[0]), ==, 0);
 
6083
    g_assert_cmpint(close(socketfds[1]), ==, 0);
 
6084
 
 
6085
    if(ssret < 0){
 
6086
      if(saved_errno != EMSGSIZE) {
 
6087
        g_test_skip("Skipping EMSGSIZE test");
 
6088
        g_test_message("Error on send(%" PRIuMAX " bytes): %s",
 
6089
                       (uintmax_t)message_size,
 
6090
                       strerror(saved_errno));
 
6091
        return;
 
6092
      }
 
6093
      break;
 
6094
    } else if(ssret != (ssize_t)message_size){
 
6095
      g_test_skip("Skipping EMSGSIZE test");
 
6096
      g_test_message("Partial send(): %" PRIuMAX " of %" PRIdMAX
 
6097
                     " bytes", (uintmax_t)ssret,
 
6098
                     (intmax_t)message_size);
 
6099
      return;
 
6100
    }
 
6101
  }
 
6102
  g_test_message("EMSGSIZE triggered by %" PRIdMAX " bytes",
 
6103
                 (intmax_t)message_size);
 
6104
 
 
6105
  buffer password = {
 
6106
    .data=message_buffer,
 
6107
    .length=message_size - 2,   /* Compensate for added '+' and NUL */
 
6108
    .allocated=message_size,
5977
6109
  };
5978
 
  g_assert_nonnull(password.data);
5979
6110
  if(mlock(password.data, password.allocated) != 0){
5980
6111
    g_assert_true(errno == EPERM or errno == ENOMEM);
5981
6112
  }
5982
 
  /* Construct test password buffer */
5983
 
  /* Start with + since that is what the real procotol uses */
5984
 
  password.data[0] = '+';
5985
 
  /* Set a special character at string end just to mark the end */
5986
 
  password.data[oversized-3] = 'y';
5987
 
  /* Set NUL at buffer end, as suggested by the protocol */
5988
 
  password.data[oversized-2] = '\0';
5989
 
  /* Fill rest of password with 'x' */
5990
 
  memset(password.data+1, 'x', oversized-3);
5991
6113
 
5992
6114
  __attribute__((cleanup(cleanup_queue)))
5993
6115
    task_queue *queue = create_queue();
5994
6116
  g_assert_nonnull(queue);
5995
 
  int socketfds[2];
5996
6117
  g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
5997
6118
                             | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
5998
6119
                             socketfds), ==, 0);
6019
6140
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
6020
6141
  g_assert_true(string_set_contains(cancelled_filenames,
6021
6142
                                    question_filename));
6022
 
#endif
6023
6143
}
6024
6144
 
6025
6145
static void test_send_password_to_socket_retry(__attribute__((unused))
8155
8275
  g_option_context_free(context);
8156
8276
  return should_run_tests != FALSE;
8157
8277
}
 
8278
 
 
8279
/*
 
8280
Local Variables:
 
8281
run-tests:
 
8282
(lambda ()
 
8283
  (if (not (funcall run-tests-in-test-buffer default-directory))
 
8284
      (funcall show-test-buffer-in-test-window)
 
8285
    (funcall remove-test-window)))
 
8286
run-tests-in-test-buffer:
 
8287
(lambda (dir)
 
8288
  (with-current-buffer (get-buffer-create "*Test*")
 
8289
    (setq buffer-read-only nil
 
8290
          default-directory dir)
 
8291
    (erase-buffer)
 
8292
    (compilation-mode))
 
8293
  (let ((process-result
 
8294
         (let ((inhibit-read-only t))
 
8295
           (process-file-shell-command
 
8296
            (funcall get-command-line) nil "*Test*"))))
 
8297
    (and (numberp process-result)
 
8298
         (= process-result 0))))
 
8299
get-command-line:
 
8300
(lambda ()
 
8301
  (let*
 
8302
      ((build-directory
 
8303
        (funcall find-build-directory (buffer-file-name)))
 
8304
       (local-build-directory
 
8305
        (if (fboundp 'file-local-name)
 
8306
            (file-local-name build-directory)
 
8307
          (or (file-remote-p build-directory 'localname)
 
8308
              build-directory)))
 
8309
       (command
 
8310
        (file-relative-name (file-name-sans-extension
 
8311
                             (buffer-file-name)) build-directory))
 
8312
       (qbdir (shell-quote-argument local-build-directory))
 
8313
       (qcmd (shell-quote-argument command)))
 
8314
    (format (concat "cd %s && CFLAGS=-Werror make --silent %s"
 
8315
             " && %s --test --verbose") qbdir qcmd qcmd)))
 
8316
find-build-directory:
 
8317
(lambda (try-directory &optional base-directory)
 
8318
  (let ((base-directory (or base-directory try-directory)))
 
8319
    (cond ((equal try-directory "/") base-directory)
 
8320
          ((file-readable-p
 
8321
            (concat (file-name-as-directory try-directory)
 
8322
                    "Makefile")) try-directory)
 
8323
          ((funcall find-build-directory
 
8324
                    (directory-file-name (file-name-directory
 
8325
                                          try-directory))
 
8326
                    base-directory)))))
 
8327
show-test-buffer-in-test-window:
 
8328
(lambda ()
 
8329
  (when (not (get-buffer-window-list "*Test*"))
 
8330
    (setq next-error-last-buffer (get-buffer "*Test*"))
 
8331
    (let* ((side (if (>= (window-width) 146) 'right 'bottom))
 
8332
           (display-buffer-overriding-action
 
8333
            `((display-buffer-in-side-window) (side . ,side)
 
8334
              (window-height . fit-window-to-buffer)
 
8335
              (window-width . fit-window-to-buffer))))
 
8336
      (display-buffer "*Test*"))))
 
8337
remove-test-window:
 
8338
(lambda ()
 
8339
  (let ((test-window (get-buffer-window "*Test*")))
 
8340
    (if test-window (delete-window test-window))))
 
8341
eval: (add-hook 'after-save-hook run-tests 90 t)
 
8342
End:
 
8343
*/