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

  • Committer: Teddy Hogeborn
  • Date: 2019-08-05 21:14:05 UTC
  • Revision ID: teddy@recompile.se-20190805211405-9m6hecekaihpttz9
Override lintian warnings about upgrading from old versions

There are some really things which are imperative that we fix in case
someone were to upgrade from a really old version.  We want to keep
these fixes in the postinst maintainer scripts, even though lintian
complains about such old upgrades not being supported by Debian in
general.  We prefer the code being there, for the sake of the users.

* debian/mandos-client.lintian-overrides
  (maintainer-script-supports-ancient-package-version): New.
  debian/mandos.lintian-overrides
  (maintainer-script-supports-ancient-package-version): - '' -

Show diffs side-by-side

added added

removed removed

Lines of Context:
48
48
#include <error.h>              /* error() */
49
49
#include <sysexits.h>           /* EX_USAGE, EX_OSERR, EX_OSFILE */
50
50
#include <errno.h>              /* errno, error_t, EACCES,
51
 
                                   ENAMETOOLONG, ENOENT, EEXIST,
52
 
                                   ECHILD, EPERM, ENOMEM, EAGAIN,
53
 
                                   EINTR, ENOBUFS, EADDRINUSE,
 
51
                                   ENAMETOOLONG, ENOENT, ENOTDIR,
 
52
                                   EEXIST, ECHILD, EPERM, ENOMEM,
 
53
                                   EAGAIN, EINTR, ENOBUFS, EADDRINUSE,
54
54
                                   ECONNREFUSED, ECONNRESET,
55
55
                                   ETOOMANYREFS, EMSGSIZE, EBADF,
56
56
                                   EINVAL */
83
83
#include <sys/mman.h>           /* munlock(), mlock() */
84
84
#include <fcntl.h>              /* O_CLOEXEC, O_NONBLOCK, fcntl(),
85
85
                                   F_GETFD, F_GETFL, FD_CLOEXEC,
86
 
                                   open(), O_WRONLY, O_RDONLY */
 
86
                                   open(), O_WRONLY, O_NOCTTY,
 
87
                                   O_RDONLY, O_NOFOLLOW */
87
88
#include <sys/wait.h>           /* waitpid(), WNOHANG, WIFEXITED(),
88
89
                                   WEXITSTATUS() */
89
90
#include <limits.h>             /* PIPE_BUF, NAME_MAX, INT_MAX */
90
91
#include <sys/inotify.h>        /* inotify_init1(), IN_NONBLOCK,
91
92
                                   IN_CLOEXEC, inotify_add_watch(),
92
93
                                   IN_CLOSE_WRITE, IN_MOVED_TO,
93
 
                                   IN_DELETE, struct inotify_event */
 
94
                                   IN_MOVED_FROM, IN_DELETE,
 
95
                                   IN_EXCL_UNLINK, IN_ONLYDIR,
 
96
                                   struct inotify_event */
94
97
#include <fnmatch.h>            /* fnmatch(), FNM_FILE_NAME */
95
98
#include <stdio.h>              /* asprintf(), FILE, fopen(),
96
99
                                   getline(), sscanf(), feof(),
431
434
    case EACCES:
432
435
    case ENAMETOOLONG:
433
436
    case ENOENT:
 
437
    case ENOTDIR:
434
438
      return EX_OSFILE;
435
439
    default:
436
440
      return EX_OSERR;
1017
1021
    return false;
1018
1022
  }
1019
1023
 
1020
 
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE
1021
 
                       | IN_MOVED_TO | IN_DELETE)
 
1024
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO
 
1025
                       | IN_MOVED_FROM| IN_DELETE | IN_EXCL_UNLINK
 
1026
                       | IN_ONLYDIR)
