/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: 2021-02-04 17:59:45 UTC
  • Revision ID: teddy@recompile.se-20210204175945-8druo6d88ipc1z58
Fix issue with french translation

Initial white space was missing in both msgid and msgstr of the french
translation, leading to checking tools reporing an incomplete
translation.  The string is a raw key id, and therefore did not need
translation, so this was never a user-visible issue.

* debian/po/fr.po: Add missing whitespace to the id and translation
  for msgid " ${key_id}".

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Mandos password agent - Simple password agent to run Mandos client
4
4
 *
5
 
 * Copyright © 2019-2020 Teddy Hogeborn
6
 
 * Copyright © 2019-2020 Björn Påhlsson
 
5
 * Copyright © 2019-2021 Teddy Hogeborn
 
6
 * Copyright © 2019-2021 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,
1193
1196
  bool *const password_is_read = task.password_is_read;
1194
1197
 
1195
1198
  /* 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 */
 
1199
     question file.  See <https://systemd.io/PASSWORD_AGENTS/> for
 
1200
     specification of contents */
1198
1201
  __attribute__((nonnull))
1199
1202
    void cleanup_g_key_file(GKeyFile **key_file){
1200
1203
    if(*key_file != NULL){
1490
1493
         not. You may but don't have to include a final NUL byte in
1491
1494
         your message.
1492
1495
 
1493
 
         — <https://www.freedesktop.org/wiki/Software/systemd/
1494
 
         PasswordAgents/> (Wed 08 Oct 2014 02:14:28 AM UTC)
 
1496
         — <https://systemd.io/PASSWORD_AGENTS/> (Tue, 15 Sep 2020
 
1497
         14:24:20 GMT)
1495
1498
      */
1496
1499
      send_buffer[0] = '+';     /* Prefix with "+" */
1497
1500
      /* Always add an extra NUL */
1502
1505
      errno = 0;
1503
1506
      ssize_t ssret = send(fd, send_buffer, send_buffer_length,
1504
1507
                           MSG_NOSIGNAL);
1505
 
      const error_t saved_errno = errno;
 
1508
      const error_t saved_errno = (ssret < 0) ? errno : 0;
1506
1509
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 25)
1507
1510
      explicit_bzero(send_buffer, send_buffer_length);
1508
1511
#else
1526
1529
          /* Retry, below */
1527
1530
          break;
1528
1531
        case EMSGSIZE:
1529
 
          error(0, 0, "Password of size %" PRIuMAX " is too big",
1530
 
                (uintmax_t)password->length);
 
1532
          error(0, saved_errno, "Password of size %" PRIuMAX
 
1533
                " is too big", (uintmax_t)password->length);
1531
1534
#if __GNUC__ < 7
1532
1535
          /* FALLTHROUGH */
1533
1536
#else
1535
1538
#endif
1536
1539
        case 0:
1537
1540
          if(ssret >= 0 and ssret < (ssize_t)send_buffer_length){
1538
 
            error(0, 0, "Password only partially sent to socket");
 
1541
            error(0, 0, "Password only partially sent to socket %s: %"
 
1542
                  PRIuMAX " out of %" PRIuMAX " bytes sent", filename,
 
1543
                  (uintmax_t)ssret, (uintmax_t)send_buffer_length);
1539
1544
          }
1540
1545
#if __GNUC__ < 7
1541
1546
          /* FALLTHROUGH */
5807
5812
  char write_data[PIPE_BUF];
