=== modified file 'debian/control' --- debian/control 2020-03-21 16:23:36 +0000 +++ debian/control 2020-11-30 16:25:32 +0000 @@ -11,7 +11,7 @@ xsltproc, pkg-config, libnl-route-3-dev, systemd Build-Depends-Indep: python3 (>= 3), python3-dbus, python3-gi, po-debconf -Standards-Version: 4.5.0 +Standards-Version: 4.5.1 Vcs-Bzr: https://ftp.recompile.se/pub/mandos/trunk Vcs-Browser: https://bzr.recompile.se/loggerhead/mandos/trunk/files Homepage: https://www.recompile.se/mandos === modified file 'debian/mandos-client.templates' --- debian/mandos-client.templates 2019-08-05 21:00:35 +0000 +++ debian/mandos-client.templates 2020-11-30 16:19:48 +0000 @@ -1,6 +1,6 @@ Template: mandos-client/key_id Type: note -_description: New client option "${key_id}" is REQUIRED on server +_Description: New client option "${key_id}" is REQUIRED on server A new "key_id" client option is REQUIRED in the server's clients.conf file, otherwise this computer most likely will not reboot unattended. This option: === modified file 'dracut-module/password-agent.c' --- dracut-module/password-agent.c 2020-07-04 11:58:52 +0000 +++ dracut-module/password-agent.c 2020-11-29 22:54:26 +0000 @@ -1193,8 +1193,8 @@ bool *const password_is_read = task.password_is_read; /* We use the GLib "Key-value file parser" functions to parse the - question file. See for specification of contents */ + question file. See for + specification of contents */ __attribute__((nonnull)) void cleanup_g_key_file(GKeyFile **key_file){ if(*key_file != NULL){ @@ -1490,8 +1490,8 @@ not. You may but don't have to include a final NUL byte in your message. - — (Wed 08 Oct 2014 02:14:28 AM UTC) + — (Tue, 15 Sep 2020 + 14:24:20 GMT) */ send_buffer[0] = '+'; /* Prefix with "+" */ /* Always add an extra NUL */ @@ -1502,7 +1502,7 @@ errno = 0; ssize_t ssret = send(fd, send_buffer, send_buffer_length, MSG_NOSIGNAL); - const error_t saved_errno = errno; + const error_t saved_errno = (ssret < 0) ? errno : 0; #if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 25) explicit_bzero(send_buffer, send_buffer_length); #else @@ -1526,8 +1526,8 @@ /* Retry, below */ break; case EMSGSIZE: - error(0, 0, "Password of size %" PRIuMAX " is too big", - (uintmax_t)password->length); + error(0, saved_errno, "Password of size %" PRIuMAX + " is too big", (uintmax_t)password->length); #if __GNUC__ < 7 /* FALLTHROUGH */ #else @@ -1535,7 +1535,9 @@ #endif case 0: if(ssret >= 0 and ssret < (ssize_t)send_buffer_length){ - error(0, 0, "Password only partially sent to socket"); + error(0, 0, "Password only partially sent to socket %s: %" + PRIuMAX " out of %" PRIuMAX " bytes sent", filename, + (uintmax_t)ssret, (uintmax_t)send_buffer_length); } #if __GNUC__ < 7 /* FALLTHROUGH */ @@ -5807,7 +5809,7 @@ char write_data[PIPE_BUF]; { /* Construct test password buffer */ - /* Start with + since that is what the real procotol uses */ + /* Start with + since that is what the real protocol uses */ write_data[0] = '+'; /* Set a special character at string end just to mark the end */ write_data[sizeof(write_data)-2] = 'y'; @@ -5958,9 +5960,6 @@ test_fixture *fixture, __attribute__((unused)) gconstpointer user_data){ -#ifndef __amd64__ - g_test_skip("Skipping EMSGSIZE test on non-AMD64 platform"); -#else __attribute__((cleanup(cleanup_close))) const int epoll_fd = epoll_create1(EPOLL_CLOEXEC); g_assert_cmpint(epoll_fd, >=, 0); @@ -5968,31 +5967,68 @@ char *const filename = strdup("/nonexistent/socket"); __attribute__((cleanup(string_set_clear))) string_set cancelled_filenames = {}; - const size_t oversized = 1024*1024; /* Limit seems to be 212960 */ - __attribute__((cleanup(cleanup_buffer))) - buffer password = { - .data=malloc(oversized), - .length=oversized, - .allocated=oversized, + int socketfds[2]; + + /* Find a message size which triggers EMSGSIZE */ + __attribute__((cleanup(cleanup_string))) + char *message_buffer = NULL; + size_t message_size = PIPE_BUF + 1; + for(ssize_t ssret = 0; ssret >= 0; message_size += 1024){ + if(message_size >= 1024*1024*1024){ /* 1 GiB */ + g_test_skip("Skipping EMSGSIZE test: Will not try 1GiB"); + return; + } + free(message_buffer); + message_buffer = malloc(message_size); + if(message_buffer == NULL){ + g_test_skip("Skipping EMSGSIZE test"); + g_test_message("Failed to malloc() %" PRIuMAX " bytes", + (uintmax_t)message_size); + return; + } + /* Fill buffer with 'x' */ + memset(message_buffer, 'x', message_size); + /* Create a new socketpair for each message size to avoid having + to empty the pipe by reading the message to a separate buffer + */ + g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM + | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, + socketfds), ==, 0); + ssret = send(socketfds[1], message_buffer, message_size, + MSG_NOSIGNAL); + error_t saved_errno = errno; + g_assert_cmpint(close(socketfds[0]), ==, 0); + g_assert_cmpint(close(socketfds[1]), ==, 0); + + if(ssret < 0){ + if(saved_errno != EMSGSIZE) { + g_test_skip("Skipping EMSGSIZE test"); + g_test_message("Error on send(): %s", strerror(saved_errno)); + return; + } + } else if(ssret != (ssize_t)message_size){ + g_test_skip("Skipping EMSGSIZE test"); + g_test_message("Partial send(): %" PRIuMAX " of %" PRIdMAX + " bytes", (uintmax_t)ssret, + (intmax_t)message_size); + return; + } + } + g_test_message("EMSGSIZE triggered by %" PRIdMAX " bytes", + (intmax_t)message_size); + + buffer password = { + .data=message_buffer, + .length=message_size - 2, /* Compensate for added '+' and NUL */ + .allocated=message_size, }; - g_assert_nonnull(password.data); if(mlock(password.data, password.allocated) != 0){ g_assert_true(errno == EPERM or errno == ENOMEM); } - /* Construct test password buffer */ - /* Start with + since that is what the real procotol uses */ - password.data[0] = '+'; - /* Set a special character at string end just to mark the end */ - password.data[oversized-3] = 'y'; - /* Set NUL at buffer end, as suggested by the protocol */ - password.data[oversized-2] = '\0'; - /* Fill rest of password with 'x' */ - memset(password.data+1, 'x', oversized-3); __attribute__((cleanup(cleanup_queue))) task_queue *queue = create_queue(); g_assert_nonnull(queue); - int socketfds[2]; g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, socketfds), ==, 0); @@ -6019,7 +6055,6 @@ g_assert_cmpuint((unsigned int)queue->length, ==, 0); g_assert_true(string_set_contains(cancelled_filenames, question_filename)); -#endif } static void test_send_password_to_socket_retry(__attribute__((unused)) === modified file 'dracut-module/password-agent.xml' --- dracut-module/password-agent.xml 2019-11-16 15:56:49 +0000 +++ dracut-module/password-agent.xml 2020-11-29 21:54:00 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -113,9 +113,9 @@ be a systemd 1 Password Agent (See Password Agents). The aim of this program is therefore - to acquire and then send a password to some other program which + url="https://systemd.io/PASSWORD_AGENTS/">Password + Agents). The aim of this program is therefore to + acquire and then send a password to some other program which will use the password to unlock the encrypted root disk. @@ -146,9 +146,8 @@ Specify a different agent directory. The default is /run/systemd/ask-password as per the - Password Agents specification. + Password + Agents specification. @@ -270,8 +269,8 @@ responsible for getting a password from the Mandos client program itself, and to send that password to whatever is currently asking for a password using the systemd Password Agents mechanism. + url="https://systemd.io/PASSWORD_AGENTS/">Password + Agents mechanism. To accomplish this, &COMMANDNAME; runs the mandos-client program (which is the actual @@ -281,9 +280,8 @@ password is acquired from the MANDOS_CLIENT program, sends that password (as per the Password Agents specification) to all currently - unanswered password questions. + url="https://systemd.io/PASSWORD_AGENTS/">Password Agents + specification) to all currently unanswered password questions. This program should be started (normally as a systemd service, @@ -330,9 +328,9 @@ The default directory to watch for password questions as per the Password Agents specification; can be changed - by the option. + url="https://systemd.io/PASSWORD_AGENTS/">Password + Agents specification; can be changed by the + option. @@ -446,9 +444,8 @@ - Password Agents + Password + Agents === modified file 'intro.xml' --- intro.xml 2019-08-04 12:42:49 +0000 +++ intro.xml 2020-11-29 21:54:00 +0000 @@ -1,7 +1,7 @@ + %common; ]> @@ -403,11 +403,11 @@ As for systemd1 in particular, it has its own Password Agents system. Mandos uses this via its + url="https://systemd.io/PASSWORD_AGENTS/">Password + Agents system. Mandos uses this via its password-agent8mandos program, which - is run instead of 8mandos program, which is + run instead of plugin-runner8mandos when systemd1 === modified file 'mandos' --- mandos 2020-07-04 13:00:37 +0000 +++ mandos 2020-08-14 20:34:56 +0000 @@ -524,7 +524,8 @@ class AvahiServiceToSyslog(AvahiService): def rename(self, *args, **kwargs): """Add the new name to the syslog messages""" - ret = super(AvahiServiceToSyslog, self).rename(*args, **kwargs) + ret = super(AvahiServiceToSyslog, self).rename(*args, + **kwargs) syslogger.setFormatter(logging.Formatter( 'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s' .format(self.name))) @@ -774,7 +775,8 @@ x509_crt_fmt_t = ctypes.c_int - # All the function declarations below are from gnutls/abstract.h + # All the function declarations below are from + # gnutls/abstract.h pubkey_init = _library.gnutls_pubkey_init pubkey_init.argtypes = [ctypes.POINTER(pubkey_t)] pubkey_init.restype = _error_code @@ -794,7 +796,8 @@ pubkey_deinit.argtypes = [pubkey_t] pubkey_deinit.restype = None else: - # All the function declarations below are from gnutls/openpgp.h + # All the function declarations below are from + # gnutls/openpgp.h openpgp_crt_init = _library.gnutls_openpgp_crt_init openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)] @@ -806,9 +809,13 @@ openpgp_crt_fmt_t] openpgp_crt_import.restype = _error_code - openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self - openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint, - ctypes.POINTER(ctypes.c_uint)] + openpgp_crt_verify_self = \ + _library.gnutls_openpgp_crt_verify_self + openpgp_crt_verify_self.argtypes = [ + openpgp_crt_t, + ctypes.c_uint, + ctypes.POINTER(ctypes.c_uint), + ] openpgp_crt_verify_self.restype = _error_code openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit @@ -2468,11 +2475,12 @@ buf = ctypes.create_string_buffer(32) buf_len = ctypes.c_size_t(len(buf)) # Get the key ID from the raw public key into the buffer - gnutls.pubkey_get_key_id(pubkey, - gnutls.KEYID_USE_SHA256, - ctypes.cast(ctypes.byref(buf), - ctypes.POINTER(ctypes.c_ubyte)), - ctypes.byref(buf_len)) + gnutls.pubkey_get_key_id( + pubkey, + gnutls.KEYID_USE_SHA256, + ctypes.cast(ctypes.byref(buf), + ctypes.POINTER(ctypes.c_ubyte)), + ctypes.byref(buf_len)) # Deinit the certificate gnutls.pubkey_deinit(pubkey) @@ -2723,7 +2731,8 @@ address = request[3] for c in self.clients.values(): - if key_id == "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855": + if key_id == ("E3B0C44298FC1C149AFBF4C8996FB924" + "27AE41E4649B934CA495991B7852B855"): continue if key_id and c.key_id == key_id: client = c @@ -2781,20 +2790,22 @@ def rfc3339_duration_to_delta(duration): """Parse an RFC 3339 "duration" and return a datetime.timedelta - >>> rfc3339_duration_to_delta("P7D") == datetime.timedelta(7) - True - >>> rfc3339_duration_to_delta("PT60S") == datetime.timedelta(0, 60) - True - >>> rfc3339_duration_to_delta("PT60M") == datetime.timedelta(0, 3600) - True - >>> rfc3339_duration_to_delta("PT24H") == datetime.timedelta(1) - True - >>> rfc3339_duration_to_delta("P1W") == datetime.timedelta(7) - True - >>> rfc3339_duration_to_delta("PT5M30S") == datetime.timedelta(0, 330) - True - >>> rfc3339_duration_to_delta("P1DT3M20S") == datetime.timedelta(1, 200) - True + >>> timedelta = datetime.timedelta + >>> rfc3339_duration_to_delta("P7D") == timedelta(7) + True + >>> rfc3339_duration_to_delta("PT60S") == timedelta(0, 60) + True + >>> rfc3339_duration_to_delta("PT60M") == timedelta(0, 3600) + True + >>> rfc3339_duration_to_delta("PT24H") == timedelta(1) + True + >>> rfc3339_duration_to_delta("P1W") == timedelta(7) + True + >>> rfc3339_duration_to_delta("PT5M30S") == timedelta(0, 330) + True + >>> rfc3339_duration_to_delta("P1DT3M20S") == timedelta(1, 200) + True + >>> del timedelta """ # Parsing an RFC 3339 duration with regular expressions is not