1022
1027
     == -1){
1023
1028
    error(0, errno, "Failed to create inotify watch on %s", dir);
1024
1029
    return false;
1071
1076
  /* "sufficient to read at least one event." - inotify(7) */
1072
1077
  const size_t ievent_size = (sizeof(struct inotify_event)
1073
1078
                              + NAME_MAX + 1);
1074
 
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
1075
 
  struct inotify_event *ievent = ((struct inotify_event *)
1076
 
                                  ievent_buffer);
 
1079
  struct {
 
1080
    struct inotify_event event;
 
1081
    char name_buffer[NAME_MAX + 1];
 
1082
  } ievent_buffer;
 
1083
  struct inotify_event *const ievent = &ievent_buffer.event;
1077
1084
 
1078
1085
  const ssize_t read_length = read(fd, ievent, ievent_size);
1079
1086
  if(read_length == 0){ /* EOF */
1117
1124
             immediately */
1118
1125
          queue->next_run = 1;
1119
1126
        }
1120
 
      } else if(ievent->mask & IN_DELETE){
 
1127
      } else if(ievent->mask & (IN_MOVED_FROM | IN_DELETE)){
1121
1128
        if(not string_set_add(cancelled_filenames,
1122
1129
                              question_filename)){
1123
1130
          error(0, errno, "Could not add question %s to"
2220
2227
 
2221
2228
  {
2222
2229
    __attribute__((cleanup(cleanup_close)))
2223
 
      const int devnull_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
 
2230
      const int devnull_fd = open("/dev/null",
 
2231
                                  O_WRONLY | O_CLOEXEC | O_NOCTTY);
2224
2232
    g_assert_cmpint(devnull_fd, >=, 0);
2225
2233
    __attribute__((cleanup(cleanup_close)))
2226
2234
      const int real_stderr_fd = dup(STDERR_FILENO);
2250
2258
    {
2251
2259
      __attribute__((cleanup(cleanup_close)))
2252
2260
        const int devnull_fd = open("/dev/null",
2253
 
                                    O_WRONLY | O_CLOEXEC);
 
2261
                                    O_WRONLY | O_CLOEXEC | O_NOCTTY);
2254
2262
      g_assert_cmpint(devnull_fd, >=, 0);
2255
2263
      __attribute__((cleanup(cleanup_close)))
2256
2264
        const int real_stderr_fd = dup(STDERR_FILENO);
2901
2909
 
2902
2910
  __attribute__((cleanup(cleanup_close)))
2903
2911
    const int devnull_fd = open("/dev/null",
2904
 
                                O_WRONLY | O_CLOEXEC);
 
2912
                                O_WRONLY | O_CLOEXEC | O_NOCTTY);
2905
2913
  g_assert_cmpint(devnull_fd, >=, 0);
2906
2914
  __attribute__((cleanup(cleanup_close)))
2907
2915
    const int real_stderr_fd = dup(STDERR_FILENO);
2972
2980
 
2973
2981
  __attribute__((cleanup(cleanup_close)))
2974
2982
    const int devnull_fd = open("/dev/null",
2975
 
                                O_WRONLY | O_CLOEXEC);
 
2983
                                O_WRONLY | O_CLOEXEC, O_NOCTTY);
2976
2984
  g_assert_cmpint(devnull_fd, >=, 0);
2977
2985
  __attribute__((cleanup(cleanup_close)))
2978
2986
    const int real_stderr_fd = dup(STDERR_FILENO);
3016
3024
    buffer password = {};
3017
3025
 
3018
3026
  /* Reading /proc/self/mem from offset 0 will always give EIO */
3019
 
  const int fd = open("/proc/self/mem", O_RDONLY | O_CLOEXEC);
 
3027
  const int fd = open("/proc/self/mem",
 
3028
                      O_RDONLY | O_CLOEXEC | O_NOCTTY);
3020
3029
 
3021
3030
  bool password_is_read = false;
3022
3031
  bool quit_now = false;
3450
3459
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
3451
3460
}
3452
3461
 
 
3462
static void test_add_inotify_dir_watch_nondir(__attribute__((unused))
 
3463
                                              test_fixture *fixture,
 
3464
                                            __attribute__((unused))
 
3465
                                              gconstpointer
 
3466
                                              user_data){
 
3467
  __attribute__((cleanup(cleanup_close)))
 
3468
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
 
3469
  g_assert_cmpint(epoll_fd, >=, 0);
 
3470
  __attribute__((cleanup(cleanup_queue)))
 
3471
    task_queue *queue = create_queue();
 
3472
  g_assert_nonnull(queue);
 
3473
  __attribute__((cleanup(string_set_clear)))
 
3474
    string_set cancelled_filenames = {};
 
3475
  const mono_microsecs current_time = 0;
 
3476
 
 
3477
  bool quit_now = false;
 
3478
  buffer password = {};
 
3479
  bool mandos_client_exited = false;
 
3480
  bool password_is_read = false;
 
3481
 
 
3482
  const char not_a_directory[] = "/dev/tty";
 
3483
 
 
3484
  FILE *real_stderr = stderr;
 
3485
  FILE *devnull = fopen("/dev/null", "we");
 
3486
  g_assert_nonnull(devnull);
 
3487
  stderr = devnull;
 
3488
  g_assert_false(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
 
3489
                                       &password, not_a_directory,
 
3490
                                       &cancelled_filenames,
 
3491
                                       &current_time,
 
3492
                                       &mandos_client_exited,
 
3493
                                       &password_is_read));
 
3494
  stderr = real_stderr;
 
3495
  g_assert_cmpint(fclose(devnull), ==, 0);
 
3496
 
 
3497
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
 
3498
}
 
