diff options
Diffstat (limited to 'include')
30 files changed, 6683 insertions, 0 deletions
diff --git a/include/Makefile.in b/include/Makefile.in new file mode 100644 index 0000000..92f0563 --- /dev/null +++ b/include/Makefile.in @@ -0,0 +1,114 @@ +# +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2011-2015, 2017-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. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +abs_srcdir = @abs_srcdir@ +top_srcdir = @top_srcdir@ +abs_top_srcdir = @abs_top_srcdir@ +top_builddir = @top_builddir@ +abs_top_builddir = @abs_top_builddir@ +includedir = @includedir@ +scriptdir = $(top_srcdir)/scripts +cross_compiling = @CROSS_COMPILING@ + +# Our install program supports extra flags... +INSTALL = $(SHELL) $(scriptdir)/install-sh -c +INSTALL_OWNER = -o $(install_uid) -g $(install_gid) + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localstatedir = @localstatedir@ + +# User and group ids the installed files should be "owned" by +install_uid = 0 +install_gid = 0 + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +all: + +depend: + +Makefile: $(srcdir)/Makefile.in + cd $(top_builddir) && ./config.status --file include/Makefile + +.SUFFIXES: .h + +pre-install: + +install: install-includes + +install-dirs: + $(SHELL) $(scriptdir)/mkinstalldirs $(DESTDIR)$(includedir) + +install-binaries: + +install-doc: + +install-includes: install-dirs + $(INSTALL) $(INSTALL_OWNER) -m 0644 $(srcdir)/sudo_plugin.h $(DESTDIR)$(includedir) + +install-plugin: + +install-fuzzer: + +uninstall: + -rm -f $(DESTDIR)$(includedir)/sudo_plugin.h + +splint: + +cppcheck: + +pvs-log-files: + +pvs-studio: + +fuzz: + +check-fuzzer: + +check: check-fuzzer + +check-verbose: check + +clean: + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile + +clobber: distclean + +realclean: distclean + +cleandir: distclean + +.PHONY: clean mostlyclean distclean cleandir clobber realclean diff --git a/include/compat/charclass.h b/include/compat/charclass.h new file mode 100644 index 0000000..77c8d7f --- /dev/null +++ b/include/compat/charclass.h @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2008, 2010 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. + */ + +/* + * POSIX character class support for fnmatch() and glob(). + */ +static struct cclass { + const char *name; + int (*isctype)(int); +} cclasses[] = { + { "alnum", isalnum }, + { "alpha", isalpha }, + { "blank", isblank }, + { "cntrl", iscntrl }, + { "digit", isdigit }, + { "graph", isgraph }, + { "lower", islower }, + { "print", isprint }, + { "punct", ispunct }, + { "space", isspace }, + { "upper", isupper }, + { "xdigit", isxdigit }, + { NULL, NULL } +}; + +#define NCCLASSES (nitems(cclasses) - 1) diff --git a/include/compat/endian.h b/include/compat/endian.h new file mode 100644 index 0000000..fe6ee83 --- /dev/null +++ b/include/compat/endian.h @@ -0,0 +1,80 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2013, 2022 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. + */ + +#ifndef COMPAT_ENDIAN_H +#define COMPAT_ENDIAN_H + +#ifndef BYTE_ORDER +# undef LITTLE_ENDIAN +# define LITTLE_ENDIAN 1234 +# undef BIG_ENDIAN +# define BIG_ENDIAN 4321 +# undef UNKNOWN_ENDIAN +# define UNKNOWN_ENDIAN 0 + +/* + * Attempt to guess endianness. + * Solaris may define _LITTLE_ENDIAN and _BIG_ENDIAN to 1 + * HP-UX may define __LITTLE_ENDIAN__ and __BIG_ENDIAN__ to 1 + * Otherwise, check for cpu-specific cpp defines. + * Note that some CPUs are bi-endian, including: arm, powerpc, alpha, + * sparc64, mips, hppa, sh4 and ia64. + * We just check for the most common uses. + */ + +# if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define BYTE_ORDER LITTLE_ENDIAN +# elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define BYTE_ORDER BIG_ENDIAN +# elif defined(__BYTE_ORDER) +# define BYTE_ORDER __BYTE_ORDER +# elif defined(_BYTE_ORDER) +# define BYTE_ORDER _BYTE_ORDER +# elif defined(_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN__) +# define BYTE_ORDER LITTLE_ENDIAN +# elif defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__) +# define BYTE_ORDER BIG_ENDIAN +# elif defined(__alpha__) || defined(__alpha) || defined(__amd64) || \ + defined(BIT_ZERO_ON_RIGHT) || defined(i386) || defined(__i386) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(ns32000) || \ + defined(__ns3200) || defined(sun386) || defined(vax) || \ + defined(__vax) || defined(__x86__) || defined(__riscv) || \ + (defined(sun) && defined(__powerpc)) || \ + (!defined(__hpux) && defined(__ia64)) +# define BYTE_ORDER LITTLE_ENDIAN +# elif defined(__68k__) || defined(apollo) || defined(BIT_ZERO_ON_LEFT) || \ + defined(__convex__) || defined(_CRAY) || defined(DGUX) || \ + defined(__hppa) || defined(__hp9000) || defined(__hp9000s300) || \ + defined(__hp9000s700) || defined(__hp3000s900) || \ + defined(ibm032) || defined(ibm370) || defined(_IBMR2) || \ + defined(is68k) || defined(mc68000) || defined(m68k) || \ + defined(__m68k) || defined(m88k) || defined(__m88k) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(MPE) || \ + defined(pyr) || defined(__powerpc) || defined(__powerpc__) || \ + defined(sel) || defined(__sparc) || defined(__sparc__) || \ + defined(tahoe) || (defined(__hpux) && defined(__ia64)) || \ + (defined(sun) && defined(__powerpc)) +# define BYTE_ORDER BIG_ENDIAN +# else +# define BYTE_ORDER UNKNOWN_ENDIAN +# endif +#endif /* BYTE_ORDER */ + +#endif /* COMPAT_ENDIAN_H */ diff --git a/include/compat/fnmatch.h b/include/compat/fnmatch.h new file mode 100644 index 0000000..75cac1f --- /dev/null +++ b/include/compat/fnmatch.h @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2011 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. + */ + +#ifndef COMPAT_FNMATCH_H +#define COMPAT_FNMATCH_H + +#define FNM_NOMATCH 1 /* String does not match pattern */ + +#define FNM_PATHNAME (1 << 0) /* Globbing chars don't match '/' */ +#define FNM_PERIOD (1 << 1) /* Leading '.' in string must exactly */ +#define FNM_NOESCAPE (1 << 2) /* Backslash treated as ordinary char */ +#define FNM_LEADING_DIR (1 << 3) /* Only match the leading directory */ +#define FNM_CASEFOLD (1 << 4) /* Case insensitive matching */ + +sudo_dso_public int sudo_fnmatch(const char *pattern, const char *string, int flags); + +#define fnmatch(_a, _b, _c) sudo_fnmatch((_a), (_b), (_c)) + +#endif /* COMPAT_FNMATCH_H */ diff --git a/include/compat/getaddrinfo.h b/include/compat/getaddrinfo.h new file mode 100644 index 0000000..c1f87ef --- /dev/null +++ b/include/compat/getaddrinfo.h @@ -0,0 +1,83 @@ +/* + * Replacement implementation of getaddrinfo. + * + * This is an implementation of the getaddrinfo family of functions for + * systems that lack it, so that code can use getaddrinfo always. It provides + * IPv4 support only; for IPv6 support, a system getaddrinfo implementation is + * required. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Written by Russ Allbery <rra@stanford.edu> + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work. + */ + +#ifndef COMPAT_GETADDRINFO_H +#define COMPAT_GETADDRINFO_H + +#include <config.h> + +/* Skip this entire file if a system getaddrinfo was detected. */ +#ifndef HAVE_GETADDRINFO + +/* OpenBSD likes to have sys/types.h included before sys/socket.h. */ +#include <sys/types.h> +#include <sys/socket.h> + +/* The struct returned by getaddrinfo, from RFC 3493. */ +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME, .. */ + int ai_family; /* AF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + socklen_t ai_addrlen; /* Length of ai_addr */ + char *ai_canonname; /* Canonical name for nodename */ + struct sockaddr *ai_addr; /* Binary address */ + struct addrinfo *ai_next; /* Next structure in linked list */ +}; + +/* Constants for ai_flags from RFC 3493, combined with binary or. */ +#define AI_PASSIVE 0x0001 +#define AI_CANONNAME 0x0002 +#define AI_NUMERICHOST 0x0004 +#define AI_NUMERICSERV 0x0008 +#define AI_V4MAPPED 0x0010 +#define AI_ALL 0x0020 +#define AI_ADDRCONFIG 0x0040 + +/* Error return codes from RFC 3493. */ +#define EAI_AGAIN 1 /* Temporary name resolution failure */ +#define EAI_BADFLAGS 2 /* Invalid value in ai_flags parameter */ +#define EAI_FAIL 3 /* Permanent name resolution failure */ +#define EAI_FAMILY 4 /* Address family not recognized */ +#define EAI_MEMORY 5 /* Memory allocation failure */ +#define EAI_NONAME 6 /* nodename or servname unknown */ +#define EAI_SERVICE 7 /* Service not recognized for socket type */ +#define EAI_SOCKTYPE 8 /* Socket type not recognized */ +#define EAI_SYSTEM 9 /* System error occurred, see errno */ +#define EAI_OVERFLOW 10 /* An argument buffer overflowed */ + +/* Function prototypes. */ +sudo_dso_public int sudo_getaddrinfo(const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res); +sudo_dso_public void sudo_freeaddrinfo(struct addrinfo *ai); +sudo_dso_public const char *sudo_gai_strerror(int ecode); + +/* Map sudo_* to RFC 3493 names. */ +#undef getaddrinfo +#define getaddrinfo(_a, _b, _c, _d) sudo_getaddrinfo((_a), (_b), (_c), (_d)) +#undef freeaddrinfo +#define freeaddrinfo(_a) sudo_freeaddrinfo((_a)) +#undef gai_strerror +#define gai_strerror(_a) sudo_gai_strerror((_a)) + +#endif /* !HAVE_GETADDRINFO */ +#endif /* COMPAT_GETADDRINFO_H */ diff --git a/include/compat/getopt.h b/include/compat/getopt.h new file mode 100644 index 0000000..da99d34 --- /dev/null +++ b/include/compat/getopt.h @@ -0,0 +1,83 @@ +/* $OpenBSD: getopt.h,v 1.2 2008/06/26 05:42:04 ray Exp $ */ +/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ +/* $FreeBSD: head/include/getopt.h 203963 2010-02-16 19:28:10Z imp $ */ + +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef COMPAT_GETOPT_H +#define COMPAT_GETOPT_H + +/* + * GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension. + */ +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +struct option { + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; +}; + +sudo_dso_public int sudo_getopt_long(int, char * const *, const char *, + const struct option *, int *); +#undef getopt_long +#define getopt_long(_a, _b, _c, _d, _e) \ + sudo_getopt_long((_a), (_b), (_c), (_d), (_e)) + +sudo_dso_public int sudo_getopt_long_only(int, char * const *, const char *, + const struct option *, int *); +#undef getopt_long_only +#define getopt_long_only(_a, _b, _c, _d, _e) \ + sudo_getopt_long_only((_a), (_b), (_c), (_d), (_e)) +#if 0 +sudo_dso_public int sudo_getopt(int, char * const [], const char *); +#undef getopt +#define getopt(_a, _b, _c) sudo_getopt((_a), (_b), (_c)) +#endif + +extern char *optarg; /* getopt(3) external variables */ +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; + +#endif /* !COMPAT_GETOPT_H */ diff --git a/include/compat/glob.h b/include/compat/glob.h new file mode 100644 index 0000000..7c06a2e --- /dev/null +++ b/include/compat/glob.h @@ -0,0 +1,78 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)glob.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef COMPAT_GLOB_H +#define COMPAT_GLOB_H + +struct stat; +typedef struct { + size_t gl_pathc; /* Count of total paths so far. */ + size_t gl_matchc; /* Count of paths matching pattern. */ + size_t gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc)(const char *, int); +} glob_t; + +/* Flags */ +#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ +#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ +#define GLOB_ERR 0x0004 /* Return on error. */ +#define GLOB_MARK 0x0008 /* Append / to matching directories. */ +#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ +#define GLOB_NOSORT 0x0020 /* Don't sort. */ +#define GLOB_NOESCAPE 0x0040 /* Disable backslash escaping. */ + +/* Non-POSIX extensions */ +#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */ +#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ +#define GLOB_TILDE 0x0200 /* Expand tilde names from the passwd file. */ +#define GLOB_LIMIT 0x0400 /* Limit pattern match output to ARG_MAX */ + +/* Error values returned by glob(3) */ +#define GLOB_NOSPACE (-1) /* Malloc call failed. */ +#define GLOB_ABORTED (-2) /* Unignored error. */ +#define GLOB_NOMATCH (-3) /* No match and GLOB_NOCHECK not set. */ +#define GLOB_NOSYS (-4) /* Function not supported. */ + +sudo_dso_public int sudo_glob(const char *, int, int (*)(const char *, int), glob_t *); +sudo_dso_public void sudo_globfree(glob_t *); + +#define glob(_a, _b, _c, _d) sudo_glob((_a), (_b), (_c), (_d)) +#define globfree(_a) sudo_globfree((_a)) + +#endif /* !COMPAT_GLOB_H */ diff --git a/include/compat/nss_dbdefs.h b/include/compat/nss_dbdefs.h new file mode 100644 index 0000000..726beae --- /dev/null +++ b/include/compat/nss_dbdefs.h @@ -0,0 +1,110 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2013 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. + */ + +#ifndef COMPAT_NSS_DBDEFS_H +#define COMPAT_NSS_DBDEFS_H + +/* + * Bits of nss_dbdefs.h and nss_common.h needed to implement + * getgrouplist(3) using nss_search(3). + * + * HP-UX does not ship those headers so we need this compatibility header. + * It may also work on other systems that use a Solaris-derived nsswitch + * API. + */ + +#ifdef NEED_HPUX_MUTEX +# include <synch.h> +#endif + +typedef enum { + NSS_SUCCESS, + NSS_NOTFOUND, + NSS_UNAVAIL, + NSS_TRYAGAIN +} nss_status_t; + +typedef struct nss_db_params { + const char *name; + const char *config_name; + const char *default_config; + unsigned int max_active_per_src; + unsigned int max_dormant_per_src; + int flags; + void *finders; + void *private; + void (*cleanup)(struct nss_db_params *); +} nss_db_params_t; + +struct nss_groupsbymem { + const char *username; + gid_t *gid_array; + int maxgids; + int force_slow_way; + int (*str2ent)(const char *instr, int instr_len, void *ent, char *buffer, int buflen); + nss_status_t (*process_cstr)(const char *instr, int instr_len, struct nss_groupsbymem *); + int numgids; +}; + +typedef struct { + void *result; /* group struct to fill in. */ + char *buffer; /* string buffer for above */ + int buflen; /* string buffer size */ +} nss_XbyY_buf_t; + +struct nss_db_state; +typedef struct { + struct nss_db_state *s; +#ifdef NEED_HPUX_MUTEX + lwp_mutex_t lock; +#endif +} nss_db_root_t; + +#ifdef NEED_HPUX_MUTEX +# define NSS_DB_ROOT_INIT { 0, LWP_MUTEX_INITIALIZER } +#else +# define NSS_DB_ROOT_INIT { 0 } +#endif +#define DEFINE_NSS_DB_ROOT(name) nss_db_root_t name = NSS_DB_ROOT_INIT + +/* Backend function to find all groups a user belongs to for initgroups(). */ +#define NSS_DBOP_GROUP_BYMEMBER 6 + +/* str2ent function return values */ +#define NSS_STR_PARSE_SUCCESS 0 +#define NSS_STR_PARSE_PARSE 1 +#define NSS_STR_PARSE_ERANGE 2 + +/* Max length for an /etc/group file line. */ +#define NSS_BUFLEN_GROUP 8192 + +/* HP-UX uses an extra underscore for these functions. */ +#ifdef HAVE___NSS_INITF_GROUP +# define _nss_initf_group __nss_initf_group +#endif +#ifdef HAVE___NSS_XBYY_BUF_ALLOC +# define _nss_XbyY_buf_alloc __nss_XbyY_buf_alloc +# define _nss_XbyY_buf_free __nss_XbyY_buf_free +#endif + +typedef void (*nss_db_initf_t)(nss_db_params_t *); +extern nss_status_t nss_search(nss_db_root_t *, nss_db_initf_t, int search_fnum, void *search_args); +extern nss_XbyY_buf_t *_nss_XbyY_buf_alloc(int struct_size, int buffer_size); +extern void _nss_XbyY_buf_free(nss_XbyY_buf_t *); + +#endif /* COMPAT_NSS_DBDEFS_H */ diff --git a/include/compat/sha2.h b/include/compat/sha2.h new file mode 100644 index 0000000..2908696 --- /dev/null +++ b/include/compat/sha2.h @@ -0,0 +1,100 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2013-2015 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. + */ + +/* + * Derived from the public domain SHA-1 and SHA-2 implementations + * by Steve Reid and Wei Dai respectively. + */ + +#ifndef COMPAT_SHA2_H +#define COMPAT_SHA2_H + +#define SHA224_BLOCK_LENGTH 64 +#define SHA224_DIGEST_LENGTH 28 +#define SHA224_DIGEST_STRING_LENGTH (SHA224_DIGEST_LENGTH * 2 + 1) + +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) + +#define SHA384_BLOCK_LENGTH 128 +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) + +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + +typedef struct { + union { + uint32_t st32[8]; /* sha224 and sha256 */ + uint64_t st64[8]; /* sha384 and sha512 */ + } state; + uint64_t count[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA2_CTX; + +sudo_dso_public void sudo_SHA224Init(SHA2_CTX *ctx); +sudo_dso_public void sudo_SHA224Pad(SHA2_CTX *ctx); +sudo_dso_public void sudo_SHA224Transform(uint32_t state[8], const uint8_t buffer[SHA224_BLOCK_LENGTH]); +sudo_dso_public void sudo_SHA224Update(SHA2_CTX *ctx, const uint8_t *data, size_t len); +sudo_dso_public void sudo_SHA224Final(uint8_t digest[SHA224_DIGEST_LENGTH], SHA2_CTX *ctx); + +#define SHA224Init sudo_SHA224Init +#define SHA224Pad sudo_SHA224Pad +#define SHA224Transform sudo_SHA224Transform +#define SHA224Update sudo_SHA224Update +#define SHA224Final sudo_SHA224Final + +sudo_dso_public void sudo_SHA256Init(SHA2_CTX *ctx); +sudo_dso_public void sudo_SHA256Pad(SHA2_CTX *ctx); +sudo_dso_public void sudo_SHA256Transform(uint32_t state[8], const uint8_t buffer[SHA256_BLOCK_LENGTH]); +sudo_dso_public void sudo_SHA256Update(SHA2_CTX *ctx, const uint8_t *data, size_t len); +sudo_dso_public void sudo_SHA256Final(uint8_t digest[SHA256_DIGEST_LENGTH], SHA2_CTX *ctx); + +#define SHA256Init sudo_SHA256Init +#define SHA256Pad sudo_SHA256Pad +#define SHA256Transform sudo_SHA256Transform +#define SHA256Update sudo_SHA256Update +#define SHA256Final sudo_SHA256Final + +sudo_dso_public void sudo_SHA384Init(SHA2_CTX *ctx); +sudo_dso_public void sudo_SHA384Pad(SHA2_CTX *ctx); +sudo_dso_public void sudo_SHA384Transform(uint64_t state[8], const uint8_t buffer[SHA384_BLOCK_LENGTH]); +sudo_dso_public void sudo_SHA384Update(SHA2_CTX *ctx, const uint8_t *data, size_t len); +sudo_dso_public void sudo_SHA384Final(uint8_t digest[SHA384_DIGEST_LENGTH], SHA2_CTX *ctx); + +#define SHA384Init sudo_SHA384Init +#define SHA384Pad sudo_SHA384Pad +#define SHA384Transform sudo_SHA384Transform +#define SHA384Update sudo_SHA384Update +#define SHA384Final sudo_SHA384Final + +sudo_dso_public void sudo_SHA512Init(SHA2_CTX *ctx); +sudo_dso_public void sudo_SHA512Pad(SHA2_CTX *ctx); +sudo_dso_public void sudo_SHA512Transform(uint64_t state[8], const uint8_t buffer[SHA512_BLOCK_LENGTH]); +sudo_dso_public void sudo_SHA512Update(SHA2_CTX *ctx, const uint8_t *data, size_t len); +sudo_dso_public void sudo_SHA512Final(uint8_t digest[SHA512_DIGEST_LENGTH], SHA2_CTX *ctx); + +#define SHA512Init sudo_SHA512Init +#define SHA512Pad sudo_SHA512Pad +#define SHA512Transform sudo_SHA512Transform +#define SHA512Update sudo_SHA512Update +#define SHA512Final sudo_SHA512Final + +#endif /* COMPAT_SHA2_H */ diff --git a/include/compat/stdbool.h b/include/compat/stdbool.h new file mode 100644 index 0000000..b865a46 --- /dev/null +++ b/include/compat/stdbool.h @@ -0,0 +1,44 @@ +/* $OpenBSD: stdbool.h,v 1.5 2010/07/24 22:17:03 guenther Exp $ */ + +/* + * Written by Marc Espie, September 25, 1999 + * Public domain. + */ + +#ifndef COMPAT_STDBOOL_H +#define COMPAT_STDBOOL_H + +#ifndef __cplusplus + +#if (defined(HAVE__BOOL) && HAVE__BOOL > 0) || defined(lint) +/* Support for _C99: type _Bool is already built-in. */ +#define false 0 +#define true 1 + +#else +/* `_Bool' type must promote to `int' or `unsigned int'. */ +typedef enum { + false = 0, + true = 1 +} _Bool; + +/* And those constants must also be available as macros. */ +#define false false +#define true true + +#endif + +/* User visible type `bool' is provided as a macro which may be redefined */ +#define bool _Bool + +#else /* __cplusplus */ +#define _Bool bool +#define bool bool +#define false false +#define true true +#endif /* __cplusplus */ + +/* Inform that everything is fine */ +#define __bool_true_false_are_defined 1 + +#endif /* COMPAT_STDBOOL_H */ diff --git a/include/hostcheck.h b/include/hostcheck.h new file mode 100644 index 0000000..5c05d36 --- /dev/null +++ b/include/hostcheck.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Laszlo Orban <laszlo.orban@oneidentity.com> + * + * 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. + */ + +#ifndef SUDO_HOSTCHECK_H +#define SUDO_HOSTCHECK_H + +#if defined(HAVE_OPENSSL) + +# include <openssl/x509v3.h> + +typedef enum { + MatchFound, + MatchNotFound, + NoSANPresent, + MalformedCertificate, + Error +} HostnameValidationResult; + +HostnameValidationResult validate_hostname(const X509 *cert, + const char *hostname, const char *ipaddr, int resolve); + +#endif /* HAVE_OPENSSL */ + +#endif /* SUDO_HOSTCHECK_H */ diff --git a/include/intercept.pb-c.h b/include/intercept.pb-c.h new file mode 100644 index 0000000..2ea1683 --- /dev/null +++ b/include/intercept.pb-c.h @@ -0,0 +1,369 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: intercept.proto */ + +#ifndef PROTOBUF_C_intercept_2eproto__INCLUDED +#define PROTOBUF_C_intercept_2eproto__INCLUDED + +#include <protobuf-c/protobuf-c.h> + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1003000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + + +typedef struct InterceptRequest InterceptRequest; +typedef struct InterceptHello InterceptHello; +typedef struct HelloResponse HelloResponse; +typedef struct PolicyCheckRequest PolicyCheckRequest; +typedef struct PolicyAcceptMessage PolicyAcceptMessage; +typedef struct PolicyRejectMessage PolicyRejectMessage; +typedef struct PolicyErrorMessage PolicyErrorMessage; +typedef struct InterceptResponse InterceptResponse; + + +/* --- enums --- */ + + +/* --- messages --- */ + +typedef enum { + INTERCEPT_REQUEST__TYPE__NOT_SET = 0, + INTERCEPT_REQUEST__TYPE_POLICY_CHECK_REQ = 1, + INTERCEPT_REQUEST__TYPE_HELLO = 2 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(INTERCEPT_REQUEST__TYPE__CASE) +} InterceptRequest__TypeCase; + +/* + * Intercept message from sudo_intercept.so. Messages on the + * wire are prefixed with a 32-bit size in network byte order. + */ +struct InterceptRequest +{ + ProtobufCMessage base; + InterceptRequest__TypeCase type_case; + union { + PolicyCheckRequest *policy_check_req; + InterceptHello *hello; + } u; +}; +#define INTERCEPT_REQUEST__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&intercept_request__descriptor) \ + , INTERCEPT_REQUEST__TYPE__NOT_SET, {0} } + + +/* + * Hello message from sudo_intercept.so to main sudo process. + * Sudo sends back the token and localhost port number. + */ +struct InterceptHello +{ + ProtobufCMessage base; + int32_t pid; +}; +#define INTERCEPT_HELLO__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&intercept_hello__descriptor) \ + , 0 } + + +/* + * Sudo response to an InterceptHello from sudo_intercept.so. + * The client uses the port number and token to connect back to sudo. + * If log_only is set there is no InterceptResponse to a PolicyCheckRequest. + */ +struct HelloResponse +{ + ProtobufCMessage base; + uint64_t token_lo; + uint64_t token_hi; + int32_t portno; + protobuf_c_boolean log_only; +}; +#define HELLO_RESPONSE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&hello_response__descriptor) \ + , 0, 0, 0, 0 } + + +/* + * Policy check request from sudo_intercept.so. + * Note that the plugin API only currently supports passing + * the new environment in to the open() function. + */ +struct PolicyCheckRequest +{ + ProtobufCMessage base; + char *command; + char *cwd; + size_t n_argv; + char **argv; + size_t n_envp; + char **envp; + int32_t intercept_fd; +}; +#define POLICY_CHECK_REQUEST__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&policy_check_request__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0,NULL, 0,NULL, 0 } + + +struct PolicyAcceptMessage +{ + ProtobufCMessage base; + char *run_command; + size_t n_run_argv; + char **run_argv; + size_t n_run_envp; + char **run_envp; +}; +#define POLICY_ACCEPT_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&policy_accept_message__descriptor) \ + , (char *)protobuf_c_empty_string, 0,NULL, 0,NULL } + + +struct PolicyRejectMessage +{ + ProtobufCMessage base; + char *reject_message; +}; +#define POLICY_REJECT_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&policy_reject_message__descriptor) \ + , (char *)protobuf_c_empty_string } + + +struct PolicyErrorMessage +{ + ProtobufCMessage base; + char *error_message; +}; +#define POLICY_ERROR_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&policy_error_message__descriptor) \ + , (char *)protobuf_c_empty_string } + + +typedef enum { + INTERCEPT_RESPONSE__TYPE__NOT_SET = 0, + INTERCEPT_RESPONSE__TYPE_HELLO_RESP = 1, + INTERCEPT_RESPONSE__TYPE_ACCEPT_MSG = 2, + INTERCEPT_RESPONSE__TYPE_REJECT_MSG = 3, + INTERCEPT_RESPONSE__TYPE_ERROR_MSG = 4 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(INTERCEPT_RESPONSE__TYPE__CASE) +} InterceptResponse__TypeCase; + +/* + * Response sent back to sudo_intercept.so. + */ +struct InterceptResponse +{ + ProtobufCMessage base; + InterceptResponse__TypeCase type_case; + union { + HelloResponse *hello_resp; + PolicyAcceptMessage *accept_msg; + PolicyRejectMessage *reject_msg; + PolicyErrorMessage *error_msg; + } u; +}; +#define INTERCEPT_RESPONSE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&intercept_response__descriptor) \ + , INTERCEPT_RESPONSE__TYPE__NOT_SET, {0} } + + +/* InterceptRequest methods */ +void intercept_request__init + (InterceptRequest *message); +size_t intercept_request__get_packed_size + (const InterceptRequest *message); +size_t intercept_request__pack + (const InterceptRequest *message, + uint8_t *out); +size_t intercept_request__pack_to_buffer + (const InterceptRequest *message, + ProtobufCBuffer *buffer); +InterceptRequest * + intercept_request__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void intercept_request__free_unpacked + (InterceptRequest *message, + ProtobufCAllocator *allocator); +/* InterceptHello methods */ +void intercept_hello__init + (InterceptHello *message); +size_t intercept_hello__get_packed_size + (const InterceptHello *message); +size_t intercept_hello__pack + (const InterceptHello *message, + uint8_t *out); +size_t intercept_hello__pack_to_buffer + (const InterceptHello *message, + ProtobufCBuffer *buffer); +InterceptHello * + intercept_hello__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void intercept_hello__free_unpacked + (InterceptHello *message, + ProtobufCAllocator *allocator); +/* HelloResponse methods */ +void hello_response__init + (HelloResponse *message); +size_t hello_response__get_packed_size + (const HelloResponse *message); +size_t hello_response__pack + (const HelloResponse *message, + uint8_t *out); +size_t hello_response__pack_to_buffer + (const HelloResponse *message, + ProtobufCBuffer *buffer); +HelloResponse * + hello_response__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void hello_response__free_unpacked + (HelloResponse *message, + ProtobufCAllocator *allocator); +/* PolicyCheckRequest methods */ +void policy_check_request__init + (PolicyCheckRequest *message); +size_t policy_check_request__get_packed_size + (const PolicyCheckRequest *message); +size_t policy_check_request__pack + (const PolicyCheckRequest *message, + uint8_t *out); +size_t policy_check_request__pack_to_buffer + (const PolicyCheckRequest *message, + ProtobufCBuffer *buffer); +PolicyCheckRequest * + policy_check_request__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void policy_check_request__free_unpacked + (PolicyCheckRequest *message, + ProtobufCAllocator *allocator); +/* PolicyAcceptMessage methods */ +void policy_accept_message__init + (PolicyAcceptMessage *message); +size_t policy_accept_message__get_packed_size + (const PolicyAcceptMessage *message); +size_t policy_accept_message__pack + (const PolicyAcceptMessage *message, + uint8_t *out); +size_t policy_accept_message__pack_to_buffer + (const PolicyAcceptMessage *message, + ProtobufCBuffer *buffer); +PolicyAcceptMessage * + policy_accept_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void policy_accept_message__free_unpacked + (PolicyAcceptMessage *message, + ProtobufCAllocator *allocator); +/* PolicyRejectMessage methods */ +void policy_reject_message__init + (PolicyRejectMessage *message); +size_t policy_reject_message__get_packed_size + (const PolicyRejectMessage *message); +size_t policy_reject_message__pack + (const PolicyRejectMessage *message, + uint8_t *out); +size_t policy_reject_message__pack_to_buffer + (const PolicyRejectMessage *message, + ProtobufCBuffer *buffer); +PolicyRejectMessage * + policy_reject_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void policy_reject_message__free_unpacked + (PolicyRejectMessage *message, + ProtobufCAllocator *allocator); +/* PolicyErrorMessage methods */ +void policy_error_message__init + (PolicyErrorMessage *message); +size_t policy_error_message__get_packed_size + (const PolicyErrorMessage *message); +size_t policy_error_message__pack + (const PolicyErrorMessage *message, + uint8_t *out); +size_t policy_error_message__pack_to_buffer + (const PolicyErrorMessage *message, + ProtobufCBuffer *buffer); +PolicyErrorMessage * + policy_error_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void policy_error_message__free_unpacked + (PolicyErrorMessage *message, + ProtobufCAllocator *allocator); +/* InterceptResponse methods */ +void intercept_response__init + (InterceptResponse *message); +size_t intercept_response__get_packed_size + (const InterceptResponse *message); +size_t intercept_response__pack + (const InterceptResponse *message, + uint8_t *out); +size_t intercept_response__pack_to_buffer + (const InterceptResponse *message, + ProtobufCBuffer *buffer); +InterceptResponse * + intercept_response__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void intercept_response__free_unpacked + (InterceptResponse *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*InterceptRequest_Closure) + (const InterceptRequest *message, + void *closure_data); +typedef void (*InterceptHello_Closure) + (const InterceptHello *message, + void *closure_data); +typedef void (*HelloResponse_Closure) + (const HelloResponse *message, + void *closure_data); +typedef void (*PolicyCheckRequest_Closure) + (const PolicyCheckRequest *message, + void *closure_data); +typedef void (*PolicyAcceptMessage_Closure) + (const PolicyAcceptMessage *message, + void *closure_data); +typedef void (*PolicyRejectMessage_Closure) + (const PolicyRejectMessage *message, + void *closure_data); +typedef void (*PolicyErrorMessage_Closure) + (const PolicyErrorMessage *message, + void *closure_data); +typedef void (*InterceptResponse_Closure) + (const InterceptResponse *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCMessageDescriptor intercept_request__descriptor; +extern const ProtobufCMessageDescriptor intercept_hello__descriptor; +extern const ProtobufCMessageDescriptor hello_response__descriptor; +extern const ProtobufCMessageDescriptor policy_check_request__descriptor; +extern const ProtobufCMessageDescriptor policy_accept_message__descriptor; +extern const ProtobufCMessageDescriptor policy_reject_message__descriptor; +extern const ProtobufCMessageDescriptor policy_error_message__descriptor; +extern const ProtobufCMessageDescriptor intercept_response__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_intercept_2eproto__INCLUDED */ diff --git a/include/log_server.pb-c.h b/include/log_server.pb-c.h new file mode 100644 index 0000000..a7238c3 --- /dev/null +++ b/include/log_server.pb-c.h @@ -0,0 +1,790 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: log_server.proto */ + +#ifndef PROTOBUF_C_log_5fserver_2eproto__INCLUDED +#define PROTOBUF_C_log_5fserver_2eproto__INCLUDED + +#include <protobuf-c/protobuf-c.h> + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1003000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + + +typedef struct ClientMessage ClientMessage; +typedef struct TimeSpec TimeSpec; +typedef struct IoBuffer IoBuffer; +typedef struct InfoMessage InfoMessage; +typedef struct InfoMessage__StringList InfoMessage__StringList; +typedef struct InfoMessage__NumberList InfoMessage__NumberList; +typedef struct AcceptMessage AcceptMessage; +typedef struct RejectMessage RejectMessage; +typedef struct ExitMessage ExitMessage; +typedef struct AlertMessage AlertMessage; +typedef struct RestartMessage RestartMessage; +typedef struct ChangeWindowSize ChangeWindowSize; +typedef struct CommandSuspend CommandSuspend; +typedef struct ClientHello ClientHello; +typedef struct ServerMessage ServerMessage; +typedef struct ServerHello ServerHello; + + +/* --- enums --- */ + + +/* --- messages --- */ + +typedef enum { + CLIENT_MESSAGE__TYPE__NOT_SET = 0, + CLIENT_MESSAGE__TYPE_ACCEPT_MSG = 1, + CLIENT_MESSAGE__TYPE_REJECT_MSG = 2, + CLIENT_MESSAGE__TYPE_EXIT_MSG = 3, + CLIENT_MESSAGE__TYPE_RESTART_MSG = 4, + CLIENT_MESSAGE__TYPE_ALERT_MSG = 5, + CLIENT_MESSAGE__TYPE_TTYIN_BUF = 6, + CLIENT_MESSAGE__TYPE_TTYOUT_BUF = 7, + CLIENT_MESSAGE__TYPE_STDIN_BUF = 8, + CLIENT_MESSAGE__TYPE_STDOUT_BUF = 9, + CLIENT_MESSAGE__TYPE_STDERR_BUF = 10, + CLIENT_MESSAGE__TYPE_WINSIZE_EVENT = 11, + CLIENT_MESSAGE__TYPE_SUSPEND_EVENT = 12, + CLIENT_MESSAGE__TYPE_HELLO_MSG = 13 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(CLIENT_MESSAGE__TYPE__CASE) +} ClientMessage__TypeCase; + +/* + * Client message to the server. Messages on the wire are + * prefixed with a 32-bit size in network byte order. + */ +struct ClientMessage +{ + ProtobufCMessage base; + ClientMessage__TypeCase type_case; + union { + AcceptMessage *accept_msg; + RejectMessage *reject_msg; + ExitMessage *exit_msg; + RestartMessage *restart_msg; + AlertMessage *alert_msg; + IoBuffer *ttyin_buf; + IoBuffer *ttyout_buf; + IoBuffer *stdin_buf; + IoBuffer *stdout_buf; + IoBuffer *stderr_buf; + ChangeWindowSize *winsize_event; + CommandSuspend *suspend_event; + ClientHello *hello_msg; + } u; +}; +#define CLIENT_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&client_message__descriptor) \ + , CLIENT_MESSAGE__TYPE__NOT_SET, {0} } + + +/* + * Equivalent of POSIX struct timespec + */ +struct TimeSpec +{ + ProtobufCMessage base; + /* + * seconds + */ + int64_t tv_sec; + /* + * nanoseconds + */ + int32_t tv_nsec; +}; +#define TIME_SPEC__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&time_spec__descriptor) \ + , 0, 0 } + + +/* + * I/O buffer with keystroke data + */ +struct IoBuffer +{ + ProtobufCMessage base; + /* + * elapsed time since last record + */ + TimeSpec *delay; + /* + * keystroke data + */ + ProtobufCBinaryData data; +}; +#define IO_BUFFER__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&io_buffer__descriptor) \ + , NULL, {0,NULL} } + + +struct InfoMessage__StringList +{ + ProtobufCMessage base; + size_t n_strings; + char **strings; +}; +#define INFO_MESSAGE__STRING_LIST__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&info_message__string_list__descriptor) \ + , 0,NULL } + + +struct InfoMessage__NumberList +{ + ProtobufCMessage base; + size_t n_numbers; + int64_t *numbers; +}; +#define INFO_MESSAGE__NUMBER_LIST__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&info_message__number_list__descriptor) \ + , 0,NULL } + + +typedef enum { + INFO_MESSAGE__VALUE__NOT_SET = 0, + INFO_MESSAGE__VALUE_NUMVAL = 2, + INFO_MESSAGE__VALUE_STRVAL = 3, + INFO_MESSAGE__VALUE_STRLISTVAL = 4, + INFO_MESSAGE__VALUE_NUMLISTVAL = 5 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(INFO_MESSAGE__VALUE__CASE) +} InfoMessage__ValueCase; + +/* + * Key/value pairs, like Privilege Manager struct info. + * The value may be a number, a string, or a list of strings. + */ +struct InfoMessage +{ + ProtobufCMessage base; + char *key; + InfoMessage__ValueCase value_case; + union { + int64_t numval; + char *strval; + InfoMessage__StringList *strlistval; + InfoMessage__NumberList *numlistval; + } u; +}; +#define INFO_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&info_message__descriptor) \ + , (char *)protobuf_c_empty_string, INFO_MESSAGE__VALUE__NOT_SET, {0} } + + +/* + * Event log data for command accepted by the policy. + */ +struct AcceptMessage +{ + ProtobufCMessage base; + /* + * when command was submitted + */ + TimeSpec *submit_time; + /* + * key,value event log data + */ + size_t n_info_msgs; + InfoMessage **info_msgs; + /* + * true if I/O logging enabled + */ + protobuf_c_boolean expect_iobufs; +}; +#define ACCEPT_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&accept_message__descriptor) \ + , NULL, 0,NULL, 0 } + + +/* + * Event log data for command rejected by the policy. + */ +struct RejectMessage +{ + ProtobufCMessage base; + /* + * when command was submitted + */ + TimeSpec *submit_time; + /* + * reason command was rejected + */ + char *reason; + /* + * key,value event log data + */ + size_t n_info_msgs; + InfoMessage **info_msgs; +}; +#define REJECT_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&reject_message__descriptor) \ + , NULL, (char *)protobuf_c_empty_string, 0,NULL } + + +/* + * Might revisit runtime and use end_time instead + */ +struct ExitMessage +{ + ProtobufCMessage base; + /* + * total elapsed run time + */ + TimeSpec *run_time; + /* + * 0-255 + */ + int32_t exit_value; + /* + * true if command dumped core + */ + protobuf_c_boolean dumped_core; + /* + * signal name if killed by signal + */ + char *signal; + /* + * if killed due to other error + */ + char *error; +}; +#define EXIT_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&exit_message__descriptor) \ + , NULL, 0, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string } + + +/* + * Alert message, policy module-specific. + */ +struct AlertMessage +{ + ProtobufCMessage base; + /* + * time alert message occurred + */ + TimeSpec *alert_time; + /* + * policy alert error string + */ + char *reason; + /* + * optional key,value event log data + */ + size_t n_info_msgs; + InfoMessage **info_msgs; +}; +#define ALERT_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&alert_message__descriptor) \ + , NULL, (char *)protobuf_c_empty_string, 0,NULL } + + +/* + * Used to restart an existing I/O log on the server. + */ +struct RestartMessage +{ + ProtobufCMessage base; + /* + * ID of log being restarted + */ + char *log_id; + /* + * resume point (elapsed time) + */ + TimeSpec *resume_point; +}; +#define RESTART_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&restart_message__descriptor) \ + , (char *)protobuf_c_empty_string, NULL } + + +/* + * Window size change event. + */ +struct ChangeWindowSize +{ + ProtobufCMessage base; + /* + * elapsed time since last record + */ + TimeSpec *delay; + /* + * new number of rows + */ + int32_t rows; + /* + * new number of columns + */ + int32_t cols; +}; +#define CHANGE_WINDOW_SIZE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&change_window_size__descriptor) \ + , NULL, 0, 0 } + + +/* + * Command suspend/resume event. + */ +struct CommandSuspend +{ + ProtobufCMessage base; + /* + * elapsed time since last record + */ + TimeSpec *delay; + /* + * signal that caused suspend/resume + */ + char *signal; +}; +#define COMMAND_SUSPEND__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&command_suspend__descriptor) \ + , NULL, (char *)protobuf_c_empty_string } + + +/* + * Hello message from client when connecting to server. + */ +struct ClientHello +{ + ProtobufCMessage base; + /* + * free-form client description + */ + char *client_id; +}; +#define CLIENT_HELLO__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&client_hello__descriptor) \ + , (char *)protobuf_c_empty_string } + + +typedef enum { + SERVER_MESSAGE__TYPE__NOT_SET = 0, + SERVER_MESSAGE__TYPE_HELLO = 1, + SERVER_MESSAGE__TYPE_COMMIT_POINT = 2, + SERVER_MESSAGE__TYPE_LOG_ID = 3, + SERVER_MESSAGE__TYPE_ERROR = 4, + SERVER_MESSAGE__TYPE_ABORT = 5 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(SERVER_MESSAGE__TYPE__CASE) +} ServerMessage__TypeCase; + +/* + * Server messages to the client. Messages on the wire are + * prefixed with a 32-bit size in network byte order. + */ +struct ServerMessage +{ + ProtobufCMessage base; + ServerMessage__TypeCase type_case; + union { + /* + * server hello message + */ + ServerHello *hello; + /* + * cumulative time of records stored + */ + TimeSpec *commit_point; + /* + * ID of server-side I/O log + */ + char *log_id; + /* + * error message from server + */ + char *error; + /* + * abort message, kill command + */ + char *abort; + } u; +}; +#define SERVER_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&server_message__descriptor) \ + , SERVER_MESSAGE__TYPE__NOT_SET, {0} } + + +/* + * Hello message from server when client connects. + */ +struct ServerHello +{ + ProtobufCMessage base; + /* + * free-form server description + */ + char *server_id; + /* + * optional redirect if busy + */ + char *redirect; + /* + * optional list of known servers + */ + size_t n_servers; + char **servers; + /* + * flag: server supports sub-commands + */ + protobuf_c_boolean subcommands; +}; +#define SERVER_HELLO__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&server_hello__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0,NULL, 0 } + + +/* ClientMessage methods */ +void client_message__init + (ClientMessage *message); +size_t client_message__get_packed_size + (const ClientMessage *message); +size_t client_message__pack + (const ClientMessage *message, + uint8_t *out); +size_t client_message__pack_to_buffer + (const ClientMessage *message, + ProtobufCBuffer *buffer); +ClientMessage * + client_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void client_message__free_unpacked + (ClientMessage *message, + ProtobufCAllocator *allocator); +/* TimeSpec methods */ +void time_spec__init + (TimeSpec *message); +size_t time_spec__get_packed_size + (const TimeSpec *message); +size_t time_spec__pack + (const TimeSpec *message, + uint8_t *out); +size_t time_spec__pack_to_buffer + (const TimeSpec *message, + ProtobufCBuffer *buffer); +TimeSpec * + time_spec__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void time_spec__free_unpacked + (TimeSpec *message, + ProtobufCAllocator *allocator); +/* IoBuffer methods */ +void io_buffer__init + (IoBuffer *message); +size_t io_buffer__get_packed_size + (const IoBuffer *message); +size_t io_buffer__pack + (const IoBuffer *message, + uint8_t *out); +size_t io_buffer__pack_to_buffer + (const IoBuffer *message, + ProtobufCBuffer *buffer); +IoBuffer * + io_buffer__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void io_buffer__free_unpacked + (IoBuffer *message, + ProtobufCAllocator *allocator); +/* InfoMessage__StringList methods */ +void info_message__string_list__init + (InfoMessage__StringList *message); +/* InfoMessage__NumberList methods */ +void info_message__number_list__init + (InfoMessage__NumberList *message); +/* InfoMessage methods */ +void info_message__init + (InfoMessage *message); +size_t info_message__get_packed_size + (const InfoMessage *message); +size_t info_message__pack + (const InfoMessage *message, + uint8_t *out); +size_t info_message__pack_to_buffer + (const InfoMessage *message, + ProtobufCBuffer *buffer); +InfoMessage * + info_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void info_message__free_unpacked + (InfoMessage *message, + ProtobufCAllocator *allocator); +/* AcceptMessage methods */ +void accept_message__init + (AcceptMessage *message); +size_t accept_message__get_packed_size + (const AcceptMessage *message); +size_t accept_message__pack + (const AcceptMessage *message, + uint8_t *out); +size_t accept_message__pack_to_buffer + (const AcceptMessage *message, + ProtobufCBuffer *buffer); +AcceptMessage * + accept_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void accept_message__free_unpacked + (AcceptMessage *message, + ProtobufCAllocator *allocator); +/* RejectMessage methods */ +void reject_message__init + (RejectMessage *message); +size_t reject_message__get_packed_size + (const RejectMessage *message); +size_t reject_message__pack + (const RejectMessage *message, + uint8_t *out); +size_t reject_message__pack_to_buffer + (const RejectMessage *message, + ProtobufCBuffer *buffer); +RejectMessage * + reject_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void reject_message__free_unpacked + (RejectMessage *message, + ProtobufCAllocator *allocator); +/* ExitMessage methods */ +void exit_message__init + (ExitMessage *message); +size_t exit_message__get_packed_size + (const ExitMessage *message); +size_t exit_message__pack + (const ExitMessage *message, + uint8_t *out); +size_t exit_message__pack_to_buffer + (const ExitMessage *message, + ProtobufCBuffer *buffer); +ExitMessage * + exit_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void exit_message__free_unpacked + (ExitMessage *message, + ProtobufCAllocator *allocator); +/* AlertMessage methods */ +void alert_message__init + (AlertMessage *message); +size_t alert_message__get_packed_size + (const AlertMessage *message); +size_t alert_message__pack + (const AlertMessage *message, + uint8_t *out); +size_t alert_message__pack_to_buffer + (const AlertMessage *message, + ProtobufCBuffer *buffer); +AlertMessage * + alert_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void alert_message__free_unpacked + (AlertMessage *message, + ProtobufCAllocator *allocator); +/* RestartMessage methods */ +void restart_message__init + (RestartMessage *message); +size_t restart_message__get_packed_size + (const RestartMessage *message); +size_t restart_message__pack + (const RestartMessage *message, + uint8_t *out); +size_t restart_message__pack_to_buffer + (const RestartMessage *message, + ProtobufCBuffer *buffer); +RestartMessage * + restart_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void restart_message__free_unpacked + (RestartMessage *message, + ProtobufCAllocator *allocator); +/* ChangeWindowSize methods */ +void change_window_size__init + (ChangeWindowSize *message); +size_t change_window_size__get_packed_size + (const ChangeWindowSize *message); +size_t change_window_size__pack + (const ChangeWindowSize *message, + uint8_t *out); +size_t change_window_size__pack_to_buffer + (const ChangeWindowSize *message, + ProtobufCBuffer *buffer); +ChangeWindowSize * + change_window_size__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void change_window_size__free_unpacked + (ChangeWindowSize *message, + ProtobufCAllocator *allocator); +/* CommandSuspend methods */ +void command_suspend__init + (CommandSuspend *message); +size_t command_suspend__get_packed_size + (const CommandSuspend *message); +size_t command_suspend__pack + (const CommandSuspend *message, + uint8_t *out); +size_t command_suspend__pack_to_buffer + (const CommandSuspend *message, + ProtobufCBuffer *buffer); +CommandSuspend * + command_suspend__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void command_suspend__free_unpacked + (CommandSuspend *message, + ProtobufCAllocator *allocator); +/* ClientHello methods */ +void client_hello__init + (ClientHello *message); +size_t client_hello__get_packed_size + (const ClientHello *message); +size_t client_hello__pack + (const ClientHello *message, + uint8_t *out); +size_t client_hello__pack_to_buffer + (const ClientHello *message, + ProtobufCBuffer *buffer); +ClientHello * + client_hello__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void client_hello__free_unpacked + (ClientHello *message, + ProtobufCAllocator *allocator); +/* ServerMessage methods */ +void server_message__init + (ServerMessage *message); +size_t server_message__get_packed_size + (const ServerMessage *message); +size_t server_message__pack + (const ServerMessage *message, + uint8_t *out); +size_t server_message__pack_to_buffer + (const ServerMessage *message, + ProtobufCBuffer *buffer); +ServerMessage * + server_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void server_message__free_unpacked + (ServerMessage *message, + ProtobufCAllocator *allocator); +/* ServerHello methods */ +void server_hello__init + (ServerHello *message); +size_t server_hello__get_packed_size + (const ServerHello *message); +size_t server_hello__pack + (const ServerHello *message, + uint8_t *out); +size_t server_hello__pack_to_buffer + (const ServerHello *message, + ProtobufCBuffer *buffer); +ServerHello * + server_hello__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void server_hello__free_unpacked + (ServerHello *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*ClientMessage_Closure) + (const ClientMessage *message, + void *closure_data); +typedef void (*TimeSpec_Closure) + (const TimeSpec *message, + void *closure_data); +typedef void (*IoBuffer_Closure) + (const IoBuffer *message, + void *closure_data); +typedef void (*InfoMessage__StringList_Closure) + (const InfoMessage__StringList *message, + void *closure_data); +typedef void (*InfoMessage__NumberList_Closure) + (const InfoMessage__NumberList *message, + void *closure_data); +typedef void (*InfoMessage_Closure) + (const InfoMessage *message, + void *closure_data); +typedef void (*AcceptMessage_Closure) + (const AcceptMessage *message, + void *closure_data); +typedef void (*RejectMessage_Closure) + (const RejectMessage *message, + void *closure_data); +typedef void (*ExitMessage_Closure) + (const ExitMessage *message, + void *closure_data); +typedef void (*AlertMessage_Closure) + (const AlertMessage *message, + void *closure_data); +typedef void (*RestartMessage_Closure) + (const RestartMessage *message, + void *closure_data); +typedef void (*ChangeWindowSize_Closure) + (const ChangeWindowSize *message, + void *closure_data); +typedef void (*CommandSuspend_Closure) + (const CommandSuspend *message, + void *closure_data); +typedef void (*ClientHello_Closure) + (const ClientHello *message, + void *closure_data); +typedef void (*ServerMessage_Closure) + (const ServerMessage *message, + void *closure_data); +typedef void (*ServerHello_Closure) + (const ServerHello *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCMessageDescriptor client_message__descriptor; +extern const ProtobufCMessageDescriptor time_spec__descriptor; +extern const ProtobufCMessageDescriptor io_buffer__descriptor; +extern const ProtobufCMessageDescriptor info_message__descriptor; +extern const ProtobufCMessageDescriptor info_message__string_list__descriptor; +extern const ProtobufCMessageDescriptor info_message__number_list__descriptor; +extern const ProtobufCMessageDescriptor accept_message__descriptor; +extern const ProtobufCMessageDescriptor reject_message__descriptor; +extern const ProtobufCMessageDescriptor exit_message__descriptor; +extern const ProtobufCMessageDescriptor alert_message__descriptor; +extern const ProtobufCMessageDescriptor restart_message__descriptor; +extern const ProtobufCMessageDescriptor change_window_size__descriptor; +extern const ProtobufCMessageDescriptor command_suspend__descriptor; +extern const ProtobufCMessageDescriptor client_hello__descriptor; +extern const ProtobufCMessageDescriptor server_message__descriptor; +extern const ProtobufCMessageDescriptor server_hello__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_log_5fserver_2eproto__INCLUDED */ diff --git a/include/protobuf-c/protobuf-c.h b/include/protobuf-c/protobuf-c.h new file mode 100644 index 0000000..442abf6 --- /dev/null +++ b/include/protobuf-c/protobuf-c.h @@ -0,0 +1,1110 @@ +/* + * Copyright (c) 2008-2022, Dave Benson and the protobuf-c authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*! \file + * \mainpage Introduction + * + * This is [protobuf-c], a C implementation of [Protocol Buffers]. + * + * This file defines the public API for the `libprotobuf-c` support library. + * This API includes interfaces that can be used directly by client code as well + * as the interfaces used by the code generated by the `protoc-c` compiler. + * + * The `libprotobuf-c` support library performs the actual serialization and + * deserialization of Protocol Buffers messages. It interacts with structures, + * definitions, and metadata generated by the `protoc-c` compiler from .proto + * files. + * + * \authors Dave Benson and the `protobuf-c` authors. + * + * \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. + * + * [protobuf-c]: https://github.com/protobuf-c/protobuf-c + * [Protocol Buffers]: https://developers.google.com/protocol-buffers/ + * [BSD-2-Clause]: http://opensource.org/licenses/BSD-2-Clause + * + * \page gencode Generated Code + * + * For each enum, we generate a C enum. For each message, we generate a C + * structure which can be cast to a `ProtobufCMessage`. + * + * For each enum and message, we generate a descriptor object that allows us to + * implement a kind of reflection on the structures. + * + * First, some naming conventions: + * + * - The name of the type for enums and messages and services is camel case + * (meaning WordsAreCrammedTogether) except that double underscores are used + * to delimit scopes. For example, the following `.proto` file: + * +~~~{.proto} + package foo.bar; + message BazBah { + optional int32 val = 1; + } +~~~ + * + * would generate a C type `Foo__Bar__BazBah`. + * + * - Identifiers for functions and globals are all lowercase, with camel case + * words separated by single underscores. For example, one of the function + * prototypes generated by `protoc-c` for the above example: + * +~~~{.c} +Foo__Bar__BazBah * + foo__bar__baz_bah__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +~~~ + * + * - Identifiers for enum values contain an uppercase prefix which embeds the + * package name and the enum type name. + * + * - A double underscore is used to separate further components of identifier + * names. + * + * For example, in the name of the unpack function above, the package name + * `foo.bar` has become `foo__bar`, the message name BazBah has become + * `baz_bah`, and the method name is `unpack`. These are all joined with double + * underscores to form the C identifier `foo__bar__baz_bah__unpack`. + * + * We also generate descriptor objects for messages and enums. These are + * declared in the `.pb-c.h` files: + * +~~~{.c} +extern const ProtobufCMessageDescriptor foo__bar__baz_bah__descriptor; +~~~ + * + * The message structures all begin with `ProtobufCMessageDescriptor *` which is + * sufficient to allow them to be cast to `ProtobufCMessage`. + * + * For each message defined in a `.proto` file, we generate a number of + * functions and macros. Each function name contains a prefix based on the + * package name and message name in order to make it a unique C identifier. + * + * - `INIT`. Statically initializes a message object, initializing its + * descriptor and setting its fields to default values. Uninitialized + * messages cannot be processed by the protobuf-c library. + * +~~~{.c} +#define FOO__BAR__BAZ_BAH__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&foo__bar__baz_bah__descriptor), 0 } +~~~ + * - `init()`. Initializes a message object, initializing its descriptor and + * setting its fields to default values. Uninitialized messages cannot be + * processed by the protobuf-c library. + * +~~~{.c} +void foo__bar__baz_bah__init + (Foo__Bar__BazBah *message); +~~~ + * - `unpack()`. Unpacks data for a particular message format. Note that the + * `allocator` parameter is usually `NULL` to indicate that the system's + * `malloc()` and `free()` functions should be used for dynamically allocating + * memory. + * +~~~{.c} +Foo__Bar__BazBah * + foo__bar__baz_bah__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +~~~ + * + * - `free_unpacked()`. Frees a message object obtained with the `unpack()` + * method. Freeing `NULL` is allowed (the same as with `free()`). + * +~~~{.c} +void foo__bar__baz_bah__free_unpacked + (Foo__Bar__BazBah *message, + ProtobufCAllocator *allocator); +~~~ + * + * - `get_packed_size()`. Calculates the length in bytes of the serialized + * representation of the message object. + * +~~~{.c} +size_t foo__bar__baz_bah__get_packed_size + (const Foo__Bar__BazBah *message); +~~~ + * + * - `pack()`. Pack a message object into a preallocated buffer. Assumes that + * the buffer is large enough. (Use `get_packed_size()` first.) + * +~~~{.c} +size_t foo__bar__baz_bah__pack + (const Foo__Bar__BazBah *message, + uint8_t *out); +~~~ + * + * - `pack_to_buffer()`. Packs a message into a "virtual buffer". This is an + * object which defines an "append bytes" callback to consume data as it is + * serialized. + * +~~~{.c} +size_t foo__bar__baz_bah__pack_to_buffer + (const Foo__Bar__BazBah *message, + ProtobufCBuffer *buffer); +~~~ + * + * \page pack Packing and unpacking messages + * + * To pack a message, first compute the packed size of the message with + * protobuf_c_message_get_packed_size(), then allocate a buffer of at least + * that size, then call protobuf_c_message_pack(). + * + * Alternatively, a message can be serialized without calculating the final size + * first. Use the protobuf_c_message_pack_to_buffer() function and provide a + * ProtobufCBuffer object which implements an "append" method that consumes + * data. + * + * To unpack a message, call the protobuf_c_message_unpack() function. The + * result can be cast to an object of the type that matches the descriptor for + * the message. + * + * The result of unpacking a message should be freed with + * protobuf_c_message_free_unpacked(). + */ + +#ifndef PROTOBUF_C_H +#define PROTOBUF_C_H + +#include <assert.h> +#include <limits.h> +#include <stddef.h> +#include <inttypes.h> /* stdint.h not present on older systems */ + +#ifdef __cplusplus +# define PROTOBUF_C__BEGIN_DECLS extern "C" { +# define PROTOBUF_C__END_DECLS } +#else +# define PROTOBUF_C__BEGIN_DECLS +# define PROTOBUF_C__END_DECLS +#endif + +PROTOBUF_C__BEGIN_DECLS + +#if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB) +# ifdef PROTOBUF_C_EXPORT +# define PROTOBUF_C__API __declspec(dllexport) +# else +# define PROTOBUF_C__API __declspec(dllimport) +# endif +#else +# define PROTOBUF_C__API +#endif + +#if !defined(PROTOBUF_C__NO_DEPRECATED) && \ + ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define PROTOBUF_C__DEPRECATED __attribute__((__deprecated__)) +#else +# define PROTOBUF_C__DEPRECATED +#endif + +#ifndef PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE + #define PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(enum_name) \ + , _##enum_name##_IS_INT_SIZE = INT_MAX +#endif + +#define PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC 0x14159bc3 +#define PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC 0x28aaeef9 +#define PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC 0x114315af + +/* Empty string used for initializers */ +#if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB) +static const char protobuf_c_empty_string[] = ""; +#else +extern const char protobuf_c_empty_string[]; +#endif + +/** + * \defgroup api Public API + * + * This is the public API for `libprotobuf-c`. These interfaces are stable and + * subject to Semantic Versioning guarantees. + * + * @{ + */ + +/** + * Values for the `flags` word in `ProtobufCFieldDescriptor`. + */ +typedef enum { + /** Set if the field is repeated and marked with the `packed` option. */ + PROTOBUF_C_FIELD_FLAG_PACKED = (1 << 0), + + /** Set if the field is marked with the `deprecated` option. */ + PROTOBUF_C_FIELD_FLAG_DEPRECATED = (1 << 1), + + /** Set if the field is a member of a oneof (union). */ + PROTOBUF_C_FIELD_FLAG_ONEOF = (1 << 2), +} ProtobufCFieldFlag; + +/** + * Message field rules. + * + * \see [Defining A Message Type] in the Protocol Buffers documentation. + * + * [Defining A Message Type]: + * https://developers.google.com/protocol-buffers/docs/proto#simple + */ +typedef enum { + /** A well-formed message must have exactly one of this field. */ + PROTOBUF_C_LABEL_REQUIRED, + + /** + * A well-formed message can have zero or one of this field (but not + * more than one). + */ + PROTOBUF_C_LABEL_OPTIONAL, + + /** + * This field can be repeated any number of times (including zero) in a + * well-formed message. The order of the repeated values will be + * preserved. + */ + PROTOBUF_C_LABEL_REPEATED, + + /** + * This field has no label. This is valid only in proto3 and is + * equivalent to OPTIONAL but no "has" quantifier will be consulted. + */ + PROTOBUF_C_LABEL_NONE, +} ProtobufCLabel; + +/** + * Field value types. + * + * \see [Scalar Value Types] in the Protocol Buffers documentation. + * + * [Scalar Value Types]: + * https://developers.google.com/protocol-buffers/docs/proto#scalar + */ +typedef enum { + PROTOBUF_C_TYPE_INT32, /**< int32 */ + PROTOBUF_C_TYPE_SINT32, /**< signed int32 */ + PROTOBUF_C_TYPE_SFIXED32, /**< signed int32 (4 bytes) */ + PROTOBUF_C_TYPE_INT64, /**< int64 */ + PROTOBUF_C_TYPE_SINT64, /**< signed int64 */ + PROTOBUF_C_TYPE_SFIXED64, /**< signed int64 (8 bytes) */ + PROTOBUF_C_TYPE_UINT32, /**< unsigned int32 */ + PROTOBUF_C_TYPE_FIXED32, /**< unsigned int32 (4 bytes) */ + PROTOBUF_C_TYPE_UINT64, /**< unsigned int64 */ + PROTOBUF_C_TYPE_FIXED64, /**< unsigned int64 (8 bytes) */ + PROTOBUF_C_TYPE_FLOAT, /**< float */ + PROTOBUF_C_TYPE_DOUBLE, /**< double */ + PROTOBUF_C_TYPE_BOOL, /**< boolean */ + PROTOBUF_C_TYPE_ENUM, /**< enumerated type */ + PROTOBUF_C_TYPE_STRING, /**< UTF-8 or ASCII string */ + PROTOBUF_C_TYPE_BYTES, /**< arbitrary byte sequence */ + PROTOBUF_C_TYPE_MESSAGE, /**< nested message */ +} ProtobufCType; + +/** + * Field wire types. + * + * \see [Message Structure] in the Protocol Buffers documentation. + * + * [Message Structure]: + * https://developers.google.com/protocol-buffers/docs/encoding#structure + */ +typedef enum { + PROTOBUF_C_WIRE_TYPE_VARINT = 0, + PROTOBUF_C_WIRE_TYPE_64BIT = 1, + PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED = 2, + /* "Start group" and "end group" wire types are unsupported. */ + PROTOBUF_C_WIRE_TYPE_32BIT = 5, +} ProtobufCWireType; + +struct ProtobufCAllocator; +struct ProtobufCBinaryData; +struct ProtobufCBuffer; +struct ProtobufCBufferSimple; +struct ProtobufCEnumDescriptor; +struct ProtobufCEnumValue; +struct ProtobufCEnumValueIndex; +struct ProtobufCFieldDescriptor; +struct ProtobufCIntRange; +struct ProtobufCMessage; +struct ProtobufCMessageDescriptor; +struct ProtobufCMessageUnknownField; +struct ProtobufCMethodDescriptor; +struct ProtobufCService; +struct ProtobufCServiceDescriptor; + +typedef struct ProtobufCAllocator ProtobufCAllocator; +typedef struct ProtobufCBinaryData ProtobufCBinaryData; +typedef struct ProtobufCBuffer ProtobufCBuffer; +typedef struct ProtobufCBufferSimple ProtobufCBufferSimple; +typedef struct ProtobufCEnumDescriptor ProtobufCEnumDescriptor; +typedef struct ProtobufCEnumValue ProtobufCEnumValue; +typedef struct ProtobufCEnumValueIndex ProtobufCEnumValueIndex; +typedef struct ProtobufCFieldDescriptor ProtobufCFieldDescriptor; +typedef struct ProtobufCIntRange ProtobufCIntRange; +typedef struct ProtobufCMessage ProtobufCMessage; +typedef struct ProtobufCMessageDescriptor ProtobufCMessageDescriptor; +typedef struct ProtobufCMessageUnknownField ProtobufCMessageUnknownField; +typedef struct ProtobufCMethodDescriptor ProtobufCMethodDescriptor; +typedef struct ProtobufCService ProtobufCService; +typedef struct ProtobufCServiceDescriptor ProtobufCServiceDescriptor; + +/** Boolean type. */ +typedef int protobuf_c_boolean; + +typedef void (*ProtobufCClosure)(const ProtobufCMessage *, void *closure_data); +typedef void (*ProtobufCMessageInit)(ProtobufCMessage *); +typedef void (*ProtobufCServiceDestroy)(ProtobufCService *); + +/** + * Structure for defining a custom memory allocator. + */ +struct ProtobufCAllocator { + /** Function to allocate memory. */ + void *(*alloc)(void *allocator_data, size_t size); + + /** Function to free memory. */ + void (*free)(void *allocator_data, void *pointer); + + /** Opaque pointer passed to `alloc` and `free` functions. */ + void *allocator_data; +}; + +/** + * Structure for the protobuf `bytes` scalar type. + * + * The data contained in a `ProtobufCBinaryData` is an arbitrary sequence of + * bytes. It may contain embedded `NUL` characters and is not required to be + * `NUL`-terminated. + */ +struct ProtobufCBinaryData { + size_t len; /**< Number of bytes in the `data` field. */ + uint8_t *data; /**< Data bytes. */ +}; + +/** + * Structure for defining a virtual append-only buffer. Used by + * protobuf_c_message_pack_to_buffer() to abstract the consumption of serialized + * bytes. + * + * `ProtobufCBuffer` "subclasses" may be defined on the stack. For example, to + * write to a `FILE` object: + * +~~~{.c} +typedef struct { + ProtobufCBuffer base; + FILE *fp; +} BufferAppendToFile; + +static void +my_buffer_file_append(ProtobufCBuffer *buffer, + size_t len, + const uint8_t *data) +{ + BufferAppendToFile *file_buf = (BufferAppendToFile *) buffer; + fwrite(data, len, 1, file_buf->fp); // XXX: No error handling! +} +~~~ + * + * To use this new type of ProtobufCBuffer, it could be called as follows: + * +~~~{.c} +... +BufferAppendToFile tmp = {0}; +tmp.base.append = my_buffer_file_append; +tmp.fp = fp; +protobuf_c_message_pack_to_buffer(&message, &tmp); +... +~~~ + */ +struct ProtobufCBuffer { + /** Append function. Consumes the `len` bytes stored at `data`. */ + void (*append)(ProtobufCBuffer *buffer, + size_t len, + const uint8_t *data); +}; + +/** + * Simple buffer "subclass" of `ProtobufCBuffer`. + * + * A `ProtobufCBufferSimple` object is declared on the stack and uses a + * scratch buffer provided by the user for the initial allocation. It performs + * exponential resizing, using dynamically allocated memory. A + * `ProtobufCBufferSimple` object can be created and used as follows: + * +~~~{.c} +uint8_t pad[128]; +ProtobufCBufferSimple simple = PROTOBUF_C_BUFFER_SIMPLE_INIT(pad); +ProtobufCBuffer *buffer = (ProtobufCBuffer *) &simple; +~~~ + * + * `buffer` can now be used with `protobuf_c_message_pack_to_buffer()`. Once a + * message has been serialized to a `ProtobufCBufferSimple` object, the + * serialized data bytes can be accessed from the `.data` field. + * + * To free the memory allocated by a `ProtobufCBufferSimple` object, if any, + * call PROTOBUF_C_BUFFER_SIMPLE_CLEAR() on the object, for example: + * +~~~{.c} +PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple); +~~~ + * + * \see PROTOBUF_C_BUFFER_SIMPLE_INIT + * \see PROTOBUF_C_BUFFER_SIMPLE_CLEAR + */ +struct ProtobufCBufferSimple { + /** "Base class". */ + ProtobufCBuffer base; + /** Number of bytes allocated in `data`. */ + size_t alloced; + /** Number of bytes currently stored in `data`. */ + size_t len; + /** Data bytes. */ + uint8_t *data; + /** Whether `data` must be freed. */ + protobuf_c_boolean must_free_data; + /** Allocator to use. May be NULL to indicate the system allocator. */ + ProtobufCAllocator *allocator; +}; + +/** + * Describes an enumeration as a whole, with all of its values. + */ +struct ProtobufCEnumDescriptor { + /** Magic value checked to ensure that the API is used correctly. */ + uint32_t magic; + + /** The qualified name (e.g., "namespace.Type"). */ + const char *name; + /** The unqualified name as given in the .proto file (e.g., "Type"). */ + const char *short_name; + /** Identifier used in generated C code. */ + const char *c_name; + /** The dot-separated namespace. */ + const char *package_name; + + /** Number elements in `values`. */ + unsigned n_values; + /** Array of distinct values, sorted by numeric value. */ + const ProtobufCEnumValue *values; + + /** Number of elements in `values_by_name`. */ + unsigned n_value_names; + /** Array of named values, including aliases, sorted by name. */ + const ProtobufCEnumValueIndex *values_by_name; + + /** Number of elements in `value_ranges`. */ + unsigned n_value_ranges; + /** Value ranges, for faster lookups by numeric value. */ + const ProtobufCIntRange *value_ranges; + + /** Reserved for future use. */ + void *reserved1; + /** Reserved for future use. */ + void *reserved2; + /** Reserved for future use. */ + void *reserved3; + /** Reserved for future use. */ + void *reserved4; +}; + +/** + * Represents a single value of an enumeration. + */ +struct ProtobufCEnumValue { + /** The string identifying this value in the .proto file. */ + const char *name; + + /** The string identifying this value in generated C code. */ + const char *c_name; + + /** The numeric value assigned in the .proto file. */ + int value; +}; + +/** + * Used by `ProtobufCEnumDescriptor` to look up enum values. + */ +struct ProtobufCEnumValueIndex { + /** Name of the enum value. */ + const char *name; + /** Index into values[] array. */ + unsigned index; +}; + +/** + * Describes a single field in a message. + */ +struct ProtobufCFieldDescriptor { + /** Name of the field as given in the .proto file. */ + const char *name; + + /** Tag value of the field as given in the .proto file. */ + uint32_t id; + + /** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */ + ProtobufCLabel label; + + /** The type of the field. */ + ProtobufCType type; + + /** + * The offset in bytes of the message's C structure's quantifier field + * (the `has_MEMBER` field for optional members or the `n_MEMBER` field + * for repeated members or the case enum for oneofs). + */ + unsigned quantifier_offset; + + /** + * The offset in bytes into the message's C structure for the member + * itself. + */ + unsigned offset; + + /** + * A type-specific descriptor. + * + * If `type` is `PROTOBUF_C_TYPE_ENUM`, then `descriptor` points to the + * corresponding `ProtobufCEnumDescriptor`. + * + * If `type` is `PROTOBUF_C_TYPE_MESSAGE`, then `descriptor` points to + * the corresponding `ProtobufCMessageDescriptor`. + * + * Otherwise this field is NULL. + */ + const void *descriptor; /* for MESSAGE and ENUM types */ + + /** The default value for this field, if defined. May be NULL. */ + const void *default_value; + + /** + * A flag word. Zero or more of the bits defined in the + * `ProtobufCFieldFlag` enum may be set. + */ + uint32_t flags; + + /** Reserved for future use. */ + unsigned reserved_flags; + /** Reserved for future use. */ + void *reserved2; + /** Reserved for future use. */ + void *reserved3; +}; + +/** + * Helper structure for optimizing int => index lookups in the case + * where the keys are mostly consecutive values, as they presumably are for + * enums and fields. + * + * The data structures requires that the values in the original array are + * sorted. + */ +struct ProtobufCIntRange { + int start_value; + unsigned orig_index; + /* + * NOTE: the number of values in the range can be inferred by looking + * at the next element's orig_index. A dummy element is added to make + * this simple. + */ +}; + +/** + * An instance of a message. + * + * `ProtobufCMessage` is a light-weight "base class" for all messages. + * + * In particular, `ProtobufCMessage` doesn't have any allocation policy + * associated with it. That's because it's common to create `ProtobufCMessage` + * objects on the stack. In fact, that's what we recommend for sending messages. + * If the object is allocated from the stack, you can't really have a memory + * leak. + * + * This means that calls to functions like protobuf_c_message_unpack() which + * return a `ProtobufCMessage` must be paired with a call to a free function, + * like protobuf_c_message_free_unpacked(). + */ +struct ProtobufCMessage { + /** The descriptor for this message type. */ + const ProtobufCMessageDescriptor *descriptor; + /** The number of elements in `unknown_fields`. */ + unsigned n_unknown_fields; + /** The fields that weren't recognized by the parser. */ + ProtobufCMessageUnknownField *unknown_fields; +}; + +/** + * Describes a message. + */ +struct ProtobufCMessageDescriptor { + /** Magic value checked to ensure that the API is used correctly. */ + uint32_t magic; + + /** The qualified name (e.g., "namespace.Type"). */ + const char *name; + /** The unqualified name as given in the .proto file (e.g., "Type"). */ + const char *short_name; + /** Identifier used in generated C code. */ + const char *c_name; + /** The dot-separated namespace. */ + const char *package_name; + + /** + * Size in bytes of the C structure representing an instance of this + * type of message. + */ + size_t sizeof_message; + + /** Number of elements in `fields`. */ + unsigned n_fields; + /** Field descriptors, sorted by tag number. */ + const ProtobufCFieldDescriptor *fields; + /** Used for looking up fields by name. */ + const unsigned *fields_sorted_by_name; + + /** Number of elements in `field_ranges`. */ + unsigned n_field_ranges; + /** Used for looking up fields by id. */ + const ProtobufCIntRange *field_ranges; + + /** Message initialisation function. */ + ProtobufCMessageInit message_init; + + /** Reserved for future use. */ + void *reserved1; + /** Reserved for future use. */ + void *reserved2; + /** Reserved for future use. */ + void *reserved3; +}; + +/** + * An unknown message field. + */ +struct ProtobufCMessageUnknownField { + /** The tag number. */ + uint32_t tag; + /** The wire type of the field. */ + ProtobufCWireType wire_type; + /** Number of bytes in `data`. */ + size_t len; + /** Field data. */ + uint8_t *data; +}; + +/** + * Method descriptor. + */ +struct ProtobufCMethodDescriptor { + /** Method name. */ + const char *name; + /** Input message descriptor. */ + const ProtobufCMessageDescriptor *input; + /** Output message descriptor. */ + const ProtobufCMessageDescriptor *output; +}; + +/** + * Service. + */ +struct ProtobufCService { + /** Service descriptor. */ + const ProtobufCServiceDescriptor *descriptor; + /** Function to invoke the service. */ + void (*invoke)(ProtobufCService *service, + unsigned method_index, + const ProtobufCMessage *input, + ProtobufCClosure closure, + void *closure_data); + /** Function to destroy the service. */ + void (*destroy)(ProtobufCService *service); +}; + +/** + * Service descriptor. + */ +struct ProtobufCServiceDescriptor { + /** Magic value checked to ensure that the API is used correctly. */ + uint32_t magic; + + /** Service name. */ + const char *name; + /** Short version of service name. */ + const char *short_name; + /** C identifier for the service name. */ + const char *c_name; + /** Package name. */ + const char *package; + /** Number of elements in `methods`. */ + unsigned n_methods; + /** Method descriptors, in the order defined in the .proto file. */ + const ProtobufCMethodDescriptor *methods; + /** Sort index of methods. */ + const unsigned *method_indices_by_name; +}; + +/** + * Get the version of the protobuf-c library. Note that this is the version of + * the library linked against, not the version of the headers compiled against. + * + * \return A string containing the version number of protobuf-c. + */ +PROTOBUF_C__API +const char * +protobuf_c_version(void); + +/** + * Get the version of the protobuf-c library. Note that this is the version of + * the library linked against, not the version of the headers compiled against. + * + * \return A 32 bit unsigned integer containing the version number of + * protobuf-c, represented in base-10 as (MAJOR*1E6) + (MINOR*1E3) + PATCH. + */ +PROTOBUF_C__API +uint32_t +protobuf_c_version_number(void); + +/** + * The version of the protobuf-c headers, represented as a string using the same + * format as protobuf_c_version(). + */ +#define PROTOBUF_C_VERSION "1.4.1" + +/** + * The version of the protobuf-c headers, represented as an integer using the + * same format as protobuf_c_version_number(). + */ +#define PROTOBUF_C_VERSION_NUMBER 1004001 + +/** + * The minimum protoc-c version which works with the current version of the + * protobuf-c headers. + */ +#define PROTOBUF_C_MIN_COMPILER_VERSION 1000000 + +/** + * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by name. + * + * \param desc + * The `ProtobufCEnumDescriptor` object. + * \param name + * The `name` field from the corresponding `ProtobufCEnumValue` object to + * match. + * \return + * A `ProtobufCEnumValue` object. + * \retval NULL + * If not found or if the optimize_for = CODE_SIZE option was set. + */ +PROTOBUF_C__API +const ProtobufCEnumValue * +protobuf_c_enum_descriptor_get_value_by_name( + const ProtobufCEnumDescriptor *desc, + const char *name); + +/** + * Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by numeric + * value. + * + * \param desc + * The `ProtobufCEnumDescriptor` object. + * \param value + * The `value` field from the corresponding `ProtobufCEnumValue` object to + * match. + * + * \return + * A `ProtobufCEnumValue` object. + * \retval NULL + * If not found. + */ +PROTOBUF_C__API +const ProtobufCEnumValue * +protobuf_c_enum_descriptor_get_value( + const ProtobufCEnumDescriptor *desc, + int value); + +/** + * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by + * the name of the field. + * + * \param desc + * The `ProtobufCMessageDescriptor` object. + * \param name + * The name of the field. + * \return + * A `ProtobufCFieldDescriptor` object. + * \retval NULL + * If not found or if the optimize_for = CODE_SIZE option was set. + */ +PROTOBUF_C__API +const ProtobufCFieldDescriptor * +protobuf_c_message_descriptor_get_field_by_name( + const ProtobufCMessageDescriptor *desc, + const char *name); + +/** + * Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by + * the tag value of the field. + * + * \param desc + * The `ProtobufCMessageDescriptor` object. + * \param value + * The tag value of the field. + * \return + * A `ProtobufCFieldDescriptor` object. + * \retval NULL + * If not found. + */ +PROTOBUF_C__API +const ProtobufCFieldDescriptor * +protobuf_c_message_descriptor_get_field( + const ProtobufCMessageDescriptor *desc, + unsigned value); + +/** + * Determine the number of bytes required to store the serialised message. + * + * \param message + * The message object to serialise. + * \return + * Number of bytes. + */ +PROTOBUF_C__API +size_t +protobuf_c_message_get_packed_size(const ProtobufCMessage *message); + +/** + * Serialise a message from its in-memory representation. + * + * This function stores the serialised bytes of the message in a pre-allocated + * buffer. + * + * \param message + * The message object to serialise. + * \param[out] out + * Buffer to store the bytes of the serialised message. This buffer must + * have enough space to store the packed message. Use + * protobuf_c_message_get_packed_size() to determine the number of bytes + * required. + * \return + * Number of bytes stored in `out`. + */ +PROTOBUF_C__API +size_t +protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out); + +/** + * Serialise a message from its in-memory representation to a virtual buffer. + * + * This function calls the `append` method of a `ProtobufCBuffer` object to + * consume the bytes generated by the serialiser. + * + * \param message + * The message object to serialise. + * \param buffer + * The virtual buffer object. + * \return + * Number of bytes passed to the virtual buffer. + */ +PROTOBUF_C__API +size_t +protobuf_c_message_pack_to_buffer( + const ProtobufCMessage *message, + ProtobufCBuffer *buffer); + +/** + * Unpack a serialised message into an in-memory representation. + * + * \param descriptor + * The message descriptor. + * \param allocator + * `ProtobufCAllocator` to use for memory allocation. May be NULL to + * specify the default allocator. + * \param len + * Length in bytes of the serialised message. + * \param data + * Pointer to the serialised message. + * \return + * An unpacked message object. + * \retval NULL + * If an error occurred during unpacking. + */ +PROTOBUF_C__API +ProtobufCMessage * +protobuf_c_message_unpack( + const ProtobufCMessageDescriptor *descriptor, + ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); + +/** + * Free an unpacked message object. + * + * This function should be used to deallocate the memory used by a call to + * protobuf_c_message_unpack(). + * + * \param message + * The message object to free. May be NULL. + * \param allocator + * `ProtobufCAllocator` to use for memory deallocation. May be NULL to + * specify the default allocator. + */ +PROTOBUF_C__API +void +protobuf_c_message_free_unpacked( + ProtobufCMessage *message, + ProtobufCAllocator *allocator); + +/** + * Check the validity of a message object. + * + * Makes sure all required fields (`PROTOBUF_C_LABEL_REQUIRED`) are present. + * Recursively checks nested messages. + * + * \retval TRUE + * Message is valid. + * \retval FALSE + * Message is invalid. + */ +PROTOBUF_C__API +protobuf_c_boolean +protobuf_c_message_check(const ProtobufCMessage *); + +/** Message initialiser. */ +#define PROTOBUF_C_MESSAGE_INIT(descriptor) { descriptor, 0, NULL } + +/** + * Initialise a message object from a message descriptor. + * + * \param descriptor + * Message descriptor. + * \param message + * Allocated block of memory of size `descriptor->sizeof_message`. + */ +PROTOBUF_C__API +void +protobuf_c_message_init( + const ProtobufCMessageDescriptor *descriptor, + void *message); + +/** + * Free a service. + * + * \param service + * The service object to free. + */ +PROTOBUF_C__API +void +protobuf_c_service_destroy(ProtobufCService *service); + +/** + * Look up a `ProtobufCMethodDescriptor` by name. + * + * \param desc + * Service descriptor. + * \param name + * Name of the method. + * + * \return + * A `ProtobufCMethodDescriptor` object. + * \retval NULL + * If not found or if the optimize_for = CODE_SIZE option was set. + */ +PROTOBUF_C__API +const ProtobufCMethodDescriptor * +protobuf_c_service_descriptor_get_method_by_name( + const ProtobufCServiceDescriptor *desc, + const char *name); + +/** + * Initialise a `ProtobufCBufferSimple` object. + */ +#define PROTOBUF_C_BUFFER_SIMPLE_INIT(array_of_bytes) \ +{ \ + { protobuf_c_buffer_simple_append }, \ + sizeof(array_of_bytes), \ + 0, \ + (array_of_bytes), \ + 0, \ + NULL \ +} + +/** + * Clear a `ProtobufCBufferSimple` object, freeing any allocated memory. + */ +#define PROTOBUF_C_BUFFER_SIMPLE_CLEAR(simp_buf) \ +do { \ + if ((simp_buf)->must_free_data) { \ + if ((simp_buf)->allocator != NULL) \ + (simp_buf)->allocator->free( \ + (simp_buf)->allocator, \ + (simp_buf)->data); \ + else \ + free((simp_buf)->data); \ + } \ +} while (0) + +/** + * The `append` method for `ProtobufCBufferSimple`. + * + * \param buffer + * The buffer object to append to. Must actually be a + * `ProtobufCBufferSimple` object. + * \param len + * Number of bytes in `data`. + * \param data + * Data to append. + */ +PROTOBUF_C__API +void +protobuf_c_buffer_simple_append( + ProtobufCBuffer *buffer, + size_t len, + const unsigned char *data); + +PROTOBUF_C__API +void +protobuf_c_service_generated_init( + ProtobufCService *service, + const ProtobufCServiceDescriptor *descriptor, + ProtobufCServiceDestroy destroy); + +PROTOBUF_C__API +void +protobuf_c_service_invoke_internal( + ProtobufCService *service, + unsigned method_index, + const ProtobufCMessage *input, + ProtobufCClosure closure, + void *closure_data); + +/**@}*/ + +PROTOBUF_C__END_DECLS + +#endif /* PROTOBUF_C_H */ diff --git a/include/sudo_compat.h b/include/sudo_compat.h new file mode 100644 index 0000000..22db66a --- /dev/null +++ b/include/sudo_compat.h @@ -0,0 +1,581 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 1996, 1998-2005, 2008, 2009-2023 + * 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. + */ + +#ifndef SUDO_COMPAT_H +#define SUDO_COMPAT_H + +#include <sys/types.h> /* for gid_t, mode_t, size_t, ssize_t, time_t, uid_t */ +#include <sys/stat.h> /* to avoid problems with mismatched headers and libc */ +#include <unistd.h> /* to avoid problems with mismatched headers and libc */ +#include <stdio.h> +#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_VASPRINTF) || \ + !defined(HAVE_VSYSLOG) || defined(PREFER_PORTABLE_SNPRINTF) +# include <stdarg.h> +#endif + +/* + * Macros and functions that may be missing on some operating systems. + */ + +/* + * Given the pointer x to the member m of the struct s, return + * a pointer to the containing structure. + */ +#ifndef __containerof +# define __containerof(x, s, m) ((s *)((char *)(x) - offsetof(s, m))) +#endif + +/* + * Pre-C99 compilers may lack a va_copy macro. + */ +#ifndef HAVE_VA_COPY +# ifdef HAVE___VA_COPY +# define va_copy(d, s) __va_copy(d, s) +# else +# define va_copy(d, s) memcpy(&(d), &(s), sizeof(d)); +# endif +#endif + +/* + * Some systems lack full limit definitions. + */ +#if defined(HAVE_DECL_LLONG_MAX) && !HAVE_DECL_LLONG_MAX +# if defined(HAVE_DECL_QUAD_MAX) && HAVE_DECL_QUAD_MAX +# define LLONG_MAX QUAD_MAX +# else +# define LLONG_MAX 0x7fffffffffffffffLL +# endif +#endif + +#if defined(HAVE_DECL_LLONG_MIN) && !HAVE_DECL_LLONG_MIN +# if defined(HAVE_DECL_QUAD_MIN) && HAVE_DECL_QUAD_MIN +# define LLONG_MIN QUAD_MIN +# else +# define LLONG_MIN (-0x7fffffffffffffffLL-1) +# endif +#endif + +#if defined(HAVE_DECL_ULLONG_MAX) && !HAVE_DECL_ULLONG_MAX +# if defined(HAVE_DECL_UQUAD_MAX) && HAVE_DECL_UQUAD_MAX +# define ULLONG_MAX UQUAD_MAX +# else +# define ULLONG_MAX 0xffffffffffffffffULL +# endif +#endif + +#if defined(HAVE_DECL_SIZE_MAX) && !HAVE_DECL_SIZE_MAX +# if defined(HAVE_DECL_SIZE_T_MAX) && HAVE_DECL_SIZE_T_MAX +# define SIZE_MAX SIZE_T_MAX +# else +# define SIZE_MAX ULONG_MAX +# endif +#endif + +#if defined(HAVE_DECL_SSIZE_MAX) && !HAVE_DECL_SSIZE_MAX +# define SSIZE_MAX LONG_MAX +#endif + +#if defined(HAVE_DECL_PATH_MAX) && !HAVE_DECL_PATH_MAX +# if defined(HAVE_DECL__POSIX_PATH_MAX) && HAVE_DECL__POSIX_PATH_MAX +# define PATH_MAX _POSIX_PATH_MAX +# else +# define PATH_MAX 256 +# endif +#endif + +/* ACCESSPERMS and ALLPERMS are handy BSDisms. */ +#ifndef ACCESSPERMS +# define ACCESSPERMS 00777 +#endif /* ACCESSPERMS */ +#ifndef ALLPERMS +# define ALLPERMS 07777 +#endif /* ALLPERMS */ + +/* For futimens() and utimensat() emulation. */ +#if !defined(HAVE_FUTIMENS) && !defined(HAVE_UTIMENSAT) +# ifndef UTIME_OMIT +# define UTIME_OMIT -1L +# endif +# ifndef UTIME_NOW +# define UTIME_NOW -2L +# endif +#endif +#if !defined(HAVE_OPENAT) || (!defined(HAVE_FUTIMENS) && !defined(HAVE_UTIMENSAT)) || !defined(HAVE_FCHMODAT) || !defined(HAVE_FSTATAT) || !defined(HAVE_UNLINKAT) +# ifndef AT_FDCWD +# define AT_FDCWD -100 +# endif +# ifndef AT_SYMLINK_NOFOLLOW +# define AT_SYMLINK_NOFOLLOW 0x02 +# endif +#endif + +/* For dup3() and pipe2() emulation. */ +#if (!defined(HAVE_PIPE2) || !defined(HAVE_DUP3)) && defined(O_NONBLOCK) +# if !defined(O_CLOEXEC) || O_CLOEXEC > 0xffffffff +# undef O_CLOEXEC +# define O_CLOEXEC 0x80000000 +# endif +#endif + +/* + * BSD defines these in <sys/param.h> but we don't include that anymore. + */ +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef MAX +# define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +/* Macros to set/clear/test flags. */ +#undef SET +#define SET(t, f) ((t) |= (f)) +#undef CLR +#define CLR(t, f) ((t) &= ~(f)) +#undef ISSET +#define ISSET(t, f) ((t) & (f)) + +/* + * Some systems define this in <sys/param.h> but we don't include that anymore. + */ +#ifndef howmany +# define howmany(x, y) (((x) + ((y) - 1)) / (y)) +#endif + +/* + * Simple isblank() macro and function for systems without it. + */ +#ifndef HAVE_ISBLANK +sudo_dso_public int isblank(int); +# define isblank(_x) ((_x) == ' ' || (_x) == '\t') +#endif + +/* + * NCR's SVr4 has _innetgr(3) instead of innetgr(3) for some reason. + */ +#ifdef HAVE__INNETGR +# define innetgr(n, h, u, d) (_innetgr(n, h, u, d)) +# define HAVE_INNETGR 1 +#endif /* HAVE__INNETGR */ + +/* + * The nitems macro may be defined in sys/param.h + */ +#ifndef nitems +# define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + +/* + * If dirfd() does not exists, hopefully dd_fd does. + */ +#if !defined(HAVE_DIRFD) && defined(HAVE_DD_FD) +# define dirfd(_d) ((_d)->dd_fd) +# define HAVE_DIRFD +#endif + +#if !defined(HAVE_KILLPG) && !defined(killpg) +# define killpg(p, s) kill(-(p), (s)) +#endif + +/* + * Declare errno if errno.h doesn't do it for us. + */ +#if defined(HAVE_DECL_ERRNO) && !HAVE_DECL_ERRNO +extern int errno; +#endif /* !HAVE_DECL_ERRNO */ + +/* Not all systems define NSIG in signal.h */ +#if defined(HAVE_DECL_NSIG) && !HAVE_DECL_NSIG +# if defined(HAVE_DECL__NSIG) && HAVE_DECL__NSIG +# define NSIG _NSIG +# elif defined(HAVE_DECL___NSIG) && HAVE_DECL___NSIG +# define NSIG __NSIG +# else +# define NSIG 64 +# endif +#endif + +/* For sig2str() */ +#if !defined(HAVE_DECL_SIG2STR_MAX) || !HAVE_DECL_SIG2STR_MAX +# define SIG2STR_MAX 32 +#endif + +/* WCOREDUMP is not POSIX, this usually works (verified on AIX). */ +#ifndef WCOREDUMP +# define WCOREDUMP(x) ((x) & 0x80) +#endif + +/* W_EXITCODE is not POSIX but the encoding of wait status is. */ +#ifndef W_EXITCODE +# define W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) +#endif + +/* Number of bits in a byte. */ +#ifndef NBBY +# ifdef __NBBY +# define NBBY __NBBY +# else +# define NBBY 8 +# endif +#endif + +#ifndef HAVE_SETEUID +# if defined(HAVE_SETRESUID) +# define seteuid(u) setresuid(-1, (u), -1) +# define setegid(g) setresgid(-1, (g), -1) +# define HAVE_SETEUID 1 +# elif defined(HAVE_SETREUID) +# define seteuid(u) setreuid(-1, (u)) +# define setegid(g) setregid(-1, (g)) +# define HAVE_SETEUID 1 +# endif +#endif /* HAVE_SETEUID */ + +/* + * Older HP-UX does not declare setresuid() or setresgid(). + */ +#if defined(HAVE_DECL_SETRESUID) && !HAVE_DECL_SETRESUID +int setresuid(uid_t, uid_t, uid_t); +int setresgid(gid_t, gid_t, gid_t); +#endif +#if defined(HAVE_DECL_GETRESUID) && !HAVE_DECL_GETRESUID +int getresuid(uid_t *, uid_t *, uid_t *); +int getresgid(gid_t *, gid_t *, gid_t *); +#endif + +/* + * HP-UX does not declare innetgr() or getdomainname(). + * Solaris does not declare getdomainname(). + */ +#if defined(HAVE_DECL_INNETGR) && !HAVE_DECL_INNETGR +int innetgr(const char *, const char *, const char *, const char *); +#endif +#if defined(HAVE_DECL__INNETGR) && !HAVE_DECL__INNETGR +int _innetgr(const char *, const char *, const char *, const char *); +#endif +#if defined(HAVE_DECL_GETDOMAINNAME) && !HAVE_DECL_GETDOMAINNAME +int getdomainname(char *, size_t); +#endif + +/* + * HP-UX 11.00 has broken pread/pwrite on 32-bit machines when + * _FILE_OFFSET_BITS == 64. Use pread64/pwrite64 instead. + */ +#if defined(__hpux) && !defined(__LP64__) +# ifdef HAVE_PREAD64 +# undef pread +# define pread(_a, _b, _c, _d) pread64((_a), (_b), (_c), (_d)) +# if defined(HAVE_DECL_PREAD64) && !HAVE_DECL_PREAD64 + ssize_t pread64(int fd, void *buf, size_t nbytes, off64_t offset); +# endif +# endif +# ifdef HAVE_PWRITE64 +# undef pwrite +# define pwrite(_a, _b, _c, _d) pwrite64((_a), (_b), (_c), (_d)) +# if defined(HAVE_DECL_PWRITE64) && !HAVE_DECL_PWRITE64 + ssize_t pwrite64(int fd, const void *buf, size_t nbytes, off64_t offset); +# endif +# endif +#endif /* __hpux && !__LP64__ */ + +/* + * Older systems may lack fseeko(3), just use fseek(3) instead. + */ +#ifndef HAVE_FSEEKO +# define fseeko(f, o, w) fseek((f), (long)(o), (w)) +#endif + +/* + * Compatibility defines for OpenSSL 1.0.2 (not needed for 1.1.x) + */ +#if defined(HAVE_OPENSSL) && !defined(HAVE_WOLFSSL) +# ifndef HAVE_X509_STORE_CTX_GET0_CERT +# define X509_STORE_CTX_get0_cert(x) ((x)->cert) +# endif +# ifndef HAVE_ASN1_STRING_GET0_DATA +# define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) +# endif +# ifndef HAVE_TLS_METHOD +# define TLS_method() SSLv23_method() +# endif +#endif /* HAVE_OPENSSL && !HAVE_WOLFSSL */ + +/* + * Functions "missing" from libc. + * All libc replacements are prefixed with "sudo_" to avoid namespace issues. + */ + +struct passwd; +struct stat; +struct timespec; +struct termios; +struct tm; + +#ifndef HAVE_CFMAKERAW +sudo_dso_public void sudo_cfmakeraw(struct termios *term); +# undef cfmakeraw +# define cfmakeraw(_a) sudo_cfmakeraw((_a)) +#endif /* HAVE_CFMAKERAW */ +#ifndef HAVE_CLOSEFROM +sudo_dso_public void sudo_closefrom(int); +# undef closefrom +# define closefrom(_a) sudo_closefrom((_a)) +#endif /* HAVE_CLOSEFROM */ +#ifndef HAVE_EXPLICIT_BZERO +sudo_dso_public void sudo_explicit_bzero(void *s, size_t n); +# undef explicit_bzero +# define explicit_bzero(_a, _b) sudo_explicit_bzero((_a), (_b)) +#endif /* HAVE_EXPLICIT_BZERO */ +#ifndef HAVE_FREEZERO +sudo_dso_public void sudo_freezero(void *p, size_t n); +# undef freezero +# define freezero(_a, _b) sudo_freezero((_a), (_b)) +#endif /* HAVE_FREEZERO */ +#ifdef PREFER_PORTABLE_GETCWD +sudo_dso_public char *sudo_getcwd(char *, size_t size); +# undef getcwd +# define getcwd(_a, _b) sudo_getcwd((_a), (_b)) +#endif /* PREFER_PORTABLE_GETCWD */ +#ifndef HAVE_GETGROUPLIST +sudo_dso_public int sudo_getgrouplist(const char *name, GETGROUPS_T basegid, GETGROUPS_T *groups, int *ngroupsp); +# undef getgrouplist +# define getgrouplist(_a, _b, _c, _d) sudo_getgrouplist((_a), (_b), (_c), (_d)) +#endif /* GETGROUPLIST */ +#if !defined(HAVE_GETDELIM) +sudo_dso_public ssize_t sudo_getdelim(char **bufp, size_t *bufsizep, int delim, FILE *fp); +# undef getdelim +# define getdelim(_a, _b, _c, _d) sudo_getdelim((_a), (_b), (_c), (_d)) +#elif defined(HAVE_DECL_GETDELIM) && !HAVE_DECL_GETDELIM +/* getdelim present in libc but missing prototype (old gcc fixed includes?) */ +ssize_t getdelim(char **bufp, size_t *bufsizep, int delim, FILE *fp); +#endif /* HAVE_GETDELIM */ +#ifndef HAVE_GETUSERSHELL +sudo_dso_public char *sudo_getusershell(void); +# undef getusershell +# define getusershell() sudo_getusershell() +sudo_dso_public void sudo_setusershell(void); +# undef setusershell +# define setusershell() sudo_setusershell() +sudo_dso_public void sudo_endusershell(void); +# undef endusershell +# define endusershell() sudo_endusershell() +#elif HAVE_DECL_GETUSERSHELL == 0 +/* Older Solaris has getusershell() et al but does not declare it. */ +char *getusershell(void); +void setusershell(void); +void endusershell(void); +#endif /* HAVE_GETUSERSHELL */ +#ifndef HAVE_GMTIME_R +sudo_dso_public struct tm *sudo_gmtime_r(const time_t *, struct tm *); +# undef gmtime_r +# define gmtime_r(_a, _b) sudo_gmtime_r((_a), (_b)) +#endif /* HAVE_GMTIME_R */ +#ifndef HAVE_LOCALTIME_R +sudo_dso_public struct tm *sudo_localtime_r(const time_t *, struct tm *); +# undef localtime_r +# define localtime_r(_a, _b) sudo_localtime_r((_a), (_b)) +#endif /* HAVE_LOCALTIME_R */ +#ifndef HAVE_TIMEGM +sudo_dso_public time_t sudo_timegm(struct tm *); +#endif /* HAVE_TIMEGM */ +#ifndef HAVE_UTIMENSAT +sudo_dso_public int sudo_utimensat(int fd, const char *file, const struct timespec *times, int flag); +# undef utimensat +# define utimensat(_a, _b, _c, _d) sudo_utimensat((_a), (_b), (_c), (_d)) +#endif /* HAVE_UTIMENSAT */ +#ifndef HAVE_FCHMODAT +sudo_dso_public int sudo_fchmodat(int dfd, const char *path, mode_t mode, int flag); +# undef fchmodat +# define fchmodat(_a, _b, _c, _d) sudo_fchmodat((_a), (_b), (_c), (_d)) +#endif /* HAVE_FCHMODAT */ +#ifndef HAVE_FSTATAT +sudo_dso_public int sudo_fstatat(int dfd, const char *path, struct stat *sb, int flag); +# undef fstatat +# define fstatat(_a, _b, _c, _d) sudo_fstatat((_a), (_b), (_c), (_d)) +#endif /* HAVE_FSTATAT */ +#ifndef HAVE_FUTIMENS +sudo_dso_public int sudo_futimens(int fd, const struct timespec *times); +# undef futimens +# define futimens(_a, _b) sudo_futimens((_a), (_b)) +#endif /* HAVE_FUTIMENS */ +#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) +sudo_dso_public int sudo_snprintf(char *str, size_t n, char const *fmt, ...) sudo_printflike(3, 4); +# undef snprintf +# define snprintf sudo_snprintf +#endif /* HAVE_SNPRINTF */ +#if !defined(HAVE_VSNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) +sudo_dso_public int sudo_vsnprintf(char *str, size_t n, const char *fmt, va_list ap) sudo_printflike(3, 0); +# undef vsnprintf +# define vsnprintf sudo_vsnprintf +#endif /* HAVE_VSNPRINTF */ +#if !defined(HAVE_ASPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) +sudo_dso_public int sudo_asprintf(char **str, char const *fmt, ...) sudo_printflike(2, 3); +# undef asprintf +# define asprintf sudo_asprintf +#endif /* HAVE_ASPRINTF */ +#if !defined(HAVE_VASPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) +sudo_dso_public int sudo_vasprintf(char **str, const char *fmt, va_list ap) sudo_printflike(2, 0); +# undef vasprintf +# define vasprintf sudo_vasprintf +#endif /* HAVE_VASPRINTF */ +#ifndef HAVE_STRLCAT +sudo_dso_public size_t sudo_strlcat(char *dst, const char *src, size_t siz); +# undef strlcat +# define strlcat(_a, _b, _c) sudo_strlcat((_a), (_b), (_c)) +#endif /* HAVE_STRLCAT */ +#ifndef HAVE_STRLCPY +sudo_dso_public size_t sudo_strlcpy(char *dst, const char *src, size_t siz); +# undef strlcpy +# define strlcpy(_a, _b, _c) sudo_strlcpy((_a), (_b), (_c)) +#endif /* HAVE_STRLCPY */ +#ifndef HAVE_STRNDUP +sudo_dso_public char *sudo_strndup(const char *str, size_t maxlen); +# undef strndup +# define strndup(_a, _b) sudo_strndup((_a), (_b)) +#endif /* HAVE_STRNDUP */ +#ifndef HAVE_STRNLEN +sudo_dso_public size_t sudo_strnlen(const char *str, size_t maxlen); +# undef strnlen +# define strnlen(_a, _b) sudo_strnlen((_a), (_b)) +#endif /* HAVE_STRNLEN */ +#ifndef HAVE_FCHOWNAT +sudo_dso_public int sudo_fchownat(int dfd, const char *path, uid_t uid, gid_t gid, int flag); +# undef fchownat +# define fchownat(_a, _b, _c, _d, _e) sudo_fchownat((_a), (_b), (_c), (_d), (_e)) +#endif /* HAVE_FCHOWNAT */ +#ifndef HAVE_MEMRCHR +sudo_dso_public void *sudo_memrchr(const void *s, int c, size_t n); +# undef memrchr +# define memrchr(_a, _b, _c) sudo_memrchr((_a), (_b), (_c)) +#endif /* HAVE_MEMRCHR */ +#ifndef HAVE_MKDIRAT +sudo_dso_public int sudo_mkdirat(int dfd, const char *path, mode_t mode); +# undef mkdirat +# define mkdirat(_a, _b, _c) sudo_mkdirat((_a), (_b), (_c)) +#endif /* HAVE_MKDIRAT */ +#if !defined(HAVE_MKDTEMPAT) || !defined(HAVE_MKOSTEMPSAT) +# if defined(HAVE_MKDTEMPAT_NP) && defined(HAVE_MKOSTEMPSAT_NP) +# undef mkdtempat +# define mkdtempat mkdtempat_np +# undef mkostempsat +# define mkostempsat mkostempsat_np +# else +sudo_dso_public char *sudo_mkdtemp(char *path); +# undef mkdtemp +# define mkdtemp(_a) sudo_mkdtemp((_a)) +sudo_dso_public char *sudo_mkdtempat(int dfd, char *path); +# undef mkdtempat +# define mkdtempat(_a, _b) sudo_mkdtempat((_a), (_b)) +sudo_dso_public int sudo_mkostempsat(int dfd, char *path, int slen, int flags); +# undef mkostempsat +# define mkostempsat(_a, _b, _c, _d) sudo_mkostempsat((_a), (_b), (_c), (_d)) +sudo_dso_public int sudo_mkstemp(char *path); +# undef mkstemp +# define mkstemp(_a) sudo_mkstemp((_a)) +sudo_dso_public int sudo_mkstemps(char *path, int slen); +# undef mkstemps +# define mkstemps(_a, _b) sudo_mkstemps((_a), (_b)) +# endif /* HAVE_MKDTEMPAT_NP || HAVE_MKOSTEMPSAT_NP */ +#endif /* !HAVE_MKDTEMPAT || !HAVE_MKOSTEMPSAT */ +#ifndef HAVE_NANOSLEEP +sudo_dso_public int sudo_nanosleep(const struct timespec *timeout, struct timespec *remainder); +#undef nanosleep +# define nanosleep(_a, _b) sudo_nanosleep((_a), (_b)) +#endif /* HAVE_NANOSLEEP */ +#ifndef HAVE_OPENAT +sudo_dso_public int sudo_openat(int dfd, const char *path, int flags, mode_t mode); +# undef openat +# define openat(_a, _b, _c, _d) sudo_openat((_a), (_b), (_c), (_d)) +#endif /* HAVE_OPENAT */ +#ifndef HAVE_PW_DUP +sudo_dso_public struct passwd *sudo_pw_dup(const struct passwd *pw); +# undef pw_dup +# define pw_dup(_a) sudo_pw_dup((_a)) +#endif /* HAVE_PW_DUP */ +#ifndef HAVE_STRSIGNAL +sudo_dso_public char *sudo_strsignal(int signo); +# undef strsignal +# define strsignal(_a) sudo_strsignal((_a)) +#endif /* HAVE_STRSIGNAL */ +#ifndef HAVE_SIG2STR +sudo_dso_public int sudo_sig2str(int signo, char *signame); +# undef sig2str +# define sig2str(_a, _b) sudo_sig2str((_a), (_b)) +#endif /* HAVE_SIG2STR */ +#ifndef HAVE_STR2SIG +sudo_dso_public int sudo_str2sig(const char *signame, int *signum); +# undef str2sig +# define str2sig(_a, _b) sudo_str2sig((_a), (_b)) +#endif /* HAVE_STR2SIG */ +#if !defined(HAVE_INET_NTOP) && defined(NEED_INET_NTOP) +sudo_dso_public char *sudo_inet_ntop(int af, const void *src, char *dst, socklen_t size); +# undef inet_ntop +# define inet_ntop(_a, _b, _c, _d) sudo_inet_ntop((_a), (_b), (_c), (_d)) +#endif /* HAVE_INET_NTOP */ +#ifndef HAVE_INET_PTON +sudo_dso_public int sudo_inet_pton(int af, const char *src, void *dst); +# undef inet_pton +# define inet_pton(_a, _b, _c) sudo_inet_pton((_a), (_b), (_c)) +#endif /* HAVE_INET_PTON */ +#ifndef HAVE_GETPROGNAME +sudo_dso_public const char *sudo_getprogname(void); +# undef getprogname +# define getprogname() sudo_getprogname() +#endif /* HAVE_GETPROGNAME */ +#ifndef HAVE_SETPROGNAME +sudo_dso_public void sudo_setprogname(const char *name); +# undef setprogname +# define setprogname(_a) sudo_setprogname(_a) +#endif /* HAVE_SETPROGNAME */ +#ifndef HAVE_REALLOCARRAY +sudo_dso_public void *sudo_reallocarray(void *ptr, size_t nmemb, size_t size); +# undef reallocarray +# define reallocarray(_a, _b, _c) sudo_reallocarray((_a), (_b), (_c)) +#endif /* HAVE_REALLOCARRAY */ +#ifndef HAVE_DUP3 +sudo_dso_public int sudo_dup3(int oldd, int newd, int flags); +# undef dup3 +# define dup3(_a, _b, _c) sudo_dup3((_a), (_b), (_c)) +#endif /* HAVE_DUP3 */ +#ifndef HAVE_PIPE2 +sudo_dso_public int sudo_pipe2(int fildes[2], int flags); +# undef pipe2 +# define pipe2(_a, _b) sudo_pipe2((_a), (_b)) +#endif /* HAVE_PIPE2 */ +#ifndef HAVE_PREAD +sudo_dso_public ssize_t sudo_pread(int fd, void *buf, size_t nbytes, off_t offset); +# undef pread +# define pread(_a, _b, _c, _d) sudo_pread((_a), (_b), (_c), (_d)) +#endif /* HAVE_PREAD */ +#ifndef HAVE_PWRITE +sudo_dso_public ssize_t sudo_pwrite(int fd, const void *buf, size_t nbytes, off_t offset); +# undef pwrite +# define pwrite(_a, _b, _c, _d) sudo_pwrite((_a), (_b), (_c), (_d)) +#endif /* HAVE_PWRITE */ +#ifndef HAVE_UNLINKAT +sudo_dso_public int sudo_unlinkat(int dfd, const char *path, int flag); +# undef unlinkat +# define unlinkat(_a, _b, _c) sudo_unlinkat((_a), (_b), (_c)) +#endif /* HAVE_UNLINKAT */ + +#endif /* SUDO_COMPAT_H */ diff --git a/include/sudo_conf.h b/include/sudo_conf.h new file mode 100644 index 0000000..5e2bad0 --- /dev/null +++ b/include/sudo_conf.h @@ -0,0 +1,97 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2011-2017, 2019-2021 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. + */ + +#ifndef SUDO_CONF_H +#define SUDO_CONF_H + +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# include "compat/stdbool.h" +#endif + +#include "sudo_queue.h" + +/* Flags for sudo_conf_read() */ +#define SUDO_CONF_DEBUG 0x01 +#define SUDO_CONF_PATHS 0x02 +#define SUDO_CONF_PLUGINS 0x04 +#define SUDO_CONF_SETTINGS 0x08 +#define SUDO_CONF_ALL 0x0f + +/* Values of sudo_conf_group_source() */ +#define GROUP_SOURCE_ADAPTIVE 0 +#define GROUP_SOURCE_STATIC 1 +#define GROUP_SOURCE_DYNAMIC 2 + +struct sudo_debug_file; +TAILQ_HEAD(sudo_conf_debug_file_list, sudo_debug_file); + +struct plugin_info { + TAILQ_ENTRY(plugin_info) entries; + char *path; + char *symbol_name; + char **options; + unsigned int lineno; +}; +TAILQ_HEAD(plugin_info_list, plugin_info); + +struct sudo_conf_debug { + TAILQ_ENTRY(sudo_conf_debug) entries; + struct sudo_conf_debug_file_list debug_files; + char *progname; +}; +TAILQ_HEAD(sudo_conf_debug_list, sudo_conf_debug); + +/* Read main sudo.conf file. */ +sudo_dso_public int sudo_conf_read_v1(const char *conf_file, int conf_types); +#define sudo_conf_read(_a, _b) sudo_conf_read_v1((_a), (_b)) + +/* Accessor functions. */ +sudo_dso_public const char *sudo_conf_askpass_path_v1(void); +sudo_dso_public const char *sudo_conf_sesh_path_v1(void); +sudo_dso_public const char *sudo_conf_intercept_path_v1(void); +sudo_dso_public const char *sudo_conf_noexec_path_v1(void); +sudo_dso_public const char *sudo_conf_plugin_dir_path_v1(void); +sudo_dso_public const char *sudo_conf_devsearch_path_v1(void); +sudo_dso_public struct sudo_conf_debug_list *sudo_conf_debugging_v1(void); +sudo_dso_public struct sudo_conf_debug_file_list *sudo_conf_debug_files_v1(const char *progname); +sudo_dso_public struct plugin_info_list *sudo_conf_plugins_v1(void); +sudo_dso_public bool sudo_conf_disable_coredump_v1(void); +sudo_dso_public bool sudo_conf_developer_mode_v1(void); +sudo_dso_public bool sudo_conf_probe_interfaces_v1(void); +sudo_dso_public int sudo_conf_group_source_v1(void); +sudo_dso_public int sudo_conf_max_groups_v1(void); +sudo_dso_public void sudo_conf_clear_paths_v1(void); +#define sudo_conf_askpass_path() sudo_conf_askpass_path_v1() +#define sudo_conf_sesh_path() sudo_conf_sesh_path_v1() +#define sudo_conf_intercept_path() sudo_conf_intercept_path_v1() +#define sudo_conf_noexec_path() sudo_conf_noexec_path_v1() +#define sudo_conf_plugin_dir_path() sudo_conf_plugin_dir_path_v1() +#define sudo_conf_devsearch_path() sudo_conf_devsearch_path_v1() +#define sudo_conf_debugging() sudo_conf_debugging_v1() +#define sudo_conf_debug_files(_a) sudo_conf_debug_files_v1((_a)) +#define sudo_conf_plugins() sudo_conf_plugins_v1() +#define sudo_conf_disable_coredump() sudo_conf_disable_coredump_v1() +#define sudo_conf_developer_mode() sudo_conf_developer_mode_v1() +#define sudo_conf_probe_interfaces() sudo_conf_probe_interfaces_v1() +#define sudo_conf_group_source() sudo_conf_group_source_v1() +#define sudo_conf_max_groups() sudo_conf_max_groups_v1() +#define sudo_conf_clear_paths() sudo_conf_clear_paths_v1() + +#endif /* SUDO_CONF_H */ diff --git a/include/sudo_debug.h b/include/sudo_debug.h new file mode 100644 index 0000000..5ee5cc1 --- /dev/null +++ b/include/sudo_debug.h @@ -0,0 +1,306 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2011-2017 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. + */ + +#ifndef SUDO_DEBUG_H +#define SUDO_DEBUG_H + +#include <sys/types.h> /* for id_t, size_t, ssize_t, time_t */ +#include <stdarg.h> +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# include "compat/stdbool.h" +#endif +#include "sudo_queue.h" + +/* + * List of debug files and flags for use in registration. + */ +struct sudo_debug_file { + TAILQ_ENTRY(sudo_debug_file) entries; + char *debug_file; + char *debug_flags; +}; +struct sudo_conf_debug_file_list; + +/* + * The priority and subsystem are encoded in a single 32-bit value. + * The lower 4 bits are the priority and the top 26 bits are the subsystem. + * This allows for 16 priorities and a very large number of subsystems. + * Bit 5 is used as a flag to specify whether to log the errno value. + * Bit 6 specifies whether to log the function, file and line number data. + */ + +/* + * Sudo debug priorities, ordered least to most verbose, + * in other words, highest to lowest priority. Max pri is 15. + * Note: order must match sudo_debug_priorities[] + */ +#define SUDO_DEBUG_CRIT 1 /* critical errors */ +#define SUDO_DEBUG_ERROR 2 /* non-critical errors */ +#define SUDO_DEBUG_WARN 3 /* non-fatal warnings */ +#define SUDO_DEBUG_NOTICE 4 /* non-error condition notices */ +#define SUDO_DEBUG_DIAG 5 /* diagnostic messages */ +#define SUDO_DEBUG_INFO 6 /* informational message */ +#define SUDO_DEBUG_TRACE 7 /* log function enter/exit */ +#define SUDO_DEBUG_DEBUG 8 /* very verbose debugging */ + +/* Flag to include string version of errno in debug info. */ +#define SUDO_DEBUG_ERRNO (1<<4) + +/* Flag to include function, file and line number in debug info. */ +#define SUDO_DEBUG_LINENO (1<<5) + +/* + * Sudo debug subsystems. + * This includes subsystems in the sudoers plugin. + * Note: order must match sudo_debug_subsystems[] + */ +#define SUDO_DEBUG_ARGS ( 1<<6) /* command line argument handling */ +#define SUDO_DEBUG_CONV ( 2<<6) /* user conversation */ +#define SUDO_DEBUG_EDIT ( 3<<6) /* sudoedit */ +#define SUDO_DEBUG_EVENT ( 4<<6) /* event handling */ +#define SUDO_DEBUG_EXEC ( 5<<6) /* command execution */ +#define SUDO_DEBUG_HOOKS ( 6<<6) /* hook functions */ +#define SUDO_DEBUG_MAIN ( 7<<6) /* sudo main() */ +#define SUDO_DEBUG_NETIF ( 8<<6) /* network interface functions */ +#define SUDO_DEBUG_PCOMM ( 9<<6) /* plugin communications */ +#define SUDO_DEBUG_PLUGIN (10<<6) /* main plugin functions */ +#define SUDO_DEBUG_PTY (11<<6) /* pseudo-tty */ +#define SUDO_DEBUG_SELINUX (12<<6) /* selinux */ +#define SUDO_DEBUG_UTIL (13<<6) /* utility functions */ +#define SUDO_DEBUG_UTMP (14<<6) /* utmp file ops */ +#define SUDO_DEBUG_APPARMOR (15<<6) /* AppArmor */ +#define SUDO_DEBUG_ALL 0xffff0000 /* all subsystems */ + +/* Error return for sudo_debug_register(). */ +#define SUDO_DEBUG_INSTANCE_ERROR -2 + +/* Initializer for instance index to indicate that debugging is not setup. */ +#define SUDO_DEBUG_INSTANCE_INITIALIZER -1 + +/* Extract priority number and convert to an index. */ +#define SUDO_DEBUG_PRI(n) (((n) & 0x0f) - 1) + +/* Extract subsystem number and convert to an index. */ +#define SUDO_DEBUG_SUBSYS(n) (((n) >> 6) - 1) + +/* + * Wrapper for sudo_debug_enter() that declares __func__ as needed + * and sets sudo_debug_subsys for sudo_debug_exit(). + */ +#ifdef HAVE___FUNC__ +# define debug_decl_func(funcname) +# define debug_decl_vars(funcname, subsys) \ + const int sudo_debug_subsys = (subsys) +#else +# define debug_decl_func(funcname) \ + const char __func__[] = #funcname; +# define debug_decl_vars(funcname, subsys) \ + debug_decl_func(funcname) \ + const int sudo_debug_subsys = (subsys) +#endif +#define debug_decl(funcname, subsys) \ + debug_decl_vars((funcname), (subsys)); \ + sudo_debug_enter(__func__, __FILE__, __LINE__, sudo_debug_subsys) + +/* + * Wrappers for sudo_debug_exit() and friends. + */ +#define debug_return \ + do { \ + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); \ + return; \ + } while (0) + +#define debug_return_int(ret) \ + do { \ + int sudo_debug_ret = (ret); \ + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_id_t(ret) \ + do { \ + id_t sudo_debug_ret = (ret); \ + sudo_debug_exit_id_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_size_t(ret) \ + do { \ + size_t sudo_debug_ret = (ret); \ + sudo_debug_exit_size_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_ssize_t(ret) \ + do { \ + ssize_t sudo_debug_ret = (ret); \ + sudo_debug_exit_ssize_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_time_t(ret) \ + do { \ + time_t sudo_debug_ret = (ret); \ + sudo_debug_exit_time_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_long(ret) \ + do { \ + long sudo_debug_ret = (ret); \ + sudo_debug_exit_long(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_bool(ret) \ + do { \ + bool sudo_debug_ret = (ret); \ + sudo_debug_exit_bool(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_str(ret) \ + do { \ + char *sudo_debug_ret = (ret); \ + sudo_debug_exit_str(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_const_str(ret) \ + do { \ + const char *sudo_debug_ret = (ret); \ + sudo_debug_exit_str(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_str_masked(ret) \ + do { \ + char *sudo_debug_ret = (ret); \ + sudo_debug_exit_str_masked(__func__, __FILE__, __LINE__, \ + sudo_debug_subsys, sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_ptr(ret) \ + do { \ + void *sudo_debug_ret = (ret); \ + sudo_debug_exit_ptr(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +#define debug_return_const_ptr(ret) \ + do { \ + const void *sudo_debug_ret = (ret); \ + sudo_debug_exit_ptr(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_ret); \ + return sudo_debug_ret; \ + } while (0) + +/* + * Variadic macros are a C99 feature but GNU cpp has supported + * a (different) version of them for a long time. + */ +#if defined(NO_VARIADIC_MACROS) +# define sudo_debug_printf sudo_debug_printf_nvm +#elif defined(__GNUC__) && __GNUC__ == 2 +# define sudo_debug_printf(pri, fmt...) \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, (pri)|sudo_debug_subsys, \ + fmt) +#else +# define sudo_debug_printf(pri, ...) \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, (pri)|sudo_debug_subsys, \ + __VA_ARGS__) +#endif + +#define sudo_debug_execve(pri, path, argv, envp) \ + sudo_debug_execve2((pri)|sudo_debug_subsys, (path), (argv), (envp)) + +#define sudo_debug_write(fd, str, len, errnum) \ + sudo_debug_write2(fd, NULL, NULL, 0, (str), (len), (errnum)) + +sudo_dso_public int sudo_debug_deregister_v1(int instance_id); +sudo_dso_public void sudo_debug_enter_v1(const char *func, const char *file, int line, int subsys); +sudo_dso_public void sudo_debug_execve2_v1(int level, const char *path, char *const argv[], char *const envp[]); +sudo_dso_public void sudo_debug_exit_v1(const char *func, const char *file, int line, int subsys); +sudo_dso_public void sudo_debug_exit_bool_v1(const char *func, const char *file, int line, int subsys, bool ret); +sudo_dso_public void sudo_debug_exit_int_v1(const char *func, const char *file, int line, int subsys, int ret); +sudo_dso_public void sudo_debug_exit_long_v1(const char *func, const char *file, int line, int subsys, long ret); +sudo_dso_public void sudo_debug_exit_ptr_v1(const char *func, const char *file, int line, int subsys, const void *ret); +sudo_dso_public void sudo_debug_exit_id_t_v1(const char *func, const char *file, int line, int subsys, id_t ret); +sudo_dso_public void sudo_debug_exit_size_t_v1(const char *func, const char *file, int line, int subsys, size_t ret); +sudo_dso_public void sudo_debug_exit_ssize_t_v1(const char *func, const char *file, int line, int subsys, ssize_t ret); +sudo_dso_public void sudo_debug_exit_str_v1(const char *func, const char *file, int line, int subsys, const char *ret); +sudo_dso_public void sudo_debug_exit_str_masked_v1(const char *func, const char *file, int line, int subsys, const char *ret); +sudo_dso_public void sudo_debug_exit_time_t_v1(const char *func, const char *file, int line, int subsys, time_t ret); +sudo_dso_public pid_t sudo_debug_fork_v1(void); +sudo_dso_public int sudo_debug_get_active_instance_v1(void); +sudo_dso_public int sudo_debug_get_fds_v1(unsigned char **fds); +sudo_dso_public int sudo_debug_get_instance_v1(const char *program); +sudo_dso_public int sudo_debug_parse_flags_v1(struct sudo_conf_debug_file_list *debug_files, const char *entry); +sudo_dso_public void sudo_debug_printf2_v1(const char *func, const char *file, int line, int level, const char *fmt, ...) sudo_printf0like(5, 6); +sudo_dso_public void sudo_debug_printf_nvm_v1(int pri, const char *fmt, ...) sudo_printf0like(2, 3); +sudo_dso_public int sudo_debug_register_v1(const char *program, const char *const subsystems[], unsigned int ids[], struct sudo_conf_debug_file_list *debug_files); +sudo_dso_public int sudo_debug_register_v2(const char *program, const char *const subsystems[], unsigned int ids[], struct sudo_conf_debug_file_list *debug_files, int minfd); +sudo_dso_public int sudo_debug_set_active_instance_v1(int inst); +sudo_dso_public void sudo_debug_update_fd_v1(int ofd, int nfd); +sudo_dso_public void sudo_debug_vprintf2_v1(const char *func, const char *file, int line, int level, const char *fmt, va_list ap) sudo_printf0like(5, 0); +sudo_dso_public void sudo_debug_write2_v1(int fd, const char *func, const char *file, int line, const char *str, int len, int errnum); +sudo_dso_public bool sudo_debug_needed_v1(int level); + +#define sudo_debug_needed(level) sudo_debug_needed_v1((level)|sudo_debug_subsys) +#define sudo_debug_deregister(_a) sudo_debug_deregister_v1((_a)) +#define sudo_debug_enter(_a, _b, _c, _d) sudo_debug_enter_v1((_a), (_b), (_c), (_d)) +#define sudo_debug_execve2(_a, _b, _c, _d) sudo_debug_execve2_v1((_a), (_b), (_c), (_d)) +#define sudo_debug_exit(_a, _b, _c, _d) sudo_debug_exit_v1((_a), (_b), (_c), (_d)) +#define sudo_debug_exit_bool(_a, _b, _c, _d, _e) sudo_debug_exit_bool_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_exit_int(_a, _b, _c, _d, _e) sudo_debug_exit_int_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_exit_long(_a, _b, _c, _d, _e) sudo_debug_exit_long_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_exit_ptr(_a, _b, _c, _d, _e) sudo_debug_exit_ptr_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_exit_id_t(_a, _b, _c, _d, _e) sudo_debug_exit_id_t_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_exit_size_t(_a, _b, _c, _d, _e) sudo_debug_exit_size_t_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_exit_ssize_t(_a, _b, _c, _d, _e) sudo_debug_exit_ssize_t_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_exit_str(_a, _b, _c, _d, _e) sudo_debug_exit_str_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_exit_str_masked(_a, _b, _c, _d, _e) sudo_debug_exit_str_masked_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_exit_time_t(_a, _b, _c, _d, _e) sudo_debug_exit_time_t_v1((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_fork() sudo_debug_fork_v1() +#define sudo_debug_get_active_instance() sudo_debug_get_active_instance_v1() +#define sudo_debug_get_fds(_a) sudo_debug_get_fds_v1((_a)) +#define sudo_debug_get_instance(_a) sudo_debug_get_instance_v1((_a)) +#define sudo_debug_parse_flags(_a, _b) sudo_debug_parse_flags_v1((_a), (_b)) +#define sudo_debug_printf2 sudo_debug_printf2_v1 +#define sudo_debug_printf_nvm sudo_debug_printf_nvm_v1 +#define sudo_debug_register(_a, _b, _c, _d, _e) sudo_debug_register_v2((_a), (_b), (_c), (_d), (_e)) +#define sudo_debug_set_active_instance(_a) sudo_debug_set_active_instance_v1((_a)) +#define sudo_debug_update_fd(_a, _b) sudo_debug_update_fd_v1((_a), (_b)) +#define sudo_debug_vprintf2(_a, _b, _c, _d, _e, _f) sudo_debug_vprintf2_v1((_a), (_b), (_c), (_d), (_e), (_f)) +#define sudo_debug_write2(_a, _b, _c, _d, _e, _f, _g) sudo_debug_write2_v1((_a), (_b), (_c), (_d), (_e), (_f), (_g)) + +#endif /* SUDO_DEBUG_H */ diff --git a/include/sudo_digest.h b/include/sudo_digest.h new file mode 100644 index 0000000..fccfc58 --- /dev/null +++ b/include/sudo_digest.h @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 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. + */ + +#ifndef SUDO_DIGEST_H +#define SUDO_DIGEST_H + +/* Digest types. */ +#define SUDO_DIGEST_SHA224 0 +#define SUDO_DIGEST_SHA256 1 +#define SUDO_DIGEST_SHA384 2 +#define SUDO_DIGEST_SHA512 3 +#define SUDO_DIGEST_INVALID 4 + +struct sudo_digest; + +/* Public functions. */ +sudo_dso_public struct sudo_digest *sudo_digest_alloc_v1(int digest_type); +sudo_dso_public void sudo_digest_free_v1(struct sudo_digest *dig); +sudo_dso_public void sudo_digest_reset_v1(struct sudo_digest *dig); +sudo_dso_public int sudo_digest_getlen_v1(int digest_type); +sudo_dso_public void sudo_digest_update_v1(struct sudo_digest *dig, const void *data, size_t len); +sudo_dso_public void sudo_digest_final_v1(struct sudo_digest *dig, unsigned char *md); + +#define sudo_digest_alloc(_a) sudo_digest_alloc_v1((_a)) +#define sudo_digest_free(_a) sudo_digest_free_v1((_a)) +#define sudo_digest_reset(_a) sudo_digest_reset_v1((_a)) +#define sudo_digest_getlen(_a) sudo_digest_getlen_v1((_a)) +#define sudo_digest_update(_a, _b, _c) sudo_digest_update_v1((_a), (_b), (_c)) +#define sudo_digest_final(_a, _b) sudo_digest_final_v1((_a), (_b)) + +#endif /* SUDO_DIGEST_H */ diff --git a/include/sudo_dso.h b/include/sudo_dso.h new file mode 100644 index 0000000..c2e1aaf --- /dev/null +++ b/include/sudo_dso.h @@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2010, 2013, 2014 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. + */ + +#ifndef SUDO_DSO_H +#define SUDO_DSO_H + +/* Values for sudo_dso_load() mode. */ +#define SUDO_DSO_LAZY 0x1 +#define SUDO_DSO_NOW 0x2 +#define SUDO_DSO_GLOBAL 0x4 +#define SUDO_DSO_LOCAL 0x8 + +/* Special handle arguments for sudo_dso_findsym(). */ +#define SUDO_DSO_NEXT ((void *)-1) /* Search subsequent objects. */ +#define SUDO_DSO_DEFAULT ((void *)-2) /* Use default search algorithm. */ +#define SUDO_DSO_SELF ((void *)-3) /* Search the caller itself. */ + +/* Internal structs for static linking of plugins. */ +struct sudo_preload_symbol { + const char *name; + void *addr; +}; +struct sudo_preload_table { + const char *path; + void *handle; + struct sudo_preload_symbol *symbols; +}; + +/* Public functions. */ +sudo_dso_public char *sudo_dso_strerror_v1(void); +sudo_dso_public int sudo_dso_unload_v1(void *handle); +sudo_dso_public void *sudo_dso_findsym_v1(void *handle, const char *symbol); +sudo_dso_public void *sudo_dso_load_v1(const char *path, int mode); +sudo_dso_public void sudo_dso_preload_table_v1(struct sudo_preload_table *table); + +#define sudo_dso_strerror() sudo_dso_strerror_v1() +#define sudo_dso_unload(_a) sudo_dso_unload_v1((_a)) +#define sudo_dso_findsym(_a, _b) sudo_dso_findsym_v1((_a), (_b)) +#define sudo_dso_load(_a, _b) sudo_dso_load_v1((_a), (_b)) +#define sudo_dso_preload_table(_a) sudo_dso_preload_table_v1((_a)) + +#endif /* SUDO_DSO_H */ diff --git a/include/sudo_event.h b/include/sudo_event.h new file mode 100644 index 0000000..67dfb20 --- /dev/null +++ b/include/sudo_event.h @@ -0,0 +1,213 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2013-2015, 2017 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. + */ + +#ifndef SUDO_EVENT_H +#define SUDO_EVENT_H + +#include <time.h> /* for struct timespec */ +#include <signal.h> /* for sigatomic_t and NSIG */ +#include "sudo_queue.h" + +struct timeval; /* for deprecated APIs */ + +/* Event types (keep in sync with sudo_plugin.h) */ +#define SUDO_EV_TIMEOUT 0x01 /* fire after timeout */ +#define SUDO_EV_READ 0x02 /* fire when readable */ +#define SUDO_EV_WRITE 0x04 /* fire when writable */ +#define SUDO_EV_PERSIST 0x08 /* persist until deleted */ +#define SUDO_EV_SIGNAL 0x10 /* fire on signal receipt */ +#define SUDO_EV_SIGINFO 0x20 /* fire on signal receipt (siginfo) */ + +/* User-settable events for sudo_ev_init() (SUDO_EV_TIMEOUT not valid here) */ +#define SUDO_EV_MASK (SUDO_EV_READ|SUDO_EV_WRITE|SUDO_EV_PERSIST|SUDO_EV_SIGNAL|SUDO_EV_SIGINFO) + +/* Event flags (internal) */ +#define SUDO_EVQ_INSERTED 0x01 /* event is on the event queue */ +#define SUDO_EVQ_ACTIVE 0x02 /* event is on the active queue */ +#define SUDO_EVQ_TIMEOUTS 0x04 /* event is on the timeouts queue */ + +/* Event loop flags */ +#define SUDO_EVLOOP_ONCE 0x01 /* Only run once through the loop */ +#define SUDO_EVLOOP_NONBLOCK 0x02 /* Do not block in event loop */ + +/* Event base flags (internal) */ +#define SUDO_EVBASE_LOOPONCE SUDO_EVLOOP_ONCE +#define SUDO_EVBASE_LOOPEXIT 0x02 +#define SUDO_EVBASE_LOOPBREAK 0x04 +#define SUDO_EVBASE_LOOPCONT 0x08 +#define SUDO_EVBASE_GOT_EXIT 0x10 +#define SUDO_EVBASE_GOT_BREAK 0x20 +#define SUDO_EVBASE_GOT_MASK 0xf0 + +/* Must match sudo_plugin_ev_callback_t in sudo_plugin.h */ +typedef void (*sudo_ev_callback_t)(int fd, int what, void *closure); + +/* + * Container for SUDO_EV_SIGINFO events that gets passed as the closure + * pointer. This allows us to pass a siginfo_t without changing everything. + */ +struct sudo_ev_siginfo_container { + void *closure; + siginfo_t *siginfo; + char si_buf[1]; +}; + +/* Member of struct sudo_event_base. */ +struct sudo_event { + TAILQ_ENTRY(sudo_event) entries; + TAILQ_ENTRY(sudo_event) active_entries; + TAILQ_ENTRY(sudo_event) timeouts_entries; + struct sudo_event_base *base; /* base this event belongs to */ + int fd; /* fd/signal we are interested in */ + short events; /* SUDO_EV_* flags (in) */ + short revents; /* SUDO_EV_* flags (out) */ + short flags; /* internal event flags */ + short pfd_idx; /* index into pfds array (XXX) */ + sudo_ev_callback_t callback;/* user-provided callback */ + struct timespec timeout; /* for SUDO_EV_TIMEOUT */ + void *closure; /* user-provided data pointer */ +}; +TAILQ_HEAD(sudo_event_list, sudo_event); + +struct sudo_event_base { + struct sudo_event_list events; /* tail queue of all events */ + struct sudo_event_list active; /* tail queue of active events */ + struct sudo_event_list timeouts; /* tail queue of timeout events */ + struct sudo_event signal_event; /* storage for signal pipe event */ + struct sudo_event_list signals[NSIG]; /* array of signal event tail queues */ + struct sigaction *orig_handlers[NSIG]; /* original signal handlers */ + siginfo_t *siginfo[NSIG]; /* detailed signal info */ + sig_atomic_t signal_pending[NSIG]; /* pending signals */ + sig_atomic_t signal_caught; /* at least one signal caught */ + int num_handlers; /* number of installed handlers */ + int signal_pipe[2]; /* so we can wake up on signal */ +#if defined(HAVE_POLL) || defined(HAVE_PPOLL) + struct pollfd *pfds; /* array of struct pollfd */ + int pfd_max; /* size of the pfds array */ + int pfd_high; /* highest slot used */ + int pfd_free; /* idx of next free entry or pfd_max if full */ +#else + void *readfds_in; /* read I/O descriptor set (in) */ + void *writefds_in; /* write I/O descriptor set (in) */ + void *readfds_out; /* read I/O descriptor set (out) */ + void *writefds_out; /* write I/O descriptor set (out) */ + int maxfd; /* max fd we can store in readfds/writefds */ + int highfd; /* highest fd to pass as 1st arg to select */ +#endif /* HAVE_POLL */ + unsigned int flags; /* SUDO_EVBASE_* */ +}; + +/* Allocate a new event base. */ +sudo_dso_public struct sudo_event_base *sudo_ev_base_alloc_v1(void); +#define sudo_ev_base_alloc() sudo_ev_base_alloc_v1() + +/* Free an event base. */ +sudo_dso_public void sudo_ev_base_free_v1(struct sudo_event_base *base); +#define sudo_ev_base_free(_a) sudo_ev_base_free_v1((_a)) + +/* Set the default event base. */ +sudo_dso_public void sudo_ev_base_setdef_v1(struct sudo_event_base *base); +#define sudo_ev_base_setdef(_a) sudo_ev_base_setdef_v1((_a)) + +/* Allocate a new event. */ +sudo_dso_public struct sudo_event *sudo_ev_alloc_v1(int fd, short events, sudo_ev_callback_t callback, void *closure); +#define sudo_ev_alloc(_a, _b, _c, _d) sudo_ev_alloc_v1((_a), (_b), (_c), (_d)) + +/* Free an event. */ +sudo_dso_public void sudo_ev_free_v1(struct sudo_event *ev); +#define sudo_ev_free(_a) sudo_ev_free_v1((_a)) + +/* Set an event struct that was pre-allocated. */ +sudo_dso_public int sudo_ev_set_v1(struct sudo_event *ev, int fd, short events, sudo_ev_callback_t callback, void *closure); +#define sudo_ev_set(_a, _b, _c, _d, _e) sudo_ev_set_v1((_a), (_b), (_c), (_d), (_e)) + +/* Add an event, returns 0 on success, -1 on error */ +sudo_dso_public int sudo_ev_add_v1(struct sudo_event_base *head, struct sudo_event *ev, const struct timeval *timo, bool tohead); +sudo_dso_public int sudo_ev_add_v2(struct sudo_event_base *head, struct sudo_event *ev, const struct timespec *timo, bool tohead); +#define sudo_ev_add(_a, _b, _c, _d) sudo_ev_add_v2((_a), (_b), (_c), (_d)) + +/* Delete an event, returns 0 on success, -1 on error */ +sudo_dso_public int sudo_ev_del_v1(struct sudo_event_base *head, struct sudo_event *ev); +#define sudo_ev_del(_a, _b) sudo_ev_del_v1((_a), (_b)) + +/* Dispatch events, returns SUDO_CB_SUCCESS, SUDO_CB_BREAK or SUDO_CB_ERROR */ +sudo_dso_public int sudo_ev_dispatch_v1(struct sudo_event_base *head); +#define sudo_ev_dispatch(_a) sudo_ev_dispatch_v1((_a)) + +/* Main event loop, returns SUDO_CB_SUCCESS, SUDO_CB_BREAK or SUDO_CB_ERROR */ +sudo_dso_public int sudo_ev_loop_v1(struct sudo_event_base *head, int flags); +#define sudo_ev_loop(_a, _b) sudo_ev_loop_v1((_a), (_b)) + +/* Return pending event types, fills in ts if non-NULL and there is a timeout */ +sudo_dso_public int sudo_ev_pending_v1(struct sudo_event *ev, short events, struct timespec *ts); +#define sudo_ev_pending(_a, _b, _c) sudo_ev_pending_v1((_a), (_b), (_c)) + +/* Return the remaining timeout associated with an event (deprecated). */ +sudo_dso_public int sudo_ev_get_timeleft_v1(struct sudo_event *ev, struct timeval *tv); +sudo_dso_public int sudo_ev_get_timeleft_v2(struct sudo_event *ev, struct timespec *tv); +#define sudo_ev_get_timeleft(_a, _b) sudo_ev_get_timeleft_v2((_a), (_b)) + +/* Cause the event loop to exit after one run through. */ +sudo_dso_public void sudo_ev_loopexit_v1(struct sudo_event_base *base); +#define sudo_ev_loopexit(_a) sudo_ev_loopexit_v1((_a)) + +/* Break out of the event loop right now. */ +sudo_dso_public void sudo_ev_loopbreak_v1(struct sudo_event_base *base); +#define sudo_ev_loopbreak(_a) sudo_ev_loopbreak_v1((_a)) + +/* Rescan for events and restart the event loop. */ +sudo_dso_public void sudo_ev_loopcontinue_v1(struct sudo_event_base *base); +#define sudo_ev_loopcontinue(_a) sudo_ev_loopcontinue_v1((_a)) + +/* Returns true if event loop stopped due to sudo_ev_loopexit(). */ +sudo_dso_public bool sudo_ev_got_exit_v1(struct sudo_event_base *base); +#define sudo_ev_got_exit(_a) sudo_ev_got_exit_v1((_a)) + +/* Returns true if event loop stopped due to sudo_ev_loopbreak(). */ +sudo_dso_public bool sudo_ev_got_break_v1(struct sudo_event_base *base); +#define sudo_ev_got_break(_a) sudo_ev_got_break_v1((_a)) + +/* Return the fd associated with an event. */ +#define sudo_ev_get_fd(_ev) ((_ev) ? (_ev)->fd : -1) + +/* Return the (absolute) timeout associated with an event or NULL. */ +#define sudo_ev_get_timeout(_ev) \ + (ISSET((_ev)->flags, SUDO_EVQ_TIMEOUTS) ? &(_ev)->timeout : NULL) + +/* Return the base an event is associated with or NULL. */ +#define sudo_ev_get_base(_ev) ((_ev) ? (_ev)->base : NULL) + +/* Set the base an event is associated with. */ +#define sudo_ev_set_base(_ev, _b) ((_ev)->base = (_b)) + +/* Magic pointer value to use self pointer as callback arg. */ +#define sudo_ev_self_cbarg() ((void *)-1) + +/* Add an event to the base's active queue and mark it active (internal). */ +void sudo_ev_activate(struct sudo_event_base *base, struct sudo_event *ev); + +/* + * Backend implementation. + */ +int sudo_ev_base_alloc_impl(struct sudo_event_base *base); +void sudo_ev_base_free_impl(struct sudo_event_base *base); +int sudo_ev_add_impl(struct sudo_event_base *base, struct sudo_event *ev); +int sudo_ev_del_impl(struct sudo_event_base *base, struct sudo_event *ev); +int sudo_ev_scan_impl(struct sudo_event_base *base, int flags); + +#endif /* SUDO_EVENT_H */ diff --git a/include/sudo_eventlog.h b/include/sudo_eventlog.h new file mode 100644 index 0000000..0e30ec4 --- /dev/null +++ b/include/sudo_eventlog.h @@ -0,0 +1,162 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2020-2021 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. + */ + +#ifndef SUDO_EVENTLOG_H +#define SUDO_EVENTLOG_H + +#include <sys/types.h> /* for gid_t, uid_t */ +#include <time.h> /* for struct timespec */ +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ + +/* Supported event types. */ +enum event_type { + EVLOG_ACCEPT, + EVLOG_REJECT, + EVLOG_EXIT, + EVLOG_ALERT +}; + +/* Supported eventlog types (bitmask). */ +#define EVLOG_NONE 0x00 +#define EVLOG_SYSLOG 0x01 +#define EVLOG_FILE 0x02 + +/* Supported eventlog formats. */ +enum eventlog_format { + EVLOG_SUDO, + EVLOG_JSON +}; + +/* Eventlog flag values. */ +#define EVLOG_RAW 0x01 /* only include message and errstr */ +#define EVLOG_MAIL 0x02 /* mail the log message too */ +#define EVLOG_MAIL_ONLY 0x04 /* only mail the message, no other logging */ +#define EVLOG_CWD 0x08 /* log cwd if no runcwd and use CWD, not PWD */ + +/* + * Maximum number of characters to log per entry. The syslogger + * will log this much, after that, it truncates the log line. + * We need this here to make sure that we continue with another + * syslog(3) call if the internal buffer is more than 1023 characters. + */ +#ifndef MAXSYSLOGLEN +# define MAXSYSLOGLEN 960 +#endif + +/* + * Indentation level for file-based logs when word wrap is enabled. + */ +#define EVENTLOG_INDENT " " + +/* + * Event log config, used with eventlog_getconf() + */ +struct eventlog_config { + int type; + enum eventlog_format format; + int syslog_acceptpri; + int syslog_rejectpri; + int syslog_alertpri; + int syslog_maxlen; + int file_maxlen; + uid_t mailuid; + bool omit_hostname; + const char *logpath; + const char *time_fmt; + const char *mailerpath; + const char *mailerflags; + const char *mailfrom; + const char *mailto; + const char *mailsub; + FILE *(*open_log)(int type, const char *); + void (*close_log)(int type, FILE *); +}; + +/* + * Info present in the eventlog file, regardless of format. + */ +struct eventlog { + char *iolog_path; + const char *iolog_file; /* substring of iolog_path, do not free */ + char *command; + char *cwd; + char *runchroot; + char *runcwd; + char *rungroup; + char *runuser; + char *peeraddr; + char *signal_name; + char *submithost; + char *submituser; + char *submitgroup; + char *ttyname; + char **argv; + char **env_add; + char **envp; + struct timespec submit_time; + struct timespec iolog_offset; + struct timespec run_time; + int exit_value; + int lines; + int columns; + uid_t runuid; + gid_t rungid; + bool dumped_core; + char sessid[7]; + char uuid_str[37]; +}; + +/* Callback from eventlog code to write log info */ +struct json_container; +struct sudo_lbuf; +typedef bool (*eventlog_json_callback_t)(struct json_container *, void *); + +bool eventlog_accept(const struct eventlog *evlog, int flags, eventlog_json_callback_t info_cb, void *info); +bool eventlog_exit(const struct eventlog *evlog, int flags); +bool eventlog_alert(const struct eventlog *evlog, int flags, struct timespec *alert_time, const char *reason, const char *errstr); +bool eventlog_mail(const struct eventlog *evlog, int flags, struct timespec *event_time, const char *reason, const char *errstr, char * const extra[]); +bool eventlog_reject(const struct eventlog *evlog, int flags, const char *reason, eventlog_json_callback_t info_cb, void *info); +bool eventlog_store_json(struct json_container *jsonc, const struct eventlog *evlog); +bool eventlog_store_sudo(int event_type, const struct eventlog *evlog, struct sudo_lbuf *lbuf); +size_t eventlog_writeln(FILE *fp, char *line, size_t len, size_t maxlen); +void eventlog_free(struct eventlog *evlog); +void eventlog_set_type(int type); +void eventlog_set_format(enum eventlog_format format); +void eventlog_set_syslog_acceptpri(int pri); +void eventlog_set_syslog_rejectpri(int pri); +void eventlog_set_syslog_alertpri(int pri); +void eventlog_set_syslog_maxlen(int len); +void eventlog_set_file_maxlen(int len); +void eventlog_set_mailuid(uid_t uid); +void eventlog_set_omit_hostname(bool omit_hostname); +void eventlog_set_logpath(const char *path); +void eventlog_set_time_fmt(const char *fmt); +void eventlog_set_mailerpath(const char *path); +void eventlog_set_mailerflags(const char *mflags); +void eventlog_set_mailfrom(const char *from_addr); +void eventlog_set_mailto(const char *to_addr); +void eventlog_set_mailsub(const char *subject); +void eventlog_set_open_log(FILE *(*fn)(int type, const char *)); +void eventlog_set_close_log(void (*fn)(int type, FILE *)); +const struct eventlog_config *eventlog_getconf(void); + +#endif /* SUDO_EVENTLOG_H */ diff --git a/include/sudo_fatal.h b/include/sudo_fatal.h new file mode 100644 index 0000000..0819e63 --- /dev/null +++ b/include/sudo_fatal.h @@ -0,0 +1,211 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2004, 2010-2015, 2017-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. + */ + +#ifndef SUDO_FATAL_H +#define SUDO_FATAL_H + +#include <stdarg.h> +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ + +#include "sudo_plugin.h" /* for conversation function */ + +/* No output to debug files when fuzzing. */ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +# define SUDO_ERROR_WRAP 0 +#endif + +/* + * We wrap fatal/fatalx and warn/warnx so that the same output can + * go to the debug file, if there is one. + */ +#if (defined(SUDO_ERROR_WRAP) && SUDO_ERROR_WRAP == 0) || defined(NO_VARIADIC_MACROS) +# define sudo_fatal sudo_fatal_nodebug_v1 +# define sudo_fatalx sudo_fatalx_nodebug_v1 +# define sudo_gai_fatal sudo_gai_fatal_nodebug_v1 +# define sudo_warn sudo_warn_nodebug_v1 +# define sudo_warnx sudo_warnx_nodebug_v1 +# define sudo_gai_warn sudo_gai_warn_nodebug_v1 +# define sudo_vfatal(fmt, ap) sudo_vfatal_nodebug_v1((fmt), (ap)) +# define sudo_vfatalx(fmt, ap) sudo_vfatalx_nodebug_v1((fmt), (ap)) +# define sudo_gai_vfatal(en, fmt, ap) sudo_vfatal_nodebug_v1((en), (fmt), (ap)) +# define sudo_vwarn(fmt, ap) sudo_vwarn_nodebug_v1((fmt), (ap)) +# define sudo_vwarnx(fmt, ap) sudo_vwarnx_nodebug_v1((fmt), (ap)) +# define sudo_gai_vwarn(en, fmt, ap) sudo_vwarn_nodebug_v1((en), (fmt), (ap)) +#else /* SUDO_ERROR_WRAP */ +# if defined(__GNUC__) && __GNUC__ == 2 +# define sudo_fatal(fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + fmt); \ + sudo_fatal_nodebug_v1(fmt); \ +} while (0) +# define sudo_fatalx(fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, fmt); \ + sudo_fatalx_nodebug_v1(fmt); \ +} while (0) +# define sudo_gai_fatal(en, fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, fmt); \ + sudo_gai_fatal_nodebug_v1((en), fmt); \ +} while (0) +# define sudo_warn(fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + fmt); \ + sudo_warn_nodebug_v1(fmt); \ +} while (0) +# define sudo_warnx(fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, fmt); \ + sudo_warnx_nodebug_v1(fmt); \ +} while (0) +# define sudo_gai_warn(en, fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, fmt); \ + sudo_gai_warn_nodebug_v1((en), fmt); \ +} while (0) +# else +# define sudo_fatal(...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + __VA_ARGS__); \ + sudo_fatal_nodebug_v1(__VA_ARGS__); \ +} while (0) +# define sudo_fatalx(...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, __VA_ARGS__); \ + sudo_fatalx_nodebug_v1(__VA_ARGS__); \ +} while (0) +# define sudo_gai_fatal(en, ...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, __VA_ARGS__); \ + sudo_gai_fatal_nodebug_v1((en), __VA_ARGS__); \ +} while (0) +# define sudo_warn(...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + __VA_ARGS__); \ + sudo_warn_nodebug_v1(__VA_ARGS__); \ +} while (0) +# define sudo_warnx(...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|sudo_debug_subsys, __VA_ARGS__); \ + sudo_warnx_nodebug_v1(__VA_ARGS__); \ +} while (0) +# define sudo_gai_warn(en, ...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|sudo_debug_subsys, __VA_ARGS__); \ + sudo_gai_warn_nodebug_v1((en), __VA_ARGS__); \ +} while (0) +# endif /* __GNUC__ == 2 */ +# define sudo_vfatal(fmt, ap) do { \ + va_list ap2; \ + va_copy(ap2, (ap)); \ + sudo_debug_vprintf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + (fmt), ap2); \ + sudo_vfatal_nodebug_v1((fmt), (ap)); \ +} while (0) +# define sudo_vfatalx(fmt, ap) do { \ + va_list ap2; \ + va_copy(ap2, (ap)); \ + sudo_debug_vprintf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, (fmt), ap2); \ + sudo_vfatalx_nodebug_v1((fmt), (ap)); \ +} while (0) +# define sudo_gai_vfatal(en, fmt, ap) do { \ + va_list ap2; \ + va_copy(ap2, (ap)); \ + sudo_debug_vprintf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, (fmt), ap2); \ + sudo_gai_vfatal_nodebug_v1((en), (fmt), (ap)); \ +} while (0) +# define sudo_vwarn(fmt, ap) do { \ + va_list ap2; \ + va_copy(ap2, (ap)); \ + sudo_debug_vprintf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + (fmt), ap2); \ + sudo_vwarn_nodebug_v1((fmt), (ap)); \ +} while (0) +# define sudo_vwarnx(fmt, ap) do { \ + va_list ap2; \ + va_copy(ap2, (ap)); \ + sudo_debug_vprintf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|sudo_debug_subsys, (fmt), ap2); \ + sudo_vwarnx_nodebug_v1((fmt), (ap)); \ +} while (0) +# define sudo_gai_vwarn(en, fmt, ap) do { \ + va_list ap2; \ + va_copy(ap2, (ap)); \ + sudo_debug_vprintf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|sudo_debug_subsys, (fmt), ap2); \ + sudo_gai_vwarn_nodebug_v1((en), (fmt), (ap)); \ +} while (0) +#endif /* SUDO_ERROR_WRAP */ + +typedef void (*sudo_fatal_callback_t)(void); +typedef bool (*sudo_warn_setlocale_t)(bool, int *); + +sudo_dso_public int sudo_fatal_callback_deregister_v1(sudo_fatal_callback_t func); +sudo_dso_public int sudo_fatal_callback_register_v1(sudo_fatal_callback_t func); +sudo_dso_public char *sudo_warn_gettext_v1(const char *domainname, const char *msgid) sudo_attr_fmt_arg(2); +sudo_dso_public void sudo_warn_set_locale_func_v1(sudo_warn_setlocale_t func); +sudo_noreturn sudo_dso_public void sudo_fatal_nodebug_v1(const char *fmt, ...) sudo_printf0like(1, 2); +sudo_noreturn sudo_dso_public void sudo_fatalx_nodebug_v1(const char *fmt, ...) sudo_printflike(1, 2); +sudo_noreturn sudo_dso_public void sudo_gai_fatal_nodebug_v1(int errnum, const char *fmt, ...) sudo_printflike(2, 3); +sudo_noreturn sudo_dso_public void sudo_vfatal_nodebug_v1(const char *fmt, va_list ap) sudo_printf0like(1, 0); +sudo_noreturn sudo_dso_public void sudo_vfatalx_nodebug_v1(const char *fmt, va_list ap) sudo_printflike(1, 0); +sudo_noreturn sudo_dso_public void sudo_gai_vfatal_nodebug_v1(int errnum, const char *fmt, va_list ap) sudo_printflike(2, 0); +sudo_dso_public void sudo_warn_nodebug_v1(const char *fmt, ...) sudo_printf0like(1, 2); +sudo_dso_public void sudo_warnx_nodebug_v1(const char *fmt, ...) sudo_printflike(1, 2); +sudo_dso_public void sudo_gai_warn_nodebug_v1(int errnum, const char *fmt, ...) sudo_printflike(2, 3); +sudo_dso_public void sudo_vwarn_nodebug_v1(const char *fmt, va_list ap) sudo_printf0like(1, 0); +sudo_dso_public void sudo_vwarnx_nodebug_v1(const char *fmt, va_list ap) sudo_printflike(1, 0); +sudo_dso_public void sudo_gai_vwarn_nodebug_v1(int errnum, const char *fmt, va_list ap) sudo_printflike(2, 0); +sudo_dso_public void sudo_warn_set_conversation_v1(sudo_conv_t conv); + +#define sudo_fatal_callback_deregister(_a) sudo_fatal_callback_deregister_v1((_a)) +#define sudo_fatal_callback_register(_a) sudo_fatal_callback_register_v1((_a)) +#define sudo_warn_set_locale_func(_a) sudo_warn_set_locale_func_v1((_a)) +#define sudo_fatal_nodebug sudo_fatal_nodebug_v1 +#define sudo_fatalx_nodebug sudo_fatalx_nodebug_v1 +#define sudo_gai_fatal_nodebug sudo_gai_fatal_nodebug_v1 +#define sudo_vfatal_nodebug(_a, _b) sudo_vfatal_nodebug_v1((_a), (_b)) +#define sudo_vfatalx_nodebug(_a, _b) sudo_vfatalx_nodebug_v1((_a), (_b)) +#define sudo_gai_vfatal_nodebug(_a, _b, _c) sudo_gai_vfatal_nodebug_v1((_a), (_b), (_c)) +#define sudo_warn_nodebug sudo_warn_nodebug_v1 +#define sudo_warnx_nodebug sudo_warnx_nodebug_v1 +#define sudo_gai_warn_nodebug sudo_gai_warn_nodebug_v1 +#define sudo_vwarn_nodebug(_a, _b) sudo_vwarn_nodebug_v1((_a), (_b)) +#define sudo_vwarnx_nodebug(_a, _b) sudo_vwarnx_nodebug_v1((_a), (_b)) +#define sudo_gai_vwarn_nodebug(_a, _b, _c) sudo_gai_vwarn_nodebug_v1((_a), (_b), (_c)) +#define sudo_warn_set_conversation(_a) sudo_warn_set_conversation_v1(_a) + +#ifdef DEFAULT_TEXT_DOMAIN +# define sudo_warn_gettext(_a) sudo_warn_gettext_v1(DEFAULT_TEXT_DOMAIN, (_a)) +#else +# define sudo_warn_gettext(_a) sudo_warn_gettext_v1(NULL, (_a)) +#endif + +#endif /* SUDO_FATAL_H */ diff --git a/include/sudo_gettext.h b/include/sudo_gettext.h new file mode 100644 index 0000000..16275ab --- /dev/null +++ b/include/sudo_gettext.h @@ -0,0 +1,77 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2011-2014 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. + */ + +#ifndef SUDO_GETTEXT_H +#define SUDO_GETTEXT_H + +/* + * Solaris locale.h includes libintl.h which causes problems when we + * redefine the gettext functions. We include it first to avoid this. + */ +#include <locale.h> + +#ifdef HAVE_LIBINTL_H + +# include <libintl.h> + +/* + * If DEFAULT_TEXT_DOMAIN is defined, use its value as the domain for + * gettext() and ngettext() instead of the value set by textdomain(). + * This is used by the sudoers plugin as well as the convenience libraries. + */ +# ifdef DEFAULT_TEXT_DOMAIN +# undef gettext +# define gettext(String) \ + dgettext(DEFAULT_TEXT_DOMAIN, String) +# undef ngettext +# define ngettext(String, String_Plural, N) \ + dngettext(DEFAULT_TEXT_DOMAIN, String, String_Plural, N) +# endif + +/* + * Older versions of Solaris lack ngettext() so we have to kludge it. + */ +# ifndef HAVE_NGETTEXT +# undef ngettext +# define ngettext(String, String_Plural, N) \ + ((N) == 1 ? gettext(String) : gettext(String_Plural)) +# endif + +/* Gettext convenience macros */ +# define _(String) gettext(String) +# define gettext_noop(String) String +# define N_(String) gettext_noop(String) +# define U_(String) sudo_warn_gettext(String) + +#else /* !HAVE_LIBINTL_H */ + +/* + * Internationalization is either unavailable or has been disabled. + * Define away the gettext functions used by sudo. + */ +# define _(String) String +# define N_(String) String +# define U_(String) String +# define textdomain(Domain) +# define bindtextdomain(Package, Directory) +# define ngettext(String, String_Plural, N) \ + ((N) == 1 ? (String) : (String_Plural)) + +#endif /* HAVE_LIBINTL_H */ + +#endif /* SUDO_GETTEXT_H */ diff --git a/include/sudo_iolog.h b/include/sudo_iolog.h new file mode 100644 index 0000000..5994241 --- /dev/null +++ b/include/sudo_iolog.h @@ -0,0 +1,155 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2009-2022 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. + */ + +#ifndef SUDO_IOLOG_H +#define SUDO_IOLOG_H + +#include <sys/types.h> /* for gid_t, mode_t, size_t, ssize_t, uid_t */ + +#ifdef HAVE_ZLIB_H +# include <zlib.h> /* for gzFile */ +#endif + +/* Default maximum session ID */ +#define SESSID_MAX 2176782336U + +/* + * I/O log event types as stored as the first field in the timing file. + * Changing existing values will result in incompatible I/O log files. + */ +#define IO_EVENT_STDIN 0 +#define IO_EVENT_STDOUT 1 +#define IO_EVENT_STDERR 2 +#define IO_EVENT_TTYIN 3 +#define IO_EVENT_TTYOUT 4 +#define IO_EVENT_WINSIZE 5 +#define IO_EVENT_TTYOUT_1_8_7 6 +#define IO_EVENT_SUSPEND 7 +#define IO_EVENT_COUNT 8 + +/* + * Indexes into iolog_files[] array. + * These must match the IO_EVENT_ defines above. + * TODO: eliminate use of IOFD_* and IO_EVENT_* as indexes in favor of + * a struct containing iolog_file *s for each (and names too?). + */ +#define IOFD_STDIN 0 +#define IOFD_STDOUT 1 +#define IOFD_STDERR 2 +#define IOFD_TTYIN 3 +#define IOFD_TTYOUT 4 +#define IOFD_TIMING 5 +#define IOFD_MAX 6 + +/* + * Default password prompt regex. + */ +#define PASSPROMPT_REGEX "[Pp]assword[: ]*" + +struct timing_closure { + struct timespec delay; + const char *decimal; + struct iolog_file *iol; + int event; + union { + struct { + int lines; + int cols; + } winsize; + size_t nbytes; + int signo; + } u; +}; + +struct iolog_file { + bool enabled; + bool compressed; + bool writable; + union { + FILE *f; +#ifdef HAVE_ZLIB_H + gzFile g; +#endif + void *v; + } fd; +}; + +struct iolog_path_escape { + const char *name; + size_t (*copy_fn)(char *, size_t, void *); +}; + +/* host_port.c */ +bool iolog_parse_host_port(char *str, char **hostp, char **portp, bool *tlsp, const char *defport, const char *defport_tls); + +/* iolog_path.c */ +bool expand_iolog_path(const char *inpath, char *path, size_t pathlen, const struct iolog_path_escape *escapes, void *closure); + +/* iolog_util.c */ +bool iolog_parse_timing(const char *line, struct timing_closure *timing); +char *iolog_parse_delay(const char *cp, struct timespec *delay, const char *decimal_point); +int iolog_read_timing_record(struct iolog_file *iol, struct timing_closure *timing); +struct eventlog *iolog_parse_loginfo(int dfd, const char *iolog_dir); +bool iolog_parse_loginfo_json(FILE *fp, const char *iolog_dir, struct eventlog *evlog); +bool iolog_parse_loginfo_legacy(FILE *fp, const char *iolog_dir, struct eventlog *evlog); +void iolog_adjust_delay(struct timespec *delay, struct timespec *max_delay, double scale_factor); + +/* iolog_fileio.c */ +struct passwd; +struct group; +bool iolog_close(struct iolog_file *iol, const char **errstr); +bool iolog_eof(struct iolog_file *iol); +bool iolog_mkdtemp(char *path); +bool iolog_mkpath(char *path); +bool iolog_nextid(const char *iolog_dir, char sessid[7]); +bool iolog_open(struct iolog_file *iol, int dfd, int iofd, const char *mode); +bool iolog_write_info_file(int dfd, struct eventlog *evlog); +char *iolog_gets(struct iolog_file *iol, char *buf, size_t nbytes, const char **errsttr); +const char *iolog_fd_to_name(int iofd); +int iolog_openat(int fdf, const char *path, int flags); +off_t iolog_seek(struct iolog_file *iol, off_t offset, int whence); +ssize_t iolog_read(struct iolog_file *iol, void *buf, size_t nbytes, const char **errstr); +ssize_t iolog_write(struct iolog_file *iol, const void *buf, size_t len, const char **errstr); +void iolog_clearerr(struct iolog_file *iol); +bool iolog_flush(struct iolog_file *iol, const char **errstr); +void iolog_rewind(struct iolog_file *iol); +unsigned int iolog_get_maxseq(void); +uid_t iolog_get_uid(void); +gid_t iolog_get_gid(void); +mode_t iolog_get_file_mode(void); +mode_t iolog_get_dir_mode(void); +bool iolog_get_compress(void); +bool iolog_get_flush(void); +void iolog_set_compress(bool); +void iolog_set_defaults(void); +void iolog_set_flush(bool); +void iolog_set_gid(gid_t gid); +void iolog_set_maxseq(unsigned int maxval); +void iolog_set_mode(mode_t mode); +void iolog_set_owner(uid_t uid, uid_t gid); +bool iolog_swapids(bool restore); +bool iolog_mkdirs(const char *path); + +/* iolog_filter.c */ +void *iolog_pwfilt_alloc(void); +bool iolog_pwfilt_add(void *handle, const char *pattern); +void iolog_pwfilt_free(void *handle); +bool iolog_pwfilt_remove(void *handle, const char *pattern); +bool iolog_pwfilt_run(void *handle, int event, const char *buf, unsigned int len, char **newbuf); + +#endif /* SUDO_IOLOG_H */ diff --git a/include/sudo_json.h b/include/sudo_json.h new file mode 100644 index 0000000..d7f2f19 --- /dev/null +++ b/include/sudo_json.h @@ -0,0 +1,100 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2013-2020 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. + */ + +#ifndef SUDO_JSON_H +#define SUDO_JSON_H + +#include <sys/types.h> /* for id_t */ + +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# include "compat/stdbool.h" +#endif + +/* + * JSON values may be of the following types. + */ +enum json_value_type { + JSON_STRING, + JSON_ID, + JSON_NUMBER, + JSON_OBJECT, + JSON_ARRAY, + JSON_BOOL, + JSON_NULL +}; + +/* + * JSON value suitable for printing. + * Note: this does not support object values. + */ +struct json_value { + enum json_value_type type; + union { + const char *string; + long long number; + id_t id; + bool boolean; + } u; +}; + +struct json_container { + char *buf; + unsigned int buflen; + unsigned int bufsize; + unsigned int indent_level; + unsigned int indent_increment; + bool minimal; + bool memfatal; + bool need_comma; + bool quiet; +}; + +sudo_dso_public bool sudo_json_init_v1(struct json_container *jsonc, int indent, bool minimal, bool memfatal); +sudo_dso_public bool sudo_json_init_v2(struct json_container *jsonc, int indent, bool minimal, bool memfatal, bool quiet); +#define sudo_json_init(_a, _b, _c, _d, _e) sudo_json_init_v2((_a), (_b), (_c), (_d), (_e)) + +sudo_dso_public void sudo_json_free_v1(struct json_container *jsonc); +#define sudo_json_free(_a) sudo_json_free_v1((_a)) + +sudo_dso_public bool sudo_json_open_object_v1(struct json_container *jsonc, const char *name); +#define sudo_json_open_object(_a, _b) sudo_json_open_object_v1((_a), (_b)) + +sudo_dso_public bool sudo_json_close_object_v1(struct json_container *jsonc); +#define sudo_json_close_object(_a) sudo_json_close_object_v1((_a)) + +sudo_dso_public bool sudo_json_open_array_v1(struct json_container *jsonc, const char *name); +#define sudo_json_open_array(_a, _b) sudo_json_open_array_v1((_a), (_b)) + +sudo_dso_public bool sudo_json_close_array_v1(struct json_container *jsonc); +#define sudo_json_close_array(_a) sudo_json_close_array_v1((_a)) + +sudo_dso_public bool sudo_json_add_value_v1(struct json_container *jsonc, const char *name, struct json_value *value); +#define sudo_json_add_value(_a, _b, _c) sudo_json_add_value_v1((_a), (_b), (_c)) + +sudo_dso_public bool sudo_json_add_value_as_object_v1(struct json_container *jsonc, const char *name, struct json_value *value); +#define sudo_json_add_value_as_object(_a, _b, _c) sudo_json_add_value_as_object_v1((_a), (_b), (_c)) + +sudo_dso_public char *sudo_json_get_buf_v1(struct json_container *jsonc); +#define sudo_json_get_buf(_a) sudo_json_get_buf_v1((_a)) + +sudo_dso_public unsigned int sudo_json_get_len_v1(struct json_container *jsonc); +#define sudo_json_get_len(_a) sudo_json_get_len_v1((_a)) + +#endif /* SUDO_JSON_H */ diff --git a/include/sudo_lbuf.h b/include/sudo_lbuf.h new file mode 100644 index 0000000..29090cb --- /dev/null +++ b/include/sudo_lbuf.h @@ -0,0 +1,62 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2007, 2010, 2011, 2013-2015, 2023 + * 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. + */ + +#ifndef SUDO_LBUF_H +#define SUDO_LBUF_H + +/* + * Line buffer struct. + */ +struct sudo_lbuf { + int (*output)(const char *); + char *buf; + const char *continuation; + unsigned int indent; + unsigned int len; + unsigned int size; + unsigned short cols; + unsigned short error; +}; + +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 + +sudo_dso_public void sudo_lbuf_init_v1(struct sudo_lbuf *lbuf, sudo_lbuf_output_t output, int indent, const char *continuation, int cols); +sudo_dso_public void sudo_lbuf_destroy_v1(struct sudo_lbuf *lbuf); +sudo_dso_public bool sudo_lbuf_append_v1(struct sudo_lbuf *lbuf, const char *fmt, ...) sudo_printflike(2, 3); +sudo_dso_public bool sudo_lbuf_append_esc_v1(struct sudo_lbuf *lbuf, int flags, const char *fmt, ...) sudo_printflike(3, 4); +sudo_dso_public bool sudo_lbuf_append_quoted_v1(struct sudo_lbuf *lbuf, const char *set, const char *fmt, ...) sudo_printflike(3, 4); +sudo_dso_public void sudo_lbuf_print_v1(struct sudo_lbuf *lbuf); +sudo_dso_public bool sudo_lbuf_error_v1(struct sudo_lbuf *lbuf); +sudo_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)) +#define sudo_lbuf_clearerr(_a) sudo_lbuf_clearerr_v1((_a)) + +#endif /* SUDO_LBUF_H */ diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h new file mode 100644 index 0000000..e363637 --- /dev/null +++ b/include/sudo_plugin.h @@ -0,0 +1,288 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2009-2023 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. + */ + +#ifndef SUDO_PLUGIN_H +#define SUDO_PLUGIN_H + +/* API version major/minor */ +#define SUDO_API_VERSION_MAJOR 1 +#define SUDO_API_VERSION_MINOR 21 +#define SUDO_API_MKVERSION(x, y) (((x) << 16) | (y)) +#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR) + +/* Getters and setters for plugin API versions */ +#define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16) +#define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffffU) +#define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffffU) | ((n) << 16); \ +} while(0) +#define SUDO_API_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000U) | (n); \ +} while(0) + +/* "plugin type" for the sudo front end, as passed to an audit plugin */ +#define SUDO_FRONT_END 0 + +/* Conversation function types and defines */ +struct sudo_conv_message { +#define SUDO_CONV_PROMPT_ECHO_OFF 0x0001 /* do not echo user input */ +#define SUDO_CONV_PROMPT_ECHO_ON 0x0002 /* echo user input */ +#define SUDO_CONV_ERROR_MSG 0x0003 /* error message */ +#define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ +#define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ +#define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ +#define SUDO_CONV_PREFER_TTY 0x2000 /* flag: use tty if possible */ + int msg_type; + int timeout; + const char *msg; +}; + +/* + * Maximum length of a reply (not including the trailing NUL) when + * conversing with the user. In practical terms, this is the longest + * password sudo will support. This means that a buffer of size + * SUDO_CONV_REPL_MAX+1 is guaranteed to be able to hold any reply + * from the conversation function. + */ +#define SUDO_CONV_REPL_MAX 1023 + +struct sudo_conv_reply { + char *reply; +}; + +/* Conversation callback API version major/minor */ +#define SUDO_CONV_CALLBACK_VERSION_MAJOR 1 +#define SUDO_CONV_CALLBACK_VERSION_MINOR 0 +#define SUDO_CONV_CALLBACK_VERSION SUDO_API_MKVERSION(SUDO_CONV_CALLBACK_VERSION_MAJOR, SUDO_CONV_CALLBACK_VERSION_MINOR) + +/* + * Callback struct to be passed to the conversation function. + * Can be used to perform operations on suspend/resume such + * as dropping/acquiring locks. + */ +typedef int (*sudo_conv_callback_fn_t)(int signo, void *closure); +struct sudo_conv_callback { + unsigned int version; + void *closure; + sudo_conv_callback_fn_t on_suspend; + sudo_conv_callback_fn_t on_resume; +}; + +typedef int (*sudo_conv_t)(int num_msgs, const struct sudo_conv_message msgs[], + struct sudo_conv_reply replies[], struct sudo_conv_callback *callback); +typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...); + +/* + * Hooks allow a plugin to hook into specific sudo and/or libc functions. + */ + +#if defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4) +# pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif + +/* Hook functions typedefs. */ +typedef int (*sudo_hook_fn_t)(); +typedef int (*sudo_hook_fn_setenv_t)(const char *name, const char *value, int overwrite, void *closure); +typedef int (*sudo_hook_fn_putenv_t)(char *string, void *closure); +typedef int (*sudo_hook_fn_getenv_t)(const char *name, char **value, void *closure); +typedef int (*sudo_hook_fn_unsetenv_t)(const char *name, void *closure); + +/* Hook structure definition. */ +struct sudo_hook { + unsigned int hook_version; + unsigned int hook_type; + sudo_hook_fn_t hook_fn; + void *closure; +}; + +/* Hook API version major/minor */ +#define SUDO_HOOK_VERSION_MAJOR 1 +#define SUDO_HOOK_VERSION_MINOR 0 +#define SUDO_HOOK_VERSION SUDO_API_MKVERSION(SUDO_HOOK_VERSION_MAJOR, SUDO_HOOK_VERSION_MINOR) + +/* + * Hook function return values. + */ +#define SUDO_HOOK_RET_ERROR -1 /* error */ +#define SUDO_HOOK_RET_NEXT 0 /* go to the next hook in the list */ +#define SUDO_HOOK_RET_STOP 1 /* stop hook processing for this type */ + +/* + * Hooks for setenv/unsetenv/putenv/getenv. + * This allows the plugin to be notified when a PAM module modifies + * the environment so it can update the copy of the environment that + * is passed to execve(). + */ +#define SUDO_HOOK_SETENV 1 +#define SUDO_HOOK_UNSETENV 2 +#define SUDO_HOOK_PUTENV 3 +#define SUDO_HOOK_GETENV 4 + +/* + * Plugin interface to sudo's main event loop. + */ +typedef void (*sudo_plugin_ev_callback_t)(int fd, int what, void *closure); + +struct timespec; +struct sudo_plugin_event { + int (*set)(struct sudo_plugin_event *pev, int fd, int events, sudo_plugin_ev_callback_t callback, void *closure); + int (*add)(struct sudo_plugin_event *pev, struct timespec *timeout); + int (*del)(struct sudo_plugin_event *pev); + int (*pending)(struct sudo_plugin_event *pev, int events, struct timespec *ts); + int (*fd)(struct sudo_plugin_event *pev); + void (*setbase)(struct sudo_plugin_event *pev, void *base); + void (*loopbreak)(struct sudo_plugin_event *pev); + void (*free)(struct sudo_plugin_event *pev); + /* actually larger... */ +}; + +/* Sudo plugin Event types */ +#define SUDO_PLUGIN_EV_TIMEOUT 0x01 /* fire after timeout */ +#define SUDO_PLUGIN_EV_READ 0x02 /* fire when readable */ +#define SUDO_PLUGIN_EV_WRITE 0x04 /* fire when writable */ +#define SUDO_PLUGIN_EV_PERSIST 0x08 /* persist until deleted */ +#define SUDO_PLUGIN_EV_SIGNAL 0x10 /* fire on signal receipt */ + +/* Policy plugin type and defines. */ +struct passwd; +struct policy_plugin { +#define SUDO_POLICY_PLUGIN 1 + unsigned int type; /* always SUDO_POLICY_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_plugin_printf, char * const settings[], + char * const user_info[], char * const user_env[], + char * const plugin_options[], const char **errstr); + void (*close)(int exit_status, int error); /* wait status or error */ + int (*show_version)(int verbose); + int (*check_policy)(int argc, char * const argv[], + char *env_add[], char **command_info[], + char **argv_out[], char **user_env_out[], const char **errstr); + int (*list)(int argc, char * const argv[], int verbose, + const char *user, const char **errstr); + int (*validate)(const char **errstr); + void (*invalidate)(int rmcred); + int (*init_session)(struct passwd *pwd, char **user_env_out[], + const char **errstr); + void (*register_hooks)(int version, int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook)); + struct sudo_plugin_event * (*event_alloc)(void); +}; + +/* I/O plugin type and defines. */ +struct io_plugin { +#define SUDO_IO_PLUGIN 2 + unsigned int type; /* always SUDO_IO_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_plugin_printf, char * const settings[], + char * const user_info[], char * const command_info[], + int argc, char * const argv[], char * const user_env[], + char * const plugin_options[], const char **errstr); + void (*close)(int exit_status, int error); /* wait status or error */ + int (*show_version)(int verbose); + int (*log_ttyin)(const char *buf, unsigned int len, const char **errstr); + int (*log_ttyout)(const char *buf, unsigned int len, const char **errstr); + int (*log_stdin)(const char *buf, unsigned int len, const char **errstr); + int (*log_stdout)(const char *buf, unsigned int len, const char **errstr); + int (*log_stderr)(const char *buf, unsigned int len, const char **errstr); + void (*register_hooks)(int version, + int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, + int (*deregister_hook)(struct sudo_hook *hook)); + int (*change_winsize)(unsigned int line, unsigned int cols, + const char **errstr); + int (*log_suspend)(int signo, const char **errstr); + struct sudo_plugin_event * (*event_alloc)(void); +}; + +/* Differ audit plugin close status types. */ +#define SUDO_PLUGIN_NO_STATUS 0 +#define SUDO_PLUGIN_WAIT_STATUS 1 +#define SUDO_PLUGIN_EXEC_ERROR 2 +#define SUDO_PLUGIN_SUDO_ERROR 3 + +/* Audit plugin type and defines */ +struct audit_plugin { +#define SUDO_AUDIT_PLUGIN 3 + unsigned int type; /* always SUDO_AUDIT_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_plugin_printf, char * const settings[], + char * const user_info[], int submit_optind, + char * const submit_argv[], char * const submit_envp[], + char * const plugin_options[], const char **errstr); + void (*close)(int status_type, int status); + int (*accept)(const char *plugin_name, unsigned int plugin_type, + char * const command_info[], char * const run_argv[], + char * const run_envp[], const char **errstr); + int (*reject)(const char *plugin_name, unsigned int plugin_type, + const char *audit_msg, char * const command_info[], + const char **errstr); + int (*error)(const char *plugin_name, unsigned int plugin_type, + const char *audit_msg, char * const command_info[], + const char **errstr); + int (*show_version)(int verbose); + void (*register_hooks)(int version, int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook)); + struct sudo_plugin_event * (*event_alloc)(void); +}; + +/* Approval plugin type and defines */ +struct approval_plugin { +#define SUDO_APPROVAL_PLUGIN 4 + unsigned int type; /* always SUDO_APPROVAL_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_plugin_printf, char * const settings[], + char * const user_info[], int submit_optind, + char * const submit_argv[], char * const submit_envp[], + char * const plugin_options[], const char **errstr); + void (*close)(void); + int (*check)(char * const command_info[], char * const run_argv[], + char * const run_envp[], const char **errstr); + int (*show_version)(int verbose); +}; + +/* Sudoers group plugin version major/minor */ +#define GROUP_API_VERSION_MAJOR 1 +#define GROUP_API_VERSION_MINOR 0 +#define GROUP_API_VERSION SUDO_API_MKVERSION(GROUP_API_VERSION_MAJOR, GROUP_API_VERSION_MINOR) + +/* Getters and setters for group version (for source compat only) */ +#define GROUP_API_VERSION_GET_MAJOR(v) SUDO_API_VERSION_GET_MAJOR(v) +#define GROUP_API_VERSION_GET_MINOR(v) SUDO_API_VERSION_GET_MINOR(v) +#define GROUP_API_VERSION_SET_MAJOR(vp, n) SUDO_API_VERSION_SET_MAJOR(vp, n) +#define GROUP_API_VERSION_SET_MINOR(vp, n) SUDO_API_VERSION_SET_MINOR(vp, n) + +/* + * version: for compatibility checking + * group_init: return 1 on success, 0 if unconfigured, -1 on error. + * group_cleanup: called to clean up resources used by provider + * user_in_group: returns 1 if user is in group, 0 if not. + * note that pwd may be NULL if the user is not in passwd. + */ +struct sudoers_group_plugin { + unsigned int version; + int (*init)(int version, sudo_printf_t sudo_plugin_printf, + char *const argv[]); + void (*cleanup)(void); + int (*query)(const char *user, const char *group, const struct passwd *pwd); +}; + +#endif /* SUDO_PLUGIN_H */ diff --git a/include/sudo_queue.h b/include/sudo_queue.h new file mode 100644 index 0000000..f055957 --- /dev/null +++ b/include/sudo_queue.h @@ -0,0 +1,823 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: head/sys/sys/queue.h 251887 2013-06-18 02:57:56Z lstewart $ + */ + +#ifndef SUDO_QUEUE_H +#define SUDO_QUEUE_H + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may be traversed in either direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A headless tail queue lacks a head structure, The first element acts + * as a de facto list head. It uses the same entry struct as a regular + * tail queue for easy conversion from headless to headful. + * It is capable of concatenating queues as well as individual elements. + * Traversing in reverse is more expensive due to lack of a list head. + * Note: elements must be initialized before use. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - + - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_FROM + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_FROM_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_FROM - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _FOREACH_REVERSE_FROM_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * _SWAP + + + + + * + */ +#ifdef QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + unsigned long lastline; + unsigned long prevline; + const char *lastfile; + const char *prevfile; +}; + +#undef TRACEBUF +#define TRACEBUF struct qm_trace trace; +#undef TRACEBUF_INITIALIZER +#define TRACEBUF_INITIALIZER { __FILE__, __LINE__, NULL, 0 } , +#undef TRASHIT +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#undef QMD_SAVELINK +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) + +#undef QMD_TRACE_HEAD +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#undef QMD_TRACE_ELEM +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#undef QMD_TRACE_ELEM +#define QMD_TRACE_ELEM(elem) +#undef QMD_TRACE_HEAD +#define QMD_TRACE_HEAD(head) +#undef QMD_SAVELINK +#define QMD_SAVELINK(name, link) +#undef TRACEBUF +#define TRACEBUF +#undef TRACEBUF_INITIALIZER +#define TRACEBUF_INITIALIZER +#undef TRASHIT +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * XXX - Work around a bug in the llvm static analyzer. + * https://bugs.llvm.org//show_bug.cgi?id=18222 + */ +#ifdef __clang_analyzer__ +# define ANALYZER_ASSERT(x) do { \ + if (!__builtin_expect(!(x), 0)) \ + __builtin_trap(); \ +} while (0) +#else +# define ANALYZER_ASSERT(x) do {} while (0) +#endif /* __clang_analyzer__ */ + + /* + * Singly-linked List declarations. + */ +#undef SLIST_HEAD +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#undef SLIST_HEAD_INITIALIZER +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#undef SLIST_ENTRY +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#undef SLIST_EMPTY +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#undef SLIST_FIRST +#define SLIST_FIRST(head) ((head)->slh_first) + +#undef SLIST_FOREACH +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#undef SLIST_FOREACH_FROM +#define SLIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#undef SLIST_FOREACH_SAFE +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#undef SLIST_FOREACH_FROM_SAFE +#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#undef SLIST_FOREACH_PREVPTR +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#undef SLIST_INIT +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#undef SLIST_INSERT_AFTER +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#undef SLIST_INSERT_HEAD +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#undef SLIST_NEXT +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#undef SLIST_REMOVE +#define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#undef SLIST_REMOVE_AFTER +#define SLIST_REMOVE_AFTER(elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#undef SLIST_REMOVE_HEAD +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +#undef SLIST_SWAP +#define SLIST_SWAP(head1, head2, type) do { \ + struct type *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#undef STAILQ_HEAD +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#undef STAILQ_HEAD_INITIALIZER +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#undef STAILQ_ENTRY +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#undef STAILQ_CONCAT +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#undef STAILQ_EMPTY +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#undef STAILQ_FIRST +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#undef STAILQ_FOREACH +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#undef STAILQ_FOREACH_FROM +#define STAILQ_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#undef STAILQ_FOREACH_SAFE +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#undef STAILQ_FOREACH_FROM_SAFE +#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#undef STAILQ_INIT +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#undef STAILQ_INSERT_AFTER +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#undef STAILQ_INSERT_HEAD +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#undef STAILQ_INSERT_TAIL +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#undef STAILQ_LAST +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? NULL : \ + __containerof((head)->stqh_last, struct type, field.stqe_next)) + +#undef STAILQ_NEXT +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#undef STAILQ_REMOVE +#define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#undef STAILQ_REMOVE_AFTER +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#undef STAILQ_REMOVE_HEAD +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#undef STAILQ_SWAP +#define STAILQ_SWAP(head1, head2, type) do { \ + struct type *swap_first = STAILQ_FIRST(head1); \ + struct type **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ +} while (0) + + +/* + * List declarations. + */ +#undef LIST_HEAD +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#undef LIST_HEAD_INITIALIZER +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#undef LIST_ENTRY +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#undef LIST_EMPTY +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#undef LIST_FIRST +#define LIST_FIRST(head) ((head)->lh_first) + +#undef LIST_FOREACH +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#undef LIST_FOREACH_FROM +#define LIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#undef LIST_FOREACH_SAFE +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#undef LIST_FOREACH_FROM_SAFE +#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#undef LIST_INIT +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#undef LIST_INSERT_AFTER +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#undef LIST_INSERT_BEFORE +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#undef LIST_INSERT_HEAD +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#undef LIST_NEXT +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#undef LIST_PREV +#define LIST_PREV(elm, head, type, field) \ + ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ + __containerof((elm)->field.le_prev, struct type, field.le_next)) + +#undef LIST_REMOVE +#define LIST_REMOVE(elm, field) do { \ + ANALYZER_ASSERT(elm != NULL); \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ +} while (0) + +#undef LIST_SWAP +#define LIST_SWAP(head1, head2, type, field) do { \ + struct type *swap_tmp = LIST_FIRST((head1)); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ +} while (0) + +/* + * Tail queue declarations. + */ +#undef TAILQ_HEAD +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#undef TAILQ_HEAD_INITIALIZER +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER } + +#undef TAILQ_ENTRY +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#undef TAILQ_CONCAT +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#undef TAILQ_EMPTY +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#undef TAILQ_FIRST +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#undef TAILQ_FOREACH +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#undef TAILQ_FOREACH_FROM +#define TAILQ_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#undef TAILQ_FOREACH_SAFE +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#undef TAILQ_FOREACH_FROM_SAFE +#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#undef TAILQ_FOREACH_REVERSE +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#undef TAILQ_FOREACH_REVERSE_FROM +#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ + for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#undef TAILQ_FOREACH_REVERSE_SAFE +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#undef TAILQ_FOREACH_REVERSE_FROM_SAFE +#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \ + for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#undef TAILQ_INIT +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#undef TAILQ_INSERT_AFTER +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#undef TAILQ_INSERT_BEFORE +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#undef TAILQ_INSERT_HEAD +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#undef TAILQ_INSERT_TAIL +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#undef TAILQ_LAST +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#undef TAILQ_NEXT +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#undef TAILQ_PREV +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#undef TAILQ_REMOVE +#define TAILQ_REMOVE(head, elm, field) do { \ + ANALYZER_ASSERT(elm != NULL); \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#undef TAILQ_SWAP +#define TAILQ_SWAP(head1, head2, type, field) do { \ + struct type *swap_first = (head1)->tqh_first; \ + struct type **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ + else \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ + else \ + (head2)->tqh_last = &(head2)->tqh_first; \ +} while (0) + +/* + * Headless Tail queue definitions. + */ +#undef HLTQ_ENTRY +#define HLTQ_ENTRY(type) TAILQ_ENTRY(type) + +#undef HLTQ_INIT +#define HLTQ_INIT(entry, field) do { \ + (entry)->field.tqe_next = NULL; \ + (entry)->field.tqe_prev = &(entry)->field.tqe_next; \ +} while (0) + +#undef HLTQ_INITIALIZER +#define HLTQ_INITIALIZER(entry, field) \ + { NULL, &(entry)->field.tqe_next } + +#undef HLTQ_FIRST +#define HLTQ_FIRST(elm) (elm) + +#undef HLTQ_END +#define HLTQ_END(elm) NULL + +#undef HLTQ_NEXT +#define HLTQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#undef HLTQ_LAST +#define HLTQ_LAST(elm, type, field) \ + ((elm)->field.tqe_next == NULL ? (elm) : \ + __containerof((elm)->field.tqe_prev, struct type, field.tqe_next)) + +#undef HLTQ_PREV +#define HLTQ_PREV(elm, type, field) \ + (*(elm)->field.tqe_prev == NULL ? NULL : \ + __containerof((elm)->field.tqe_prev, struct type, field.tqe_next)) + +#undef HLTQ_FOREACH +#define HLTQ_FOREACH(var, head, field) \ + for ((var) = HLTQ_FIRST(head); \ + (var) != HLTQ_END(head); \ + (var) = HLTQ_NEXT(var, field)) + +#undef HLTQ_FOREACH_SAFE +#define HLTQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = HLTQ_FIRST(head); \ + (var) != HLTQ_END(head) && \ + ((tvar) = HLTQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +#undef HLTQ_FOREACH_REVERSE +#define HLTQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = HLTQ_LAST(head, headname); \ + (var) != HLTQ_END(head); \ + (var) = HLTQ_PREV(var, headname, field)) + +#undef HLTQ_FOREACH_REVERSE_SAFE +#define HLTQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = HLTQ_LAST(head, headname); \ + (var) != HLTQ_END(head) && \ + ((tvar) = HLTQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* Concatenate queue2 to the end of queue1. */ +#undef HLTQ_CONCAT +#define HLTQ_CONCAT(queue1, queue2, field) do { \ + (queue2)->field.tqe_prev = (queue1)->field.tqe_prev; \ + *(queue1)->field.tqe_prev = (queue2); \ + (queue1)->field.tqe_prev = &(queue2)->field.tqe_next; \ +} while (0) + +/* Convert a headless tailq to a headful one. */ +#define HLTQ_TO_TAILQ(head, hl, field) do { \ + (head)->tqh_first = (hl); \ + (head)->tqh_last = (hl)->field.tqe_prev; \ + (hl)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +/* Concatenate a headless tail queue to the end of a regular tail queue. */ +#define TAILQ_CONCAT_HLTQ(head, hl, field) do { \ + void *last = (hl)->field.tqe_prev; \ + (hl)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (hl); \ + (head)->tqh_last = last; \ +} while (0) + +#endif /* !SUDO_QUEUE_H */ diff --git a/include/sudo_rand.h b/include/sudo_rand.h new file mode 100644 index 0000000..d030ed0 --- /dev/null +++ b/include/sudo_rand.h @@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 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. + */ + +#ifndef SUDO_RAND_H +#define SUDO_RAND_H + +#include <stdlib.h> /* For arc4random() on systems that have it */ + +/* + * All libc replacements are prefixed with "sudo_" to avoid namespace issues. + */ + +#ifndef HAVE_ARC4RANDOM +sudo_dso_public uint32_t sudo_arc4random(void); +# undef arc4random +# define arc4random() sudo_arc4random() +#endif /* ARC4RANDOM */ + +#ifndef HAVE_ARC4RANDOM_BUF +sudo_dso_public void sudo_arc4random_buf(void *buf, size_t n); +# undef arc4random_buf +# define arc4random_buf(a, b) sudo_arc4random_buf((a), (b)) +#endif /* ARC4RANDOM_BUF */ + +#ifndef HAVE_ARC4RANDOM_UNIFORM +sudo_dso_public uint32_t sudo_arc4random_uniform(uint32_t upper_bound); +# undef arc4random_uniform +# define arc4random_uniform(_a) sudo_arc4random_uniform((_a)) +#endif /* ARC4RANDOM_UNIFORM */ + +#ifndef HAVE_GETENTROPY +/* Note: not exported by libutil. */ +int sudo_getentropy(void *buf, size_t buflen); +# undef getentropy +# define getentropy(_a, _b) sudo_getentropy((_a), (_b)) +#endif /* HAVE_GETENTROPY */ + +#endif /* SUDO_RAND_H */ diff --git a/include/sudo_util.h b/include/sudo_util.h new file mode 100644 index 0000000..100d5eb --- /dev/null +++ b/include/sudo_util.h @@ -0,0 +1,375 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2013-2022 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. + */ + +#ifndef SUDO_UTIL_H +#define SUDO_UTIL_H + +#include <sys/types.h> /* for dev_t, mode_t, gid_t, size_t, ssize_t, uid_t */ +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ + +#ifdef __TANDEM +# define ROOT_UID 65535 +#else +# define ROOT_UID 0 +#endif +#define ROOT_GID 0 + +#ifndef TIME_T_MIN +# if SIZEOF_TIME_T == 8 +# define TIME_T_MIN LLONG_MIN +# else +# define TIME_T_MIN INT_MIN +# endif +#endif +#ifndef TIME_T_MAX +# if SIZEOF_TIME_T == 8 +# define TIME_T_MAX LLONG_MAX +# else +# define TIME_T_MAX INT_MAX +# endif +#endif + +/* + * Macros for operating on struct timeval. + */ +#define sudo_timevalclear(tv) ((tv)->tv_sec = (tv)->tv_usec = 0) + +#define sudo_timevalisset(tv) ((tv)->tv_sec || (tv)->tv_usec) + +#define sudo_timevalcmp(tv1, tv2, op) \ + (((tv1)->tv_sec == (tv2)->tv_sec) ? \ + ((tv1)->tv_usec op (tv2)->tv_usec) : \ + ((tv1)->tv_sec op (tv2)->tv_sec)) + +#define sudo_timevaladd(tv1, tv2, tv3) \ + do { \ + (tv3)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ + (tv3)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \ + if ((tv3)->tv_usec >= 1000000) { \ + (tv3)->tv_sec++; \ + (tv3)->tv_usec -= 1000000; \ + } \ + } while (0) + +#define sudo_timevalsub(tv1, tv2, tv3) \ + do { \ + (tv3)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \ + (tv3)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec; \ + if ((tv3)->tv_usec < 0) { \ + (tv3)->tv_sec--; \ + (tv3)->tv_usec += 1000000; \ + } \ + } while (0) + +#ifndef TIMEVAL_TO_TIMESPEC +# define TIMEVAL_TO_TIMESPEC(tv, ts) \ + do { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ + } while (0) +#endif + +/* + * Macros for operating on struct timespec. + */ +#define sudo_timespecclear(ts) ((ts)->tv_sec = (ts)->tv_nsec = 0) + +#define sudo_timespecisset(ts) ((ts)->tv_sec || (ts)->tv_nsec) + +#define sudo_timespeccmp(ts1, ts2, op) \ + (((ts1)->tv_sec == (ts2)->tv_sec) ? \ + ((ts1)->tv_nsec op (ts2)->tv_nsec) : \ + ((ts1)->tv_sec op (ts2)->tv_sec)) + +#define sudo_timespecadd(ts1, ts2, ts3) \ + do { \ + (ts3)->tv_sec = (ts1)->tv_sec + (ts2)->tv_sec; \ + (ts3)->tv_nsec = (ts1)->tv_nsec + (ts2)->tv_nsec; \ + while ((ts3)->tv_nsec >= 1000000000) { \ + (ts3)->tv_sec++; \ + (ts3)->tv_nsec -= 1000000000; \ + } \ + } while (0) + +#define sudo_timespecsub(ts1, ts2, ts3) \ + do { \ + (ts3)->tv_sec = (ts1)->tv_sec - (ts2)->tv_sec; \ + (ts3)->tv_nsec = (ts1)->tv_nsec - (ts2)->tv_nsec; \ + while ((ts3)->tv_nsec < 0) { \ + (ts3)->tv_sec--; \ + (ts3)->tv_nsec += 1000000000; \ + } \ + } while (0) + +#ifndef TIMESPEC_TO_TIMEVAL +# define TIMESPEC_TO_TIMEVAL(tv, ts) \ + do { \ + (tv)->tv_sec = (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ + } while (0) +#endif + +/* + * The timespec version of st_mtime may vary on different platforms. + */ +#if defined(HAVE_ST_MTIM) +# if defined(HAVE_ST__TIM) +# define SUDO_ST_MTIM st_mtim.st__tim +# else +# define SUDO_ST_MTIM st_mtim +# endif +#elif defined(HAVE_ST_MTIMESPEC) +# define SUDO_ST_MTIM st_mtimespec +#endif + +/* + * Macro to extract mtime as timespec. + * If there is no way to set the timestamp using nanosecond precision, + * we only fetch microsecond precision. Otherwise there is a mismatch + * between the timestamp we read and the one we wrote. + */ +#if defined(SUDO_ST_MTIM) +# if defined(HAVE_FUTIMENS) && defined(HAVE_UTIMENSAT) +# define mtim_get(_x, _y) do { (_y).tv_sec = (_x)->SUDO_ST_MTIM.tv_sec; (_y).tv_nsec = (_x)->SUDO_ST_MTIM.tv_nsec; } while (0) +# else +# define mtim_get(_x, _y) do { (_y).tv_sec = (_x)->SUDO_ST_MTIM.tv_sec; (_y).tv_nsec = ((_x)->SUDO_ST_MTIM.tv_nsec / 1000) * 1000; } while (0) +# endif +#elif defined(HAVE_ST_NMTIME) +# define mtim_get(_x, _y) do { (_y).tv_sec = (_x)->st_mtime; (_y).tv_nsec = (_x)->st_nmtime; } while (0) +#else +# define mtim_get(_x, _y) do { (_y).tv_sec = (_x)->st_mtime; (_y).tv_nsec = 0; } while (0) +#endif /* HAVE_ST_MTIM */ + +/* sizeof() that returns a signed value */ +#define ssizeof(_x) ((ssize_t)sizeof(_x)) + +/* Bit map macros. */ +#define sudo_setbit(_a, _i) ((_a)[(_i) / NBBY] |= 1 << ((_i) % NBBY)) +#define sudo_clrbit(_a, _i) ((_a)[(_i) / NBBY] &= ~(1<<((_i) % NBBY))) +#define sudo_isset(_a, _i) ((_a)[(_i) / NBBY] & (1<<((_i) % NBBY))) +#define sudo_isclr(_a, _i) (((_a)[(_i) / NBBY] & (1<<((_i) % NBBY))) == 0) + +/* sudo_parseln() flags */ +#define PARSELN_COMM_BOL 0x01 /* comments only at beginning of line */ +#define PARSELN_CONT_IGN 0x02 /* ignore line continuation char */ + +/* + * Macros to quiet gcc's warn_unused_result attribute. + */ +#ifdef __GNUC__ +# define ignore_result(x) do { \ + __typeof__(x) y = (x); \ + (void)y; \ +} while(0) +#else +# define ignore_result(x) (void)(x) +#endif + +/* Forward struct declarations. */ +struct stat; + +/* aix.c */ +sudo_dso_public int aix_getauthregistry_v1(char *user, char *saved_registry); +#define aix_getauthregistry(_a, _b) aix_getauthregistry_v1((_a), (_b)) +sudo_dso_public int aix_prep_user_v1(char *user, const char *tty); +#define aix_prep_user(_a, _b) aix_prep_user_v1((_a), (_b)) +sudo_dso_public int aix_restoreauthdb_v1(void); +#define aix_restoreauthdb() aix_restoreauthdb_v1() +sudo_dso_public int aix_setauthdb_v1(char *user); +sudo_dso_public int aix_setauthdb_v2(char *user, char *registry); +#define aix_setauthdb(_a, _b) aix_setauthdb_v2((_a), (_b)) + +/* basename.c */ +sudo_dso_public char *sudo_basename_v1(const char *filename); +#define sudo_basename(_a) sudo_basename_v1(_a) + +/* gethostname.c */ +sudo_dso_public char *sudo_gethostname_v1(void); +#define sudo_gethostname() sudo_gethostname_v1() + +/* gettime.c */ +sudo_dso_public int sudo_gettime_awake_v1(struct timespec *ts); +#define sudo_gettime_awake(_a) sudo_gettime_awake_v1((_a)) +sudo_dso_public int sudo_gettime_mono_v1(struct timespec *ts); +#define sudo_gettime_mono(_a) sudo_gettime_mono_v1((_a)) +sudo_dso_public int sudo_gettime_real_v1(struct timespec *ts); +#define sudo_gettime_real(_a) sudo_gettime_real_v1((_a)) + +/* gidlist.c */ +sudo_dso_public int sudo_parse_gids_v1(const char *gidstr, const gid_t *basegid, GETGROUPS_T **gidsp); +#define sudo_parse_gids(_a, _b, _c) sudo_parse_gids_v1((_a), (_b), (_c)) + +/* getgrouplist.c */ +sudo_dso_public int sudo_getgrouplist2_v1(const char *name, gid_t basegid, GETGROUPS_T **groupsp, int *ngroupsp); +#define sudo_getgrouplist2(_a, _b, _c, _d) sudo_getgrouplist2_v1((_a), (_b), (_c), (_d)) + +/* hexchar.c */ +sudo_dso_public int sudo_hexchar_v1(const char *s); +#define sudo_hexchar(_a) sudo_hexchar_v1(_a) + +/* key_val.c */ +sudo_dso_public char *sudo_new_key_val_v1(const char *key, const char *value); +#define sudo_new_key_val(_a, _b) sudo_new_key_val_v1((_a), (_b)) + +/* locking.c */ +#define SUDO_LOCK 1 /* lock a file */ +#define SUDO_TLOCK 2 /* test & lock a file (non-blocking) */ +#define SUDO_UNLOCK 4 /* unlock a file */ +sudo_dso_public bool sudo_lock_file_v1(int fd, int action); +#define sudo_lock_file(_a, _b) sudo_lock_file_v1((_a), (_b)) +sudo_dso_public bool sudo_lock_region_v1(int fd, int action, off_t len); +#define sudo_lock_region(_a, _b, _c) sudo_lock_region_v1((_a), (_b), (_c)) + +/* logfac.c */ +sudo_dso_public bool sudo_str2logfac_v1(const char *str, int *logfac); +#define sudo_str2logfac(_a, _b) sudo_str2logfac_v1((_a), (_b)) +sudo_dso_public const char *sudo_logfac2str_v1(int num); +#define sudo_logfac2str(_a) sudo_logfac2str_v1((_a)) + +/* logpri.c */ +sudo_dso_public bool sudo_str2logpri_v1(const char *str, int *logpri); +#define sudo_str2logpri(_a, _b) sudo_str2logpri_v1((_a), (_b)) +sudo_dso_public const char *sudo_logpri2str_v1(int num); +#define sudo_logpri2str(_a) sudo_logpri2str_v1((_a)) + +/* mkdir_parents.c */ +sudo_dso_public bool sudo_mkdir_parents_v1(const char *path, uid_t uid, gid_t gid, mode_t mode, bool quiet); +#define sudo_mkdir_parents(_a, _b, _c, _d, _e) sudo_mkdir_parents_v1((_a), (_b), (_c), (_d), (_e)) +sudo_dso_public int sudo_open_parent_dir_v1(const char *path, uid_t uid, gid_t gid, mode_t mode, bool quiet); +#define sudo_open_parent_dir(_a, _b, _c, _d, _e) sudo_open_parent_dir_v1((_a), (_b), (_c), (_d), (_e)) + +/* mmap_alloc.c */ +sudo_dso_public void *sudo_mmap_alloc_v1(size_t size) sudo_malloclike; +#define sudo_mmap_alloc(_a) sudo_mmap_alloc_v1(_a) +sudo_dso_public void *sudo_mmap_allocarray_v1(size_t count, size_t size) sudo_malloclike; +#define sudo_mmap_allocarray(_a, _b) sudo_mmap_allocarray_v1((_a), (_b)) +sudo_dso_public char *sudo_mmap_strdup_v1(const char *str); +#define sudo_mmap_strdup(_a) sudo_mmap_strdup_v1(_a) +sudo_dso_public void sudo_mmap_free_v1(void *ptr); +#define sudo_mmap_free(_a) sudo_mmap_free_v1(_a) +sudo_dso_public int sudo_mmap_protect_v1(void *ptr); +#define sudo_mmap_protect(_a) sudo_mmap_protect_v1(_a) + +/* multiarch.c */ +sudo_dso_public char *sudo_stat_multiarch_v1(const char *path, struct stat *sb); +#define sudo_stat_multiarch(_a, _b) sudo_stat_multiarch_v1((_a), (_b)) + +/* parseln.c */ +sudo_dso_public ssize_t sudo_parseln_v1(char **buf, size_t *bufsize, unsigned int *lineno, FILE *fp); +sudo_dso_public ssize_t sudo_parseln_v2(char **buf, size_t *bufsize, unsigned int *lineno, FILE *fp, int flags); +#define sudo_parseln(_a, _b, _c, _d, _e) sudo_parseln_v2((_a), (_b), (_c), (_d), (_e)) + +/* progname.c */ +sudo_dso_public void initprogname(const char *); +sudo_dso_public void initprogname2(const char *, const char * const *); + +/* rcstr.c */ +sudo_dso_public char *sudo_rcstr_dup(const char *src); +sudo_dso_public char *sudo_rcstr_alloc(size_t len) sudo_malloclike; +sudo_dso_public char *sudo_rcstr_addref(const char *s); +sudo_dso_public void sudo_rcstr_delref(const char *s); + +/* regex.c */ +sudo_dso_public bool sudo_regex_compile_v1(void *v, const char *pattern, const char **errstr); +#define sudo_regex_compile(_a, _b, _c) sudo_regex_compile_v1((_a), (_b), (_c)) + +/* roundup.c */ +sudo_dso_public unsigned int sudo_pow2_roundup_v1(unsigned int len); +#define sudo_pow2_roundup(_a) sudo_pow2_roundup_v1((_a)) + +/* secure_path.c */ +#define SUDO_PATH_SECURE 0 +#define SUDO_PATH_MISSING -1 +#define SUDO_PATH_BAD_TYPE -2 +#define SUDO_PATH_WRONG_OWNER -3 +#define SUDO_PATH_WORLD_WRITABLE -4 +#define SUDO_PATH_GROUP_WRITABLE -5 +sudo_dso_public int sudo_secure_dir_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb); +#define sudo_secure_dir(_a, _b, _c, _d) sudo_secure_dir_v1((_a), (_b), (_c), (_d)) +sudo_dso_public int sudo_secure_file_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb); +#define sudo_secure_file(_a, _b, _c, _d) sudo_secure_file_v1((_a), (_b), (_c), (_d)) +sudo_dso_public int sudo_secure_open_file_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb, int *error); +#define sudo_secure_open_file(_a, _b, _c, _d, _e) sudo_secure_open_file_v1((_a), (_b), (_c), (_d), (_e)) +sudo_dso_public int sudo_secure_open_dir_v1(const char *path, uid_t uid, gid_t gid, struct stat *sb, int *error); +#define sudo_secure_open_dir(_a, _b, _c, _d, _e) sudo_secure_open_dir_v1((_a), (_b), (_c), (_d), (_e)) + +/* setgroups.c */ +sudo_dso_public int sudo_setgroups_v1(int ngids, const GETGROUPS_T *gids); +#define sudo_setgroups(_a, _b) sudo_setgroups_v1((_a), (_b)) + +/* strsplit.c */ +sudo_dso_public const char *sudo_strsplit_v1(const char *str, const char *endstr, const char *sep, const char **last); +#define sudo_strsplit(_a, _b, _c, _d) sudo_strsplit_v1(_a, _b, _c, _d) + +/* strtobool.c */ +sudo_dso_public int sudo_strtobool_v1(const char *str); +#define sudo_strtobool(_a) sudo_strtobool_v1((_a)) + +/* strtonum.c */ +/* Not versioned for historical reasons. */ +sudo_dso_public long long sudo_strtonum(const char *, long long, long long, const char **); +/* Not currently exported. */ +long long sudo_strtonumx(const char *str, long long minval, long long maxval, char **endp, const char **errstrp); + +/* strtoid.c */ +sudo_dso_public id_t sudo_strtoid_v1(const char *str, const char *sep, char **endp, const char **errstr); +sudo_dso_public id_t sudo_strtoid_v2(const char *str, const char **errstr); +#define sudo_strtoid(_a, _b) sudo_strtoid_v2((_a), (_b)) +sudo_dso_public id_t sudo_strtoidx_v1(const char *str, const char *sep, char **endp, const char **errstr); +#define sudo_strtoidx(_a, _b, _c, _d) sudo_strtoidx_v1((_a), (_b), (_c), (_d)) + +/* strtomode.c */ +sudo_dso_public int sudo_strtomode_v1(const char *cp, const char **errstr); +#define sudo_strtomode(_a, _b) sudo_strtomode_v1((_a), (_b)) + +/* sudo_printf.c */ +extern int (*sudo_printf)(int msg_type, const char *fmt, ...); + +/* term.c */ +sudo_dso_public bool sudo_term_cbreak_v1(int fd); +#define sudo_term_cbreak(_a) sudo_term_cbreak_v1((_a)) +sudo_dso_public bool sudo_term_copy_v1(int src, int dst); +#define sudo_term_copy(_a, _b) sudo_term_copy_v1((_a), (_b)) +sudo_dso_public bool sudo_term_noecho_v1(int fd); +#define sudo_term_noecho(_a) sudo_term_noecho_v1((_a)) +sudo_dso_public bool sudo_term_raw_v1(int fd, int isig); +#define sudo_term_raw(_a, _b) sudo_term_raw_v1((_a), (_b)) +sudo_dso_public bool sudo_term_restore_v1(int fd, bool flush); +#define sudo_term_restore(_a, _b) sudo_term_restore_v1((_a), (_b)) +sudo_dso_public bool sudo_term_is_raw_v1(int fd); +#define sudo_term_is_raw(_a) sudo_term_is_raw_v1((_a)) + +/* ttyname_dev.c */ +sudo_dso_public char *sudo_ttyname_dev_v1(dev_t tdev, char *name, size_t namelen); +#define sudo_ttyname_dev(_a, _b, _c) sudo_ttyname_dev_v1((_a), (_b), (_c)) + +/* ttysize.c */ +sudo_dso_public void sudo_get_ttysize_v1(int *rowp, int *colp); +#define sudo_get_ttysize(_a, _b) sudo_get_ttysize_v1((_a), (_b)) + +/* uuid.c */ +sudo_dso_public void sudo_uuid_create_v1(unsigned char uuid_out[16]); +#define sudo_uuid_create(_a) sudo_uuid_create_v1((_a)) +sudo_dso_public char *sudo_uuid_to_string_v1(unsigned char uuid[16], char *dst, size_t dstsiz); +#define sudo_uuid_to_string(_a, _b, _c) sudo_uuid_to_string_v1((_a), (_b), (_c)) + +#endif /* SUDO_UTIL_H */ |