/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: 2019-07-27 10:11:45 UTC
  • mto: This revision was merged to the branch mainline in revision 384.
  • Revision ID: teddy@recompile.se-20190727101145-jnpbpf8220gldbcd
Add dracut(8) support

Add support for the dracut(8) system for generating initramfs image
files; dracut is an alternative to the "initramfs-tools" package.

* .bzrignore (dracut-module/password-agent): Ignore new binary file.
* dracut-module: New directory for the dracut module.
* INSTALL (Prerequisites/Libraries/Mandos Client): Add dracut as an
                                                   alternative to
                                                   initramfs-tools,
                                                   and also add GLib.
* Makefile (DRACUTMODULE, GLIB_CFLAGS, GLIB_LIBS): New.
  (CPROGS): Add "dracut-module/password-agent".
  (DOCS): Add "dracut-module/password-agent.8mandos".
  (dracut-module/password-agent.8mandos): New.
  (dracut-module/password-agent.8mandos.xhtml): - '' -
  (dracut-module/password-agent): - '' -
  (check): Add command to run tests of password-agent(8mandos).
  (install-client-nokey): Also install the dracut module directory,
                          its files, and the password-agent(8mandos)
                          manual page.
  (install-client): To update the initramfs image file, run
                    update-initramfs or dracut depending on what is
                    installed.
  (uninstall-client): - '' - and also uninstall the the files in the
                      dracut module directory, that directory itself,
                      and the password-agent(8mandos) manual page.
* debian/control (Build-Depends): Add "libglib2.0-dev (>=2.40)".
  (Package: mandos-client/Depends): Add "dracut (>= 044+241-3)" as an
                                    alternative dependency to
                                    initramfs-tools.
  (Package: mandos-client/Conflicts): New; set to
                                      "dracut-config-generic".
  (debian/mandos-client.README.Debian): Document alternative commands
                                        to update the initramfs image
                                        for when dracut is used.
* debian/mandos-client.postinst (update_initramfs): Use alternative
                                                    commands to update
                                                    the initramfs
                                                    image for when
                                                    dracut is used.
* debian/tests/control (password-agent, password-agent-suid): Add two
                                                              new tests.
* dracut-module/ask-password-mandos.path: New.
* dracut-module/ask-password-mandos.service: - '' -
* dracut-module/cmdline-mandos.sh: - '' -
* dracut-module/module-setup.sh: - '' -
* dracut-module/password-agent.c: - '' -
* dracut-module/password-agent.xml: - '' -
* initramfs-unpack: Use the dracut "skipcpio" command, if available.
                    Also be more flexible and try hard to detect where
                    compressed data starts.
* plugins.d/mandos-client.xml (SECURITY): Be more precise that the
                                          mandos-client binary might
                                          not always be setuid, but
                                          that the program assumes
                                          that it has been started
                                          that way.
* plugins.d/password-prompt.c: Add new "--prompt" option.
  (conflict_detection): First try to detect the new PID file of
                        plymouth.
  (main): Define and use new "prompt" variable.
* plugins.d/password-prompt.xml (SYNOPSIS): Show new --prompt option.
  (DESCRIPTION): Describe new behavior of looking for plymouth PID
                 file.
  (OPTIONS): Document new "--prompt" option.
  (ENVIRONMENT): Clarify that the CRYPTTAB_SOURCE and CRYPTTAB_NAME
                 environment variables are not used if the --prompt
                 option is used.  Remove unnecessarily specific
                 details about where the CRYPTTAB_SOURCE and
                 CRYPTTAB_NAME comes from, since this can now be
                 either initramfs-tools or dracut.
  (SEE ALSO): Remove superfluous crypttab(5) reference, and add commas
              to separate the other references.
* plugins.d/plymouth.c: Add new "--prompt" and "--debug" options.
  (debug): New global flag.
  (fprintf_plus): New function, used for debug output.
  (exec_and_wait): Add extra "const" to "argv" argument.
  (main): Define and use new "prompt" variable.  Add debug output.
  (main/options, main/parse_opt): New; used to parse options.