3499
 
3453
3500
static void test_add_inotify_dir_watch_EAGAIN(__attribute__((unused))
3454
3501
                                              test_fixture *fixture,
3455
3502
                                              __attribute__((unused))
3670
3717
}
3671
3718
 
3672
3719
static
 
3720
void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused))
 
3721
                                              test_fixture *fixture,
 
3722
                                              __attribute__((unused))
 
3723
                                              gconstpointer
 
3724
                                              user_data){
 
3725
  __attribute__((cleanup(cleanup_close)))
 
3726
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
 
3727
  g_assert_cmpint(epoll_fd, >=, 0);
 
3728
  __attribute__((cleanup(cleanup_queue)))
 
3729
    task_queue *queue = create_queue();
 
3730
  g_assert_nonnull(queue);
 
3731
  __attribute__((cleanup(string_set_clear)))
 
3732
    string_set cancelled_filenames = {};
 
3733
  const mono_microsecs current_time = 0;
 
3734
 
 
3735
  bool quit_now = false;
 
3736
  buffer password = {};
 
3737
  bool mandos_client_exited = false;
 
3738
  bool password_is_read = false;
 
3739
 
 
3740
  __attribute__((cleanup(cleanup_string)))
 
3741
    char *tempdir = make_temporary_directory();
 
3742
  g_assert_nonnull(tempdir);
 
3743
 
 
3744
  __attribute__((cleanup(cleanup_string)))
 
3745
    char *tempfilename = make_temporary_file_in_directory(tempdir);
 
3746
  g_assert_nonnull(tempfilename);
 
3747
 
 
3748
  __attribute__((cleanup(cleanup_string)))
 
3749
    char *targetdir = make_temporary_directory();
 
3750
  g_assert_nonnull(targetdir);
 
3751
 
 
3752
  __attribute__((cleanup(cleanup_string)))
 
3753
    char *targetfilename = NULL;
 
3754
  g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir,
 
3755
                           basename(tempfilename)), >, 0);
 
3756
  g_assert_nonnull(targetfilename);
 
3757
 
 
3758
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
 
3759
                                      &password, tempdir,
 
3760
                                      &cancelled_filenames,
 
3761
                                      &current_time,
 
3762
                                      &mandos_client_exited,
 
3763
                                      &password_is_read));
 
3764
 
 
3765
  g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0);
 
3766
 
 
3767
  const task_context *const added_read_task
 
3768
    = find_matching_task(queue,
 
3769
                         (task_context){ .func=read_inotify_event });
 
3770
  g_assert_nonnull(added_read_task);
 
3771
 
 
3772
  /* "sufficient to read at least one event." - inotify(7) */
 
3773
  const size_t ievent_size = (sizeof(struct inotify_event)
 
3774
                              + NAME_MAX + 1);
 
3775
  struct inotify_event *ievent = malloc(ievent_size);
 
3776
  g_assert_nonnull(ievent);
 
3777
 
 
3778
  ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
 
3779
 
 
3780
  g_assert_cmpint((int)read_size, >, 0);
 
3781
  g_assert_true(ievent->mask & IN_MOVED_FROM);
 
3782
  g_assert_cmpstr(ievent->name, ==, basename(tempfilename));
 
3783
 
 
3784
  free(ievent);
 
3785
 
 
3786
  g_assert_cmpint(unlink(targetfilename), ==, 0);
 
3787
  g_assert_cmpint(rmdir(targetdir), ==, 0);
 
3788
  g_assert_cmpint(rmdir(tempdir), ==, 0);
 
3789
}
 
3790
 
 
3791
static
3673
3792
void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused))
3674
3793
                                          test_fixture *fixture,
3675
3794
                                          __attribute__((unused))
3733
3852
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3734
3853
}
3735
3854
 
 
3855
static
 
