Initial realm_auth_sudo plugin commit
Some checks failed
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
CIFuzz / Fuzzing (push) Has been cancelled

This commit is contained in:
isa
2025-02-11 23:06:36 -05:00
parent 27963e39f3
commit f7f0457b92
8 changed files with 753 additions and 4 deletions

View File

@@ -595,6 +595,9 @@ plugins/sample/sample_plugin.exp
plugins/sample_approval/Makefile.in
plugins/sample_approval/sample_approval.c
plugins/sample_approval/sample_approval.exp
plugins/realm_sudo_auth/Makefile.in
plugins/realm_sudo_auth/realm_sudo_auth_plugin.c
plugins/realm_sudo_auth/realm_sudo_auth_plugin.exp
plugins/sudoers/Makefile.in
plugins/sudoers/alias.c
plugins/sudoers/audit.c

View File

@@ -62,7 +62,7 @@ SUBDIRS = lib/util @ZLIB_SRC@ lib/eventlog lib/fuzzstub lib/iolog \
plugins/system_group @PYTHON_PLUGIN_SRC@ src include \
docs examples
SAMPLES = plugins/sample plugins/sample_approval
SAMPLES = plugins/sample plugins/sample_approval plugins/realm_sudo_auth
VERSION = @PACKAGE_VERSION@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
@@ -223,7 +223,7 @@ depend: siglist.c signame.c tsgetusershell.c
lib/iolog/Makefile.in lib/logsrv/Makefile.in logsrvd/Makefile.in \
lib/protobuf-c/Makefile.in lib/ssl_compat/Makefile.in \
plugins/group_file/Makefile.in plugins/audit_json/Makefile.in \
plugins/sample/Makefile.in plugins/sample_approval/Makefile.in \
plugins/sample/Makefile.in plugins/sample_approval/Makefile.in plugins/realm_sudo_auth/Makefile.in \
plugins/sudoers/Makefile.in plugins/system_group/Makefile.in \
plugins/python/Makefile.in src/Makefile.in && \
$(top_builddir)/config.status --file $(top_builddir)/lib/util/Makefile \
@@ -239,6 +239,7 @@ depend: siglist.c signame.c tsgetusershell.c
--file $(top_builddir)/plugins/audit_json/Makefile \
--file $(top_builddir)/plugins/sample/Makefile \
--file $(top_builddir)/plugins/sample_approval/Makefile \
--file $(top_builddir)/plugins/realm_sudo_auth/Makefile \
--file $(top_builddir)/plugins/sudoers/Makefile \
--file $(top_builddir)/plugins/system_group/Makefile \
--file $(top_builddir)/plugins/python/Makefile \

3
configure vendored
View File

@@ -36149,7 +36149,7 @@ then :
fi
ac_config_files="$ac_config_files Makefile docs/Makefile examples/Makefile examples/sudoers examples/sudo.conf examples/sudo_logsrvd.conf examples/syslog.conf include/Makefile lib/eventlog/Makefile lib/fuzzstub/Makefile lib/iolog/Makefile lib/logsrv/Makefile lib/protobuf-c/Makefile lib/ssl_compat/Makefile lib/util/Makefile lib/util/regress/harness lib/util/util.exp logsrvd/Makefile src/intercept.exp src/sudo_usage.h src/Makefile plugins/audit_json/Makefile plugins/sample/Makefile plugins/group_file/Makefile plugins/sample_approval/Makefile plugins/system_group/Makefile plugins/sudoers/Makefile plugins/sudoers/regress/harness plugins/sudoers/sudoers"
ac_config_files="$ac_config_files Makefile docs/Makefile examples/Makefile examples/sudoers examples/sudo.conf examples/sudo_logsrvd.conf examples/syslog.conf include/Makefile lib/eventlog/Makefile lib/fuzzstub/Makefile lib/iolog/Makefile lib/logsrv/Makefile lib/protobuf-c/Makefile lib/ssl_compat/Makefile lib/util/Makefile lib/util/regress/harness lib/util/util.exp logsrvd/Makefile src/intercept.exp src/sudo_usage.h src/Makefile plugins/audit_json/Makefile plugins/sample/Makefile plugins/group_file/Makefile plugins/sample_approval/Makefile plugins/realm_sudo_auth/Makefile plugins/system_group/Makefile plugins/sudoers/Makefile plugins/sudoers/regress/harness plugins/sudoers/sudoers"
ac_config_commands="$ac_config_commands harness"
@@ -37178,6 +37178,7 @@ do
"plugins/sample/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sample/Makefile" ;;
"plugins/group_file/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/group_file/Makefile" ;;
"plugins/sample_approval/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sample_approval/Makefile" ;;
"plugins/realm_sudo_auth/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/realm_sudo_auth/Makefile" ;;
"plugins/system_group/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/system_group/Makefile" ;;
"plugins/sudoers/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sudoers/Makefile" ;;
"plugins/sudoers/regress/harness") CONFIG_FILES="$CONFIG_FILES plugins/sudoers/regress/harness" ;;