* plugins.d/plymouth.xml (SYNOPSIS): Show new options.
  (OPTIONS): Document new options.
  (ENVIRONMENT): Clarify that the cryptsource and crypttarget
                 environment variables are not used if the --prompt
                 option is used.  Remove unnecessarily specific
                 details about where the cryptsource and crypttarget
                 comes from, since this can now be either
                 initramfs-tools or dracut.
  (EXAMPLE): Add an example using an option.
  (SEE ALSO): Remove superfluous crypttab(5) reference.
* plugins.d/splashy.xml (ENVIRONMENT): Clarify that the cryptsource
                                       and crypttarget environment
                                       variables are not used if the
                                       --prompt option is used.
                                       Remove unnecessarily specific
                                       details about where the
                                       cryptsource and crypttarget
                                       comes from, since this can now
                                       be either initramfs-tools or
                                       dracut.
  (SEE ALSO): Remove superfluous crypttab(5) reference.
* plugins.d/usplash.xml (ENVIRONMENT): Clarify that the cryptsource
                                       and crypttarget environment
                                       variables are not used if the
                                       --prompt option is used.
                                       Remove unnecessarily specific
                                       details about where the
                                       cryptsource and crypttarget
                                       comes from, since this can now
                                       be either initramfs-tools or
                                       dracut.
  (SEE ALSO): Remove superfluous crypttab(5) reference.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1017
1017
    return false;
1018
1018
  }
1019
1019
 
1020
 
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO
1021
 
                       | IN_MOVED_FROM| IN_DELETE | IN_EXCL_UNLINK)
 
1020
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE
 
1021
                       | IN_MOVED_TO | IN_DELETE)
1022
1022
     == -1){
1023
1023
    error(0, errno, "Failed to create inotify watch on %s", dir);
1024
1024
    return false;
1071
1071
  /* "sufficient to read at least one event." - inotify(7) */
1072
1072
  const size_t ievent_size = (sizeof(struct inotify_event)
1073
1073
                              + NAME_MAX + 1);
1074
 
  struct {
1075
 
    struct inotify_event event;
1076
 
    char name_buffer[NAME_MAX + 1];
1077
 
  } ievent_buffer;
1078
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
1074
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
1075
  struct inotify_event *ievent = ((struct inotify_event *)
 
1076
                                  ievent_buffer);
1079
1077
 
1080
1078
  const ssize_t read_length = read(fd, ievent, ievent_size);
1081
1079
  if(read_length == 0){ /* EOF */
1119
1117
             immediately */
1120
1118
          queue->next_run = 1;
1121
1119
        }
1122
 
      } else if(ievent->mask & (IN_MOVED_FROM | IN_DELETE)){
 
1120
      } else if(ievent->mask & IN_DELETE){
1123
1121
        if(not string_set_add(cancelled_filenames,
1124
1122
                              question_filename)){
1125
1123
          error(0, errno, "Could not add question %s to"
3672
3670
}
3673
3671
 
3674
3672
static
3675
 
void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused))
3676
 
                                              test_fixture *fixture,
3677
 
                                              __attribute__((unused))
3678
 
                                              gconstpointer
3679
 
                                              user_data){
3680
 
  __attribute__((cleanup(cleanup_close)))
3681
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3682
 
  g_assert_cmpint(epoll_fd, >=, 0);
3683
 
  __attribute__((cleanup(cleanup_queue)))
3684
 
    task_queue *queue = create_queue();
3685
 
  g_assert_nonnull(queue);
3686
 
  __attribute__((cleanup(string_set_clear)))
3687
 
    string_set cancelled_filenames = {};
3688
 
  const mono_microsecs current_time = 0;
3689
 
 
3690
 
  bool quit_now = false;
3691
 
  buffer password = {};
3692
 
  bool mandos_client_exited = false;
3693
 
  bool password_is_read = false;
3694
 
 
3695
 
  __attribute__((cleanup(cleanup_string)))
3696
 
    char *tempdir = make_temporary_directory();
3697
 
  g_assert_nonnull(tempdir);
3698
 
 
3699
 
  __attribute__((cleanup(cleanup_string)))
3700
 
    char *tempfilename = make_temporary_file_in_directory(tempdir);
3701
 
  g_assert_nonnull(tempfilename);
3702
 
 
3703
 
  __attribute__((cleanup(cleanup_string)))
3704
 
    char *targetdir = make_temporary_directory();
3705
 
  g_assert_nonnull(targetdir);
3706
 
 
3707
 
  __attribute__((cleanup(cleanup_string)))
3708
 
    char *targetfilename = NULL;
3709
 
  g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir,
3710
 
                           basename(tempfilename)), >, 0);