3856
void test_add_inotify_dir_watch_IN_EXCL_UNLINK(__attribute__((unused))
 
3857
                                               test_fixture *fixture,
 
3858
                                               __attribute__((unused))
 
3859
                                               gconstpointer
 
3860
                                               user_data){
 
3861
  __attribute__((cleanup(cleanup_close)))
 
3862
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
 
3863
  g_assert_cmpint(epoll_fd, >=, 0);
 
3864
  __attribute__((cleanup(cleanup_queue)))
 
3865
    task_queue *queue = create_queue();
 
3866
  g_assert_nonnull(queue);
 
3867
  __attribute__((cleanup(string_set_clear)))
 
3868
    string_set cancelled_filenames = {};
 
3869
  const mono_microsecs current_time = 0;
 
3870
 
 
3871
  bool quit_now = false;
 
3872
  buffer password = {};
 
3873
  bool mandos_client_exited = false;
 
3874
  bool password_is_read = false;
 
3875
 
 
3876
  __attribute__((cleanup(cleanup_string)))
 
3877
    char *tempdir = make_temporary_directory();
 
3878
  g_assert_nonnull(tempdir);
 
3879
 
 
3880
  __attribute__((cleanup(cleanup_string)))
 
3881
    char *tempfile = make_temporary_file_in_directory(tempdir);
 
3882
  g_assert_nonnull(tempfile);
 
3883
  int tempfile_fd = open(tempfile, O_WRONLY | O_CLOEXEC | O_NOCTTY
 
3884
                         | O_NOFOLLOW);
 
3885
  g_assert_cmpint(tempfile_fd, >, 2);
 
3886
 
 
3887
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
 
3888
                                      &password, tempdir,
 
3889
                                      &cancelled_filenames,
 
3890
                                      &current_time,
 
3891
                                      &mandos_client_exited,
 
3892
                                      &password_is_read));
 
3893
  g_assert_cmpint(unlink(tempfile), ==, 0);
 
3894
 
 
3895
  g_assert_cmpuint((unsigned int)queue->length, >, 0);
 
3896
 
 
3897
  const task_context *const added_read_task
 
3898
    = find_matching_task(queue,
 
3899
                         (task_context){ .func=read_inotify_event });
 
3900
  g_assert_nonnull(added_read_task);
 
3901
 
 
3902
  g_assert_cmpint(added_read_task->fd, >, 2);
 
3903
  g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
 
3904
 
 
3905
  /* "sufficient to read at least one event." - inotify(7) */
 
3906
  const size_t ievent_size = (sizeof(struct inotify_event)
 
3907
                              + NAME_MAX + 1);
 
3908
  struct inotify_event *ievent = malloc(ievent_size);
 
3909
  g_assert_nonnull(ievent);
 
3910
 
 
3911
  ssize_t read_size = 0;
 
3912
  read_size = read(added_read_task->fd, ievent, ievent_size);
 
3913
 
 
3914
  g_assert_cmpint((int)read_size, >, 0);
 
3915
  g_assert_true(ievent->mask & IN_DELETE);
 
3916
  g_assert_cmpstr(ievent->name, ==, basename(tempfile));
 
3917
 
 
3918
  g_assert_cmpint(close(tempfile_fd), ==, 0);
 
3919
 
 
3920
  /* IN_EXCL_UNLINK should make the closing of the previously unlinked
 
3921
     file not appear as an ievent, so we should not see it now. */
 
3922
  read_size = read(added_read_task->fd, ievent, ievent_size);
 
3923
  g_assert_cmpint((int)read_size, ==, -1);
 
3924
  g_assert_true(errno == EAGAIN);
 
3925
 
 
3926
  free(ievent);
 
3927
 
 
3928
  g_assert_cmpint(rmdir(tempdir), ==, 0);
 
3929
}
 
3930
 