5808
5813
  {
5809
5814
    /* Construct test password buffer */
5810
 
    /* Start with + since that is what the real procotol uses */
 
5815
    /* Start with + since that is what the real protocol uses */
5811
5816
    write_data[0] = '+';
5812
5817
    /* Set a special character at string end just to mark the end */
5813
5818
    write_data[sizeof(write_data)-2] = 'y';
5958
5963
                                           test_fixture *fixture,
5959
5964
                                           __attribute__((unused))
5960
5965
                                           gconstpointer user_data){
5961
 
#ifndef __amd64__
5962
 
  g_test_skip("Skipping EMSGSIZE test on non-AMD64 platform");
5963
 
#else
5964
5966
  __attribute__((cleanup(cleanup_close)))
5965
5967
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
5966
5968
  g_assert_cmpint(epoll_fd, >=, 0);
5968
5970
  char *const filename = strdup("/nonexistent/socket");
5969
5971
  __attribute__((cleanup(string_set_clear)))
5970
5972
    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,
 
5973
  int socketfds[2];
 
5974
 
 
5975
  /* Find a message size which triggers EMSGSIZE */
 
5976
  __attribute__((cleanup(cleanup_string)))
 
5977
    char *message_buffer = NULL;
 
5978
  size_t message_size = PIPE_BUF + 1;
 
5979
  for(ssize_t ssret = 0; ssret >= 0; message_size += 1024){
 
5980
    if(message_size >= 1024*1024*1024){ /* 1 GiB */
 
5981
      g_test_skip("Skipping EMSGSIZE test: Will not try 1GiB");
 
5982
      return;
 
5983
    }
 
5984
    message_buffer = realloc(message_buffer, message_size);
 
5985
    if(message_buffer == NULL){
 
5986
      g_test_skip("Skipping EMSGSIZE test");
 
5987
      g_test_message("Failed to malloc() %" PRIuMAX " bytes",
 
5988
                     (uintmax_t)message_size);
 
5989
      return;
 
5990
    }
 
5991
    /* Fill buffer with 'x' */
 
5992
    memset(message_buffer, 'x', message_size);
 
5993
    /* Create a new socketpair for each message size to avoid having
 
5994
       to empty the pipe by reading the message to a separate buffer
 
5995
    */
 
5996
    g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
 
5997
                               | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
 
5998
                               socketfds), ==, 0);
 
5999
    ssret = send(socketfds[1], message_buffer, message_size,
 
6000
                 MSG_NOSIGNAL);
 
6001
    error_t saved_errno = errno;
 
6002
    g_assert_cmpint(close(socketfds[0]), ==, 0);
 
6003
    g_assert_cmpint(close(socketfds[1]), ==, 0);
 
6004
 
 
6005
    if(ssret < 0){
 
6006
      if(saved_errno != EMSGSIZE) {
 
6007
        g_test_skip("Skipping EMSGSIZE test");
 
6008
        g_test_message("Error on send(%" PRIuMAX " bytes): %s",
 
6009
                       (uintmax_t)message_size,
 
6010
                       strerror(saved_errno));
 
6011
        return;
 
6012
      }
 
6013
      break;
 
6014
    } else if(ssret != (ssize_t)message_size){
 
6015
      g_test_skip("Skipping EMSGSIZE test");
 
6016
      g_test_message("Partial send(): %" PRIuMAX " of %" PRIdMAX
 
6017
                     " bytes", (uintmax_t)ssret,
 
6018
                     (intmax_t)message_size);
 
6019
      return;
 
6020
    }
 
6021
  }
 
6022
  g_test_message("EMSGSIZE triggered by %" PRIdMAX " bytes",
 
6023
                 (intmax_t)message_size);
 
6024
 
 
6025
  buffer password = {
 
6026
    .data=message_buffer,
 
6027
    .length=message_size - 2,   /* Compensate for added '+' and NUL */
 
6028
    .allocated=message_size,
5977
6029
  };
5978
 
  g_assert_nonnull(password.data);
5979
6030
  if(mlock(password.data, password.allocated) != 0){
5980
6031
    g_assert_true(errno == EPERM or errno == ENOMEM);
5981
6032
  }
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
6033
 
5992
6034
  __attribute__((cleanup(cleanup_queue)))
5993
6035
    task_queue *queue = create_queue();
5994
6036
  g_assert_nonnull(queue);
5995
 
  int socketfds[2];
5996
6037
  g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
5997
6038
                             | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
5998
6039
                             socketfds), ==, 0);
6019
6060
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
6020
6061
  g_assert_true(string_set_contains(cancelled_filenames,
6021
6062
                                    question_filename));
6022
 
#endif
6023
6063
}
6024
6064
 
6025
6065
static void test_send_password_to_socket_retry(__attribute__((unused))