diff options
Diffstat (limited to '')
31 files changed, 3985 insertions, 6 deletions
diff --git a/debian/changelog b/debian/changelog index 53cca7a..3b94c40 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,19 @@ +sudo (1.8.27-1+deb10u6) buster-security; urgency=high + + * Non-maintainer upload by the LTS Security Team. + * Fix CVE-2023-7090: A flaw was found in sudo in the handling of + ipa_hostname, where ipa_hostname from /etc/sssd/sssd.conf + was not propagated in sudo. Therefore, it leads to + privilege mismanagement vulnerability in applications, + where client hosts retain privileges even after retracting them. + * Fix CVE-2023-28486: Sudo did not escape control characters + in log messages. + * Fix CVE-2023-28487: Sudo did not escape control characters + in sudoreplay output. + * Regenerate parsers from yacc file. + + -- Bastien Roucariès <rouca@debian.org> Sun, 21 Jan 2024 20:52:36 +0000 + sudo (1.8.27-1+deb10u5progress5u1) engywuck-security; urgency=high * Uploading to engywuck-security, remaining changes: diff --git a/debian/patches/0016-CVE-2023-7090-Fix-special-handling-of-ipa_hostname-t.patch b/debian/patches/0016-CVE-2023-7090-Fix-special-handling-of-ipa_hostname-t.patch new file mode 100644 index 0000000..49c5b3d --- /dev/null +++ b/debian/patches/0016-CVE-2023-7090-Fix-special-handling-of-ipa_hostname-t.patch @@ -0,0 +1,2574 @@ +From: "Todd C. Miller" <Todd.Miller@sudo.ws> +Date: Thu, 15 Aug 2019 14:20:12 -0600 +Subject: CVE-2023-7090: Fix special handling of ipa_hostname that was lost + +We now include the long and short hostname in sudo parser container. + +[backport: remove generated yacc file] + +origin: https://www.sudo.ws/repos/sudo/rev/b4f31dbe3109 +bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2023-7090 +--- + plugins/sudoers/file.c | 2 +- + plugins/sudoers/gram.c | 2300 ----------------------------------------------- + plugins/sudoers/gram.h | 63 -- + plugins/sudoers/gram.y | 9 +- + plugins/sudoers/ldap.c | 2 +- + plugins/sudoers/match.c | 23 +- + plugins/sudoers/parse.h | 3 +- + plugins/sudoers/sssd.c | 7 +- + 8 files changed, 30 insertions(+), 2379 deletions(-) + delete mode 100644 plugins/sudoers/gram.c + delete mode 100644 plugins/sudoers/gram.h + +diff --git a/plugins/sudoers/file.c b/plugins/sudoers/file.c +index a8b02b3..7ea9522 100644 +--- a/plugins/sudoers/file.c ++++ b/plugins/sudoers/file.c +@@ -83,7 +83,7 @@ sudo_file_open(struct sudo_nss *nss) + if (handle != NULL) { + handle->fp = open_sudoers(sudoers_file, false, NULL); + if (handle->fp != NULL) { +- init_parse_tree(&handle->parse_tree); ++ init_parse_tree(&handle->parse_tree, NULL, NULL); + } else { + free(handle); + handle = NULL; +diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c +deleted file mode 100644 +index fff971b..0000000 +--- a/plugins/sudoers/gram.c ++++ /dev/null +@@ -1,2300 +0,0 @@ +-/* +- * This is an open source non-commercial project. Dear PVS-Studio, please check it. +- * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +- */ +- +-#include <config.h> +-#include <stdlib.h> +-#include <string.h> +-#define YYBYACC 1 +-#define YYMAJOR 1 +-#define YYMINOR 9 +-#define YYLEX yylex() +-#define YYEMPTY -1 +-#define yyclearin (yychar=(YYEMPTY)) +-#define yyerrok (yyerrflag=0) +-#define YYRECOVERING() (yyerrflag!=0) +-#define yyparse sudoersparse +-#define yylex sudoerslex +-#define yyerror sudoerserror +-#define yychar sudoerschar +-#define yyval sudoersval +-#define yylval sudoerslval +-#define yydebug sudoersdebug +-#define yynerrs sudoersnerrs +-#define yyerrflag sudoerserrflag +-#define yyss sudoersss +-#define yysslim sudoerssslim +-#define yyssp sudoersssp +-#define yyvs sudoersvs +-#define yyvsp sudoersvsp +-#define yystacksize sudoersstacksize +-#define yylhs sudoerslhs +-#define yylen sudoerslen +-#define yydefred sudoersdefred +-#define yydgoto sudoersdgoto +-#define yysindex sudoerssindex +-#define yyrindex sudoersrindex +-#define yygindex sudoersgindex +-#define yytable sudoerstable +-#define yycheck sudoerscheck +-#define yyname sudoersname +-#define yyrule sudoersrule +-#define YYPREFIX "sudoers" +-#line 2 "gram.y" +-/* +- * Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2018 +- * Todd C. Miller <Todd.Miller@sudo.ws> +- * +- * Permission to use, copy, modify, and distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- * +- * Sponsored in part by the Defense Advanced Research Projects +- * Agency (DARPA) and Air Force Research Laboratory, Air Force +- * Materiel Command, USAF, under agreement number F39502-99-1-0512. +- */ +- +-#include <config.h> +- +-#include <sys/types.h> +-#include <stdio.h> +-#include <stdlib.h> +-#include <stddef.h> +-#ifdef HAVE_STRING_H +-# include <string.h> +-#endif /* HAVE_STRING_H */ +-#ifdef HAVE_STRINGS_H +-# include <strings.h> +-#endif /* HAVE_STRINGS_H */ +-#include <unistd.h> +-#if defined(HAVE_STDINT_H) +-# include <stdint.h> +-#elif defined(HAVE_INTTYPES_H) +-# include <inttypes.h> +-#endif +-#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) +-# include <alloca.h> +-#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */ +-#include <errno.h> +- +-#include "sudoers.h" +-#include "sudo_digest.h" +-#include "toke.h" +- +-/* If we last saw a newline the entry is on the preceding line. */ +-#define this_lineno (last_token == COMMENT ? sudolineno - 1 : sudolineno) +- +-/* +- * Globals +- */ +-bool sudoers_warnings = true; +-bool parse_error = false; +-int errorlineno = -1; +-char *errorfile = NULL; +- +-struct sudoers_parse_tree parsed_policy = { +- TAILQ_HEAD_INITIALIZER(parsed_policy.userspecs), +- TAILQ_HEAD_INITIALIZER(parsed_policy.defaults), +- NULL /* aliases */ +-}; +- +-/* +- * Local protoypes +- */ +-static void init_options(struct command_options *opts); +-static bool add_defaults(int, struct member *, struct defaults *); +-static bool add_userspec(struct member *, struct privilege *); +-static struct defaults *new_default(char *, char *, short); +-static struct member *new_member(char *, int); +-static struct command_digest *new_digest(int, char *); +-#line 78 "gram.y" +-#ifndef YYSTYPE_DEFINED +-#define YYSTYPE_DEFINED +-typedef union { +- struct cmndspec *cmndspec; +- struct defaults *defaults; +- struct member *member; +- struct runascontainer *runas; +- struct privilege *privilege; +- struct command_digest *digest; +- struct sudo_command command; +- struct command_options options; +- struct cmndtag tag; +- char *string; +- int tok; +-} YYSTYPE; +-#endif /* YYSTYPE_DEFINED */ +-#line 131 "gram.c" +-#define COMMAND 257 +-#define ALIAS 258 +-#define DEFVAR 259 +-#define NTWKADDR 260 +-#define NETGROUP 261 +-#define USERGROUP 262 +-#define WORD 263 +-#define DIGEST 264 +-#define DEFAULTS 265 +-#define DEFAULTS_HOST 266 +-#define DEFAULTS_USER 267 +-#define DEFAULTS_RUNAS 268 +-#define DEFAULTS_CMND 269 +-#define NOPASSWD 270 +-#define PASSWD 271 +-#define NOEXEC 272 +-#define EXEC 273 +-#define SETENV 274 +-#define NOSETENV 275 +-#define LOG_INPUT 276 +-#define NOLOG_INPUT 277 +-#define LOG_OUTPUT 278 +-#define NOLOG_OUTPUT 279 +-#define MAIL 280 +-#define NOMAIL 281 +-#define FOLLOW 282 +-#define NOFOLLOW 283 +-#define ALL 284 +-#define COMMENT 285 +-#define HOSTALIAS 286 +-#define CMNDALIAS 287 +-#define USERALIAS 288 +-#define RUNASALIAS 289 +-#define ERROR 290 +-#define TYPE 291 +-#define ROLE 292 +-#define PRIVS 293 +-#define LIMITPRIVS 294 +-#define CMND_TIMEOUT 295 +-#define NOTBEFORE 296 +-#define NOTAFTER 297 +-#define MYSELF 298 +-#define SHA224_TOK 299 +-#define SHA256_TOK 300 +-#define SHA384_TOK 301 +-#define SHA512_TOK 302 +-#define YYERRCODE 256 +-#if defined(__cplusplus) || defined(__STDC__) +-const short sudoerslhs[] = +-#else +-short sudoerslhs[] = +-#endif +- { -1, +- 0, 0, 32, 32, 33, 33, 33, 33, 33, 33, +- 33, 33, 33, 33, 33, 33, 4, 4, 3, 3, +- 3, 3, 3, 21, 21, 20, 11, 11, 9, 9, +- 9, 9, 9, 2, 2, 1, 31, 31, 31, 31, +- 7, 7, 6, 6, 28, 29, 30, 24, 25, 26, +- 27, 18, 18, 19, 19, 19, 19, 19, 23, 23, +- 23, 23, 23, 23, 23, 23, 22, 22, 22, 22, +- 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, +- 22, 5, 5, 5, 35, 35, 38, 10, 10, 36, +- 36, 39, 8, 8, 37, 37, 40, 34, 34, 41, +- 14, 14, 12, 12, 13, 13, 13, 13, 13, 17, +- 17, 15, 15, 16, 16, 16, +-}; +-#if defined(__cplusplus) || defined(__STDC__) +-const short sudoerslen[] = +-#else +-short sudoerslen[] = +-#endif +- { 2, +- 0, 1, 1, 2, 1, 2, 2, 2, 2, 2, +- 2, 2, 3, 3, 3, 3, 1, 3, 1, 2, +- 3, 3, 3, 1, 3, 3, 1, 2, 1, 1, +- 1, 1, 1, 1, 3, 4, 3, 3, 3, 3, +- 1, 2, 1, 2, 3, 3, 3, 3, 3, 3, +- 3, 0, 3, 0, 1, 3, 2, 1, 0, 2, +- 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, +- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +- 2, 1, 1, 1, 1, 3, 3, 1, 3, 1, +- 3, 3, 1, 3, 1, 3, 3, 1, 3, 3, +- 1, 3, 1, 2, 1, 1, 1, 1, 1, 1, +- 3, 1, 2, 1, 1, 1, +-}; +-#if defined(__cplusplus) || defined(__STDC__) +-const short sudoersdefred[] = +-#else +-short sudoersdefred[] = +-#endif +- { 0, +- 0, 105, 107, 108, 109, 0, 0, 0, 0, 0, +- 106, 5, 0, 0, 0, 0, 0, 0, 101, 103, +- 0, 0, 3, 6, 0, 0, 17, 0, 29, 32, +- 31, 33, 30, 0, 27, 0, 88, 0, 0, 84, +- 83, 82, 0, 0, 0, 0, 0, 43, 41, 93, +- 0, 0, 0, 0, 85, 0, 0, 90, 0, 0, +- 98, 0, 0, 95, 104, 0, 0, 24, 0, 4, +- 0, 0, 0, 20, 0, 28, 0, 0, 0, 0, +- 44, 0, 0, 0, 0, 0, 0, 42, 0, 0, +- 0, 0, 0, 0, 0, 0, 102, 0, 0, 21, +- 22, 23, 18, 89, 37, 38, 39, 40, 94, 0, +- 86, 0, 91, 0, 99, 0, 96, 0, 34, 0, +- 59, 25, 0, 0, 0, 0, 0, 114, 116, 115, +- 0, 110, 112, 0, 0, 53, 35, 0, 0, 0, +- 0, 0, 0, 0, 0, 63, 64, 65, 66, 62, +- 60, 61, 113, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 68, 69, 70, 71, 72, 73, 74, 75, +- 76, 77, 80, 81, 78, 79, 36, 111, 49, 48, +- 50, 51, 45, 46, 47, +-}; +-#if defined(__cplusplus) || defined(__STDC__) +-const short sudoersdgoto[] = +-#else +-short sudoersdgoto[] = +-#endif +- { 18, +- 119, 120, 27, 28, 48, 49, 50, 51, 35, 67, +- 37, 19, 20, 21, 132, 133, 134, 121, 125, 68, +- 69, 145, 127, 146, 147, 148, 149, 150, 151, 152, +- 52, 22, 23, 60, 54, 57, 63, 55, 58, 64, +- 61, +-}; +-#if defined(__cplusplus) || defined(__STDC__) +-const short sudoerssindex[] = +-#else +-short sudoerssindex[] = +-#endif +- { 512, +- -272, 0, 0, 0, 0, -23, 227, -19, -19, -5, +- 0, 0, -239, -236, -234, -232, -231, 0, 0, 0, +- -33, 512, 0, 0, -3, -220, 0, 3, 0, 0, +- 0, 0, 0, -225, 0, -28, 0, -24, -24, 0, +- 0, 0, -240, -15, -8, 2, 4, 0, 0, 0, +- -21, -12, -9, 6, 0, 7, 12, 0, 10, 14, +- 0, 13, 25, 0, 0, -19, -36, 0, 26, 0, +- -208, -202, -198, 0, -23, 0, 227, 3, 3, 3, +- 0, -179, -178, -174, -173, -5, 3, 0, 227, -239, +- -5, -236, -19, -234, -19, -232, 0, 52, 227, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, +- 0, 51, 0, 54, 0, 54, 0, -29, 0, 55, +- 0, 0, 289, -7, 59, 52, -216, 0, 0, 0, +- -217, 0, 0, 57, 289, 0, 0, 32, 41, 42, +- 43, 44, 45, 47, 450, 0, 0, 0, 0, 0, +- 0, 0, 0, 289, 57, -154, -153, -150, -149, -148, +- -147, -146, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0,}; +-#if defined(__cplusplus) || defined(__STDC__) +-const short sudoersrindex[] = +-#else +-short sudoersrindex[] = +-#endif +- { 118, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 119, 0, 0, 1, 0, 0, 145, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 159, 0, 0, 193, 0, 0, 207, +- 0, 0, 241, 0, 0, 0, 0, 0, 275, 0, +- 0, 0, 0, 0, 0, 0, 0, 309, 323, 357, +- 0, 0, 0, 0, 0, 0, 371, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, +- 0, 49, 0, 63, 0, 97, 0, 79, 0, 111, +- 0, 0, 81, 82, 0, 404, 483, 0, 0, 0, +- 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0,}; +-#if defined(__cplusplus) || defined(__STDC__) +-const short sudoersgindex[] = +-#else +-short sudoersgindex[] = +-#endif +- { 0, +- 5, 0, 53, 18, 86, 74, -79, 36, 98, -1, +- 56, 68, 120, -6, -18, 8, 11, 0, 0, 39, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 113, 0, 0, 0, 0, 58, 48, 46, +- 60, +-}; +-#define YYTABLESIZE 801 +-#if defined(__cplusplus) || defined(__STDC__) +-const short sudoerstable[] = +-#else +-short sudoerstable[] = +-#endif +- { 34, +- 19, 38, 39, 17, 26, 36, 109, 77, 26, 26, +- 66, 26, 24, 17, 87, 77, 40, 41, 53, 66, +- 43, 56, 86, 59, 98, 62, 2, 43, 123, 3, +- 4, 5, 29, 19, 30, 31, 66, 32, 74, 72, +- 128, 73, 82, 42, 19, 129, 75, 87, 92, 83, +- 135, 89, 11, 78, 100, 79, 80, 71, 33, 84, +- 101, 85, 100, 90, 102, 177, 130, 91, 87, 92, +- 93, 94, 87, 95, 138, 139, 140, 141, 142, 143, +- 144, 92, 96, 99, 105, 106, 114, 110, 116, 107, +- 108, 118, 156, 77, 86, 100, 97, 66, 126, 136, +- 154, 157, 158, 159, 160, 161, 92, 162, 179, 180, +- 26, 124, 181, 182, 183, 184, 185, 1, 2, 54, +- 100, 58, 55, 57, 56, 88, 112, 103, 81, 97, +- 137, 76, 104, 97, 70, 178, 65, 122, 153, 113, +- 0, 117, 0, 26, 12, 155, 0, 111, 0, 0, +- 0, 0, 0, 115, 97, 0, 0, 0, 9, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, +- 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 29, 10, 30, 31, 2, 32, +- 25, 3, 4, 5, 25, 25, 0, 25, 2, 8, +- 11, 3, 4, 5, 40, 41, 0, 0, 0, 0, +- 33, 40, 41, 0, 11, 0, 19, 0, 19, 34, +- 0, 19, 19, 19, 11, 19, 19, 19, 19, 19, +- 87, 42, 87, 11, 7, 87, 87, 87, 42, 87, +- 87, 87, 87, 87, 19, 19, 19, 19, 19, 19, +- 0, 0, 0, 44, 45, 46, 47, 0, 87, 87, +- 87, 87, 87, 87, 92, 0, 92, 7, 15, 92, +- 92, 92, 0, 92, 92, 92, 92, 92, 100, 0, +- 100, 131, 13, 100, 100, 100, 0, 100, 100, 100, +- 100, 100, 92, 92, 92, 92, 92, 92, 0, 0, +- 0, 15, 0, 0, 0, 0, 100, 100, 100, 100, +- 100, 100, 97, 0, 97, 13, 14, 97, 97, 97, +- 0, 97, 97, 97, 97, 97, 26, 0, 26, 0, +- 16, 26, 26, 26, 0, 26, 26, 26, 26, 26, +- 97, 97, 97, 97, 97, 97, 0, 0, 0, 14, +- 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, +- 12, 0, 12, 16, 0, 12, 12, 12, 0, 12, +- 12, 12, 12, 12, 9, 0, 9, 0, 0, 9, +- 9, 9, 0, 9, 9, 9, 9, 9, 12, 12, +- 12, 12, 12, 12, 0, 0, 52, 0, 0, 0, +- 0, 0, 9, 9, 9, 9, 9, 9, 10, 0, +- 10, 0, 0, 10, 10, 10, 0, 10, 10, 10, +- 10, 10, 8, 0, 8, 0, 0, 8, 8, 8, +- 0, 8, 8, 8, 8, 8, 10, 10, 10, 10, +- 10, 10, 43, 0, 29, 0, 30, 31, 0, 32, +- 8, 8, 8, 8, 8, 8, 11, 0, 11, 0, +- 0, 11, 11, 11, 0, 11, 11, 11, 11, 11, +- 33, 0, 0, 0, 0, 67, 0, 0, 0, 0, +- 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, +- 7, 0, 7, 0, 0, 7, 7, 7, 0, 7, +- 7, 7, 7, 7, 17, 0, 128, 0, 0, 0, +- 0, 129, 0, 0, 0, 0, 0, 0, 7, 7, +- 7, 7, 7, 7, 15, 0, 15, 0, 0, 15, +- 15, 15, 130, 15, 15, 15, 15, 15, 13, 0, +- 13, 0, 0, 13, 13, 13, 0, 13, 13, 13, +- 13, 13, 15, 15, 15, 15, 15, 15, 0, 0, +- 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, +- 13, 13, 14, 0, 14, 0, 0, 14, 14, 14, +- 0, 14, 14, 14, 14, 14, 16, 0, 16, 0, +- 0, 16, 16, 16, 0, 16, 16, 16, 16, 16, +- 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, +- 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, +- 52, 52, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 52, 52, 52, 52, 52, 52, 52, +- 52, 52, 52, 52, 52, 52, 52, 52, 0, 0, +- 0, 0, 0, 0, 52, 52, 52, 52, 52, 52, +- 52, 0, 52, 52, 52, 52, 40, 41, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, +- 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, +- 174, 175, 176, 42, 0, 0, 0, 0, 0, 67, +- 67, 0, 0, 0, 0, 0, 0, 0, 44, 45, +- 46, 47, 67, 67, 67, 67, 67, 67, 67, 67, +- 67, 67, 67, 67, 67, 67, 67, 1, 0, 2, +- 0, 0, 3, 4, 5, 0, 6, 7, 8, 9, +- 10, 67, 67, 67, 67, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 11, 12, 13, 14, 15, +- 16, +-}; +-#if defined(__cplusplus) || defined(__STDC__) +-const short sudoerscheck[] = +-#else +-short sudoerscheck[] = +-#endif +- { 33, +- 0, 8, 9, 33, 33, 7, 86, 44, 33, 33, +- 44, 33, 285, 33, 0, 44, 257, 258, 258, 44, +- 33, 258, 44, 258, 61, 258, 258, 33, 58, 261, +- 262, 263, 258, 33, 260, 261, 44, 263, 259, 43, +- 258, 45, 58, 284, 44, 263, 44, 33, 0, 58, +- 58, 61, 284, 36, 263, 38, 39, 61, 284, 58, +- 263, 58, 0, 58, 263, 145, 284, 61, 51, 58, +- 61, 58, 58, 61, 291, 292, 293, 294, 295, 296, +- 297, 33, 58, 58, 264, 264, 93, 89, 95, 264, +- 264, 40, 61, 44, 44, 33, 0, 44, 44, 41, +- 44, 61, 61, 61, 61, 61, 58, 61, 263, 263, +- 0, 118, 263, 263, 263, 263, 263, 0, 0, 41, +- 58, 41, 41, 41, 41, 52, 91, 75, 43, 33, +- 126, 34, 77, 66, 22, 154, 17, 99, 131, 92, +- -1, 96, -1, 33, 0, 135, -1, 90, -1, -1, +- -1, -1, -1, 94, 58, -1, -1, -1, 0, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, +- -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +- -1, 33, 0, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, 258, 33, 260, 261, 258, 263, +- 259, 261, 262, 263, 259, 259, -1, 259, 258, 33, +- 0, 261, 262, 263, 257, 258, -1, -1, -1, -1, +- 284, 257, 258, -1, 284, -1, 256, -1, 258, 33, +- -1, 261, 262, 263, 284, 265, 266, 267, 268, 269, +- 256, 284, 258, 33, 0, 261, 262, 263, 284, 265, +- 266, 267, 268, 269, 284, 285, 286, 287, 288, 289, +- -1, -1, -1, 299, 300, 301, 302, -1, 284, 285, +- 286, 287, 288, 289, 256, -1, 258, 33, 0, 261, +- 262, 263, -1, 265, 266, 267, 268, 269, 256, -1, +- 258, 33, 0, 261, 262, 263, -1, 265, 266, 267, +- 268, 269, 284, 285, 286, 287, 288, 289, -1, -1, +- -1, 33, -1, -1, -1, -1, 284, 285, 286, 287, +- 288, 289, 256, -1, 258, 33, 0, 261, 262, 263, +- -1, 265, 266, 267, 268, 269, 256, -1, 258, -1, +- 0, 261, 262, 263, -1, 265, 266, 267, 268, 269, +- 284, 285, 286, 287, 288, 289, -1, -1, -1, 33, +- -1, -1, -1, -1, 284, 285, 286, 287, 288, 289, +- 256, -1, 258, 33, -1, 261, 262, 263, -1, 265, +- 266, 267, 268, 269, 256, -1, 258, -1, -1, 261, +- 262, 263, -1, 265, 266, 267, 268, 269, 284, 285, +- 286, 287, 288, 289, -1, -1, 33, -1, -1, -1, +- -1, -1, 284, 285, 286, 287, 288, 289, 256, -1, +- 258, -1, -1, 261, 262, 263, -1, 265, 266, 267, +- 268, 269, 256, -1, 258, -1, -1, 261, 262, 263, +- -1, 265, 266, 267, 268, 269, 284, 285, 286, 287, +- 288, 289, 33, -1, 258, -1, 260, 261, -1, 263, +- 284, 285, 286, 287, 288, 289, 256, -1, 258, -1, +- -1, 261, 262, 263, -1, 265, 266, 267, 268, 269, +- 284, -1, -1, -1, -1, 33, -1, -1, -1, -1, +- -1, -1, -1, -1, 284, 285, 286, 287, 288, 289, +- 256, -1, 258, -1, -1, 261, 262, 263, -1, 265, +- 266, 267, 268, 269, 33, -1, 258, -1, -1, -1, +- -1, 263, -1, -1, -1, -1, -1, -1, 284, 285, +- 286, 287, 288, 289, 256, -1, 258, -1, -1, 261, +- 262, 263, 284, 265, 266, 267, 268, 269, 256, -1, +- 258, -1, -1, 261, 262, 263, -1, 265, 266, 267, +- 268, 269, 284, 285, 286, 287, 288, 289, -1, -1, +- -1, -1, -1, -1, -1, -1, 284, 285, 286, 287, +- 288, 289, 256, -1, 258, -1, -1, 261, 262, 263, +- -1, 265, 266, 267, 268, 269, 256, -1, 258, -1, +- -1, 261, 262, 263, -1, 265, 266, 267, 268, 269, +- 284, 285, 286, 287, 288, 289, -1, -1, -1, -1, +- -1, -1, -1, -1, 284, 285, 286, 287, 288, 289, +- 257, 258, -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, 270, 271, 272, 273, 274, 275, 276, +- 277, 278, 279, 280, 281, 282, 283, 284, -1, -1, +- -1, -1, -1, -1, 291, 292, 293, 294, 295, 296, +- 297, -1, 299, 300, 301, 302, 257, 258, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, -1, 270, +- 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, +- 281, 282, 283, 284, -1, -1, -1, -1, -1, 257, +- 258, -1, -1, -1, -1, -1, -1, -1, 299, 300, +- 301, 302, 270, 271, 272, 273, 274, 275, 276, 277, +- 278, 279, 280, 281, 282, 283, 284, 256, -1, 258, +- -1, -1, 261, 262, 263, -1, 265, 266, 267, 268, +- 269, 299, 300, 301, 302, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, 284, 285, 286, 287, 288, +- 289, +-}; +-#define YYFINAL 18 +-#ifndef YYDEBUG +-#define YYDEBUG 0 +-#endif +-#define YYMAXTOKEN 302 +-#if YYDEBUG +-#if defined(__cplusplus) || defined(__STDC__) +-const char * const sudoersname[] = +-#else +-char *sudoersname[] = +-#endif +- { +-"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +-"'!'",0,0,0,0,0,0,"'('","')'",0,"'+'","','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,"':'", +-0,0,"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +-"COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DIGEST", +-"DEFAULTS","DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","DEFAULTS_CMND", +-"NOPASSWD","PASSWD","NOEXEC","EXEC","SETENV","NOSETENV","LOG_INPUT", +-"NOLOG_INPUT","LOG_OUTPUT","NOLOG_OUTPUT","MAIL","NOMAIL","FOLLOW","NOFOLLOW", +-"ALL","COMMENT","HOSTALIAS","CMNDALIAS","USERALIAS","RUNASALIAS","ERROR","TYPE", +-"ROLE","PRIVS","LIMITPRIVS","CMND_TIMEOUT","NOTBEFORE","NOTAFTER","MYSELF", +-"SHA224_TOK","SHA256_TOK","SHA384_TOK","SHA512_TOK", +-}; +-#if defined(__cplusplus) || defined(__STDC__) +-const char * const sudoersrule[] = +-#else +-char *sudoersrule[] = +-#endif +- {"$accept : file", +-"file :", +-"file : line", +-"line : entry", +-"line : line entry", +-"entry : COMMENT", +-"entry : error COMMENT", +-"entry : userlist privileges", +-"entry : USERALIAS useraliases", +-"entry : HOSTALIAS hostaliases", +-"entry : CMNDALIAS cmndaliases", +-"entry : RUNASALIAS runasaliases", +-"entry : DEFAULTS defaults_list", +-"entry : DEFAULTS_USER userlist defaults_list", +-"entry : DEFAULTS_RUNAS userlist defaults_list", +-"entry : DEFAULTS_HOST hostlist defaults_list", +-"entry : DEFAULTS_CMND cmndlist defaults_list", +-"defaults_list : defaults_entry", +-"defaults_list : defaults_list ',' defaults_entry", +-"defaults_entry : DEFVAR", +-"defaults_entry : '!' DEFVAR", +-"defaults_entry : DEFVAR '=' WORD", +-"defaults_entry : DEFVAR '+' WORD", +-"defaults_entry : DEFVAR '-' WORD", +-"privileges : privilege", +-"privileges : privileges ':' privilege", +-"privilege : hostlist '=' cmndspeclist", +-"ophost : host", +-"ophost : '!' host", +-"host : ALIAS", +-"host : ALL", +-"host : NETGROUP", +-"host : NTWKADDR", +-"host : WORD", +-"cmndspeclist : cmndspec", +-"cmndspeclist : cmndspeclist ',' cmndspec", +-"cmndspec : runasspec options cmndtag digcmnd", +-"digest : SHA224_TOK ':' DIGEST", +-"digest : SHA256_TOK ':' DIGEST", +-"digest : SHA384_TOK ':' DIGEST", +-"digest : SHA512_TOK ':' DIGEST", +-"digcmnd : opcmnd", +-"digcmnd : digest opcmnd", +-"opcmnd : cmnd", +-"opcmnd : '!' cmnd", +-"timeoutspec : CMND_TIMEOUT '=' WORD", +-"notbeforespec : NOTBEFORE '=' WORD", +-"notafterspec : NOTAFTER '=' WORD", +-"rolespec : ROLE '=' WORD", +-"typespec : TYPE '=' WORD", +-"privsspec : PRIVS '=' WORD", +-"limitprivsspec : LIMITPRIVS '=' WORD", +-"runasspec :", +-"runasspec : '(' runaslist ')'", +-"runaslist :", +-"runaslist : userlist", +-"runaslist : userlist ':' grouplist", +-"runaslist : ':' grouplist", +-"runaslist : ':'", +-"options :", +-"options : options notbeforespec", +-"options : options notafterspec", +-"options : options timeoutspec", +-"options : options rolespec", +-"options : options typespec", +-"options : options privsspec", +-"options : options limitprivsspec", +-"cmndtag :", +-"cmndtag : cmndtag NOPASSWD", +-"cmndtag : cmndtag PASSWD", +-"cmndtag : cmndtag NOEXEC", +-"cmndtag : cmndtag EXEC", +-"cmndtag : cmndtag SETENV", +-"cmndtag : cmndtag NOSETENV", +-"cmndtag : cmndtag LOG_INPUT", +-"cmndtag : cmndtag NOLOG_INPUT", +-"cmndtag : cmndtag LOG_OUTPUT", +-"cmndtag : cmndtag NOLOG_OUTPUT", +-"cmndtag : cmndtag FOLLOW", +-"cmndtag : cmndtag NOFOLLOW", +-"cmndtag : cmndtag MAIL", +-"cmndtag : cmndtag NOMAIL", +-"cmnd : ALL", +-"cmnd : ALIAS", +-"cmnd : COMMAND", +-"hostaliases : hostalias", +-"hostaliases : hostaliases ':' hostalias", +-"hostalias : ALIAS '=' hostlist", +-"hostlist : ophost", +-"hostlist : hostlist ',' ophost", +-"cmndaliases : cmndalias", +-"cmndaliases : cmndaliases ':' cmndalias", +-"cmndalias : ALIAS '=' cmndlist", +-"cmndlist : digcmnd", +-"cmndlist : cmndlist ',' digcmnd", +-"runasaliases : runasalias", +-"runasaliases : runasaliases ':' runasalias", +-"runasalias : ALIAS '=' userlist", +-"useraliases : useralias", +-"useraliases : useraliases ':' useralias", +-"useralias : ALIAS '=' userlist", +-"userlist : opuser", +-"userlist : userlist ',' opuser", +-"opuser : user", +-"opuser : '!' user", +-"user : ALIAS", +-"user : ALL", +-"user : NETGROUP", +-"user : USERGROUP", +-"user : WORD", +-"grouplist : opgroup", +-"grouplist : grouplist ',' opgroup", +-"opgroup : group", +-"opgroup : '!' group", +-"group : ALIAS", +-"group : ALL", +-"group : WORD", +-}; +-#endif +-#ifdef YYSTACKSIZE +-#undef YYMAXDEPTH +-#define YYMAXDEPTH YYSTACKSIZE +-#else +-#ifdef YYMAXDEPTH +-#define YYSTACKSIZE YYMAXDEPTH +-#else +-#define YYSTACKSIZE 10000 +-#define YYMAXDEPTH 10000 +-#endif +-#endif +-#define YYINITSTACKSIZE 200 +-/* LINTUSED */ +-int yydebug; +-int yynerrs; +-int yyerrflag; +-int yychar; +-short *yyssp; +-YYSTYPE *yyvsp; +-YYSTYPE yyval; +-YYSTYPE yylval; +-short *yyss; +-short *yysslim; +-YYSTYPE *yyvs; +-unsigned int yystacksize; +-int yyparse(void); +-#line 904 "gram.y" +-void +-sudoerserror(const char *s) +-{ +- debug_decl(sudoerserror, SUDOERS_DEBUG_PARSER) +- +- /* Save the line the first error occurred on. */ +- if (errorlineno == -1) { +- errorlineno = this_lineno; +- rcstr_delref(errorfile); +- errorfile = rcstr_addref(sudoers); +- } +- if (sudoers_warnings && s != NULL) { +- LEXTRACE("<*> "); +-#ifndef TRACELEXER +- if (trace_print == NULL || trace_print == sudoers_trace_print) { +- const char fmt[] = ">>> %s: %s near line %d <<<\n"; +- int oldlocale; +- +- /* Warnings are displayed in the user's locale. */ +- sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale); +- sudo_printf(SUDO_CONV_ERROR_MSG, _(fmt), sudoers, _(s), this_lineno); +- sudoers_setlocale(oldlocale, NULL); +- } +-#endif +- } +- parse_error = true; +- debug_return; +-} +- +-static struct defaults * +-new_default(char *var, char *val, short op) +-{ +- struct defaults *d; +- debug_decl(new_default, SUDOERS_DEBUG_PARSER) +- +- if ((d = calloc(1, sizeof(struct defaults))) == NULL) { +- sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +- "unable to allocate memory"); +- debug_return_ptr(NULL); +- } +- +- d->var = var; +- d->val = val; +- /* d->type = 0; */ +- d->op = op; +- /* d->binding = NULL */ +- d->lineno = this_lineno; +- d->file = rcstr_addref(sudoers); +- HLTQ_INIT(d, entries); +- +- debug_return_ptr(d); +-} +- +-static struct member * +-new_member(char *name, int type) +-{ +- struct member *m; +- debug_decl(new_member, SUDOERS_DEBUG_PARSER) +- +- if ((m = calloc(1, sizeof(struct member))) == NULL) { +- sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +- "unable to allocate memory"); +- debug_return_ptr(NULL); +- } +- +- m->name = name; +- m->type = type; +- HLTQ_INIT(m, entries); +- +- debug_return_ptr(m); +-} +- +-static struct command_digest * +-new_digest(int digest_type, char *digest_str) +-{ +- struct command_digest *digest; +- debug_decl(new_digest, SUDOERS_DEBUG_PARSER) +- +- if ((digest = malloc(sizeof(*digest))) == NULL) { +- sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +- "unable to allocate memory"); +- debug_return_ptr(NULL); +- } +- +- digest->digest_type = digest_type; +- digest->digest_str = digest_str; +- if (digest->digest_str == NULL) { +- sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +- "unable to allocate memory"); +- free(digest); +- digest = NULL; +- } +- +- debug_return_ptr(digest); +-} +- +-/* +- * Add a list of defaults structures to the defaults list. +- * The binding, if non-NULL, specifies a list of hosts, users, or +- * runas users the entries apply to (specified by the type). +- */ +-static bool +-add_defaults(int type, struct member *bmem, struct defaults *defs) +-{ +- struct defaults *d, *next; +- struct member_list *binding; +- bool ret = true; +- debug_decl(add_defaults, SUDOERS_DEBUG_PARSER) +- +- if (defs != NULL) { +- /* +- * We use a single binding for each entry in defs. +- */ +- if ((binding = malloc(sizeof(*binding))) == NULL) { +- sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +- "unable to allocate memory"); +- sudoerserror(N_("unable to allocate memory")); +- debug_return_bool(false); +- } +- if (bmem != NULL) +- HLTQ_TO_TAILQ(binding, bmem, entries); +- else +- TAILQ_INIT(binding); +- +- /* +- * Set type and binding (who it applies to) for new entries. +- * Then add to the global defaults list. +- */ +- HLTQ_FOREACH_SAFE(d, defs, entries, next) { +- d->type = type; +- d->binding = binding; +- TAILQ_INSERT_TAIL(&parsed_policy.defaults, d, entries); +- } +- } +- +- debug_return_bool(ret); +-} +- +-/* +- * Allocate a new struct userspec, populate it, and insert it at the +- * end of the userspecs list. +- */ +-static bool +-add_userspec(struct member *members, struct privilege *privs) +-{ +- struct userspec *u; +- debug_decl(add_userspec, SUDOERS_DEBUG_PARSER) +- +- if ((u = calloc(1, sizeof(*u))) == NULL) { +- sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, +- "unable to allocate memory"); +- debug_return_bool(false); +- } +- u->lineno = this_lineno; +- u->file = rcstr_addref(sudoers); +- HLTQ_TO_TAILQ(&u->users, members, entries); +- HLTQ_TO_TAILQ(&u->privileges, privs, entries); +- STAILQ_INIT(&u->comments); +- TAILQ_INSERT_TAIL(&parsed_policy.userspecs, u, entries); +- +- debug_return_bool(true); +-} +- +-/* +- * Free a member struct and its contents. +- */ +-void +-free_member(struct member *m) +-{ +- debug_decl(free_member, SUDOERS_DEBUG_PARSER) +- +- if (m->type == COMMAND) { +- struct sudo_command *c = (struct sudo_command *)m->name; +- free(c->cmnd); +- free(c->args); +- if (c->digest != NULL) { +- free(c->digest->digest_str); +- free(c->digest); +- } +- } +- free(m->name); +- free(m); +- +- debug_return; +-} +- +-/* +- * Free a tailq of members but not the struct member_list container itself. +- */ +-void +-free_members(struct member_list *members) +-{ +- struct member *m; +- debug_decl(free_members, SUDOERS_DEBUG_PARSER) +- +- while ((m = TAILQ_FIRST(members)) != NULL) { +- TAILQ_REMOVE(members, m, entries); +- free_member(m); +- } +- +- debug_return; +-} +- +-void +-free_defaults(struct defaults_list *defs) +-{ +- struct member_list *prev_binding = NULL; +- struct defaults *def; +- debug_decl(free_defaults, SUDOERS_DEBUG_PARSER) +- +- while ((def = TAILQ_FIRST(defs)) != NULL) { +- TAILQ_REMOVE(defs, def, entries); +- free_default(def, &prev_binding); +- } +- +- debug_return; +-} +- +-void +-free_default(struct defaults *def, struct member_list **binding) +-{ +- debug_decl(free_default, SUDOERS_DEBUG_PARSER) +- +- if (def->binding != *binding) { +- *binding = def->binding; +- if (def->binding != NULL) { +- free_members(def->binding); +- free(def->binding); +- } +- } +- rcstr_delref(def->file); +- free(def->var); +- free(def->val); +- free(def); +- +- debug_return; +-} +- +-void +-free_privilege(struct privilege *priv) +-{ +- struct member_list *runasuserlist = NULL, *runasgrouplist = NULL; +- struct member_list *prev_binding = NULL; +- struct cmndspec *cs; +- struct defaults *def; +-#ifdef HAVE_SELINUX +- char *role = NULL, *type = NULL; +-#endif /* HAVE_SELINUX */ +-#ifdef HAVE_PRIV_SET +- char *privs = NULL, *limitprivs = NULL; +-#endif /* HAVE_PRIV_SET */ +- debug_decl(free_privilege, SUDOERS_DEBUG_PARSER) +- +- free(priv->ldap_role); +- free_members(&priv->hostlist); +- while ((cs = TAILQ_FIRST(&priv->cmndlist)) != NULL) { +- TAILQ_REMOVE(&priv->cmndlist, cs, entries); +-#ifdef HAVE_SELINUX +- /* Only free the first instance of a role/type. */ +- if (cs->role != role) { +- role = cs->role; +- free(cs->role); +- } +- if (cs->type != type) { +- type = cs->type; +- free(cs->type); +- } +-#endif /* HAVE_SELINUX */ +-#ifdef HAVE_PRIV_SET +- /* Only free the first instance of privs/limitprivs. */ +- if (cs->privs != privs) { +- privs = cs->privs; +- free(cs->privs); +- } +- if (cs->limitprivs != limitprivs) { +- limitprivs = cs->limitprivs; +- free(cs->limitprivs); +- } +-#endif /* HAVE_PRIV_SET */ +- /* Only free the first instance of runas user/group lists. */ +- if (cs->runasuserlist && cs->runasuserlist != runasuserlist) { +- runasuserlist = cs->runasuserlist; +- free_members(runasuserlist); +- free(runasuserlist); +- } +- if (cs->runasgrouplist && cs->runasgrouplist != runasgrouplist) { +- runasgrouplist = cs->runasgrouplist; +- free_members(runasgrouplist); +- free(runasgrouplist); +- } +- free_member(cs->cmnd); +- free(cs); +- } +- while ((def = TAILQ_FIRST(&priv->defaults)) != NULL) { +- TAILQ_REMOVE(&priv->defaults, def, entries); +- free_default(def, &prev_binding); +- } +- free(priv); +- +- debug_return; +-} +- +-void +-free_userspecs(struct userspec_list *usl) +-{ +- struct userspec *us; +- debug_decl(free_userspecs, SUDOERS_DEBUG_PARSER) +- +- while ((us = TAILQ_FIRST(usl)) != NULL) { +- TAILQ_REMOVE(usl, us, entries); +- free_userspec(us); +- } +- +- debug_return; +-} +- +-void +-free_userspec(struct userspec *us) +-{ +- struct privilege *priv; +- struct sudoers_comment *comment; +- debug_decl(free_userspec, SUDOERS_DEBUG_PARSER) +- +- free_members(&us->users); +- while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) { +- TAILQ_REMOVE(&us->privileges, priv, entries); +- free_privilege(priv); +- } +- while ((comment = STAILQ_FIRST(&us->comments)) != NULL) { +- STAILQ_REMOVE_HEAD(&us->comments, entries); +- free(comment->str); +- free(comment); +- } +- rcstr_delref(us->file); +- free(us); +- +- debug_return; +-} +- +-/* +- * Initialized a sudoers parse tree. +- */ +-void +-init_parse_tree(struct sudoers_parse_tree *parse_tree) +-{ +- TAILQ_INIT(&parse_tree->userspecs); +- TAILQ_INIT(&parse_tree->defaults); +- parse_tree->aliases = NULL; +-} +- +-/* +- * Move the contents of parsed_policy to new_tree. +- */ +-void +-reparent_parse_tree(struct sudoers_parse_tree *new_tree) +-{ +- TAILQ_CONCAT(&new_tree->userspecs, &parsed_policy.userspecs, entries); +- TAILQ_CONCAT(&new_tree->defaults, &parsed_policy.defaults, entries); +- new_tree->aliases = parsed_policy.aliases; +- parsed_policy.aliases = NULL; +-} +- +-/* +- * Free the contents of a sudoers parse tree and initialize it. +- */ +-void +-free_parse_tree(struct sudoers_parse_tree *parse_tree) +-{ +- free_userspecs(&parse_tree->userspecs); +- free_defaults(&parse_tree->defaults); +- free_aliases(parse_tree->aliases); +- parse_tree->aliases = NULL; +-} +- +-/* +- * Free up space used by data structures from a previous parser run and sets +- * the current sudoers file to path. +- */ +-bool +-init_parser(const char *path, bool quiet) +-{ +- bool ret = true; +- debug_decl(init_parser, SUDOERS_DEBUG_PARSER) +- +- free_parse_tree(&parsed_policy); +- init_lexer(); +- +- rcstr_delref(sudoers); +- if (path != NULL) { +- if ((sudoers = rcstr_dup(path)) == NULL) { +- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); +- ret = false; +- } +- } else { +- sudoers = NULL; +- } +- +- parse_error = false; +- errorlineno = -1; +- rcstr_delref(errorfile); +- errorfile = NULL; +- sudoers_warnings = !quiet; +- +- debug_return_bool(ret); +-} +- +-/* +- * Initialize all options in a cmndspec. +- */ +-static void +-init_options(struct command_options *opts) +-{ +- opts->notbefore = UNSPEC; +- opts->notafter = UNSPEC; +- opts->timeout = UNSPEC; +-#ifdef HAVE_SELINUX +- opts->role = NULL; +- opts->type = NULL; +-#endif +-#ifdef HAVE_PRIV_SET +- opts->privs = NULL; +- opts->limitprivs = NULL; +-#endif +-} +-#line 1044 "gram.c" +-/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +-#if defined(__cplusplus) || defined(__STDC__) +-static int yygrowstack(void) +-#else +-static int yygrowstack() +-#endif +-{ +- unsigned int newsize; +- long sslen; +- short *newss; +- YYSTYPE *newvs; +- +- if ((newsize = yystacksize) == 0) +- newsize = YYINITSTACKSIZE; +- else if (newsize >= YYMAXDEPTH) +- return -1; +- else if ((newsize *= 2) > YYMAXDEPTH) +- newsize = YYMAXDEPTH; +-#ifdef SIZE_MAX +-#define YY_SIZE_MAX SIZE_MAX +-#else +-#ifdef __STDC__ +-#define YY_SIZE_MAX 0xffffffffU +-#else +-#define YY_SIZE_MAX (unsigned int)0xffffffff +-#endif +-#endif +- if (YY_SIZE_MAX / newsize < sizeof *newss) +- goto bail; +- sslen = yyssp - yyss; +- newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : +- (short *)malloc(newsize * sizeof *newss); /* overflow check above */ +- if (newss == NULL) +- goto bail; +- yyss = newss; +- yyssp = newss + sslen; +- newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : +- (YYSTYPE *)malloc(newsize * sizeof *newvs); /* overflow check above */ +- if (newvs == NULL) +- goto bail; +- yyvs = newvs; +- yyvsp = newvs + sslen; +- yystacksize = newsize; +- yysslim = yyss + newsize - 1; +- return 0; +-bail: +- if (yyss) +- free(yyss); +- if (yyvs) +- free(yyvs); +- yyss = yyssp = NULL; +- yyvs = yyvsp = NULL; +- yystacksize = 0; +- return -1; +-} +- +-#define YYABORT goto yyabort +-#define YYREJECT goto yyabort +-#define YYACCEPT goto yyaccept +-#define YYERROR goto yyerrlab +-int +-#if defined(__cplusplus) || defined(__STDC__) +-yyparse(void) +-#else +-yyparse() +-#endif +-{ +- int yym, yyn, yystate; +-#if YYDEBUG +-#if defined(__cplusplus) || defined(__STDC__) +- const char *yys; +-#else /* !(defined(__cplusplus) || defined(__STDC__)) */ +- char *yys; +-#endif /* !(defined(__cplusplus) || defined(__STDC__)) */ +- +- if ((yys = getenv("YYDEBUG"))) +- { +- yyn = *yys; +- if (yyn >= '0' && yyn <= '9') +- yydebug = yyn - '0'; +- } +-#endif /* YYDEBUG */ +- +- yynerrs = 0; +- yyerrflag = 0; +- yychar = (-1); +- +- if (yyss == NULL && yygrowstack()) goto yyoverflow; +- yyssp = yyss; +- yyvsp = yyvs; +- *yyssp = yystate = 0; +- +-yyloop: +- if ((yyn = yydefred[yystate]) != 0) goto yyreduce; +- if (yychar < 0) +- { +- if ((yychar = yylex()) < 0) yychar = 0; +-#if YYDEBUG +- if (yydebug) +- { +- yys = 0; +- if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; +- if (!yys) yys = "illegal-symbol"; +- printf("%sdebug: state %d, reading %d (%s)\n", +- YYPREFIX, yystate, yychar, yys); +- } +-#endif +- } +- if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && +- yyn <= YYTABLESIZE && yycheck[yyn] == yychar) +- { +-#if YYDEBUG +- if (yydebug) +- printf("%sdebug: state %d, shifting to state %d\n", +- YYPREFIX, yystate, yytable[yyn]); +-#endif +- if (yyssp >= yysslim && yygrowstack()) +- { +- goto yyoverflow; +- } +- *++yyssp = yystate = yytable[yyn]; +- *++yyvsp = yylval; +- yychar = (-1); +- if (yyerrflag > 0) --yyerrflag; +- goto yyloop; +- } +- if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && +- yyn <= YYTABLESIZE && yycheck[yyn] == yychar) +- { +- yyn = yytable[yyn]; +- goto yyreduce; +- } +- if (yyerrflag) goto yyinrecovery; +-#if defined(__GNUC__) +- goto yynewerror; +-#endif +-yynewerror: +- yyerror("syntax error"); +-#if defined(__GNUC__) +- goto yyerrlab; +-#endif +-yyerrlab: +- ++yynerrs; +-yyinrecovery: +- if (yyerrflag < 3) +- { +- yyerrflag = 3; +- for (;;) +- { +- if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && +- yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) +- { +-#if YYDEBUG +- if (yydebug) +- printf("%sdebug: state %d, error recovery shifting\ +- to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +-#endif +- if (yyssp >= yysslim && yygrowstack()) +- { +- goto yyoverflow; +- } +- *++yyssp = yystate = yytable[yyn]; +- *++yyvsp = yylval; +- goto yyloop; +- } +- else +- { +-#if YYDEBUG +- if (yydebug) +- printf("%sdebug: error recovery discarding state %d\n", +- YYPREFIX, *yyssp); +-#endif +- if (yyssp <= yyss) goto yyabort; +- --yyssp; +- --yyvsp; +- } +- } +- } +- else +- { +- if (yychar == 0) goto yyabort; +-#if YYDEBUG +- if (yydebug) +- { +- yys = 0; +- if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; +- if (!yys) yys = "illegal-symbol"; +- printf("%sdebug: state %d, error recovery discards token %d (%s)\n", +- YYPREFIX, yystate, yychar, yys); +- } +-#endif +- yychar = (-1); +- goto yyloop; +- } +-yyreduce: +-#if YYDEBUG +- if (yydebug) +- printf("%sdebug: state %d, reducing by rule %d (%s)\n", +- YYPREFIX, yystate, yyn, yyrule[yyn]); +-#endif +- yym = yylen[yyn]; +- if (yym) +- yyval = yyvsp[1-yym]; +- else +- memset(&yyval, 0, sizeof yyval); +- switch (yyn) +- { +-case 1: +-#line 176 "gram.y" +-{ ; } +-break; +-case 5: +-#line 184 "gram.y" +-{ +- ; +- } +-break; +-case 6: +-#line 187 "gram.y" +-{ +- yyerrok; +- } +-break; +-case 7: +-#line 190 "gram.y" +-{ +- if (!add_userspec(yyvsp[-1].member, yyvsp[0].privilege)) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 8: +-#line 196 "gram.y" +-{ +- ; +- } +-break; +-case 9: +-#line 199 "gram.y" +-{ +- ; +- } +-break; +-case 10: +-#line 202 "gram.y" +-{ +- ; +- } +-break; +-case 11: +-#line 205 "gram.y" +-{ +- ; +- } +-break; +-case 12: +-#line 208 "gram.y" +-{ +- if (!add_defaults(DEFAULTS, NULL, yyvsp[0].defaults)) +- YYERROR; +- } +-break; +-case 13: +-#line 212 "gram.y" +-{ +- if (!add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults)) +- YYERROR; +- } +-break; +-case 14: +-#line 216 "gram.y" +-{ +- if (!add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults)) +- YYERROR; +- } +-break; +-case 15: +-#line 220 "gram.y" +-{ +- if (!add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults)) +- YYERROR; +- } +-break; +-case 16: +-#line 224 "gram.y" +-{ +- if (!add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults)) +- YYERROR; +- } +-break; +-case 18: +-#line 231 "gram.y" +-{ +- HLTQ_CONCAT(yyvsp[-2].defaults, yyvsp[0].defaults, entries); +- yyval.defaults = yyvsp[-2].defaults; +- } +-break; +-case 19: +-#line 237 "gram.y" +-{ +- yyval.defaults = new_default(yyvsp[0].string, NULL, true); +- if (yyval.defaults == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 20: +-#line 244 "gram.y" +-{ +- yyval.defaults = new_default(yyvsp[0].string, NULL, false); +- if (yyval.defaults == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 21: +-#line 251 "gram.y" +-{ +- yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, true); +- if (yyval.defaults == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 22: +-#line 258 "gram.y" +-{ +- yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+'); +- if (yyval.defaults == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 23: +-#line 265 "gram.y" +-{ +- yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-'); +- if (yyval.defaults == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 25: +-#line 275 "gram.y" +-{ +- HLTQ_CONCAT(yyvsp[-2].privilege, yyvsp[0].privilege, entries); +- yyval.privilege = yyvsp[-2].privilege; +- } +-break; +-case 26: +-#line 281 "gram.y" +-{ +- struct privilege *p = calloc(1, sizeof(*p)); +- if (p == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- TAILQ_INIT(&p->defaults); +- HLTQ_TO_TAILQ(&p->hostlist, yyvsp[-2].member, entries); +- HLTQ_TO_TAILQ(&p->cmndlist, yyvsp[0].cmndspec, entries); +- HLTQ_INIT(p, entries); +- yyval.privilege = p; +- } +-break; +-case 27: +-#line 295 "gram.y" +-{ +- yyval.member = yyvsp[0].member; +- yyval.member->negated = false; +- } +-break; +-case 28: +-#line 299 "gram.y" +-{ +- yyval.member = yyvsp[0].member; +- yyval.member->negated = true; +- } +-break; +-case 29: +-#line 305 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, ALIAS); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 30: +-#line 312 "gram.y" +-{ +- yyval.member = new_member(NULL, ALL); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 31: +-#line 319 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, NETGROUP); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 32: +-#line 326 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, NTWKADDR); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 33: +-#line 333 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, WORD); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 35: +-#line 343 "gram.y" +-{ +- struct cmndspec *prev; +- prev = HLTQ_LAST(yyvsp[-2].cmndspec, cmndspec, entries); +- HLTQ_CONCAT(yyvsp[-2].cmndspec, yyvsp[0].cmndspec, entries); +-#ifdef HAVE_SELINUX +- /* propagate role and type */ +- if (yyvsp[0].cmndspec->role == NULL && yyvsp[0].cmndspec->type == NULL) { +- yyvsp[0].cmndspec->role = prev->role; +- yyvsp[0].cmndspec->type = prev->type; +- } +-#endif /* HAVE_SELINUX */ +-#ifdef HAVE_PRIV_SET +- /* propagate privs & limitprivs */ +- if (yyvsp[0].cmndspec->privs == NULL && yyvsp[0].cmndspec->limitprivs == NULL) { +- yyvsp[0].cmndspec->privs = prev->privs; +- yyvsp[0].cmndspec->limitprivs = prev->limitprivs; +- } +-#endif /* HAVE_PRIV_SET */ +- /* propagate command time restrictions */ +- if (yyvsp[0].cmndspec->notbefore == UNSPEC) +- yyvsp[0].cmndspec->notbefore = prev->notbefore; +- if (yyvsp[0].cmndspec->notafter == UNSPEC) +- yyvsp[0].cmndspec->notafter = prev->notafter; +- /* propagate command timeout */ +- if (yyvsp[0].cmndspec->timeout == UNSPEC) +- yyvsp[0].cmndspec->timeout = prev->timeout; +- /* propagate tags and runas list */ +- if (yyvsp[0].cmndspec->tags.nopasswd == UNSPEC) +- yyvsp[0].cmndspec->tags.nopasswd = prev->tags.nopasswd; +- if (yyvsp[0].cmndspec->tags.noexec == UNSPEC) +- yyvsp[0].cmndspec->tags.noexec = prev->tags.noexec; +- if (yyvsp[0].cmndspec->tags.setenv == UNSPEC && +- prev->tags.setenv != IMPLIED) +- yyvsp[0].cmndspec->tags.setenv = prev->tags.setenv; +- if (yyvsp[0].cmndspec->tags.log_input == UNSPEC) +- yyvsp[0].cmndspec->tags.log_input = prev->tags.log_input; +- if (yyvsp[0].cmndspec->tags.log_output == UNSPEC) +- yyvsp[0].cmndspec->tags.log_output = prev->tags.log_output; +- if (yyvsp[0].cmndspec->tags.send_mail == UNSPEC) +- yyvsp[0].cmndspec->tags.send_mail = prev->tags.send_mail; +- if (yyvsp[0].cmndspec->tags.follow == UNSPEC) +- yyvsp[0].cmndspec->tags.follow = prev->tags.follow; +- if ((yyvsp[0].cmndspec->runasuserlist == NULL && +- yyvsp[0].cmndspec->runasgrouplist == NULL) && +- (prev->runasuserlist != NULL || +- prev->runasgrouplist != NULL)) { +- yyvsp[0].cmndspec->runasuserlist = prev->runasuserlist; +- yyvsp[0].cmndspec->runasgrouplist = prev->runasgrouplist; +- } +- yyval.cmndspec = yyvsp[-2].cmndspec; +- } +-break; +-case 36: +-#line 396 "gram.y" +-{ +- struct cmndspec *cs = calloc(1, sizeof(*cs)); +- if (cs == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- if (yyvsp[-3].runas != NULL) { +- if (yyvsp[-3].runas->runasusers != NULL) { +- cs->runasuserlist = +- malloc(sizeof(*cs->runasuserlist)); +- if (cs->runasuserlist == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- HLTQ_TO_TAILQ(cs->runasuserlist, +- yyvsp[-3].runas->runasusers, entries); +- } +- if (yyvsp[-3].runas->runasgroups != NULL) { +- cs->runasgrouplist = +- malloc(sizeof(*cs->runasgrouplist)); +- if (cs->runasgrouplist == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- HLTQ_TO_TAILQ(cs->runasgrouplist, +- yyvsp[-3].runas->runasgroups, entries); +- } +- free(yyvsp[-3].runas); +- } +-#ifdef HAVE_SELINUX +- cs->role = yyvsp[-2].options.role; +- cs->type = yyvsp[-2].options.type; +-#endif +-#ifdef HAVE_PRIV_SET +- cs->privs = yyvsp[-2].options.privs; +- cs->limitprivs = yyvsp[-2].options.limitprivs; +-#endif +- cs->notbefore = yyvsp[-2].options.notbefore; +- cs->notafter = yyvsp[-2].options.notafter; +- cs->timeout = yyvsp[-2].options.timeout; +- cs->tags = yyvsp[-1].tag; +- cs->cmnd = yyvsp[0].member; +- HLTQ_INIT(cs, entries); +- /* sudo "ALL" implies the SETENV tag */ +- if (cs->cmnd->type == ALL && !cs->cmnd->negated && +- cs->tags.setenv == UNSPEC) +- cs->tags.setenv = IMPLIED; +- yyval.cmndspec = cs; +- } +-break; +-case 37: +-#line 447 "gram.y" +-{ +- yyval.digest = new_digest(SUDO_DIGEST_SHA224, yyvsp[0].string); +- if (yyval.digest == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 38: +-#line 454 "gram.y" +-{ +- yyval.digest = new_digest(SUDO_DIGEST_SHA256, yyvsp[0].string); +- if (yyval.digest == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 39: +-#line 461 "gram.y" +-{ +- yyval.digest = new_digest(SUDO_DIGEST_SHA384, yyvsp[0].string); +- if (yyval.digest == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 40: +-#line 468 "gram.y" +-{ +- yyval.digest = new_digest(SUDO_DIGEST_SHA512, yyvsp[0].string); +- if (yyval.digest == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 41: +-#line 477 "gram.y" +-{ +- yyval.member = yyvsp[0].member; +- } +-break; +-case 42: +-#line 480 "gram.y" +-{ +- if (yyvsp[0].member->type != COMMAND) { +- sudoerserror(N_("a digest requires a path name")); +- YYERROR; +- } +- /* XXX - yuck */ +- ((struct sudo_command *) yyvsp[0].member->name)->digest = yyvsp[-1].digest; +- yyval.member = yyvsp[0].member; +- } +-break; +-case 43: +-#line 491 "gram.y" +-{ +- yyval.member = yyvsp[0].member; +- yyval.member->negated = false; +- } +-break; +-case 44: +-#line 495 "gram.y" +-{ +- yyval.member = yyvsp[0].member; +- yyval.member->negated = true; +- } +-break; +-case 45: +-#line 501 "gram.y" +-{ +- yyval.string = yyvsp[0].string; +- } +-break; +-case 46: +-#line 506 "gram.y" +-{ +- yyval.string = yyvsp[0].string; +- } +-break; +-case 47: +-#line 510 "gram.y" +-{ +- yyval.string = yyvsp[0].string; +- } +-break; +-case 48: +-#line 515 "gram.y" +-{ +- yyval.string = yyvsp[0].string; +- } +-break; +-case 49: +-#line 520 "gram.y" +-{ +- yyval.string = yyvsp[0].string; +- } +-break; +-case 50: +-#line 525 "gram.y" +-{ +- yyval.string = yyvsp[0].string; +- } +-break; +-case 51: +-#line 529 "gram.y" +-{ +- yyval.string = yyvsp[0].string; +- } +-break; +-case 52: +-#line 534 "gram.y" +-{ +- yyval.runas = NULL; +- } +-break; +-case 53: +-#line 537 "gram.y" +-{ +- yyval.runas = yyvsp[-1].runas; +- } +-break; +-case 54: +-#line 542 "gram.y" +-{ +- yyval.runas = calloc(1, sizeof(struct runascontainer)); +- if (yyval.runas != NULL) { +- yyval.runas->runasusers = new_member(NULL, MYSELF); +- /* $$->runasgroups = NULL; */ +- if (yyval.runas->runasusers == NULL) { +- free(yyval.runas); +- yyval.runas = NULL; +- } +- } +- if (yyval.runas == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 55: +-#line 557 "gram.y" +-{ +- yyval.runas = calloc(1, sizeof(struct runascontainer)); +- if (yyval.runas == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- yyval.runas->runasusers = yyvsp[0].member; +- /* $$->runasgroups = NULL; */ +- } +-break; +-case 56: +-#line 566 "gram.y" +-{ +- yyval.runas = calloc(1, sizeof(struct runascontainer)); +- if (yyval.runas == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- yyval.runas->runasusers = yyvsp[-2].member; +- yyval.runas->runasgroups = yyvsp[0].member; +- } +-break; +-case 57: +-#line 575 "gram.y" +-{ +- yyval.runas = calloc(1, sizeof(struct runascontainer)); +- if (yyval.runas == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- /* $$->runasusers = NULL; */ +- yyval.runas->runasgroups = yyvsp[0].member; +- } +-break; +-case 58: +-#line 584 "gram.y" +-{ +- yyval.runas = calloc(1, sizeof(struct runascontainer)); +- if (yyval.runas != NULL) { +- yyval.runas->runasusers = new_member(NULL, MYSELF); +- /* $$->runasgroups = NULL; */ +- if (yyval.runas->runasusers == NULL) { +- free(yyval.runas); +- yyval.runas = NULL; +- } +- } +- if (yyval.runas == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 59: +-#line 601 "gram.y" +-{ +- init_options(&yyval.options); +- } +-break; +-case 60: +-#line 604 "gram.y" +-{ +- yyval.options.notbefore = parse_gentime(yyvsp[0].string); +- free(yyvsp[0].string); +- if (yyval.options.notbefore == -1) { +- sudoerserror(N_("invalid notbefore value")); +- YYERROR; +- } +- } +-break; +-case 61: +-#line 612 "gram.y" +-{ +- yyval.options.notafter = parse_gentime(yyvsp[0].string); +- free(yyvsp[0].string); +- if (yyval.options.notafter == -1) { +- sudoerserror(N_("invalid notafter value")); +- YYERROR; +- } +- } +-break; +-case 62: +-#line 620 "gram.y" +-{ +- yyval.options.timeout = parse_timeout(yyvsp[0].string); +- free(yyvsp[0].string); +- if (yyval.options.timeout == -1) { +- if (errno == ERANGE) +- sudoerserror(N_("timeout value too large")); +- else +- sudoerserror(N_("invalid timeout value")); +- YYERROR; +- } +- } +-break; +-case 63: +-#line 631 "gram.y" +-{ +-#ifdef HAVE_SELINUX +- free(yyval.options.role); +- yyval.options.role = yyvsp[0].string; +-#endif +- } +-break; +-case 64: +-#line 637 "gram.y" +-{ +-#ifdef HAVE_SELINUX +- free(yyval.options.type); +- yyval.options.type = yyvsp[0].string; +-#endif +- } +-break; +-case 65: +-#line 643 "gram.y" +-{ +-#ifdef HAVE_PRIV_SET +- free(yyval.options.privs); +- yyval.options.privs = yyvsp[0].string; +-#endif +- } +-break; +-case 66: +-#line 649 "gram.y" +-{ +-#ifdef HAVE_PRIV_SET +- free(yyval.options.limitprivs); +- yyval.options.limitprivs = yyvsp[0].string; +-#endif +- } +-break; +-case 67: +-#line 657 "gram.y" +-{ +- TAGS_INIT(yyval.tag); +- } +-break; +-case 68: +-#line 660 "gram.y" +-{ +- yyval.tag.nopasswd = true; +- } +-break; +-case 69: +-#line 663 "gram.y" +-{ +- yyval.tag.nopasswd = false; +- } +-break; +-case 70: +-#line 666 "gram.y" +-{ +- yyval.tag.noexec = true; +- } +-break; +-case 71: +-#line 669 "gram.y" +-{ +- yyval.tag.noexec = false; +- } +-break; +-case 72: +-#line 672 "gram.y" +-{ +- yyval.tag.setenv = true; +- } +-break; +-case 73: +-#line 675 "gram.y" +-{ +- yyval.tag.setenv = false; +- } +-break; +-case 74: +-#line 678 "gram.y" +-{ +- yyval.tag.log_input = true; +- } +-break; +-case 75: +-#line 681 "gram.y" +-{ +- yyval.tag.log_input = false; +- } +-break; +-case 76: +-#line 684 "gram.y" +-{ +- yyval.tag.log_output = true; +- } +-break; +-case 77: +-#line 687 "gram.y" +-{ +- yyval.tag.log_output = false; +- } +-break; +-case 78: +-#line 690 "gram.y" +-{ +- yyval.tag.follow = true; +- } +-break; +-case 79: +-#line 693 "gram.y" +-{ +- yyval.tag.follow = false; +- } +-break; +-case 80: +-#line 696 "gram.y" +-{ +- yyval.tag.send_mail = true; +- } +-break; +-case 81: +-#line 699 "gram.y" +-{ +- yyval.tag.send_mail = false; +- } +-break; +-case 82: +-#line 704 "gram.y" +-{ +- yyval.member = new_member(NULL, ALL); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 83: +-#line 711 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, ALIAS); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 84: +-#line 718 "gram.y" +-{ +- struct sudo_command *c = calloc(1, sizeof(*c)); +- if (c == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- c->cmnd = yyvsp[0].command.cmnd; +- c->args = yyvsp[0].command.args; +- yyval.member = new_member((char *)c, COMMAND); +- if (yyval.member == NULL) { +- free(c); +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 87: +-#line 739 "gram.y" +-{ +- const char *s; +- s = alias_add(&parsed_policy, yyvsp[-2].string, HOSTALIAS, +- sudoers, this_lineno, yyvsp[0].member); +- if (s != NULL) { +- sudoerserror(s); +- YYERROR; +- } +- } +-break; +-case 89: +-#line 751 "gram.y" +-{ +- HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); +- yyval.member = yyvsp[-2].member; +- } +-break; +-case 92: +-#line 761 "gram.y" +-{ +- const char *s; +- s = alias_add(&parsed_policy, yyvsp[-2].string, CMNDALIAS, +- sudoers, this_lineno, yyvsp[0].member); +- if (s != NULL) { +- sudoerserror(s); +- YYERROR; +- } +- } +-break; +-case 94: +-#line 773 "gram.y" +-{ +- HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); +- yyval.member = yyvsp[-2].member; +- } +-break; +-case 97: +-#line 783 "gram.y" +-{ +- const char *s; +- s = alias_add(&parsed_policy, yyvsp[-2].string, RUNASALIAS, +- sudoers, this_lineno, yyvsp[0].member); +- if (s != NULL) { +- sudoerserror(s); +- YYERROR; +- } +- } +-break; +-case 100: +-#line 798 "gram.y" +-{ +- const char *s; +- s = alias_add(&parsed_policy, yyvsp[-2].string, USERALIAS, +- sudoers, this_lineno, yyvsp[0].member); +- if (s != NULL) { +- sudoerserror(s); +- YYERROR; +- } +- } +-break; +-case 102: +-#line 810 "gram.y" +-{ +- HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); +- yyval.member = yyvsp[-2].member; +- } +-break; +-case 103: +-#line 816 "gram.y" +-{ +- yyval.member = yyvsp[0].member; +- yyval.member->negated = false; +- } +-break; +-case 104: +-#line 820 "gram.y" +-{ +- yyval.member = yyvsp[0].member; +- yyval.member->negated = true; +- } +-break; +-case 105: +-#line 826 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, ALIAS); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 106: +-#line 833 "gram.y" +-{ +- yyval.member = new_member(NULL, ALL); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 107: +-#line 840 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, NETGROUP); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 108: +-#line 847 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, USERGROUP); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 109: +-#line 854 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, WORD); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 111: +-#line 864 "gram.y" +-{ +- HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); +- yyval.member = yyvsp[-2].member; +- } +-break; +-case 112: +-#line 870 "gram.y" +-{ +- yyval.member = yyvsp[0].member; +- yyval.member->negated = false; +- } +-break; +-case 113: +-#line 874 "gram.y" +-{ +- yyval.member = yyvsp[0].member; +- yyval.member->negated = true; +- } +-break; +-case 114: +-#line 880 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, ALIAS); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 115: +-#line 887 "gram.y" +-{ +- yyval.member = new_member(NULL, ALL); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-case 116: +-#line 894 "gram.y" +-{ +- yyval.member = new_member(yyvsp[0].string, WORD); +- if (yyval.member == NULL) { +- sudoerserror(N_("unable to allocate memory")); +- YYERROR; +- } +- } +-break; +-#line 2173 "gram.c" +- } +- yyssp -= yym; +- yystate = *yyssp; +- yyvsp -= yym; +- yym = yylhs[yyn]; +- if (yystate == 0 && yym == 0) +- { +-#if YYDEBUG +- if (yydebug) +- printf("%sdebug: after reduction, shifting from state 0 to\ +- state %d\n", YYPREFIX, YYFINAL); +-#endif +- yystate = YYFINAL; +- *++yyssp = YYFINAL; +- *++yyvsp = yyval; +- if (yychar < 0) +- { +- if ((yychar = yylex()) < 0) yychar = 0; +-#if YYDEBUG +- if (yydebug) +- { +- yys = 0; +- if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; +- if (!yys) yys = "illegal-symbol"; +- printf("%sdebug: state %d, reading %d (%s)\n", +- YYPREFIX, YYFINAL, yychar, yys); +- } +-#endif +- } +- if (yychar == 0) goto yyaccept; +- goto yyloop; +- } +- if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && +- yyn <= YYTABLESIZE && yycheck[yyn] == yystate) +- yystate = yytable[yyn]; +- else +- yystate = yydgoto[yym]; +-#if YYDEBUG +- if (yydebug) +- printf("%sdebug: after reduction, shifting from state %d \ +-to state %d\n", YYPREFIX, *yyssp, yystate); +-#endif +- if (yyssp >= yysslim && yygrowstack()) +- { +- goto yyoverflow; +- } +- *++yyssp = yystate; +- *++yyvsp = yyval; +- goto yyloop; +-yyoverflow: +- yyerror("yacc stack overflow"); +-yyabort: +- if (yyss) +- free(yyss); +- if (yyvs) +- free(yyvs); +- yyss = yyssp = NULL; +- yyvs = yyvsp = NULL; +- yystacksize = 0; +- return (1); +-yyaccept: +- if (yyss) +- free(yyss); +- if (yyvs) +- free(yyvs); +- yyss = yyssp = NULL; +- yyvs = yyvsp = NULL; +- yystacksize = 0; +- return (0); +-} +diff --git a/plugins/sudoers/gram.h b/plugins/sudoers/gram.h +deleted file mode 100644 +index c53f97a..0000000 +--- a/plugins/sudoers/gram.h ++++ /dev/null +@@ -1,63 +0,0 @@ +-#define COMMAND 257 +-#define ALIAS 258 +-#define DEFVAR 259 +-#define NTWKADDR 260 +-#define NETGROUP 261 +-#define USERGROUP 262 +-#define WORD 263 +-#define DIGEST 264 +-#define DEFAULTS 265 +-#define DEFAULTS_HOST 266 +-#define DEFAULTS_USER 267 +-#define DEFAULTS_RUNAS 268 +-#define DEFAULTS_CMND 269 +-#define NOPASSWD 270 +-#define PASSWD 271 +-#define NOEXEC 272 +-#define EXEC 273 +-#define SETENV 274 +-#define NOSETENV 275 +-#define LOG_INPUT 276 +-#define NOLOG_INPUT 277 +-#define LOG_OUTPUT 278 +-#define NOLOG_OUTPUT 279 +-#define MAIL 280 +-#define NOMAIL 281 +-#define FOLLOW 282 +-#define NOFOLLOW 283 +-#define ALL 284 +-#define COMMENT 285 +-#define HOSTALIAS 286 +-#define CMNDALIAS 287 +-#define USERALIAS 288 +-#define RUNASALIAS 289 +-#define ERROR 290 +-#define TYPE 291 +-#define ROLE 292 +-#define PRIVS 293 +-#define LIMITPRIVS 294 +-#define CMND_TIMEOUT 295 +-#define NOTBEFORE 296 +-#define NOTAFTER 297 +-#define MYSELF 298 +-#define SHA224_TOK 299 +-#define SHA256_TOK 300 +-#define SHA384_TOK 301 +-#define SHA512_TOK 302 +-#ifndef YYSTYPE_DEFINED +-#define YYSTYPE_DEFINED +-typedef union { +- struct cmndspec *cmndspec; +- struct defaults *defaults; +- struct member *member; +- struct runascontainer *runas; +- struct privilege *privilege; +- struct command_digest *digest; +- struct sudo_command command; +- struct command_options options; +- struct cmndtag tag; +- char *string; +- int tok; +-} YYSTYPE; +-#endif /* YYSTYPE_DEFINED */ +-extern YYSTYPE sudoerslval; +diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y +index 0665ce9..6ad0f04 100644 +--- a/plugins/sudoers/gram.y ++++ b/plugins/sudoers/gram.y +@@ -61,7 +61,9 @@ char *errorfile = NULL; + struct sudoers_parse_tree parsed_policy = { + TAILQ_HEAD_INITIALIZER(parsed_policy.userspecs), + TAILQ_HEAD_INITIALIZER(parsed_policy.defaults), +- NULL /* aliases */ ++ NULL, /* aliases */ ++ NULL, /* lhost */ ++ NULL /* shost */ + }; + + /* +@@ -1244,11 +1246,14 @@ free_userspec(struct userspec *us) + * Initialized a sudoers parse tree. + */ + void +-init_parse_tree(struct sudoers_parse_tree *parse_tree) ++init_parse_tree(struct sudoers_parse_tree *parse_tree, const char *lhost, ++ const char *shost) + { + TAILQ_INIT(&parse_tree->userspecs); + TAILQ_INIT(&parse_tree->defaults); + parse_tree->aliases = NULL; ++ parse_tree->shost = shost; ++ parse_tree->lhost = lhost; + } + + /* +diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c +index bc2baec..fe6cb3c 100644 +--- a/plugins/sudoers/ldap.c ++++ b/plugins/sudoers/ldap.c +@@ -1663,7 +1663,7 @@ sudo_ldap_open(struct sudo_nss *nss) + } + handle->ld = ld; + /* handle->pw = NULL; */ +- init_parse_tree(&handle->parse_tree); ++ init_parse_tree(&handle->parse_tree, NULL, NULL); + nss->handle = handle; + + done: +diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c +index 7c8e9d8..444d654 100644 +--- a/plugins/sudoers/match.c ++++ b/plugins/sudoers/match.c +@@ -99,8 +99,10 @@ int + user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + const struct member *m) + { +- struct alias *a; ++ const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost; ++ const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost; + int matched = UNSPEC; ++ struct alias *a; + debug_decl(user_matches, SUDOERS_DEBUG_MATCH) + + switch (m->type) { +@@ -109,8 +111,8 @@ user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + break; + case NETGROUP: + if (netgr_matches(m->name, +- def_netgroup_tuple ? user_runhost : NULL, +- def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name)) ++ def_netgroup_tuple ? lhost : NULL, ++ def_netgroup_tuple ? shost : NULL, pw->pw_name)) + matched = !m->negated; + break; + case USERGROUP: +@@ -180,11 +182,13 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + const struct member_list *user_list, const struct member_list *group_list, + struct member **matching_user, struct member **matching_group) + { ++ const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost; ++ const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost; ++ int user_matched = UNSPEC; ++ int group_matched = UNSPEC; + struct member *m; + struct alias *a; + int rc; +- int user_matched = UNSPEC; +- int group_matched = UNSPEC; + debug_decl(runaslist_matches, SUDOERS_DEBUG_MATCH) + + if (ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) || !ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED)) { +@@ -202,8 +206,8 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + break; + case NETGROUP: + if (netgr_matches(m->name, +- def_netgroup_tuple ? user_runhost : NULL, +- def_netgroup_tuple ? user_srunhost : NULL, ++ def_netgroup_tuple ? lhost : NULL, ++ def_netgroup_tuple ? shost : NULL, + runas_pw->pw_name)) + user_matched = !m->negated; + break; +@@ -336,7 +340,10 @@ int + hostlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + const struct member_list *list) + { +- return hostlist_matches_int(parse_tree, pw, user_runhost, user_srunhost, list); ++ const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost; ++ const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost; ++ ++ return hostlist_matches_int(parse_tree, pw, lhost, shost, list); + } + + /* +diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h +index 7dcbdca..b17761a 100644 +--- a/plugins/sudoers/parse.h ++++ b/plugins/sudoers/parse.h +@@ -265,6 +265,7 @@ struct sudoers_parse_tree { + struct userspec_list userspecs; + struct defaults_list defaults; + struct rbtree *aliases; ++ const char *shost, *lhost; + }; + + /* alias.c */ +@@ -290,7 +291,7 @@ void free_userspec(struct userspec *us); + void free_userspecs(struct userspec_list *usl); + void free_default(struct defaults *def, struct member_list **binding); + void free_defaults(struct defaults_list *defs); +-void init_parse_tree(struct sudoers_parse_tree *parse_tree); ++void init_parse_tree(struct sudoers_parse_tree *parse_tree, const char *shost, const char *lhost); + void free_parse_tree(struct sudoers_parse_tree *parse_tree); + void reparent_parse_tree(struct sudoers_parse_tree *new_tree); + +diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c +index 085549f..fa9a930 100644 +--- a/plugins/sudoers/sssd.c ++++ b/plugins/sudoers/sssd.c +@@ -552,7 +552,6 @@ sudo_sss_open(struct sudo_nss *nss) + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + debug_return_int(ENOMEM); + } +- init_parse_tree(&handle->parse_tree); + + /* Load symbols */ + handle->ssslib = sudo_dso_load(path, SUDO_DSO_LAZY); +@@ -610,8 +609,6 @@ sudo_sss_open(struct sudo_nss *nss) + debug_return_int(EFAULT); + } + +- nss->handle = handle; +- + /* + * If runhost is the same as the local host, check for ipa_hostname + * in sssd.conf and use it in preference to user_runhost. +@@ -623,6 +620,10 @@ sudo_sss_open(struct sudo_nss *nss) + } + } + ++ /* The "parse tree" contains userspecs, defaults, aliases and hostnames. */ ++ init_parse_tree(&handle->parse_tree, handle->ipa_host, handle->ipa_shost); ++ nss->handle = handle; ++ + sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle); + + debug_return_int(0); diff --git a/debian/patches/0017-Escape-control-characters-in-log-messages-and-sudore.patch b/debian/patches/0017-Escape-control-characters-in-log-messages-and-sudore.patch new file mode 100644 index 0000000..ebd2c6e --- /dev/null +++ b/debian/patches/0017-Escape-control-characters-in-log-messages-and-sudore.patch @@ -0,0 +1,663 @@ +From: "Todd C. Miller" <Todd.Miller@sudo.ws> +Date: Wed, 18 Jan 2023 08:21:34 -0700 +Subject: Escape control characters in log messages and "sudoreplay -l" + output. + +The log message contains user-controlled strings that could +include things like terminal control characters. +Space characters in the command path are now also escaped. + +Command line arguments that contain spaces are surrounded with +single quotes and any literal single quote or backslash characters +are escaped with a backslash. This makes it possible to distinguish +multiple command line arguments from a single argument that contains +spaces. + +Issue found by Matthieu Barjole and Victor Cutillas of Synacktiv +(https://synacktiv.com). + +origin: https://github.com/sudo-project/sudo/commit/334daf92b31b79ce68ed75e2ee14fca265f029ca +bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2023-28486 +bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2023-28487 +bug-ubuntu-security: https://people.canonical.com/~ubuntu-security/cve/CVE-2023-28487 +bug-ubuntu-security: https://people.canonical.com/~ubuntu-security/cve/CVE-2023-28486 +--- + doc/sudoers.man.in | 33 +++++++--- + doc/sudoers.mdoc.in | 28 +++++++-- + doc/sudoreplay.man.in | 9 +++ + doc/sudoreplay.mdoc.in | 10 +++ + include/sudo_compat.h | 6 ++ + include/sudo_lbuf.h | 7 +++ + lib/util/lbuf.c | 106 ++++++++++++++++++++++++++++++++ + lib/util/util.exp.in | 1 + + plugins/sudoers/logging.c | 141 +++++++++++-------------------------------- + plugins/sudoers/sudoreplay.c | 42 ++++++++++--- + 10 files changed, 254 insertions(+), 129 deletions(-) + +diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in +index e2470b5..46bf8ea 100644 +--- a/doc/sudoers.man.in ++++ b/doc/sudoers.man.in +@@ -4419,6 +4419,19 @@ can log events using either + syslog(3) + or a simple log file. + The log format is almost identical in both cases. ++Any control characters present in the log data are formatted in octal ++with a leading ++\(oq#\(cq ++character. ++For example, a horizontal tab is stored as ++\(oq#011\(cq ++and an embedded carriage return is stored as ++\(oq#015\(cq. ++In addition, space characters in the command path are stored as ++\(oq#040\(cq. ++Literal single quotes and backslash characters ++(\(oq\e\(cq) ++in command line arguments are escaped with a backslash. + .SS "Accepted command log entries" + Commands that sudo runs are logged using the following format (split + into multiple lines for readability): +@@ -4499,7 +4512,7 @@ A list of environment variables specified on the command line, + if specified. + .TP 14n + command +-The actual command that was executed. ++The actual command that was executed, including any command line arguments. + .PP + Messages are logged using the locale specified by + \fIsudoers_locale\fR, +@@ -4735,17 +4748,21 @@ with a few important differences: + 1.\& + The + \fIprogname\fR +-and +-\fIhostname\fR +-fields are not present. ++field is not present. + .TP 5n + 2.\& +-If the +-\fIlog_year\fR +-option is enabled, +-the date will also include the year. ++The ++\fIhostname\fR ++is only logged if the ++\fIlog_host\fR ++option is enabled. + .TP 5n + 3.\& ++The date does not include the year unless the ++\fIlog_year\fR ++option is enabled. ++.TP 5n ++4.\& + Lines that are longer than + \fIloglinelen\fR + characters (80 by default) are word-wrapped and continued on the +diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in +index 2053b5d..208f9d3 100644 +--- a/doc/sudoers.mdoc.in ++++ b/doc/sudoers.mdoc.in +@@ -4120,6 +4120,19 @@ can log events using either + .Xr syslog 3 + or a simple log file. + The log format is almost identical in both cases. ++Any control characters present in the log data are formatted in octal ++with a leading ++.Ql # ++character. ++For example, a horizontal tab is stored as ++.Ql #011 ++and an embedded carriage return is stored as ++.Ql #015 . ++In addition, space characters in the command path are stored as ++.Ql #040 . ++Literal single quotes and backslash characters ++.Pq Ql \e ++in command line arguments are escaped with a backslash. + .Ss Accepted command log entries + Commands that sudo runs are logged using the following format (split + into multiple lines for readability): +@@ -4187,7 +4200,7 @@ option is enabled. + A list of environment variables specified on the command line, + if specified. + .It command +-The actual command that was executed. ++The actual command that was executed, including any command line arguments. + .El + .Pp + Messages are logged using the locale specified by +@@ -4409,14 +4422,17 @@ with a few important differences: + .It + The + .Em progname +-and ++field is not present. ++.It ++The + .Em hostname +-fields are not present. ++is only logged if the ++.Em log_host ++option is enabled. + .It +-If the ++The date does not include the year unless the + .Em log_year +-option is enabled, +-the date will also include the year. ++option is enabled. + .It + Lines that are longer than + .Em loglinelen +diff --git a/doc/sudoreplay.man.in b/doc/sudoreplay.man.in +index 7bb2da6..6e28807 100644 +--- a/doc/sudoreplay.man.in ++++ b/doc/sudoreplay.man.in +@@ -138,6 +138,15 @@ In this mode, + will list available sessions in a format similar to the + \fBsudo\fR + log file format, sorted by file name (or sequence number). ++Any control characters present in the log data are formated in octal ++with a leading ++\(oq#\(cq ++character. ++For example, a horizontal tab is displayed as ++\(oq#011\(cq ++and an embedded carriage return is displayed as ++\(oq#015\(cq. ++.sp + If a + \fIsearch expression\fR + is specified, it will be used to restrict the IDs that are displayed. +diff --git a/doc/sudoreplay.mdoc.in b/doc/sudoreplay.mdoc.in +index 4eefaf6..91ca3af 100644 +--- a/doc/sudoreplay.mdoc.in ++++ b/doc/sudoreplay.mdoc.in +@@ -131,6 +131,16 @@ In this mode, + will list available sessions in a format similar to the + .Nm sudo + log file format, sorted by file name (or sequence number). ++Any control characters present in the log data are formatted in octal ++with a leading ++.Ql # ++character. ++For example, a horizontal tab is displayed as ++.Ql #011 ++and an embedded carriage return is displayed as ++.Ql #015 . ++Space characters in the command name and arguments are also formatted in octal. ++.Pp + If a + .Ar search expression + is specified, it will be used to restrict the IDs that are displayed. +diff --git a/include/sudo_compat.h b/include/sudo_compat.h +index 5c32840..c4366c0 100644 +--- a/include/sudo_compat.h ++++ b/include/sudo_compat.h +@@ -77,6 +77,12 @@ + # endif + #endif + ++#ifdef HAVE_FALLTHROUGH_ATTRIBUTE ++# define FALLTHROUGH __attribute__((__fallthrough__)) ++#else ++# define FALLTHROUGH do { } while (0) ++#endif ++ + /* + * Given the pointer x to the member m of the struct s, return + * a pointer to the containing structure. +diff --git a/include/sudo_lbuf.h b/include/sudo_lbuf.h +index 8e07063..c2c1fa1 100644 +--- a/include/sudo_lbuf.h ++++ b/include/sudo_lbuf.h +@@ -34,9 +34,15 @@ struct sudo_lbuf { + + typedef int (*sudo_lbuf_output_t)(const char *); + ++/* Flags for sudo_lbuf_append_esc() */ ++#define LBUF_ESC_CNTRL 0x01 ++#define LBUF_ESC_BLANK 0x02 ++#define LBUF_ESC_QUOTE 0x04 ++ + __dso_public void sudo_lbuf_init_v1(struct sudo_lbuf *lbuf, sudo_lbuf_output_t output, int indent, const char *continuation, int cols); + __dso_public void sudo_lbuf_destroy_v1(struct sudo_lbuf *lbuf); + __dso_public bool sudo_lbuf_append_v1(struct sudo_lbuf *lbuf, const char *fmt, ...) __printflike(2, 3); ++__dso_public bool sudo_lbuf_append_esc_v1(struct sudo_lbuf *lbuf, int flags, const char *fmt, ...) __printflike(3, 4); + __dso_public bool sudo_lbuf_append_quoted_v1(struct sudo_lbuf *lbuf, const char *set, const char *fmt, ...) __printflike(3, 4); + __dso_public void sudo_lbuf_print_v1(struct sudo_lbuf *lbuf); + __dso_public bool sudo_lbuf_error_v1(struct sudo_lbuf *lbuf); +@@ -45,6 +51,7 @@ __dso_public void sudo_lbuf_clearerr_v1(struct sudo_lbuf *lbuf); + #define sudo_lbuf_init(_a, _b, _c, _d, _e) sudo_lbuf_init_v1((_a), (_b), (_c), (_d), (_e)) + #define sudo_lbuf_destroy(_a) sudo_lbuf_destroy_v1((_a)) + #define sudo_lbuf_append sudo_lbuf_append_v1 ++#define sudo_lbuf_append_esc sudo_lbuf_append_esc_v1 + #define sudo_lbuf_append_quoted sudo_lbuf_append_quoted_v1 + #define sudo_lbuf_print(_a) sudo_lbuf_print_v1((_a)) + #define sudo_lbuf_error(_a) sudo_lbuf_error_v1((_a)) +diff --git a/lib/util/lbuf.c b/lib/util/lbuf.c +index 5e48258..39d4ddd 100644 +--- a/lib/util/lbuf.c ++++ b/lib/util/lbuf.c +@@ -90,6 +90,112 @@ sudo_lbuf_expand(struct sudo_lbuf *lbuf, int extra) + debug_return_bool(true); + } + ++/* ++ * Escape a character in octal form (#0n) and store it as a string ++ * in buf, which must have at least 6 bytes available. ++ * Returns the length of buf, not counting the terminating NUL byte. ++ */ ++static int ++escape(unsigned char ch, char *buf) ++{ ++ const int len = ch < 0100 ? (ch < 010 ? 3 : 4) : 5; ++ ++ /* Work backwards from the least significant digit to most significant. */ ++ switch (len) { ++ case 5: ++ buf[4] = (ch & 7) + '0'; ++ ch >>= 3; ++ FALLTHROUGH; ++ case 4: ++ buf[3] = (ch & 7) + '0'; ++ ch >>= 3; ++ FALLTHROUGH; ++ case 3: ++ buf[2] = (ch & 7) + '0'; ++ buf[1] = '0'; ++ buf[0] = '#'; ++ break; ++ } ++ buf[len] = '\0'; ++ ++ return len; ++} ++ ++/* ++ * Parse the format and append strings, only %s and %% escapes are supported. ++ * Any non-printable characters are escaped in octal as #0nn. ++ */ ++bool ++sudo_lbuf_append_esc_v1(struct sudo_lbuf *lbuf, int flags, const char *fmt, ...) ++{ ++ unsigned int saved_len = lbuf->len; ++ bool ret = false; ++ const char *s; ++ va_list ap; ++ debug_decl(sudo_lbuf_append_esc, SUDO_DEBUG_UTIL); ++ ++ if (sudo_lbuf_error(lbuf)) ++ debug_return_bool(false); ++ ++#define should_escape(ch) \ ++ ((ISSET(flags, LBUF_ESC_CNTRL) && iscntrl((unsigned char)ch)) || \ ++ (ISSET(flags, LBUF_ESC_BLANK) && isblank((unsigned char)ch))) ++#define should_quote(ch) \ ++ (ISSET(flags, LBUF_ESC_QUOTE) && (ch == '\'' || ch == '\\')) ++ ++ va_start(ap, fmt); ++ while (*fmt != '\0') { ++ if (fmt[0] == '%' && fmt[1] == 's') { ++ if ((s = va_arg(ap, char *)) == NULL) ++ s = "(NULL)"; ++ while (*s != '\0') { ++ if (should_escape(*s)) { ++ if (!sudo_lbuf_expand(lbuf, sizeof("#0177") - 1)) ++ goto done; ++ lbuf->len += escape(*s++, lbuf->buf + lbuf->len); ++ continue; ++ } ++ if (should_quote(*s)) { ++ if (!sudo_lbuf_expand(lbuf, 2)) ++ goto done; ++ lbuf->buf[lbuf->len++] = '\\'; ++ lbuf->buf[lbuf->len++] = *s++; ++ continue; ++ } ++ if (!sudo_lbuf_expand(lbuf, 1)) ++ goto done; ++ lbuf->buf[lbuf->len++] = *s++; ++ } ++ fmt += 2; ++ continue; ++ } ++ if (should_escape(*fmt)) { ++ if (!sudo_lbuf_expand(lbuf, sizeof("#0177") - 1)) ++ goto done; ++ if (*fmt == '\'') { ++ lbuf->buf[lbuf->len++] = '\\'; ++ lbuf->buf[lbuf->len++] = *fmt++; ++ } else { ++ lbuf->len += escape(*fmt++, lbuf->buf + lbuf->len); ++ } ++ continue; ++ } ++ if (!sudo_lbuf_expand(lbuf, 1)) ++ goto done; ++ lbuf->buf[lbuf->len++] = *fmt++; ++ } ++ ret = true; ++ ++done: ++ if (!ret) ++ lbuf->len = saved_len; ++ if (lbuf->size != 0) ++ lbuf->buf[lbuf->len] = '\0'; ++ va_end(ap); ++ ++ debug_return_bool(ret); ++} ++ + /* + * Parse the format and append strings, only %s and %% escapes are supported. + * Any characters in set are quoted with a backslash. +diff --git a/lib/util/util.exp.in b/lib/util/util.exp.in +index 510c34c..b683d84 100644 +--- a/lib/util/util.exp.in ++++ b/lib/util/util.exp.in +@@ -80,6 +80,7 @@ sudo_gethostname_v1 + sudo_gettime_awake_v1 + sudo_gettime_mono_v1 + sudo_gettime_real_v1 ++sudo_lbuf_append_esc_v1 + sudo_lbuf_append_quoted_v1 + sudo_lbuf_append_v1 + sudo_lbuf_clearerr_v1 +diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c +index 9562609..bb31861 100644 +--- a/plugins/sudoers/logging.c ++++ b/plugins/sudoers/logging.c +@@ -56,6 +56,7 @@ + #include <syslog.h> + + #include "sudoers.h" ++#include "sudo_lbuf.h" + + #ifndef HAVE_GETADDRINFO + # include "compat/getaddrinfo.h" +@@ -877,14 +878,6 @@ should_mail(int status) + (def_mail_no_perms && !ISSET(status, VALIDATE_SUCCESS))); + } + +-#define LL_TTY_STR "TTY=" +-#define LL_CWD_STR "PWD=" /* XXX - should be CWD= */ +-#define LL_USER_STR "USER=" +-#define LL_GROUP_STR "GROUP=" +-#define LL_ENV_STR "ENV=" +-#define LL_CMND_STR "COMMAND=" +-#define LL_TSID_STR "TSID=" +- + #define IS_SESSID(s) ( \ + isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \ + (s)[2] == '/' && \ +@@ -899,14 +892,16 @@ should_mail(int status) + static char * + new_logline(const char *message, const char *errstr) + { +- char *line = NULL, *evstr = NULL; + #ifndef SUDOERS_NO_SEQ + char sessid[7]; + #endif + const char *tsid = NULL; +- size_t len = 0; ++ struct sudo_lbuf lbuf; ++ int i; + debug_decl(new_logline, SUDOERS_DEBUG_LOGGING) + ++ sudo_lbuf_init(&lbuf, NULL, 0, NULL, 0); ++ + #ifndef SUDOERS_NO_SEQ + /* A TSID may be a sudoers-style session ID or a free-form string. */ + if (sudo_user.iolog_file != NULL) { +@@ -926,119 +921,55 @@ new_logline(const char *message, const char *errstr) + #endif + + /* +- * Compute line length ++ * Format the log line as an lbuf, escaping control characters in ++ * octal form (#0nn). Error checking (ENOMEM) is done at the end. + */ +- if (message != NULL) +- len += strlen(message) + 3; +- if (errstr != NULL) +- len += strlen(errstr) + 3; +- len += sizeof(LL_TTY_STR) + 2 + strlen(user_tty); +- len += sizeof(LL_CWD_STR) + 2 + strlen(user_cwd); +- if (runas_pw != NULL) +- len += sizeof(LL_USER_STR) + 2 + strlen(runas_pw->pw_name); +- if (runas_gr != NULL) +- len += sizeof(LL_GROUP_STR) + 2 + strlen(runas_gr->gr_name); +- if (tsid != NULL) +- len += sizeof(LL_TSID_STR) + 2 + strlen(tsid); +- if (sudo_user.env_vars != NULL) { +- size_t evlen = 0; +- char * const *ep; +- +- for (ep = sudo_user.env_vars; *ep != NULL; ep++) +- evlen += strlen(*ep) + 1; +- if (evlen != 0) { +- if ((evstr = malloc(evlen)) == NULL) +- goto oom; +- evstr[0] = '\0'; +- for (ep = sudo_user.env_vars; *ep != NULL; ep++) { +- strlcat(evstr, *ep, evlen); +- strlcat(evstr, " ", evlen); /* NOTE: last one will fail */ +- } +- len += sizeof(LL_ENV_STR) + 2 + evlen; +- } +- } +- if (user_cmnd != NULL) { +- /* Note: we log "sudo -l command arg ..." as "list command arg ..." */ +- len += sizeof(LL_CMND_STR) - 1 + strlen(user_cmnd); +- if (ISSET(sudo_mode, MODE_CHECK)) +- len += sizeof("list ") - 1; +- if (user_args != NULL) +- len += strlen(user_args) + 1; +- } +- +- /* +- * Allocate and build up the line. +- */ +- if ((line = malloc(++len)) == NULL) +- goto oom; +- line[0] = '\0'; + + if (message != NULL) { +- if (strlcat(line, message, len) >= len || +- strlcat(line, errstr ? " : " : " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s", message, ++ errstr ? " : " : " ; "); + } + if (errstr != NULL) { +- if (strlcat(line, errstr, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s ; ", errstr); ++ } ++ if (user_tty != NULL) { ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "TTY=%s ; ", user_tty); ++ } ++ if (user_cwd != NULL) { ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "PWD=%s ; ", user_cwd); + } +- if (strlcat(line, LL_TTY_STR, len) >= len || +- strlcat(line, user_tty, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; +- if (strlcat(line, LL_CWD_STR, len) >= len || +- strlcat(line, user_cwd, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; + if (runas_pw != NULL) { +- if (strlcat(line, LL_USER_STR, len) >= len || +- strlcat(line, runas_pw->pw_name, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "USER=%s ; ", ++ runas_pw->pw_name); + } + if (runas_gr != NULL) { +- if (strlcat(line, LL_GROUP_STR, len) >= len || +- strlcat(line, runas_gr->gr_name, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "GROUP=%s ; ", ++ runas_gr->gr_name); + } + if (tsid != NULL) { +- if (strlcat(line, LL_TSID_STR, len) >= len || +- strlcat(line, tsid, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "TSID=%s ; ", tsid); + } +- if (evstr != NULL) { +- if (strlcat(line, LL_ENV_STR, len) >= len || +- strlcat(line, evstr, len) >= len || +- strlcat(line, " ; ", len) >= len) +- goto toobig; +- free(evstr); +- evstr = NULL; ++ if (sudo_user.env_vars != NULL) { ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "ENV=%s", sudo_user.env_vars[0]); ++ for (i = 1; sudo_user.env_vars[i] != NULL; i++) { ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " %s", ++ sudo_user.env_vars[i]); ++ } + } + if (user_cmnd != NULL) { +- if (strlcat(line, LL_CMND_STR, len) >= len) +- goto toobig; +- if (ISSET(sudo_mode, MODE_CHECK) && strlcat(line, "list ", len) >= len) +- goto toobig; +- if (strlcat(line, user_cmnd, len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK, ++ "COMMAND=%s", user_cmnd); + if (user_args != NULL) { +- if (strlcat(line, " ", len) >= len || +- strlcat(line, user_args, len) >= len) +- goto toobig; ++ sudo_lbuf_append_esc(&lbuf, ++ LBUF_ESC_CNTRL|LBUF_ESC_QUOTE, ++ " %s", user_args); + } + } + +- debug_return_str(line); +-oom: +- free(evstr); ++ if (!sudo_lbuf_error(&lbuf)) ++ debug_return_str(lbuf.buf); ++ ++ sudo_lbuf_destroy(&lbuf); + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + debug_return_str(NULL); +-toobig: +- free(evstr); +- free(line); +- sudo_warnx(U_("internal error, %s overflow"), __func__); +- debug_return_str(NULL); + } +diff --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c +index a447cd0..01bc53a 100644 +--- a/plugins/sudoers/sudoreplay.c ++++ b/plugins/sudoers/sudoreplay.c +@@ -69,6 +69,7 @@ + #include "sudo_conf.h" + #include "sudo_debug.h" + #include "sudo_event.h" ++#include "sudo_lbuf.h" + #include "sudo_util.h" + + #ifdef HAVE_GETOPT_LONG +@@ -1347,7 +1348,8 @@ match_expr(struct search_node_list *head, struct log_info *log, bool last_match) + } + + static int +-list_session(char *logfile, regex_t *re, const char *user, const char *tty) ++list_session(struct sudo_lbuf *lbuf, char *logfile, regex_t *re, ++ const char *user, const char *tty) + { + char idbuf[7], *idstr, *cp; + const char *timestr; +@@ -1380,16 +1382,32 @@ list_session(char *logfile, regex_t *re, const char *user, const char *tty) + } + /* XXX - print rows + cols? */ + timestr = get_timestr(li->tstamp, 1); +- printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ", +- timestr ? timestr : "invalid date", +- li->user, li->tty, li->cwd, li->runas_user); +- if (li->runas_group) +- printf("GROUP=%s ; ", li->runas_group); +- printf("TSID=%s ; COMMAND=%s\n", idstr, li->cmd); +- +- ret = 0; ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "%s : %s : ", ++ timestr ? timestr : "invalid date", li->user); ++ if (li->tty != NULL) { ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "TTY=%s ; ", ++ li->tty); ++ } ++ if (li->cwd != NULL) { ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "CWD=%s ; ", ++ li->cwd); ++ } ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "USER=%s ; ", li->runas_user); ++ if (li->runas_group != NULL) { ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "GROUP=%s ; ", ++ li->runas_group); ++ } ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "TSID=%s ; ", idstr); ++ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "COMMAND=%s", ++ li->cmd); + ++ if (!sudo_lbuf_error(lbuf)) { ++ puts(lbuf->buf); ++ ret = 0; ++ } + done: ++ lbuf->error = 0; ++ lbuf->len = 0; + free_log_info(li); + debug_return_int(ret); + } +@@ -1409,6 +1427,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty) + DIR *d; + struct dirent *dp; + struct stat sb; ++ struct sudo_lbuf lbuf; + size_t sdlen, sessions_len = 0, sessions_size = 0; + unsigned int i; + int len; +@@ -1420,6 +1439,8 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty) + #endif + debug_decl(find_sessions, SUDO_DEBUG_UTIL) + ++ sudo_lbuf_init(&lbuf, NULL, 0, NULL, 0); ++ + d = opendir(dir); + if (d == NULL) + sudo_fatal(U_("unable to open %s"), dir); +@@ -1479,7 +1500,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty) + + /* Check for dir with a log file. */ + if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) { +- list_session(pathbuf, re, user, tty); ++ list_session(&lbuf, pathbuf, re, user, tty); + } else { + /* Strip off "/log" and recurse if a dir. */ + pathbuf[sdlen + len - 4] = '\0'; +@@ -1490,6 +1511,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty) + } + free(sessions); + } ++ sudo_lbuf_destroy(&lbuf); + + debug_return_int(0); + } diff --git a/debian/patches/0018-Add-missing-separator-between-environment-variables-.patch b/debian/patches/0018-Add-missing-separator-between-environment-variables-.patch new file mode 100644 index 0000000..ee38855 --- /dev/null +++ b/debian/patches/0018-Add-missing-separator-between-environment-variables-.patch @@ -0,0 +1,24 @@ +From: "Todd C. Miller" <Todd.Miller@sudo.ws> +Date: Mon, 13 Mar 2023 08:04:32 -0600 +Subject: Add missing " ; + " separator between environment variables and command. + +This is a regression introduced in sudo 1.9.13. GitHub issue #254. + +bug: https://github.com/sudo-project/sudo/issues/254 +--- + plugins/sudoers/logging.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c +index bb31861..65ee04e 100644 +--- a/plugins/sudoers/logging.c ++++ b/plugins/sudoers/logging.c +@@ -955,6 +955,7 @@ new_logline(const char *message, const char *errstr) + sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " %s", + sudo_user.env_vars[i]); + } ++ sudo_lbuf_append(&lbuf, " ; "); + } + if (user_cmnd != NULL) { + sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK, diff --git a/debian/patches/series b/debian/patches/series index 286e759..43c82cc 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -11,5 +11,7 @@ Fix-potential-buffer-overflow-when-unescaping-backsl.patch Fix-the-memset-offset-when-converting-a-v1-timestamp.patch Don-t-assume-that-argv-is-allocated-as-a-single-flat.patch CVE-2021-23239.patch - CVE-2023-22809.patch +0016-CVE-2023-7090-Fix-special-handling-of-ipa_hostname-t.patch +0017-Escape-control-characters-in-log-messages-and-sudore.patch +0018-Add-missing-separator-between-environment-variables-.patch diff --git a/debian/rules b/debian/rules index 2b5375b..80f329d 100755 --- a/debian/rules +++ b/debian/rules @@ -28,12 +28,13 @@ configure-stamp: reconf-stamp # simple version NROFFPROG=/usr/bin/nroff CFLAGS="$(CFLAGS)" \ - CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ + CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" devdir=. \ dh_auto_configure --builddirectory=build-simple -- \ -v \ --with-all-insults \ --with-pam \ --with-fqdn \ + --with-devel=yes \ --with-logging=syslog \ --with-logfac=authpriv \ --with-env-editor \ @@ -56,6 +57,7 @@ configure-stamp: reconf-stamp -v \ --with-all-insults \ --with-pam \ + --with-devel=yes \ --with-ldap \ --with-fqdn \ --with-logging=syslog \ @@ -82,12 +84,11 @@ build-arch: build-stamp build-indep: build-stamp build-stamp: configure-stamp dh_testdir - - $(MAKE) -C build-simple - $(MAKE) -C build-ldap + cd build-simple && $(MAKE) + cd build-ldap && $(MAKE) ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - $(MAKE) -C build-simple check + cd build-simple && $(MAKE) check endif touch build-stamp @@ -98,6 +99,7 @@ clean: rm -f configure-stamp build-stamp rm -rf build-simple build-ldap rm -f config.cache + rm -f plugins/sudoers/gram.c plugins/sudoers/gram.h dh_clean install: build-stamp diff --git a/debian/.gitlab-ci.yml b/debian/salsa-ci.yml index efd58ac..efd58ac 100644 --- a/debian/.gitlab-ci.yml +++ b/debian/salsa-ci.yml diff --git a/debian/tests/01-getroot b/debian/tests/01-getroot new file mode 100755 index 0000000..4edef3e --- /dev/null +++ b/debian/tests/01-getroot @@ -0,0 +1,100 @@ +#!/bin/sh + +set -e + +# set a root password so that we can later replace sudo with sudo-ldap +# see #1001858 +passwd=$(getent shadow root|cut -f2 -d:) +passwd1=$(echo "$passwd" |cut -c1) +# Note: we do need the 'xfoo' syntax here, since POSIX special-cases +# the $passwd value '!' as negation. +if [ "x$passwd" = "x*" ] || [ "x$passwd1" = "x!" ]; then + echo "root:rootpassword" | chpasswd +fi + +TESTNR="01" +BASEDIR="$(pwd)/debian/tests" +COMMONDIR="${BASEDIR}/common" +DIR="${BASEDIR}/${TESTNR}" +PATH="/bin:/usr/bin:/sbin:/usr/sbin" +ACCTA="test${TESTNR}a" +ACCTB="test${TESTNR}b" +PASSWD="test${TESTNR}23456" +HOMEDIRA="/home/${ACCTA}" +HOMEDIRB="/home/${ACCTB}" +LDIFDIR="${DIR}/ldif" + +trap ' + deluser --remove-home "${ACCTA}" 2>/dev/null || true + deluser --remove-home "${ACCTB}" 2>/dev/null || true +' 0 INT QUIT ABRT PIPE TERM + +printf > /etc/hosts "127.0.1.1 %s\n" "$(hostname)" +cat /etc/hosts + +printf "========= test %s\.1: account group member, correct password\n" "${TESTNR}" +deluser ${ACCTA} 2>/dev/null || true +adduser --disabled-password --home "${HOMEDIRA}" --gecos "" "${ACCTA}" +printf "%s:%s\n" "${ACCTA}" "${PASSWD}" | chpasswd +adduser "${ACCTA}" sudo +RET=0 +printf "trying %s with correct password\n" "${ACCTA}" +su - "${ACCTA}" -c "${COMMONDIR}/asuser ${PASSWD}" || RET=$? +printf "%s with correct password, return value %s\n" "${ACCTA}" "${RET}" +if [ "$(cat ${HOMEDIRA}/stdout)" != "0" ]; then + echo >&2 id -u did not give 0 + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRA}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRA}/stderr + printf >&2 "exit code %s\n" "${RET}" + printf >&2 "exit 1\n" "${RET}" + exit 1 +fi + +printf "========= test %s\.2: account group member, wrong password\n" "${TESTNR}" +rm -f "${HOMEDIRA}/std*" +RET=0 +printf "trying %s with wrong password\n" "${ACCTA}" +su - "${ACCTA}" -c "${COMMONDIR}/asuser wrongpasswd" || RET=$? +printf "%s with wrong password, return value %s\n" "${ACCTA}" "${RET}" +head -n-0 ${HOMEDIRA}/stdout ${HOMEDIRA}/stderr +printf -- "\n-------\n" +for string in "[sudo] password for ${ACCTA}" "Sorry, try again" "sudo: no password was provided" "sudo: 1 incorrect password attempt"; do + if ! grep -F "${string}" ${HOMEDIRA}/stderr; then + printf "%s missing in stderr output\n" "${string}" + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRA}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRA}/stderr + printf >&2 "\nexit code %s\n" "${RET}" + printf >&2 -- "------\n exit 1\n" + exit 1 + fi +done + +printf "========= test %s\.3: account not group member, correct password\n" "${TESTNR}" +deluser ${ACCTB} 2>/dev/null || true +adduser --disabled-password --home "${HOMEDIRB}" --gecos "" "${ACCTB}" +printf "%s:%s\n" "${ACCTB}" "${PASSWD}" | chpasswd +RET=0 +printf "trying %s (no sudo membership) with correct password\n" "${ACCTB}" +su - "${ACCTB}" -c "${COMMONDIR}/asuser ${PASSWD}" || RET=$? +printf "%s with correct password, return value %s\n" "${ACCTB}" "${RET}" +head -n-0 ${HOMEDIRB}/stdout ${HOMEDIRA}/stderr +printf -- "\n-------\n" +for string in "[sudo] password for ${ACCTB}" "${ACCTB} is not in the sudoers file"; do + if ! grep -F "${string}" ${HOMEDIRB}/stderr; then + printf "%s missing in stderr output\n" "${string}" + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRB}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRB}/stderr + printf >&2 "\nexit code %s\n" "${RET}" + printf >&2 -- "------\n exit 1\n" + exit 1 + fi +done + +printf "test series sucessful, exit 0\n" +exit 0 diff --git a/debian/tests/02-1003969-audit-no-resolve b/debian/tests/02-1003969-audit-no-resolve new file mode 100755 index 0000000..3fc32aa --- /dev/null +++ b/debian/tests/02-1003969-audit-no-resolve @@ -0,0 +1,43 @@ +#!/bin/sh + +set -e + +TESTNR="02" +BASEDIR="$(pwd)/debian/tests" +COMMONDIR="${BASEDIR}/common" +DIR="${BASEDIR}/${TESTNR}" +PATH="/bin:/usr/bin:/sbin:/usr/sbin" +ACCTA="test${TESTNR}a" +ACCTB="test${TESTNR}b" +PASSWD="test${TESTNR}23456" +HOMEDIRA="/root" +LDIFDIR="${DIR}/ldif" + +trap ' + printf "\ntrap handler\n" + mv /etc/resolv.conf.disabled /etc/resolv.conf || true + mv /etc/hosts.disabled /etc/hosts || true +' 0 INT QUIT ABRT PIPE TERM + +printf "========= test %s\.1: sudo to nobody\n" "${TESTNR}" +mv /etc/resolv.conf /etc/resolv.conf.disabled +mv /etc/hosts /etc/hosts.disabled +RET=0 +printf "trying sudo to nobody\n" +cd "${HOMEDIRA}" +${COMMONDIR}/asuser "" nobody || RET=$? +printf "sudo to nobody, return value %s\n" "${RET}" +STDERRLENGTH="$(cat ${HOMEDIRA}/stderr | grep -vE 'sudo: unable to resolve host [^:]+: Temporary failure in name resolution' | wc -l)" +if [ "${STDERRLENGTH}" != "0" ]; then + echo >&2 non-empty stderr + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRA}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRA}/stderr + printf >&2 "exit code %s\n" "${RET}" + printf >&2 "exit 1\n" "${RET}" + exit 1 +fi + +printf "test series sucessful, exit 0\n" +exit 0 diff --git a/debian/tests/03-getroot-ldap b/debian/tests/03-getroot-ldap new file mode 100755 index 0000000..f50be3a --- /dev/null +++ b/debian/tests/03-getroot-ldap @@ -0,0 +1,132 @@ +#!/bin/sh + +set -e + +TESTNR="03" +BASEDIR="$(pwd)/debian/tests" +COMMONDIR="${BASEDIR}/common" +DIR="${BASEDIR}/${TESTNR}" +PATH="/bin:/usr/bin:/sbin:/usr/sbin" +ACCTA="test${TESTNR}a" +ACCTB="test${TESTNR}b" +PASSWD="test${TESTNR}23456" +HOMEDIRA="/home/${ACCTA}" +HOMEDIRB="/home/${ACCTB}" +LDIFDIR="${DIR}/ldif" + +trap ' + kill $(pidof slapd) 2>/dev/null || true + deluser --remove-home "${ACCTA}" 2>/dev/null || true + deluser --remove-home "${ACCTB}" 2>/dev/null || true + mv /etc/disabled.sudoers /etc/sudoers 2>/dev/null || true +' 0 INT QUIT ABRT PIPE TERM + +if ! grep -q '^slapd: ALL' /etc/hosts.allow; then + echo "slapd: ALL" >> /etc/hosts.allow +fi + +< ${LDIFDIR}/debconf debconf-set-selections +printf "clean up ldap database ... " +rm -rf /var/lib/ldap/*.mdb +printf "reconfigure slapd ... " +DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -pcritical slapd 2>/dev/null +if ! grep -q '^slapd: ALL$' /etc/hosts.allow; then + echo "slapd: ALL" >> /etc/hosts.allow +fi +printf "start slapd ... " +slapd -h 'ldap://127.0.0.1:11389/ ldapi:///' -g openldap -u openldap -F /etc/ldap/slapd.d +echo "URI ldap://127.0.0.1:11389" > /etc/ldap/ldap.conf +# ldapsearch -x -LLL -s base -b "" namingContexts should work here +printf "add sudo schema to slapd ... " +< /usr/share/doc/sudo-ldap/schema.olcSudo ldapadd -Y EXTERNAL -H ldapi:/// 2>/dev/null +printf "add sudo group ... " +< ${LDIFDIR}/container.ldif ldapadd -x -D 'cn=admin,dc=example,dc=com' -w ldappw 2>/dev/null +if ! grep -q '^sudoers: ldap$' /etc/nsswitch.conf; then + sed -i '/^sudoers.*/d' /etc/nsswitch.conf + echo "sudoers: ldap" >> /etc/nsswitch.conf +fi +touch /etc/ldap/ldap.conf +if ! grep -q '^sudoers_base ou=SUDOers,dc=example,dc=com' /etc/ldap/ldap.conf; then + echo "sudoers_base ou=SUDOers,dc=example,dc=com" >> /etc/ldap/ldap.conf +fi +printf "reconfigure sudo-ldap (#1001851) ... " +DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -pcritical sudo-ldap 2>/dev/null +printf "cvtsudoers into sudoers.ldif ... " +cvtsudoers -b ou=SUDOers,dc=example,dc=com -o ${LDIFDIR}/sudoers.ldif /etc/sudoers +printf "\n cat sudoers.ldif\n" +cat ${LDIFDIR}/sudoers.ldif +printf "pull sudoers.ldif into ldap ..." +< ${LDIFDIR}/sudoers.ldif ldapadd -x -D 'cn=admin,dc=example,dc=com' -w ldappw +# ldapsearch -x -LLL -b "ou=SUDOers,dc=example,dc=com" should work here +printf "move away sudoers ...\n" +mv /etc/sudoers /etc/disabled.sudoers + + +printf "========= test %s\.1: account group member, correct password\n" "${TESTNR}" +printf > /etc/hosts "127.0.1.1 %s\n" "$(hostname)" +deluser ${ACCTA} 2>/dev/null || true +adduser --disabled-password --home "${HOMEDIRA}" --gecos "" "${ACCTA}" +printf "%s:%s\n" "${ACCTA}" "${PASSWD}" | chpasswd +adduser "${ACCTA}" sudo +RET=0 +printf "trying %s with correct password\n" "${ACCTA}" +su - "${ACCTA}" -c "${COMMONDIR}/asuser ${PASSWD}" || RET=$? +printf "%s with correct password, return value %s\n" "${ACCTA}" "${RET}" +if [ "$(cat ${HOMEDIRA}/stdout)" != "0" ]; then + printf >&2 "id -u did not give 0\n" + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRA}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRA}/stderr + printf >&2 "exit code %s\n" "${RET}" + printf >&2 "exit 1\n" "${RET}" + exit 1 +fi + +printf "========= test %s\.2: account group member, wrong password\n" "${TESTNR}" +rm -f "${HOMEDIRA}/std*" +RET=0 +printf "trying %s with wrong password\n" "${ACCTA}" +su - "${ACCTA}" -c "${COMMONDIR}/asuser wrongpasswd" || RET=$? +printf "%s with wrong password, return value %s\n" "${ACCTA}" "${RET}" +head -n-0 ${HOMEDIRA}/stdout ${HOMEDIRA}/stderr +printf -- "\n-------\n" +for string in "[sudo] password for ${ACCTA}" "Sorry, try again" "sudo: no password was provided" "sudo: 1 incorrect password attempt"; do + if ! grep -F "${string}" ${HOMEDIRA}/stderr; then + printf "%s missing in stderr output\n" "${string}" + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRA}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRA}/stderr + printf >&2 "\nexit code %s\n" "${RET}" + printf >&2 -- "------\n exit 1\n" + exit 1 + fi +done + +printf "========= test %s\.3: account not group member, correct password\n" "${TESTNR}" +deluser ${ACCTB} 2>/dev/null || true +adduser --disabled-password --home "${HOMEDIRB}" --gecos "" "${ACCTB}" +printf "%s:%s\n" "${ACCTB}" "${PASSWD}" | chpasswd +RET=0 +printf "trying %s (no sudo membership) with correct password\n" "${ACCTB}" +su - "${ACCTB}" -c "${COMMONDIR}/asuser ${PASSWD}" || RET=$? +printf "%s with correct password, return value %s\n" "${ACCTB}" "${RET}" +head -n-0 ${HOMEDIRB}/stdout ${HOMEDIRB}/stderr +printf -- "\n-------\n" +for string in "[sudo] password for ${ACCTB}" "${ACCTB} is not allowed to run sudo on"; do + if ! grep -F "${string}" ${HOMEDIRB}/stderr; then + printf "%s missing in stderr output\n" "${string}" + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRB}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRB}/stderr + printf >&2 "\nexit code %s\n" "${RET}" + printf >&2 -- "------\n exit 1\n" + exit 1 + fi +done + +printf "test series sucessful, exit 0\n" +exit 0 + diff --git a/debian/tests/03/ldif/container.ldif b/debian/tests/03/ldif/container.ldif new file mode 100644 index 0000000..8f02a68 --- /dev/null +++ b/debian/tests/03/ldif/container.ldif @@ -0,0 +1,5 @@ +dn: ou=SUDOers,dc=example,dc=com +objectClass: top +objectClass: organizationalUnit +ou: SUDOers + diff --git a/debian/tests/03/ldif/debconf b/debian/tests/03/ldif/debconf new file mode 100644 index 0000000..d40ae8c --- /dev/null +++ b/debian/tests/03/ldif/debconf @@ -0,0 +1,16 @@ +slapd slapd/password1 password ldappw +slapd slapd/password2 password ldappw +slapd slapd/internal/adminpw password ldappw +slapd slapd/internal/generated_adminpw password ldappw +slapd slapd/password_mismatch note +slapd slapd/domain string example.com +slapd slapd/dump_database_destdir string /var/backups/slapd-VERSION +slapd slapd/purge_database boolean true +slapd slapd/dump_database select when needed +slapd slapd/no_configuration boolean false +slapd slapd/ppolicy_schema_needs_update select abort installation +slapd slapd/invalid_config boolean false +slapd shared/organization string example.com +slapd slapd/move_old_database boolean true +slapd slapd/unsafe_selfwrite_acl note + diff --git a/debian/tests/03/ldif/sudoers.ldif b/debian/tests/03/ldif/sudoers.ldif new file mode 100644 index 0000000..d321d52 --- /dev/null +++ b/debian/tests/03/ldif/sudoers.ldif @@ -0,0 +1,32 @@ +dn: cn=defaults,ou=SUDOers,dc=example,dc=com +objectClass: top +objectClass: sudoRole +cn: defaults +description: Default sudoOption's go here +sudoOption: env_reset +sudoOption: mail_badpass +sudoOption: secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +sudoOption: use_pty + +dn: cn=root,ou=SUDOers,dc=example,dc=com +objectClass: top +objectClass: sudoRole +cn: root +sudoUser: root +sudoHost: ALL +sudoRunAsUser: ALL +sudoRunAsGroup: ALL +sudoCommand: ALL +sudoOrder: 1 + +dn: cn=%sudo,ou=SUDOers,dc=example,dc=com +objectClass: top +objectClass: sudoRole +cn: %sudo +sudoUser: %sudo +sudoHost: ALL +sudoRunAsUser: ALL +sudoRunAsGroup: ALL +sudoCommand: ALL +sudoOrder: 2 + diff --git a/debian/tests/04-getroot-sssd b/debian/tests/04-getroot-sssd new file mode 100755 index 0000000..eb13852 --- /dev/null +++ b/debian/tests/04-getroot-sssd @@ -0,0 +1,138 @@ +#!/bin/sh + +set -e + +# DEBIAN_FRONTEND=noninteractive apt --yes install adduser slapd ldap-utils sssd cron sudo man-db procps vim whiptail +# slappasswd -s kkkk + +TESTNR="04" +BASEDIR="$(pwd)/debian/tests" +COMMONDIR="${BASEDIR}/common" +DIR="${BASEDIR}/${TESTNR}" +PATH="/bin:/usr/bin:/sbin:/usr/sbin" +ACCTA="testuser1" +ACCTB="testuser2" +PASSWD="test${TESTNR}23456" +HOMEDIRA="/home/${ACCTA}" +HOMEDIRB="/home/${ACCTB}" +LDIFDIR="${DIR}/ldif" +SSSDCONF="/etc/sssd/sssd.conf" + +trap ' + kill $(pidof slapd) 2>/dev/null || true + kill $(pidof sssd) 2>/dev/null || true +' 0 INT QUIT ABRT PIPE TERM + +# openssl req -x509 -days 365 -nodes -newkey rsa:4096 -keyout server_key.pem -out server_cert.pem --subj "/C=DE/CN=emptysid86.zugschlus.de" + +< ${LDIFDIR}/debconf debconf-set-selections +printf "clean up ldap database ... " +rm -rf /var/lib/ldap/*.mdb +printf "move configuration in place ... " +mkdir -p /etc/ldap /etc/sssd +cp ${LDIFDIR}/server_*.pem /etc/ldap/ +cp ${LDIFDIR}/ldap.conf /etc/ldap/ +chown openldap:openldap /etc/ldap/server_*.pem +chmod 600 /etc/ldap/server_key.pem +cp ${LDIFDIR}/sssd.conf /etc/sssd +chown root:root /etc/sssd/sssd.conf +chmod 600 /etc/sssd/sssd.conf +cp ${LDIFDIR}/slapd-default /etc/default/slapd +echo "slapd: [::1]" >> /etc/hosts.allow +printf "reconfigure slapd ... " +DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -pcritical slapd 2>/dev/null +kill $(pidof slapd) 2>/dev/null || true +sleep 1 +printf "start slapd ... " +slapd -h "ldaps:/// ldapi:///" -g openldap -u openldap -F /etc/ldap/slapd.d +# ldapsearch -x -LLL -s base -b "" namingContexts should work here +printf "set LDAP passwords" +ldapmodify -v -Y external -H ldapi:/// -f ${LDIFDIR}/tls.ldif 2>/dev/null +printf "set LDAP passwords for admin" +ldapmodify -v -Y external -H ldapi:/// -f ${LDIFDIR}/adminpw.ldif 2>/dev/null +printf "set LDAP passwords for admin example" +ldapmodify -v -Y external -H ldapi:/// -f ${LDIFDIR}/adminpw-example-com.ldif 2>/dev/null +printf "add users and groups OUs ..." +ldapadd -x -D "cn=admin,dc=example,dc=com" -w ldappw -f ${LDIFDIR}/sss-ous.ldif 2>/dev/null +printf "add users ..." + +printf "sssd.conf ...\n" +cp ${LDIFDIR}/sssd.conf "${SSSDCONF}" + +printf "sudoers file ...\n"A +mkdir -p /etc/sudoers.d/ +mv ${LDIFDIR}/ldapsudoers /etc/sudoers.d/ +chown root:root "${SSSDCONF}" /etc/sudoers.d/ /etc/sudoers.d/* +chmod 755 /etc/sudoers.d/ +chmod 600 "${SSSDCONF}" /etc/sudoers.d/* +kill $(pidof sssd) 2>/dev/null || true +sleep 1 +sssd --logger=files -D + +for user in testuser1 testuser2; do + ldapadd -x -D "cn=admin,dc=example,dc=com" -w ldappw -f ${LDIFDIR}/${user}.ldif 2>/dev/null + mkdir -p /home/${user} + chown ${user}:nogroup /home/${user} +done +ldapadd -x -D "cn=admin,dc=example,dc=com" -w ldappw -f ${LDIFDIR}/ldapsudoers.ldif 2>/dev/null +# ldapsearch -x -D "cn=admin,dc=example,dc=com" -w ldappw -b "dc=example,dc=com" -s sub "(objectclass=*)" should work here. + +printf "========= test %s\.1: account group member, correct password\n" "${TESTNR}" +RET=0 +printf "trying %s with correct password\n" "${ACCTA}" +su - "${ACCTA}" -c "${COMMONDIR}/asuser ${PASSWD}" || RET=$? +printf "%s with correct password, return value %s\n" "${ACCTA}" "${RET}" +if [ "$(cat ${HOMEDIRA}/stdout)" != "0" ]; then + printf >&2 "id -u did not give 0\n" + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRA}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRA}/stderr + printf >&2 "exit code %s\n" "${RET}" + printf >&2 "exit 1\n" "${RET}" + exit 1 +fi + +printf "========= test %s\.2: account group member, wrong password\n" "${TESTNR}" +rm -f "${HOMEDIRA}/std*" +RET=0 +printf "trying %s with wrong password\n" "${ACCTA}" +su - "${ACCTA}" -c "${COMMONDIR}/asuser wrongpasswd" || RET=$? +printf "%s with wrong password, return value %s\n" "${ACCTA}" "${RET}" +head -n-0 ${HOMEDIRA}/stdout ${HOMEDIRA}/stderr +printf -- "\n-------\n" +for string in "[sudo] password for ${ACCTA}" "Sorry, try again" "sudo: no password was provided" "sudo: 1 incorrect password attempt"; do + if ! grep -F "${string}" ${HOMEDIRA}/stderr; then + printf "%s missing in stderr output\n" "${string}" + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRA}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRA}/stderr + printf >&2 "\nexit code %s\n" "${RET}" + printf >&2 -- "------\n exit 1\n" + exit 1 + fi +done + +printf "========= test %s\.3: account not group member, correct password\n" "${TESTNR}" +printf "trying %s (no sudo membership) with correct password\n" "${ACCTB}" +su - "${ACCTB}" -c "${COMMONDIR}/asuser ${PASSWD}" || RET=$? +printf "%s with correct password, return value %s\n" "${ACCTB}" "${RET}" +head -n-0 ${HOMEDIRB}/stdout ${HOMEDIRB}/stderr +printf -- "\n-------\n" +for string in "[sudo] password for ${ACCTB}: ${ACCTB} is not in the sudoers file." ; do + if ! grep -q -F "${string}" ${HOMEDIRB}/stderr; then + printf "%s missing in stderr output\n" "${string}" + printf >&2 "stdout:\n" + cat >&2 ${HOMEDIRB}/stdout + printf >&2 "stderr:\n" + cat >&2 ${HOMEDIRB}/stderr + printf >&2 "\nexit code %s\n" "${RET}" + printf >&2 -- "------\n exit 1\n" + exit 1 + fi +done + +printf "test series sucessful, exit 0\n" +exit 0 + diff --git a/debian/tests/04/ldif/adminpw-example-com.ldif b/debian/tests/04/ldif/adminpw-example-com.ldif new file mode 100644 index 0000000..adf42d5 --- /dev/null +++ b/debian/tests/04/ldif/adminpw-example-com.ldif @@ -0,0 +1,4 @@ +dn: olcDatabase={1}mdb,cn=config +changetype: modify +replace: olcRootPW +olcRootPW: {SSHA}5VEuBX9dLCSCj+TIp7XBXQRb3F5M2aSN diff --git a/debian/tests/04/ldif/adminpw.ldif b/debian/tests/04/ldif/adminpw.ldif new file mode 100644 index 0000000..6cf1bb8 --- /dev/null +++ b/debian/tests/04/ldif/adminpw.ldif @@ -0,0 +1,7 @@ +# this sets a password ldappw for the config database +# ldapsearch -H ldapi:// -LLL -D "cn=admin,cn=config" -W -b "cn=config" "(olcRootDN=*)" dn olcRootDN olcRootPW olcSuffix +# should work without -Y EXTERNAL and as normal user now +dn: olcDatabase={0}config,cn=config +changetype: modify +replace: olcRootPW +olcRootPW: {SSHA}5VEuBX9dLCSCj+TIp7XBXQRb3F5M2aSN diff --git a/debian/tests/04/ldif/container.ldif b/debian/tests/04/ldif/container.ldif new file mode 100644 index 0000000..8f02a68 --- /dev/null +++ b/debian/tests/04/ldif/container.ldif @@ -0,0 +1,5 @@ +dn: ou=SUDOers,dc=example,dc=com +objectClass: top +objectClass: organizationalUnit +ou: SUDOers + diff --git a/debian/tests/04/ldif/debconf b/debian/tests/04/ldif/debconf new file mode 100644 index 0000000..bb14313 --- /dev/null +++ b/debian/tests/04/ldif/debconf @@ -0,0 +1,15 @@ +slapd slapd/password1 password ldappw +slapd slapd/password2 password ldappw +slapd slapd/internal/adminpw password ldappw +slapd slapd/internal/generated_adminpw password ldappw +slapd slapd/password_mismatch note +slapd slapd/domain string example.com +slapd slapd/dump_database_destdir string /var/backups/slapd-VERSION +slapd slapd/purge_database boolean true +slapd slapd/no_configuration boolean false +slapd slapd/ppolicy_schema_needs_update select abort installation +slapd slapd/invalid_config boolean false +slapd shared/organization string example.com +slapd slapd/move_old_database boolean true +slapd slapd/unsafe_selfwrite_acl note + diff --git a/debian/tests/04/ldif/ldap.conf b/debian/tests/04/ldif/ldap.conf new file mode 100644 index 0000000..3f3000a --- /dev/null +++ b/debian/tests/04/ldif/ldap.conf @@ -0,0 +1,6 @@ +BASE dc=example,dc=com +URI ldaps://[::1]:636/ +TLS_CACERT /etc/ldap/server_cert.pem +TLS_REQCERT allow +SASL_NOCANON on + diff --git a/debian/tests/04/ldif/ldapsudoers b/debian/tests/04/ldif/ldapsudoers new file mode 100644 index 0000000..8d11b0b --- /dev/null +++ b/debian/tests/04/ldif/ldapsudoers @@ -0,0 +1 @@ +%ldapsudoers ALL=(ALL:ALL) ALL diff --git a/debian/tests/04/ldif/ldapsudoers.ldif b/debian/tests/04/ldif/ldapsudoers.ldif new file mode 100644 index 0000000..029d73e --- /dev/null +++ b/debian/tests/04/ldif/ldapsudoers.ldif @@ -0,0 +1,6 @@ +dn: cn=ldapsudoers,ou=groups,dc=example,dc=com +objectClass: posixGroup +objectClass: top +gidNumber: 270 +cn: ldapsudoers +memberUid: testuser1 diff --git a/debian/tests/04/ldif/server_cert.pem b/debian/tests/04/ldif/server_cert.pem new file mode 100644 index 0000000..69392cd --- /dev/null +++ b/debian/tests/04/ldif/server_cert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFMTCCAxmgAwIBAgIUatkSzjnbPNHqrbv9GByfPIoUjtYwDQYJKoZIhvcNAQEL +BQAwKDELMAkGA1UEBhMCREUxGTAXBgNVBAMMEGxkYXAuZXhhbXBsZS5jb20wHhcN +MjMwMTAyMTc0NDA2WhcNMjQwMTAyMTc0NDA2WjAoMQswCQYDVQQGEwJERTEZMBcG +A1UEAwwQbGRhcC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAOscbfVg0NKHrFWLv2y+veqaRv/8ANup0ZSm/Qyx1zHdCV0sQMxfxeVb +OMcucCoBbAsPznHLZXaJFL3cgqdcaQ5oLYGCaaj7TbfBwm4i0bGP+xpDV7nvxyW3 +HLw5mYmoYpm5iAFaRuqWuMbCU2bILuTVO/D7V/1TUS4ciLpz9Dw5rrFy9t+ZURMv +bf45/tjlD4T6ItDrr4gBKJ6fqRbCVZl38oyiont/Spm+nBRpHpZz70F4AYo8rwMD +dLGonJ85KrVeIDg5TZEMEKgxgXu6hrvNVxyGWXmA3mOVy+vyRj8XHDebDX8qmPgF +g/Rzzm4VgrlXqtuEc/YQqyu6VqpNR9Yu0oj+q7J/A4BU316PioNB4zHWWwqqBEKu +bXy9EtXfYXppPV56/XfnYm6mbyIn0x382oBrcQiQD5pTWoz61lawrt9YDGnDvWSH +BHUhzoVSY++D0QX0hae35zZkTbW9/eXpZGr5UDVFgkZGWDPPxrXyOAgiJfwiTtqm +Du9Lp3JycX95ywGhTPBNM9nvaPk5bBSWgz9uaoP2NY4VQga4vhn2mC0WbJOtUHSm ++tMpjTcBIJzpdyH0yh7DEGORk5aev9gU+K1VcSRD/3pXkSjo7xSEfSNW+flAGwVS +UABDs/0XkdmhvL4zawnuMapEttWqHKH0wrQLkvzTkFUnqJsQ8cerAgMBAAGjUzBR +MB0GA1UdDgQWBBS1r+sdVFP2hBByMEw9iSvkvvGqxTAfBgNVHSMEGDAWgBS1r+sd +VFP2hBByMEw9iSvkvvGqxTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4ICAQA8otnqTtetl0Tqqx+lNsmfOi2iEbptyKuvDhSBSlkdHVGD+rRilDeehdVN +9vE2fNOdYdtAfxBVEUW6S4RRY3gJZ38oik0JbYxotUYqAgFzY53Zg5CAQpmGDCYg +GMS/2zHlo5ZFNoKLMJG5o8qGao1HehBlIJ9D06mRQO88aguMa4jPBYHMb43ZWOxh +Un9P6fOl7bfRqomxgixnovPlFiELg/ZWANpECRY7lsVahKLndWf+Tw3Ayp4+CpvL +mWc0xRCYTFDua1lyLypxsH/4H5IZlDwpw8bvSAmmpdqhbA4Sh+Qo6gXn4Bm92A4L +sltnUjCliJb79Q3gkuvIB/qlPPbZ/s9L0OxRHnHYR+7JfVxlsWb2guMApGc4R3Um +5U4sK4QEFZFCBgsrA3DpXQo1pW30DCZjXjrzQ3kbPuKX8njOzPI9Q02xdoMkuqMw +o4tvo28xgWlW2HZrzU7fnm7t0MTGJG33LKlcz/tRco9Ky+YxKz5HvQAGCKrb3L6x +iOeVuT90cKfNX7pVoHNR7YSav+n9YacIknB+HBpGLKGlfvHIlwvCMtOK9axHxUiO +AZaCYYUXgFbYetyoux5PyYBDwIrJSIw7FpQkONmHLRSM2j3S9RRGi9ipR3jzvvqz +d7dsFok749nOEuJ4qvnWrJ5WkcrbrX5GcR0UL1mWSJqCRXOp1A== +-----END CERTIFICATE----- diff --git a/debian/tests/04/ldif/server_key.pem b/debian/tests/04/ldif/server_key.pem new file mode 100644 index 0000000..7baef03 --- /dev/null +++ b/debian/tests/04/ldif/server_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDrHG31YNDSh6xV +i79svr3qmkb//ADbqdGUpv0Msdcx3QldLEDMX8XlWzjHLnAqAWwLD85xy2V2iRS9 +3IKnXGkOaC2Bgmmo+023wcJuItGxj/saQ1e578cltxy8OZmJqGKZuYgBWkbqlrjG +wlNmyC7k1Tvw+1f9U1EuHIi6c/Q8Oa6xcvbfmVETL23+Of7Y5Q+E+iLQ66+IASie +n6kWwlWZd/KMoqJ7f0qZvpwUaR6Wc+9BeAGKPK8DA3SxqJyfOSq1XiA4OU2RDBCo +MYF7uoa7zVcchll5gN5jlcvr8kY/Fxw3mw1/Kpj4BYP0c85uFYK5V6rbhHP2EKsr +ulaqTUfWLtKI/quyfwOAVN9ej4qDQeMx1lsKqgRCrm18vRLV32F6aT1eev1352Ju +pm8iJ9Md/NqAa3EIkA+aU1qM+tZWsK7fWAxpw71khwR1Ic6FUmPvg9EF9IWnt+c2 +ZE21vf3l6WRq+VA1RYJGRlgzz8a18jgIIiX8Ik7apg7vS6dycnF/ecsBoUzwTTPZ +72j5OWwUloM/bmqD9jWOFUIGuL4Z9pgtFmyTrVB0pvrTKY03ASCc6Xch9MoewxBj +kZOWnr/YFPitVXEkQ/96V5Eo6O8UhH0jVvn5QBsFUlAAQ7P9F5HZoby+M2sJ7jGq +RLbVqhyh9MK0C5L805BVJ6ibEPHHqwIDAQABAoICAE2uU4BnECf3Ts/nAAT4krxQ +ZBQRGeF6HvaMJADNQ6pEe2MPC4vbOwIYXU6mP8YJOT8AZnf/uZLsIO/IS1zrsgRi +FGL9iVadTaTgvpJwK7OMvG0Fghc7q6OA+FwSdfHfMlDTVaYIw3Sf/wYgz7iefKv7 +7jWlfgGDxUdEg0KDrFc3wcn8j6f6Oqjpm2CLnfHg4PtRQC6iKJl5tIeQfig4Zlry +IDAqTiAawzXAHka6IrKYNJ1/fpbDjRmkSyql6LXNCBjrtB6PhFrfzyMbVEpiq0Ci +zFzu4OI923yw0jMvldkjlB2lO9Tf6LHN9LbQioyhy9LcLeYgwcWz5TJp+1eCeDCg +np5ipwqhkTvx9T6rQRtInZCJZSmY+JxWYlQJ7Gz2e4V4L+9or3nTBs/YDPV+dDSs +SjcQgEstc/nEj0y4l2iEZq7N9Ro3PtWM6beM3yYacsJEdDwhH2vRBj/xl9j3fKc+ +0kvWem0r9+kKXw/LweSmeTTtrsjKZPi2pFrvXBG1yrhwmERtQOoQN0llRgQy7XBW +EUN3WMHYVfUcKzRRHrlDQ3tTuTlm1cFv6JQ5ip4sedNJSkWMBAv1yyLH5CnISm6k +OpOhz1oGHTNG91PkVvVJP8GvhOXafi84bLrXU7FJaAkgci/EGQAkqO5R3ITjYKMG +eoPul58iQ8057C9As9LhAoIBAQD4mvuPSxTwaH/9AsEPrv3fhmG0QfeD0wFUvFKO +X/gDfVbkQjH6CcNe5QjbRzooJAGdENmQzn8S9qhqcdghYKAtKnabwhgqzVv2Xr6z +XpyhmJCF+MEaTfhIw/C1HmjURwdxmk0w4uaTOixKlCwwA1bi69dDZ82dMqM1Y7u4 +uPQwykud4AAeFRETAcWAXe0BZ4d5uow7siaSRS24Do7SEAa7zcLiTqVbuKhBNqRa +FSY/r7f8W78oL7Z/TwhYP0MpQLAG9gAUc48BO6Rm5tJfMmd2D8KLQ2Lfze4ETBSA +ZJk0j1LuXNWzSM2wQ4vbhGrw4qLTue6uv9V0lY1FB0d9y+JLAoIBAQDyGrGLPPeR +IBHzXiFGGFd/it20ux1x7+iFhC/NEwJVKU6oVO39jqte4nVfFo5cb4WKuQHfmiEN +E6hcdkXBCezgTGKsvqaY+nmmoNMNg2wh/cGc6VoBMiixZYa43S+i5U4pdWZbwbgB +1zUqh1k1NcSBQErqoML2R1aORw627OV1Ef+/UpnVlQGlrqor+w1XtmOb9s6/02gb +QA+pZlLEuyJwhXhxAioFoY+G7zKcJisAKORGS7ZtvmCzOqq2cUD4EYtYPGJmjpU5 +yfwW7YoJALmoIckORHQuQXkL6nnDXOhvL66dKAU523NkbfHUmdl/DyiedZxOtUH8 +Jky+oarQm1QhAoIBAQCNDWItqyv2O1Ri+W0QuPjSGizVWZhV8yKOMUul/E17rWHf +oK86bs+qx8h+oasdm1BPDYBj6MWwvMJRosY+KdS3y6AAP9/2aQ4Eez04CDZWeXmG +id0GT7bPklzAZsCTsLlIe4PQeOzaG+eFaQypMTvbBHTeicbfqhtv72ZTKJ1kEWNV +8AIhD1LgteCZNLGEWnlDV9S5ChtYYmfORnRCO1WWuOgZ/wVTRTIxzg7yDY3mFI0P +Yf7Tjj69fNn/N+WjQlCdonXpJKe+y1g8CjrSSIbrNYXr/g/ba7vgNEptjqZea/Nh +ysp1LpmFqM1xf3AtvGkmOBh0jeNOgovk3nxxo3yBAoIBAGs6/XYhS7mAjdLP10b3 +kxGPjQD2e2UykDdKw+09xSO5BvixnTNX1HlTLg8uq2Evl+NIbBcAajEjisdhLyX/ +4mW6D15ZlupczjLKOpBarDMl9HIuPMoY0EM6J4CLnwS0MXlVYT+0vm46RncOualC +pkVlF4lyKMfx8tlTiaXlqP/AOBkiWbZqp+8dPIv8Rv2Zb+btWsdFuG+RYR5zjqdK +B0f1JdJP1hLmau6l1TGqChOpCOpFsIhM8QGRM3lZEiCNjL1JCYBJGLkeyEPTc/bm +1lQsmqNyGE9Aen+Xm9S2utA8O0eqKR5mH2bU925lshp/uUrt5oxJ5e7re8RXUJPS +qGECggEAMBcRhHnk9mlo6zi89hRY4YduN14ahxatZu99fFep9Ea3mslcTDzy26Xm +Mw0X3oij6+eJODlWpwzUMp5MylI8XEeOkfZ9il+6etFSOK6QWe2U7SDAy6nXYUVB +PZc5kTtCYSMIUmU+GjShMoEYPNCjqRSEY9sArZ85wFWEl5nRn5sEg8NLBhbURWu1 +iY1R0ie8XeXEoOWujMfhVmJUNadkeR23/XMmzfZ6M5gavkYkUjNMvCNMu7+GVeYU +uuxNmnNqjJP5GcLsd7dgzgslE+FPPxHiVjONIR7qrZwZcg9rGO2ODrLnuHZHzZha +x4rwQL3+5SADD++19sqJhDoXJW8KEw== +-----END PRIVATE KEY----- diff --git a/debian/tests/04/ldif/slapd-default b/debian/tests/04/ldif/slapd-default new file mode 100644 index 0000000..9d92858 --- /dev/null +++ b/debian/tests/04/ldif/slapd-default @@ -0,0 +1,7 @@ +SLAPD_CONF= +SLAPD_USER="openldap" +SLAPD_GROUP="openldap" +SLAPD_PIDFILE= +SLAPD_SERVICES="ldaps:/// ldapi:///" +SLAPD_SENTINEL_FILE=/etc/ldap/noslapd +SLAPD_OPTIONS="" diff --git a/debian/tests/04/ldif/sss-ous.ldif b/debian/tests/04/ldif/sss-ous.ldif new file mode 100644 index 0000000..5ba018c --- /dev/null +++ b/debian/tests/04/ldif/sss-ous.ldif @@ -0,0 +1,9 @@ +dn: ou=users,dc=example,dc=com +objectClass: top +objectClass: organizationalUnit +ou: users + +dn: ou=groups,dc=example,dc=com +objectClass: top +objectClass: organizationalUnit +ou: groups diff --git a/debian/tests/04/ldif/sssd.conf b/debian/tests/04/ldif/sssd.conf new file mode 100755 index 0000000..ee06ef5 --- /dev/null +++ b/debian/tests/04/ldif/sssd.conf @@ -0,0 +1,24 @@ +[sssd] +domains = example.com +services = nss, pam +debug_level = 0x01ff + +[domain/example.com] +id_provider = ldap +auth_provider = ldap + +ldap_uri = ldaps://[::1]:636/ +ldap_search_base = dc=example,dc=com + +ldap_tls_cacert = /etc/ldap/server_cert.pem +ldap_tls_reqcert = allow + +ldap_default_bind_dn = cn=admin,dc=example,dc=com +ldap_default_authtok_type = password +ldap_default_authtok = ldappw + +[pam] +offline_credentials_expiration = 2 +offline_failed_login_attempts = 3 +offline_failed_login_delay = 5 + diff --git a/debian/tests/04/ldif/testuser1.ldif b/debian/tests/04/ldif/testuser1.ldif new file mode 100644 index 0000000..2419a68 --- /dev/null +++ b/debian/tests/04/ldif/testuser1.ldif @@ -0,0 +1,16 @@ +dn: uid=testuser1,ou=users,dc=example,dc=com +objectClass: top +objectClass: account +objectClass: posixAccount +objectClass: shadowAccount +cn: testuser1 +uid: testuser1 +uidNumber: 10001 +gidNumber: 100 +homeDirectory: /home/testuser1 +loginShell: /bin/bash +gecos: testuser1 from LDAP +userPassword: {SSHA}n8CrO1tNcRrd4u8rMLOE91a18iFRQFBx +shadowLastChange: 0 +shadowMax: 0 +shadowWarning: 0 diff --git a/debian/tests/04/ldif/testuser2.ldif b/debian/tests/04/ldif/testuser2.ldif new file mode 100644 index 0000000..541c383 --- /dev/null +++ b/debian/tests/04/ldif/testuser2.ldif @@ -0,0 +1,17 @@ +dn: uid=testuser2,ou=users,dc=example,dc=com +objectClass: top +objectClass: account +objectClass: posixAccount +objectClass: shadowAccount +cn: testuser2 +uid: testuser2 +uidNumber: 10002 +gidNumber: 100 +homeDirectory: /home/testuser2 +loginShell: /bin/bash +gecos: testuser2 from LDAP +userPassword: {SSHA}n8CrO1tNcRrd4u8rMLOE91a18iFRQFBx +shadowLastChange: 0 +shadowMax: 0 +shadowWarning: 0 + diff --git a/debian/tests/04/ldif/tls.ldif b/debian/tests/04/ldif/tls.ldif new file mode 100644 index 0000000..012adf2 --- /dev/null +++ b/debian/tests/04/ldif/tls.ldif @@ -0,0 +1,10 @@ +dn: cn=config +changetype: modify +add: olcTLSCACertificateFile +olcTLSCACertificateFile: /etc/ldap/server_cert.pem +- +add: olcTLSCertificateKeyFile +olcTLSCertificateKeyFile: /etc/ldap/server_key.pem +- +add: olcTLSCertificateFile +olcTLSCertificateFile: /etc/ldap/server_cert.pem diff --git a/debian/tests/common/asuser b/debian/tests/common/asuser new file mode 100755 index 0000000..291b40a --- /dev/null +++ b/debian/tests/common/asuser @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e + +echo "${1:-}" | sudo -u "${2:-root}" --stdin id -u > "${3:-stdout}" 2> "${4:-stderr}" + + diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 0000000..a0bc0d6 --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,16 @@ +Tests: 01-getroot +Depends: sudo, adduser +Restrictions: needs-root + +Tests: 02-1003969-audit-no-resolve +Depends: sudo +Restrictions: needs-root + +Tests: 03-getroot-ldap +Depends: sudo-ldap, adduser, slapd, ldap-utils, cron +Restrictions: needs-root + +#Tests: 04-getroot-sssd +#Depends: sudo, adduser, slapd, ldap-utils, sssd-common, sssd-ldap, cron +#Restrictions: needs-root + |