3736
3931
static void test_read_inotify_event_readerror(__attribute__((unused))
3737
3932
                                              test_fixture *fixture,
3738
3933
                                              __attribute__((unused))
3744
3939
  const mono_microsecs current_time = 0;
3745
3940
 
3746
3941
  /* Reading /proc/self/mem from offset 0 will always result in EIO */
3747
 
  const int fd = open("/proc/self/mem", O_RDONLY | O_CLOEXEC);
 
3942
  const int fd = open("/proc/self/mem",
 
3943
                      O_RDONLY | O_CLOEXEC | O_NOCTTY);
3748
3944
 
3749
3945
  bool quit_now = false;
3750
3946
  __attribute__((cleanup(cleanup_queue)))
3929
4125
  const size_t ievent_max_size = (sizeof(struct inotify_event)
3930
4126
                                  + NAME_MAX + 1);
3931
4127
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
3932
 
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
3933
 
  struct inotify_event *ievent = ((struct inotify_event *)
3934
 
                                  ievent_buffer);
 
4128
  struct {
 
4129
    struct inotify_event event;
 
4130
    char name_buffer[NAME_MAX + 1];
 
4131
  } ievent_buffer;
 
4132
  struct inotify_event *const ievent = &ievent_buffer.event;
3935
4133
 
3936
4134
  const char dummy_file_name[] = "ask.dummy_file_name";
3937
4135
  ievent->mask = IN_CLOSE_WRITE;
3939
4137
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
3940
4138
  const size_t ievent_size = (sizeof(struct inotify_event)
3941
4139
                              + sizeof(dummy_file_name));
3942
 
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
 
4140
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
3943
4141
                  ==, ievent_size);
3944
4142
  g_assert_cmpint(close(pipefds[1]), ==, 0);
3945
4143
 
4022
4220
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4023
4221
                                  + NAME_MAX + 1);
4024
4222
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4025
 
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4026
 
  struct inotify_event *ievent = ((struct inotify_event *)
4027
 
                                  ievent_buffer);
 
4223
  struct {
 
4224
    struct inotify_event event;
 
4225
    char name_buffer[NAME_MAX + 1];
 
4226
  } ievent_buffer;
 
4227
  struct inotify_event *const ievent = &ievent_buffer.event;
4028
4228
 
4029
4229
  const char dummy_file_name[] = "ask.dummy_file_name";
4030
4230
  ievent->mask = IN_MOVED_TO;
4032
4232
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4033
4233
  const size_t ievent_size = (sizeof(struct inotify_event)
4034
4234
                              + sizeof(dummy_file_name));
4035
 
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
 
4235
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4036
4236
                  ==, ievent_size);
4037
4237
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4038
4238
 
4098
4298
      }));
4099
4299
}
4100
4300
 
 
4301
static
 
4302
void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused))
 
4303
                                           test_fixture *fixture,
 
4304
                                           __attribute__((unused))
 
4305
                                           gconstpointer user_data){
 
4306
  __attribute__((cleanup(cleanup_close)))
 
4307
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
 
4308
  g_assert_cmpint(epoll_fd, >=, 0);
 
4309
  __attribute__((cleanup(string_set_clear)))
 
4310
    string_set cancelled_filenames = {};
 
4311
  const mono_microsecs current_time = 0;
 
4312
 
 
4313
  int pipefds[2];
 
4314
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
 
4315
 
 
4316
  /* "sufficient to read at least one event." - inotify(7) */
 
4317
  const size_t ievent_max_size = (sizeof(struct inotify_event)
 
4318
                                  + NAME_MAX + 1);
 
4319
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
 
4320
  struct {
 
4321
    struct inotify_event event;
 
4322
    char name_buffer[NAME_MAX + 1];
 
4323
  } ievent_buffer;
 
4324
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4325
 
 
4326
  const char dummy_file_name[] = "ask.dummy_file_name";
 
4327
  ievent->mask = IN_MOVED_FROM;
 
4328
  ievent->len = sizeof(dummy_file_name);
 
4329
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
 
4330
  const size_t ievent_size = (sizeof(struct inotify_event)
 
4331
                              + sizeof(dummy_file_name));
 
4332
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4333
                  ==, ievent_size);
 
4334
  g_assert_cmpint(close(pipefds[1]), ==, 0);
 
4335
 
 
4336
  bool quit_now = false;
 
4337
  buffer password = {};
 
4338
  bool mandos_client_exited = false;
 
4339
  bool password_is_read = false;
 
4340
  __attribute__((cleanup(cleanup_queue)))
 
4341
    task_queue *queue = create_queue();
 
4342
  g_assert_nonnull(queue);
 
4343
 
 
4344
  task_context task = {
 
4345
    .func=read_inotify_event,
 
4346
    .epoll_fd=epoll_fd,
 
4347
    .fd=pipefds[0],
 
4348
    .quit_now=&quit_now,
 
4349
    .password=&password,
 
4350
    .filename=strdup("/nonexistent"),
 
4351
    .cancelled_filenames=&cancelled_filenames,
 
4352
    .current_time=&current_time,
 
4353
    .mandos_client_exited=&mandos_client_exited,
 
4354
    .password_is_read=&password_is_read,
 
4355
  };
 