3711
 
  g_assert_nonnull(targetfilename);
3712
 
 
3713
 
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3714
 
                                      &password, tempdir,
3715
 
                                      &cancelled_filenames,
3716
 
                                      &current_time,
3717
 
                                      &mandos_client_exited,
3718
 
                                      &password_is_read));
3719
 
 
3720
 
  g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0);
3721
 
 
3722
 
  const task_context *const added_read_task
3723
 
    = find_matching_task(queue,
3724
 
                         (task_context){ .func=read_inotify_event });
3725
 
  g_assert_nonnull(added_read_task);
3726
 
 
3727
 
  /* "sufficient to read at least one event." - inotify(7) */
3728
 
  const size_t ievent_size = (sizeof(struct inotify_event)
3729
 
                              + NAME_MAX + 1);
3730
 
  struct inotify_event *ievent = malloc(ievent_size);
3731
 
  g_assert_nonnull(ievent);
3732
 
 
3733
 
  ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
3734
 
 
3735
 
  g_assert_cmpint((int)read_size, >, 0);
3736
 
  g_assert_true(ievent->mask & IN_MOVED_FROM);
3737
 
  g_assert_cmpstr(ievent->name, ==, basename(tempfilename));
3738
 
 
3739
 
  free(ievent);
3740
 
 
3741
 
  g_assert_cmpint(unlink(targetfilename), ==, 0);
3742
 
  g_assert_cmpint(rmdir(targetdir), ==, 0);
3743
 
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3744
 
}
3745
 
 
3746
 
static
3747
3673
void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused))
3748
3674
                                          test_fixture *fixture,
3749
3675
                                          __attribute__((unused))
3807
3733
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3808
3734
}
3809
3735
 
3810
 
static
3811
 
void test_add_inotify_dir_watch_IN_EXCL_UNLINK(__attribute__((unused))
3812
 
                                               test_fixture *fixture,
3813
 
                                               __attribute__((unused))
3814
 
                                               gconstpointer
3815
 
                                               user_data){
3816
 
  __attribute__((cleanup(cleanup_close)))
3817
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3818
 
  g_assert_cmpint(epoll_fd, >=, 0);
3819
 
  __attribute__((cleanup(cleanup_queue)))
3820
 
    task_queue *queue = create_queue();
3821
 
  g_assert_nonnull(queue);
3822
 
  __attribute__((cleanup(string_set_clear)))
3823
 
    string_set cancelled_filenames = {};
3824
 
  const mono_microsecs current_time = 0;
3825
 
 
3826
 
  bool quit_now = false;
3827
 
  buffer password = {};
3828
 
  bool mandos_client_exited = false;
3829
 
  bool password_is_read = false;
3830
 
 
3831
 
  __attribute__((cleanup(cleanup_string)))
3832
 
    char *tempdir = make_temporary_directory();
3833
 
  g_assert_nonnull(tempdir);
3834
 
 
3835
 
  __attribute__((cleanup(cleanup_string)))
3836
 
    char *tempfile = make_temporary_file_in_directory(tempdir);
3837
 
  g_assert_nonnull(tempfile);
3838
 
  int tempfile_fd = open(tempfile, O_WRONLY | O_CLOEXEC | O_NOCTTY
3839
 
                         | O_NOFOLLOW);
3840
 
  g_assert_cmpint(tempfile_fd, >, 2);
3841
 
 
3842
 
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3843
 
                                      &password, tempdir,
3844
 
                                      &cancelled_filenames,
3845
 
                                      &current_time,
3846
 
                                      &mandos_client_exited,
3847
 
                                      &password_is_read));
