Merge pull request #2453 from matt335672/update_kerberos
Fix the kerberos module
This commit is contained in:
commit
a4fb635a5d
@ -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;
|
||||
|
@ -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[]);
|
||||
|
19
configure.ac
19
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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
35
sesman/tools/authmod.c
Normal file
35
sesman/tools/authmod.c
Normal file
@ -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 <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include XRDP_AUTHMOD_SRC
|
267
sesman/tools/authtest.c
Normal file
267
sesman/tools/authtest.c
Normal file
@ -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 <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#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 <password>\n"
|
||||
" -F <file-descriptor> Read password from this file descriptor\n"
|
||||
" -c <command> 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;
|
||||
}
|
@ -32,379 +32,149 @@
|
||||
#include "auth.h"
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <krb5.h>
|
||||
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user