4356
  task.func(task, queue);
 
4357
  g_assert_false(quit_now);
 
4358
  g_assert_true(queue->next_run == 0);
 
4359
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
 
4360
 
 
4361
  g_assert_nonnull(find_matching_task(queue, (task_context){
 
4362
        .func=read_inotify_event,
 
4363
        .epoll_fd=epoll_fd,
 
4364
        .fd=pipefds[0],
 
4365
        .quit_now=&quit_now,
 
4366
        .password=&password,
 
4367
        .filename=task.filename,
 
4368
        .cancelled_filenames=&cancelled_filenames,
 
4369
        .current_time=&current_time,
 
4370
        .mandos_client_exited=&mandos_client_exited,
 
4371
        .password_is_read=&password_is_read,
 
4372
      }));
 
4373
 
 
4374
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
 
4375
                                   EPOLLIN | EPOLLRDHUP));
 
4376
 
 
4377
  __attribute__((cleanup(cleanup_string)))
 
4378
    char *filename = NULL;
 
4379
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
 
4380
                           dummy_file_name), >, 0);
 
4381
  g_assert_nonnull(filename);
 
4382
  g_assert_true(string_set_contains(*task.cancelled_filenames,
 
4383
                                    filename));
 
4384
}
 
4385
 
4101
4386
static void test_read_inotify_event_IN_DELETE(__attribute__((unused))
4102
4387
                                              test_fixture *fixture,
4103
4388
                                              __attribute__((unused))
4117
4402
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4118
4403
                                  + NAME_MAX + 1);
4119
4404
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4120
 
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4121
 
  struct inotify_event *ievent = ((struct inotify_event *)
4122
 
                                  ievent_buffer);
 
4405
  struct {
 
4406
    struct inotify_event event;
 
4407
    char name_buffer[NAME_MAX + 1];
 
4408
  } ievent_buffer;
 
4409
  struct inotify_event *const ievent = &ievent_buffer.event;
4123
4410
 
4124
4411
  const char dummy_file_name[] = "ask.dummy_file_name";
4125
4412
  ievent->mask = IN_DELETE;
4127
4414
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4128
4415
  const size_t ievent_size = (sizeof(struct inotify_event)
4129
4416
                              + sizeof(dummy_file_name));
4130
 
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
 
4417
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4131
4418
                  ==, ievent_size);
4132
4419
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4133
4420
 
4199
4486
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4200
4487
                                  + NAME_MAX + 1);
4201
4488
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4202
 
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4203
 
  struct inotify_event *ievent = ((struct inotify_event *)
4204
 
                                  ievent_buffer);
 
4489
  struct {
 
4490
    struct inotify_event event;
 
4491
    char name_buffer[NAME_MAX + 1];
 
4492
  } ievent_buffer;
 
4493
  struct inotify_event *const ievent = &ievent_buffer.event;
4205
4494
 
4206
4495
  const char dummy_file_name[] = "ignored.dummy_file_name";
4207
4496
  ievent->mask = IN_CLOSE_WRITE;
4209
4498
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4210
4499
  const size_t ievent_size = (sizeof(struct inotify_event)
4211
4500
                              + sizeof(dummy_file_name));
4212
 
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
 
4501
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4213
4502
                  ==, ievent_size);
4214
4503
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4215
4504
 
4273
4562
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4274
4563
                                  + NAME_MAX + 1);
4275
4564
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4276
 
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4277
 
  struct inotify_event *ievent = ((struct inotify_event *)
4278
 
                                  ievent_buffer);
 
4565
  struct {
 
4566
    struct inotify_event event;
 
4567
    char name_buffer[NAME_MAX + 1];
 
4568
  } ievent_buffer;
 
4569
  struct inotify_event *const ievent = &ievent_buffer.event;
4279
4570
 
4280
4571
  const char dummy_file_name[] = "ignored.dummy_file_name";
4281
4572
  ievent->mask = IN_MOVED_TO;
4283
4574
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4284
4575
  const size_t ievent_size = (sizeof(struct inotify_event)
4285
4576
                              + sizeof(dummy_file_name));
4286
 
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
 
4577
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4287
4578
                  ==, ievent_size);
4288
4579
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4289
4580
 
4330
4621
                                   EPOLLIN | EPOLLRDHUP));
