diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 02:23:56 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 02:23:56 +0000 |
commit | 9620f76a210d9d8c1aaff25e99d6dc513f87e6e9 (patch) | |
tree | ceecc90fb95780872c35da764c5163f38e4727c4 /include | |
parent | Initial commit. (diff) | |
download | sudo-9620f76a210d9d8c1aaff25e99d6dc513f87e6e9.tar.xz sudo-9620f76a210d9d8c1aaff25e99d6dc513f87e6e9.zip |
Adding upstream version 1.8.27.upstream/1.8.27upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | include/Makefile.in | 96 | ||||
-rw-r--r-- | include/compat/charclass.h | 39 | ||||
-rw-r--r-- | include/compat/endian.h | 72 | ||||
-rw-r--r-- | include/compat/fnmatch.h | 32 | ||||
-rw-r--r-- | include/compat/getaddrinfo.h | 83 | ||||
-rw-r--r-- | include/compat/getopt.h | 81 | ||||
-rw-r--r-- | include/compat/glob.h | 76 | ||||
-rw-r--r-- | include/compat/nss_dbdefs.h | 106 | ||||
-rw-r--r-- | include/compat/sha2.h | 98 | ||||
-rw-r--r-- | include/compat/stdbool.h | 44 | ||||
-rw-r--r-- | include/sudo_compat.h | 531 | ||||
-rw-r--r-- | include/sudo_conf.h | 85 | ||||
-rw-r--r-- | include/sudo_debug.h | 297 | ||||
-rw-r--r-- | include/sudo_digest.h | 44 | ||||
-rw-r--r-- | include/sudo_dso.h | 55 | ||||
-rw-r--r-- | include/sudo_event.h | 193 | ||||
-rw-r--r-- | include/sudo_fatal.h | 205 | ||||
-rw-r--r-- | include/sudo_gettext.h | 75 | ||||
-rw-r--r-- | include/sudo_lbuf.h | 53 | ||||
-rw-r--r-- | include/sudo_plugin.h | 201 | ||||
-rw-r--r-- | include/sudo_queue.h | 821 | ||||
-rw-r--r-- | include/sudo_rand.h | 50 | ||||
-rw-r--r-- | include/sudo_util.h | 275 |
23 files changed, 3612 insertions, 0 deletions
diff --git a/include/Makefile.in b/include/Makefile.in new file mode 100644 index 0000000..cb39b36 --- /dev/null +++ b/include/Makefile.in @@ -0,0 +1,96 @@ +# +# 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@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +includedir = @includedir@ +cross_compiling = @CROSS_COMPILING@ + +# Our install program supports extra flags... +INSTALL = $(SHELL) $(top_srcdir)/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: + +Makefile: $(srcdir)/Makefile.in + cd $(top_builddir) && ./config.status --file include/Makefile + +.SUFFIXES: .h + +pre-install: + +install: install-includes + +install-dirs: + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(includedir) + +install-binaries: + +install-doc: + +install-includes: install-dirs + $(INSTALL) $(INSTALL_OWNER) -m 0644 $(srcdir)/sudo_plugin.h $(DESTDIR)$(includedir) + +install-plugin: + +uninstall: + -rm -f $(DESTDIR)$(includedir)/sudo_plugin.h + +splint: + +cppcheck: + +pvs-log-files: + +pvs-studio: + +check: + +clean: + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile + +clobber: distclean + +realclean: distclean + +cleandir: distclean diff --git a/include/compat/charclass.h b/include/compat/charclass.h new file mode 100644 index 0000000..645e884 --- /dev/null +++ b/include/compat/charclass.h @@ -0,0 +1,39 @@ +/* + * 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..279549c --- /dev/null +++ b/include/compat/endian.h @@ -0,0 +1,72 @@ +/* + * 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_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) +# 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(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..fb81e38 --- /dev/null +++ b/include/compat/fnmatch.h @@ -0,0 +1,32 @@ +/* + * 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 */ + +__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..6f2f203 --- /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 native getaddrinfo implemenation 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. */ +__dso_public int sudo_getaddrinfo(const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res); +__dso_public void sudo_freeaddrinfo(struct addrinfo *ai); +__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..8f49518 --- /dev/null +++ b/include/compat/getopt.h @@ -0,0 +1,81 @@ +/* $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 $ */ + +/*- + * 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; +}; + +__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)) + +__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 +__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..40f5d39 --- /dev/null +++ b/include/compat/glob.h @@ -0,0 +1,76 @@ +/* + * 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 { + int gl_pathc; /* Count of total paths so far. */ + int gl_matchc; /* Count of paths matching pattern. */ + int 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. */ + +__dso_public int sudo_glob(const char *, int, int (*)(const char *, int), glob_t *); +__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..bc3f9b9 --- /dev/null +++ b/include/compat/nss_dbdefs.h @@ -0,0 +1,106 @@ +/* + * 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_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 *, int, void *, char *, int); + nss_status_t (*process_cstr)(const char *, int, struct nss_groupsbymem *); + int numgids; +}; + +typedef struct { + void *result; /* group struct to fill in. */ + char *buffer; /* string buffer for above */ + size_t buflen; /* string buffer size */ +} nss_XbyY_buf_t; + +typedef struct { + void *state; /* really struct nss_db_state * */ +#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, void *); +extern nss_XbyY_buf_t *_nss_XbyY_buf_alloc(int, int); +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..3638423 --- /dev/null +++ b/include/compat/sha2.h @@ -0,0 +1,98 @@ +/* + * 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; + +__dso_public void sudo_SHA224Init(SHA2_CTX *ctx); +__dso_public void sudo_SHA224Pad(SHA2_CTX *ctx); +__dso_public void sudo_SHA224Transform(uint32_t state[8], const uint8_t buffer[SHA224_BLOCK_LENGTH]); +__dso_public void sudo_SHA224Update(SHA2_CTX *ctx, const uint8_t *data, size_t len); +__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 + +__dso_public void sudo_SHA256Init(SHA2_CTX *ctx); +__dso_public void sudo_SHA256Pad(SHA2_CTX *ctx); +__dso_public void sudo_SHA256Transform(uint32_t state[8], const uint8_t buffer[SHA256_BLOCK_LENGTH]); +__dso_public void sudo_SHA256Update(SHA2_CTX *ctx, const uint8_t *data, size_t len); +__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 + +__dso_public void sudo_SHA384Init(SHA2_CTX *ctx); +__dso_public void sudo_SHA384Pad(SHA2_CTX *ctx); +__dso_public void sudo_SHA384Transform(uint64_t state[8], const uint8_t buffer[SHA384_BLOCK_LENGTH]); +__dso_public void sudo_SHA384Update(SHA2_CTX *ctx, const uint8_t *data, size_t len); +__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 + +__dso_public void sudo_SHA512Init(SHA2_CTX *ctx); +__dso_public void sudo_SHA512Pad(SHA2_CTX *ctx); +__dso_public void sudo_SHA512Transform(uint64_t state[8], const uint8_t buffer[SHA512_BLOCK_LENGTH]); +__dso_public void sudo_SHA512Update(SHA2_CTX *ctx, const uint8_t *data, size_t len); +__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/sudo_compat.h b/include/sudo_compat.h new file mode 100644 index 0000000..5c32840 --- /dev/null +++ b/include/sudo_compat.h @@ -0,0 +1,531 @@ +/* + * Copyright (c) 1996, 1998-2005, 2008, 2009-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_COMPAT_H +#define SUDO_COMPAT_H + +#include <stdio.h> +#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_VASPRINTF) || \ + !defined(HAVE_VSYSLOG) || defined(PREFER_PORTABLE_SNPRINTF) +# include <stdarg.h> +#endif +#if !defined(HAVE_MEMSET_S) && !defined(rsize_t) +# include <stddef.h> /* for rsize_t */ +# ifdef HAVE_STRING_H +# include <string.h> /* for rsize_t on AIX */ +# endif /* HAVE_STRING_H */ +#endif /* HAVE_MEMSET_S && rsize_t */ + +/* + * Macros and functions that may be missing on some operating systems. + */ + +#ifndef __GNUC_PREREQ__ +# ifdef __GNUC__ +# define __GNUC_PREREQ__(ma, mi) \ + ((__GNUC__ > (ma)) || (__GNUC__ == (ma) && __GNUC_MINOR__ >= (mi))) +# else +# define __GNUC_PREREQ__(ma, mi) 0 +# endif +#endif + +/* Define away __attribute__ for non-gcc or old gcc */ +#if !defined(__attribute__) && !__GNUC_PREREQ__(2, 5) +# define __attribute__(x) +#endif + +/* For catching format string mismatches */ +#ifndef __printflike +# if __GNUC_PREREQ__(3, 3) +# define __printflike(f, v) __attribute__((__format__ (__printf__, f, v))) __attribute__((__nonnull__ (f))) +# elif __GNUC_PREREQ__(2, 7) +# define __printflike(f, v) __attribute__((__format__ (__printf__, f, v))) +# else +# define __printflike(f, v) +# endif +#endif +#ifndef __printf0like +# if __GNUC_PREREQ__(2, 7) +# define __printf0like(f, v) __attribute__((__format__ (__printf__, f, v))) +# else +# define __printf0like(f, v) +# endif +#endif +#ifndef __format_arg +# if __GNUC_PREREQ__(2, 7) +# define __format_arg(f) __attribute__((__format_arg__ (f))) +# else +# define __format_arg(f) +# endif +#endif + +/* + * 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 + +#ifndef __dso_public +# ifdef HAVE_DSO_VISIBILITY +# if defined(__GNUC__) +# define __dso_public __attribute__((__visibility__("default"))) +# define __dso_hidden __attribute__((__visibility__("hidden"))) +# elif defined(__SUNPRO_C) +# define __dso_public __global +# define __dso_hidden __hidden +# else +# define __dso_public __declspec(dllexport) +# define __dso_hidden +# endif +# else +# define __dso_public +# define __dso_hidden +# endif +#endif + +/* + * Pre-C99 compilers may lack a va_copy macro. + */ +#ifndef va_copy +# ifdef __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_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 + +/* + * POSIX versions for those without... + */ +#ifndef _S_IFMT +# define _S_IFMT S_IFMT +#endif /* _S_IFMT */ +#ifndef _S_IFREG +# define _S_IFREG S_IFREG +#endif /* _S_IFREG */ +#ifndef _S_IFDIR +# define _S_IFDIR S_IFDIR +#endif /* _S_IFDIR */ +#ifndef _S_IFLNK +# define _S_IFLNK S_IFLNK +#endif /* _S_IFLNK */ +#ifndef _S_IFIFO +# define _S_IFIFO S_IFIFO +#endif /* _S_IFIFO */ +#ifndef S_ISREG +# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +#endif /* S_ISREG */ +#ifndef S_ISDIR +# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) +#endif /* S_ISDIR */ +#ifndef S_ISLNK +# define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK) +#endif /* S_ISLNK */ +#ifndef S_ISFIFO +# define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO) +#endif /* S_ISLNK */ +#ifndef S_ISTXT +# define S_ISTXT 0001000 +#endif /* S_ISTXT */ + +/* + * ACCESSPERMS (00777) and ALLPERMS (07777) are handy BSDisms + */ +#ifndef ACCESSPERMS +# define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) +#endif /* ACCESSPERMS */ +#ifndef ALLPERMS +# define ALLPERMS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) +#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)) +# ifndef AT_FDCWD +# define AT_FDCWD -100 +# endif +#endif + +/* For pipe2() emulation. */ +#if !defined(HAVE_PIPE2) && defined(O_NONBLOCK) && !defined(O_CLOEXEC) +# define O_CLOEXEC 0x80000000 +#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 +__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(NSIG) +# if defined(_NSIG) +# define NSIG _NSIG +# elif defined(__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 that can't handle a 64-bit off_t + * on 32-bit machines. + */ +#if defined(__hpux) && !defined(__LP64__) +# ifdef HAVE_PREAD64 +# undef pread +# define pread(_a, _b, _c, _d) pread64((_a), (_b), (_c), (_d)) +# endif +# ifdef HAVE_PWRITE64 +# undef pwrite +# define pwrite(_a, _b, _c, _d) pwrite64((_a), (_b), (_c), (_d)) +# endif +#endif /* __hpux && !__LP64__ */ + +/* We wrap OpenBSD's strtonum() to get translatable error strings. */ +__dso_public long long sudo_strtonum(const char *, long long, long long, const char **); +#undef strtonum +#define strtonum(_a, _b, _c, _d) sudo_strtonum((_a), (_b), (_c), (_d)) + +/* + * Functions "missing" from libc. + * All libc replacements are prefixed with "sudo_" to avoid namespace issues. + */ + +struct passwd; +struct timespec; + +#ifndef HAVE_CLOSEFROM +__dso_public void sudo_closefrom(int); +# undef closefrom +# define closefrom(_a) sudo_closefrom((_a)) +#endif /* HAVE_CLOSEFROM */ +#ifdef PREFER_PORTABLE_GETCWD +__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 +__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 */ +#ifndef HAVE_GETLINE +__dso_public ssize_t sudo_getline(char **bufp, size_t *bufsizep, FILE *fp); +# undef getline +# define getline(_a, _b, _c) sudo_getline((_a), (_b), (_c)) +#endif /* HAVE_GETLINE */ +#ifndef HAVE_UTIMENSAT +__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_FUTIMENS +__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) +__dso_public int sudo_snprintf(char *str, size_t n, char const *fmt, ...) __printflike(3, 4); +# undef snprintf +# define snprintf sudo_snprintf +#endif /* HAVE_SNPRINTF */ +#if !defined(HAVE_VSNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) +__dso_public int sudo_vsnprintf(char *str, size_t n, const char *fmt, va_list ap) __printflike(3, 0); +# undef vsnprintf +# define vsnprintf sudo_vsnprintf +#endif /* HAVE_VSNPRINTF */ +#if !defined(HAVE_ASPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) +__dso_public int sudo_asprintf(char **str, char const *fmt, ...) __printflike(2, 3); +# undef asprintf +# define asprintf sudo_asprintf +#endif /* HAVE_ASPRINTF */ +#if !defined(HAVE_VASPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) +__dso_public int sudo_vasprintf(char **str, const char *fmt, va_list ap) __printflike(2, 0); +# undef vasprintf +# define vasprintf sudo_vasprintf +#endif /* HAVE_VASPRINTF */ +#ifndef HAVE_STRLCAT +__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 +__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 +__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 +__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_MEMRCHR +__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_MEMSET_S +__dso_public errno_t sudo_memset_s(void *v, rsize_t smax, int c, rsize_t n); +# undef memset_s +# define memset_s(_a, _b, _c, _d) sudo_memset_s((_a), (_b), (_c), (_d)) +#endif /* HAVE_MEMSET_S */ +#if !defined(HAVE_MKDTEMP) || !defined(HAVE_MKSTEMPS) +__dso_public char *sudo_mkdtemp(char *path); +# undef mkdtemp +# define mkdtemp(_a) sudo_mkdtemp((_a)) +__dso_public int sudo_mkstemps(char *path, int slen); +# undef mkstemps +# define mkstemps(_a, _b) sudo_mkstemps((_a), (_b)) +#endif /* !HAVE_MKDTEMP || !HAVE_MKSTEMPS */ +#ifndef HAVE_NANOSLEEP +__dso_public int sudo_nanosleep(const struct timespec *timeout, struct timespec *remainder); +#undef nanosleep +# define nanosleep(_a, _b) sudo_nanosleep((_a), (_b)) +#endif +#ifndef HAVE_PW_DUP +__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 +__dso_public char *sudo_strsignal(int signo); +# undef strsignal +# define strsignal(_a) sudo_strsignal((_a)) +#endif /* HAVE_STRSIGNAL */ +#ifndef HAVE_SIG2STR +__dso_public int sudo_sig2str(int signo, char *signame); +# undef sig2str +# define sig2str(_a, _b) sudo_sig2str((_a), (_b)) +#endif /* HAVE_SIG2STR */ +#if !defined(HAVE_INET_NTOP) && defined(SUDO_NET_IFS_C) +__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 +__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 +__dso_public const char *sudo_getprogname(void); +# undef getprogname +# define getprogname() sudo_getprogname() +#endif /* HAVE_GETPROGNAME */ +#ifndef HAVE_REALLOCARRAY +__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_VSYSLOG +__dso_public void sudo_vsyslog(int pri, const char *fmt, va_list ap); +# undef vsyslog +# define vsyslog(_a, _b, _c) sudo_vsyslog((_a), (_b), (_c)) +#endif /* HAVE_VSYSLOG */ +#ifndef HAVE_PIPE2 +__dso_public int sudo_pipe2(int fildes[2], int flags); +# undef pipe2 +# define pipe2(_a, _b) sudo_pipe2((_a), (_b)) +#endif /* HAVE_PIPE2 */ + +#endif /* SUDO_COMPAT_H */ diff --git a/include/sudo_conf.h b/include/sudo_conf.h new file mode 100644 index 0000000..6676116 --- /dev/null +++ b/include/sudo_conf.h @@ -0,0 +1,85 @@ +/* + * 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_CONF_H +#define SUDO_CONF_H + +#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. */ +__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. */ +__dso_public const char *sudo_conf_askpass_path_v1(void); +__dso_public const char *sudo_conf_sesh_path_v1(void); +__dso_public const char *sudo_conf_noexec_path_v1(void); +__dso_public const char *sudo_conf_plugin_dir_path_v1(void); +__dso_public const char *sudo_conf_devsearch_path_v1(void); +__dso_public struct sudo_conf_debug_list *sudo_conf_debugging_v1(void); +__dso_public struct sudo_conf_debug_file_list *sudo_conf_debug_files_v1(const char *progname); +__dso_public struct plugin_info_list *sudo_conf_plugins_v1(void); +__dso_public bool sudo_conf_disable_coredump_v1(void); +__dso_public bool sudo_conf_probe_interfaces_v1(void); +__dso_public int sudo_conf_group_source_v1(void); +__dso_public int sudo_conf_max_groups_v1(void); +__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_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_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..105a7e6 --- /dev/null +++ b/include/sudo_debug.h @@ -0,0 +1,297 @@ +/* + * 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 <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_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) \ + const int sudo_debug_subsys = (subsys); \ + debug_decl_func(funcname); +#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)) + +__dso_public int sudo_debug_deregister_v1(int instance_id); +__dso_public void sudo_debug_enter_v1(const char *func, const char *file, int line, int subsys); +__dso_public void sudo_debug_execve2_v1(int level, const char *path, char *const argv[], char *const envp[]); +__dso_public void sudo_debug_exit_v1(const char *func, const char *file, int line, int subsys); +__dso_public void sudo_debug_exit_bool_v1(const char *func, const char *file, int line, int subsys, bool ret); +__dso_public void sudo_debug_exit_int_v1(const char *func, const char *file, int line, int subsys, int ret); +__dso_public void sudo_debug_exit_long_v1(const char *func, const char *file, int line, int subsys, long ret); +__dso_public void sudo_debug_exit_ptr_v1(const char *func, const char *file, int line, int subsys, const void *ret); +__dso_public void sudo_debug_exit_id_t_v1(const char *func, const char *file, int line, int subsys, id_t ret); +__dso_public void sudo_debug_exit_size_t_v1(const char *func, const char *file, int line, int subsys, size_t ret); +__dso_public void sudo_debug_exit_ssize_t_v1(const char *func, const char *file, int line, int subsys, ssize_t ret); +__dso_public void sudo_debug_exit_str_v1(const char *func, const char *file, int line, int subsys, const char *ret); +__dso_public void sudo_debug_exit_str_masked_v1(const char *func, const char *file, int line, int subsys, const char *ret); +__dso_public void sudo_debug_exit_time_t_v1(const char *func, const char *file, int line, int subsys, time_t ret); +__dso_public pid_t sudo_debug_fork_v1(void); +__dso_public int sudo_debug_get_active_instance_v1(void); +__dso_public int sudo_debug_get_fds_v1(unsigned char **fds); +__dso_public int sudo_debug_get_instance_v1(const char *program); +__dso_public void sudo_debug_printf2_v1(const char *func, const char *file, int line, int level, const char *fmt, ...) __printf0like(5, 6); +__dso_public void sudo_debug_printf_nvm_v1(int pri, const char *fmt, ...) __printf0like(2, 3); +__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); +__dso_public int sudo_debug_set_active_instance_v1(int inst); +__dso_public void sudo_debug_update_fd_v1(int ofd, int nfd); +__dso_public void sudo_debug_vprintf2_v1(const char *func, const char *file, int line, int level, const char *fmt, va_list ap) __printf0like(5, 0); +__dso_public void sudo_debug_write2_v1(int fd, const char *func, const char *file, int line, const char *str, int len, int errnum); + +#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_printf2 sudo_debug_printf2_v1 +#define sudo_debug_printf_nvm sudo_debug_printf_nvm_v1 +#define sudo_debug_register(_a, _b, _c, _d) sudo_debug_register_v1((_a), (_b), (_c), (_d)) +#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..9fffa1b --- /dev/null +++ b/include/sudo_digest.h @@ -0,0 +1,44 @@ +/* + * 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. */ +__dso_public struct sudo_digest *sudo_digest_alloc_v1(int digest_type); +__dso_public void sudo_digest_free_v1(struct sudo_digest *dig); +__dso_public void sudo_digest_reset_v1(struct sudo_digest *dig); +__dso_public int sudo_digest_getlen_v1(int digest_type); +__dso_public void sudo_digest_update_v1(struct sudo_digest *dig, const void *data, size_t len); +__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..08fd8a8 --- /dev/null +++ b/include/sudo_dso.h @@ -0,0 +1,55 @@ +/* + * 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. */ +__dso_public char *sudo_dso_strerror_v1(void); +__dso_public int sudo_dso_unload_v1(void *handle); +__dso_public void *sudo_dso_findsym_v1(void *handle, const char *symbol); +__dso_public void *sudo_dso_load_v1(const char *path, int mode); +__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..9797d58 --- /dev/null +++ b/include/sudo_event.h @@ -0,0 +1,193 @@ +/* + * 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 <signal.h> /* for sigatomic_t and NSIG */ +#include "sudo_queue.h" + +/* Event types */ +#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) */ + +/* 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 + +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 singal */ +#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 + fd_set *readfds_in; /* read I/O descriptor set (in) */ + fd_set *writefds_in; /* write I/O descriptor set (in) */ + fd_set *readfds_out; /* read I/O descriptor set (out) */ + fd_set *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. */ +__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. */ +__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. */ +__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. */ +__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. */ +__dso_public void sudo_ev_free_v1(struct sudo_event *ev); +#define sudo_ev_free(_a) sudo_ev_free_v1((_a)) + +/* Add an event, returns 0 on success, -1 on error */ +__dso_public int sudo_ev_add_v1(struct sudo_event_base *head, struct sudo_event *ev, struct timeval *timo, bool tohead); +__dso_public int sudo_ev_add_v2(struct sudo_event_base *head, struct sudo_event *ev, 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 */ +__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 */ +__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 */ +__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 the remaining timeout associated with an event. */ +__dso_public int sudo_ev_get_timeleft_v1(struct sudo_event *ev, struct timeval *tv); +__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. */ +__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. */ +__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. */ +__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(). */ +__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(). */ +__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) + +/* 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_fatal.h b/include/sudo_fatal.h new file mode 100644 index 0000000..ea92b3b --- /dev/null +++ b/include/sudo_fatal.h @@ -0,0 +1,205 @@ +/* + * 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 */ + +/* + * 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); + +struct sudo_conv_message; +struct sudo_conv_reply; +struct sudo_conv_callback; + +__dso_public int sudo_fatal_callback_deregister_v1(sudo_fatal_callback_t func); +__dso_public int sudo_fatal_callback_register_v1(sudo_fatal_callback_t func); +__dso_public char *sudo_warn_gettext_v1(const char *domainname, const char *msgid) __format_arg(2); +__dso_public void sudo_warn_set_locale_func_v1(bool (*func)(bool, int *)); +__dso_public void sudo_fatal_nodebug_v1(const char *fmt, ...) __printf0like(1, 2) __attribute__((__noreturn__)); +__dso_public void sudo_fatalx_nodebug_v1(const char *fmt, ...) __printflike(1, 2) __attribute__((__noreturn__)); +__dso_public void sudo_gai_fatal_nodebug_v1(int errnum, const char *fmt, ...) __printflike(2, 3) __attribute__((__noreturn__)); +__dso_public void sudo_vfatal_nodebug_v1(const char *fmt, va_list ap) __printf0like(1, 0) __attribute__((__noreturn__)); +__dso_public void sudo_vfatalx_nodebug_v1(const char *fmt, va_list ap) __printflike(1, 0) __attribute__((__noreturn__)); +__dso_public void sudo_gai_vfatal_nodebug_v1(int errnum, const char *fmt, va_list ap) __printflike(2, 0) __attribute__((__noreturn__)); +__dso_public void sudo_warn_nodebug_v1(const char *fmt, ...) __printf0like(1, 2); +__dso_public void sudo_warnx_nodebug_v1(const char *fmt, ...) __printflike(1, 2); +__dso_public void sudo_gai_warn_nodebug_v1(int errnum, const char *fmt, ...) __printflike(2, 3); +__dso_public void sudo_vwarn_nodebug_v1(const char *fmt, va_list ap) __printf0like(1, 0); +__dso_public void sudo_vwarnx_nodebug_v1(const char *fmt, va_list ap) __printflike(1, 0); +__dso_public void sudo_gai_vwarn_nodebug_v1(int errnum, const char *fmt, va_list ap) __printflike(2, 0); +__dso_public void sudo_warn_set_conversation_v1(int (*conv)(int num_msgs, const struct sudo_conv_message *msgs, struct sudo_conv_reply *replies, struct sudo_conv_callback *callback)); + +#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..a770b08 --- /dev/null +++ b/include/sudo_gettext.h @@ -0,0 +1,75 @@ +/* + * 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_lbuf.h b/include/sudo_lbuf.h new file mode 100644 index 0000000..8e07063 --- /dev/null +++ b/include/sudo_lbuf.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2010, 2011, 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. + */ + +#ifndef SUDO_LBUF_H +#define SUDO_LBUF_H + +/* + * Line buffer struct. + */ +struct sudo_lbuf { + int (*output)(const char *); + char *buf; + const char *continuation; + int indent; + int len; + int size; + short cols; + short error; +}; + +typedef int (*sudo_lbuf_output_t)(const char *); + +__dso_public void sudo_lbuf_init_v1(struct sudo_lbuf *lbuf, sudo_lbuf_output_t output, int indent, const char *continuation, int cols); +__dso_public void sudo_lbuf_destroy_v1(struct sudo_lbuf *lbuf); +__dso_public bool sudo_lbuf_append_v1(struct sudo_lbuf *lbuf, const char *fmt, ...) __printflike(2, 3); +__dso_public bool sudo_lbuf_append_quoted_v1(struct sudo_lbuf *lbuf, const char *set, const char *fmt, ...) __printflike(3, 4); +__dso_public void sudo_lbuf_print_v1(struct sudo_lbuf *lbuf); +__dso_public bool sudo_lbuf_error_v1(struct sudo_lbuf *lbuf); +__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_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..31d96cc --- /dev/null +++ b/include/sudo_plugin.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2009-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_PLUGIN_H +#define SUDO_PLUGIN_H + +/* API version major/minor */ +#define SUDO_API_VERSION_MAJOR 1 +#define SUDO_API_VERSION_MINOR 13 +#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) + +/* 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. It is also useful as a max value + * for memset_s() when clearing passwords returned by the conversation + * function. + */ +#define SUDO_CONV_REPL_MAX 255 + +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. + */ + +/* 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 + +/* 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_printf, char * const settings[], + char * const user_info[], char * const user_env[], + char * const plugin_options[]); + 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[]); + int (*list)(int argc, char * const argv[], int verbose, + const char *list_user); + int (*validate)(void); + void (*invalidate)(int remove); + int (*init_session)(struct passwd *pwd, char **user_env_out[]); + void (*register_hooks)(int version, int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook)); +}; + +/* 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_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[]); + 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); + int (*log_ttyout)(const char *buf, unsigned int len); + int (*log_stdin)(const char *buf, unsigned int len); + int (*log_stdout)(const char *buf, unsigned int len); + int (*log_stderr)(const char *buf, unsigned int len); + 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 rows, unsigned int cols); + int (*log_suspend)(int signo); +}; + +/* 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_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..f48daf9 --- /dev/null +++ b/include/sudo_queue.h @@ -0,0 +1,821 @@ +/* + * 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..2e83085 --- /dev/null +++ b/include/sudo_rand.h @@ -0,0 +1,50 @@ +/* + * 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 +/* Note: not exported by libutil. */ +uint32_t sudo_arc4random(void); +# undef arc4random +# define arc4random() sudo_arc4random() +#endif /* ARC4RANDOM */ + +#ifndef HAVE_ARC4RANDOM_UNIFORM +__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..96cac16 --- /dev/null +++ b/include/sudo_util.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2013-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_UTIL_H +#define SUDO_UTIL_H + +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ + +#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 */ + +/* 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 begining 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 + +/* aix.c */ +__dso_public int aix_getauthregistry_v1(char *user, char *saved_registry); +#define aix_getauthregistry(_a, _b) aix_getauthregistry_v1((_a), (_b)) +__dso_public int aix_prep_user_v1(char *user, const char *tty); +#define aix_prep_user(_a, _b) aix_prep_user_v1((_a), (_b)) +__dso_public int aix_restoreauthdb_v1(void); +#define aix_restoreauthdb() aix_restoreauthdb_v1() +__dso_public int aix_setauthdb_v1(char *user); +__dso_public int aix_setauthdb_v2(char *user, char *registry); +#define aix_setauthdb(_a, _b) aix_setauthdb_v2((_a), (_b)) + +/* gethostname.c */ +__dso_public char *sudo_gethostname_v1(void); +#define sudo_gethostname() sudo_gethostname_v1() + +/* gettime.c */ +__dso_public int sudo_gettime_awake_v1(struct timespec *ts); +#define sudo_gettime_awake(_a) sudo_gettime_awake_v1((_a)) +__dso_public int sudo_gettime_mono_v1(struct timespec *ts); +#define sudo_gettime_mono(_a) sudo_gettime_mono_v1((_a)) +__dso_public int sudo_gettime_real_v1(struct timespec *ts); +#define sudo_gettime_real(_a) sudo_gettime_real_v1((_a)) + +/* gidlist.c */ +__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 */ +__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)) + +/* key_val.c */ +__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 */ +__dso_public bool sudo_lock_file_v1(int fd, int action); +#define sudo_lock_file(_a, _b) sudo_lock_file_v1((_a), (_b)) +__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)) + +/* parseln.c */ +__dso_public ssize_t sudo_parseln_v1(char **buf, size_t *bufsize, unsigned int *lineno, FILE *fp); +__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 */ +__dso_public void initprogname(const char *); + +/* 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 +struct stat; +__dso_public int sudo_secure_dir_v1(const char *path, uid_t uid, gid_t gid, struct stat *sbp); +#define sudo_secure_dir(_a, _b, _c, _d) sudo_secure_dir_v1((_a), (_b), (_c), (_d)) +__dso_public int sudo_secure_file_v1(const char *path, uid_t uid, gid_t gid, struct stat *sbp); +#define sudo_secure_file(_a, _b, _c, _d) sudo_secure_file_v1((_a), (_b), (_c), (_d)) + +/* setgroups.c */ +__dso_public int sudo_setgroups_v1(int ngids, const GETGROUPS_T *gids); +#define sudo_setgroups(_a, _b) sudo_setgroups_v1((_a), (_b)) + +/* strsplit.c */ +__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 */ +__dso_public int sudo_strtobool_v1(const char *str); +#define sudo_strtobool(_a) sudo_strtobool_v1((_a)) + +/* strtoid.c */ +__dso_public id_t sudo_strtoid_v1(const char *str, const char *sep, char **endp, const char **errstr); +#define sudo_strtoid(_a, _b, _c, _d) sudo_strtoid_v1((_a), (_b), (_c), (_d)) + +/* strtomode.c */ +__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 */ +__dso_public bool sudo_term_cbreak_v1(int fd); +#define sudo_term_cbreak(_a) sudo_term_cbreak_v1((_a)) +__dso_public bool sudo_term_copy_v1(int src, int dst); +#define sudo_term_copy(_a, _b) sudo_term_copy_v1((_a), (_b)) +__dso_public bool sudo_term_noecho_v1(int fd); +#define sudo_term_noecho(_a) sudo_term_noecho_v1((_a)) +__dso_public bool sudo_term_raw_v1(int fd, int isig); +#define sudo_term_raw(_a, _b) sudo_term_raw_v1((_a), (_b)) +__dso_public bool sudo_term_restore_v1(int fd, bool flush); +#define sudo_term_restore(_a, _b) sudo_term_restore_v1((_a), (_b)) + +/* ttyname_dev.c */ +__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 */ +__dso_public void sudo_get_ttysize_v1(int *rowp, int *colp); +#define sudo_get_ttysize(_a, _b) sudo_get_ttysize_v1((_a), (_b)) + +#endif /* SUDO_UTIL_H */ |