3848
 
  g_assert_cmpint(unlink(tempfile), ==, 0);
3849
 
 
3850
 
  g_assert_cmpuint((unsigned int)queue->length, >, 0);
3851
 
 
3852
 
  const task_context *const added_read_task
3853
 
    = find_matching_task(queue,
3854
 
                         (task_context){ .func=read_inotify_event });
3855
 
  g_assert_nonnull(added_read_task);
3856
 
 
3857
 
  g_assert_cmpint(added_read_task->fd, >, 2);
3858
 
  g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
3859
 
 
3860
 
  /* "sufficient to read at least one event." - inotify(7) */
3861
 
  const size_t ievent_size = (sizeof(struct inotify_event)
3862
 
                              + NAME_MAX + 1);
3863
 
  struct inotify_event *ievent = malloc(ievent_size);
3864
 
  g_assert_nonnull(ievent);
3865
 
 
3866
 
  ssize_t read_size = 0;
3867
 
  read_size = read(added_read_task->fd, ievent, ievent_size);
3868
 
 
3869
 
  g_assert_cmpint((int)read_size, >, 0);
3870
 
  g_assert_true(ievent->mask & IN_DELETE);
3871
 
  g_assert_cmpstr(ievent->name, ==, basename(tempfile));
3872
 
 
3873
 
  g_assert_cmpint(close(tempfile_fd), ==, 0);
3874
 
 
3875
 
  /* IN_EXCL_UNLINK should make the closing of the previously unlinked
3876
 
     file not appear as an ievent, so we should not see it now. */
3877
 
  read_size = read(added_read_task->fd, ievent, ievent_size);
3878
 
  g_assert_cmpint((int)read_size, ==, -1);
3879
 
  g_assert_true(errno == EAGAIN);
3880
 
 
3881
 
  free(ievent);
3882
 
 
3883
 
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3884
 
}
3885
 
 
3886
3736
static void test_read_inotify_event_readerror(__attribute__((unused))
3887
3737
                                              test_fixture *fixture,
3888
3738
                                              __attribute__((unused))
4079
3929
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4080
3930
                                  + NAME_MAX + 1);
4081
3931
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4082
 
  struct {
4083
 
    struct inotify_event event;
4084
 
    char name_buffer[NAME_MAX + 1];
4085
 
  } ievent_buffer;
4086
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
3932
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
3933
  struct inotify_event *ievent = ((struct inotify_event *)
 
3934
                                  ievent_buffer);
4087
3935
 
4088
3936
  const char dummy_file_name[] = "ask.dummy_file_name";
4089
3937
  ievent->mask = IN_CLOSE_WRITE;
4091
3939
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4092
3940
  const size_t ievent_size = (sizeof(struct inotify_event)
4093
3941
                              + sizeof(dummy_file_name));
4094
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
3942
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4095
3943
                  ==, ievent_size);
4096
3944
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4097
3945
 
4174
4022
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4175
4023
                                  + NAME_MAX + 1);
4176
4024
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4177
 
  struct {
4178
 
    struct inotify_event event;
4179
 
    char name_buffer[NAME_MAX + 1];
4180
 
  } ievent_buffer;
4181
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4025
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4026
  struct inotify_event *ievent = ((struct inotify_event *)
 
4027
                                  ievent_buffer);
4182
4028
 
4183
4029
  const char dummy_file_name[] = "ask.dummy_file_name";
4184
4030
  ievent->mask = IN_MOVED_TO;
4186
4032
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4187
4033
  const size_t ievent_size = (sizeof(struct inotify_event)
4188
4034
                              + sizeof(dummy_file_name));
4189
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4035
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4190
4036
                  ==, ievent_size);
4191
4037
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4192
4038
 
4252
4098
      }));
4253
4099
}
4254
4100
 
4255
 
static
4256
 
void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused))
4257
 
                                           test_fixture *fixture,
4258
 
                                           __attribute__((unused))