View File

@@ -4424,7 +4424,7 @@ AS_IF([test X"$INIT_SCRIPT" != X""], [
AC_CONFIG_FILES([etc/init.d/sudo.conf])
])
AC_CONFIG_FILES([Makefile docs/Makefile examples/Makefile examples/sudoers examples/sudo.conf examples/sudo_logsrvd.conf examples/syslog.conf include/Makefile lib/eventlog/Makefile lib/fuzzstub/Makefile lib/iolog/Makefile lib/logsrv/Makefile lib/protobuf-c/Makefile lib/ssl_compat/Makefile lib/util/Makefile lib/util/regress/harness lib/util/util.exp logsrvd/Makefile src/intercept.exp src/sudo_usage.h src/Makefile plugins/audit_json/Makefile plugins/sample/Makefile plugins/group_file/Makefile plugins/sample_approval/Makefile plugins/system_group/Makefile plugins/sudoers/Makefile plugins/sudoers/regress/harness plugins/sudoers/sudoers])
AC_CONFIG_FILES([Makefile docs/Makefile examples/Makefile examples/sudoers examples/sudo.conf examples/sudo_logsrvd.conf examples/syslog.conf include/Makefile lib/eventlog/Makefile lib/fuzzstub/Makefile lib/iolog/Makefile lib/logsrv/Makefile lib/protobuf-c/Makefile lib/ssl_compat/Makefile lib/util/Makefile lib/util/regress/harness lib/util/util.exp logsrvd/Makefile src/intercept.exp src/sudo_usage.h src/Makefile plugins/audit_json/Makefile plugins/sample/Makefile plugins/group_file/Makefile plugins/sample_approval/Makefile plugins/realm_sudo_auth/Makefile plugins/system_group/Makefile plugins/sudoers/Makefile plugins/sudoers/regress/harness plugins/sudoers/sudoers])
AC_CONFIG_COMMANDS([harness], [chmod +x lib/util/regress/harness plugins/sudoers/regress/harness])
AC_OUTPUT

View File

