From df83fbf9bfdc5edbb3bd7f2f82335db399794f7e Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 8 Dec 2022 16:23:35 +0000 Subject: [PATCH 1/3] Fix const-correctness for g_system() --- common/os_calls.c | 2 +- common/os_calls.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/os_calls.c b/common/os_calls.c index 91646423..095359c1 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -2565,7 +2565,7 @@ g_get_proc_address(long lib, const char *name) /*****************************************************************************/ /* does not work in win32 */ int -g_system(char *aexec) +g_system(const char *aexec) { #if defined(_WIN32) return 0; diff --git a/common/os_calls.h b/common/os_calls.h index eb54aff3..df24cd69 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -162,7 +162,7 @@ int g_file_get_inode_num(const char *filename); long g_load_library(char *in); int g_free_library(long lib); void *g_get_proc_address(long lib, const char *name); -int g_system(char *aexec); +int g_system(const char *aexec); char *g_get_strerror(void); int g_get_errno(void); int g_execvp(const char *p1, char *args[]); 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 2/3] 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; +} From a6714225e68099e9bacbff47e9da2b19dded4f22 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 2 Dec 2022 16:30:53 +0000 Subject: [PATCH 3/3] Changes to verify_user_kerberos.c --- sesman/verify_user_kerberos.c | 468 ++++++++-------------------------- 1 file changed, 111 insertions(+), 357 deletions(-) diff --git a/sesman/verify_user_kerberos.c b/sesman/verify_user_kerberos.c index 77c9030d..514bc11c 100644 --- a/sesman/verify_user_kerberos.c +++ b/sesman/verify_user_kerberos.c @@ -32,379 +32,149 @@ #include "auth.h" #include "os_calls.h" #include "string_calls.h" +#include "log.h" #include -typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type; - -struct k_opts -{ - /* in seconds */ - krb5_deltat starttime; - krb5_deltat lifetime; - krb5_deltat rlife; - - int forwardable; - int proxiable; - int addresses; - - int not_forwardable; - int not_proxiable; - int no_addresses; - - int verbose; - - char *principal_name; - char *service_name; - char *keytab_name; - char *k5_cache_name; - char *k4_cache_name; - - action_type action; -}; - -struct k5_data +struct auth_info { krb5_context ctx; krb5_ccache cc; krb5_principal me; - char *name; -}; - -struct user_info -{ - const char *name; - const char *pass; -}; - -/* - * Need a complete type for struct auth_info, even though we're - * not really using it if this module (Kerberos authentication) is selected */ -struct auth_info -{ - char dummy; }; /******************************************************************************/ -/* returns boolean */ -static int -k5_begin(struct k_opts *opts, struct k5_data *k5, struct user_info *u_info) -{ - krb5_error_code code = 0; - - code = krb5_init_context(&k5->ctx); - - if (code != 0) - { - g_printf("krb5_init_context failed in k5_begin\n"); - return 0; - } - - if (opts->k5_cache_name) - { - code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc); - - if (code != 0) - { - g_printf("krb5_cc_resolve failed in k5_begin\n"); - return 0; - } - } - else - { - code = krb5_cc_default(k5->ctx, &k5->cc); - - if (code != 0) - { - g_printf("krb5_cc_default failed in k5_begin\n"); - return 0; - } - } - - if (opts->principal_name) - { - /* Use specified name */ - code = krb5_parse_name(k5->ctx, opts->principal_name, &k5->me); - - if (code != 0) - { - g_printf("krb5_parse_name failed in k5_begin\n"); - return 0; - } - } - else - { - /* No principal name specified */ - if (opts->action == INIT_KT) - { - /* Use the default host/service name */ - code = krb5_sname_to_principal(k5->ctx, NULL, NULL, - KRB5_NT_SRV_HST, &k5->me); - - if (code != 0) - { - g_printf("krb5_sname_to_principal failed in k5_begin\n"); - return 0; - } - } - else - { - /* Get default principal from cache if one exists */ - code = krb5_cc_get_principal(k5->ctx, k5->cc, &k5->me); - - if (code != 0) - { - code = krb5_parse_name(k5->ctx, u_info->name, &k5->me); - - if (code != 0) - { - g_printf("krb5_parse_name failed in k5_begin\n"); - return 0; - } - } - } - } - - code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); - - if (code != 0) - { - g_printf("krb5_unparse_name failed in k5_begin\n"); - return 0; - } - - opts->principal_name = k5->name; - return 1; -} - -/******************************************************************************/ +/* Logs a kerberos error code */ static void -k5_end(struct k5_data *k5) +log_kerberos_failure(krb5_context ctx, krb5_error_code code, const char *where) { - if (k5->name) - { - krb5_free_unparsed_name(k5->ctx, k5->name); - } - - if (k5->me) - { - krb5_free_principal(k5->ctx, k5->me); - } - - if (k5->cc) - { - krb5_cc_close(k5->ctx, k5->cc); - } - - if (k5->ctx) - { - krb5_free_context(k5->ctx); - } - - g_memset(k5, 0, sizeof(struct k5_data)); + const char *errstr = krb5_get_error_message(ctx, code); + LOG(LOG_LEVEL_ERROR, "Kerberos call to %s failed [%s]", where, errstr); + krb5_free_error_message(ctx, errstr); } /******************************************************************************/ -static krb5_error_code KRB5_CALLCONV -kinit_prompter(krb5_context ctx, void *data, const char *name, - const char *banner, int num_prompts, krb5_prompt prompts[]) +int +auth_end(struct auth_info *auth_info) { - int i; - krb5_prompt_type *types; - krb5_error_code rc; - struct user_info *u_info; - - u_info = (struct user_info *)data; - rc = 0; - types = krb5_get_prompt_types(ctx); - - for (i = 0; i < num_prompts; i++) + if (auth_info != NULL) { - if (types[i] == KRB5_PROMPT_TYPE_PASSWORD || - types[i] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) + if (auth_info->me) { - g_strncpy(prompts[i].reply->data, u_info->pass, 255); + krb5_free_principal(auth_info->ctx, auth_info->me); } + + if (auth_info->cc) + { + krb5_cc_close(auth_info->ctx, auth_info->cc); + } + + if (auth_info->ctx) + { + krb5_free_context(auth_info->ctx); + } + + g_memset(auth_info, 0, sizeof(*auth_info)); + g_free(auth_info); + } + return 0; +} + +/******************************************************************************/ +/* Checks Kerberos can be used + * + * If all is well, an auth_info struct is returned */ +static struct auth_info * +k5_begin(const char *username) +{ + int ok = 0; + struct auth_info *auth_info = g_new0(struct auth_info, 1); + krb5_error_code code; + + if (auth_info == NULL) + { + LOG(LOG_LEVEL_ERROR, "Out of memory in k5_begin()"); + } + else if ((code = krb5_init_context(&auth_info->ctx)) != 0) + { + LOG(LOG_LEVEL_ERROR, "Can't init Kerberos context"); + } + /* Determine the credentials cache to use */ + else if ((code = krb5_cc_default(auth_info->ctx, &auth_info->cc)) != 0) + { + log_kerberos_failure(auth_info->ctx, code, "krb5_cc_default"); + } + /* Parse the username into a full principal */ + else if ((code = krb5_parse_name(auth_info->ctx, + username, &auth_info->me)) != 0) + { + log_kerberos_failure(auth_info->ctx, code, "krb5_parse_name"); + } + else + { + ok = 1; } - return rc; + if (!ok) + { + auth_end(auth_info); + auth_info = NULL; + } + + return auth_info; } + /******************************************************************************/ /* returns boolean */ static int -k5_kinit(struct k_opts *opts, struct k5_data *k5, struct user_info *u_info) +k5_kinit(struct auth_info *auth_info, const char *password) { - const char *doing; - int notix = 1; - krb5_keytab keytab = 0; krb5_creds my_creds; krb5_error_code code = 0; - krb5_get_init_creds_opt options; - krb5_address **addresses; - - krb5_get_init_creds_opt_init(&options); - g_memset(&my_creds, 0, sizeof(my_creds)); - - /* - From this point on, we can goto cleanup because my_creds is - initialized. - */ - if (opts->lifetime) - { - krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime); - } - - if (opts->rlife) - { - krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife); - } - - if (opts->forwardable) - { - krb5_get_init_creds_opt_set_forwardable(&options, 1); - } - - if (opts->not_forwardable) - { - krb5_get_init_creds_opt_set_forwardable(&options, 0); - } - - if (opts->proxiable) - { - krb5_get_init_creds_opt_set_proxiable(&options, 1); - } - - if (opts->not_proxiable) - { - krb5_get_init_creds_opt_set_proxiable(&options, 0); - } - - if (opts->addresses) - { - addresses = NULL; - code = krb5_os_localaddr(k5->ctx, &addresses); - - if (code != 0) - { - g_printf("krb5_os_localaddr failed in k5_kinit\n"); - goto cleanup; - } - - krb5_get_init_creds_opt_set_address_list(&options, addresses); - } - - if (opts->no_addresses) - { - krb5_get_init_creds_opt_set_address_list(&options, NULL); - } - - if ((opts->action == INIT_KT) && opts->keytab_name) - { - code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab); - - if (code != 0) - { - g_printf("krb5_kt_resolve failed in k5_kinit\n"); - goto cleanup; - } - } - - switch (opts->action) - { - case INIT_PW: - code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, - 0, kinit_prompter, u_info, - opts->starttime, - opts->service_name, - &options); - break; - case INIT_KT: - code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, - keytab, - opts->starttime, - opts->service_name, - &options); - break; - case VALIDATE: - code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc, - opts->service_name); - break; - case RENEW: - code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc, - opts->service_name); - break; - } + int rv = 0; + code = krb5_get_init_creds_password(auth_info->ctx, + &my_creds, auth_info->me, + password, NULL, NULL, + 0, + NULL, + NULL); if (code != 0) { - doing = 0; - - switch (opts->action) + log_kerberos_failure(auth_info->ctx, code, + "krb5_get_init_creds_password"); + } + else + { + /* + * Try to store the creds in the credentials cache + */ + if ((code = krb5_cc_initialize(auth_info->ctx, auth_info->cc, + auth_info->me)) != 0) { - case INIT_PW: - case INIT_KT: - doing = "getting initial credentials"; - break; - case VALIDATE: - doing = "validating credentials"; - break; - case RENEW: - doing = "renewing credentials"; - break; + log_kerberos_failure(auth_info->ctx, code, "krb5_cc_initialize"); } - - if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) + else if ((code = krb5_cc_store_cred(auth_info->ctx, auth_info->cc, + &my_creds)) != 0) { - g_printf("sesman: Password incorrect while %s in k5_kinit\n", doing); + log_kerberos_failure(auth_info->ctx, code, "krb5_cc_store_cred"); } else { - g_printf("sesman: error while %s in k5_kinit\n", doing); + rv = 1; } - goto cleanup; + /* Prevent double-free of the client principal */ + if (my_creds.client == auth_info->me) + { + my_creds.client = NULL; + } + + krb5_free_cred_contents(auth_info->ctx, &my_creds); } - if (!opts->lifetime) - { - /* We need to figure out what lifetime to use for Kerberos 4. */ - opts->lifetime = my_creds.times.endtime - my_creds.times.authtime; - } - - code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me); - - if (code != 0) - { - g_printf("krb5_cc_initialize failed in k5_kinit\n"); - goto cleanup; - } - - code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds); - - if (code != 0) - { - g_printf("krb5_cc_store_cred failed in k5_kinit\n"); - goto cleanup; - } - - notix = 0; - -cleanup: - - if (my_creds.client == k5->me) - { - my_creds.client = 0; - } - - krb5_free_cred_contents(k5->ctx, &my_creds); - - if (keytab) - { - krb5_kt_close(k5->ctx, keytab); - } - - return notix ? 0 : 1; + return rv; } /******************************************************************************/ @@ -413,29 +183,20 @@ struct auth_info * auth_userpass(const char *user, const char *pass, const char *client_ip, int *errorcode) { - struct k_opts opts; - struct k5_data k5; - struct user_info u_info; - int got_k5; - /* Need a non-NULL pointer to return to indicate success */ - static struct auth_info success = {0}; - struct auth_info *auth_info = NULL; + struct auth_info *auth_info = k5_begin(user); - g_memset(&opts, 0, sizeof(opts)); - opts.action = INIT_PW; - g_memset(&k5, 0, sizeof(k5)); - g_memset(&u_info, 0, sizeof(u_info)); - u_info.name = user; - u_info.pass = pass; - got_k5 = k5_begin(&opts, &k5, &u_info); - - if (got_k5) + if (auth_info) { - if (k5_kinit(&opts, &k5, &u_info)) + if (!k5_kinit(auth_info, pass)) { - auth_info = &success; + auth_end(auth_info); + auth_info = NULL; } - k5_end(&k5); + } + + if (errorcode != NULL) + { + *errorcode = (auth_info == NULL); } return auth_info; @@ -457,13 +218,6 @@ auth_stop_session(struct auth_info *auth_info) return 0; } -/******************************************************************************/ -int -auth_end(struct auth_info *auth_info) -{ - return 0; -} - /******************************************************************************/ int auth_set_env(struct auth_info *auth_info)