4259
 
                                           gconstpointer user_data){
4260
 
  __attribute__((cleanup(cleanup_close)))
4261
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4262
 
  g_assert_cmpint(epoll_fd, >=, 0);
4263
 
  __attribute__((cleanup(string_set_clear)))
4264
 
    string_set cancelled_filenames = {};
4265
 
  const mono_microsecs current_time = 0;
4266
 
 
4267
 
  int pipefds[2];
4268
 
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4269
 
 
4270
 
  /* "sufficient to read at least one event." - inotify(7) */
4271
 
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4272
 
                                  + NAME_MAX + 1);
4273
 
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4274
 
  struct {
4275
 
    struct inotify_event event;
4276
 
    char name_buffer[NAME_MAX + 1];
4277
 
  } ievent_buffer;
4278
 
  struct inotify_event *const ievent = &ievent_buffer.event;
4279
 
 
4280
 
  const char dummy_file_name[] = "ask.dummy_file_name";
4281
 
  ievent->mask = IN_MOVED_FROM;
4282
 
  ievent->len = sizeof(dummy_file_name);
4283
 
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4284
 
  const size_t ievent_size = (sizeof(struct inotify_event)
4285
 
                              + sizeof(dummy_file_name));
4286
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4287
 
                  ==, ievent_size);
4288
 
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4289
 
 
4290
 
  bool quit_now = false;
4291
 
  buffer password = {};
4292
 
  bool mandos_client_exited = false;
4293
 
  bool password_is_read = false;
4294
 
  __attribute__((cleanup(cleanup_queue)))
4295
 
    task_queue *queue = create_queue();
4296
 
  g_assert_nonnull(queue);
4297
 
 
4298
 
  task_context task = {
4299
 
    .func=read_inotify_event,
4300
 
    .epoll_fd=epoll_fd,
4301
 
    .fd=pipefds[0],
4302
 
    .quit_now=&quit_now,
4303
 
    .password=&password,
4304
 
    .filename=strdup("/nonexistent"),
4305
 
    .cancelled_filenames=&cancelled_filenames,
4306
 
    .current_time=&current_time,
4307
 
    .mandos_client_exited=&mandos_client_exited,
4308
 
    .password_is_read=&password_is_read,
4309
 
  };
4310
 
  task.func(task, queue);
4311
 
  g_assert_false(quit_now);
4312
 
  g_assert_true(queue->next_run == 0);
4313
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4314
 
 
4315
 
  g_assert_nonnull(find_matching_task(queue, (task_context){
4316
 
        .func=read_inotify_event,
4317
 
        .epoll_fd=epoll_fd,
4318
 
        .fd=pipefds[0],
4319
 
        .quit_now=&quit_now,
4320
 
        .password=&password,
4321
 
        .filename=task.filename,
4322
 
        .cancelled_filenames=&cancelled_filenames,
4323
 
        .current_time=&current_time,
4324
 
        .mandos_client_exited=&mandos_client_exited,
4325
 
        .password_is_read=&password_is_read,
4326
 
      }));
4327
 
 
4328
 
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4329
 
                                   EPOLLIN | EPOLLRDHUP));
4330
 
 
4331
 
  __attribute__((cleanup(cleanup_string)))
4332
 
    char *filename = NULL;
4333
 
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4334
 
                           dummy_file_name), >, 0);
4335
 
  g_assert_nonnull(filename);
4336
 
  g_assert_true(string_set_contains(*task.cancelled_filenames,
4337
 
                                    filename));
4338
 
}
4339
 
 
4340
4101
static void test_read_inotify_event_IN_DELETE(__attribute__((unused))
4341
4102
                                              test_fixture *fixture,
4342
4103
                                              __attribute__((unused))
4356
4117
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4357
4118
                                  + NAME_MAX + 1);
4358
4119
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4359
 
  struct {
4360
 
    struct inotify_event event;
4361
 
    char name_buffer[NAME_MAX + 1];
4362
 
  } ievent_buffer;
4363
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4120
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4121
  struct inotify_event *ievent = ((struct inotify_event *)
 
4122
                                  ievent_buffer);
4364
4123
 
4365
4124
  const char dummy_file_name[] = "ask.dummy_file_name";
4366
4125
  ievent->mask = IN_DELETE;
4368
4127
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4369
4128
  const size_t ievent_size = (sizeof(struct inotify_event)
4370
4129
                              + sizeof(dummy_file_name));