4331
4622
}
4332
4623
 
 
4624
static void
 
4625
test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused))
 
4626
                                              test_fixture *fixture,
 
4627
                                              __attribute__((unused))
 
4628
                                              gconstpointer
 
4629
                                              user_data){
 
4630
  __attribute__((cleanup(cleanup_close)))
 
4631
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
 
4632
  g_assert_cmpint(epoll_fd, >=, 0);
 
4633
  __attribute__((cleanup(string_set_clear)))
 
4634
    string_set cancelled_filenames = {};
 
4635
  const mono_microsecs current_time = 0;
 
4636
 
 
4637
  int pipefds[2];
 
4638
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
 
4639
 
 
4640
  /* "sufficient to read at least one event." - inotify(7) */
 
4641
  const size_t ievent_max_size = (sizeof(struct inotify_event)
 
4642
                                  + NAME_MAX + 1);
 
4643
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
 
4644
  struct {
 
4645
    struct inotify_event event;
 
4646
    char name_buffer[NAME_MAX + 1];
 
4647
  } ievent_buffer;
 
4648
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4649
 
 
4650
  const char dummy_file_name[] = "ignored.dummy_file_name";
 
4651
  ievent->mask = IN_MOVED_FROM;
 
4652
  ievent->len = sizeof(dummy_file_name);
 
4653
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
 
4654
  const size_t ievent_size = (sizeof(struct inotify_event)
 
4655
                              + sizeof(dummy_file_name));
 
4656
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4657
                  ==, ievent_size);
 
4658
  g_assert_cmpint(close(pipefds[1]), ==, 0);
 
4659
 
 
4660
  bool quit_now = false;
 
4661
  buffer password = {};
 
4662
  bool mandos_client_exited = false;
 
4663
  bool password_is_read = false;
 
4664
  __attribute__((cleanup(cleanup_queue)))
 
4665
    task_queue *queue = create_queue();
 
4666
  g_assert_nonnull(queue);
 
4667
 
 
4668
  task_context task = {
 
4669
    .func=read_inotify_event,
 
4670
    .epoll_fd=epoll_fd,
 
4671
    .fd=pipefds[0],
 
4672
    .quit_now=&quit_now,
 
4673
    .password=&password,
 
4674
    .filename=strdup("/nonexistent"),
 
4675
    .cancelled_filenames=&cancelled_filenames,
 
4676
    .current_time=&current_time,
 
4677
    .mandos_client_exited=&mandos_client_exited,
 
4678
    .password_is_read=&password_is_read,
 
4679
  };
 
4680
  task.func(task, queue);
 
4681
  g_assert_false(quit_now);
 
4682
  g_assert_true(queue->next_run == 0);
 
4683
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
 
4684
 
 
4685
  g_assert_nonnull(find_matching_task(queue, (task_context){
 
4686
        .func=read_inotify_event,
 
4687
        .epoll_fd=epoll_fd,
 
4688
        .fd=pipefds[0],
 
4689
        .quit_now=&quit_now,
 
4690
        .password=&password,
 
4691
        .filename=task.filename,
 
4692
        .cancelled_filenames=&cancelled_filenames,
 
4693
        .current_time=&current_time,
 
4694
        .mandos_client_exited=&mandos_client_exited,
 
4695
        .password_is_read=&password_is_read,
 
4696
      }));
 
4697
 
 
4698
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
 
4699
                                   EPOLLIN | EPOLLRDHUP));
 
4700
 
 
4701
  __attribute__((cleanup(cleanup_string)))
 
4702
    char *filename = NULL;
 
4703
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
 
4704
                           dummy_file_name), >, 0);
 
4705
  g_assert_nonnull(filename);
 
4706
  g_assert_false(string_set_contains(cancelled_filenames, filename));
 
4707
}
 
4708
 
4333
4709
static
4334
4710
void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused))
4335
4711
                                               test_fixture *fixture,
4350
4726
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4351
4727
                                  + NAME_MAX + 1);
4352
4728
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4353
 
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4354
 
  struct inotify_event *ievent = ((struct inotify_event *)
4355
 
                                  ievent_buffer);
 
4729
  struct {
 
4730
    struct inotify_event event;
 
4731
    char name_buffer[NAME_MAX + 1];
 
4732
  } ievent_buffer;
 
4733
  struct inotify_event *const ievent = &ievent_buffer.event;
4356
4734
 
