From 767d861df4abe1de1ce4cde8ec58485b1a729c7d Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 2 Dec 2022 17:02:46 +0000 Subject: [PATCH] Add authtest Also, change the sesman Makefile generation to make it easy to pick the correct authorization module for the authtest utility. --- configure.ac | 19 +++ sesman/Makefile.am | 42 +++--- sesman/tools/Makefile.am | 11 ++ sesman/tools/authmod.c | 35 +++++ sesman/tools/authtest.c | 267 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 348 insertions(+), 26 deletions(-) create mode 100644 sesman/tools/authmod.c create mode 100644 sesman/tools/authtest.c diff --git a/configure.ac b/configure.ac index 96d98943..dfebca7a 100644 --- a/configure.ac +++ b/configure.ac @@ -325,25 +325,40 @@ AM_CONDITIONAL([USE_FREETYPE2], [test "x$use_freetype2" = xyes]) # Check only one auth mechanism is specified, and give it a name auth_cnt=0 auth_mech="Builtin" +AUTHMOD_SRC=verify_user.c +AUTHMOD_OBJ=verify_user.${OBJEXT} +AUTHMOD_LIB=-lcrypt if test x$enable_pam = xyes then auth_cnt=`expr $auth_cnt + 1` auth_mech="PAM" + AUTHMOD_SRC=verify_user_pam.c + AUTHMOD_OBJ=verify_user_pam.${OBJEXT} + AUTHMOD_LIB=-lpam fi if test x$bsd = xtrue then auth_cnt=`expr $auth_cnt + 1` auth_mech="BSD" + AUTHMOD_SRC=verify_user_bsd.c + AUTHMOD_OBJ=verify_user_bsd.${OBJEXT} + AUTHMOD_LIB= fi if test x$enable_kerberos = xyes then auth_cnt=`expr $auth_cnt + 1` auth_mech="Kerberos" + AUTHMOD_SRC=verify_user_kerberos.c + AUTHMOD_OBJ=verify_user_kerberos.${OBJEXT} + AUTHMOD_LIB=-lkrb5 fi if test x$enable_pamuserpass = xyes then auth_cnt=`expr $auth_cnt + 1` auth_mech="PAM userpass" + AUTHMOD_SRC=verify_user_pam_userpass.c + AUTHMOD_OBJ=verify_user_pam_userpass.${OBJEXT} + AUTHMOD_LIB="-lpam -lpam_userpass" fi if test $auth_cnt -gt 1 @@ -351,6 +366,10 @@ then AC_MSG_ERROR([--enable-pam, --enable-bsd, --enable-pamuserpass and --enable-kerberos are mutually exclusive]) fi +AC_SUBST([AUTHMOD_SRC]) +AC_SUBST([AUTHMOD_OBJ]) +AC_SUBST([AUTHMOD_LIB]) + # checking if pam should be autodetected. if test "x$enable_pam" = "xyes" then diff --git a/sesman/Makefile.am b/sesman/Makefile.am index 7d7052a5..78bb3d4d 100644 --- a/sesman/Makefile.am +++ b/sesman/Makefile.am @@ -12,29 +12,6 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common \ -I$(top_srcdir)/libipm -if SESMAN_BSD -AUTH_C = verify_user_bsd.c -AUTH_LIB = -else -if SESMAN_PAMUSERPASS -AUTH_C = verify_user_pam_userpass.c -AUTH_LIB = -lpam -lpam_userpass -else -if SESMAN_KERBEROS -AUTH_C = verify_user_kerberos.c -AUTH_LIB = -lkrb5 -else -if SESMAN_NOPAM -AUTH_C = verify_user.c -AUTH_LIB = -lcrypt -else -AUTH_C = verify_user_pam.c -AUTH_LIB = -lpam -endif -endif -endif -endif - sbin_PROGRAMS = \ xrdp-sesman @@ -57,13 +34,26 @@ xrdp_sesman_SOURCES = \ sig.c \ sig.h \ xauth.c \ - xauth.h \ - $(AUTH_C) + xauth.h +# Possible authentication modules +# See https://www.gnu.org/software/automake/manual/html_node/Conditional-Sources.html +EXTRA_xrdp_sesman_SOURCES = \ + verify_user.c \ + verify_user_bsd.c \ + verify_user_kerberos.c \ + verify_user_pam.c \ + verify_user_pam_userpass.c + +# Make sure the right authentication module is pulled in +xrdp_sesman_DEPENDENCIES = $(AUTHMOD_OBJ) + +# Make sure the right authentication module is linked with xrdp_sesman_LDADD = \ + $(AUTHMOD_OBJ) \ $(top_builddir)/libipm/libipm.la \ $(top_builddir)/common/libcommon.la \ - $(AUTH_LIB) \ + $(AUTHMOD_LIB) \ -lpthread sesmansysconfdir=$(sysconfdir)/xrdp diff --git a/sesman/tools/Makefile.am b/sesman/tools/Makefile.am index a113a4f4..8e811d75 100644 --- a/sesman/tools/Makefile.am +++ b/sesman/tools/Makefile.am @@ -1,9 +1,11 @@ AM_CPPFLAGS = \ + -DXRDP_SYSCONF_PATH=\"${sysconfdir}\" \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ -DXRDP_SOCKET_PATH=\"${socketdir}\" \ + -DXRDP_AUTHMOD_SRC=\"../${AUTHMOD_SRC}\" \ -I$(top_srcdir)/common \ -I$(top_srcdir)/libipm \ -I$(top_srcdir)/sesman @@ -16,6 +18,7 @@ bin_PROGRAMS = \ xrdp-dis noinst_PROGRAMS = \ + xrdp-authtest \ xrdp-xcon xrdp_sesrun_SOURCES = \ @@ -38,6 +41,10 @@ xrdp_dis_LDADD = \ xrdp_xcon_SOURCES = \ xcon.c +xrdp_authtest_SOURCES = \ + authmod.c \ + authtest.c + xrdp_sesrun_LDADD = \ $(top_builddir)/common/libcommon.la \ $(top_builddir)/libipm/libipm.la @@ -51,3 +58,7 @@ xrdp_xcon_LDFLAGS = \ xrdp_xcon_LDADD = \ $(X_PRE_LIBS) -lX11 $(X_EXTRA_LIBS) + +xrdp_authtest_LDADD = \ + $(top_builddir)/common/libcommon.la \ + $(AUTHMOD_LIB) diff --git a/sesman/tools/authmod.c b/sesman/tools/authmod.c new file mode 100644 index 00000000..144d923f --- /dev/null +++ b/sesman/tools/authmod.c @@ -0,0 +1,35 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * @file authmod.c + * + * @brief Pull in the configured authentication module + * + * Configured auth module is referenced by the macro define + * XRDP_AUTHMOD_SRC, defined by the configure system + * + * @author Matt Burt + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include XRDP_AUTHMOD_SRC diff --git a/sesman/tools/authtest.c b/sesman/tools/authtest.c new file mode 100644 index 00000000..93e151c6 --- /dev/null +++ b/sesman/tools/authtest.c @@ -0,0 +1,267 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * @file authtest.c + * @brief An utility to test the compiled-in authentication module + * @author Matt Burt + * + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include + +#include "log.h" +#include "auth.h" +#include "os_calls.h" +#include "string_calls.h" + +#if !defined(PACKAGE_VERSION) +#define PACKAGE_VERSION "???" +#endif + +#ifndef MAX_PASSWORD_LEN +# define MAX_PASSWORD_LEN 512 +#endif + +/** + * Parameters needed to call the auth module + */ +struct authmod_params +{ + const char *username; + char password[MAX_PASSWORD_LEN + 1]; + const char *command; + int start_session; +}; + + +/**************************************************************************//** + * Prints a brief summary of options and defaults + */ +static void +usage(void) +{ + g_printf("xrdp auth module tester v" PACKAGE_VERSION "\n"); + g_printf("\n" + "Calls functions in the compiled-in auth module, so that the\n" + "module can be checked simply for functionality, memory leaks,\n" + "etc.\n\n" + "This is a DEVELOPER-ONLY tool\n"); + g_printf("\nusage:\n"); + g_printf("authtest [options] username\n\n"); + g_printf("options:\n"); + g_printf(" -p \n" + " -F Read password from this file descriptor\n" + " -c Start a session and run the\n" + " specified non-interactive command\n" + " in it\n"); + g_printf("Password is prompted if -p or -F are not specified\n"); +} + + +/**************************************************************************//** + * Read a password from a file descriptor + * + * @param fd_str string representing file descriptor + * @param sp Authmod parameter structure for resulting password + * @return !=0 for success + */ +static int +read_password_from_fd(const char *fd_str, struct authmod_params *amp) +{ + int result = 0; + int s = g_file_read(atoi(fd_str), amp->password, + sizeof (amp->password) - 1); + if (s < 0) + { + LOG(LOG_LEVEL_ERROR, "Can't read password from fd %s - %s", + fd_str, g_get_strerror()); + amp->password[0] = '\0'; + } + else + { + amp->password[s] = '\0'; + if (s > 0 && amp->password[s - 1] == '\n') + { + amp->password[s - 1] = '\0'; + } + result = 1; + } + return result; +} + +/**************************************************************************//** + * Parses the program args + * + * @param argc Passed to main + * @param @argv Passed to main + * @param amp Authmod parameter structure for resulting values + * @return !=0 for success + */ +static int +parse_program_args(int argc, char *argv[], struct authmod_params *amp) +{ + int params_ok = 1; + int opt; + bool_t password_set = 0; + + amp->username = NULL; + amp->password[0] = '\0'; + amp->start_session = 0; + amp->command = NULL; + + while ((opt = getopt(argc, argv, "c:p:F:")) != -1) + { + switch (opt) + { + case 'c': + if (amp->command) + { + LOG(LOG_LEVEL_WARNING, "Ignoring multiple '%c' options", + (char)opt); + } + else + { + amp->command = optarg; + } + break; + + case 'p': + if (password_set) + { + LOG(LOG_LEVEL_WARNING, + "Ignoring option '%c' - password already set ", + (char)opt); + } + else + { + g_strncpy(amp->password, optarg, sizeof(amp->password) - 1); + password_set = 1; + } + break; + + case 'F': + if (password_set) + { + LOG(LOG_LEVEL_WARNING, + "Ignoring option '%c' - password already set ", + (char)opt); + } + else + { + if (read_password_from_fd(optarg, amp)) + { + password_set = 1; + } + else + { + params_ok = 0; + } + } + break; + + default: + LOG(LOG_LEVEL_ERROR, "Unrecognised switch '%c'", (char)opt); + params_ok = 0; + } + } + + if (argc <= optind) + { + LOG(LOG_LEVEL_ERROR, "No user name specified"); + params_ok = 0; + } + else if ((argc - optind) > 1) + { + LOG(LOG_LEVEL_ERROR, "Unexpected arguments after username"); + params_ok = 0; + } + else + { + amp->username = argv[optind]; + } + + if (params_ok && !password_set) + { + const char *p = getpass("Password: "); + if (p != NULL) + { + g_strcpy(amp->password, p); + } + } + + return params_ok; +} + +/******************************************************************************/ +int +main(int argc, char **argv) +{ + struct log_config *logging; + int rv = 1; + struct authmod_params amp; + + logging = log_config_init_for_console(LOG_LEVEL_DEBUG, + g_getenv("AUTHTEST_LOG_LEVEL")); + log_start_from_param(logging); + log_config_free(logging); + + if (!parse_program_args(argc, argv, &)) + { + usage(); + } + else + { + struct auth_info *auth_info; + auth_info = auth_userpass(amp.username, amp.password, + NULL, &rv); + + LOG(LOG_LEVEL_INFO, "auth_userpass() returned %s, errorcode=%d", + (auth_info == NULL) ? "NULL" : "non-NULL", + rv); + if (auth_info && rv == 0 && amp.command != NULL) + { + int display = 10; + rv = auth_start_session(auth_info, display); + LOG(LOG_LEVEL_INFO, "auth_start_session(,%d) returned %d", + display, rv); + if (rv == 0) + { + rv = g_system(amp.command); + LOG(LOG_LEVEL_INFO, "command \"%s\" returned %d", + amp.command, rv); + auth_stop_session(auth_info); + } + } + if (auth_info != NULL) + { + int rv2 = auth_end(auth_info); + LOG(LOG_LEVEL_INFO, "auth_end() returned %d", rv2); + rv = (rv == 0) ? rv2 : rv; + } + } + + log_end(); + + return rv; +}