4371
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4130
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4372
4131
                  ==, ievent_size);
4373
4132
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4374
4133
 
4440
4199
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4441
4200
                                  + NAME_MAX + 1);
4442
4201
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4443
 
  struct {
4444
 
    struct inotify_event event;
4445
 
    char name_buffer[NAME_MAX + 1];
4446
 
  } ievent_buffer;
4447
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4202
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4203
  struct inotify_event *ievent = ((struct inotify_event *)
 
4204
                                  ievent_buffer);
4448
4205
 
4449
4206
  const char dummy_file_name[] = "ignored.dummy_file_name";
4450
4207
  ievent->mask = IN_CLOSE_WRITE;
4452
4209
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4453
4210
  const size_t ievent_size = (sizeof(struct inotify_event)
4454
4211
                              + sizeof(dummy_file_name));
4455
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4212
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4456
4213
                  ==, ievent_size);
4457
4214
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4458
4215
 
4516
4273
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4517
4274
                                  + NAME_MAX + 1);
4518
4275
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4519
 
  struct {
4520
 
    struct inotify_event event;
4521
 
    char name_buffer[NAME_MAX + 1];
4522
 
  } ievent_buffer;
4523
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4276
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4277
  struct inotify_event *ievent = ((struct inotify_event *)
 
4278
                                  ievent_buffer);
4524
4279
 
4525
4280
  const char dummy_file_name[] = "ignored.dummy_file_name";
4526
4281
  ievent->mask = IN_MOVED_TO;
4528
4283
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4529
4284
  const size_t ievent_size = (sizeof(struct inotify_event)
4530
4285
                              + sizeof(dummy_file_name));
4531
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4286
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4532
4287
                  ==, ievent_size);
4533
4288
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4534
4289
 
4575
4330
                                   EPOLLIN | EPOLLRDHUP));
4576
4331
}
4577
4332
 
4578
 
static void
4579
 
test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused))
4580
 
                                              test_fixture *fixture,
4581
 
                                              __attribute__((unused))
4582
 
                                              gconstpointer
4583
 
                                              user_data){
4584
 
  __attribute__((cleanup(cleanup_close)))
4585
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4586
 
  g_assert_cmpint(epoll_fd, >=, 0);
4587
 
  __attribute__((cleanup(string_set_clear)))
4588
 
    string_set cancelled_filenames = {};
4589
 
  const mono_microsecs current_time = 0;
4590
 
 
4591
 
  int pipefds[2];
4592
 
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4593
 
 
4594
 
  /* "sufficient to read at least one event." - inotify(7) */
4595
 
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4596
 
                                  + NAME_MAX + 1);
4597
 
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4598
 
  struct {
4599
 
    struct inotify_event event;
4600
 
    char name_buffer[NAME_MAX + 1];
4601
 
  } ievent_buffer;
4602
 
  struct inotify_event *const ievent = &ievent_buffer.event;
4603
 
 
4604
 
  const char dummy_file_name[] = "ignored.dummy_file_name";
4605
 
  ievent->mask = IN_MOVED_FROM;
4606
 
  ievent->len = sizeof(dummy_file_name);
4607
 
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4608
 
  const size_t ievent_size = (sizeof(struct inotify_event)
4609
 
                              + sizeof(dummy_file_name));
4610
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4611
 
                  ==, ievent_size);
4612
 
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4613
 
 
4614
 
  bool quit_now = false;
4615
 
  buffer password = {};
4616
 
  bool mandos_client_exited = false;
4617
 
  bool password_is_read = false;
4618
 
  __attribute__((cleanup(cleanup_queue)))
4619
 
    task_queue *queue = create_queue();
4620
 
  g_assert_nonnull(queue);
4621
 
 
4622
 
  task_context task = {
4623
 
    .func=read_inotify_event,
4624
 
    .epoll_fd=epoll_fd,
4625
 
    .fd=pipefds[0],
4626
 
    .quit_now=&quit_now,
4627
 
    .password=&password,
4628
 
    .filename=strdup("/nonexistent"),
4629
 
    .cancelled_filenames=&cancelled_filenames,
4630
 
    .current_time=&current_time,
4631
 
    .mandos_client_exited=&mandos_client_exited,
4632
 
    .password_is_read=&password_is_read,
4633
 
  };