4357
4735
  const char dummy_file_name[] = "ignored.dummy_file_name";
4358
4736
  ievent->mask = IN_DELETE;
4360
4738
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4361
4739
  const size_t ievent_size = (sizeof(struct inotify_event)
4362
4740
                              + sizeof(dummy_file_name));
4363
 
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
 
4741
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4364
4742
                  ==, ievent_size);
4365
4743
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4366
4744
 
5253
5631
                                            __attribute__((unused))
5254
5632
                                            gconstpointer user_data){
5255
5633
  __attribute__((cleanup(cleanup_close)))
5256
 
    const int epoll_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
 
5634
    const int epoll_fd = open("/dev/null",
 
5635
                              O_WRONLY | O_CLOEXEC | O_NOCTTY);
5257
5636
  __attribute__((cleanup(cleanup_string)))
5258
5637
    char *const question_filename = strdup("/nonexistent/question");
5259
5638
  g_assert_nonnull(question_filename);
5663
6042
                                            __attribute__((unused))
5664
6043
                                            gconstpointer user_data){
5665
6044
  __attribute__((cleanup(cleanup_close)))
5666
 
    const int epoll_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
 
6045
    const int epoll_fd = open("/dev/null",
 
6046
                              O_WRONLY | O_CLOEXEC | O_NOCTTY);
5667
6047
  __attribute__((cleanup(cleanup_string)))
5668
6048
    char *const question_filename = strdup("/nonexistent/question");
5669
6049
  g_assert_nonnull(question_filename);
5932
6312
                                              const char *const
5933
6313
                                              dirname){
5934
6314
  __attribute__((cleanup(cleanup_close)))
5935
 
    const int devnull_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
 
6315
    const int devnull_fd = open("/dev/null",
 
6316
                                O_WRONLY | O_CLOEXEC | O_NOCTTY);
5936
6317
  g_assert_cmpint(devnull_fd, >=, 0);
5937
6318
  __attribute__((cleanup(cleanup_close)))
5938
6319
    const int real_stderr_fd = dup(STDERR_FILENO);
7573
7954
              test_add_inotify_dir_watch);
7574
7955
  test_add_st("/task-creators/add_inotify_dir_watch/fail",
7575
7956
              test_add_inotify_dir_watch_fail);
 
7957
  test_add_st("/task-creators/add_inotify_dir_watch/not-a-directory",
 
7958
              test_add_inotify_dir_watch_nondir);
7576
7959
  test_add_st("/task-creators/add_inotify_dir_watch/EAGAIN",
7577
7960
              test_add_inotify_dir_watch_EAGAIN);
7578
7961
  test_add_st("/task-creators/add_inotify_dir_watch/IN_CLOSE_WRITE",
7579
7962
              test_add_inotify_dir_watch_IN_CLOSE_WRITE);
7580
7963
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO",
7581
7964
              test_add_inotify_dir_watch_IN_MOVED_TO);
 
7965
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM",
 
7966
              test_add_inotify_dir_watch_IN_MOVED_FROM);
 
7967
  test_add_st("/task-creators/add_inotify_dir_watch/IN_EXCL_UNLINK",
 
7968
              test_add_inotify_dir_watch_IN_EXCL_UNLINK);
7582
7969
  test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE",
7583
7970
              test_add_inotify_dir_watch_IN_DELETE);
7584
7971
  test_add_st("/task/read_inotify_event/readerror",
7593
7980
              test_read_inotify_event_IN_CLOSE_WRITE);
7594
7981
  test_add_st("/task/read_inotify_event/IN_MOVED_TO",
7595
7982
              test_read_inotify_event_IN_MOVED_TO);
 
7983
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM",
 
7984
              test_read_inotify_event_IN_MOVED_FROM);
7596
7985
  test_add_st("/task/read_inotify_event/IN_DELETE",
7597
7986
              test_read_inotify_event_IN_DELETE);
7598
7987
  test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname",
7599
7988
              test_read_inotify_event_IN_CLOSE_WRITE_badname);
7600
7989
  test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname",
7601
7990
              test_read_inotify_event_IN_MOVED_TO_badname);
 
7991
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname",
 
7992
              test_read_inotify_event_IN_MOVED_FROM_badname);
7602
7993
  test_add_st("/task/read_inotify_event/IN_DELETE/badname",
7603
7994
              test_read_inotify_event_IN_DELETE_badname);
7604
7995
  test_add_st("/task/open_and_parse_question/ENOENT",