@@ -0,0 +1,222 @@
#
# SPDX-License-Identifier: ISC
#
# Copyright (c) 2011-2024 Todd C. Miller <Todd.Miller@sudo.ws>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# @configure_input@
#
#### Start of system configuration section. ####
srcdir = @srcdir@
abs_srcdir = @abs_srcdir@
top_srcdir = @top_srcdir@
abs_top_srcdir = @abs_top_srcdir@
top_builddir = @top_builddir@
abs_top_builddir = @abs_top_builddir@
devdir = @devdir@
scriptdir = $(top_srcdir)/scripts
incdir = $(top_srcdir)/include
cross_compiling = @CROSS_COMPILING@
# Compiler & tools to use
CC = @CC@
CPP = @CPP@
LIBTOOL = @LIBTOOL@
SED = @SED@
AWK = @AWK@
# Our install program supports extra flags...
INSTALL = $(SHELL) $(scriptdir)/install-sh -c
INSTALL_OWNER = -o $(install_uid) -g $(install_gid)
INSTALL_BACKUP = @INSTALL_BACKUP@
# Libraries
LIBS = $(top_builddir)/lib/util/libsudo_util.la
# C preprocessor flags
CPPFLAGS = -I$(incdir) -I$(top_builddir) @CPPFLAGS@
# Usually -O and/or -g
CFLAGS = @CFLAGS@
# Flags to pass to the link stage
LDFLAGS = @LDFLAGS@
LT_LDFLAGS = @LT_LDFLAGS@ @LT_LDEXPORTS@
# Flags to pass to libtool
LTFLAGS = --tag=disable-static
# Address sanitizer flags
ASAN_CFLAGS = @ASAN_CFLAGS@
ASAN_LDFLAGS = @ASAN_LDFLAGS@
# PIE flags
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
# Stack smashing protection flags
HARDENING_CFLAGS = @HARDENING_CFLAGS@
HARDENING_LDFLAGS = @HARDENING_LDFLAGS@
# cppcheck options, usually set in the top-level Makefile
CPPCHECK_OPTS = -q --enable=warning,performance,portability --suppress=constStatement --suppress=compareBoolExpressionWithInt --error-exitcode=1 --inline-suppr -Dva_copy=va_copy -U__cplusplus -UQUAD_MAX -UQUAD_MIN -UUQUAD_MAX -U_POSIX_HOST_NAME_MAX -U_POSIX_PATH_MAX -U__NBBY -DNSIG=64
# splint options, usually set in the top-level Makefile
SPLINT_OPTS = -D__restrict= -checks
# PVS-studio options
PVS_CFG = $(top_srcdir)/PVS-Studio.cfg
PVS_IGNORE = 'V707,V011,V002,V536'
PVS_LOG_OPTS = -a 'GA:1,2' -e -t errorfile -d $(PVS_IGNORE)
# Where to install things...
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
sysconfdir = @sysconfdir@
adminconfdir = @adminconfdir@
libexecdir = @libexecdir@
datarootdir = @datarootdir@
localstatedir = @localstatedir@
plugindir = @plugindir@
# File mode and map file to use for shared libraries/objects
shlib_enable = @SHLIB_ENABLE@
shlib_mode = @SHLIB_MODE@
shlib_exp = $(srcdir)/realm_sudo_auth_plugin.exp
shlib_map = realm_sudo_auth_plugin.map
shlib_opt = realm_sudo_auth_plugin.opt
# User and group ids the installed files should be "owned" by
install_uid = 0
install_gid = 0
#### End of system configuration section. ####
SHELL = @SHELL@
OBJS = realm_sudo_auth_plugin.lo
LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/
VERSION = @PACKAGE_VERSION@
all: realm_sudo_auth_plugin.la
depend:
$(scriptdir)/mkdep.pl --srcdir=$(abs_top_srcdir) \
--builddir=$(abs_top_builddir) plugins/realm_sudo_auth/Makefile.in
cd $(top_builddir) && ./config.status --file plugins/realm_sudo_auth/Makefile
Makefile: $(srcdir)/Makefile.in
cd $(top_builddir) && ./config.status --file plugins/realm_sudo_auth/Makefile
.SUFFIXES: .c .h .i .lo .plog
.c.lo:
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(HARDENING_CFLAGS) $<
.c.i:
$(CPP) $(CPPFLAGS) $< > $@
.i.plog:
ifile=$<; rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $${ifile%i}c --i-file $< --output-file $@
$(shlib_map): $(shlib_exp)
@$(AWK) 'BEGIN { print "{\n\tglobal:" } { print "\t\t"$$0";" } END { print "\tlocal:\n\t\t*;\n};" }' $(shlib_exp) > $@
$(shlib_opt): $(shlib_exp)
@$(SED) 's/^/+e /' $(shlib_exp) > $@
realm_sudo_auth_plugin.la: $(OBJS) @LT_LDDEP@
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) $(ASAN_LDFLAGS) $(HARDENING_LDFLAGS) $(LT_LDFLAGS) -o $@ $(OBJS) $(LIBS) -module -avoid-version -rpath $(plugindir) -shrext .so
pre-install:
install: install-plugin
install-dirs:
$(SHELL) $(scriptdir)/mkinstalldirs $(DESTDIR)$(plugindir)
install-binaries:
install-includes:
install-doc:
install-plugin: install-dirs realm_sudo_auth_plugin.la
if [ X"$(shlib_enable)" = X"yes" ]; then \
INSTALL_BACKUP='$(INSTALL_BACKUP)' $(LIBTOOL) $(LTFLAGS) --mode=install $(INSTALL) $(INSTALL_OWNER) -m $(shlib_mode) realm_sudo_auth_plugin.la $(DESTDIR)$(plugindir); \
fi
install-fuzzer:
uninstall:
-$(LIBTOOL) $(LTFLAGS) --mode=uninstall rm -f $(DESTDIR)$(plugindir)/realm_sudo_auth_plugin.la
-test -z "$(INSTALL_BACKUP)" || \
rm -f $(DESTDIR)$(plugindir)/realm_sudo_auth_plugin.so$(INSTALL_BACKUP)
splint:
splint $(SPLINT_OPTS) -I$(incdir) -I$(top_builddir) $(srcdir)/*.c
cppcheck:
cppcheck $(CPPCHECK_OPTS) -I$(incdir) -I$(top_builddir) $(srcdir)/*.c
pvs-log-files: $(POBJS)
pvs-studio: $(POBJS)
plog-converter $(PVS_LOG_OPTS) $(POBJS)
fuzz:
check-fuzzer:
check: check-fuzzer
check-verbose: check
clean:
-$(LIBTOOL) $(LTFLAGS) --mode=clean rm -f *.lo *.o *.la
-rm -f *.i *.plog stamp-* core *.core core.*
mostlyclean: clean
distclean: clean
-rm -rf Makefile .libs $(shlib_map) $(shlib_opt)
clobber: distclean
realclean: distclean
rm -f TAGS tags
cleandir: realclean
.PHONY: clean mostlyclean distclean cleandir clobber realclean
# Autogenerated dependencies, do not modify
realm_sudo_auth_plugin.lo: $(srcdir)/realm_sudo_auth_plugin.c $(incdir)/compat/stdbool.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_plugin.h \
$(incdir)/sudo_util.h $(top_builddir)/config.h \
$(top_builddir)/pathnames.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(HARDENING_CFLAGS) $(srcdir)/realm_sudo_auth_plugin.c
realm_sudo_auth_plugin.i: $(srcdir)/realm_sudo_auth_plugin.c $(incdir)/compat/stdbool.h \
$(incdir)/sudo_compat.h $(incdir)/sudo_plugin.h \
$(incdir)/sudo_util.h $(top_builddir)/config.h \
$(top_builddir)/pathnames.h
$(CPP) $(CPPFLAGS) $(srcdir)/realm_sudo_auth_plugin.c > $@
realm_sudo_auth_plugin.plog: realm_sudo_auth_plugin.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/realm_sudo_auth_plugin.c --i-file realm_sudo_auth_plugin.i --output-file $@

View File

@@ -0,0 +1,22 @@
This is a sample sudo policy plugin. See the sudo_plugin manual for
information on writing your own plugin.
The sample policy plugin is not installed by default. It can be installed
by running "make install" as the superuser from the plugins/sample
directory.
To actually use the sample plugin, you'll need to modify the
/etc/sudo.conf file. Caution: you should not make changes to
/etc/sudo.conf without also having a root shell open repair things
in case of an error. To enable the plugin, first comment out any
existing policy Plugin line in /etc/sudo.conf, for example:
Plugin sudoers_policy sudoers.so
Then add a line for the realm_sudo_auth plugin:
Plugin realm_sudo_auth_policy realm_sudo_auth_plugin.so
You may need to create /etc/sudo.conf if it does not already exist.
Note that you may only have a single policy plugin defined.

View File

@@ -0,0 +1,498 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2010-2016, 2022 Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STDBOOL_H
# include <stdbool.h>
#else
# include <compat/stdbool.h>
#endif /* HAVE_STDBOOL_H */
#include <string.h>
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#include <ctype.h>
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <pwd.h>
#include <unistd.h>
#include <pathnames.h>
#include <sudo_compat.h>
#include <sudo_plugin.h>
#include <sudo_util.h>
#include <sys/socket.h>
#include <sys/un.h>
#define WRITE_BUFFER_SIZE 1024
#define READ_BUFFER_SIZE 2
#define SOCKET_PATH "/tmp/sudo_realm_plugin.sock"
/*
* Sample plugin module that allows any user who knows the password
* ("test") to run any command as root. Since there is no credential
* caching the validate and invalidate functions are NULL.
*/
static struct plugin_state {
char **envp;
char *const *settings;
char *const *user_info;
} plugin_state;
static sudo_conv_t sudo_conv;
static sudo_printf_t sudo_log;
static FILE *input, *output;
static uid_t runas_uid = ROOT_UID;
static gid_t runas_gid = (gid_t)-1;
static int use_sudoedit = false;
/*
* Plugin policy open function.
*/
static int
policy_open(unsigned int version, sudo_conv_t conversation,
sudo_printf_t sudo_plugin_printf, char *const settings[],
char *const user_info[], char *const user_env[], char *const args[],
const char **errstr)
{
char *const *ui;
struct passwd *pw;
const char *runas_user = NULL;
struct group *gr;
const char *runas_group = NULL;
if (!sudo_conv)
sudo_conv = conversation;
if (!sudo_log)
sudo_log = sudo_plugin_printf;
if (SUDO_API_VERSION_GET_MAJOR(version) != SUDO_API_VERSION_MAJOR) {
sudo_log(SUDO_CONV_ERROR_MSG,
"the sample plugin requires API version %d.x\n",
SUDO_API_VERSION_MAJOR);
return -1;
}
/* Only allow commands to be run as root. */
for (ui = settings; *ui != NULL; ui++) {
if (strncmp(*ui, "runas_user=", sizeof("runas_user=") - 1) == 0) {
runas_user = *ui + sizeof("runas_user=") - 1;
}
if (strncmp(*ui, "runas_group=", sizeof("runas_group=") - 1) == 0) {
runas_group = *ui + sizeof("runas_group=") - 1;
}
if (strncmp(*ui, "progname=", sizeof("progname=") - 1) == 0) {
initprogname(*ui + sizeof("progname=") - 1);
}
/* Check to see if sudo was called as sudoedit or with -e flag. */
if (strncmp(*ui, "sudoedit=", sizeof("sudoedit=") - 1) == 0) {
if (strcasecmp(*ui + sizeof("sudoedit=") - 1, "true") == 0)
use_sudoedit = true;
}
/* This plugin doesn't support running sudo with no arguments. */
if (strncmp(*ui, "implied_shell=", sizeof("implied_shell=") - 1) == 0) {
if (strcasecmp(*ui + sizeof("implied_shell=") - 1, "true") == 0)
return -2; /* usage error */
}
}
if (runas_user != NULL) {
if ((pw = getpwnam(runas_user)) == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "unknown user %s\n", runas_user);
return 0;
}
runas_uid = pw->pw_uid;
}
if (runas_group != NULL) {
if ((gr = getgrnam(runas_group)) == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "unknown group %s\n", runas_group);
return 0;
}
runas_gid = gr->gr_gid;
}
/* Plugin state. */
plugin_state.envp = (char **)user_env;
plugin_state.settings = settings;
plugin_state.user_info = user_info;
return 1;
}
static char *
find_in_path(char *command, char **envp)
{
struct stat sb;
char *path = NULL;
char *path0, **ep, *cp;
char pathbuf[PATH_MAX], *qualified = NULL;
if (strchr(command, '/') != NULL)
return command;
for (ep = plugin_state.envp; *ep != NULL; ep++) {
if (strncmp(*ep, "PATH=", 5) == 0) {
path = *ep + 5;
break;
}
}
path = path0 = strdup(path ? path : _PATH_DEFPATH);
do {
if ((cp = strchr(path, ':')))
*cp = '\0';
snprintf(
pathbuf, sizeof(pathbuf), "%s/%s", *path ? path : ".", command);
if (stat(pathbuf, &sb) == 0) {
if (S_ISREG(sb.st_mode) && (sb.st_mode & 0000111)) {
qualified = pathbuf;
break;
}
}
path = cp + 1;
} while (cp != NULL);
free(path0);
return qualified ? strdup(qualified) : NULL;
}
static char **
build_command_info(const char *command)
{
char **command_info;
int i = 0;
/* Setup command info. */
command_info = calloc(32, sizeof(char *));
if (command_info == NULL)
goto oom;
if ((command_info[i] = sudo_new_key_val("command", command)) == NULL)
goto oom;
i++;
if (asprintf(&command_info[i], "runas_euid=%ld", (long)runas_uid) == -1)
goto oom;
i++;
if (asprintf(&command_info[i++], "runas_uid=%ld", (long)runas_uid) == -1)
goto oom;
i++;
if (runas_gid != (gid_t)-1) {
if (asprintf(&command_info[i++], "runas_gid=%ld", (long)runas_gid) ==
-1)
goto oom;
i++;
if (asprintf(&command_info[i++], "runas_egid=%ld", (long)runas_gid) ==
-1)
goto oom;
i++;
}
#ifdef USE_TIMEOUT
if ((command_info[i] = strdup("timeout=30")) == NULL)
goto oom;
i++;
#endif
if (use_sudoedit) {
if ((command_info[i] = strdup("sudoedit=true")) == NULL)
goto oom;
}
return command_info;
oom:
while (i > 0) {
free(command_info[i--]);
}
free(command_info);
return NULL;
}
static char *
find_editor(int nfiles, char *const files[], char **argv_out[])
{
char *cp, *last, **ep, **nargv, *editor_path;
char *editor = NULL;
int ac, i, nargc, wasblank;
/* Lookup EDITOR in user's environment. */
for (ep = plugin_state.envp; *ep != NULL; ep++) {
if (strncmp(*ep, "EDITOR=", 7) == 0) {
editor = *ep + 7;
break;
}
}
editor = strdup(editor ? editor : _PATH_VI);
if (editor == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "unable to allocate memory\n");
return NULL;
}
/*
* Split editor into an argument vector; editor is reused (do not free).
* The EDITOR environment variables may contain command
* line args so look for those and alloc space for them too.
*/
nargc = 1;
for (wasblank = 0, cp = editor; *cp != '\0'; cp++) {
if (isblank((unsigned char)*cp))
wasblank = 1;
else if (wasblank) {
wasblank = 0;
nargc++;
}
}
/* If we can't find the editor in the user's PATH, give up. */
cp = strtok_r(editor, " \t", &last);
if (cp == NULL ||
(editor_path = find_in_path(editor, plugin_state.envp)) == NULL) {
free(editor);
return NULL;
}
if (editor_path != editor)
free(editor);
nargv = reallocarray(
NULL, (size_t)nargc + 1 + (size_t)nfiles + 1, sizeof(char *));
if (nargv == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "unable to allocate memory\n");
free(editor_path);
return NULL;
}
for (ac = 0; cp != NULL && ac < nargc; ac++) {
nargv[ac] = cp;
cp = strtok_r(NULL, " \t", &last);
}
nargv[ac++] = (char *)"--";
for (i = 0; i < nfiles;)
nargv[ac++] = files[i++];
nargv[ac] = NULL;
*argv_out = nargv;
return editor_path;
}
static int
get_auth_from_socket(char *command)
{
struct sockaddr_un addr;
int ret;
int data_socket;
char write_buffer[WRITE_BUFFER_SIZE];
char read_buffer[READ_BUFFER_SIZE];
/* Create local socket. */
data_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (data_socket == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
ret = connect(data_socket, (const struct sockaddr *)&addr,
sizeof(struct sockaddr_un));
if (ret == -1) {
fprintf(stderr,
"The server is down. You can try to restart the realm_sudo "
"service from the host.\n");
exit(EXIT_FAILURE);
}
/* Send command passed to sudo through socket */
ret = write(data_socket, command, strlen(command) + 1);
if (ret == -1) {
perror("write");
exit(EXIT_FAILURE);
}
/* Receive auth result */
ret = read(data_socket, read_buffer, sizeof(read_buffer));
if (ret == -1) {
perror("read");
exit(EXIT_FAILURE);
}
/* Ensure buffer is 0-terminated. */
write_buffer[WRITE_BUFFER_SIZE - 1] = 0;
read_buffer[READ_BUFFER_SIZE - 1] = 0;
close(data_socket);
int auth_return = *read_buffer - '0';
return auth_return;
}
/*
* Plugin policy check function.
* Simple example that prompts for a password, hard-coded to "test".
*/
static int
policy_check(int argc, char *const argv[], char *env_add[],
char **command_info_out[], char **argv_out[], char **user_env_out[],
const char **errstr)
{
char *command;
// char *total_command = calloc(1024, sizeof(char));
size_t total_len = 0;
// count the args first so we calculate the buffer size
for (int i = 0; i < argc; i++) {
total_len += strlen(argv[i]);
}
total_len += argc;
char *total_command = malloc(total_len);
// setup counter for offset in building string
size_t idx = 0;
for (int i = 0; i < argc; i++) {
memcpy(total_command + idx, argv[i], strlen(argv[i]));
idx += strlen(argv[i]);
// add spaces between command options
if (i < argc - 1) {
total_command[idx] = ' ';
idx++;
}
}
// null terminate string
total_command[total_len - 1] = (char)0;
// printf("total_command = %s\n", total_command);
if (get_auth_from_socket(total_command))
return false;
free(total_command);
if (!argc || argv[0] == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "no command specified\n");
return false;
}
command = find_in_path(argv[0], plugin_state.envp);
if (command == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "%s: command not found\n", argv[0]);
return false;
}
/* If "sudo vi" is run, auto-convert to sudoedit. */
if (strcmp(command, _PATH_VI) == 0)
use_sudoedit = true;
if (use_sudoedit) {
/* Rebuild argv using editor */
free(command);
command = find_editor(argc - 1, argv + 1, argv_out);
if (command == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "unable to find valid editor\n");
return -1;
}
use_sudoedit = true;
} else {
/* No changes needed to argv */
*argv_out = (char **)argv;
}
/* No changes to envp */
*user_env_out = plugin_state.envp;
/* Setup command info. */
*command_info_out = build_command_info(command);
free(command);
if (*command_info_out == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG, "out of memory\n");
return -1;
}
return true;
}
static int
policy_list(int argc, char *const argv[], int verbose, const char *list_user,
const char **errstr)
{
/*
* List user's capabilities.
*/
sudo_log(SUDO_CONV_INFO_MSG, "Validated users may run any command\n");
return true;
}
static int
policy_version(int verbose)
{
sudo_log(SUDO_CONV_INFO_MSG,
"Citadel realms authentication sudo plugin version %s\n",
PACKAGE_VERSION);
return true;
}
static void
policy_close(int exit_status, int error)
{
/*
* The policy might log the command exit status here.
* In this example, we just print a message.
*/
if (exit_status == 0 && error != 0) {
sudo_log(SUDO_CONV_INFO_MSG,
"Authentication request denied from realms sudo plugin\n");
} else if (exit_status != 1) {
if (error) {
sudo_log(SUDO_CONV_ERROR_MSG, "Command error: %s\n",
strerror(error));
} else {
if (WIFSIGNALED(exit_status)) {
sudo_log(SUDO_CONV_INFO_MSG, "Command killed by signal %d\n",
WTERMSIG(exit_status));
}
}
}
}
sudo_dso_public struct policy_plugin sample_policy = {
SUDO_POLICY_PLUGIN, SUDO_API_VERSION, policy_open, policy_close,
policy_version, policy_check, policy_list, NULL, /* validate */
NULL, /* invalidate */
NULL, /* init_session */
NULL, /* register_hooks */
NULL, /* deregister_hooks */
NULL /* event_alloc() filled in by sudo */
};
/*
* Note: This plugin does not differentiate between tty and pipe I/O.
* It all gets logged to the same file.
*/
sudo_dso_public struct io_plugin sample_io = {
SUDO_IO_PLUGIN, SUDO_API_VERSION, NULL, /* register_hooks */
NULL, /* deregister_hooks */
NULL, /* change_winsize */
NULL, /* log_suspend */
NULL /* event_alloc() filled in by sudo */
};

View File

@@ -0,0 +1,2 @@
realm_sudo_auth_policy
realm_sudo_auth_io