4634
 
  task.func(task, queue);
4635
 
  g_assert_false(quit_now);
4636
 
  g_assert_true(queue->next_run == 0);
4637
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4638
 
 
4639
 
  g_assert_nonnull(find_matching_task(queue, (task_context){
4640
 
        .func=read_inotify_event,
4641
 
        .epoll_fd=epoll_fd,
4642
 
        .fd=pipefds[0],
4643
 
        .quit_now=&quit_now,
4644
 
        .password=&password,
4645
 
        .filename=task.filename,
4646
 
        .cancelled_filenames=&cancelled_filenames,
4647
 
        .current_time=&current_time,
4648
 
        .mandos_client_exited=&mandos_client_exited,
4649
 
        .password_is_read=&password_is_read,
4650
 
      }));
4651
 
 
4652
 
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4653
 
                                   EPOLLIN | EPOLLRDHUP));
4654
 
 
4655
 
  __attribute__((cleanup(cleanup_string)))
4656
 
    char *filename = NULL;
4657
 
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4658
 
                           dummy_file_name), >, 0);
4659
 
  g_assert_nonnull(filename);
4660
 
  g_assert_false(string_set_contains(cancelled_filenames, filename));
4661
 
}
4662
 
 
4663
4333
static
4664
4334
void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused))
4665
4335
                                               test_fixture *fixture,
4680
4350
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4681
4351
                                  + NAME_MAX + 1);
4682
4352
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4683
 
  struct {
4684
 
    struct inotify_event event;
4685
 
    char name_buffer[NAME_MAX + 1];
4686
 
  } ievent_buffer;
4687
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4353
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4354
  struct inotify_event *ievent = ((struct inotify_event *)
 
4355
                                  ievent_buffer);
4688
4356
 
4689
4357
  const char dummy_file_name[] = "ignored.dummy_file_name";
4690
4358
  ievent->mask = IN_DELETE;
4692
4360
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4693
4361
  const size_t ievent_size = (sizeof(struct inotify_event)
4694
4362
                              + sizeof(dummy_file_name));
4695
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4363
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4696
4364
                  ==, ievent_size);
4697
4365
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4698
4366
 
7911
7579
              test_add_inotify_dir_watch_IN_CLOSE_WRITE);
7912
7580
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO",
7913
7581
              test_add_inotify_dir_watch_IN_MOVED_TO);
7914
 
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM",
7915
 
              test_add_inotify_dir_watch_IN_MOVED_FROM);
7916
 
  test_add_st("/task-creators/add_inotify_dir_watch/IN_EXCL_UNLINK",
7917
 
              test_add_inotify_dir_watch_IN_EXCL_UNLINK);
7918
7582
  test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE",
7919
7583
              test_add_inotify_dir_watch_IN_DELETE);
7920
7584
  test_add_st("/task/read_inotify_event/readerror",
7929
7593
              test_read_inotify_event_IN_CLOSE_WRITE);
7930
7594
  test_add_st("/task/read_inotify_event/IN_MOVED_TO",
7931
7595
              test_read_inotify_event_IN_MOVED_TO);
7932
 
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM",
7933
 
              test_read_inotify_event_IN_MOVED_FROM);
7934
7596
  test_add_st("/task/read_inotify_event/IN_DELETE",
7935
7597
              test_read_inotify_event_IN_DELETE);
7936
7598
  test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname",
7937
7599
              test_read_inotify_event_IN_CLOSE_WRITE_badname);
7938
7600
  test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname",
7939
7601
              test_read_inotify_event_IN_MOVED_TO_badname);
7940
 
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname",
7941
 
              test_read_inotify_event_IN_MOVED_FROM_badname);
7942
7602
  test_add_st("/task/read_inotify_event/IN_DELETE/badname",
7943
7603
              test_read_inotify_event_IN_DELETE_badname);
7944
7604
  test_add_st("/task/open_and_parse_question/ENOENT",