include\Makefile \
lib\Makefile lib\crypto\Makefile \
lib\crypto\krb\crc32\Makefile lib\crypto\builtin\des\Makefile \
- lib\crypto\krb\dk\Makefile lib\crypto\krb\enc_provider\Makefile \
+ lib\crypto\krb\dk\Makefile lib\crypto\builtin\enc_provider\Makefile \
lib\crypto\krb\hash_provider\Makefile \
lib\crypto\krb\keyhash_provider\Makefile \
lib\crypto\krb\raw\Makefile lib\crypto\old\Makefile \
##DOS## $(WCONFIG) config < $@.in > $@
##DOS##lib\crypto\krb\dk\Makefile: lib\crypto\krb\dk\Makefile.in $(MKFDEP)
##DOS## $(WCONFIG) config < $@.in > $@
-##DOS##lib\crypto\krb\enc_provider\Makefile: lib\crypto\krb\enc_provider\Makefile.in $(MKFDEP)
+##DOS##lib\crypto\builtin\enc_provider\Makefile: lib\crypto\builtin\enc_provider\Makefile.in $(MKFDEP)
##DOS## $(WCONFIG) config < $@.in > $@
##DOS##lib\crypto\krb\hash_provider\Makefile: lib\crypto\krb\hash_provider\Makefile.in $(MKFDEP)
##DOS## $(WCONFIG) config < $@.in > $@
config/* include/* include/kerberosIV/* \
include/krb5/* include/krb5/stock/* include/sys/* lib/* \
lib/crypto/* lib/crypto/krb/crc32/* lib/crypto/builtin/des/* lib/crypto/krb/dk/* \
- lib/crypto/krb/enc_provider/* lib/crypto/krb/hash_provider/* \
+ lib/crypto/builtin/enc_provider/* lib/crypto/krb/hash_provider/* \
lib/crypto/krb/keyhash_provider/* lib/crypto/krb/old/* lib/crypto/krb/raw/* \
lib/crypto/builtin/sha1/* lib/crypto/builtin/arcfour/* lib/crypto/builtin/md4/* \
lib/crypto/builtin/md5/* lib/crypto/krb/yarrow/* \
[\fB\-f\fP | \fB\-F\fP]
[\fB\-a\fP]
[\fB\-A\fP]
+[\fB\-C\fP]
+[\fB\-E\fP]
[\fB\-v\fP] [\fB\-R\fP]
[\fB\-k\fP [\fB\-t\fP \fIkeytab_file\fP]] [\fB\-c\fP \fIcache_name\fP]
-[\fB\-S\fP \fIservice_name\fP][\fB\-T\fP \fIarmor_ccache\fP]
+[\fB\-S\fP \fIservice_name\fP][\fB\-T\fP \fIarmor_ccache\fP]
[\fB\-X\fP \fIattribute\fP[=\fIvalue\fP]]
[\fIprincipal\fP]
.ad b
.B \-A
request address-less tickets.
.TP
+.B \-C
+requests canonicalization of the principal name.
+.TP
+.B \-E
+treats the principal name as an enterprise name.
+.TP
.B \-v
requests that the ticket granting ticket in the cache (with the
.I invalid
/*
** change the password -
*/
- fprintf( stderr, "the password is %s\n", new_password );
-
{
int pw_result;
krb5_ccache ccache;
.B \-h
prints a usage statement and exits
.TP
+.B \-P
+specifies that the
+.B service1 service2 ...
+arguments are to be treated as services for which credentials should
+be acquired using constrained delegation. This option is only valid
+when used in conjunction with protocol transition.
+.TP
.B \-S sname
specifies that krb5_sname_to_principal() will be used to build
principal names. If this flag is specified, the
and
.B sname
is interpreted as the service name.
+.TP
+.B \-U for_user
+specifies that protocol transition (S4U2Self) is to be used to acquire
+a ticket on behalf of
+.B for_user.
+If constrained delegation is not requested, the service name
+must match the credentials cache client principal.
.SH ENVIRONMENT
.B Kvno
uses the following environment variable:
static void xusage()
{
- fprintf(stderr, "usage: %s [-C] [-u] [-c ccache] [-e etype] [-k keytab] [-S sname] service1 service2 ...\n",
- prog);
+ fprintf(stderr, "usage: %s [-C] [-u] [-c ccache] [-e etype]\n", prog);
+ fprintf(stderr, "\t[-k keytab] [-S sname] [-U for_user [-P]]\n");
+ fprintf(stderr, "\tservice1 service2 ...\n");
exit(1);
}
static void do_v5_kvno (int argc, char *argv[],
char *ccachestr, char *etypestr, char *keytab_name,
- char *sname, int canon, int unknown);
+ char *sname, int canon, int unknown,
+ char *for_user, int proxy);
#include <com_err.h>
static void extended_com_err_fn (const char *, errcode_t, const char *,
{
int option;
char *etypestr = NULL, *ccachestr = NULL, *keytab_name = NULL;
- char *sname = NULL;
- int canon = 0, unknown = 0;
+ char *sname = NULL, *for_user = NULL;
+ int canon = 0, unknown = 0, proxy = 0;
set_com_err_hook (extended_com_err_fn);
prog = strrchr(argv[0], '/');
prog = prog ? (prog + 1) : argv[0];
- while ((option = getopt(argc, argv, "uCc:e:hk:qS:")) != -1) {
+ while ((option = getopt(argc, argv, "uCc:e:hk:qPS:U:")) != -1) {
switch (option) {
case 'C':
canon = 1;
case 'q':
quiet = 1;
break;
+ case 'P':
+ proxy = 1; /* S4U2Proxy - constrained delegation */
+ break;
case 'S':
sname = optarg;
if (unknown == 1){
xusage();
}
break;
+ case 'U':
+ for_user = optarg; /* S4U2Self - protocol transition */
+ break;
default:
xusage();
break;
}
}
+ if (proxy) {
+ if (keytab_name == NULL) {
+ fprintf(stderr, "Option -P (constrained delegation) "
+ "requires keytab to be specified\n");
+ xusage();
+ } else if (for_user == NULL) {
+ fprintf(stderr, "Option -P (constrained delegation) requires "
+ "option -U (protocol transition)\n");
+ xusage();
+ }
+ }
+
if ((argc - optind) < 1)
xusage();
do_v5_kvno(argc - optind, argv + optind,
- ccachestr, etypestr, keytab_name, sname, canon, unknown);
+ ccachestr, etypestr, keytab_name, sname,
+ canon, unknown, for_user, proxy);
return 0;
}
-#include <krb5.h>
+#include <k5-int.h>
static krb5_context context;
static void extended_com_err_fn (const char *myprog, errcode_t code,
const char *fmt, va_list args)
static void do_v5_kvno (int count, char *names[],
char * ccachestr, char *etypestr, char *keytab_name,
- char *sname, int canon, int unknown)
+ char *sname, int canon, int unknown, char *for_user,
+ int proxy)
{
krb5_error_code ret;
int i, errors;
krb5_enctype etype;
krb5_ccache ccache;
krb5_principal me;
- krb5_creds in_creds, *out_creds;
- krb5_ticket *ticket;
- char *princ;
+ krb5_creds in_creds;
krb5_keytab keytab = NULL;
+ krb5_principal for_user_princ = NULL;
+ krb5_flags options;
ret = krb5_init_context(&context);
if (ret) {
}
}
+ if (for_user) {
+ ret = krb5_parse_name_flags(context, for_user,
+ KRB5_PRINCIPAL_PARSE_ENTERPRISE,
+ &for_user_princ);
+ if (ret) {
+ com_err(prog, ret, "while parsing principal name %s", for_user);
+ exit(1);
+ }
+ }
+
ret = krb5_cc_get_principal(context, ccache, &me);
if (ret) {
com_err(prog, ret, "while getting client principal name");
errors = 0;
+ options = 0;
+ if (canon)
+ options |= KRB5_GC_CANONICALIZE;
+
for (i = 0; i < count; i++) {
- memset(&in_creds, 0, sizeof(in_creds));
+ krb5_principal server = NULL;
+ krb5_ticket *ticket = NULL;
+ krb5_creds *out_creds = NULL;
+ char *princ = NULL;
- in_creds.client = me;
+ memset(&in_creds, 0, sizeof(in_creds));
if (sname != NULL) {
ret = krb5_sname_to_principal(context, names[i],
sname, KRB5_NT_SRV_HST,
- &in_creds.server);
+ &server);
} else {
- ret = krb5_parse_name(context, names[i], &in_creds.server);
+ ret = krb5_parse_name(context, names[i], &server);
}
if (ret) {
if (!quiet)
com_err(prog, ret, "while parsing principal name %s", names[i]);
- errors++;
- continue;
+ goto error;
}
if (unknown == 1) {
- krb5_princ_type(context, in_creds.server) = KRB5_NT_UNKNOWN;
+ krb5_princ_type(context, server) = KRB5_NT_UNKNOWN;
}
- ret = krb5_unparse_name(context, in_creds.server, &princ);
+ ret = krb5_unparse_name(context, server, &princ);
if (ret) {
com_err(prog, ret,
"while formatting parsed principal name for '%s'",
names[i]);
- errors++;
- continue;
+ goto error;
}
in_creds.keyblock.enctype = etype;
- ret = krb5_get_credentials(context, canon ? KRB5_GC_CANONICALIZE : 0,
- ccache, &in_creds, &out_creds);
+ if (for_user) {
+ if (!proxy &&
+ !krb5_principal_compare(context, me, server)) {
+ com_err(prog, EINVAL,
+ "client and server principal names must match");
+ goto error;
+ }
- krb5_free_principal(context, in_creds.server);
+ in_creds.client = for_user_princ;
+ in_creds.server = me;
+
+ ret = krb5_get_credentials_for_user(context, options, ccache,
+ &in_creds, NULL, &out_creds);
+ } else {
+ in_creds.client = me;
+ in_creds.server = server;
+ ret = krb5_get_credentials(context, options, ccache,
+ &in_creds, &out_creds);
+ }
if (ret) {
com_err(prog, ret, "while getting credentials for %s", princ);
-
- krb5_free_unparsed_name(context, princ);
-
- errors++;
- continue;
+ goto error;
}
/* we need a native ticket */
ret = krb5_decode_ticket(&out_creds->ticket, &ticket);
if (ret) {
com_err(prog, ret, "while decoding ticket for %s", princ);
- krb5_free_creds(context, out_creds);
- krb5_free_unparsed_name(context, princ);
-
- errors++;
- continue;
+ goto error;
}
-
+
if (keytab) {
ret = krb5_server_decrypt_ticket_keytab(context, keytab, ticket);
if (ret) {
- if (!quiet)
- printf("%s: kvno = %d, keytab entry invalid", princ, ticket->enc_part.kvno);
+ if (!quiet) {
+ fprintf(stderr, "%s: kvno = %d, keytab entry invalid\n",
+ princ, ticket->enc_part.kvno);
+ }
com_err(prog, ret, "while decrypting ticket for %s", princ);
- krb5_free_ticket(context, ticket);
- krb5_free_creds(context, out_creds);
- krb5_free_unparsed_name(context, princ);
-
- errors++;
- continue;
+ goto error;
}
if (!quiet)
- printf("%s: kvno = %d, keytab entry valid\n", princ, ticket->enc_part.kvno);
+ printf("%s: kvno = %d, keytab entry valid\n",
+ princ, ticket->enc_part.kvno);
+ if (proxy) {
+ krb5_free_creds(context, out_creds);
+ out_creds = NULL;
+
+ in_creds.client = ticket->enc_part2->client;
+ in_creds.server = server;
+
+ ret = krb5_get_credentials_for_proxy(context,
+ KRB5_GC_CANONICALIZE,
+ ccache,
+ &in_creds,
+ ticket,
+ &out_creds);
+ if (ret) {
+ com_err(prog, ret,
+ "%s: constrained delegation failed", princ);
+ goto error;
+ }
+ }
} else {
if (!quiet)
printf("%s: kvno = %d\n", princ, ticket->enc_part.kvno);
}
- krb5_free_creds(context, out_creds);
- krb5_free_unparsed_name(context, princ);
+ continue;
+
+error:
+ if (server != NULL)
+ krb5_free_principal(context, server);
+ if (ticket != NULL)
+ krb5_free_ticket(context, ticket);
+ if (out_creds != NULL)
+ krb5_free_creds(context, out_creds);
+ if (princ != NULL)
+ krb5_free_unparsed_name(context, princ);
+ errors++;
}
if (keytab)
krb5_kt_close(context, keytab);
krb5_free_principal(context, me);
+ krb5_free_principal(context, for_user_princ);
krb5_cc_close(context, ccache);
krb5_free_context(context);
K5_AC_INIT([aclocal.m4])
-dnl
-dnl autoconf 2.49 defaults to a /dev/null cache file, which is what we
-dnl do not want for performance reasons.
+#
+# autoconf 2.49 defaults to a /dev/null cache file, which is what we
+# do not want for performance reasons.
if test "x$cache_file" = "x/dev/null"; then
cache_file=./config.cache
AC_CACHE_LOAD
fi
-dnl
+
CONFIG_RULES
KRB5_VERSION=K5_VERSION
AC_SUBST(KRB5_VERSION)
-dnl
-dnl
+
+
AC_REQUIRE_CPP
-dnl
+
AC_CACHE_CHECK(if va_copy is available, krb5_cv_va_copy,
[AC_LINK_IFELSE([
#include <stdarg.h>
if test "$krb5_cv_va_copy" = yes; then
AC_DEFINE(HAS_VA_COPY,1,[Define if va_copy macro or function is available.])
fi
-dnl
-dnl Note that this isn't checking if the copied value *works*, just
-dnl whether the C language constraints permit the copying. If
-dnl va_list is defined as an array type, it can't be assigned.
+
+# Note that this isn't checking if the copied value *works*, just
+# whether the C language constraints permit the copying. If
+# va_list is defined as an array type, it can't be assigned.
AC_CACHE_CHECK(if va_list objects can be copied by assignment,
krb5_cv_va_simple_copy,
[AC_COMPILE_IFELSE([
if test "$krb5_cv_va_simple_copy" = yes; then
AC_DEFINE(CAN_COPY_VA_LIST,1,[Define if va_list objects can be simply copied by assignment.])
fi
-dnl
-dnl The following lines are so that configure --help gives some global
-dnl configuration options.
-dnl
+
+# The following lines are so that configure --help gives some global
+# configuration options.
+
KRB5_LIB_AUX
AC_KRB5_TCL
AC_ARG_ENABLE([athena],
[ --enable-athena build with MIT Project Athena configuration],,)
-dnl
-dnl Begin autoconf tests for the Makefiles generated out of the top-level
-dnl configure.in...
-dnl
+
+# Begin autoconf tests for the Makefiles generated out of the top-level
+# configure.in...
+
AC_CHECK_FUNCS(memmove)
KRB5_BUILD_LIBOBJS
KRB5_BUILD_LIBRARY
KRB5_BUILD_PROGRAM
-dnl for slave
+# for slave
AC_TYPE_MODE_T
AC_PROG_INSTALL
KRB5_AC_NEED_DAEMON
LIBUTIL=-lutil
])
AC_SUBST(LIBUTIL)
-dnl for kdc
+# for kdc
AC_CHECK_HEADERS(syslog.h stdarg.h sys/select.h sys/sockio.h ifaddrs.h unistd.h)
AC_CHECK_FUNCS(openlog syslog closelog strftime vsprintf vasprintf vsnprintf)
AC_CHECK_FUNCS(strlcpy)
#include <stdlib.h>
],swab,1)
KRB5_NEED_PROTO([#include <ctype.h>],isblank,1)
-dnl
+
AC_PROG_AWK
KRB5_AC_INET6
KRB5_SOCKADDR_SA_LEN
CHECK_SIGNALS
-dnl
-dnl --with-vague-errors disables useful error messages.
-dnl
+
+# --with-vague-errors disables useful error messages.
+
AC_ARG_WITH([vague-errors],
-AC_HELP_STRING([--with-vague-errors],[Do not @<:@do@:>@ send helpful errors to client]), , withval=no)dnl
+AC_HELP_STRING([--with-vague-errors],[Do not @<:@do@:>@ send helpful errors to client]), , withval=no)
if test "$withval" = yes; then
AC_MSG_RESULT(Supplying vague error messages to KDC clients)
AC_DEFINE(KRBCONF_VAGUE_ERRORS,1,[Define if the KDC should return only vague error codes to clients])
fi
-dnl
-dnl WITH_CRYPTO_IMPL
-dnl
+
+# WITH_CRYPTO_IMPL
+
CRYPTO_IMPL="builtin"
AC_ARG_WITH([crypto-impl],
AC_HELP_STRING([--with-crypto-impl=IMPL], [use specified crypto implementation @<:@builtin@:>@]),
[CRYPTO_IMPL=$withval
AC_MSG_RESULT("k5crypto will use \'$withval\'")
-], withval=builtin)dnl
+], withval=builtin)
AC_SUBST(CRYPTO_IMPL)
-dnl
-dnl --with-kdc-kdb-update makes the KDC update the database with last request
-dnl information and failure information.
-dnl
+
+# --with-kdc-kdb-update makes the KDC update the database with last request
+# information and failure information.
+
AC_ARG_WITH([kdc-kdb-update],
-AC_HELP_STRING([--with-kdc-kdb-update],[Update the database @<:@don't update@:>@]), , withval=no)dnl
+AC_HELP_STRING([--with-kdc-kdb-update],[Update the database @<:@don't update@:>@]), , withval=no)
if test "$withval" = yes; then
AC_MSG_RESULT(Updating KDC database with each request)
AC_DEFINE(KRBCONF_KDC_MODIFIES_KDB,1,[Define if KDC should update database with each request])
fi
-dnl
-dnl Needed for hw-preauth replay detection on KDC.
-dnl
-dnl USE_RCACHE enables the replay cache
-dnl NOCACHE disables the lookaside cache
-dnl
-dnl The lookaside cache is checked first; if *exactly* the same message
-dnl comes in twice, e.g., because the (legitimate) client resent it,
-dnl the previous response will be resent. Otherwise, the replay cache
-dnl is used to check for attempts to fake out the KDC. Some hardware
-dnl preauth methods are weak enough that we *really* want to have this
-dnl checking turned on.
-dnl
+
+# Needed for hw-preauth replay detection on KDC.
+
+# USE_RCACHE enables the replay cache
+# NOCACHE disables the lookaside cache
+
+# The lookaside cache is checked first; if *exactly* the same message
+# comes in twice, e.g., because the (legitimate) client resent it,
+# the previous response will be resent. Otherwise, the replay cache
+# is used to check for attempts to fake out the KDC. Some hardware
+# preauth methods are weak enough that we *really* want to have this
+# checking turned on.
+
AC_ARG_ENABLE([kdc-replay-cache],
-AC_HELP_STRING([--enable-kdc-replay-cache],[check for replayed/retransmitted KDC requests (recommended when hardware preauthentication is in use) @<:@disabled@:>@]), , enableval=yes)dnl
+AC_HELP_STRING([--enable-kdc-replay-cache],[check for replayed/retransmitted KDC requests (recommended when hardware preauthentication is in use) @<:@disabled@:>@]), , enableval=yes)
if test "$enableval" = yes ; then
AC_DEFINE(USE_RCACHE,1,[Define if the KDC should use a replay cache])
else
AC_DEFINE(NOCACHE,1,[Define if the KDC should use no replay cache])
fi
KRB5_RUN_FLAGS
-dnl
+
AC_TYPE_SIGNAL
-dnl
-dnl from old include/configure.in
+
+# from old include/configure.in
AH_TEMPLATE([HAVE_STRUCT_SOCKADDR_STORAGE],
[Define if "struct sockaddr_storage" is available.])
-dnl
+
AC_CONFIG_HEADERS(include/autoconf.h, [echo timestamp > include/autoconf.stamp])
AC_PROG_INSTALL
AC_PROG_AWK
AC_C_CONST
AC_HEADER_DIRENT
AC_CHECK_FUNCS(strdup setvbuf inet_ntoa inet_aton seteuid setresuid setreuid setegid setresgid setregid setsid flock fchmod chmod strftime strptime geteuid setenv unsetenv getenv gethostbyname2 getifaddrs gmtime_r localtime_r pthread_mutex_lock sched_yield bswap16 bswap64 mkstemp getusershell lstat access ftime getcwd srand48 srand srandom stat strchr strerror strerror_r strstr timezone umask waitpid sem_init sem_trywait daemon)
-dnl
+
AC_CHECK_FUNC(mkstemp,
[MKSTEMP_ST_OBJ=
MKSTEMP_OBJ=],
AC_SUBST(MKSTEMP_OBJ)
AC_SUBST(MKSTEMP_ST_OBJ)
AC_SUBST(EXTRA_SUPPORT_SYMS)
-dnl
+
AC_HEADER_STDARG
DECLARE_SYS_ERRLIST
AC_CHECK_HEADERS(unistd.h paths.h regex.h regexpr.h fcntl.h memory.h ifaddrs.h sys/filio.h sched.h byteswap.h machine/endian.h machine/byte_order.h sys/bswap.h endian.h pwd.h arpa/inet.h alloca.h dlfcn.h limits.h pthread.h semaphore.h krb_db.h kdc.h)
#include <sys/stat.h>])
KRB5_AC_REGEX_FUNCS
AC_TYPE_OFF_T
-dnl
-dnl Fancy caching of perror result...
+
+# Fancy caching of perror result...
AC_MSG_CHECKING(for perror declaration)
AC_CACHE_VAL(krb5_cv_decl_perror,
[AC_EGREP_HEADER(perror, errno.h,
- krb5_cv_decl_perror=yes, krb5_cv_decl_perror=no)])dnl
+ krb5_cv_decl_perror=yes, krb5_cv_decl_perror=no)])
AC_MSG_RESULT($krb5_cv_decl_perror)
if test $krb5_cv_decl_perror = yes; then
AC_DEFINE(HDR_HAS_PERROR,1,[Define if errno.h declares perror])
fi
-dnl
+
KRB5_NEED_PROTO([#include <time.h>],strptime)
CHECK_WAIT_TYPE
CHECK_SIGPROCMASK
AC_TYPE_GETGROUPS
CHECK_SETJMP
-dnl
-dnl *rpcent return types needed for lib/rpc
-dnl
+
+# *rpcent return types needed for lib/rpc
+
AC_MSG_CHECKING([return type of setrpcent])
AC_CACHE_VAL(k5_cv_type_setrpcent,
[AC_TRY_COMPILE([#include <netdb.h>
extern "C"
#endif
extern void setrpcent();],
-[int i;], k5_cv_type_setrpcent=void, k5_cv_type_setrpcent=int)])dnl
+[int i;], k5_cv_type_setrpcent=void, k5_cv_type_setrpcent=int)])
AC_MSG_RESULT($k5_cv_type_setrpcent)
AC_DEFINE_UNQUOTED(SETRPCENT_TYPE, $k5_cv_type_setrpcent, [Define as return type of setrpcent])
-dnl
+
AC_MSG_CHECKING([return type of endrpcent])
AC_CACHE_VAL(k5_cv_type_endrpcent,
[AC_TRY_COMPILE([#include <netdb.h>
extern "C"
#endif
extern void endrpcent();],
-[int i;], k5_cv_type_endrpcent=void, k5_cv_type_endrpcent=int)])dnl
+[int i;], k5_cv_type_endrpcent=void, k5_cv_type_endrpcent=int)])
AC_MSG_RESULT($k5_cv_type_endrpcent)
AC_DEFINE_UNQUOTED(ENDRPCENT_TYPE, $k5_cv_type_endrpcent, [Define as return type of endrpcent])
-dnl
-dnl
-dnl bswap_16 is a macro in byteswap.h under GNU libc
+
+
+# bswap_16 is a macro in byteswap.h under GNU libc
AC_MSG_CHECKING(for bswap_16)
AC_CACHE_VAL(krb5_cv_bswap_16,[
AC_TRY_LINK([#if HAVE_BYTESWAP_H
if test "$krb5_cv_bswap_64" = yes; then
AC_DEFINE(HAVE_BSWAP_64,1,[Define to 1 if bswap_64 is available via byteswap.h])
fi
-dnl
-dnl Needed for ksu and some appl stuff.
-dnl
+
+# Needed for ksu and some appl stuff.
+
case $krb5_cv_host in
alpha*-dec-osf*)
AC_CHECK_LIB(security,setluid,
;;
esac
AC_SUBST(KSU_LIBS)
-dnl
+
if test $ac_cv_func_setenv = no || test $ac_cv_func_unsetenv = no \
|| test $ac_cv_func_getenv = no; then
SETENVOBJ=setenv.o
SETENVOBJ=
fi
AC_SUBST(SETENVOBJ)
-dnl
-dnl Check what the return types for gethostbyname_r and getservbyname_r are.
-dnl
+
+# Check what the return types for gethostbyname_r and getservbyname_r are.
+
AC_CHECK_FUNC(gethostbyname_r,[
ac_cv_func_gethostbyname_r=yes
if test "$ac_cv_func_gethostbyname_r" = yes; then
AC_CHECK_FUNC(gethostbyaddr_r)
fi
])
-dnl
+
AC_CHECK_FUNC(getpwnam_r,ac_cv_func_getpwnam_r=yes,ac_cv_func_getpwnam_r=no)
AC_CHECK_FUNC(getpwuid_r,ac_cv_func_getpwuid_r=yes,ac_cv_func_getpwuid_r=no)
AC_CHECK_FUNC(getservbyport_r)
fi
])
-dnl
+
HAVE_YYLINENO
CHECK_DIRENT
AC_TYPE_UID_T
AC_TYPE_MODE_T
-dnl
-AC_CHECK_HEADER(termios.h,dnl
-[AC_CHECK_FUNC([tcsetattr],dnl
+
+AC_CHECK_HEADER(termios.h,
+[AC_CHECK_FUNC([tcsetattr],
AC_DEFINE(POSIX_TERMIOS,1,[Define if termios.h exists and tcsetattr exists]))])
-dnl
+
KRB5_SIGTYPE
AC_CHECK_HEADERS(stdlib.h string.h stddef.h sys/types.h sys/file.h sys/param.h sys/stat.h sys/time.h netinet/in.h sys/uio.h sys/filio.h sys/select.h time.h paths.h errno.h)
AC_HEADER_STDARG
KRB5_AC_INET6
-dnl
-dnl If compiling with IPv6 support, test if in6addr_any functions.
-dnl Irix 6.5.16 defines it, but lacks support in the C library.
+
+# If compiling with IPv6 support, test if in6addr_any functions.
+# Irix 6.5.16 defines it, but lacks support in the C library.
if test $krb5_cv_inet6 = yes || test "$krb5_cv_inet6_with_dinet6" = yes ; then
AC_CACHE_CHECK([for in6addr_any definition in library],
krb5_cv_var_in6addr_any,
fi
fi
-dnl
-dnl
-dnl check for ANSI stdio, esp "b" option to fopen(). This (unfortunately)
-dnl requires a run check...
-dnl
+
+
+# check for ANSI stdio, esp "b" option to fopen(). This (unfortunately)
+# requires a run check...
+
AC_MSG_CHECKING([for ANSI stdio])
AC_CACHE_VAL(krb5_cv_has_ansi_stdio,
[AC_TRY_RUN(
exit(0);
}],
krb5_cv_has_ansi_stdio=yes, krb5_cv_has_ansi_stdio=no,
-krb5_cv_has_ansi_stdio=yes)])dnl assume ANSI in cross environment
+krb5_cv_has_ansi_stdio=yes)])# assume ANSI in cross environment
AC_MSG_RESULT($krb5_cv_has_ansi_stdio)
if test $krb5_cv_has_ansi_stdio = yes; then
AC_DEFINE(ANSI_STDIO,1,[Define if ANSI stdio is present (in particular "b" option to fopen)])
fi
-dnl
-dnl then from osconf.h, we have
-dnl
+
+# then from osconf.h, we have
+
AC_HEADER_TIME
AC_CHECK_TYPE(time_t, long)
-dnl
-dnl Determine where to put the replay cache.
-dnl
+
+# Determine where to put the replay cache.
+
AC_MSG_CHECKING([for replay cache directory])
AC_CACHE_VAL(krb5_cv_sys_rcdir,
[
test -d $t_dir || continue
krb5_cv_sys_rcdir=$t_dir
break
-done])dnl
+done])
AC_MSG_RESULT($krb5_cv_sys_rcdir)
KRB5_RCTMPDIR=$krb5_cv_sys_rcdir
AC_SUBST(KRB5_RCTMPDIR)
-dnl
-dnl
+
+
AC_MSG_CHECKING(for socklen_t)
AC_CACHE_VAL(krb5_cv_has_type_socklen_t,
[AC_TRY_COMPILE(
if test $krb5_cv_has_type_socklen_t = yes; then
AC_DEFINE(HAVE_SOCKLEN_T,1,[Define if there is a socklen_t type. If not, probably use size_t])
fi
-dnl
+
AC_MSG_CHECKING(for struct lifconf)
AC_CACHE_VAL(krb5_cv_has_struct_lifconf,
[AC_TRY_COMPILE(
if test $krb5_cv_has_struct_lifconf = yes; then
AC_DEFINE(HAVE_STRUCT_LIFCONF,1,[Define if there is a struct lifconf.])
fi
-dnl HP-UX 11 uses stuct if_laddrconf
+# HP-UX 11 uses stuct if_laddrconf
AC_MSG_CHECKING(for struct if_laddrconf)
AC_CACHE_VAL(krb5_cv_has_struct_if_laddrconf,
[AC_TRY_COMPILE(
if test $krb5_cv_has_struct_if_laddrconf = yes; then
AC_DEFINE(HAVE_STRUCT_IF_LADDRCONF,1,[Define if there is a struct if_laddrconf.])
fi
-dnl
-dnl
+
+
AC_MSG_CHECKING([for h_errno in netdb.h])
AC_CACHE_VAL(krb5_cv_header_netdb_h_h_errno,
[AC_TRY_COMPILE(
AC_DEFINE([HAVE_NETDB_H_H_ERRNO], 1,
[Define if netdb.h declares h_errno])
fi
-dnl
-dnl
+
+
AC_ARG_ENABLE([athena],
[ --enable-athena build with MIT Project Athena configuration],
AC_DEFINE(KRB5_ATHENA_COMPAT,1,[Define if MIT Project Athena default configuration should be used]),)
-dnl
+
AC_C_INLINE
AH_TOP([
#ifndef KRB5_AUTOCONF_H
#endif
#endif /* KRB5_AUTOCONF_H */
])
-dnl
-dnl Not used yet, but let's find out what we've got on the platforms
-dnl we're working with....
+
+# Not used yet, but let's find out what we've got on the platforms
+# we're working with....
AC_CHECK_HEADERS(inttypes.h stdint.h)
AC_CHECK_TYPES([uint32_t, int32_t, uint64_t, int64_t, uint_least32_t, uintptr_t, uintmax_t, long long], , , [
#ifdef HAVE_STDINT_H
#include <net/if.h>
#include <net/route.h>
])
-dnl
-dnl stuff for util/profile
-dnl
-dnl AC_KRB5_TCL already done
+
+# stuff for util/profile
+
+# AC_KRB5_TCL already done
DO_TCL=
test "$TCL_LIBS" != "" && DO_TCL=ok
AC_SUBST(DO_TCL)
-dnl
-dnl types libdb2 wants
-dnl
+
+# types libdb2 wants
+
AC_CHECK_TYPES([ssize_t, u_char, u_int, u_long, u_int8_t, u_int16_t, u_int32_t, int8_t, int16_t, int32_t])
-dnl
-dnl Some libdb2 test programs want a shell that supports functions.
+
+# Some libdb2 test programs want a shell that supports functions.
FCTSH=false
AC_PATH_PROG(SH,sh,false)
AC_PATH_PROG(SH5,sh5,false)
fi
done
AC_SUBST(FCTSH)
-dnl
-dnl Test for POSIX 2001 *printf support (X/Open System Interfaces extension
-dnl to ANSI/ISO C 1999 specification). Specifically, positional
-dnl specifications; not checking for other features like %zx at present.
+
+# Test for POSIX 2001 *printf support (X/Open System Interfaces extension
+# to ANSI/ISO C 1999 specification). Specifically, positional
+# specifications; not checking for other features like %zx at present.
AC_MSG_CHECKING(for POSIX printf positional specification support)
AC_CACHE_VAL(ac_cv_printf_positional,[
AC_TRY_RUN([
ac_cv_printf_positional=yes,
ac_cv_printf_positional=no,
AC_MSG_ERROR([Cannot test for printf positional argument support when cross compiling]))])
-dnl Nothing for autoconf.h for now.
+# Nothing for autoconf.h for now.
AC_MSG_RESULT($ac_cv_printf_positional)
-dnl
-dnl
-dnl for kadmin
-dnl
+
+
+# for kadmin
+
AC_PROG_YACC
ath_compat=
AC_ARG_ENABLE([athena],
[ --enable-athena build with MIT Project Athena configuration],
ath_compat=compat,)
-dnl The following are tests for the presence of programs required for
-dnl kadmin testing.
+# The following are tests for the presence of programs required for
+# kadmin testing.
AC_CHECK_PROG(have_RUNTEST,runtest,runtest)
AC_CHECK_PROG(have_PERL,perl,perl)
AC_KRB5_TCL
DO_TEST=ok
fi
AC_SUBST(DO_TEST)
-dnl
-dnl The following are substituted into kadmin/testing/scripts/env-setup.sh
+
+# The following are substituted into kadmin/testing/scripts/env-setup.sh
RBUILD=`pwd`
AC_SUBST(RBUILD)
case "$srcdir" in
AC_SUBST(S_TOP)
AC_PATH_PROG(PERL_PATH,perl)
AC_PATH_PROG(EXPECT,expect)
-dnl For kadmin/testing/util/Makefile.in
+# For kadmin/testing/util/Makefile.in
if test "$TCL_LIBS" != "" ; then
DO_ALL=tcl
fi
AC_SUBST(DO_ALL)
KRB5_AC_PRIOCNTL_HACK
K5_GEN_FILE(kadmin/testing/scripts/env-setup.sh:kadmin/testing/scripts/env-setup.shin)
-dnl for lib/kadm5
+# for lib/kadm5
AC_CHECK_PROG(RUNTEST,runtest,runtest)
AC_CHECK_PROG(PERL,perl,perl)
-dnl
-dnl lib/gssapi
+
+# lib/gssapi
AC_CHECK_HEADER(stdint.h,[
include_stdint='awk '\''END{printf("%cinclude <stdint.h>\n", 35);}'\'' < /dev/null'],
include_stdint='echo "/* no stdint.h */"')
include_xom='awk '\''END{printf("%cinclude <xom.h>\n", 35);}'\'' < /dev/null'], [
include_xom='echo "/* no xom.h */"'])
AC_SUBST(include_xom)
-dnl
-dnl
-dnl lib/rpc
+
+
+# lib/rpc
### Check where struct rpcent is declared.
-#
+
# This is necessary to determine:
# 1. If /usr/include/netdb.h declares struct rpcent
# 2. If /usr/include/rpc/netdb.h declares struct rpcent
-#
+
# We have our own rpc/netdb.h, and if /usr/include/netdb.h includes
# rpc/netdb.h, then nastiness could happen.
-#
+
# Logic: If /usr/include/netdb.h declares struct rpcent, then check
# rpc/netdb.h. If /usr/include/rpc/netdb.h declares struct rpcent,
# then define STRUCT_RPCENT_IN_RPC_NETDB_H, otherwise do not. If
# neither netdb.h nor rpc/netdb.h declares struct rpcent, then define
# STRUCT_RPCENT_IN_RPC_NETDB_H anyway.
-#
+
AC_MSG_CHECKING([where struct rpcent is declared])
AC_TRY_COMPILE([#include <netdb.h>],
[struct rpcent e;
GSSRPC__BSD_TYPEALIASES='#define GSSRPC__BSD_TYPEALIASES 1'
fi
AC_SUBST(GSSRPC__BSD_TYPEALIASES)
-#
+
# sockaddr length field checks
-#
+
AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], , ,
[#include <sys/types.h>
@%:@include <netinet/in.h>])
extern "C"
#endif
extern void setrpcent();],
-[int i;], k5_cv_type_setrpcent=void, k5_cv_type_setrpcent=int)])dnl
+[int i;], k5_cv_type_setrpcent=void, k5_cv_type_setrpcent=int)])
AC_MSG_RESULT($k5_cv_type_setrpcent)
AC_DEFINE_UNQUOTED(SETRPCENT_TYPE, $k5_cv_type_setrpcent, [Define as return type of setrpcent])
-dnl
+
AC_MSG_CHECKING([return type of endrpcent])
AC_CACHE_VAL(k5_cv_type_endrpcent,
[AC_TRY_COMPILE([#include <netdb.h>
extern "C"
#endif
extern void endrpcent();],
-[int i;], k5_cv_type_endrpcent=void, k5_cv_type_endrpcent=int)])dnl
+[int i;], k5_cv_type_endrpcent=void, k5_cv_type_endrpcent=int)])
AC_MSG_RESULT($k5_cv_type_endrpcent)
AC_DEFINE_UNQUOTED(ENDRPCENT_TYPE, $k5_cv_type_endrpcent, [Define as return type of endrpcent])
K5_GEN_FILE(include/gssrpc/types.h:include/gssrpc/types.hin)
changequote([, ])
AC_SUBST(PASS)
-dnl for pkinit
+# for pkinit
AC_ARG_ENABLE([pkinit],
[ --disable-pkinit disable PKINIT plugin support],,
enable_pkinit=try)
AC_MSG_NOTICE([Disabling PKINIT support.])
fi
-dnl for lib/apputils
+# for lib/apputils
AC_REPLACE_FUNCS(daemon)
-dnl for tests/
+# for tests/
if test x"$RUNTEST" != x; then
HAVE_RUNTEST=yes
else
fi
AC_SUBST(HAVE_RUNTEST)
-dnl for plugins/kdb/db2
-dnl
-dnl AIX is unusual in that it wants all symbols resolved at link time
-dnl Fortunately, it will allow us to link the kdb library now, even if
-dnl it is linked again later.
+# for plugins/kdb/db2
+
+# AIX is unusual in that it wants all symbols resolved at link time
+# Fortunately, it will allow us to link the kdb library now, even if
+# it is linked again later.
case $krb5_cv_host in
*-*-aix*)
DB_EXTRA_LIBS=-ldb
esac
AC_SUBST(DB_EXTRA_LIBS)
-dnl
-dnl
-dnl Check for thread safety issues.
-dnl (Is there a better place for this?)
-dnl tsfuncs="getpwnam_r getpwuid_r gethostbyname_r getservbyname_r gmtime_r localtime_r"
-dnl Removed getpwnam_r and getpwuid_r because include/configure.in has some
-dnl more careful checks, and may decide to pretend that they're not found if
-dnl the function signatures can't be figured out.
+
+
+# Check for thread safety issues.
+# (Is there a better place for this?)
+# tsfuncs="getpwnam_r getpwuid_r gethostbyname_r getservbyname_r gmtime_r localtime_r"
+# Removed getpwnam_r and getpwuid_r because include/configure.in has some
+# more careful checks, and may decide to pretend that they're not found if
+# the function signatures can't be figured out.
tsfuncs="gethostbyname_r getservbyname_r gmtime_r localtime_r"
AC_CHECK_FUNCS($tsfuncs)
if test "$enable_thread_support" = yes; then
AC_MSG_WARN([may not be thread-safe.])
fi # tsmissing not empty
fi # enable_thread_support
-dnl
-dnl Sadly, we seem to have accidentally committed ourselves in 1.4 to
-dnl an ABI that includes the existence of libkrb5support.0 even
-dnl though random apps should never use anything from it. And on
-dnl the Mac, to which that didn't apply, we can't use major version 0.
-dnl
+
+# Sadly, we seem to have accidentally committed ourselves in 1.4 to
+# an ABI that includes the existence of libkrb5support.0 even
+# though random apps should never use anything from it. And on
+# the Mac, to which that didn't apply, we can't use major version 0.
+
case $krb5_cv_host in
*-*-darwin* | *-*-rhapsody*) SUPPORTLIB_MAJOR=1 ;;
*) SUPPORTLIB_MAJOR=0 ;;
esac
AC_SUBST(SUPPORTLIB_MAJOR)
-dnl
-dnl On the Mac we need CoreFoundation for UCS-2 conversion for RC4.
+
+# On the Mac we need CoreFoundation for UCS-2 conversion for RC4.
case $krb5_cv_host in
*-*-darwin* | *-*-rhapsody*) CRYPTO_LIBS="-framework CoreFoundation" ;;
*) CRYPTO_LIBS="" ;;
esac
AC_SUBST(CRYPTO_LIBS)
-dnl
-dnl
+
+
if test "$COM_ERR_VERSION" = k5 ; then
K5_GEN_MAKEFILE(util/et)
fi
if test "$SS_VERSION" = k5 ; then
K5_GEN_MAKEFILE(util/ss)
fi
-dnl
-dnl
+
+
ldap_plugin_dir=""
ldap_lib=""
if test -n "$OPENLDAP_PLUGIN"; then
AC_SUBST(ldap_plugin_dir)
AC_SUBST(LDAP)
-dnl We really should look for and use python-config.
+# We really should look for and use python-config.
PYTHON_LIB=
AC_CHECK_HEADERS(Python.h python2.3/Python.h python2.5/Python.h)
AC_CHECK_LIB(python2.3,main,[PYTHON_LIB=-lpython2.3],
AC_CHECK_LIB(python2.5,main,[PYTHON_LIB=-lpython2.5]))
AC_SUBST(PYTHON_LIB)
-dnl
-dnl Kludge for simple server --- FIXME is this the best way to do this?
-dnl
+
+# Kludge for simple server --- FIXME is this the best way to do this?
+
if test "$ac_cv_lib_socket" = "yes" -a "$ac_cv_lib_nsl" = "yes"; then
AC_DEFINE(BROKEN_STREAMS_SOCKETS,1,[Define if socket can't be bound to 0.0.0.0])
fi
-dnl
+
AC_CONFIG_SUBDIRS(appl/libpty appl/bsd appl/gssftp appl/telnet)
AC_CONFIG_FILES(krb5-config, [chmod +x krb5-config])
lib lib/kdb
lib/crypto lib/crypto/krb lib/crypto/krb/crc32 lib/crypto/builtin/des
- lib/crypto/krb/dk lib/crypto/krb/enc_provider
+ lib/crypto/krb/dk lib/crypto/builtin/enc_provider
lib/crypto/krb/hash_provider lib/crypto/krb/keyhash_provider
lib/crypto/builtin lib/crypto/builtin/md4 lib/crypto/builtin/md5
lib/crypto/krb/old lib/crypto/krb/raw lib/crypto/builtin/sha1
};
struct krb5_hash_provider {
+ char hash_name[8];
size_t hashsize, blocksize;
/* this takes multiple inputs to avoid lots of copying. */
krb5_data auth_package;
} krb5_pa_for_user;
+typedef struct _krb5_s4u_userid {
+ krb5_int32 nonce;
+ krb5_principal user;
+ krb5_data subject_cert;
+ krb5_flags options;
+} krb5_s4u_userid;
+
+#define KRB5_S4U_OPTS_CHECK_LOGON_HOURS 0x40000000 /* check logon hour restrictions */
+#define KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE 0x20000000 /* sign with usage 27 instead of 26 */
+
+typedef struct _krb5_pa_s4u_x509_user {
+ krb5_s4u_userid user_id;
+ krb5_checksum cksum;
+} krb5_pa_s4u_x509_user;
+
enum {
KRB5_FAST_ARMOR_AP_REQUEST = 0x1
};
(krb5_context, krb5_pa_enc_ts *);
void KRB5_CALLCONV krb5_free_pa_for_user
(krb5_context, krb5_pa_for_user * );
+void KRB5_CALLCONV krb5_free_s4u_userid_contents
+ (krb5_context, krb5_s4u_userid * );
+void KRB5_CALLCONV krb5_free_pa_s4u_x509_user
+ (krb5_context, krb5_pa_s4u_x509_user * );
void KRB5_CALLCONV krb5_free_pa_svr_referral_data
(krb5_context, krb5_pa_svr_referral_data * );
void KRB5_CALLCONV krb5_free_pa_server_referral_data
krb5_error_code encode_krb5_pa_for_user
(const krb5_pa_for_user * , krb5_data **);
+krb5_error_code encode_krb5_s4u_userid
+ (const krb5_s4u_userid * , krb5_data **);
+
+krb5_error_code encode_krb5_pa_s4u_x509_user
+ (const krb5_pa_s4u_x509_user * , krb5_data **);
+
krb5_error_code encode_krb5_pa_svr_referral_data
(const krb5_pa_svr_referral_data * , krb5_data **);
krb5_error_code decode_krb5_pa_for_user
(const krb5_data *, krb5_pa_for_user **);
+krb5_error_code decode_krb5_pa_s4u_x509_user
+ (const krb5_data *, krb5_pa_s4u_x509_user **);
+
krb5_error_code decode_krb5_pa_svr_referral_data
(const krb5_data *, krb5_pa_svr_referral_data **);
krb5_pa_data * const *,
const krb5_data *,
krb5_creds *,
+ krb5_error_code (*gcvt_fct)(krb5_context,
+ krb5_keyblock *,
+ krb5_kdc_req *,
+ void *),
+ void *gcvt_data,
krb5_response * , krb5_keyblock **subkey);
/* The subkey field is an output parameter; if a
* tgs-rep is received then the subkey will be filled
const krb5_keyblock *privsvr_key,
krb5_data *data);
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
+ krb5_ccache ccache,
+ krb5_creds *in_creds,
+ krb5_data *cert,
+ krb5_creds **out_creds);
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_proxy(krb5_context context,
+ krb5_flags options,
+ krb5_ccache ccache,
+ krb5_creds *in_creds,
+ krb5_ticket *evidence_tkt,
+ krb5_creds **out_creds);
+
krb5_error_code krb5int_parse_enctype_list(krb5_context context, char *profstr,
krb5_enctype *default_list,
krb5_enctype **result);
#define KRB5_KDB_SUPPORT_DESMD5 0x00004000
#define KRB5_KDB_NEW_PRINC 0x00008000
#define KRB5_KDB_OK_AS_DELEGATE 0x00100000
+#define KRB5_KDB_OK_TO_AUTH_AS_DELEGATE 0x00200000 /* S4U2Self OK */
+#define KRB5_KDB_NO_AUTH_DATA_REQUIRED 0x00400000
/* Creation flags */
#define KRB5_KDB_CREATE_BTREE 0x00000001
#ifndef KRB5_KDB5_EXT__
#define KRB5_KDB5_EXT__
-/* Allowed to use protocol transition */
-#define KRB5_KDB_OK_TO_AUTH_AS_DELEGATE 0x00200000
-/* Service does not require authorization data */
-#define KRB5_KDB_NO_AUTH_DATA_REQUIRED 0x00400000
/* Private flag used to indicate principal is local TGS */
#define KRB5_KDB_TICKET_GRANTING_SERVICE 0x01000000
/* Private flag used to indicate xrealm relationship is non-transitive */
/* Defined in KDC referrals draft */
#define KRB5_KEYUSAGE_PA_REFERRAL 26 /* XXX note conflict with above */
+
+/* Defined in [MS-SFU] */
+#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST 26 /* XXX note conflict with above */
+#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY 27 /* XXX note conflict with above */
+
/* define in draft-ietf-krb-wg-preauth-framework*/
#define KRB5_KEYUSAGE_FAST_REQ_CHKSUM 50
#define KRB5_KEYUSAGE_FAST_ENC 51
#define KRB5_GC_USER_USER 1 /* want user-user ticket */
#define KRB5_GC_CACHED 2 /* want cached ticket only */
#define KRB5_GC_CANONICALIZE 4 /* set canonicalize KDC option */
+#define KRB5_GC_NO_STORE 8 /* do not store in credentials cache */
+#define KRB5_GC_FORWARDABLE 16 /* acquire forwardable tickets */
+#define KRB5_GC_NO_TRANSIT_CHECK 32 /* disable transited check */
+#define KRB5_GC_CONSTRAINED_DELEGATION 64 /* constrained delegation */
krb5_error_code KRB5_CALLCONV krb5_get_credentials
(krb5_context,
{"allow_svr", 9, KRB5_KDB_DISALLOW_SVR, 1},
{"password_changing_service", 25, KRB5_KDB_PWCHANGE_SERVICE, 0 },
{"support_desmd5", 14, KRB5_KDB_SUPPORT_DESMD5, 0 },
-{"ok_as_delegate", 14, KRB5_KDB_OK_AS_DELEGATE, 0 }
+{"ok_as_delegate", 14, KRB5_KDB_OK_AS_DELEGATE, 0 },
+{"ok_to_auth_as_delegate", 22, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, 0 },
+{"no_auth_data_required", 21, KRB5_KDB_NO_AUTH_DATA_REQUIRED, 0},
};
static char *prflags[] = {
"UNKNOWN_0x00040000", /* 0x00040000 */
"UNKNOWN_0x00080000", /* 0x00080000 */
"OK_AS_DELEGATE", /* 0x00100000 */
+ "OK_TO_AUTH_AS_DELEGATE", /* 0x00200000 */
+ "NO_AUTH_DATA_REQUIRED", /* 0x00400000 */
};
char *getenv();
"\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n",
"\t\tallow_proxiable allow_dup_skey allow_tix requires_preauth\n",
"\t\trequires_hwauth needchange allow_svr password_changing_service\n"
- "\t\tok_as_delegate\n"
+ "\t\tok_as_delegate ok_to_auth_as_delegate no_auth_data_required\n"
"\nwhere,\n\t[-x db_princ_args]* - any number of database specific arguments.\n"
"\t\t\tLook at each database documentation for supported arguments\n");
}
"\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n",
"\t\tallow_proxiable allow_dup_skey allow_tix requires_preauth\n",
"\t\trequires_hwauth needchange allow_svr password_changing_service\n"
- "\t\tok_as_delegate\n"
+ "\t\tok_as_delegate ok_to_auth_as_delegate no_auth_data_required\n"
"\nwhere,\n\t[-x db_princ_args]* - any number of database specific arguments.\n"
"\t\t\tLook at each database documentation for supported arguments\n"
);
fi
if [ "x$PS_ALL" = "x" ]; then
- ps -axwwu >/dev/null 2>&1
- ps_bsd=$?
-
- ps -ef >/dev/null 2>&1
- ps_sysv=$?
-
- if [ $ps_bsd = 0 -a $ps_sysv = 1 ]; then
- PS_ALL="ps -auxww"
- PS_PID="ps -auxww"
- elif [ $ps_bsd = 1 -a $ps_sysv = 0 ]; then
+ if ps auxww >/dev/null 2>&1; then
+ PS_ALL="ps auxww"
+ PS_PID="ps auxww"
+ elif ps -ef >/dev/null 2>&1; then
PS_ALL="ps -ef"
PS_PID="ps -fp"
else
- PS_ALL="ps -auxww"
- PS_PID="ps -auxww"
+ PS_ALL="ps auxww"
+ PS_PID="ps auxww"
echo "WARNING! Cannot auto-detect ps type, assuming BSD."
fi
ret = kadm5_randkey_principal(server_handle,
princ, keyblock_var ? &keyblocks : 0,
- num_var ? &num_keys : 0);
+ &num_keys);
if (ret == KADM5_OK) {
if (keyblock_var) {
krb5_enc_tkt_part *header_enc_tkt = NULL; /* ticket granting or evidence ticket */
krb5_db_entry client, krbtgt;
int c_nprincs = 0, k_nprincs = 0;
- krb5_pa_for_user *for_user = NULL; /* protocol transition request */
+ krb5_pa_s4u_x509_user *s4u_x509_user = NULL; /* protocol transition request */
krb5_authdata **kdc_issued_auth_data = NULL; /* auth data issued by KDC */
unsigned int c_flags = 0, s_flags = 0; /* client/server KDB flags */
char *s4u_name = NULL;
krb5_data scratch;
session_key.contents = NULL;
-
+
retval = decode_krb5_tgs_req(pkt, &request);
if (retval)
return retval;
!krb5_principal_compare(kdc_context, tgs_server, server.princ);
/* Check for protocol transition */
- errcode = kdc_process_s4u2self_req(kdc_context, request, header_enc_tkt->client,
- &server, header_enc_tkt->session, kdc_time,
- &for_user, &client, &c_nprincs, &status);
+ errcode = kdc_process_s4u2self_req(kdc_context,
+ request,
+ header_enc_tkt->client,
+ &server,
+ subkey,
+ header_enc_tkt->session,
+ kdc_time,
+ &s4u_x509_user,
+ &client,
+ &c_nprincs,
+ &status);
if (errcode)
goto cleanup;
- if (for_user != NULL)
+ if (s4u_x509_user != NULL)
setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
/*
/* processing of any of these flags. For example, some */
/* realms may refuse to issue renewable tickets */
- if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE))
+ if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE)) {
setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
- if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
- if (!krb5_is_tgs_principal(server.princ) &&
- is_local_principal(server.princ)) {
- if (isflagset(server.attributes, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
- setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
- else
+
+ if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
+ /*
+ * If S4U2Self principal is not forwardable, then mark ticket as
+ * unforwardable. This behaviour matches Windows, but it is
+ * different to the MIT AS-REQ path, which returns an error
+ * (KDC_ERR_POLICY) if forwardable tickets cannot be issued.
+ *
+ * Consider this block the S4U2Self equivalent to
+ * validate_forwardable().
+ */
+ if (c_nprincs &&
+ isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
+ clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
+ /*
+ * OK_TO_AUTH_AS_DELEGATE must be set on the service requesting
+ * S4U2Self in order for forwardable tickets to be returned.
+ */
+ else if (!is_referral &&
+ !isflagset(server.attributes, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
}
- if (isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
- clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
}
+
if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) {
setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);
enc_tkt_reply.times.starttime = 0;
if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
- errcode = krb5_unparse_name(kdc_context, for_user->user, &s4u_name);
+ errcode = krb5_unparse_name(kdc_context, s4u_x509_user->user_id.user, &s4u_name);
} else if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
errcode = krb5_unparse_name(kdc_context, header_enc_tkt->client, &s4u_name);
} else {
enc_tkt_reply.authorization_data = NULL;
if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
- is_local_principal(header_enc_tkt->client))
- enc_tkt_reply.client = for_user->user;
+ !isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM))
+ enc_tkt_reply.client = s4u_x509_user->user_id.user;
else
enc_tkt_reply.client = header_enc_tkt->client;
&encrypting_key, /* U2U or server key */
pkt,
request,
- for_user ? for_user->user : NULL,
+ s4u_x509_user ?
+ s4u_x509_user->user_id.user : NULL,
header_enc_tkt,
&enc_tkt_reply);
if (errcode) {
/* Start assembling the response */
reply.msg_type = KRB5_TGS_REP;
reply.padata = 0;/* always */
+ if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
+ find_pa_data(request->padata, KRB5_PADATA_S4U_X509_USER) != NULL) {
+ errcode = kdc_make_s4u2self_rep(kdc_context,
+ subkey,
+ header_ticket->enc_part2->session,
+ s4u_x509_user,
+ &reply,
+ &reply_encpart);
+ if (errcode) {
+ status = "KDC_RETURN_S4U2SELF_PADATA";
+ goto cleanup;
+ }
+ }
+
reply.client = enc_tkt_reply.client;
reply.enc_part.kvno = 0;/* We are using the session key */
reply.ticket = &ticket_reply;
krb5_db_free_principal(kdc_context, &krbtgt, k_nprincs);
if (c_nprincs)
krb5_db_free_principal(kdc_context, &client, c_nprincs);
- if (for_user != NULL)
- krb5_free_pa_for_user(kdc_context, for_user);
+ if (s4u_x509_user != NULL)
+ krb5_free_pa_s4u_x509_user(kdc_context, s4u_x509_user);
if (kdc_issued_auth_data != NULL)
krb5_free_authdata(kdc_context, kdc_issued_auth_data);
if (s4u_name != NULL)
free(s4u_name);
if (subkey != NULL)
krb5_free_keyblock(kdc_context, subkey);
+ if (reply.padata)
+ krb5_free_pa_data(kdc_context, reply.padata);
+ if (reply_encpart.enc_padata)
+ krb5_free_pa_data(kdc_context, reply_encpart.enc_padata);
return retval;
}
}
if (ad_nprincs != 0) {
+ /*
+ * This code was submitted by Novell; however there is no
+ * mention in [MS-SFU] of needing to examine the authorization
+ * data to clear the forwardable flag. My understanding is that
+ * the state of the forwardable flag is propagated through the
+ * cross-realm TGTs.
+ */
+#if 0
if (isflagset(flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
isflagset(ad_entry.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
clear(enc_tkt_reply->flags, TKT_FLG_FORWARDABLE);
+#endif
krb5_db_free_principal(context, &ad_entry, ad_nprincs);
return (retval);
}
-static krb5_boolean
-enctype_requires_etype_info_2(krb5_enctype enctype)
-{
- switch(enctype) {
- case ENCTYPE_DES_CBC_CRC:
- case ENCTYPE_DES_CBC_MD4:
- case ENCTYPE_DES_CBC_MD5:
- case ENCTYPE_DES3_CBC_SHA1:
- case ENCTYPE_DES3_CBC_RAW:
- case ENCTYPE_ARCFOUR_HMAC:
- case ENCTYPE_ARCFOUR_HMAC_EXP :
- return 0;
- default:
- if (krb5_c_valid_enctype(enctype))
- return 1;
- else return 0;
- }
-}
-
static krb5_boolean
request_contains_enctype (krb5_context context, const krb5_kdc_req *request,
krb5_enctype enctype)
krb5_pa_data *
find_pa_data(krb5_pa_data **padata, krb5_preauthtype pa_type)
{
-return krb5int_find_pa_data(kdc_context, padata, pa_type);
+ return krb5int_find_pa_data(kdc_context, padata, pa_type);
}
krb5_error_code
}
/* make sure the client is of proper lineage (see above) */
- if (foreign_server && !find_pa_data(request->padata, KRB5_PADATA_FOR_USER)) {
+ if (foreign_server &&
+ !find_pa_data(request->padata, KRB5_PADATA_FOR_USER)) {
if (is_local_principal((*ticket)->enc_part2->client)) {
/* someone in a foreign realm claiming to be local */
krb5_klog_syslog(LOG_INFO, "PROCESS_TGS: failed lineage check");
* as a com_err error number!
*/
#define AS_INVALID_OPTIONS (KDC_OPT_FORWARDED | KDC_OPT_PROXY |\
-KDC_OPT_VALIDATE | KDC_OPT_RENEW | KDC_OPT_ENC_TKT_IN_SKEY)
+ KDC_OPT_VALIDATE | KDC_OPT_RENEW | \
+ KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)
int
validate_as_request(register krb5_kdc_req *request, krb5_db_entry client,
krb5_db_entry server, krb5_timestamp kdc_time,
* preauthentication data is absent in the request.
*
* Hence, this check most be done after the check for preauth
- * data, and is now performed by validate_forwardable().
+ * data, and is now performed by validate_forwardable() (the
+ * contents of which were previously below).
*/
-#if 0
- /* Client and server must allow forwardable tickets */
- if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE) &&
- (isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE) ||
- isflagset(server.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))) {
- *status = "FORWARDABLE NOT ALLOWED";
- return(KDC_ERR_POLICY);
- }
-#endif
/* Client and server must allow renewable tickets */
if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE) &&
}
static krb5_error_code
-verify_s4u2self_checksum(krb5_context context,
+verify_for_user_checksum(krb5_context context,
krb5_keyblock *key,
krb5_pa_for_user *req)
{
&valid);
if (code == 0 && valid == FALSE)
- code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ code = KRB5KRB_AP_ERR_MODIFIED;
free(data.data);
}
/*
- * Protocol transition validation code based on AS-REQ
- * validation code
+ * Legacy protocol transition (Windows 2003 and above)
*/
-static int
-validate_s4u2self_request(krb5_kdc_req *request,
- const krb5_db_entry *client,
- krb5_timestamp kdc_time,
- const char **status)
+static krb5_error_code
+kdc_process_for_user(krb5_context context,
+ krb5_pa_data *pa_data,
+ krb5_keyblock *tgs_session,
+ krb5_pa_s4u_x509_user **s4u_x509_user,
+ const char **status)
{
- int errcode;
- krb5_db_entry server = { 0 };
-
- /* The client must not be expired */
- if (client->expiration && client->expiration < kdc_time) {
- *status = "CLIENT EXPIRED";
- return KDC_ERR_NAME_EXP;
+ krb5_error_code code;
+ krb5_pa_for_user *for_user;
+ krb5_data req_data;
+
+ req_data.length = pa_data->length;
+ req_data.data = (char *)pa_data->contents;
+
+ code = decode_krb5_pa_for_user(&req_data, &for_user);
+ if (code)
+ return code;
+
+ code = verify_for_user_checksum(context, tgs_session, for_user);
+ if (code) {
+ *status = "INVALID_S4U2SELF_CHECKSUM";
+ krb5_free_pa_for_user(kdc_context, for_user);
+ return code;
}
- /* The client's password must not be expired, unless the server is
- a KRB5_KDC_PWCHANGE_SERVICE. */
- if (client->pw_expiration && client->pw_expiration < kdc_time) {
- *status = "CLIENT KEY EXPIRED";
- return KDC_ERR_KEY_EXP;
+ *s4u_x509_user = calloc(1, sizeof(krb5_pa_s4u_x509_user));
+ if (*s4u_x509_user == NULL) {
+ krb5_free_pa_for_user(kdc_context, for_user);
+ return ENOMEM;
}
+ (*s4u_x509_user)->user_id.user = for_user->user;
+ for_user->user = NULL;
+ krb5_free_pa_for_user(context, for_user);
+
+ return 0;
+}
+
+static krb5_error_code
+verify_s4u_x509_user_checksum(krb5_context context,
+ krb5_keyblock *key,
+ krb5_data *req_data,
+ krb5_int32 kdc_req_nonce,
+ krb5_pa_s4u_x509_user *req)
+{
+ krb5_error_code code;
+ krb5_data scratch;
+ krb5_boolean valid = FALSE;
+
+ if (enctype_requires_etype_info_2(key->enctype) &&
+ !krb5_c_is_keyed_cksum(req->cksum.checksum_type))
+ return KRB5KRB_AP_ERR_INAPP_CKSUM;
+
+ if (req->user_id.nonce != kdc_req_nonce)
+ return KRB5KRB_AP_ERR_MODIFIED;
+
/*
- * If the client requires password changing, then return an
- * error; S4U2Self cannot be used to change a password.
+ * Verify checksum over the encoded userid. If that fails,
+ * re-encode, and verify that. This is similar to the
+ * behaviour in kdc_process_tgs_req().
*/
- if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PWCHANGE)) {
- *status = "REQUIRED PWCHANGE";
- return KDC_ERR_KEY_EXP;
+ if (fetch_asn1_field((unsigned char *)req_data->data, 1, 0, &scratch) < 0)
+ return ASN1_PARSE_ERROR;
+
+ code = krb5_c_verify_checksum(context,
+ key,
+ KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST,
+ &scratch,
+ &req->cksum,
+ &valid);
+ if (code != 0)
+ return code;
+
+ if (valid == FALSE) {
+ krb5_data *data;
+
+ code = encode_krb5_s4u_userid(&req->user_id, &data);
+ if (code != 0)
+ return code;
+
+ code = krb5_c_verify_checksum(context,
+ key,
+ KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST,
+ data,
+ &req->cksum,
+ &valid);
+
+ krb5_free_data(context, data);
+
+ if (code != 0)
+ return code;
}
- /* Check to see if client is locked out */
- if (isflagset(client->attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
- *status = "CLIENT LOCKED OUT";
- return KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ return valid ? 0 : KRB5KRB_AP_ERR_MODIFIED;
+}
+
+/*
+ * New protocol transition request (Windows 2008 and above)
+ */
+static krb5_error_code
+kdc_process_s4u_x509_user(krb5_context context,
+ krb5_kdc_req *request,
+ krb5_pa_data *pa_data,
+ krb5_keyblock *tgs_subkey,
+ krb5_keyblock *tgs_session,
+ krb5_pa_s4u_x509_user **s4u_x509_user,
+ const char **status)
+{
+ krb5_error_code code;
+ krb5_data req_data;
+
+ req_data.length = pa_data->length;
+ req_data.data = (char *)pa_data->contents;
+
+ code = decode_krb5_pa_s4u_x509_user(&req_data, s4u_x509_user);
+ if (code)
+ return code;
+
+ code = verify_s4u_x509_user_checksum(context,
+ tgs_subkey ? tgs_subkey :
+ tgs_session,
+ &req_data,
+ request->nonce, *s4u_x509_user);
+
+ if (code) {
+ *status = "INVALID_S4U2SELF_CHECKSUM";
+ krb5_free_pa_s4u_x509_user(context, *s4u_x509_user);
+ *s4u_x509_user = NULL;
+ return code;
}
+ if (krb5_princ_size(context, (*s4u_x509_user)->user_id.user) == 0 ||
+ (*s4u_x509_user)->user_id.subject_cert.length != 0) {
+ *status = "INVALID_S4U2SELF_REQUEST";
+ krb5_free_pa_s4u_x509_user(context, *s4u_x509_user);
+ *s4u_x509_user = NULL;
+ return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ }
+
+ return 0;
+}
+
+krb5_error_code
+kdc_make_s4u2self_rep(krb5_context context,
+ krb5_keyblock *tgs_subkey,
+ krb5_keyblock *tgs_session,
+ krb5_pa_s4u_x509_user *req_s4u_user,
+ krb5_kdc_rep *reply,
+ krb5_enc_kdc_rep_part *reply_encpart)
+{
+ krb5_error_code code;
+ krb5_data *data = NULL;
+ krb5_pa_s4u_x509_user rep_s4u_user;
+ krb5_pa_data padata;
+ krb5_enctype enctype;
+ krb5_keyusage usage;
+
+ memset(&rep_s4u_user, 0, sizeof(rep_s4u_user));
+
+ rep_s4u_user.user_id.nonce = req_s4u_user->user_id.nonce;
+ rep_s4u_user.user_id.user = req_s4u_user->user_id.user;
+ rep_s4u_user.user_id.options =
+ req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE;
+
+ code = encode_krb5_s4u_userid(&rep_s4u_user.user_id, &data);
+ if (code != 0)
+ goto cleanup;
+
+ if (req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE)
+ usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY;
+ else
+ usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST;
+
+ code = krb5_c_make_checksum(context, req_s4u_user->cksum.checksum_type,
+ tgs_subkey != NULL ? tgs_subkey : tgs_session,
+ usage, data,
+ &rep_s4u_user.cksum);
+ if (code != 0)
+ goto cleanup;
+
+ krb5_free_data(context, data);
+ data = NULL;
+
+ code = encode_krb5_pa_s4u_x509_user(&rep_s4u_user, &data);
+ if (code != 0)
+ goto cleanup;
+
+ padata.magic = KV5M_PA_DATA;
+ padata.pa_type = KRB5_PADATA_S4U_X509_USER;
+ padata.length = data->length;
+ padata.contents = (krb5_octet *)data->data;
+
+ code = add_pa_data_element(context, &padata, &reply->padata, FALSE);
+ if (code != 0)
+ goto cleanup;
+
+ free(data);
+ data = NULL;
+
+ if (tgs_subkey != NULL)
+ enctype = tgs_subkey->enctype;
+ else
+ enctype = tgs_session->enctype;
+
/*
- * Check against local policy
+ * Owing to a bug in Windows, unkeyed checksums were used for older
+ * enctypes, including rc4-hmac. A forthcoming workaround for this
+ * includes the checksum bytes in the encrypted padata.
*/
- errcode = against_local_policy_as(request, *client, server,
- kdc_time, status);
- if (errcode)
- return errcode;
+ if ((req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE) &&
+ enctype_requires_etype_info_2(enctype) == FALSE) {
+ padata.length = req_s4u_user->cksum.length +
+ rep_s4u_user.cksum.length;
+ padata.contents = malloc(padata.length);
+ if (padata.contents == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
- return 0;
+ memcpy(padata.contents,
+ req_s4u_user->cksum.contents,
+ req_s4u_user->cksum.length);
+ memcpy(&padata.contents[req_s4u_user->cksum.length],
+ rep_s4u_user.cksum.contents,
+ rep_s4u_user.cksum.length);
+
+ code = add_pa_data_element(context,&padata,
+ &reply_encpart->enc_padata, FALSE);
+ if (code != 0)
+ goto cleanup;
+ }
+
+cleanup:
+ if (rep_s4u_user.cksum.contents != NULL)
+ krb5_free_checksum_contents(context, &rep_s4u_user.cksum);
+ krb5_free_data(context, data);
+
+ return code;
}
/*
krb5_kdc_req *request,
krb5_const_principal client_princ,
const krb5_db_entry *server,
- krb5_keyblock *subkey,
+ krb5_keyblock *tgs_subkey,
+ krb5_keyblock *tgs_session,
krb5_timestamp kdc_time,
- krb5_pa_for_user **for_user,
+ krb5_pa_s4u_x509_user **s4u_x509_user,
krb5_db_entry *princ,
int *nprincs,
const char **status)
{
krb5_error_code code;
- krb5_pa_data **pa_data;
- krb5_data req_data;
+ krb5_pa_data *pa_data;
krb5_boolean more;
+ int flags;
*nprincs = 0;
memset(princ, 0, sizeof(*princ));
- if (request->padata == NULL) {
- return 0;
- }
-
- for (pa_data = request->padata; *pa_data != NULL; pa_data++) {
- if ((*pa_data)->pa_type == KRB5_PADATA_FOR_USER)
- break;
- }
- if (*pa_data == NULL) {
- return 0;
+ pa_data = find_pa_data(request->padata, KRB5_PADATA_S4U_X509_USER);
+ if (pa_data != NULL) {
+ code = kdc_process_s4u_x509_user(context,
+ request,
+ pa_data,
+ tgs_subkey,
+ tgs_session,
+ s4u_x509_user,
+ status);
+ if (code != 0)
+ return code;
+ } else {
+ pa_data = find_pa_data(request->padata, KRB5_PADATA_FOR_USER);
+ if (pa_data != NULL) {
+ code = kdc_process_for_user(context,
+ pa_data,
+ tgs_session,
+ s4u_x509_user,
+ status);
+ if (code != 0)
+ return code;
+ } else
+ return 0;
}
-#if 0
/*
- * Ignore request if the server principal is a TGS, not so much
- * to avoid unconstrained tickets being issued (as that would
- * require knowing the TGS key anyway) but so that we do not
- * block the server referral path.
+ * We need to compare the client name in the TGT with the requested
+ * server name. Supporting server name aliases without assuming a
+ * global name service makes this difficult to do.
+ *
+ * The comparison below handles the following cases (note that the
+ * term "principal name" below excludes the realm).
+ *
+ * (1) The requested service is a host-based service with two name
+ * components, in which case we assume the principal name to
+ * contain sufficient qualifying information. The realm is
+ * ignored for the purpose of comparison.
+ *
+ * (2) The requested service name is an enterprise principal name:
+ * the service principal name is compared with the unparsed
+ * form of the client name (including its realm).
+ *
+ * (3) The requested service is some other name type: an exact
+ * match is required.
+ *
+ * An alternative would be to look up the server once again with
+ * FLAG_CANONICALIZE | FLAG_CLIENT_REFERRALS_ONLY set, do an exact
+ * match between the returned name and client_princ. However, this
+ * assumes that the client set FLAG_CANONICALIZE when requesting
+ * the TGT and that we have a global name service.
*/
- if (krb5_is_tgs_principal(server->princ)) {
- return 0;
- }
-#endif
-
- *status = "PROCESS_S4U2SELF_REQUEST";
-
- req_data.length = (*pa_data)->length;
- req_data.data = (char *)(*pa_data)->contents;
-
- code = decode_krb5_pa_for_user(&req_data, for_user);
- if (code) {
- return code;
- }
-
- if (krb5_princ_type(context, (*for_user)->user) !=
- KRB5_NT_ENTERPRISE_PRINCIPAL) {
- *status = "INVALID_S4U2SELF_REQUEST";
- return KRB5KDC_ERR_POLICY;
+ flags = 0;
+ switch (krb5_princ_type(kdc_context, request->server)) {
+ case KRB5_NT_SRV_HST: /* (1) */
+ if (krb5_princ_size(kdc_context, request->server) == 2)
+ flags |= KRB5_PRINCIPAL_COMPARE_IGNORE_REALM;
+ break;
+ case KRB5_NT_ENTERPRISE_PRINCIPAL: /* (2) */
+ flags |= KRB5_PRINCIPAL_COMPARE_ENTERPRISE;
+ break;
+ default: /* (3) */
+ break;
}
- code = verify_s4u2self_checksum(context, subkey, *for_user);
- if (code) {
- *status = "INVALID_S4U2SELF_CHECKSUM";
- krb5_free_pa_for_user(kdc_context, *for_user);
- *for_user = NULL;
- return code;
- }
- if (!krb5_principal_compare_flags(context, request->server, client_princ,
- KRB5_PRINCIPAL_COMPARE_ENTERPRISE)) {
+ if (!krb5_principal_compare_flags(context,
+ request->server,
+ client_princ,
+ flags)) {
*status = "INVALID_S4U2SELF_REQUEST";
- return KRB5KDC_ERR_POLICY;
+ return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; /* match Windows error code */
}
/*
* Protocol transition is mutually exclusive with renew/forward/etc
- * as well as user-to-user and constrained delegation.
+ * as well as user-to-user and constrained delegation. This check
+ * is also made in validate_as_request().
*
* We can assert from this check that the header ticket was a TGT, as
* that is validated previously in validate_tgs_request().
*/
- if (request->kdc_options & (NO_TGT_OPTION | KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)) {
+ if (request->kdc_options & AS_INVALID_OPTIONS) {
+ *status = "INVALID AS OPTIONS";
return KRB5KDC_ERR_BADOPTION;
}
/*
* Do not attempt to lookup principals in foreign realms.
*/
- if (is_local_principal((*for_user)->user)) {
+ if (is_local_principal((*s4u_x509_user)->user_id.user)) {
+ krb5_db_entry no_server;
+
*nprincs = 1;
code = krb5_db_get_principal_ext(kdc_context,
- (*for_user)->user,
+ (*s4u_x509_user)->user_id.user,
KRB5_KDB_FLAG_INCLUDE_PAC,
princ, nprincs, &more);
if (code) {
return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
}
- code = validate_s4u2self_request(request, princ, kdc_time, status);
+ memset(&no_server, 0, sizeof(no_server));
+
+ code = validate_as_request(request, *princ,
+ no_server, kdc_time, status);
if (code) {
return code;
}
}
- *status = NULL;
-
return 0;
}
/* Must be in same realm */
if (!krb5_realm_compare(context, server->princ, proxy)) {
- return KRB5KDC_ERR_BADOPTION;
+ return KRB5KDC_ERR_POLICY;
}
req.server = server;
/* OpenSolaris: audit_krb5kdc_tgs_req_alt_tgt(...) */
}
+krb5_boolean
+enctype_requires_etype_info_2(krb5_enctype enctype)
+{
+ switch(enctype) {
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES_CBC_MD4:
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES3_CBC_SHA1:
+ case ENCTYPE_DES3_CBC_RAW:
+ case ENCTYPE_ARCFOUR_HMAC:
+ case ENCTYPE_ARCFOUR_HMAC_EXP :
+ return 0;
+ default:
+ return krb5_c_valid_enctype(enctype);
+ }
+}
+
+/* XXX where are the generic helper routines for this? */
+krb5_error_code
+add_pa_data_element(krb5_context context,
+ krb5_pa_data *padata,
+ krb5_pa_data ***inout_padata,
+ krb5_boolean copy)
+{
+ int i;
+ krb5_pa_data **p;
+
+ if (*inout_padata != NULL) {
+ for (i = 0; (*inout_padata)[i] != NULL; i++)
+ ;
+ } else
+ i = 0;
+
+ p = realloc(*inout_padata, (i + 2) * sizeof(krb5_pa_data *));
+ if (p == NULL)
+ return ENOMEM;
+
+ *inout_padata = p;
+
+ p[i] = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
+ if (p[i] == NULL)
+ return ENOMEM;
+ *(p[i]) = *padata;
+
+ p[i + 1] = NULL;
+
+ if (copy) {
+ p[i]->contents = (krb5_octet *)malloc(padata->length);
+ if (p[i]->contents == NULL) {
+ free(p[i]);
+ p[i] = NULL;
+ return ENOMEM;
+ }
+
+ memcpy(p[i]->contents, padata->contents, padata->length);
+ }
+
+ return 0;
+}
+
krb5_ticket *, const char **);
/* kdc_preauth.c */
+krb5_boolean enctype_requires_etype_info_2(krb5_enctype enctype);
+
const char * missing_required_preauth
(krb5_db_entry *client, krb5_db_entry *server,
krb5_enc_tkt_part *enc_tkt_reply);
krb5_pa_data *find_pa_data
(krb5_pa_data **padata, krb5_preauthtype pa_type);
+krb5_error_code add_pa_data_element
+ (krb5_context context,
+ krb5_pa_data *padata,
+ krb5_pa_data ***out_padata,
+ krb5_boolean copy);
+
/* kdc_authdata.c */
krb5_error_code load_authdata_plugins(krb5_context context);
krb5_error_code unload_authdata_plugins(krb5_context context);
krb5_kdc_req *request,
krb5_const_principal client_princ,
const krb5_db_entry *server,
- krb5_keyblock *subkey,
+ krb5_keyblock *tgs_subkey,
+ krb5_keyblock *tgs_session,
krb5_timestamp kdc_time,
- krb5_pa_for_user **s4u2_req,
+ krb5_pa_s4u_x509_user **s4u2self_req,
krb5_db_entry *princ,
int *nprincs,
const char **status);
+krb5_error_code kdc_make_s4u2self_rep
+ (krb5_context context,
+ krb5_keyblock *tgs_subkey,
+ krb5_keyblock *tgs_session,
+ krb5_pa_s4u_x509_user *req_s4u_user,
+ krb5_kdc_rep *reply,
+ krb5_enc_kdc_rep_part *reply_encpart);
+
krb5_error_code kdc_process_s4u2proxy_req
(krb5_context context,
krb5_kdc_req *request,
myfulldir=lib/crypto
mydir=lib/crypto
BUILDTOP=$(REL)..$(S)..
-SUBDIRS=krb builtin crypto_tests
+SUBDIRS= builtin krb crypto_tests
RUN_SETUP = @KRB5_RUN_ENV@
PROG_LIBPATH=-L$(TOPLIBD)
LIBFINIFUNC=cryptoint_cleanup_library
RELDIR=crypto
-STOBJLISTS=krb/crc32/OBJS.ST krb/dk/OBJS.ST krb/enc_provider/OBJS.ST \
- krb/hash_provider/OBJS.ST krb/keyhash_provider/OBJS.ST \
- krb/old/OBJS.ST krb/raw/OBJS.ST krb/yarrow/OBJS.ST \
- @CRYPTO_IMPL@/md4/OBJS.ST @CRYPTO_IMPL@/md5/OBJS.ST @CRYPTO_IMPL@/sha1/OBJS.ST \
- @CRYPTO_IMPL@/arcfour/OBJS.ST @CRYPTO_IMPL@/aes/OBJS.ST @CRYPTO_IMPL@/des/OBJS.ST \
- krb/OBJS.ST @CRYPTO_IMPL@/OBJS.ST
+STOBJLISTS=krb/crc32/OBJS.ST krb/dk/OBJS.ST builtin/enc_provider/OBJS.ST \
+ krb/hash_provider/OBJS.ST krb/keyhash_provider/OBJS.ST \
+ krb/old/OBJS.ST krb/raw/OBJS.ST krb/yarrow/OBJS.ST \
+ builtin/md4/OBJS.ST builtin/md5/OBJS.ST builtin/sha1/OBJS.ST \
+ builtin/arcfour/OBJS.ST builtin/aes/OBJS.ST builtin/des/OBJS.ST \
+ krb/OBJS.ST builtin/OBJS.ST
-SUBDIROBJLISTS=krb/crc32/OBJS.ST krb/dk/OBJS.ST krb/enc_provider/OBJS.ST \
- krb/hash_provider/OBJS.ST krb/keyhash_provider/OBJS.ST \
+SUBDIROBJLISTS=krb/crc32/OBJS.ST krb/dk/OBJS.ST builtin/enc_provider/OBJS.ST \
+ krb/hash_provider/OBJS.ST krb/keyhash_provider/OBJS.ST \
krb/old/OBJS.ST krb/raw/OBJS.ST krb/yarrow/OBJS.ST \
- @CRYPTO_IMPL@/md4/OBJS.ST @CRYPTO_IMPL@/md5/OBJS.ST @CRYPTO_IMPL@/sha1/OBJS.ST \
- @CRYPTO_IMPL@/arcfour/OBJS.ST @CRYPTO_IMPL@/aes/OBJS.ST @CRYPTO_IMPL@/des/OBJS.ST \
- krb/OBJS.ST @CRYPTO_IMPL@/OBJS.ST
+ builtin/md4/OBJS.ST builtin/md5/OBJS.ST builtin/sha1/OBJS.ST \
+ builtin/arcfour/OBJS.ST builtin/aes/OBJS.ST builtin/des/OBJS.ST \
+ krb/OBJS.ST builtin/OBJS.ST
# No dependencies. Record places to find this shared object if the target
# link editor and loader support it.
myfulldir=lib/crypto/builtin
mydir=lib/crypto/builtin
BUILDTOP=$(REL)..$(S)..$(S)..
-SUBDIRS=../@CRYPTO_IMPL@/des ../@CRYPTO_IMPL@/arcfour ../@CRYPTO_IMPL@/aes \
- ../@CRYPTO_IMPL@/md4 ../@CRYPTO_IMPL@/md5 ../@CRYPTO_IMPL@/sha1
-LOCALINCLUDES = -I$(srcdir)/../krb -I$(srcdir)/../krb/hash_provider \
+SUBDIRS=des arcfour aes md4 md5 sha1 enc_provider
+LOCALINCLUDES = -I$(srcdir)/../krb \
+ -I$(srcdir)/../krb/hash_provider \
-I$(srcdir)/../@CRYPTO_IMPL@/des \
-I$(srcdir)/../@CRYPTO_IMPL@/aes \
-I$(srcdir)/../@CRYPTO_IMPL@/arcfour \
-I$(srcdir)/../@CRYPTO_IMPL@/sha1 \
-I$(srcdir)/../@CRYPTO_IMPL@/md4 \
- -I$(srcdir)/../@CRYPTO_IMPL@/md5
+ -I$(srcdir)/../@CRYPTO_IMPL@/md5 \
+ -I$(srcdir)/../@CRYPTO_IMPL@/enc_provider
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
DEFS=
##DOSOBJFILEDEP =$(OUTPRE)crypto.lst $(OUTPRE)des.lst $(OUTPRE)md4.lst $(OUTPRE)md5.lst $(OUTPRE)sha1.lst $(OUTPRE)arcfour.lst $(OUTPRE)crc32.lst $(OUTPRE)dk.lst $(OUTPRE)old.lst $(OUTPRE)raw.lst $(OUTPRE)enc_prov.lst $(OUTPRE)hash_pro.lst $(OUTPRE)kh_pro.lst $(OUTPRE)aes.lst
STLIBOBJS=\
- hmac.o \
- pbkdf2.o
+ ../@CRYPTO_IMPL@/hmac.o \
+ ../@CRYPTO_IMPL@/pbkdf2.o
OBJS=\
$(OUTPRE)../@CRYPTO_IMPL@/hmac.$(OBJEXT) \
$(srcdir)/../@CRYPTO_IMPL@/hmac.c \
$(srcdir)/../@CRYPTO_IMPL@/pbkdf2.c
-STOBJLISTS= ../@CRYPTO_IMPL@/des/OBJS.ST ../@CRYPTO_IMPL@/md4/OBJS.ST \
- ../@CRYPTO_IMPL@/md5/OBJS.ST ../@CRYPTO_IMPL@/sha1/OBJS.ST \
- ../@CRYPTO_IMPL@/arcfour/OBJS.ST \
- ../@CRYPTO_IMPL@/aes/OBJS.ST \
- ../@CRYPTO_IMPL@/OBJS.ST
+STOBJLISTS= des/OBJS.ST md4/OBJS.ST \
+ md5/OBJS.ST sha1/OBJS.ST \
+ enc_provider/OBJS.ST \
+ arcfour/OBJS.ST \
+ aes/OBJS.ST \
+ OBJS.ST
-SUBDIROBJLISTS= ../@CRYPTO_IMPL@/des/OBJS.ST ../@CRYPTO_IMPL@/md4/OBJS.ST \
- ../@CRYPTO_IMPL@/md5/OBJS.ST ../@CRYPTO_IMPL@/sha1/OBJS.ST \
- ../@CRYPTO_IMPL@/arcfour/OBJS.ST \
- ../@CRYPTO_IMPL@/aes/OBJS.ST ../@CRYPTO_IMPL@/OBJS.ST
+SUBDIROBJLISTS= des/OBJS.ST md4/OBJS.ST \
+ md5/OBJS.ST sha1/OBJS.ST \
+ enc_provider/OBJS.ST \
+ arcfour/OBJS.ST \
+ aes/OBJS.ST OBJS.ST
##DOS##LIBOBJS = $(OBJS)
cd ..\sha1
@echo Making in crypto\sha1
$(MAKE) -$(MFLAGS)
+ cd ..\enc_provider
+ @echo Making in crypto\enc_provider
+ $(MAKE) -$(MFLAGS)
cd ..\arcfour
@echo Making in crypto\arcfour
$(MAKE) -$(MFLAGS)
cd ..\sha1
@echo Making clean in crypto\sha1
$(MAKE) -$(MFLAGS) clean
+ cd ..\enc_provider
+ @echo Making clean in crypto\enc_provider
+ $(MAKE) -$(MFLAGS) clean
cd ..\arcfour
@echo Making clean in crypto\arcfour
$(MAKE) -$(MFLAGS) clean
cd ..\sha1
@echo Making check in crypto\sha1
$(MAKE) -$(MFLAGS) check
+ cd ..\enc_provider
+ @echo Making check in crypto\enc_provider
+ $(MAKE) -$(MFLAGS) check
cd ..\arcfour
@echo Making check in crypto\arcfour
$(MAKE) -$(MFLAGS) check
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
+CIMPL = @CRYPTO_IMPL@/aes
+
STLIBOBJS=\
- aescrypt.o \
- aestab.o \
- aeskey.o \
- aes_s2k.o
+ ../../$(CIMPL)/aescrypt.o \
+ ../../$(CIMPL)/aestab.o \
+ ../../$(CIMPL)/aeskey.o \
+ ../../$(CIMPL)/aes_s2k.o
OBJS=\
- $(OUTPRE)aescrypt.$(OBJEXT) \
- $(OUTPRE)aestab.$(OBJEXT) \
- $(OUTPRE)aeskey.$(OBJEXT) \
- $(OUTPRE)aes_s2k.$(OBJEXT)
+ $(OUTPRE)../../$(CIMPL)/aescrypt.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/aestab.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/aeskey.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/aes_s2k.$(OBJEXT)
SRCS=\
- $(srcdir)/aescrypt.c \
- $(srcdir)/aestab.c \
- $(srcdir)/aeskey.c \
- $(srcdir)/aes_s2k.c
+ $(srcdir)..//../$(CIMPL)/aescrypt.c \
+ $(srcdir)..//../$(CIMPL)/aestab.c \
+ $(srcdir)/../../$(CIMPL)/aeskey.c \
+ $(srcdir)/../../$(CIMPL)/aes_s2k.c
GEN_OBJS=\
- $(OUTPRE)aescrypt.$(OBJEXT) \
- $(OUTPRE)aestab.$(OBJEXT) \
- $(OUTPRE)aeskey.$(OBJEXT)
+ $(OUTPRE)../../$(CIMPL)/aescrypt.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/aestab.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/aeskey.$(OBJEXT)
##DOS##LIBOBJS = $(OBJS)
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
+CIMPL = @CRYPTO_IMPL@/arcfour
+
STLIBOBJS=\
- arcfour.o \
- arcfour_aead.o \
- arcfour_s2k.o
+ ../../$(CIMPL)/arcfour.o \
+ ../../$(CIMPL)/arcfour_aead.o \
+ ../../$(CIMPL)/arcfour_s2k.o
OBJS=\
- $(OUTPRE)arcfour.$(OBJEXT) \
- $(OUTPRE)arcfour_aead.$(OBJEXT) \
- $(OUTPRE)arcfour_s2k.$(OBJEXT)
+ $(OUTPRE)../../$(CIMPL)/arcfour.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/arcfour_aead.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/arcfour_s2k.$(OBJEXT)
SRCS=\
- $(srcdir)/arcfour.c \
- $(srcdir)/arcfour_aead.c\
- $(srcdir)/arcfour_s2k.c
+ $(srcdir)/../../$(CIMPL)/arcfour.c \
+ $(srcdir)/../../$(CIMPL)/arcfour_aead.c\
+ $(srcdir)/../../$(CIMPL)/arcfour_s2k.c
##DOS##LIBOBJS = $(OBJS)
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
+CIMPL = @CRYPTO_IMPL@/des
+
STLIBOBJS=\
- afsstring2key.o \
- d3_cbc.o \
- d3_aead.o \
- d3_kysched.o \
- des_prf.o \
- f_aead.o \
- f_cbc.o \
- f_cksum.o \
- f_parity.o \
- f_sched.o \
- f_tables.o \
- key_sched.o \
- string2key.o \
- weak_key.o
+ ../../$(CIMPL)/afsstring2key.o \
+ ../../$(CIMPL)/d3_cbc.o \
+ ../../$(CIMPL)/d3_aead.o \
+ ../../$(CIMPL)/d3_kysched.o \
+ ../../$(CIMPL)/des_prf.o \
+ ../../$(CIMPL)/f_aead.o \
+ ../../$(CIMPL)/f_cbc.o \
+ ../../$(CIMPL)/f_cksum.o \
+ ../../$(CIMPL)/f_parity.o \
+ ../../$(CIMPL)/f_sched.o \
+ ../../$(CIMPL)/f_tables.o \
+ ../../$(CIMPL)/key_sched.o \
+ ../../$(CIMPL)/string2key.o \
+ ../../$(CIMPL)/weak_key.o
-OBJS= $(OUTPRE)afsstring2key.$(OBJEXT) \
- $(OUTPRE)d3_cbc.$(OBJEXT) \
- $(OUTPRE)d3_aead.$(OBJEXT) \
- $(OUTPRE)d3_kysched.$(OBJEXT) \
- $(OUTPRE)des_prf.$(OBJEXT) \
- $(OUTPRE)f_aead.$(OBJEXT) \
- $(OUTPRE)f_cbc.$(OBJEXT) \
- $(OUTPRE)f_cksum.$(OBJEXT) \
- $(OUTPRE)f_parity.$(OBJEXT) \
- $(OUTPRE)f_sched.$(OBJEXT) \
- $(OUTPRE)f_tables.$(OBJEXT) \
- $(OUTPRE)key_sched.$(OBJEXT) \
- $(OUTPRE)string2key.$(OBJEXT) \
- $(OUTPRE)weak_key.$(OBJEXT)
+OBJS= $(OUTPRE)../../$(CIMPL)/afsstring2key.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/d3_cbc.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/d3_aead.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/d3_kysched.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/des_prf.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/f_aead.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/f_cbc.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/f_cksum.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/f_parity.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/f_sched.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/f_tables.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/key_sched.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/string2key.$(OBJEXT) \
+ $(OUTPRE)../../$(CIMPL)/weak_key.$(OBJEXT)
-SRCS= $(srcdir)/afsstring2key.c \
- $(srcdir)/d3_cbc.c \
- $(srcdir)/d3_aead.c \
- $(srcdir)/d3_kysched.c \
- $(srcdir)/des_prf.c \
- $(srcdir)/f_aead.c \
- $(srcdir)/f_cbc.c \
- $(srcdir)/f_cksum.c \
- $(srcdir)/f_parity.c \
- $(srcdir)/f_sched.c \
- $(srcdir)/f_tables.c \
- $(srcdir)/key_sched.c \
- $(srcdir)/weak_key.c \
- $(srcdir)/string2key.c
+SRCS= $(srcdir)/../../$(CIMPL)/afsstring2key.c \
+ $(srcdir)/../../$(CIMPL)/d3_cbc.c \
+ $(srcdir)/../../$(CIMPL)/d3_aead.c \
+ $(srcdir)/../../$(CIMPL)/d3_kysched.c \
+ $(srcdir)/../../$(CIMPL)/des_prf.c \
+ $(srcdir)/../../$(CIMPL)/f_aead.c \
+ $(srcdir)/../../$(CIMPL)/f_cbc.c \
+ $(srcdir)/../../$(CIMPL)/f_cksum.c \
+ $(srcdir)/../../$(CIMPL)/f_parity.c \
+ $(srcdir)/../../$(CIMPL)/f_sched.c \
+ $(srcdir)/../../$(CIMPL)/f_tables.c \
+ $(srcdir)/../../$(CIMPL)/key_sched.c \
+ $(srcdir)/../../$(CIMPL)/weak_key.c \
+ $(srcdir)/../../$(CIMPL)/string2key.c
##DOS##LIBOBJS = $(OBJS)
--- /dev/null
+thisconfigdir=../../../..
+myfulldir=lib/crypto/builtin/enc_provider
+mydir=lib/crypto/builtin/enc_provider
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/../../@CRYPTO_IMPL@/des \
+ -I$(srcdir)/../../@CRYPTO_IMPL@/arcfour \
+ -I$(srcdir)/../../@CRYPTO_IMPL@/aes \
+ -I$(srcdir)/../../krb \
+ -I$(srcdir)/.. -I$(srcdir)/../../@CRYPTO_IMPL@
+DEFS=
+
+##DOS##BUILDTOP = ..\..\..\..
+##DOS##PREFIXDIR=enc_provider
+##DOS##OBJFILE=..\$(OUTPRE)enc_prov.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+STLIBOBJS= \
+ ../../@CRYPTO_IMPL@/enc_provider/des.o \
+ ../../@CRYPTO_IMPL@/enc_provider/des3.o \
+ ../../@CRYPTO_IMPL@/enc_provider/rc4.o \
+ ../../@CRYPTO_IMPL@/enc_provider/aes.o
+
+OBJS= \
+ $(OUTPRE)../../@CRYPTO_IMPL@/enc_provider/des.$(OBJEXT) \
+ $(OUTPRE)../../@CRYPTO_IMPL@/enc_provider/des3.$(OBJEXT) \
+ $(OUTPRE)../../@CRYPTO_IMPL@/enc_provider/aes.$(OBJEXT) \
+ $(OUTPRE)../../@CRYPTO_IMPL@/enc_provider/rc4.$(OBJEXT)
+
+SRCS= \
+ $(srcdir)/../../@CRYPTO_IMPL@/enc_provider/des.c \
+ $(srcdir)/../../@CRYPTO_IMPL@/enc_provider/des3.c \
+ $(srcdir)/../../@CRYPTO_IMPL@/enc_provider/aes.c \
+ $(srcdir)/../../@CRYPTO_IMPL@/enc_provider/rc4.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+@libobj_frag@
+
--- /dev/null
+/*
+ * lib/crypto/enc_provider/aes.c
+ *
+ * Copyright (C) 2003, 2007, 2008 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "enc_provider.h"
+#include "aes.h"
+#include <aead.h>
+
+#if 0
+aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]);
+aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+#endif
+
+#define CHECK_SIZES 0
+
+#if 0
+static void printd (const char *descr, krb5_data *d) {
+ int i, j;
+ const int r = 16;
+
+ printf("%s:", descr);
+
+ for (i = 0; i < d->length; i += r) {
+ printf("\n %04x: ", i);
+ for (j = i; j < i + r && j < d->length; j++)
+ printf(" %02x", 0xff & d->data[j]);
+#ifdef SHOW_TEXT
+ for (; j < i + r; j++)
+ printf(" ");
+ printf(" ");
+ for (j = i; j < i + r && j < d->length; j++) {
+ int c = 0xff & d->data[j];
+ printf("%c", isprint(c) ? c : '.');
+ }
+#endif
+ }
+ printf("\n");
+}
+#endif
+
+static inline void enc(char *out, const char *in, aes_ctx *ctx)
+{
+ if (aes_enc_blk((const unsigned char *)in, (unsigned char *)out, ctx)
+ != aes_good)
+ abort();
+}
+static inline void dec(char *out, const char *in, aes_ctx *ctx)
+{
+ if (aes_dec_blk((const unsigned char *)in, (unsigned char *)out, ctx)
+ != aes_good)
+ abort();
+}
+
+static void xorblock(char *out, const char *in)
+{
+ int z;
+ for (z = 0; z < BLOCK_SIZE; z++)
+ out[z] ^= in[z];
+}
+
+krb5_error_code
+krb5int_aes_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+ aes_ctx ctx;
+ char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+ int nblocks = 0, blockno;
+
+/* CHECK_SIZES; */
+
+ if (aes_enc_key(key->contents, key->length, &ctx) != aes_good)
+ abort();
+
+ if (ivec)
+ memcpy(tmp, ivec->data, BLOCK_SIZE);
+ else
+ memset(tmp, 0, BLOCK_SIZE);
+
+ nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+ if (nblocks == 1) {
+ /* XXX Used for DK function. */
+ enc(output->data, input->data, &ctx);
+ } else {
+ unsigned int nleft;
+
+ for (blockno = 0; blockno < nblocks - 2; blockno++) {
+ xorblock(tmp, input->data + blockno * BLOCK_SIZE);
+ enc(tmp2, tmp, &ctx);
+ memcpy(output->data + blockno * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+
+ /* Set up for next block. */
+ memcpy(tmp, tmp2, BLOCK_SIZE);
+ }
+ /* Do final CTS step for last two blocks (the second of which
+ may or may not be incomplete). */
+ xorblock(tmp, input->data + (nblocks - 2) * BLOCK_SIZE);
+ enc(tmp2, tmp, &ctx);
+ nleft = input->length - (nblocks - 1) * BLOCK_SIZE;
+ memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2, nleft);
+ memcpy(tmp, tmp2, BLOCK_SIZE);
+
+ memset(tmp3, 0, sizeof(tmp3));
+ memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE, nleft);
+ xorblock(tmp, tmp3);
+ enc(tmp2, tmp, &ctx);
+ memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+ if (ivec)
+ memcpy(ivec->data, tmp2, BLOCK_SIZE);
+ }
+
+ return 0;
+}
+
+krb5_error_code
+krb5int_aes_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+ aes_ctx ctx;
+ char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+ int nblocks = 0, blockno;
+
+ CHECK_SIZES;
+
+ if (aes_dec_key(key->contents, key->length, &ctx) != aes_good)
+ abort();
+
+ if (ivec)
+ memcpy(tmp, ivec->data, BLOCK_SIZE);
+ else
+ memset(tmp, 0, BLOCK_SIZE);
+
+ nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+ if (nblocks == 1) {
+ if (input->length < BLOCK_SIZE)
+ abort();
+ dec(output->data, input->data, &ctx);
+ } else {
+
+ for (blockno = 0; blockno < nblocks - 2; blockno++) {
+ dec(tmp2, input->data + blockno * BLOCK_SIZE, &ctx);
+ xorblock(tmp2, tmp);
+ memcpy(output->data + blockno * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+ memcpy(tmp, input->data + blockno * BLOCK_SIZE, BLOCK_SIZE);
+ }
+ /* Do last two blocks, the second of which (next-to-last block
+ of plaintext) may be incomplete. */
+ dec(tmp2, input->data + (nblocks - 2) * BLOCK_SIZE, &ctx);
+ /* Set tmp3 to last ciphertext block, padded. */
+ memset(tmp3, 0, sizeof(tmp3));
+ memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE,
+ input->length - (nblocks - 1) * BLOCK_SIZE);
+ /* Set tmp2 to last (possibly partial) plaintext block, and
+ save it. */
+ xorblock(tmp2, tmp3);
+ memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2,
+ input->length - (nblocks - 1) * BLOCK_SIZE);
+ /* Maybe keep the trailing part, and copy in the last
+ ciphertext block. */
+ memcpy(tmp2, tmp3, input->length - (nblocks - 1) * BLOCK_SIZE);
+ /* Decrypt, to get next to last plaintext block xor previous
+ ciphertext. */
+ dec(tmp3, tmp2, &ctx);
+ xorblock(tmp3, tmp);
+ memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, tmp3, BLOCK_SIZE);
+ if (ivec)
+ memcpy(ivec->data, input->data + (nblocks - 2) * BLOCK_SIZE,
+ BLOCK_SIZE);
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+krb5int_aes_encrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ aes_ctx ctx;
+ char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE];
+ int nblocks = 0, blockno;
+ size_t input_length, i;
+
+ if (aes_enc_key(key->contents, key->length, &ctx) != aes_good)
+ abort();
+
+ if (ivec != NULL)
+ memcpy(tmp, ivec->data, BLOCK_SIZE);
+ else
+ memset(tmp, 0, BLOCK_SIZE);
+
+ for (i = 0, input_length = 0; i < num_data; i++) {
+ krb5_crypto_iov *iov = &data[i];
+
+ if (ENCRYPT_IOV(iov))
+ input_length += iov->data.length;
+ }
+
+ nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+ assert(nblocks > 1);
+
+ {
+ char blockN2[BLOCK_SIZE]; /* second last */
+ char blockN1[BLOCK_SIZE]; /* last block */
+ struct iov_block_state input_pos, output_pos;
+
+ IOV_BLOCK_STATE_INIT(&input_pos);
+ IOV_BLOCK_STATE_INIT(&output_pos);
+
+ for (blockno = 0; blockno < nblocks - 2; blockno++) {
+ char blockN[BLOCK_SIZE];
+
+ krb5int_c_iov_get_block((unsigned char *)blockN, BLOCK_SIZE, data, num_data, &input_pos);
+ xorblock(tmp, blockN);
+ enc(tmp2, tmp, &ctx);
+ krb5int_c_iov_put_block(data, num_data, (unsigned char *)tmp2, BLOCK_SIZE, &output_pos);
+
+ /* Set up for next block. */
+ memcpy(tmp, tmp2, BLOCK_SIZE);
+ }
+
+ /* Do final CTS step for last two blocks (the second of which
+ may or may not be incomplete). */
+
+ /* First, get the last two blocks */
+ memset(blockN1, 0, sizeof(blockN1)); /* pad last block with zeros */
+ krb5int_c_iov_get_block((unsigned char *)blockN2, BLOCK_SIZE, data, num_data, &input_pos);
+ krb5int_c_iov_get_block((unsigned char *)blockN1, BLOCK_SIZE, data, num_data, &input_pos);
+
+ /* Encrypt second last block */
+ xorblock(tmp, blockN2);
+ enc(tmp2, tmp, &ctx);
+ memcpy(blockN2, tmp2, BLOCK_SIZE); /* blockN2 now contains first block */
+ memcpy(tmp, tmp2, BLOCK_SIZE);
+
+ /* Encrypt last block */
+ xorblock(tmp, blockN1);
+ enc(tmp2, tmp, &ctx);
+ memcpy(blockN1, tmp2, BLOCK_SIZE);
+
+ /* Put the last two blocks back into the iovec (reverse order) */
+ krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN1, BLOCK_SIZE, &output_pos);
+ krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN2, BLOCK_SIZE, &output_pos);
+
+ if (ivec != NULL)
+ memcpy(ivec->data, blockN1, BLOCK_SIZE);
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+krb5int_aes_decrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ aes_ctx ctx;
+ char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+ int nblocks = 0, blockno;
+ unsigned int i;
+ size_t input_length;
+
+ CHECK_SIZES;
+
+ if (aes_dec_key(key->contents, key->length, &ctx) != aes_good)
+ abort();
+
+ if (ivec != NULL)
+ memcpy(tmp, ivec->data, BLOCK_SIZE);
+ else
+ memset(tmp, 0, BLOCK_SIZE);
+
+ for (i = 0, input_length = 0; i < num_data; i++) {
+ krb5_crypto_iov *iov = &data[i];
+
+ if (ENCRYPT_IOV(iov))
+ input_length += iov->data.length;
+ }
+
+ nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+ assert(nblocks > 1);
+
+ {
+ char blockN2[BLOCK_SIZE]; /* second last */
+ char blockN1[BLOCK_SIZE]; /* last block */
+ struct iov_block_state input_pos, output_pos;
+
+ IOV_BLOCK_STATE_INIT(&input_pos);
+ IOV_BLOCK_STATE_INIT(&output_pos);
+
+ for (blockno = 0; blockno < nblocks - 2; blockno++) {
+ char blockN[BLOCK_SIZE];
+
+ krb5int_c_iov_get_block((unsigned char *)blockN, BLOCK_SIZE, data, num_data, &input_pos);
+ dec(tmp2, blockN, &ctx);
+ xorblock(tmp2, tmp);
+ krb5int_c_iov_put_block(data, num_data, (unsigned char *)tmp2, BLOCK_SIZE, &output_pos);
+ memcpy(tmp, blockN, BLOCK_SIZE);
+ }
+
+ /* Do last two blocks, the second of which (next-to-last block
+ of plaintext) may be incomplete. */
+
+ /* First, get the last two encrypted blocks */
+ memset(blockN1, 0, sizeof(blockN1)); /* pad last block with zeros */
+ krb5int_c_iov_get_block((unsigned char *)blockN2, BLOCK_SIZE, data, num_data, &input_pos);
+ krb5int_c_iov_get_block((unsigned char *)blockN1, BLOCK_SIZE, data, num_data, &input_pos);
+
+ /* Decrypt second last block */
+ dec(tmp2, blockN2, &ctx);
+ /* Set tmp2 to last (possibly partial) plaintext block, and
+ save it. */
+ xorblock(tmp2, blockN1);
+ memcpy(blockN2, tmp2, BLOCK_SIZE);
+
+ /* Maybe keep the trailing part, and copy in the last
+ ciphertext block. */
+ input_length %= BLOCK_SIZE;
+ memcpy(tmp2, blockN1, input_length ? input_length : BLOCK_SIZE);
+ dec(tmp3, tmp2, &ctx);
+ xorblock(tmp3, tmp);
+ /* Copy out ivec first before we clobber blockN1 with plaintext */
+ if (ivec != NULL)
+ memcpy(ivec->data, blockN1, BLOCK_SIZE);
+ memcpy(blockN1, tmp3, BLOCK_SIZE);
+
+ /* Put the last two blocks back into the iovec */
+ krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN1, BLOCK_SIZE, &output_pos);
+ krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN2, BLOCK_SIZE, &output_pos);
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+k5_aes_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+ if (key->length != 16 && key->length != 32)
+ return(KRB5_BAD_KEYSIZE);
+ if (randombits->length != key->length)
+ return(KRB5_CRYPTO_INTERNAL);
+
+ key->magic = KV5M_KEYBLOCK;
+
+ memcpy(key->contents, randombits->data, randombits->length);
+ return(0);
+}
+
+static krb5_error_code
+krb5int_aes_init_state (const krb5_keyblock *key, krb5_keyusage usage,
+ krb5_data *state)
+{
+ state->length = 16;
+ state->data = (void *) malloc(16);
+ if (state->data == NULL)
+ return ENOMEM;
+ memset(state->data, 0, state->length);
+ return 0;
+}
+
+const struct krb5_enc_provider krb5int_enc_aes128 = {
+ 16,
+ 16, 16,
+ krb5int_aes_encrypt,
+ krb5int_aes_decrypt,
+ k5_aes_make_key,
+ krb5int_aes_init_state,
+ krb5int_default_free_state,
+ krb5int_aes_encrypt_iov,
+ krb5int_aes_decrypt_iov
+};
+
+const struct krb5_enc_provider krb5int_enc_aes256 = {
+ 16,
+ 32, 32,
+ krb5int_aes_encrypt,
+ krb5int_aes_decrypt,
+ k5_aes_make_key,
+ krb5int_aes_init_state,
+ krb5int_default_free_state,
+ krb5int_aes_encrypt_iov,
+ krb5int_aes_decrypt_iov
+};
+
--- /dev/null
+#
+# Generated makefile dependencies follow.
+#
+des.so des.po $(OUTPRE)des.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \
+ $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \
+ $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \
+ $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+ $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+ $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+ $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+ $(srcdir)/../des/des_int.h $(srcdir)/../../krb/aead.h \
+ $(srcdir)/../../krb/cksumtypes.h des.c enc_provider.h
+des3.so des3.po $(OUTPRE)des3.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \
+ $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \
+ $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \
+ $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+ $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+ $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+ $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+ $(srcdir)/../des/des_int.h $(srcdir)/../../krb/aead.h \
+ $(srcdir)/../../krb/cksumtypes.h des3.c
+aes.so aes.po $(OUTPRE)aes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \
+ $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \
+ $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \
+ $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+ $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+ $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+ $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+ $(srcdir)/../aes/aes.h $(srcdir)/../aes/uitypes.h \
+ $(srcdir)/../../krb/aead.h $(srcdir)/../../krb/cksumtypes.h aes.c \
+ enc_provider.h
+rc4.so rc4.po $(OUTPRE)rc4.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \
+ $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \
+ $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \
+ $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+ $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+ $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+ $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+ $(srcdir)/../arcfour/arcfour-int.h $(srcdir)/../arcfour/arcfour.h \
+ $(srcdir)/../../krb/aead.h $(srcdir)/../../krb/cksumtypes.h enc_provider.h \
+ rc4.c
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include "enc_provider.h"
+#include "aead.h"
+
+static krb5_error_code
+k5_des_docrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output, int enc)
+{
+ mit_des_key_schedule schedule;
+
+ /* key->enctype was checked by the caller */
+
+ if (key->length != 8)
+ return(KRB5_BAD_KEYSIZE);
+ if ((input->length%8) != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+ if (input->length != output->length)
+ return(KRB5_BAD_MSIZE);
+
+ switch (mit_des_key_sched(key->contents, schedule)) {
+ case -1:
+ return(KRB5DES_BAD_KEYPAR);
+ case -2:
+ return(KRB5DES_WEAK_KEY);
+ }
+
+ /* this has a return value, but the code always returns zero */
+
+ mit_des_cbc_encrypt((krb5_pointer) input->data,
+ (krb5_pointer) output->data, input->length,
+ schedule,
+ (ivec
+ ? (const unsigned char *) ivec->data
+ : (const unsigned char *) mit_des_zeroblock),
+ enc);
+
+ memset(schedule, 0, sizeof(schedule));
+
+ return(0);
+}
+
+static krb5_error_code
+k5_des_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+ return(k5_des_docrypt(key, ivec, input, output, 1));
+}
+
+static krb5_error_code
+k5_des_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+ return(k5_des_docrypt(key, ivec, input, output, 0));
+}
+
+static krb5_error_code
+k5_des_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+ if (key->length != 8)
+ return(KRB5_BAD_KEYSIZE);
+ if (randombits->length != 7)
+ return(KRB5_CRYPTO_INTERNAL);
+
+ key->magic = KV5M_KEYBLOCK;
+ key->length = 8;
+
+ /* take the seven bytes, move them around into the top 7 bits of the
+ 8 key bytes, then compute the parity bits */
+
+ memcpy(key->contents, randombits->data, randombits->length);
+ key->contents[7] = (((key->contents[0]&1)<<1) | ((key->contents[1]&1)<<2) |
+ ((key->contents[2]&1)<<3) | ((key->contents[3]&1)<<4) |
+ ((key->contents[4]&1)<<5) | ((key->contents[5]&1)<<6) |
+ ((key->contents[6]&1)<<7));
+
+ mit_des_fixup_key_parity(key->contents);
+
+ return(0);
+}
+
+static krb5_error_code
+k5_des_docrypt_iov(const krb5_keyblock *key, const krb5_data *ivec,
+ krb5_crypto_iov *data, size_t num_data, int enc)
+{
+ mit_des_key_schedule schedule;
+ size_t input_length = 0;
+ unsigned int i;
+
+ /* key->enctype was checked by the caller */
+
+ if (key->length != 8)
+ return(KRB5_BAD_KEYSIZE);
+
+ for (i = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (ENCRYPT_DATA_IOV(iov))
+ input_length += iov->data.length;
+ }
+
+ if ((input_length % 8) != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+
+ switch (mit_des_key_sched(key->contents, schedule)) {
+ case -1:
+ return(KRB5DES_BAD_KEYPAR);
+ case -2:
+ return(KRB5DES_WEAK_KEY);
+ }
+
+ /* this has a return value, but the code always returns zero */
+ if (enc)
+ krb5int_des_cbc_encrypt_iov(data, num_data, schedule, ivec ? ivec->data : NULL);
+ else
+ krb5int_des_cbc_decrypt_iov(data, num_data, schedule, ivec ? ivec->data : NULL);
+
+ memset(schedule, 0, sizeof(schedule));
+
+ return(0);
+}
+
+static krb5_error_code
+k5_des_encrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ return k5_des_docrypt_iov(key, ivec, data, num_data, 1);
+}
+
+static krb5_error_code
+k5_des_decrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ return k5_des_docrypt_iov(key, ivec, data, num_data, 0);
+}
+
+const struct krb5_enc_provider krb5int_enc_des = {
+ 8,
+ 7, 8,
+ k5_des_encrypt,
+ k5_des_decrypt,
+ k5_des_make_key,
+ krb5int_des_init_state,
+ krb5int_default_free_state,
+ k5_des_encrypt_iov,
+ k5_des_decrypt_iov
+};
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include <aead.h>
+
+static krb5_error_code
+validate_and_schedule(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, const krb5_data *output,
+ mit_des3_key_schedule *schedule)
+{
+ /* key->enctype was checked by the caller */
+
+ if (key->length != 24)
+ return(KRB5_BAD_KEYSIZE);
+ if ((input->length%8) != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+ if (input->length != output->length)
+ return(KRB5_BAD_MSIZE);
+
+ switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+ *schedule)) {
+ case -1:
+ return(KRB5DES_BAD_KEYPAR);
+ case -2:
+ return(KRB5DES_WEAK_KEY);
+ }
+ return 0;
+}
+
+static krb5_error_code
+validate_and_schedule_iov(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_crypto_iov *data, size_t num_data,
+ mit_des3_key_schedule *schedule)
+{
+ size_t i, input_length;
+
+ for (i = 0, input_length = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (ENCRYPT_IOV(iov))
+ input_length += iov->data.length;
+ }
+
+ if (key->length != 24)
+ return(KRB5_BAD_KEYSIZE);
+ if ((input_length%8) != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+
+ switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+ *schedule)) {
+ case -1:
+ return(KRB5DES_BAD_KEYPAR);
+ case -2:
+ return(KRB5DES_WEAK_KEY);
+ }
+ return 0;
+}
+
+static krb5_error_code
+k5_des3_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+ mit_des3_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule(key, ivec, input, output, &schedule);
+ if (err)
+ return err;
+
+ /* this has a return value, but the code always returns zero */
+ krb5int_des3_cbc_encrypt((krb5_pointer) input->data,
+ (krb5_pointer) output->data, input->length,
+ schedule[0], schedule[1], schedule[2],
+ ivec?(const unsigned char *) ivec->data:(const unsigned char *)mit_des_zeroblock);
+
+ zap(schedule, sizeof(schedule));
+
+ return(0);
+}
+
+static krb5_error_code
+k5_des3_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+ mit_des3_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule(key, ivec, input, output, &schedule);
+ if (err)
+ return err;
+
+ /* this has a return value, but the code always returns zero */
+ krb5int_des3_cbc_decrypt((krb5_pointer) input->data,
+ (krb5_pointer) output->data, input->length,
+ schedule[0], schedule[1], schedule[2],
+ ivec?(const unsigned char *) ivec->data:(const unsigned char *)mit_des_zeroblock);
+
+ zap(schedule, sizeof(schedule));
+
+ return(0);
+}
+
+static krb5_error_code
+k5_des3_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+ int i;
+
+ if (key->length != 24)
+ return(KRB5_BAD_KEYSIZE);
+ if (randombits->length != 21)
+ return(KRB5_CRYPTO_INTERNAL);
+
+ key->magic = KV5M_KEYBLOCK;
+ key->length = 24;
+
+ /* take the seven bytes, move them around into the top 7 bits of the
+ 8 key bytes, then compute the parity bits. Do this three times. */
+
+ for (i=0; i<3; i++) {
+ memcpy(key->contents+i*8, randombits->data+i*7, 7);
+ key->contents[i*8+7] = (((key->contents[i*8]&1)<<1) |
+ ((key->contents[i*8+1]&1)<<2) |
+ ((key->contents[i*8+2]&1)<<3) |
+ ((key->contents[i*8+3]&1)<<4) |
+ ((key->contents[i*8+4]&1)<<5) |
+ ((key->contents[i*8+5]&1)<<6) |
+ ((key->contents[i*8+6]&1)<<7));
+
+ mit_des_fixup_key_parity(key->contents+i*8);
+ }
+
+ return(0);
+}
+
+static krb5_error_code
+k5_des3_encrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ mit_des3_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+ if (err)
+ return err;
+
+ /* this has a return value, but the code always returns zero */
+ krb5int_des3_cbc_encrypt_iov(data, num_data,
+ schedule[0], schedule[1], schedule[2],
+ ivec != NULL ? (unsigned char *) ivec->data : NULL);
+
+ zap(schedule, sizeof(schedule));
+
+ return(0);
+}
+
+static krb5_error_code
+k5_des3_decrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ mit_des3_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+ if (err)
+ return err;
+
+ /* this has a return value, but the code always returns zero */
+ krb5int_des3_cbc_decrypt_iov(data, num_data,
+ schedule[0], schedule[1], schedule[2],
+ ivec != NULL ? (unsigned char *) ivec->data : NULL);
+
+ zap(schedule, sizeof(schedule));
+
+ return(0);
+}
+
+const struct krb5_enc_provider krb5int_enc_des3 = {
+ 8,
+ 21, 24,
+ k5_des3_encrypt,
+ k5_des3_decrypt,
+ k5_des3_make_key,
+ krb5int_des_init_state,
+ krb5int_default_free_state,
+ k5_des3_encrypt_iov,
+ k5_des3_decrypt_iov
+};
+
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern const struct krb5_enc_provider krb5int_enc_des;
+extern const struct krb5_enc_provider krb5int_enc_des3;
+extern const struct krb5_enc_provider krb5int_enc_arcfour;
+extern const struct krb5_enc_provider krb5int_enc_aes128;
+extern const struct krb5_enc_provider krb5int_enc_aes256;
+extern const struct krb5_enc_provider krb5int_enc_aes128_ctr;
+extern const struct krb5_enc_provider krb5int_enc_aes256_ctr;
+
--- /dev/null
+/* arcfour.c
+ *
+ * Copyright (c) 2000 by Computer Science Laboratory,
+ * Rensselaer Polytechnic Institute
+ *
+ * #include STD_DISCLAIMER
+ */
+
+#include "k5-int.h"
+#include "arcfour-int.h"
+#include "enc_provider.h"
+#include <aead.h>
+/* gets the next byte from the PRNG */
+#if ((__GNUC__ >= 2) )
+static __inline__ unsigned int k5_arcfour_byte(ArcfourContext *);
+#else
+static unsigned int k5_arcfour_byte(ArcfourContext *);
+#endif /* gcc inlines*/
+
+/* Initializes the context and sets the key. */
+static krb5_error_code k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
+ unsigned int keylen);
+
+/* Encrypts/decrypts data. */
+static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
+ const unsigned char *src, unsigned int len);
+
+/* Interface layer to kerb5 crypto layer */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *, const krb5_data *,
+ const krb5_data *, krb5_data *);
+
+/* from a random bitstrem, construct a key */
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *, krb5_keyblock *);
+
+static const unsigned char arcfour_weakkey1[] = {0x00, 0x00, 0xfd};
+static const unsigned char arcfour_weakkey2[] = {0x03, 0xfd, 0xfc};
+static const struct {
+ size_t length;
+ const unsigned char *data;
+} arcfour_weakkeys[] = {
+ { sizeof (arcfour_weakkey1), arcfour_weakkey1},
+ { sizeof (arcfour_weakkey2), arcfour_weakkey2},
+};
+
+static inline unsigned int k5_arcfour_byte(ArcfourContext * ctx)
+{
+ unsigned int x;
+ unsigned int y;
+ unsigned int sx, sy;
+ unsigned char *state;
+
+ state = ctx->state;
+ x = (ctx->x + 1) & 0xff;
+ sx = state[x];
+ y = (sx + ctx->y) & 0xff;
+ sy = state[y];
+ ctx->x = x;
+ ctx->y = y;
+ state[y] = sx;
+ state[x] = sy;
+ return state[(sx + sy) & 0xff];
+}
+
+static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
+ const unsigned char *src, unsigned int len)
+{
+ unsigned int i;
+ for (i = 0; i < len; i++)
+ dest[i] = src[i] ^ k5_arcfour_byte(ctx);
+}
+
+
+static krb5_error_code
+k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
+ unsigned int key_len)
+{
+ unsigned int t, u;
+ unsigned int keyindex;
+ unsigned int stateindex;
+ unsigned char* state;
+ unsigned int counter;
+
+ if (key_len != 16)
+ return KRB5_BAD_MSIZE; /*this is probably not the correct error code
+ to return */
+ for (counter=0;
+ counter < sizeof(arcfour_weakkeys)/sizeof(arcfour_weakkeys[0]);
+ counter++)
+ if (!memcmp(key, arcfour_weakkeys[counter].data,
+ arcfour_weakkeys[counter].length))
+ return KRB5DES_WEAK_KEY; /* most certainly not the correct error */
+
+ state = &ctx->state[0];
+ ctx->x = 0;
+ ctx->y = 0;
+ for (counter = 0; counter < 256; counter++)
+ state[counter] = counter;
+ keyindex = 0;
+ stateindex = 0;
+ for (counter = 0; counter < 256; counter++)
+ {
+ t = state[counter];
+ stateindex = (stateindex + key[keyindex] + t) & 0xff;
+ u = state[stateindex];
+ state[stateindex] = t;
+ state[counter] = u;
+ if (++keyindex >= key_len)
+ keyindex = 0;
+ }
+ return 0;
+}
+
+
+/* The workhorse of the arcfour system, this impliments the cipher */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *key, const krb5_data *state,
+ const krb5_data *input, krb5_data *output)
+{
+ ArcfourContext *arcfour_ctx;
+ ArcFourCipherState *cipher_state;
+ int ret;
+
+ if (key->length != 16)
+ return(KRB5_BAD_KEYSIZE);
+ if (state && (state->length != sizeof (ArcFourCipherState)))
+ return(KRB5_BAD_MSIZE);
+ if (input->length != output->length)
+ return(KRB5_BAD_MSIZE);
+
+ if (state) {
+ cipher_state = (ArcFourCipherState *) state->data;
+ arcfour_ctx=&cipher_state->ctx;
+ if (cipher_state->initialized == 0) {
+ if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) {
+ return ret;
+ }
+ cipher_state->initialized = 1;
+ }
+ k5_arcfour_crypt(arcfour_ctx, (unsigned char *) output->data, (const unsigned char *) input->data, input->length);
+ }
+ else {
+ arcfour_ctx=malloc(sizeof (ArcfourContext));
+ if (arcfour_ctx == NULL)
+ return ENOMEM;
+ if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) {
+ free(arcfour_ctx);
+ return (ret);
+ }
+ k5_arcfour_crypt(arcfour_ctx, (unsigned char * ) output->data,
+ (const unsigned char * ) input->data, input->length);
+ memset(arcfour_ctx, 0, sizeof (ArcfourContext));
+ free(arcfour_ctx);
+ }
+
+ return 0;
+}
+
+/* In-place encryption */
+static krb5_error_code
+k5_arcfour_docrypt_iov(const krb5_keyblock *key,
+ const krb5_data *state,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ ArcfourContext *arcfour_ctx = NULL;
+ ArcFourCipherState *cipher_state = NULL;
+ krb5_error_code ret;
+ size_t i;
+
+ if (key->length != 16)
+ return KRB5_BAD_KEYSIZE;
+ if (state != NULL && (state->length != sizeof(ArcFourCipherState)))
+ return KRB5_BAD_MSIZE;
+
+ if (state != NULL) {
+ cipher_state = (ArcFourCipherState *)state->data;
+ arcfour_ctx = &cipher_state->ctx;
+ if (cipher_state->initialized == 0) {
+ ret = k5_arcfour_init(arcfour_ctx, key->contents, key->length);
+ if (ret != 0)
+ return ret;
+
+ cipher_state->initialized = 1;
+ }
+ } else {
+ arcfour_ctx = (ArcfourContext *)malloc(sizeof(ArcfourContext));
+ if (arcfour_ctx == NULL)
+ return ENOMEM;
+
+ ret = k5_arcfour_init(arcfour_ctx, key->contents, key->length);
+ if (ret != 0) {
+ free(arcfour_ctx);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < num_data; i++) {
+ krb5_crypto_iov *iov = &data[i];
+
+ if (ENCRYPT_IOV(iov))
+ k5_arcfour_crypt(arcfour_ctx, (unsigned char *)iov->data.data,
+ (const unsigned char *)iov->data.data, iov->data.length);
+ }
+
+ if (state == NULL) {
+ memset(arcfour_ctx, 0, sizeof(ArcfourContext));
+ free(arcfour_ctx);
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+ if (key->length != 16)
+ return(KRB5_BAD_KEYSIZE);
+ if (randombits->length != 16)
+ return(KRB5_CRYPTO_INTERNAL);
+
+ key->magic = KV5M_KEYBLOCK;
+ key->length = 16;
+
+ memcpy(key->contents, randombits->data, randombits->length);
+
+ return(0);
+}
+
+static krb5_error_code
+k5_arcfour_init_state (const krb5_keyblock *key,
+ krb5_keyusage keyusage, krb5_data *new_state)
+{
+ /* Note that we can't actually set up the state here because the key
+ * will change between now and when encrypt is called
+ * because it is data dependent. Yeah, this has strange
+ * properties. --SDH
+ */
+ new_state->length = sizeof (ArcFourCipherState);
+ new_state->data = malloc (new_state->length);
+ if (new_state->data) {
+ memset (new_state->data, 0 , new_state->length);
+ /* That will set initialized to zero*/
+ }else {
+ return (ENOMEM);
+ }
+ return 0;
+}
+
+/* Since the arcfour cipher is identical going forwards and backwards,
+ we just call "docrypt" directly
+*/
+const struct krb5_enc_provider krb5int_enc_arcfour = {
+ /* This seems to work... although I am not sure what the
+ implications are in other places in the kerberos library */
+ 1,
+ /* Keysize is arbitrary in arcfour, but the constraints of the
+ system, and to attempt to work with the MSFT system forces us
+ to 16byte/128bit. Since there is no parity in the key, the
+ byte and length are the same. */
+ 16, 16,
+ k5_arcfour_docrypt,
+ k5_arcfour_docrypt,
+ k5_arcfour_make_key,
+ k5_arcfour_init_state, /*xxx not implemented yet*/
+ krb5int_default_free_state,
+ k5_arcfour_docrypt_iov,
+ k5_arcfour_docrypt_iov
+};
+
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
-STLIBOBJS= md4.o
+STLIBOBJS= ../../@CRYPTO_IMPL@/md4/md4.o
-OBJS= $(OUTPRE)md4.$(OBJEXT)
+OBJS= $(OUTPRE)../../@CRYPTO_IMPL@/md4/md4.$(OBJEXT)
-SRCS= $(srcdir)/md4.c
+SRCS= $(srcdir)/../../@CRYPTO_IMPL@/md4/md4.c
##DOS##LIBOBJS = $(OBJS)
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
-STLIBOBJS= md5.o
+STLIBOBJS= ../../@CRYPTO_IMPL@/md5/md5.o
-OBJS= $(OUTPRE)md5.$(OBJEXT)
+OBJS= $(OUTPRE)../../@CRYPTO_IMPL@/md5/md5.$(OBJEXT)
-SRCS= $(srcdir)/md5.c
+SRCS= $(srcdir)/../../@CRYPTO_IMPL@/md5/md5.c
##DOS##LIBOBJS = $(OBJS)
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
-STLIBOBJS= shs.o
+STLIBOBJS= ../../@CRYPTO_IMPL@/sha1/shs.o
-OBJS= $(OUTPRE)shs.$(OBJEXT)
+OBJS= $(OUTPRE)../../@CRYPTO_IMPL@/sha1/shs.$(OBJEXT)
-SRCS= $(srcdir)/shs.c
+SRCS= $(srcdir)/../../@CRYPTO_IMPL@/sha1/shs.c
##DOS##LIBOBJS = $(OBJS)
myfulldir=lib/crypto/crypto_tests
mydir=lib/crypto/crypto_tests
BUILDTOP=$(REL)..$(S)..$(S)..
-LOCALINCLUDES = -I$(srcdir)/../krb -I$(srcdir)/../krb/enc_provider \
+LOCALINCLUDES = -I$(srcdir)/../krb -I$(srcdir)/../@CRYPTO_IMPL@/enc_provider \
-I$(srcdir)/../krb/hash_provider -I$(srcdir)/../krb/keyhash_provider \
-I$(srcdir)/../krb/dk -I$(srcdir)/../@CRYPTO_IMPL@/ \
-I$(srcdir)/../krb/yarrow \
myfulldir=lib/crypto/krb
mydir=lib/crypto/krb
BUILDTOP=$(REL)..$(S)..$(S)..
-SUBDIRS= crc32 dk enc_provider hash_provider keyhash_provider \
+SUBDIRS= crc32 dk hash_provider keyhash_provider \
old raw yarrow
-LOCALINCLUDES = -I$(srcdir) -I$(srcdir)/enc_provider -I$(srcdir)/dk \
- -I$(srcdir)/hash_provider -I$(srcdir)/keyhash_provider \
- -I$(srcdir)/old -I$(srcdir)/raw -I$(srcdir)/yarrow \
+LOCALINCLUDES = -I$(srcdir) -I$(srcdir)/../@CRYPTO_IMPL@/enc_provider -I$(srcdir)/dk \
+ -I$(srcdir)/hash_provider -I$(srcdir)/keyhash_provider \
+ -I$(srcdir)/old -I$(srcdir)/raw -I$(srcdir)/yarrow \
-I$(srcdir)/../@CRYPTO_IMPL@/ -I$(srcdir)/../@CRYPTO_IMPL@/des \
-I$(srcdir)/../@CRYPTO_IMPL@/aes -I$(srcdir)/../@CRYPTO_IMPL@/arcfour \
-I$(srcdir)/../@CRYPTO_IMPL@/sha1
$(srcdir)/verify_checksum.c \
$(srcdir)/verify_checksum_iov.c
-STOBJLISTS=crc32/OBJS.ST dk/OBJS.ST enc_provider/OBJS.ST \
+STOBJLISTS=crc32/OBJS.ST dk/OBJS.ST \
hash_provider/OBJS.ST keyhash_provider/OBJS.ST \
old/OBJS.ST raw/OBJS.ST yarrow/OBJS.ST OBJS.ST
-SUBDIROBJLISTS=crc32/OBJS.ST dk/OBJS.ST enc_provider/OBJS.ST \
+SUBDIROBJLISTS=crc32/OBJS.ST dk/OBJS.ST \
hash_provider/OBJS.ST keyhash_provider/OBJS.ST \
old/OBJS.ST raw/OBJS.ST yarrow/OBJS.ST OBJS.ST
cd ..\dk
@echo Making in crypto\dk
$(MAKE) -$(MFLAGS)
- cd ..\enc_provider
- @echo Making in crypto\enc_provider
- $(MAKE) -$(MFLAGS)
cd ..\hash_provider
@echo Making in crypto\hash_provider
$(MAKE) -$(MFLAGS)
cd ..\dk
@echo Making clean in crypto\dk
$(MAKE) -$(MFLAGS) clean
- cd ..\enc_provider
- @echo Making clean in crypto\enc_provider
- $(MAKE) -$(MFLAGS) clean
cd ..\hash_provider
@echo Making clean in crypto\hash_provider
$(MAKE) -$(MFLAGS) clean
cd ..\dk
@echo Making check in crypto\dk
$(MAKE) -$(MFLAGS) check
- cd ..\enc_provider
- @echo Making check in crypto\enc_provider
- $(MAKE) -$(MFLAGS) check
cd ..\hash_provider
@echo Making check in crypto\hash_provider
$(MAKE) -$(MFLAGS) check
$(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
$(srcdir)/../builtin/aes/aes_s2k.h $(srcdir)/../builtin/arcfour/arcfour.h \
$(srcdir)/../builtin/des/des_int.h $(srcdir)/dk/dk.h \
- $(srcdir)/enc_provider/enc_provider.h $(srcdir)/hash_provider/hash_provider.h \
+ $(srcdir)/../builtin/enc_provider/enc_provider.h $(srcdir)/hash_provider/hash_provider.h \
$(srcdir)/old/old.h $(srcdir)/raw/raw.h etypes.c etypes.h
keyblocks.so keyblocks.po $(OUTPRE)keyblocks.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
$(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
$(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
$(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
- $(srcdir)/../builtin/sha1/shs.h $(srcdir)/enc_provider/enc_provider.h \
+ $(srcdir)/../builtin/sha1/shs.h $(srcdir)/../builtin/enc_provider/enc_provider.h \
$(srcdir)/yarrow/yarrow.h $(srcdir)/yarrow/ycipher.h \
$(srcdir)/yarrow/yhash.h $(srcdir)/yarrow/ytypes.h \
prng.c
}
const struct krb5_hash_provider krb5int_hash_crc32 = {
+ "CRC32",
CRC32_CKSUM_LENGTH,
1,
k5_crc32_hash
}
const struct krb5_hash_provider krb5int_hash_md4 = {
+ "MD4",
RSA_MD4_CKSUM_LENGTH,
64,
k5_md4_hash
}
const struct krb5_hash_provider krb5int_hash_md5 = {
+ "MD5",
RSA_MD5_CKSUM_LENGTH,
64,
k5_md5_hash
}
const struct krb5_hash_provider krb5int_hash_sha1 = {
+ "SHA1",
SHS_DIGESTSIZE,
SHS_DATASIZE,
k5_sha1_hash
myfulldir=lib/crypto/krb/yarrow
mydir=lib/crypto/krb/yarrow
BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
-LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../@CRYPTO_IMPL@ -I$(srcdir)/../../@CRYPTO_IMPL@/sha1 -I$(srcdir)/../enc_provider
+LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../@CRYPTO_IMPL@ -I$(srcdir)/../../@CRYPTO_IMPL@/sha1 -I$(srcdir)/../../@CRYPTO_IMPL@/enc_provider
DEFS=
##DOS##BUILDTOP = ..\..\..\..
$(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
$(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
$(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
- $(srcdir)/../../builtin/sha1/shs.h $(srcdir)/../enc_provider/enc_provider.h \
+ $(srcdir)/../../builtin/sha1/shs.h $(srcdir)/../../builtin/enc_provider/enc_provider.h \
yarrow.h ycipher.c ycipher.h yhash.h ytypes.h
--- /dev/null
+#
+# Generated makefile dependencies follow.
+#
+des.so des.po $(OUTPRE)des.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+ $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+ $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+ $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+ $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+ $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+ $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+ $(SRCTOP)/include/socket-utils.h $(srcdir)/../../builtin/des/des_int.h \
+ $(srcdir)/../../krb/aead.h $(srcdir)/../cksumtypes.h des.c \
+ enc_provider.h
+des3.so des3.po $(OUTPRE)des3.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+ $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+ $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+ $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+ $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+ $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+ $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+ $(SRCTOP)/include/socket-utils.h $(srcdir)/../../builtin/des/des_int.h \
+ $(srcdir)/../../krb/aead.h $(srcdir)/../cksumtypes.h des3.c
+aes.so aes.po $(OUTPRE)aes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+ $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+ $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+ $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+ $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+ $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+ $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+ $(SRCTOP)/include/socket-utils.h $(srcdir)/../../builtin/aes/aes.h \
+ $(srcdir)/../../builtin/aes/uitypes.h $(srcdir)/../../krb/aead.h \
+ $(srcdir)/../cksumtypes.h aes.c enc_provider.h
+rc4.so rc4.po $(OUTPRE)rc4.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+ $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+ $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+ $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+ $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+ $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+ $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+ $(SRCTOP)/include/socket-utils.h $(srcdir)/../../builtin/arcfour/arcfour-int.h \
+ $(srcdir)/../../builtin/arcfour/arcfour.h $(srcdir)/../../krb/aead.h \
+ $(srcdir)/../cksumtypes.h enc_provider.h rc4.c
--- /dev/null
+/*
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include "enc_provider.h"
+#include <aead.h>
+#include <openssl/evp.h>
+
+#define DES_BLOCK_SIZE 8
+#define DES_KEY_BYTES 7
+#define DES_KEY_LEN 8
+
+static krb5_error_code
+k5_des_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+ int ret = 0, tmp_len = 0;
+ EVP_CIPHER_CTX ciph_ctx;
+ unsigned char *keybuf = NULL;
+ unsigned char *tmp_buf = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+
+ if (key->length != DES_KEY_LEN)
+ return(KRB5_BAD_KEYSIZE);
+ if ((input->length%8) != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+ if (input->length != output->length)
+ return(KRB5_BAD_MSIZE);
+
+ keybuf=key->contents;
+ keybuf[key->length] = '\0';
+
+ if ( ivec && ivec->data ) {
+ memset(iv,0,sizeof(iv));
+ memcpy(iv,ivec->data,ivec->length);
+ }
+
+ tmp_buf=OPENSSL_malloc(output->length);
+ if (!tmp_buf)
+ return ENOMEM;
+ memset(tmp_buf,0,output->length);
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+
+ ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_des_cbc(), NULL, keybuf,
+ (ivec && ivec->data) ? iv : NULL);
+ if (ret) {
+ EVP_CIPHER_CTX_set_padding(&ciph_ctx,0);
+ ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+ (unsigned char *)input->data, input->length);
+ if (ret) {
+ output->length = tmp_len;
+ ret = EVP_EncryptFinal_ex(&ciph_ctx, tmp_buf + tmp_len, &tmp_len);
+ }
+ }
+
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ if (ret)
+ memcpy(output->data,tmp_buf, output->length);
+
+ memset(tmp_buf,0,output->length);
+ OPENSSL_free(tmp_buf);
+
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+ return 0;
+}
+
+static krb5_error_code
+k5_des_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+ /* key->enctype was checked by the caller */
+ int ret = 0, tmp_len = 0;
+ EVP_CIPHER_CTX ciph_ctx;
+ unsigned char *keybuf = NULL;
+ unsigned char *tmp_buf;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+
+ if (key->length != DES_KEY_LEN)
+ return(KRB5_BAD_KEYSIZE);
+ if ((input->length%8) != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+ if (input->length != output->length)
+ return(KRB5_BAD_MSIZE);
+
+ keybuf=key->contents;
+ keybuf[key->length] = '\0';
+
+ if ( ivec != NULL && ivec->data ){
+ memset(iv,0,sizeof(iv));
+ memcpy(iv,ivec->data,ivec->length);
+ }
+
+ tmp_buf=OPENSSL_malloc(output->length);
+ if (!tmp_buf)
+ return ENOMEM;
+ memset(tmp_buf,0,output->length);
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+
+ ret = EVP_DecryptInit_ex(&ciph_ctx, EVP_des_cbc(), NULL, keybuf,
+ (ivec && ivec->data) ? iv : NULL);
+ if (ret) {
+ EVP_CIPHER_CTX_set_padding(&ciph_ctx,0);
+ ret = EVP_DecryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+ (unsigned char *)input->data, input->length);
+ if (ret) {
+ output->length = tmp_len;
+ ret = EVP_DecryptFinal_ex(&ciph_ctx, tmp_buf+tmp_len, &tmp_len);
+ }
+ }
+
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ if (ret)
+ memcpy(output->data,tmp_buf, output->length);
+
+ memset(tmp_buf,0,output->length );
+ OPENSSL_free(tmp_buf);
+
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+ return 0;
+}
+
+static krb5_error_code
+k5_des_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+ if (key->length != DES_KEY_LEN)
+ return(KRB5_BAD_KEYSIZE);
+ if (randombits->length != 7)
+ return(KRB5_CRYPTO_INTERNAL);
+
+ key->magic = KV5M_KEYBLOCK;
+
+ /* take the seven bytes, move them around into the top 7 bits of the
+ 8 key bytes, then compute the parity bits */
+
+ memcpy(key->contents, randombits->data, randombits->length);
+ key->contents[7] = (((key->contents[0]&1)<<1) | ((key->contents[1]&1)<<2) |
+ ((key->contents[2]&1)<<3) | ((key->contents[3]&1)<<4) |
+ ((key->contents[4]&1)<<5) | ((key->contents[5]&1)<<6) |
+ ((key->contents[6]&1)<<7));
+
+ mit_des_fixup_key_parity(key->contents);
+
+ return(0);
+}
+
+static krb5_error_code
+k5_des_encrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ int ret = 0, tmp_len = 0;
+ unsigned int i = 0;
+ EVP_CIPHER_CTX ciph_ctx;
+ unsigned char *keybuf = NULL ;
+ krb5_crypto_iov *iov = NULL;
+ unsigned char *tmp_buf = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+
+ if (ivec && ivec->data){
+ memset(iv,0,sizeof(iv));
+ memcpy(iv,ivec->data,ivec->length);
+ }
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+
+ ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_des_cbc(), NULL,
+ keybuf, (ivec && ivec->data) ? iv : NULL);
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+
+ for (i = 0; i < num_data; i++) {
+ iov = &data[i];
+ if (iov->data.length <= 0) break;
+ tmp_len = iov->data.length;
+
+ if (ENCRYPT_DATA_IOV(iov)) {
+ tmp_buf=(unsigned char *)iov->data.data;
+ ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+ (unsigned char *)iov->data.data, iov->data.length);
+ if (!ret) break;
+ iov->data.length = tmp_len;
+ }
+ }
+ if(ret)
+ ret = EVP_EncryptFinal_ex(&ciph_ctx, (unsigned char *)tmp_buf, &tmp_len);
+
+ if (ret)
+ iov->data.length += tmp_len;
+
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+ return 0;
+
+}
+
+static krb5_error_code
+k5_des_decrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ int ret = 0, tmp_len = 0;
+ unsigned int i = 0;
+ EVP_CIPHER_CTX ciph_ctx;
+ unsigned char *keybuf = NULL ;
+ krb5_crypto_iov *iov = NULL;
+ unsigned char *tmp_buf = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+
+ if (ivec && ivec->data){
+ memset(iv,0,sizeof(iv));
+ memcpy(iv,ivec->data,ivec->length);
+ }
+
+ ret = EVP_DecryptInit_ex(&ciph_ctx, EVP_des_cbc(), NULL,
+ keybuf, (ivec && ivec->data) ? iv : NULL);
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+
+ for (i = 0; i < num_data; i++) {
+ iov = &data[i];
+ if (iov->data.length <= 0) break;
+ tmp_len = iov->data.length;
+
+ if (ENCRYPT_DATA_IOV(iov)) {
+ tmp_buf=(unsigned char *)iov->data.data;
+ ret = EVP_DecryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+ (unsigned char *)iov->data.data, iov->data.length);
+ if (!ret) break;
+ iov->data.length = tmp_len;
+ }
+ }
+ if(ret)
+ ret = EVP_DecryptFinal_ex(&ciph_ctx, (unsigned char *)tmp_buf, &tmp_len);
+
+ if (ret)
+ iov->data.length += tmp_len;
+
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+ return 0;
+}
+
+const struct krb5_enc_provider krb5int_enc_des = {
+ DES_BLOCK_SIZE,
+ DES_KEY_BYTES, DES_KEY_LEN,
+ k5_des_encrypt,
+ k5_des_decrypt,
+ k5_des_make_key,
+ krb5int_des_init_state,
+ krb5int_default_free_state,
+ k5_des_encrypt_iov,
+ k5_des_decrypt_iov
+};
+
--- /dev/null
+/*
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include <aead.h>
+#include <openssl/evp.h>
+
+
+#define DES_BLOCK_SIZE 8
+#define DES3_KEY_BYTES 21
+#define DES3_KEY_LEN 24
+
+static krb5_error_code
+validate(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, const krb5_data *output)
+{
+ mit_des3_key_schedule schedule;
+
+ /* key->enctype was checked by the caller */
+
+ if (key->length != DES3_KEY_LEN)
+ return(KRB5_BAD_KEYSIZE);
+ if ((input->length%DES_BLOCK_SIZE) != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+ if (input->length != output->length)
+ return(KRB5_BAD_MSIZE);
+
+ switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+ schedule)) {
+ case -1:
+ return(KRB5DES_BAD_KEYPAR);
+ case -2:
+ return(KRB5DES_WEAK_KEY);
+ }
+ return 0;
+}
+
+static krb5_error_code
+validate_iov(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_crypto_iov *data, size_t num_data)
+{
+ size_t i, input_length;
+ mit_des3_key_schedule schedule;
+
+ for (i = 0, input_length = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (ENCRYPT_IOV(iov))
+ input_length += iov->data.length;
+ }
+
+ if (key->length != DES3_KEY_LEN)
+ return(KRB5_BAD_KEYSIZE);
+ if ((input_length%DES_BLOCK_SIZE) != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+
+ switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+ schedule)) {
+ case -1:
+ return(KRB5DES_BAD_KEYPAR);
+ case -2:
+ return(KRB5DES_WEAK_KEY);
+ }
+ return 0;
+}
+
+static krb5_error_code
+k5_des3_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+
+ int ret = 0, tmp_len = 0;
+ EVP_CIPHER_CTX ciph_ctx;
+ unsigned char *keybuf = NULL;
+ unsigned char *tmp_buf = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+
+ ret = validate(key, ivec, input, output);
+ if (ret)
+ return ret;
+
+ keybuf=key->contents;
+ keybuf[key->length] = '\0';
+
+ if (ivec && ivec->data) {
+ memset(iv,0,sizeof(iv));
+ memcpy(iv,ivec->data,ivec->length);
+ }
+
+ tmp_buf = OPENSSL_malloc(output->length);
+ if (!tmp_buf)
+ return ENOMEM;
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+
+ ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_des_ede3_cbc(), NULL, keybuf,
+ (ivec && ivec->data) ? iv : NULL);
+ if (ret) {
+ EVP_CIPHER_CTX_set_padding(&ciph_ctx,0);
+ ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+ (unsigned char *)input->data, input->length);
+ if (ret) {
+ output->length = tmp_len;
+ ret = EVP_EncryptFinal_ex(&ciph_ctx, tmp_buf+tmp_len, &tmp_len);
+ }
+ }
+
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ if (ret)
+ memcpy(output->data,tmp_buf, output->length);
+ memset(tmp_buf,0,output->length);
+ OPENSSL_free(tmp_buf);
+
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+ return 0;
+
+}
+
+static krb5_error_code
+k5_des3_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_data *input, krb5_data *output)
+{
+ int ret = 0, tmp_len = 0;
+ EVP_CIPHER_CTX ciph_ctx;
+ unsigned char *keybuf = NULL;
+ unsigned char *tmp_buf = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+
+ ret = validate(key, ivec, input, output);
+ if (ret)
+ return ret;
+
+ keybuf=key->contents;
+ keybuf[key->length] = '\0';
+
+ if (ivec && ivec->data) {
+ memset(iv,0,sizeof(iv));
+ memcpy(iv,ivec->data,ivec->length);
+ }
+
+ tmp_buf=OPENSSL_malloc(output->length);
+ if (!tmp_buf)
+ return ENOMEM;
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+
+ ret = EVP_DecryptInit_ex(&ciph_ctx, EVP_des_ede3_cbc(), NULL, keybuf,
+ (ivec && ivec->data) ? iv: NULL);
+ if (ret) {
+ EVP_CIPHER_CTX_set_padding(&ciph_ctx,0);
+ ret = EVP_DecryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+ (unsigned char *)input->data, input->length);
+ if (ret) {
+ output->length = tmp_len;
+ ret = EVP_DecryptFinal_ex(&ciph_ctx, tmp_buf+tmp_len, &tmp_len);
+ }
+ }
+
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ if (ret)
+ memcpy(output->data,tmp_buf, output->length);
+
+ memset(tmp_buf,0,output->length);
+ OPENSSL_free(tmp_buf);
+
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+ return 0;
+
+}
+
+static krb5_error_code
+k5_des3_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+ int i;
+
+ if (key->length != DES3_KEY_LEN)
+ return(KRB5_BAD_KEYSIZE);
+ if (randombits->length != DES3_KEY_BYTES)
+ return(KRB5_CRYPTO_INTERNAL);
+
+ key->magic = KV5M_KEYBLOCK;
+
+ /* take the seven bytes, move them around into the top 7 bits of the
+ 8 key bytes, then compute the parity bits. Do this three times. */
+
+ for (i=0; i<3; i++) {
+ memcpy(key->contents+i*8, randombits->data+i*7, 7);
+ key->contents[i*8+7] = (((key->contents[i*8]&1)<<1) |
+ ((key->contents[i*8+1]&1)<<2) |
+ ((key->contents[i*8+2]&1)<<3) |
+ ((key->contents[i*8+3]&1)<<4) |
+ ((key->contents[i*8+4]&1)<<5) |
+ ((key->contents[i*8+5]&1)<<6) |
+ ((key->contents[i*8+6]&1)<<7));
+
+ mit_des_fixup_key_parity(key->contents+i*8);
+ }
+
+ return(0);
+}
+
+static krb5_error_code
+validate_and_schedule_iov(const krb5_keyblock *key, const krb5_data *ivec,
+ const krb5_crypto_iov *data, size_t num_data,
+ mit_des3_key_schedule *schedule)
+{
+ size_t i, input_length;
+
+ for (i = 0, input_length = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (ENCRYPT_IOV(iov))
+ input_length += iov->data.length;
+ }
+
+ if (key->length != 24)
+ return(KRB5_BAD_KEYSIZE);
+ if ((input_length%8) != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+
+ switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+ *schedule)) {
+ case -1:
+ return(KRB5DES_BAD_KEYPAR);
+ case -2:
+ return(KRB5DES_WEAK_KEY);
+ }
+ return 0;
+}
+
+static krb5_error_code
+k5_des3_encrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+#if 0
+ int ret = 0, tmp_len = 0;
+ unsigned int i = 0;
+ EVP_CIPHER_CTX ciph_ctx;
+ unsigned char *keybuf = NULL ;
+ krb5_crypto_iov *iov = NULL;
+ unsigned char *tmp_buf = NULL;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+
+ ret = validate_iov(key, ivec, data, num_data);
+ if (ret)
+ return ret;
+
+ if (ivec && ivec->data){
+ memset(iv,0,sizeof(iv));
+ memcpy(iv,ivec->data,ivec->length);
+ }
+
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+
+ ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_des_ede3_cbc(), NULL,
+ keybuf, (ivec && ivec->data) ? iv : NULL);
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+
+ for (i = 0; i < num_data; i++) {
+ iov = &data[i];
+ if (iov->data.length <= 0) break;
+ tmp_len = iov->data.length;
+
+ if (ENCRYPT_IOV(iov)) {
+ tmp_buf=(unsigned char *)iov->data.data;
+ ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+ (unsigned char *)iov->data.data, iov->data.length);
+ if (!ret) break;
+ iov->data.length = tmp_len;
+ }
+ }
+ if(ret)
+ ret = EVP_EncryptFinal_ex(&ciph_ctx, (unsigned char *)tmp_buf, &tmp_len);
+
+ if (ret)
+ iov->data.length += tmp_len;
+
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+ return 0;
+#endif
+
+//#if 0
+ mit_des3_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+ if (err)
+ return err;
+
+ /* this has a return value, but the code always returns zero */
+ krb5int_des3_cbc_encrypt_iov(data, num_data,
+ schedule[0], schedule[1], schedule[2],
+ ivec != NULL ? (unsigned char *) ivec->data : NULL);
+
+ zap(schedule, sizeof(schedule));
+ return(0);
+//#endif
+}
+
+static krb5_error_code
+k5_des3_decrypt_iov(const krb5_keyblock *key,
+ const krb5_data *ivec,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ mit_des3_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+ if (err)
+ return err;
+
+ /* this has a return value, but the code always returns zero */
+ krb5int_des3_cbc_decrypt_iov(data, num_data,
+ schedule[0], schedule[1], schedule[2],
+ ivec != NULL ? (unsigned char *) ivec->data : NULL);
+
+ zap(schedule, sizeof(schedule));
+
+ return(0);
+}
+
+const struct krb5_enc_provider krb5int_enc_des3 = {
+ DES_BLOCK_SIZE,
+ DES3_KEY_BYTES, DES3_KEY_LEN,
+ k5_des3_encrypt,
+ k5_des3_decrypt,
+ k5_des3_make_key,
+ krb5int_des_init_state,
+ krb5int_default_free_state,
+ k5_des3_encrypt_iov,
+ k5_des3_decrypt_iov
+};
+
--- /dev/null
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern const struct krb5_enc_provider krb5int_enc_des;
+extern const struct krb5_enc_provider krb5int_enc_des3;
+extern const struct krb5_enc_provider krb5int_enc_arcfour;
+extern const struct krb5_enc_provider krb5int_enc_aes128;
+extern const struct krb5_enc_provider krb5int_enc_aes256;
+extern const struct krb5_enc_provider krb5int_enc_aes128_ctr;
+extern const struct krb5_enc_provider krb5int_enc_aes256_ctr;
+
--- /dev/null
+/* arcfour.c
+ *
+ * #include STD_DISCLAIMER
+ */
+
+#include "k5-int.h"
+#include "arcfour-int.h"
+#include "enc_provider.h"
+#include <aead.h>
+#include <openssl/evp.h>
+
+#define RC4_KEY_SIZE 16
+#define RC4_BLOCK_SIZE 1
+
+/* Interface layer to kerb5 crypto layer */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *, const krb5_data *,
+ const krb5_data *, krb5_data *);
+
+/* from a random bitstrem, construct a key */
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *, krb5_keyblock *);
+
+static krb5_error_code
+k5_arcfour_free_state ( krb5_data *state);
+static krb5_error_code
+k5_arcfour_init_state (const krb5_keyblock *key,
+ krb5_keyusage keyusage, krb5_data *new_state);
+
+/* The workhorse of the arcfour system, this impliments the cipher */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *key, const krb5_data *state,
+ const krb5_data *input, krb5_data *output)
+{
+ int ret = 0, tmp_len = 0;
+ unsigned char *keybuf = NULL;
+ unsigned char *tmp_buf = NULL;
+ EVP_CIPHER_CTX ciph_ctx;
+
+ if (key->length != RC4_KEY_SIZE)
+ return(KRB5_BAD_KEYSIZE);
+
+ if (input->length != output->length)
+ return(KRB5_BAD_MSIZE);
+
+ keybuf=key->contents;
+ keybuf[key->length] = '\0';
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+ ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_rc4(), NULL, keybuf, NULL);
+ if (ret) {
+ tmp_buf=(unsigned char *)output->data;
+ ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf, &tmp_len, (unsigned char *)input->data, input->length);
+ output->length = tmp_len;
+ }
+ if (ret) {
+ tmp_buf += tmp_len;
+ ret = EVP_EncryptFinal_ex(&ciph_ctx, tmp_buf, &tmp_len);
+ }
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+ output->length += tmp_len;
+
+ if (!ret)
+ return KRB5_CRYPTO_INTERNAL;
+ return 0;
+}
+
+
+/* In-place decryption */
+static krb5_error_code
+k5_arcfour_docrypt_iov(const krb5_keyblock *key,
+ const krb5_data *state,
+ krb5_crypto_iov *data,
+ size_t num_data)
+{
+ size_t i;
+ int ret = 0, tmp_len = 0;
+ EVP_CIPHER_CTX ciph_ctx;
+ unsigned char *keybuf = NULL ;
+ krb5_crypto_iov *iov = NULL;
+ unsigned char *tmp_buf = NULL;
+
+ keybuf=key->contents;
+ keybuf[key->length] = '\0';
+
+ EVP_CIPHER_CTX_init(&ciph_ctx);
+
+ ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_rc4(), NULL, keybuf, NULL);
+ if (!ret)
+ return -1;
+
+ for (i = 0; i < num_data; i++) {
+ iov = &data[i];
+ if (iov->data.length <= 0) break;
+ tmp_len = iov->data.length;
+
+ if (ENCRYPT_IOV(iov)) {
+ tmp_buf=(unsigned char *)iov->data.data;
+ ret = EVP_EncryptUpdate(&ciph_ctx,
+ tmp_buf, &tmp_len,
+ (unsigned char *)iov->data.data, iov->data.length);
+ if (!ret) break;
+ iov->data.length = tmp_len;
+ }
+ }
+ if(ret)
+ ret = EVP_EncryptFinal_ex(&ciph_ctx, (unsigned char *)tmp_buf, &tmp_len);
+ if (ret)
+ iov->data.length += tmp_len;
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ if (!ret)
+ return -1;
+ return 0;
+}
+
+
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+ if (key->length != RC4_KEY_SIZE)
+ return(KRB5_BAD_KEYSIZE);
+ if (randombits->length != RC4_KEY_SIZE)
+ return(KRB5_CRYPTO_INTERNAL);
+
+ key->magic = KV5M_KEYBLOCK;
+
+ memcpy(key->contents, randombits->data, randombits->length);
+
+ return(0);
+}
+
+static krb5_error_code
+k5_arcfour_free_state ( krb5_data *state)
+{
+ return 0; /* not implemented */
+}
+
+static krb5_error_code
+k5_arcfour_init_state (const krb5_keyblock *key,
+ krb5_keyusage keyusage, krb5_data *new_state)
+{
+ return 0; /* not implemented */
+
+}
+
+/* Since the arcfour cipher is identical going forwards and backwards,
+ we just call "docrypt" directly
+*/
+const struct krb5_enc_provider krb5int_enc_arcfour = {
+ /* This seems to work... although I am not sure what the
+ implications are in other places in the kerberos library */
+ RC4_BLOCK_SIZE,
+ /* Keysize is arbitrary in arcfour, but the constraints of the
+ system, and to attempt to work with the MSFT system forces us
+ to 16byte/128bit. Since there is no parity in the key, the
+ byte and length are the same. */
+ RC4_KEY_SIZE, RC4_KEY_SIZE,
+ k5_arcfour_docrypt,
+ k5_arcfour_docrypt,
+ k5_arcfour_make_key,
+ k5_arcfour_init_state, /*xxx not implemented */
+ k5_arcfour_free_state, /*xxx not implemented */
+ k5_arcfour_docrypt_iov,
+ k5_arcfour_docrypt_iov
+};
+
--- /dev/null
+/*
+ */
+
+#include "k5-int.h"
+#include "aead.h"
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+
+/*
+ * the HMAC transform looks like:
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ *
+ * where H is a cryptographic hash
+ * K is an n byte key
+ * ipad is the byte 0x36 repeated blocksize times
+ * opad is the byte 0x5c repeated blocksize times
+ * and text is the data being protected
+ */
+
+static const EVP_MD *
+map_digest(const struct krb5_hash_provider *hash)
+{
+ if (!strncmp(hash->hash_name, "SHA1",4))
+ return EVP_sha1();
+ else if (!strncmp(hash->hash_name, "MD5", 3))
+ return EVP_md5();
+ else if (!strncmp(hash->hash_name, "MD4", 3))
+ return EVP_md4();
+ else
+ return NULL;
+}
+
+krb5_error_code
+krb5_hmac(const struct krb5_hash_provider *hash, const krb5_keyblock *key,
+ unsigned int icount, const krb5_data *input, krb5_data *output)
+{
+ unsigned int i = 0, md_len = 0;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ HMAC_CTX c;
+ size_t hashsize, blocksize;
+
+ hashsize = hash->hashsize;
+ blocksize = hash->blocksize;
+
+ if (key->length > blocksize)
+ return(KRB5_CRYPTO_INTERNAL);
+ if (output->length < hashsize)
+ return(KRB5_BAD_MSIZE);
+ /* if this isn't > 0, then there won't be enough space in this
+ array to compute the outer hash */
+ if (icount == 0)
+ return(KRB5_CRYPTO_INTERNAL);
+
+ if (!map_digest(hash))
+ return(KRB5_CRYPTO_INTERNAL); // unsupported alg
+
+ HMAC_CTX_init(&c);
+ HMAC_Init(&c, key->contents, key->length, map_digest(hash));
+ for ( i = 0; i < icount; i++ ) {
+ HMAC_Update(&c,(const unsigned char*)input[i].data, input[i].length);
+ }
+ HMAC_Final(&c,(unsigned char *)md, &md_len);
+ if ( md_len <= output->length) {
+ output->length = md_len;
+ memcpy(output->data, md, output->length);
+ }
+ HMAC_CTX_cleanup(&c);
+ return 0;
+
+
+}
+
+krb5_error_code
+krb5int_hmac_iov(const struct krb5_hash_provider *hash, const krb5_keyblock *key,
+ const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
+{
+ krb5_data *sign_data;
+ size_t num_sign_data;
+ krb5_error_code ret;
+ size_t i, j;
+
+ /* Create a checksum over all the data to be signed */
+ for (i = 0, num_sign_data = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (SIGN_IOV(iov))
+ num_sign_data++;
+ }
+
+ /* XXX cleanup to avoid alloc */
+ sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data));
+ if (sign_data == NULL)
+ return ENOMEM;
+
+ for (i = 0, j = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (SIGN_IOV(iov))
+ sign_data[j++] = iov->data;
+ }
+
+ /* caller must store checksum in iov as it may be TYPE_TRAILER or TYPE_CHECKSUM */
+ ret = krb5_hmac(hash, key, num_sign_data, sign_data, output);
+
+ free(sign_data);
+
+ return ret;
+}
+
--- /dev/null
+#
+# Generated makefile dependencies follow.
+#
+md4.so md4.po $(OUTPRE)md4.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+ $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+ $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+ $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+ $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+ $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+ $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+ $(SRCTOP)/include/socket-utils.h md4.c rsa-md4.h
--- /dev/null
+/*
+ * lib/crypto/openssl/md4/md4.c
+ */
+
+#include "k5-int.h"
+#include "rsa-md4.h"
+#include <openssl/evp.h>
+#include <openssl/md4.h>
+
+void
+krb5_MD4Init (krb5_MD4_CTX *mdContext)
+{
+ EVP_MD_CTX_init(&mdContext->ossl_md4_ctx );
+ EVP_DigestInit_ex(&mdContext->ossl_md4_ctx, EVP_md4(), NULL);
+
+}
+void
+krb5_MD4Update (krb5_MD4_CTX *mdContext, const unsigned char *inBuf, unsigned int inLen)
+{
+ EVP_DigestUpdate(&mdContext->ossl_md4_ctx, inBuf, inLen);
+}
+
+void
+krb5_MD4Final (krb5_MD4_CTX *mdContext)
+{
+ EVP_DigestFinal_ex(&mdContext->ossl_md4_ctx, mdContext->digest , NULL);
+ EVP_MD_CTX_cleanup(&mdContext->ossl_md4_ctx );
+}
+
--- /dev/null
+/*
+ * lib/crypto/md4/rsa-md4.h
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * RSA MD4 header file, with Kerberos/STDC additions.
+ */
+
+#ifndef __KRB5_RSA_MD4_H__
+#define __KRB5_RSA_MD4_H__
+
+#ifdef unicos61
+#include <sys/types.h>
+#endif /* unicos61 */
+
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+/* 16 u_char's in the digest */
+#define RSA_MD4_CKSUM_LENGTH 16
+/* des blocksize is 8, so this works nicely... */
+#define OLD_RSA_MD4_DES_CKSUM_LENGTH 16
+#define NEW_RSA_MD4_DES_CKSUM_LENGTH 24
+#define RSA_MD4_DES_CONFOUND_LENGTH 8
+
+/*
+ **********************************************************************
+ ** md4.h -- Header file for implementation of MD4 **
+ ** RSA Data Security, Inc. MD4 Message Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ **********************************************************************
+ */
+
+/*
+ **********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD4 Message **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD4 Message Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ **********************************************************************
+ */
+
+/* Data structure for MD4 (Message Digest) computation */
+typedef struct {
+ EVP_MD_CTX ossl_md4_ctx;
+ krb5_int32 * digest_len;
+ krb5_ui_4 i[2]; /* number of _bits_ handled mod 2^64 */
+ krb5_ui_4 buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD4Final call */
+} krb5_MD4_CTX;
+
+extern void krb5_MD4Init(krb5_MD4_CTX *);
+extern void krb5_MD4Update(krb5_MD4_CTX *, const unsigned char *, unsigned int);
+extern void krb5_MD4Final(krb5_MD4_CTX *);
+
+/*
+ **********************************************************************
+ ** End of md4.h **
+ ******************************* (cut) ********************************
+ */
+#endif /* __KRB5_RSA_MD4_H__ */
--- /dev/null
+#
+# Generated makefile dependencies follow.
+#
+md5.so md5.po $(OUTPRE)md5.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+ $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+ $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+ $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+ $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+ $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+ $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+ $(SRCTOP)/include/socket-utils.h md5.c rsa-md5.h
--- /dev/null
+
+#include "k5-int.h"
+#include "rsa-md5.h"
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+/* The routine krb5_MD5Init initializes the message-digest context
+ mdContext. All fields are set to zero.
+ */
+void
+krb5_MD5Init (krb5_MD5_CTX *mdContext)
+{
+ EVP_MD_CTX_init(&mdContext->ossl_md5_ctx);
+ EVP_DigestInit_ex(&mdContext->ossl_md5_ctx, EVP_md5(), NULL);
+}
+
+/* The routine krb5_MD5Update updates the message-digest context to
+ account for the presence of each of the characters inBuf[0..inLen-1]
+ in the message whose digest is being computed.
+ */
+void
+krb5_MD5Update (krb5_MD5_CTX *mdContext, const unsigned char *inBuf, unsigned int inLen)
+{
+ EVP_DigestUpdate(&mdContext->ossl_md5_ctx, inBuf, inLen);
+}
+
+/* The routine krb5_MD5Final terminates the message-digest computation and
+ ends with the desired message digest in mdContext->digest[0...15].
+ */
+void
+krb5_MD5Final (krb5_MD5_CTX *mdContext)
+{
+ EVP_DigestFinal_ex(&mdContext->ossl_md5_ctx, mdContext->digest, NULL);
+ EVP_MD_CTX_cleanup(&mdContext->ossl_md5_ctx);
+}
+
--- /dev/null
+
+#ifndef KRB5_RSA_MD5__
+#define KRB5_RSA_MD5__
+
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+ EVP_MD_CTX ossl_md5_ctx;
+ krb5_int32 * digest_len;
+ krb5_ui_4 i[2]; /* number of _bits_ handled mod 2^64 */
+ krb5_ui_4 buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD5Final call */
+} krb5_MD5_CTX;
+
+extern void krb5_MD5Init(krb5_MD5_CTX *);
+extern void krb5_MD5Update(krb5_MD5_CTX *,const unsigned char *,unsigned int);
+extern void krb5_MD5Final(krb5_MD5_CTX *);
+
+#define RSA_MD5_CKSUM_LENGTH 16
+#define OLD_RSA_MD5_DES_CKSUM_LENGTH 16
+#define NEW_RSA_MD5_DES_CKSUM_LENGTH 24
+#define RSA_MD5_DES_CONFOUND_LENGTH 8
+
+#endif /* KRB5_RSA_MD5__ */
--- /dev/null
+/*
+ * lib/crypto/openssl/pbkdf2.c
+ *
+ * Copyright 2002, 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Implementation of PBKDF2 from RFC 2898.
+ * Not currently used; likely to be used when we get around to AES support.
+ */
+
+#include <ctype.h>
+#include "k5-int.h"
+#include "hash_provider.h"
+
+#include <openssl/x509.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+
+krb5_error_code
+krb5int_pbkdf2_hmac_sha1 (const krb5_data *out, unsigned long count,
+ const krb5_data *pass, const krb5_data *salt)
+{
+/*
+ * This is an implementation of PKCS#5 v2.0
+ * Does not return an error
+ */
+ PKCS5_PBKDF2_HMAC_SHA1(pass->data, pass->length,
+ (unsigned char *)salt->data, salt->length, count,
+ out->length, (unsigned char *)out->data);
+ return 0;
+}
+
--- /dev/null
+#
+# Generated makefile dependencies follow.
+#
+shs.so shs.po $(OUTPRE)shs.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+ $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+ $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+ $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+ $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+ $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+ $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+ $(SRCTOP)/include/socket-utils.h shs.c shs.h
--- /dev/null
+#include "shs.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <string.h>
+
+/* Initialize the SHS values */
+void shsInit(SHS_INFO *shsInfo)
+{
+ EVP_MD_CTX_init(&shsInfo->ossl_sha1_ctx );
+ EVP_DigestInit_ex(&shsInfo->ossl_sha1_ctx , EVP_sha1(), NULL);
+}
+
+/* Update SHS for a block of data */
+
+void shsUpdate(SHS_INFO *shsInfo, const SHS_BYTE *buffer, unsigned int count)
+{
+ EVP_DigestUpdate(&shsInfo->ossl_sha1_ctx , buffer, count);
+}
+/* Final wrapup - pad to SHS_DATASIZE-byte boundary with the bit pattern
+ 1 0* (64-bit count of bits processed, MSB-first) */
+
+void shsFinal(SHS_INFO *shsInfo)
+{
+ unsigned char *digest_buf = NULL;
+
+ digest_buf = (unsigned char *)OPENSSL_malloc( sizeof(shsInfo->digest));
+
+ EVP_DigestFinal_ex(&shsInfo->ossl_sha1_ctx , digest_buf , &shsInfo->digest_len);
+
+ memcpy(shsInfo->digest, digest_buf, shsInfo->digest_len);
+ OPENSSL_free(digest_buf);
+ EVP_MD_CTX_cleanup(&shsInfo->ossl_sha1_ctx );
+}
--- /dev/null
+#ifndef _SHS_DEFINED
+
+#include "k5-int.h"
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+
+#define _SHS_DEFINED
+
+/* Some useful types */
+
+typedef krb5_octet SHS_BYTE;
+typedef krb5_ui_4 SHS_LONG;
+
+/* Define the following to use the updated SHS implementation */
+#define NEW_SHS /**/
+
+/* The SHS block size and message digest sizes, in bytes */
+
+#define SHS_DATASIZE 64
+#define SHS_DIGESTSIZE 20
+
+/* The structure for storing SHS info */
+
+typedef struct {
+ EVP_MD_CTX ossl_sha1_ctx;
+ unsigned int digest_len;
+ SHS_LONG digest[ 5 ]; /* Message digest */
+ SHS_LONG countLo, countHi; /* 64-bit bit count */
+ SHS_LONG data[ 16 ]; /* SHS data buffer */
+} SHS_INFO;
+
+/* Message digest functions (shs.c) */
+void shsInit(SHS_INFO *shsInfo);
+void shsUpdate(SHS_INFO *shsInfo, const SHS_BYTE *buffer, unsigned int count);
+void shsFinal(SHS_INFO *shsInfo);
+
+
+/* Keyed Message digest functions (hmac_sha.c) */
+krb5_error_code hmac_sha(krb5_octet *text,
+ int text_len,
+ krb5_octet *key,
+ int key_len,
+ krb5_octet *digest);
+
+
+#define NIST_SHA_CKSUM_LENGTH SHS_DIGESTSIZE
+#define HMAC_SHA_CKSUM_LENGTH SHS_DIGESTSIZE
+
+#endif /* _SHS_DEFINED */
gss_iov_buffer_desc *, /* iov */
int); /* iov_count */
+/*
+ * Protocol transition
+ */
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ const gss_OID, /* desired_mech */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 *); /* acceptor_time_rec */
+
/*
* Naming extensions
*/
$(srcdir)/rel_cred.c \
$(srcdir)/rel_oid.c \
$(srcdir)/rel_name.c \
+ $(srcdir)/s4u_gss_glue.c \
$(srcdir)/seal.c \
$(srcdir)/set_allowable_enctypes.c \
$(srcdir)/ser_sctx.c \
$(OUTPRE)rel_cred.$(OBJEXT) \
$(OUTPRE)rel_oid.$(OBJEXT) \
$(OUTPRE)rel_name.$(OBJEXT) \
+ $(OUTPRE)s4u_gss_glue.$(OBJEXT) \
$(OUTPRE)seal.$(OBJEXT) \
$(OUTPRE)set_allowable_enctypes.$(OBJEXT) \
$(OUTPRE)ser_sctx.$(OBJEXT) \
rel_cred.o \
rel_oid.o \
rel_name.o \
+ s4u_gss_glue.o \
seal.o \
set_allowable_enctypes.o \
ser_sctx.o \
#ifndef LEAN_CLIENT
+static OM_uint32
+create_constrained_deleg_creds(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t verifier_cred_handle,
+ krb5_ticket *ticket,
+ krb5_gss_cred_id_t *out_cred,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_creds krb_creds;
+ krb5_data *data;
+ krb5_error_code code;
+
+ assert(out_cred != NULL);
+ assert(verifier_cred_handle->usage == GSS_C_BOTH);
+
+ memset(&krb_creds, 0, sizeof(krb_creds));
+ krb_creds.client = ticket->enc_part2->client;
+ krb_creds.server = ticket->server;
+ krb_creds.keyblock = *(ticket->enc_part2->session);
+ krb_creds.ticket_flags = ticket->enc_part2->flags;
+ krb_creds.times = ticket->enc_part2->times;
+ krb_creds.magic = KV5M_CREDS;
+ krb_creds.authdata = NULL;
+
+ code = encode_krb5_ticket(ticket, &data);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ krb_creds.ticket = *data;
+
+ major_status = kg_compose_deleg_cred(minor_status,
+ verifier_cred_handle,
+ &krb_creds,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET,
+ out_cred,
+ NULL,
+ NULL,
+ context);
+
+ krb5_free_data(context, data);
+
+ return major_status;
+}
+
/* Decode, decrypt and store the forwarded creds in the local ccache. */
static krb5_error_code
rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
ctx->krb_times = ticket->enc_part2->times; /* struct copy */
ctx->krb_flags = ticket->enc_part2->flags;
+ if (delegated_cred_handle != NULL &&
+ deleg_cred == NULL && /* no unconstrained delegation */
+ cred->usage == GSS_C_BOTH &&
+ (ticket->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
+ /*
+ * Now, we always fabricate a delegated credentials handle
+ * containing the service ticket to ourselves, which can be
+ * used for S4U2Proxy.
+ */
+ major_status = create_constrained_deleg_creds(minor_status, cred,
+ ticket, &deleg_cred,
+ context);
+ if (GSS_ERROR(major_status))
+ goto fail;
+ ctx->gss_flags |= GSS_C_DELEG_FLAG;
+ }
+
krb5_free_ticket(context, ticket); /* Done with ticket */
{
if (src_name)
*src_name = (gss_name_t) name;
- if (delegated_cred_handle && deleg_cred) {
- if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
+ if (delegated_cred_handle) {
+ if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
major_status = GSS_S_FAILURE;
code = G_VALIDATE_FAILED;
goto fail;
cred->usage = cred_usage;
cred->name = NULL;
- cred->prerfc_mech = req_old;
- cred->rfc_mech = req_new;
+ cred->prerfc_mech = (req_old != 0);
+ cred->rfc_mech = (req_new != 0);
#ifndef LEAN_CLIENT
cred->keytab = NULL;
*minor_status = 0;
return GSS_S_COMPLETE;
}
+
krb5_free_context(context);
return(GSS_S_FAILURE);
}
- while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor, &creds))
+ while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor,
+ &creds)) {
code = krb5_cc_store_cred(context, out_ccache, &creds);
+ krb5_free_cred_contents(context, &creds);
+ }
krb5_cc_end_seq_get(context, k5creds->ccache, &cursor);
k5_mutex_unlock(&k5creds->lock);
*minor_status = code;
/* name/type of credential */
gss_cred_usage_t usage;
krb5_gss_name_t name;
- int prerfc_mech;
- int rfc_mech;
+ unsigned int prerfc_mech : 1;
+ unsigned int rfc_mech : 1;
+ unsigned int proxy_cred : 1;
/* keytab (accept) data */
krb5_keytab keytab;
krb5_error_code kg_allocate_iov(gss_iov_buffer_t iov, size_t size);
+krb5_error_code
+krb5_to_gss_cred(krb5_context context,
+ krb5_creds *creds,
+ krb5_gss_cred_id_t *out_cred);
+
+OM_uint32
+kg_new_connection(
+ OM_uint32 *minor_status,
+ krb5_gss_cred_id_t cred,
+ gss_ctx_id_t *context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec,
+ krb5_context context,
+ int default_mech);
+
/** declarations of internal name mechanism functions **/
OM_uint32 krb5_gss_acquire_cred
gss_cred_id_t /* cred */
);
+OM_uint32 krb5_gss_acquire_cred_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
OM_uint32
krb5_gss_validate_cred_1(OM_uint32 * /* minor_status */,
gss_cred_id_t /* cred_handle */,
gss_buffer_t type_id,
gss_any_t *input);
+/* s4u_gss_glue.c */
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_creds *subject_creds,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ krb5_gss_cred_id_t *output_cred,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec,
+ krb5_context context);
+
/*
* These take unglued krb5-mech-specific contexts.
*/
/* gss_nt_krb5_principal. Object identifier for a krb5_principal. Do not use. */
{10, "\052\206\110\206\367\022\001\002\002\002"},
+
{ 0, 0 }
};
/*
* gss_set_sec_context_option() methods
*/
-#if 0
static struct {
gss_OID_desc oid;
OM_uint32 (*func)(OM_uint32 *, gss_ctx_id_t *, const gss_OID, const gss_buffer_t);
} krb5_gss_set_sec_context_option_ops[] = {
};
-#endif
static OM_uint32
krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
return GSS_S_NO_CONTEXT;
ctx = (krb5_gss_ctx_id_rec *) context_handle;
-
- if (!ctx->established)
- return GSS_S_NO_CONTEXT;
}
-#if 0
for (i = 0; i < sizeof(krb5_gss_set_sec_context_option_ops)/
sizeof(krb5_gss_set_sec_context_option_ops[0]); i++) {
if (g_OID_prefix_equal(desired_object, &krb5_gss_set_sec_context_option_ops[i].oid)) {
value);
}
}
-#endif
*minor_status = EINVAL;
{
{GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH, GSS_KRB5_SET_CRED_RCACHE_OID},
gss_krb5int_set_cred_rcache
- }
+ },
};
static OM_uint32
{
{GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH, GSS_KRB5_USE_KDC_CONTEXT_OID},
krb5int_gss_use_kdc_context
- }
+ },
};
static OM_uint32
krb5_gss_unwrap_iov,
krb5_gss_wrap_iov_length,
NULL, /* complete_auth_token */
+ krb5_gss_acquire_cred_impersonate_name,
+ NULL, /* krb5_gss_add_cred_impersonate_name */
NULL, /* display_name_ext */
krb5_gss_inquire_name,
krb5_gss_get_name_attribute,
krb5_creds **out_creds;
{
krb5_error_code code;
- krb5_creds in_creds;
+ krb5_creds in_creds, evidence_creds;
+ krb5_flags flags = 0;
+ krb5_principal cc_princ = NULL;
k5_mutex_assert_locked(&cred->lock);
memset(&in_creds, 0, sizeof(krb5_creds));
+ memset(&evidence_creds, 0, sizeof(krb5_creds));
in_creds.client = in_creds.server = NULL;
assert(cred->name != NULL);
- in_creds.client = cred->name->princ;
+ if ((code = krb5_cc_get_principal(context, cred->ccache, &cc_princ)))
+ goto cleanup;
+
+ /*
+ * Do constrained delegation if we have proxy credentials and
+ * we're not trying to get a ticket to ourselves (in which case
+ * we can just use the S4U2Self or evidence ticket directly).
+ */
+ if (cred->proxy_cred &&
+ !krb5_principal_compare(context, cc_princ, server->princ)) {
+ krb5_creds mcreds;
+
+ flags |= KRB5_GC_CANONICALIZE |
+ KRB5_GC_NO_STORE |
+ KRB5_GC_CONSTRAINED_DELEGATION;
+
+ memset(&mcreds, 0, sizeof(mcreds));
+
+ mcreds.magic = KV5M_CREDS;
+ mcreds.times.endtime = cred->tgt_expire;
+ mcreds.server = cc_princ;
+ mcreds.client = cred->name->princ;
+
+ code = krb5_cc_retrieve_cred(context, cred->ccache,
+ KRB5_TC_MATCH_TIMES, &mcreds,
+ &evidence_creds);
+ if (code)
+ goto cleanup;
+
+ assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
+
+ in_creds.client = cc_princ;
+ in_creds.second_ticket = evidence_creds.ticket;
+ } else {
+ in_creds.client = cred->name->princ;
+ }
+
in_creds.server = server->princ;
in_creds.times.endtime = endtime;
in_creds.authdata = NULL;
goto cleanup;
}
- code = krb5_get_credentials(context, 0, cred->ccache,
+ code = krb5_get_credentials(context, flags, cred->ccache,
&in_creds, out_creds);
if (code)
goto cleanup;
+ if (flags & KRB5_GC_CONSTRAINED_DELEGATION) {
+ if (!krb5_principal_compare(context, cred->name->princ,
+ (*out_creds)->client)) {
+ /* server did not support constrained delegation */
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+ }
+
/*
* Enforce a stricter limit (without timeskew forgiveness at the
* boundaries) because accept_sec_context code is also similarly
cleanup:
krb5_free_authdata(context, in_creds.authdata);
+ krb5_free_principal(context, cc_princ);
+ krb5_free_cred_contents(context, &evidence_creds);
return code;
}
*
* Do the grunt work of setting up a new context.
*/
-static OM_uint32
-new_connection(
+OM_uint32
+kg_new_connection(
OM_uint32 *minor_status,
krb5_gss_cred_id_t cred,
gss_ctx_id_t *context_handle,
/*SUPPRESS 29*/
if (*context_handle == GSS_C_NO_CONTEXT) {
- major_status = new_connection(minor_status, cred, context_handle,
- target_name, mech_type, req_flags,
- time_req, input_chan_bindings,
- input_token, actual_mech_type,
- output_token, ret_flags, time_rec,
- context, default_mech);
+ major_status = kg_new_connection(minor_status, cred, context_handle,
+ target_name, mech_type, req_flags,
+ time_req, input_chan_bindings,
+ input_token, actual_mech_type,
+ output_token, ret_flags, time_rec,
+ context, default_mech);
k5_mutex_unlock(&cred->lock);
if (*context_handle == GSS_C_NO_CONTEXT) {
save_error_info (*minor_status, context);
return GSS_S_COMPLETE;
}
+
--- /dev/null
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+static OM_uint32
+kg_set_desired_mechs(OM_uint32 *minor_status,
+ const gss_OID_set desired_mechs,
+ krb5_gss_cred_id_t cred)
+{
+ unsigned int i;
+
+ if (desired_mechs == GSS_C_NULL_OID_SET) {
+ cred->prerfc_mech = 1;
+ cred->rfc_mech = 1;
+ } else {
+ cred->prerfc_mech = 0;
+ cred->rfc_mech = 0;
+
+ for (i = 0; i < desired_mechs->count; i++) {
+ if (g_OID_equal(gss_mech_krb5_old, &desired_mechs->elements[i]))
+ cred->prerfc_mech = 1;
+ else if (g_OID_equal(gss_mech_krb5, &desired_mechs->elements[i]))
+ cred->rfc_mech = 1;
+ }
+
+ if (!cred->prerfc_mech && !cred->rfc_mech) {
+ *minor_status = 0;
+ return GSS_S_BAD_MECH;
+ }
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+kg_return_mechs(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t cred,
+ gss_OID_set *actual_mechs)
+{
+ OM_uint32 major_status, minor;
+ gss_OID_set mechs;
+
+ if (actual_mechs == NULL)
+ return GSS_S_COMPLETE;
+
+ major_status = generic_gss_create_empty_oid_set(minor_status, &mechs);
+ if (GSS_ERROR(major_status))
+ return major_status;
+
+ if (cred->prerfc_mech) {
+ major_status = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5_old,
+ &mechs);
+ if (GSS_ERROR(major_status)) {
+ generic_gss_release_oid_set(&minor, &mechs);
+ return major_status;
+ }
+ }
+ if (cred->rfc_mech) {
+ major_status = generic_gss_add_oid_set_member(minor_status,
+ gss_mech_krb5,
+ &mechs);
+ if (GSS_ERROR(major_status)) {
+ generic_gss_release_oid_set(&minor, &mechs);
+ return major_status;
+ }
+ }
+
+ *actual_mechs = mechs;
+
+ return GSS_S_COMPLETE;
+}
+
+static int
+kg_is_initiator_cred(krb5_gss_cred_id_t cred)
+{
+ return (cred->usage == GSS_C_INITIATE || cred->usage == GSS_C_BOTH) &&
+ (cred->ccache != NULL);
+}
+
+static OM_uint32
+kg_impersonate_name(OM_uint32 *minor_status,
+ const krb5_gss_cred_id_t impersonator_cred,
+ const krb5_gss_name_t user,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ krb5_gss_cred_id_t *output_cred,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_creds in_creds, *out_creds = NULL;
+
+ memset(&in_creds, 0, sizeof(in_creds));
+ memset(&out_creds, 0, sizeof(out_creds));
+
+ in_creds.client = user->princ;
+ in_creds.server = impersonator_cred->name->princ;
+
+ if (impersonator_cred->req_enctypes != NULL)
+ in_creds.keyblock.enctype = impersonator_cred->req_enctypes[0];
+
+ if (user->ad_context != NULL) {
+ code = krb5_authdata_export_attributes(context,
+ user->ad_context,
+ AD_USAGE_TGS_REQ,
+ &in_creds.authdata);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+ }
+
+ code = krb5_get_credentials_for_user(context,
+ KRB5_GC_CANONICALIZE | KRB5_GC_NO_STORE,
+ impersonator_cred->ccache,
+ &in_creds,
+ NULL, &out_creds);
+ if (code != 0) {
+ krb5_free_authdata(context, in_creds.authdata);
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = kg_compose_deleg_cred(minor_status,
+ impersonator_cred,
+ out_creds,
+ time_req,
+ desired_mechs,
+ output_cred,
+ actual_mechs,
+ time_rec,
+ context);
+
+ krb5_free_authdata(context, in_creds.authdata);
+ krb5_free_creds(context, out_creds);
+
+ return major_status;
+}
+
+OM_uint32
+krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t cred;
+ krb5_context context;
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (desired_name == GSS_C_NO_NAME)
+ return GSS_S_CALL_INACCESSIBLE_READ;
+
+ if (output_cred_handle == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_usage != GSS_C_INITIATE) {
+ *minor_status = (OM_uint32)G_BAD_USAGE;
+ return GSS_S_FAILURE;
+ }
+
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ code = krb5_gss_init_context(&context);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = krb5_gss_validate_cred_1(minor_status,
+ impersonator_cred_handle,
+ context);
+ if (GSS_ERROR(major_status)) {
+ krb5_free_context(context);
+ return major_status;
+ }
+
+ major_status = kg_impersonate_name(minor_status,
+ (krb5_gss_cred_id_t)impersonator_cred_handle,
+ (krb5_gss_name_t)desired_name,
+ time_req,
+ desired_mechs,
+ &cred,
+ actual_mechs,
+ time_rec,
+ context);
+
+ *output_cred_handle = (gss_cred_id_t)cred;
+
+ k5_mutex_unlock(&((krb5_gss_cred_id_t)impersonator_cred_handle)->lock);
+ krb5_free_context(context);
+
+ return major_status;
+
+}
+
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+ krb5_gss_cred_id_t impersonator_cred,
+ krb5_creds *subject_creds,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ krb5_gss_cred_id_t *output_cred,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec,
+ krb5_context context)
+{
+ OM_uint32 major_status;
+ krb5_error_code code;
+ krb5_gss_cred_id_t cred = NULL;
+
+ k5_mutex_assert_locked(&impersonator_cred->lock);
+
+ if (!kg_is_initiator_cred(impersonator_cred) ||
+ impersonator_cred->name == NULL ||
+ impersonator_cred->proxy_cred) {
+ code = G_BAD_USAGE;
+ goto cleanup;
+ }
+
+ assert(impersonator_cred->name->princ != NULL);
+
+ assert(subject_creds != NULL);
+ assert(subject_creds->client != NULL);
+
+ cred = xmalloc(sizeof(*cred));
+ if (cred == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ memset(cred, 0, sizeof(*cred));
+
+ code = k5_mutex_init(&cred->lock);
+ if (code != 0)
+ goto cleanup;
+
+ /*
+ * Only return a "proxy" credential for use with constrained
+ * delegation if the subject credentials are forwardable.
+ * Submitting non-forwardable credentials to the KDC for use
+ * with constrained delegation will only return an error.
+ */
+ cred->usage = GSS_C_INITIATE;
+ cred->proxy_cred = !!(subject_creds->ticket_flags & TKT_FLG_FORWARDABLE);
+
+ major_status = kg_set_desired_mechs(minor_status, desired_mechs, cred);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ cred->tgt_expire = impersonator_cred->tgt_expire;
+
+ code = kg_init_name(context, subject_creds->client, NULL, 0, &cred->name);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_cc_initialize(context, cred->ccache,
+ cred->proxy_cred ? impersonator_cred->name->princ :
+ subject_creds->client);
+ if (code != 0)
+ goto cleanup;
+
+ if (cred->proxy_cred) {
+ /* Impersonator's TGT will be necessary for S4U2Proxy */
+ code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
+ cred->ccache);
+ if (code != 0)
+ goto cleanup;
+ }
+
+ code = krb5_cc_store_cred(context, cred->ccache, subject_creds);
+ if (code != 0)
+ goto cleanup;
+
+ if (time_rec != NULL) {
+ krb5_timestamp now;
+
+ code = krb5_timeofday(context, &now);
+ if (code != 0)
+ goto cleanup;
+
+ *time_rec = cred->tgt_expire - now;
+ }
+
+ major_status = kg_return_mechs(minor_status, cred, actual_mechs);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+
+ if (!kg_save_cred_id((gss_cred_id_t)cred)) {
+ code = G_VALIDATE_FAILED;
+ goto cleanup;
+ }
+
+ major_status = GSS_S_COMPLETE;
+ *minor_status = 0;
+ *output_cred = cred;
+
+cleanup:
+ if (code != 0) {
+ *minor_status = code;
+ major_status = GSS_S_FAILURE;
+ }
+
+ if (GSS_ERROR(major_status) && cred != NULL) {
+ k5_mutex_destroy(&cred->lock);
+ krb5_cc_destroy(context, cred->ccache);
+ kg_release_name(context, 0, &cred->name);
+ xfree(cred);
+ }
+
+ return major_status;
+}
+
*minor_status = code;
return(GSS_S_DEFECTIVE_CREDENTIAL);
}
- if (!krb5_principal_compare(context, princ, cred->name->princ)) {
+ if (!cred->proxy_cred &&
+ !krb5_principal_compare(context, princ, cred->name->princ)) {
k5_mutex_unlock(&cred->lock);
*minor_status = KG_CCACHE_NOMATCH;
return(GSS_S_DEFECTIVE_CREDENTIAL);
GSS_KRB5_NT_PRINCIPAL_NAME
gss_accept_sec_context
gss_acquire_cred
+gss_acquire_cred_impersonate_name
gss_add_buffer_set_member
gss_add_cred
+gss_add_cred_impersonate_name
gss_add_oid_set_member
gss_canonicalize_name
gss_compare_name
SRCS = \
$(srcdir)/g_accept_sec_context.c \
$(srcdir)/g_acquire_cred.c \
+ $(srcdir)/g_acquire_cred_imp_name.c \
$(srcdir)/g_buffer_set.c \
$(srcdir)/g_canon_name.c \
$(srcdir)/g_compare_name.c \
OBJS = \
$(OUTPRE)g_accept_sec_context.$(OBJEXT) \
$(OUTPRE)g_acquire_cred.$(OBJEXT) \
+ $(OUTPRE)g_acquire_cred_imp_name.$(OBJEXT) \
$(OUTPRE)g_buffer_set.$(OBJEXT) \
$(OUTPRE)g_canon_name.$(OBJEXT) \
$(OUTPRE)g_compare_name.$(OBJEXT) \
STLIBOBJS = \
g_accept_sec_context.o \
g_acquire_cred.o \
+ g_acquire_cred_imp_name.o \
g_buffer_set.o \
g_canon_name.o \
g_compare_name.o \
gss_name_t tmp_src_name = GSS_C_NO_NAME;
gss_OID_desc token_mech_type_desc;
gss_OID token_mech_type = &token_mech_type_desc;
+ gss_OID actual_mech = GSS_C_NO_OID;
gss_mechanism mech;
status = val_acc_sec_ctx_args(minor_status,
input_cred_handle,
input_token_buffer,
input_chan_bindings,
- &internal_name,
- mech_type,
+ src_name ? &internal_name : NULL,
+ &actual_mech,
output_token,
&temp_ret_flags,
time_rec,
* then call gss_import_name() to create
* the union name struct cast to src_name
*/
- if (internal_name != NULL) {
- temp_status = gssint_convert_name_to_union_name(
- &temp_minor_status, mech,
- internal_name, &tmp_src_name);
- if (temp_status != GSS_S_COMPLETE) {
- *minor_status = temp_minor_status;
- map_error(minor_status, mech);
- if (output_token->length)
- (void) gss_release_buffer(&temp_minor_status,
- output_token);
- if (internal_name != GSS_C_NO_NAME)
- mech->gss_release_name(
- &temp_minor_status,
- &internal_name);
- return (temp_status);
- }
- if (src_name != NULL) {
+ if (src_name != NULL) {
+ if (internal_name != GSS_C_NO_NAME) {
+ /* consumes internal_name regardless of success */
+ temp_status = gssint_convert_name_to_union_name(
+ &temp_minor_status, mech,
+ internal_name, &tmp_src_name);
+ if (temp_status != GSS_S_COMPLETE) {
+ *minor_status = temp_minor_status;
+ map_error(minor_status, mech);
+ if (output_token->length)
+ (void) gss_release_buffer(&temp_minor_status,
+ output_token);
+ return (temp_status);
+ }
*src_name = tmp_src_name;
- }
- } else if (src_name != NULL) {
- *src_name = GSS_C_NO_NAME;
+ } else
+ *src_name = GSS_C_NO_NAME;
}
+#define g_OID_prefix_equal(o1, o2) \
+ (((o1)->length >= (o2)->length) && \
+ (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
+
/* Ensure we're returning correct creds format */
if ((temp_ret_flags & GSS_C_DELEG_FLAG) &&
tmp_d_cred != GSS_C_NO_CREDENTIAL) {
- gss_union_cred_t d_u_cred = NULL;
-
- d_u_cred = malloc(sizeof (gss_union_cred_desc));
- if (d_u_cred == NULL) {
- status = GSS_S_FAILURE;
- goto error_out;
- }
- (void) memset(d_u_cred, 0,
- sizeof (gss_union_cred_desc));
-
- d_u_cred->count = 1;
+ if (actual_mech != GSS_C_NO_OID &&
+ !g_OID_prefix_equal(actual_mech, token_mech_type)) {
+ *d_cred = tmp_d_cred; /* unwrapped pseudo-mech */
+ } else {
+ gss_union_cred_t d_u_cred = NULL;
- status = generic_gss_copy_oid(&temp_minor_status,
- token_mech_type,
- &d_u_cred->mechs_array);
+ d_u_cred = malloc(sizeof (gss_union_cred_desc));
+ if (d_u_cred == NULL) {
+ status = GSS_S_FAILURE;
+ goto error_out;
+ }
+ (void) memset(d_u_cred, 0, sizeof (gss_union_cred_desc));
- if (status != GSS_S_COMPLETE) {
- free(d_u_cred);
- goto error_out;
- }
+ d_u_cred->count = 1;
- d_u_cred->cred_array = malloc(sizeof (gss_cred_id_t));
- if (d_u_cred->cred_array != NULL) {
- d_u_cred->cred_array[0] = tmp_d_cred;
- } else {
- free(d_u_cred);
- status = GSS_S_FAILURE;
- goto error_out;
- }
+ status = generic_gss_copy_oid(&temp_minor_status,
+ token_mech_type,
+ &d_u_cred->mechs_array);
- internal_name = GSS_C_NO_NAME;
+ if (status != GSS_S_COMPLETE) {
+ free(d_u_cred);
+ goto error_out;
+ }
- d_u_cred->auxinfo.creation_time = time(0);
- d_u_cred->auxinfo.time_rec = 0;
- d_u_cred->loopback = d_u_cred;
+ d_u_cred->cred_array = malloc(sizeof(gss_cred_id_t));
+ if (d_u_cred->cred_array != NULL) {
+ d_u_cred->cred_array[0] = tmp_d_cred;
+ } else {
+ free(d_u_cred);
+ status = GSS_S_FAILURE;
+ goto error_out;
+ }
- if (mech->gss_inquire_cred) {
- status = mech->gss_inquire_cred(minor_status,
- tmp_d_cred,
- &internal_name,
- &d_u_cred->auxinfo.time_rec,
- &d_u_cred->auxinfo.cred_usage,
- NULL);
- if (status != GSS_S_COMPLETE)
- map_error(minor_status, mech);
- }
+ d_u_cred->auxinfo.creation_time = time(0);
+ d_u_cred->auxinfo.time_rec = 0;
+ d_u_cred->loopback = d_u_cred;
+
+ internal_name = GSS_C_NO_NAME;
+
+ if (mech->gss_inquire_cred) {
+ status = mech->gss_inquire_cred(minor_status,
+ tmp_d_cred,
+ &internal_name,
+ &d_u_cred->auxinfo.time_rec,
+ &d_u_cred->auxinfo.cred_usage,
+ NULL);
+ if (status != GSS_S_COMPLETE)
+ map_error(minor_status, mech);
+ }
- if (internal_name != NULL) {
- temp_status = gssint_convert_name_to_union_name(
- &temp_minor_status, mech,
- internal_name, &tmp_src_name);
- if (temp_status != GSS_S_COMPLETE) {
- *minor_status = temp_minor_status;
- map_error(minor_status, mech);
- if (output_token->length)
- (void) gss_release_buffer(
+ if (internal_name != GSS_C_NO_NAME) {
+ /* consumes internal_name regardless of success */
+ temp_status = gssint_convert_name_to_union_name(
+ &temp_minor_status, mech,
+ internal_name, &tmp_src_name);
+ if (temp_status != GSS_S_COMPLETE) {
+ *minor_status = temp_minor_status;
+ map_error(minor_status, mech);
+ if (output_token->length)
+ (void) gss_release_buffer(
+ &temp_minor_status,
+ output_token);
+ (void) gss_release_oid(&temp_minor_status,
+ &actual_mech);
+ free(d_u_cred->cred_array);
+ free(d_u_cred);
+ return (temp_status);
+ }
+
+ if (tmp_src_name != GSS_C_NO_NAME) {
+ status = gss_display_name(
&temp_minor_status,
- output_token);
- free(d_u_cred->cred_array);
- free(d_u_cred);
- return (temp_status);
+ tmp_src_name,
+ &d_u_cred->auxinfo.name,
+ &d_u_cred->auxinfo.name_type);
+ (void) gss_release_name(&temp_minor_status,
+ &tmp_src_name);
+ }
}
- }
- if (tmp_src_name != NULL) {
- status = gss_display_name(
- &temp_minor_status,
- tmp_src_name,
- &d_u_cred->auxinfo.name,
- &d_u_cred->auxinfo.name_type);
+ *d_cred = (gss_cred_id_t)d_u_cred;
}
-
- *d_cred = (gss_cred_id_t)d_u_cred;
}
- if (src_name == NULL && tmp_src_name != NULL)
- (void) gss_release_name(&temp_minor_status,
- &tmp_src_name);
+ if (mech_type != NULL)
+ *mech_type = actual_mech;
+ else
+ (void) gss_release_oid(&temp_minor_status, &actual_mech);
if (ret_flags != NULL)
*ret_flags = temp_ret_flags;
return (status);
/*
* Copyright 1996 by Sun Microsystems, Inc.
- *
+ *
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appears in all copies and
* without specific, written prior permission. Sun Microsystems makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
- *
+ *
* SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
#include <errno.h>
#include <time.h>
-static gss_OID_set
-create_actual_mechs(mechs_array, count)
- const gss_OID mechs_array;
- int count;
-{
- gss_OID_set actual_mechs;
- int i;
- OM_uint32 minor;
-
- actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
- if (!actual_mechs)
- return NULL;
-
- actual_mechs->elements = (gss_OID)
- malloc(sizeof (gss_OID_desc) * count);
- if (!actual_mechs->elements) {
- free(actual_mechs);
- return NULL;
- }
-
- actual_mechs->count = 0;
-
- for (i = 0; i < count; i++) {
- actual_mechs->elements[i].elements = (void *)
- malloc(mechs_array[i].length);
- if (actual_mechs->elements[i].elements == NULL) {
- (void) gss_release_oid_set(&minor, &actual_mechs);
- return (NULL);
- }
- g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
- actual_mechs->count++;
- }
-
- return actual_mechs;
-}
-
static OM_uint32
val_acq_cred_args(
OM_uint32 *minor_status,
mech = gssint_get_mechanism(NULL);
if (mech == NULL)
return (GSS_S_BAD_MECH);
-
+
mechs = &default_OID_set;
default_OID_set.count = 1;
default_OID_set.elements = &default_OID;
* setup the actual mechs output parameter
*/
if (actual_mechs != NULL) {
- if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
- creds->count)) == NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = creds->count;
+ oids.elements = creds->mechs_array;
+
+ major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(major)) {
(void) gss_release_cred(minor_status,
(gss_cred_id_t *)&creds);
- *minor_status = 0;
- return (GSS_S_FAILURE);
+ return (major);
}
}
gss_add_cred(minor_status, input_cred_handle,
desired_name, desired_mech, cred_usage,
initiator_time_req, acceptor_time_req,
- output_cred_handle, actual_mechs,
+ output_cred_handle, actual_mechs,
initiator_time_rec, acceptor_time_rec)
OM_uint32 *minor_status;
gss_cred_id_t input_cred_handle;
status = mech->gss_display_name(&temp_minor_status, internal_name,
&union_cred->auxinfo.name,
&union_cred->auxinfo.name_type);
-
+
if (status != GSS_S_COMPLETE)
goto errout;
}
g_OID_copy(&new_mechs_array[union_cred->count],
&mech->mech_type);
- if (actual_mechs) {
- *actual_mechs = create_actual_mechs(new_mechs_array,
- union_cred->count + 1);
- if (*actual_mechs == NULL) {
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = union_cred->count + 1;
+ oids.elements = new_mechs_array;
+
+ status = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(status)) {
free(new_mechs_array[union_cred->count].elements);
goto errout;
}
--- /dev/null
+/* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */
+
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, 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.
+ */
+
+/*
+ * glue routine for gss_acquire_cred_impersonate_name
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static OM_uint32
+val_acq_cred_impersonate_name_args(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NULL_OID_SET;
+
+ if (time_rec != NULL)
+ *time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (desired_name == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ OM_uint32 time_req,
+ const gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major = GSS_S_FAILURE;
+ OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+ gss_OID_set_desc default_OID_set;
+ gss_OID_set mechs;
+ gss_OID_desc default_OID;
+ gss_mechanism mech;
+ unsigned int i;
+ gss_union_cred_t creds;
+
+ major = val_acq_cred_impersonate_name_args(minor_status,
+ impersonator_cred_handle,
+ desired_name,
+ time_req,
+ desired_mechs,
+ cred_usage,
+ output_cred_handle,
+ actual_mechs,
+ time_rec);
+ if (major != GSS_S_COMPLETE)
+ return (major);
+
+ /* Initial value needed below. */
+ major = GSS_S_FAILURE;
+
+ /*
+ * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
+ * appropriate default. We use the first mechanism in the
+ * mechansim list as the default. This set is created with
+ * statics thus needs not be freed
+ */
+ if(desired_mechs == GSS_C_NULL_OID_SET) {
+ mech = gssint_get_mechanism(NULL);
+ if (mech == NULL)
+ return (GSS_S_BAD_MECH);
+
+ mechs = &default_OID_set;
+ default_OID_set.count = 1;
+ default_OID_set.elements = &default_OID;
+ default_OID.length = mech->mech_type.length;
+ default_OID.elements = mech->mech_type.elements;
+ } else
+ mechs = desired_mechs;
+
+ if (mechs->count == 0)
+ return (GSS_S_BAD_MECH);
+
+ /* allocate the output credential structure */
+ creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+ if (creds == NULL)
+ return (GSS_S_FAILURE);
+
+ /* initialize to 0s */
+ (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+ creds->loopback = creds;
+
+ /* for each requested mech attempt to obtain a credential */
+ for (i = 0; i < mechs->count; i++) {
+ major = gss_add_cred_impersonate_name(minor_status,
+ (gss_cred_id_t)creds,
+ impersonator_cred_handle,
+ desired_name,
+ &mechs->elements[i],
+ cred_usage,
+ time_req,
+ time_req, NULL,
+ NULL,
+ &initTimeOut,
+ &acceptTimeOut);
+ if (major == GSS_S_COMPLETE) {
+ /* update the credential's time */
+ if (cred_usage == GSS_C_ACCEPT) {
+ if (outTime > acceptTimeOut)
+ outTime = acceptTimeOut;
+ } else if (cred_usage == GSS_C_INITIATE) {
+ if (outTime > initTimeOut)
+ outTime = initTimeOut;
+ } else {
+ /*
+ * time_rec is the lesser of the
+ * init/accept times
+ */
+ if (initTimeOut > acceptTimeOut)
+ outTime = (outTime > acceptTimeOut) ?
+ acceptTimeOut : outTime;
+ else
+ outTime = (outTime > initTimeOut) ?
+ initTimeOut : outTime;
+ }
+ }
+ } /* for */
+
+ /* ensure that we have at least one credential element */
+ if (creds->count < 1) {
+ free(creds);
+ return (major);
+ }
+
+ /*
+ * fill in output parameters
+ * setup the actual mechs output parameter
+ */
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = creds->count;
+ oids.elements = creds->mechs_array;
+
+ major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(major)) {
+ (void) gss_release_cred(minor_status,
+ (gss_cred_id_t *)&creds);
+ return (major);
+ }
+ }
+
+ if (time_rec)
+ *time_rec = outTime;
+
+
+ creds->loopback = creds;
+ *output_cred_handle = (gss_cred_id_t)creds;
+ return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+val_add_cred_impersonate_name_args(
+ OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_cred_id_t impersonator_cred_handle,
+ gss_name_t desired_name,
+ gss_OID desired_mech,
+ gss_cred_usage_t cred_usage,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+
+ /* Initialize outputs. */
+
+ if (minor_status != NULL)
+ *minor_status = 0;
+
+ if (output_cred_handle != NULL)
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ if (actual_mechs != NULL)
+ *actual_mechs = GSS_C_NO_OID_SET;
+
+ if (acceptor_time_rec != NULL)
+ *acceptor_time_rec = 0;
+
+ if (initiator_time_rec != NULL)
+ *initiator_time_rec = 0;
+
+ /* Validate arguments. */
+
+ if (minor_status == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+ if (desired_name == GSS_C_NO_NAME)
+ return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+ output_cred_handle == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+ if (cred_usage != GSS_C_ACCEPT
+ && cred_usage != GSS_C_INITIATE
+ && cred_usage != GSS_C_BOTH) {
+ if (minor_status) {
+ *minor_status = EINVAL;
+ map_errcode(minor_status);
+ }
+ return GSS_S_FAILURE;
+ }
+
+ return (GSS_S_COMPLETE);
+}
+
+
+/* V2 KRB5_CALLCONV */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_impersonate_name(OM_uint32 *minor_status,
+ gss_cred_id_t input_cred_handle,
+ const gss_cred_id_t impersonator_cred_handle,
+ const gss_name_t desired_name,
+ const gss_OID desired_mech,
+ gss_cred_usage_t cred_usage,
+ OM_uint32 initiator_time_req,
+ OM_uint32 acceptor_time_req,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *initiator_time_rec,
+ OM_uint32 *acceptor_time_rec)
+{
+ OM_uint32 status, temp_minor_status;
+ OM_uint32 time_req, time_rec;
+ gss_union_name_t union_name;
+ gss_union_cred_t new_union_cred, union_cred;
+ gss_cred_id_t mech_impersonator_cred;
+ gss_name_t internal_name = GSS_C_NO_NAME;
+ gss_name_t allocated_name = GSS_C_NO_NAME;
+ gss_mechanism mech;
+ gss_cred_id_t cred = NULL;
+ gss_OID new_mechs_array = NULL;
+ gss_cred_id_t * new_cred_array = NULL;
+
+ status = val_add_cred_impersonate_name_args(minor_status,
+ input_cred_handle,
+ impersonator_cred_handle,
+ desired_name,
+ desired_mech,
+ cred_usage,
+ initiator_time_req,
+ acceptor_time_req,
+ output_cred_handle,
+ actual_mechs,
+ initiator_time_rec,
+ acceptor_time_rec);
+ if (status != GSS_S_COMPLETE)
+ return (status);
+
+ mech = gssint_get_mechanism(desired_mech);
+ if (!mech)
+ return GSS_S_BAD_MECH;
+ else if (!mech->gss_acquire_cred)
+ return (GSS_S_UNAVAILABLE);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (union_cred == NULL)
+ return (GSS_S_FAILURE);
+
+ (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+ /* for default credentials we will use GSS_C_NO_NAME */
+ internal_name = GSS_C_NO_NAME;
+ } else {
+ union_cred = (gss_union_cred_t)input_cred_handle;
+ if (gssint_get_mechanism_cred(union_cred, desired_mech) !=
+ GSS_C_NO_CREDENTIAL)
+ return (GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ mech_impersonator_cred =
+ gssint_get_mechanism_cred((gss_union_cred_t)impersonator_cred_handle,
+ desired_mech);
+ if (mech_impersonator_cred == GSS_C_NO_CREDENTIAL)
+ return (GSS_S_NO_CRED);
+
+ /* may need to create a mechanism specific name */
+ union_name = (gss_union_name_t)desired_name;
+ if (union_name->mech_type &&
+ g_OID_equal(union_name->mech_type,
+ &mech->mech_type))
+ internal_name = union_name->mech_name;
+ else {
+ if (gssint_import_internal_name(minor_status,
+ &mech->mech_type, union_name,
+ &allocated_name) != GSS_S_COMPLETE)
+ return (GSS_S_BAD_NAME);
+ internal_name = allocated_name;
+ }
+
+ if (cred_usage == GSS_C_ACCEPT)
+ time_req = acceptor_time_req;
+ else if (cred_usage == GSS_C_INITIATE)
+ time_req = initiator_time_req;
+ else if (cred_usage == GSS_C_BOTH)
+ time_req = (acceptor_time_req > initiator_time_req) ?
+ acceptor_time_req : initiator_time_req;
+ else
+ time_req = 0;
+
+ status = mech->gss_acquire_cred_impersonate_name(minor_status,
+ mech_impersonator_cred,
+ internal_name,
+ time_req,
+ GSS_C_NULL_OID_SET,
+ cred_usage,
+ &cred,
+ NULL,
+ &time_rec);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ goto errout;
+ }
+
+ /* may need to set credential auxinfo strucutre */
+ if (union_cred->auxinfo.creation_time == 0) {
+ union_cred->auxinfo.creation_time = time(NULL);
+ union_cred->auxinfo.time_rec = time_rec;
+ union_cred->auxinfo.cred_usage = cred_usage;
+
+ /*
+ * we must set the name; if name is not supplied
+ * we must do inquire cred to get it
+ */
+ if (internal_name == NULL) {
+ if (mech->gss_inquire_cred == NULL ||
+ ((status = mech->gss_inquire_cred(
+ &temp_minor_status, cred,
+ &allocated_name, NULL, NULL,
+ NULL)) != GSS_S_COMPLETE))
+ goto errout;
+ internal_name = allocated_name;
+ }
+
+ if (internal_name != GSS_C_NO_NAME) {
+ status = mech->gss_display_name(&temp_minor_status, internal_name,
+ &union_cred->auxinfo.name,
+ &union_cred->auxinfo.name_type);
+
+ if (status != GSS_S_COMPLETE)
+ goto errout;
+ }
+ }
+
+ /* now add the new credential elements */
+ new_mechs_array = (gss_OID)
+ malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
+ new_cred_array = (gss_cred_id_t *)
+ malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
+
+ if (!new_mechs_array || !new_cred_array) {
+ status = GSS_S_FAILURE;
+ goto errout;
+ }
+
+ if (acceptor_time_rec)
+ if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
+ *acceptor_time_rec = time_rec;
+ if (initiator_time_rec)
+ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
+ *initiator_time_rec = time_rec;
+
+ /*
+ * OK, expand the mechanism array and the credential array
+ */
+ (void) memcpy(new_mechs_array, union_cred->mechs_array,
+ sizeof (gss_OID_desc) * union_cred->count);
+ (void) memcpy(new_cred_array, union_cred->cred_array,
+ sizeof (gss_cred_id_t) * union_cred->count);
+
+ new_cred_array[union_cred->count] = cred;
+ if ((new_mechs_array[union_cred->count].elements =
+ malloc(mech->mech_type.length)) == NULL)
+ goto errout;
+
+ g_OID_copy(&new_mechs_array[union_cred->count],
+ &mech->mech_type);
+
+ if (actual_mechs != NULL) {
+ gss_OID_set_desc oids;
+
+ oids.count = union_cred->count + 1;
+ oids.elements = new_mechs_array;
+
+ status = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+ if (GSS_ERROR(status)) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ }
+
+ if (output_cred_handle == NULL) {
+ free(union_cred->mechs_array);
+ free(union_cred->cred_array);
+ new_union_cred = union_cred;
+ } else {
+ new_union_cred = malloc(sizeof (gss_union_cred_desc));
+ if (new_union_cred == NULL) {
+ free(new_mechs_array[union_cred->count].elements);
+ goto errout;
+ }
+ *new_union_cred = *union_cred;
+ *output_cred_handle = (gss_cred_id_t)new_union_cred;
+ }
+
+ new_union_cred->mechs_array = new_mechs_array;
+ new_union_cred->cred_array = new_cred_array;
+ new_union_cred->count++;
+ new_union_cred->loopback = new_union_cred;
+
+ /* We're done with the internal name. Free it if we allocated it. */
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &allocated_name);
+
+ return (GSS_S_COMPLETE);
+
+errout:
+ if (new_mechs_array)
+ free(new_mechs_array);
+ if (new_cred_array)
+ free(new_cred_array);
+
+ if (cred != NULL && mech->gss_release_cred)
+ mech->gss_release_cred(&temp_minor_status, &cred);
+
+ if (allocated_name)
+ (void) gssint_release_internal_name(&temp_minor_status,
+ &mech->mech_type,
+ &allocated_name);
+
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
+ if (union_cred->auxinfo.name.value)
+ free(union_cred->auxinfo.name.value);
+ free(union_cred);
+ }
+
+ return (status);
+}
if (union_cred == GSS_C_NO_CREDENTIAL)
return GSS_C_NO_CREDENTIAL;
- /* SPNEGO mechanism will again call into GSSAPI */
- if (g_OID_equal(&gss_spnego_mechanism_oid_desc, mech_type))
- return (gss_cred_id_t)union_cred;
-
for (i=0; i < union_cred->count; i++) {
if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
return union_cred->cred_array[i];
-
- /* for SPNEGO, check the next-lower set of creds */
- if (g_OID_equal(&gss_spnego_mechanism_oid_desc, &union_cred->mechs_array[i])) {
- gss_union_cred_t candidate_cred;
- gss_cred_id_t sub_cred;
-
- candidate_cred = (gss_union_cred_t)union_cred->cred_array[i];
- sub_cred = gssint_get_mechanism_cred(candidate_cred, mech_type);
-
- if(sub_cred != GSS_C_NO_CREDENTIAL)
- return sub_cred;
- }
}
return GSS_C_NO_CREDENTIAL;
}
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_unwrap_iov);
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_wrap_iov_length);
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_complete_auth_token);
- /* Naming extensions */
+ /* Services4User (introduced in 1.8) */
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_acquire_cred_impersonate_name);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_add_cred_impersonate_name);
+ /* Naming extensions (introduced in 1.8) */
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_display_name_ext);
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_name);
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_get_name_attribute);
return GSS_S_UNAVAILABLE;
status = mech->gss_set_sec_context_option(minor_status,
- ctx ? &internal_ctx :
- &ctx->internal_ctx_id,
+ ctx ? &ctx->internal_ctx_id :
+ &internal_ctx,
desired_object,
value);
if (status == GSS_S_COMPLETE) {
gss_buffer_t /* input_message_buffer */
);
+ /* New for 1.8 */
+
+ OM_uint32 (*gss_acquire_cred_impersonate_name)
+ (
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 * /* time_rec */
+ /* */);
+
+ OM_uint32 (*gss_add_cred_impersonate_name)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* input_cred_handle */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ const gss_OID, /* desired_mech */
+ gss_cred_usage_t, /* cred_usage */
+ OM_uint32, /* initiator_time_req */
+ OM_uint32, /* acceptor_time_req */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *, /* initiator_time_rec */
+ OM_uint32 * /* acceptor_time_rec */
+ /* */);
+
OM_uint32 (*gss_display_name_ext)
(
OM_uint32 *, /* minor_status */
gss_buffer_t, /* type_id */
gss_any_t * /* input */
/* */);
+
} *gss_mechanism;
/* This structure MUST NOT be used by any code outside libgss */
gss_name_t * /* input_name */
);
+OM_uint32 spnego_gss_inquire_cred
+(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ gss_name_t *, /* name */
+ OM_uint32 *, /* lifetime */
+ int *, /* cred_usage */
+ gss_OID_set * /* mechanisms */
+);
+
OM_uint32 spnego_gss_inquire_names_for_mech
(
OM_uint32 *, /* minor_status */
gss_buffer_set_t *data_set
);
+OM_uint32
+spnego_gss_inquire_cred_by_oid
+(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set
+);
+
OM_uint32
spnego_gss_set_sec_context_option
(
gss_buffer_t input_message_buffer
);
+OM_uint32
+spnego_gss_acquire_cred_impersonate_name(
+ OM_uint32 *, /* minor_status */
+ const gss_cred_id_t, /* impersonator_cred_handle */
+ const gss_name_t, /* desired_name */
+ OM_uint32, /* time_req */
+ const gss_OID_set, /* desired_mechs */
+ gss_cred_usage_t, /* cred_usage */
+ gss_cred_id_t *, /* output_cred_handle */
+ gss_OID_set *, /* actual_mechs */
+ OM_uint32 *); /* time_rec */
+
OM_uint32
spnego_gss_display_name_ext
(
spnego_gss_display_name,
spnego_gss_import_name,
spnego_gss_release_name,
- NULL, /* gss_inquire_cred */
+ spnego_gss_inquire_cred, /* gss_inquire_cred */
NULL, /* gss_add_cred */
#ifndef LEAN_CLIENT
spnego_gss_export_sec_context, /* gss_export_sec_context */
NULL, /* gss_export_name */
NULL, /* gss_store_cred */
spnego_gss_inquire_sec_context_by_oid, /* gss_inquire_sec_context_by_oid */
- NULL, /* gss_inquire_cred_by_oid */
+ spnego_gss_inquire_cred_by_oid, /* gss_inquire_cred_by_oid */
spnego_gss_set_sec_context_option, /* gss_set_sec_context_option */
NULL, /* gssspi_set_cred_option */
NULL, /* gssspi_mech_invoke */
spnego_gss_unwrap_iov,
spnego_gss_wrap_iov_length,
spnego_gss_complete_auth_token,
+ spnego_gss_complete_auth_token,
+ spnego_gss_acquire_cred_impersonate_name,
+ NULL, /* gss_add_cred_impersonate_name */
spnego_gss_display_name_ext,
spnego_gss_inquire_name,
spnego_gss_get_name_attribute,
*src_name = sc->internal_name;
}
release_spnego_ctx(&sc);
+ } else if (ret != GSS_S_CONTINUE_NEEDED) {
+ if (sc != NULL) {
+ gss_delete_sec_context(&tmpmin, &sc->ctx_handle,
+ GSS_C_NO_BUFFER);
+ release_spnego_ctx(&sc);
+ }
+ *context_handle = GSS_C_NO_CONTEXT;
}
gss_release_buffer(&tmpmin, &mechtok_out);
if (mechtok_in != GSS_C_NO_BUFFER) {
return (status);
}
+OM_uint32
+spnego_gss_inquire_cred(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ gss_name_t *name,
+ OM_uint32 *lifetime,
+ int *cred_usage,
+ gss_OID_set *mechanisms)
+{
+ OM_uint32 status;
+ gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
+ OM_uint32 tmp_minor_status;
+ OM_uint32 initiator_lifetime, acceptor_lifetime;
+
+ dsyslog("Entering inquire_cred\n");
+
+ /*
+ * To avoid infinite recursion, if GSS_C_NO_CREDENTIAL is
+ * supplied we call gss_inquire_cred_by_mech() on the
+ * first non-SPNEGO mechanism.
+ */
+ if (cred_handle == GSS_C_NO_CREDENTIAL) {
+ status = get_available_mechs(minor_status,
+ GSS_C_NO_NAME,
+ GSS_C_BOTH,
+ &creds,
+ mechanisms);
+ if (status != GSS_S_COMPLETE) {
+ dsyslog("Leaving inquire_cred\n");
+ return (status);
+ }
+
+ if ((*mechanisms)->count == 0) {
+ gss_release_cred(&tmp_minor_status, &creds);
+ gss_release_oid_set(&tmp_minor_status, mechanisms);
+ dsyslog("Leaving inquire_cred\n");
+ return (GSS_S_DEFECTIVE_CREDENTIAL);
+ }
+
+ assert((*mechanisms)->elements != NULL);
+
+ status = gss_inquire_cred_by_mech(minor_status,
+ creds,
+ &(*mechanisms)->elements[0],
+ name,
+ &initiator_lifetime,
+ &acceptor_lifetime,
+ cred_usage);
+ if (status != GSS_S_COMPLETE) {
+ gss_release_cred(&tmp_minor_status, &creds);
+ dsyslog("Leaving inquire_cred\n");
+ return (status);
+ }
+
+ if (lifetime != NULL)
+ *lifetime = (*cred_usage == GSS_C_ACCEPT) ?
+ acceptor_lifetime : initiator_lifetime;
+
+ gss_release_cred(&tmp_minor_status, &creds);
+ } else {
+ status = gss_inquire_cred(minor_status, cred_handle,
+ name, lifetime,
+ cred_usage, mechanisms);
+ }
+
+ dsyslog("Leaving inquire_cred\n");
+
+ return (status);
+}
+
/*ARGSUSED*/
OM_uint32
spnego_gss_compare_name(
return (ret);
}
+OM_uint32
+spnego_gss_inquire_cred_by_oid(
+ OM_uint32 *minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_object,
+ gss_buffer_set_t *data_set)
+{
+ OM_uint32 ret;
+ ret = gss_inquire_cred_by_oid(minor_status,
+ cred_handle,
+ desired_object,
+ data_set);
+ return (ret);
+}
+
OM_uint32
spnego_gss_set_sec_context_option(
OM_uint32 *minor_status,
return (ret);
}
+OM_uint32
+spnego_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+ const gss_cred_id_t impersonator_cred_handle,
+ gss_name_t desired_name,
+ OM_uint32 time_req,
+ gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 status;
+ gss_OID_set amechs = GSS_C_NULL_OID_SET;
+
+ dsyslog("Entering spnego_gss_acquire_cred_impersonate_name\n");
+
+ if (actual_mechs)
+ *actual_mechs = NULL;
+
+ if (time_rec)
+ *time_rec = 0;
+
+ if (desired_mechs == GSS_C_NO_OID_SET) {
+ status = gss_inquire_cred(minor_status,
+ impersonator_cred_handle,
+ NULL, NULL,
+ NULL, &amechs);
+ if (status != GSS_S_COMPLETE)
+ return status;
+
+ desired_mechs = amechs;
+ }
+
+ status = gss_acquire_cred_impersonate_name(minor_status,
+ impersonator_cred_handle,
+ desired_name, time_req,
+ desired_mechs, cred_usage,
+ output_cred_handle, actual_mechs,
+ time_rec);
+
+ if (amechs != GSS_C_NULL_OID_SET)
+ (void) gss_release_oid_set(minor_status, &amechs);
+
+ dsyslog("Leaving spnego_gss_acquire_cred_impersonate_name\n");
+ return (status);
+}
+
OM_uint32
spnego_gss_display_name_ext(OM_uint32 *minor_status,
gss_name_t name,
static const char flags_service_in[] = "service";
static const char flags_pwsvc_in[] = "pwservice";
static const char flags_md5_in[] = "md5";
+static const char flags_ok_to_auth_as_delegate_in[] = "ok-to-auth-as-delegate";
+static const char flags_no_auth_data_required_in[] = "no-auth-data-required";
static const char flags_pdate_out[] = "Not Postdateable";
static const char flags_fwd_out[] = "Not Forwardable";
static const char flags_tgtbased_out[] = "No TGT-based requests";
static const char flags_proxy_out[] = "Not proxiable";
static const char flags_dup_skey_out[] = "No DUP_SKEY requests";
static const char flags_tickets_out[] = "All Tickets Disallowed";
-static const char flags_preauth_out[] = "Preauthorization required";
-static const char flags_hwauth_out[] = "HW Authorization required";
+static const char flags_preauth_out[] = "Preauthentication required";
+static const char flags_hwauth_out[] = "HW authentication required";
static const char flags_ok_as_delegate_out[] = "OK as Delegate";
static const char flags_pwchange_out[] = "Password Change required";
static const char flags_service_out[] = "Service Disabled";
static const char flags_pwsvc_out[] = "Password Changing Service";
static const char flags_md5_out[] = "RSA-MD5 supported";
+static const char flags_ok_to_auth_as_delegate_out[] = "Protocol transition with delegation allowed";
+static const char flags_no_auth_data_required_out[] = "No authorization data required";
static const char flags_default_neg[] = "-";
static const char flags_default_sep[] = " ";
{ KRB5_KDB_REQUIRES_PWCHANGE, 1, flags_pwchange_in, flags_pwchange_out},
{ KRB5_KDB_DISALLOW_SVR, 0, flags_service_in, flags_service_out },
{ KRB5_KDB_PWCHANGE_SERVICE, 1, flags_pwsvc_in, flags_pwsvc_out },
-{ KRB5_KDB_SUPPORT_DESMD5, 1, flags_md5_in, flags_md5_out }
+{ KRB5_KDB_SUPPORT_DESMD5, 1, flags_md5_in, flags_md5_out },
+{ KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, 1, flags_ok_to_auth_as_delegate_in, flags_ok_to_auth_as_delegate_out },
+{ KRB5_KDB_NO_AUTH_DATA_REQUIRED, 1, flags_no_auth_data_required_in, flags_no_auth_data_required_out }
};
static const int flags_table_nents = sizeof(flags_table)/
sizeof(flags_table[0]);
set pid [spawn $API]
expect {
-re "$prompt$" {}
- eof { error "EOF starting API" }
- timeout { error "Timeout starting API" }
+ eof { perror "EOF starting API" }
+ timeout { perror "Timeout starting API" }
}
if {! [info exists env(TCLUTIL)]} {
- error "TCLUTIL environment variable isn't set"
+ perror "TCLUTIL environment variable isn't set"
}
# tcl 8.4 for some reason screws up autodetection of output
# EOL translation. Work around it for now.
send "if { \[info commands fconfigure\] ne \"\" } { fconfigure stdout -translation lf }\n"
expect {
-re "$prompt$" {}
- eof { error "EOF starting API" }
- timeout { error "Timeout starting API" }
+ eof { perror "EOF starting API" }
+ timeout { perror "Timeout starting API" }
}
send "source $env(TCLUTIL)\n"
expect {
-re "$prompt$" {}
- eof { error "EOF starting API" }
- timeout { error "Timeout starting API" }
+ eof { perror "EOF starting API" }
+ timeout { perror "Timeout starting API" }
}
send "set current_struct_version \[expr \$KADM5_STRUCT_VERSION &~ \$KADM5_STRUCT_VERSION_MASK\]\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
send "set current_api_version \[expr \$KADM5_API_VERSION_2 &~ \$KADM5_API_VERSION_MASK\]\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
send "set bad_struct_version_mask \[expr 0x65432100 | \$current_struct_version\]\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
send "set bad_api_version_mask \[expr 0x65432100 | \$current_api_version\]\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
send "set no_api_version_mask \$current_api_version\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
send "set no_struct_version_mask \$current_struct_version\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
send "set old_api_version \[expr \$KADM5_API_VERSION_MASK | 0x00\]\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
send "set old_struct_version \[expr \$KADM5_STRUCT_VERSION_MASK | 0x00\]\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
send "set new_api_version \[expr \$KADM5_API_VERSION_MASK | 0xca\]\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
send "set new_struct_version \[expr \$KADM5_STRUCT_VERSION_MASK | 0xca\]\n"
expect {
-re "$prompt$" {}
- eof { error "EOF setting API varibles"}
- timeout { error "timeout setting API varibles"}
+ eof { perror "EOF setting API varibles"}
+ timeout { perror "timeout setting API varibles"}
}
set api_pid $pid
$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
lib_handle
}]} {
- error "$test: unexpected failure in init"
+ perror "$test: unexpected failure in init"
return
}
verbose "+++ restarted api ($lib_pid) for lib"
expect {
-re "OK .*$prompt$" { return 1 }
-re "ERROR .*$prompt$" { return 0 }
- "wrong # args" { error "$test: wrong number args"; return 0 }
+ "wrong # args" { perror "$test: wrong number args"; return 0 }
timeout { fail "$test: timeout"; return 0 }
eof { fail "$test: eof"; api_exit; lib_start_api; return 0 }
}
send "[string trim $command]\n"
expect {
-re "$prompt$" { return 1}
- "wrong # args" { error "$test: wrong number args"; return 0 }
+ "wrong # args" { perror "$test: wrong number args"; return 0 }
timeout { error_and_restart "timeout" }
eof { api_exit; lib_start_api; return 0 }
}
-re "ERROR .*$prompt$" {
fail "$test: $expect_out(buffer)"; return 0
}
- "wrong # args" { error "$test: wrong number args"; return 0 }
+ "wrong # args" { perror "$test: wrong number args"; return 0 }
timeout { fail "$test: timeout"; return 0 }
eof { fail "$test: eof"; api_exit; lib_start_api; return 0 }
}
-re "ERROR .*$code.*$prompt$" { pass "$test"; return 1 }
-re "ERROR .*$prompt$" { fail "$test: bad failure"; return 0 }
-re "OK .*$prompt$" { fail "$test: bad success"; return 0 }
- "wrong # args" { error "$test: wrong number args"; return 0 }
+ "wrong # args" { perror "$test: wrong number args"; return 0 }
timeout { fail "$test: timeout"; return 0 }
eof { fail "$test: eof"; api_exit; lib_start_api; return 0 }
}
expect {
-re "ERROR .*$prompt$" { pass "$test:"; return 1 }
-re "OK .*$prompt$" { fail "$test: bad success"; return 0 }
- "wrong # args" { error "$test: wrong number args"; return 0 }
+ "wrong # args" { perror "$test: wrong number args"; return 0 }
timeout { fail "$test: timeout"; return 0 }
eof { fail "$test: eof"; api_exit; lib_start_api; return 0 }
}
expect {
-re "$prompt$" {}
- "wrong # args" { error "$test: wrong number args"; return 0 }
+ "wrong # args" { perror "$test: wrong number args"; return 0 }
eof { api_exit; lib_start_api }
}
}
lib_start_api
set ret [cmd [format {
- kadm5_get_principal $lib_handle "%s" principal
+ kadm5_get_principal $lib_handle "%s" principal \
+ KADM5_PRINCIPAL_NORMAL_MASK
} $name]]
# puts stdout "Finishing principal_exists."
# the parent, which is us, to read pending data.
expect {
- "when initializing cache" { error "kinit failed: $expect_out(buffer)" }
+ "when initializing cache" { perror "kinit failed: $expect_out(buffer)" }
eof {}
}
wait
spawn $kadmin_local -e "$keysalts"
expect {
"kadmin.local:" {}
- default { error "waiting for kadmin.local prompt"; return 1}
+ default { perror "waiting for kadmin.local prompt"; return 1}
}
send "ank -pw \"$name\" \"$name\"\n"
expect {
-re "Principal \"$name.*\" created." {}
"kadmin.local:" {
- error "expecting principal created message";
+ perror "expecting principal created message";
return 1
}
- default { error "waiting for principal created message"; return 1 }
+ default { perror "waiting for principal created message"; return 1 }
}
expect {
"kadmin.local:" {}
- default { error "waiting for kadmin.local prompt"; return 1 }
+ default { perror "waiting for kadmin.local prompt"; return 1 }
}
close
wait
return retval;
}
+asn1_error_code asn1_decode_s4u_userid(asn1buf *buf, krb5_s4u_userid *val)
+{
+ setup();
+ val->nonce = 0;
+ val->user = NULL;
+ val->subject_cert.data = NULL;
+ val->options = 0;
+ { begin_structure();
+ get_field(val->nonce,0,asn1_decode_int32);
+ alloc_principal(val->user);
+ opt_field(val->user,1,asn1_decode_principal_name,0);
+ get_field(val->user,2,asn1_decode_realm);
+ opt_lenfield(val->subject_cert.length,val->subject_cert.data,3,asn1_decode_charstring);
+ opt_field(val->options,4,asn1_decode_krb5_flags,0);
+ end_structure();
+ }
+ return 0;
+error_out:
+ krb5_free_principal(NULL, val->user);
+ krb5_free_data_contents(NULL, &val->subject_cert);
+ val->user = NULL;
+ val->subject_cert.data = NULL;
+ return retval;
+}
+
+asn1_error_code asn1_decode_pa_s4u_x509_user(asn1buf *buf, krb5_pa_s4u_x509_user *val)
+{
+ setup();
+ val->cksum.contents = NULL;
+ { begin_structure();
+ get_field(val->user_id,0,asn1_decode_s4u_userid);
+ get_field(val->cksum,1,asn1_decode_checksum);
+ end_structure();
+ }
+ return 0;
+error_out:
+ krb5_free_s4u_userid_contents(NULL, &val->user_id);
+ krb5_free_checksum_contents(NULL, &val->cksum);
+ return retval;
+}
+
asn1_error_code asn1_decode_pa_pac_req(asn1buf *buf, krb5_pa_pac_req *val)
{
setup();
(asn1buf *buf, krb5_data *rep, krb5_principal *principal);
asn1_error_code asn1_decode_pa_for_user
(asn1buf *buf, krb5_pa_for_user *val);
+asn1_error_code asn1_decode_s4u_userid
+ (asn1buf *buf, krb5_s4u_userid *val);
+asn1_error_code asn1_decode_pa_s4u_x509_user
+ (asn1buf *buf, krb5_pa_s4u_x509_user *val);
asn1_error_code asn1_decode_pa_pac_req
(asn1buf *buf, krb5_pa_pac_req *val);
optional |= (1u << 8);
if (val->caddrs != NULL && val->caddrs[0] != NULL)
optional |= (1u << 11);
+ if (val->enc_padata != NULL)
+ optional |= (1u << 12);
return optional;
}
DEFSEQTYPE(pa_for_user, krb5_pa_for_user, pa_for_user_fields, 0);
+/* [MS-SFU] Section 2.2.2. */
+static const struct field_info s4u_userid_fields[] = {
+ FIELDOF_NORM(krb5_s4u_userid, int32, nonce, 0),
+ FIELDOF_OPT(krb5_s4u_userid, principal, user, 1, 1),
+ FIELDOF_NORM(krb5_s4u_userid, realm_of_principal, user, 2),
+ FIELDOF_OPT(krb5_s4u_userid, ostring_data, subject_cert, 3, 3),
+ FIELDOF_OPT(krb5_s4u_userid, krb5_flags, options, 4, 4),
+};
+
+static unsigned int s4u_userid_optional (const void *p) {
+ const krb5_s4u_userid *val = p;
+ unsigned int optional = 0;
+ if (val->user != NULL && val->user->length != 0)
+ optional |= (1u)<<1;
+ if (val->subject_cert.length != 0)
+ optional |= (1u)<<3;
+ if (val->options != 0)
+ optional |= (1u)<<4;
+ return optional;
+}
+
+DEFSEQTYPE(s4u_userid, krb5_s4u_userid, s4u_userid_fields, s4u_userid_optional);
+
+static const struct field_info pa_s4u_x509_user_fields[] = {
+ FIELDOF_NORM(krb5_pa_s4u_x509_user, s4u_userid, user_id, 0),
+ FIELDOF_NORM(krb5_pa_s4u_x509_user, checksum, cksum, 1),
+};
+
+DEFSEQTYPE(pa_s4u_x509_user, krb5_pa_s4u_x509_user, pa_s4u_x509_user_fields, 0);
+
/* draft-ietf-krb-wg-kerberos-referrals Appendix A. */
static const struct field_info pa_svr_referral_data_fields[] = {
FIELDOF_NORM(krb5_pa_svr_referral_data, realm_of_principal, principal, 0),
predicted_sam_response);
MAKE_FULL_ENCODER(encode_krb5_setpw_req, setpw_req);
MAKE_FULL_ENCODER(encode_krb5_pa_for_user, pa_for_user);
+MAKE_FULL_ENCODER(encode_krb5_s4u_userid, s4u_userid);
+MAKE_FULL_ENCODER(encode_krb5_pa_s4u_x509_user, pa_s4u_x509_user);
MAKE_FULL_ENCODER(encode_krb5_pa_svr_referral_data, pa_svr_referral_data);
MAKE_FULL_ENCODER(encode_krb5_pa_server_referral_data, pa_server_referral_data);
MAKE_FULL_ENCODER(encode_krb5_etype_list, etype_list);
cleanup(free);
}
+krb5_error_code
+decode_krb5_pa_s4u_x509_user(const krb5_data *code, krb5_pa_s4u_x509_user **repptr)
+{
+ setup_buf_only(krb5_pa_s4u_x509_user *);
+ alloc_field(rep);
+
+ retval = asn1_decode_pa_s4u_x509_user(&buf, rep);
+ if (retval) clean_return(retval);
+
+ cleanup(free);
+}
+
krb5_error_code
decode_krb5_pa_pac_req(const krb5_data *code, krb5_pa_pac_req **repptr)
{
rd_req_dec.o \
rd_safe.o \
recvauth.o \
+ s4u_creds.o \
sendauth.o \
send_tgs.o \
ser_actx.o \
$(OUTPRE)rd_req_dec.$(OBJEXT) \
$(OUTPRE)rd_safe.$(OBJEXT) \
$(OUTPRE)recvauth.$(OBJEXT) \
+ $(OUTPRE)s4u_creds.$(OBJEXT) \
$(OUTPRE)sendauth.$(OBJEXT) \
$(OUTPRE)send_tgs.$(OBJEXT) \
$(OUTPRE)ser_actx.$(OBJEXT) \
$(srcdir)/rd_req_dec.c \
$(srcdir)/rd_safe.c \
$(srcdir)/recvauth.c \
+ $(srcdir)/s4u_creds.c \
$(srcdir)/sendauth.c \
$(srcdir)/send_tgs.c \
$(srcdir)/ser_actx.c \
DUMP_PRINC("gc_from_kdc: server as requested", supplied_server);
+ if (in_cred->second_ticket.length != 0 &&
+ (kdcopt & KDC_OPT_CNAME_IN_ADDL_TKT) == 0) {
+ kdcopt |= KDC_OPT_ENC_TKT_IN_SKEY;
+ }
+
/*
* Try requesting a service ticket from our local KDC with referrals
* turned on. If the first referral succeeds, follow a referral-only
retval = krb5_get_cred_via_tkt(context, tgtptr,
KDC_OPT_CANONICALIZE |
FLAGS2OPTS(tgtptr->ticket_flags) |
- kdcopt |
- (in_cred->second_ticket.length ?
- KDC_OPT_ENC_TKT_IN_SKEY : 0),
+ kdcopt,
tgtptr->addresses, in_cred, out_cred);
if (retval) {
DPRINTF(("gc_from_kdc: referral TGS-REQ request failed: <%s>\n",
"retrying without option.\n", referral_count + 1));
retval = krb5_get_cred_via_tkt(context, tgtptr,
FLAGS2OPTS(tgtptr->ticket_flags) |
- kdcopt |
- (in_cred->second_ticket.length ?
- KDC_OPT_ENC_TKT_IN_SKEY : 0),
+ kdcopt,
tgtptr->addresses,
in_cred, out_cred);
/* Whether or not that succeeded, we're done. */
retval = krb5_get_cred_via_tkt(context, tgtptr,
KDC_OPT_CANONICALIZE |
FLAGS2OPTS(tgtptr->ticket_flags) |
- kdcopt |
- (in_cred->second_ticket.length ?
- KDC_OPT_ENC_TKT_IN_SKEY : 0),
+ kdcopt,
tgtptr->addresses,
in_cred, out_cred);
goto cleanup;
context->use_conf_ktypes = old_use_conf_ktypes;
retval = krb5_get_cred_via_tkt(context, tgtptr,
FLAGS2OPTS(tgtptr->ticket_flags) |
- kdcopt |
- (in_cred->second_ticket.length ?
- KDC_OPT_ENC_TKT_IN_SKEY : 0),
+ kdcopt,
tgtptr->addresses, in_cred, out_cred);
cleanup:
/*
* lib/krb5/krb/gc_via_tgt.c
*
- * Copyright 1990,1991,2007,2008 by the Massachusetts Institute of Technology.
+ * Copyright 1990,1991,2007-2009 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
krb5_flags kdcoptions, krb5_address *const *address,
krb5_creds *in_cred, krb5_creds **out_cred)
+{
+ return krb5_get_cred_via_tkt_ext (context, tkt,
+ kdcoptions, address,
+ NULL, in_cred, NULL, NULL,
+ NULL, NULL, out_cred, NULL);
+}
+
+krb5_error_code
+krb5_get_cred_via_tkt_ext (krb5_context context, krb5_creds *tkt,
+ krb5_flags kdcoptions, krb5_address *const *address,
+ krb5_pa_data **in_padata,
+ krb5_creds *in_cred,
+ krb5_error_code (*pacb_fct)(krb5_context,
+ krb5_keyblock *,
+ krb5_kdc_req *,
+ void *),
+ void *pacb_data,
+ krb5_pa_data ***out_padata,
+ krb5_pa_data ***out_enc_padata,
+ krb5_creds **out_cred,
+ krb5_keyblock **out_subkey)
{
krb5_error_code retval;
krb5_kdc_rep *dec_rep;
krb5_response tgsrep;
krb5_enctype *enctypes = 0;
krb5_keyblock *subkey = NULL;
+ krb5_boolean s4u2self = FALSE, second_tkt;
#ifdef DEBUG_REFERRALS
printf("krb5_get_cred_via_tkt starting; referral flag is %s\n", kdcoptions&KDC_OPT_CANONICALIZE?"on":"off");
if (!tkt->ticket.length)
return KRB5_NO_TKT_SUPPLIED;
- if ((kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) &&
- (!in_cred->second_ticket.length))
+ second_tkt = ((kdcoptions & (KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)) != 0);
+
+ if (second_tkt && !in_cred->second_ticket.length)
return(KRB5_NO_2ND_TKT);
+ s4u2self = krb5int_find_pa_data(context, in_padata, KRB5_PADATA_S4U_X509_USER) ||
+ krb5int_find_pa_data(context, in_padata, KRB5_PADATA_FOR_USER);
/* check if we have the right TGT */
/* tkt->server must be equal to */
enctypes[0] = in_cred->keyblock.enctype;
enctypes[1] = 0;
}
-
+
retval = krb5int_send_tgs(context, kdcoptions, &in_cred->times, enctypes,
in_cred->server, address, in_cred->authdata,
- 0, /* no padata */
- (kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) ?
- &in_cred->second_ticket : NULL,
- tkt, &tgsrep, &subkey);
+ in_padata,
+ second_tkt ? &in_cred->second_ticket : NULL,
+ tkt, pacb_fct, pacb_data, &tgsrep, &subkey);
if (enctypes)
free(enctypes);
if (retval) {
/* make sure the response hasn't been tampered with..... */
retval = 0;
- if (!krb5_principal_compare(context, dec_rep->client, tkt->client))
- retval = KRB5_KDCREP_MODIFIED;
+ if (s4u2self && !IS_TGS_PRINC(context, dec_rep->ticket->server)) {
+ /* Final hop, check whether KDC supports S4U2Self */
+ if (krb5_principal_compare(context, dec_rep->client, in_cred->server))
+ retval = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+ } else if ((kdcoptions & KDC_OPT_CNAME_IN_ADDL_TKT) == 0) {
+ /* XXX for constrained delegation this check must be performed by caller
+ * as we don't have access to the key to decrypt the evidence ticket.
+ */
+ if (!krb5_principal_compare(context, dec_rep->client, tkt->client))
+ retval = KRB5_KDCREP_MODIFIED;
+ }
if (retval == 0)
retval = check_reply_server(context, kdcoptions, in_cred, dec_rep);
retval = KRB5_KDCREP_SKEW;
goto error_3;
}
+
+ if (out_padata != NULL) {
+ *out_padata = dec_rep->padata;
+ dec_rep->padata = NULL;
+ }
+ if (out_enc_padata != NULL) {
+ *out_enc_padata = dec_rep->enc_part2->enc_padata;
+ dec_rep->enc_part2->enc_padata = NULL;
+ }
retval = krb5_kdcrep2creds(context, dec_rep, address,
&in_cred->second_ticket, out_cred);
error_3:;
- if (subkey != NULL)
- krb5_free_keyblock(context, subkey);
+ if (subkey != NULL) {
+ if (retval == 0 && out_subkey != NULL)
+ *out_subkey = subkey;
+ else
+ krb5_free_keyblock(context, subkey);
+ }
memset(dec_rep->enc_part2->session->contents, 0,
dec_rep->enc_part2->session->length);
#include "k5-int.h"
#include "int-proto.h"
-static krb5_error_code
+krb5_error_code
krb5_get_credentials_core(krb5_context context, krb5_flags options,
krb5_creds *in_creds, krb5_creds *mcreds,
krb5_flags *fields)
if (ret)
return ret;
}
- if (options & KRB5_GC_USER_USER) {
+ if (options & (KRB5_GC_USER_USER | KRB5_GC_CONSTRAINED_DELEGATION)) {
/* also match on identical 2nd tkt and tkt encrypted in a
session key */
- *fields |= KRB5_TC_MATCH_2ND_TKT|KRB5_TC_MATCH_IS_SKEY;
- mcreds->is_skey = TRUE;
+ *fields |= KRB5_TC_MATCH_2ND_TKT;
+ if (options & KRB5_GC_USER_USER) {
+ *fields |= KRB5_TC_MATCH_IS_SKEY;
+ mcreds->is_skey = TRUE;
+ }
mcreds->second_ticket = in_creds->second_ticket;
if (!in_creds->second_ticket.length)
return KRB5_NO_2ND_TKT;
int not_ktype;
int kdcopt = 0;
- retval = krb5_get_credentials_core(context, options,
- in_creds,
- &mcreds, &fields);
+ if ((options & KRB5_GC_CONSTRAINED_DELEGATION) == 0) {
+ retval = krb5_get_credentials_core(context, options,
+ in_creds,
+ &mcreds, &fields);
- if (retval) return retval;
+ if (retval)
+ return retval;
- if ((ncreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL)
- return ENOMEM;
+ if ((ncreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL)
+ return ENOMEM;
- memset(ncreds, 0, sizeof(krb5_creds));
- ncreds->magic = KV5M_CREDS;
+ memset(ncreds, 0, sizeof(krb5_creds));
+ ncreds->magic = KV5M_CREDS;
- /* The caller is now responsible for cleaning up in_creds */
- if ((retval = krb5_cc_retrieve_cred(context, ccache, fields, &mcreds,
- ncreds))) {
- free(ncreds);
- ncreds = in_creds;
+ /* The caller is now responsible for cleaning up in_creds */
+ if ((retval = krb5_cc_retrieve_cred(context, ccache, fields, &mcreds,
+ ncreds))) {
+ free(ncreds);
+ ncreds = in_creds;
+ } else {
+ *out_creds = ncreds;
+ }
} else {
- *out_creds = ncreds;
+ /*
+ * To do this usefully for constrained delegation, we would
+ * need to look inside second_ticket, which we can't do.
+ */
+ ncreds = in_creds;
+ retval = KRB5_CC_NOTFOUND;
}
if ((retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE)
if (options & KRB5_GC_CANONICALIZE)
kdcopt |= KDC_OPT_CANONICALIZE;
+ if (options & KRB5_GC_FORWARDABLE)
+ kdcopt |= KDC_OPT_FORWARDABLE;
+ if (options & KRB5_GC_NO_TRANSIT_CHECK)
+ kdcopt |= KDC_OPT_DISABLE_TRANSITED_CHECK;
+ if (options & KRB5_GC_CONSTRAINED_DELEGATION) {
+ if (options & KRB5_GC_USER_USER)
+ return EINVAL;
+ kdcopt |= KDC_OPT_FORWARDABLE | KDC_OPT_CNAME_IN_ADDL_TKT;
+ }
retval = krb5_get_cred_from_kdc_opt(context, ccache, ncreds,
out_creds, &tgts, kdcopt);
}
krb5_free_tgt_creds(context, tgts);
}
+ if (!retval && (options & KRB5_GC_CONSTRAINED_DELEGATION)) {
+ if (((*out_creds)->ticket_flags & TKT_FLG_FORWARDABLE) == 0) {
+ retval = KRB5_TKT_NOT_FORWARDABLE;
+ krb5_free_creds(context, *out_creds);
+ *out_creds = NULL;
+ }
+ }
/*
* Translate KRB5_CC_NOTFOUND if we previously got
* KRB5_CC_NOT_KTYPE from krb5_cc_retrieve_cred(), in order to
&& not_ktype)
retval = KRB5_CC_NOT_KTYPE;
- if (!retval) {
+ if (!retval && (options & KRB5_GC_NO_STORE) == 0) {
/* the purpose of the krb5_get_credentials call is to
* obtain a set of credentials for the caller. the
* krb5_cc_store_cred() call is to optimize performance
*/
krb5_cc_store_cred(context, ccache, *out_creds);
}
+
return retval;
}
return(krb5_validate_or_renew_creds(context, creds, client, ccache,
in_tkt_service, 0));
}
+
0
};
+static krb5_error_code
+rewrite_server_realm(krb5_context context,
+ krb5_const_principal old_server,
+ const krb5_data *realm,
+ krb5_boolean tgs,
+ krb5_principal *server)
+{
+ krb5_error_code retval;
+
+ assert(*server == NULL);
+
+ retval = krb5_copy_principal(context, old_server, server);
+ if (retval)
+ return retval;
+
+ krb5_free_data_contents(context, &(*server)->realm);
+ (*server)->realm.data = NULL;
+
+ retval = krb5int_copy_data_contents(context, realm, &(*server)->realm);
+ if (retval)
+ goto cleanup;
+
+ if (tgs) {
+ krb5_free_data_contents(context, &(*server)->data[1]);
+ (*server)->data[1].data = NULL;
+
+ retval = krb5int_copy_data_contents(context, realm, &(*server)->data[1]);
+ if (retval)
+ goto cleanup;
+ }
+
+cleanup:
+ if (retval) {
+ krb5_free_principal(context, *server);
+ *server = NULL;
+ }
+
+ return retval;
+}
+
+static inline int
+tgt_is_local_realm(krb5_creds *tgt)
+{
+ return (tgt->server->length == 2
+ && data_eq_string(tgt->server->data[0], KRB5_TGS_NAME)
+ && data_eq(tgt->server->data[1], tgt->client->realm)
+ && data_eq(tgt->server->realm, tgt->client->realm));
+}
+
krb5_error_code KRB5_CALLCONV
krb5_get_in_tkt(krb5_context context,
krb5_flags options,
int use_master = 0;
int referral_count = 0;
krb5_principal_data referred_client;
+ krb5_principal referred_server = NULL;
+ krb5_boolean is_tgt_req;
#if APPLE_PKINIT
inTktDebug("krb5_get_in_tkt top\n");
goto cleanup;
}
+ is_tgt_req = tgt_is_local_realm(creds);
+
while (1) {
if (loopcount++ > MAX_IN_TKT_LOOPS) {
retval = KRB5_GET_IN_TKT_LOOP;
if (retval)
goto cleanup;
request.client = &referred_client;
+
+ if (referred_server != NULL) {
+ krb5_free_principal(context, referred_server);
+ referred_server = NULL;
+ }
+
+ retval = rewrite_server_realm(context,
+ creds->server,
+ &referred_client.realm,
+ is_tgt_req,
+ &referred_server);
+ if (retval)
+ goto cleanup;
+ request.server = referred_server;
+
continue;
} else {
retval = (krb5_error_code) err_reply->error
}
if (referred_client.realm.data)
krb5_free_data_contents(context, &referred_client.realm);
+ if (referred_server)
+ krb5_free_principal(context, referred_server);
return (retval);
}
return 0;
}
+static krb5_error_code
+build_in_tkt_name(krb5_context context,
+ char *in_tkt_service,
+ krb5_const_principal client,
+ krb5_principal *server)
+{
+ krb5_error_code ret;
+
+ *server = NULL;
+
+ if (in_tkt_service) {
+ /* this is ugly, because so are the data structures involved. I'm
+ in the library, so I'm going to manipulate the data structures
+ directly, otherwise, it will be worse. */
+
+ if ((ret = krb5_parse_name(context, in_tkt_service, server)))
+ return ret;
+
+ /* stuff the client realm into the server principal.
+ realloc if necessary */
+ if ((*server)->realm.length < client->realm.length) {
+ char *p = realloc((*server)->realm.data,
+ client->realm.length);
+ if (p == NULL) {
+ krb5_free_principal(context, *server);
+ *server = NULL;
+ return ENOMEM;
+ }
+ (*server)->realm.data = p;
+ }
+
+ (*server)->realm.length = client->realm.length;
+ memcpy((*server)->realm.data, client->realm.data, client->realm.length);
+ } else {
+ ret = krb5_build_principal_ext(context, server,
+ client->realm.length,
+ client->realm.data,
+ KRB5_TGS_NAME_SIZE,
+ KRB5_TGS_NAME,
+ client->realm.length,
+ client->realm.data,
+ 0);
+ }
+ return ret;
+}
+
krb5_error_code KRB5_CALLCONV
krb5_get_init_creds(krb5_context context,
krb5_creds *creds,
client->type == KRB5_NT_ENTERPRISE_PRINCIPAL;
/* service */
-
- if (in_tkt_service) {
- /* this is ugly, because so are the data structures involved. I'm
- in the library, so I'm going to manipulate the data structures
- directly, otherwise, it will be worse. */
-
- if ((ret = krb5_parse_name(context, in_tkt_service, &request.server)))
- goto cleanup;
-
- /* stuff the client realm into the server principal.
- realloc if necessary */
- if (request.server->realm.length < request.client->realm.length) {
- char *p = realloc(request.server->realm.data,
- request.client->realm.length);
- if (p == NULL) {
- ret = ENOMEM;
- goto cleanup;
- }
- request.server->realm.data = p;
- }
-
- request.server->realm.length = request.client->realm.length;
- memcpy(request.server->realm.data, request.client->realm.data,
- request.client->realm.length);
- } else {
- if ((ret = krb5_build_principal_ext(context, &request.server,
- request.client->realm.length,
- request.client->realm.data,
- KRB5_TGS_NAME_SIZE,
- KRB5_TGS_NAME,
- request.client->realm.length,
- request.client->realm.data,
- 0)))
- goto cleanup;
- }
+ if ((ret = build_in_tkt_name(context, in_tkt_service,
+ request.client, &request.server)))
+ goto cleanup;
krb5_preauth_request_context_init(context);
}
preauth_to_use = out_padata;
out_padata = NULL;
- krb5_free_error(context, err_reply);
- err_reply = NULL;
+ if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED) {
+ krb5_free_error(context, err_reply);
+ err_reply = NULL;
+ }
ret = sort_krb5_padata_sequence(context,
&request.server->realm,
preauth_to_use);
if (ret)
goto cleanup;
request.client = &referred_client;
+
+ krb5_free_principal(context, request.server);
+ request.server = NULL;
+
+ ret = build_in_tkt_name(context, in_tkt_service,
+ request.client, &request.server);
+ if (ret)
+ goto cleanup;
} else {
if (retry) {
/* continue to next iteration */
krb5_creds *in_cred, krb5_creds **out_cred,
krb5_creds ***tgts, int kdcopt);
+krb5_error_code
+krb5_get_credentials_core(krb5_context context, krb5_flags options,
+ krb5_creds *in_creds, krb5_creds *mcreds,
+ krb5_flags *fields);
+
#define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew)
#define IS_TGS_PRINC(c, p) \
(krb5_princ_size((c), (p)) == 2 && \
data_eq_string(*krb5_princ_component((c), (p), 0), KRB5_TGS_NAME))
+krb5_error_code
+krb5_get_cred_via_tkt_ext (krb5_context context, krb5_creds *tkt,
+ krb5_flags kdcoptions, krb5_address *const *address,
+ krb5_pa_data **in_padata,
+ krb5_creds *in_cred,
+ krb5_error_code (*gcvt_fct)(krb5_context,
+ krb5_keyblock *,
+ krb5_kdc_req *,
+ void *),
+ void *gcvt_data,
+ krb5_pa_data ***out_padata,
+ krb5_pa_data ***enc_padata,
+ krb5_creds **out_cred,
+ krb5_keyblock **out_subkey);
+
#endif /* KRB5_INT_FUNC_PROTO__ */
if (val == NULL)
return;
free(val->contents);
- val->contents = 0;
+ val->contents = NULL;
}
void KRB5_CALLCONV
krb5_free_last_req(context, val->last_req);
krb5_free_principal(context, val->server);
krb5_free_addresses(context, val->caddrs);
+ krb5_free_pa_data(context, val->enc_padata);
free(val);
}
free(req);
}
+void KRB5_CALLCONV
+krb5_free_s4u_userid_contents(krb5_context context, krb5_s4u_userid *user_id)
+{
+ if (user_id == NULL)
+ return;
+ user_id->nonce = 0;
+ krb5_free_principal(context, user_id->user);
+ user_id->user = NULL;
+ krb5_free_data_contents(context, &user_id->subject_cert);
+ user_id->subject_cert.length = 0;
+ user_id->subject_cert.data = NULL;
+ user_id->options = 0;
+}
+
+void KRB5_CALLCONV
+krb5_free_pa_s4u_x509_user(krb5_context context, krb5_pa_s4u_x509_user *req)
+{
+ if (req == NULL)
+ return;
+ krb5_free_s4u_userid_contents(context, &req->user_id);
+ krb5_free_checksum_contents(context, &req->cksum);
+ free(req);
+}
+
void KRB5_CALLCONV
krb5_free_pa_server_referral_data(krb5_context context,
krb5_pa_server_referral_data *ref)
return(0);
}
+static krb5_error_code pa_s4u_x509_user(
+ krb5_context context,
+ krb5_kdc_req *request,
+ krb5_pa_data *in_padata,
+ krb5_pa_data **out_padata,
+ krb5_data *salt,
+ krb5_data *s2kparams,
+ krb5_enctype *etype,
+ krb5_keyblock *as_key,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ krb5_gic_get_as_key_fct gak_fct,
+ void *gak_data)
+{
+ krb5_s4u_userid *userid = (krb5_s4u_userid *)gak_data; /* XXX private contract */
+ krb5_pa_data *s4u_padata;
+ krb5_error_code code;
+ krb5_principal client;
+
+ *out_padata = NULL;
+
+ if (userid == NULL)
+ return EINVAL;
+
+ code = krb5_copy_principal(context, request->client, &client);
+ if (code != 0)
+ return code;
+
+ if (userid->user != NULL)
+ krb5_free_principal(context, userid->user);
+ userid->user = client;
+
+ if (userid->subject_cert.length != 0) {
+ s4u_padata = malloc(sizeof(*s4u_padata));
+ if (s4u_padata == NULL)
+ return ENOMEM;
+
+ s4u_padata->magic = KV5M_PA_DATA;
+ s4u_padata->pa_type = KRB5_PADATA_S4U_X509_USER;
+ s4u_padata->contents = malloc(userid->subject_cert.length);
+ if (s4u_padata->contents == NULL) {
+ free(s4u_padata);
+ return ENOMEM;
+ }
+ memcpy(s4u_padata->contents, userid->subject_cert.data, userid->subject_cert.length);
+ s4u_padata->length = userid->subject_cert.length;
+
+ *out_padata = s4u_padata;
+ }
+
+ return 0;
+}
+
/* FIXME - order significant? */
static const pa_types_t pa_types[] = {
{
pa_fx_cookie,
PA_INFO,
},
+ {
+ KRB5_PADATA_S4U_X509_USER,
+ pa_s4u_x509_user,
+ PA_INFO,
+ },
{
-1,
NULL,
--- /dev/null
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * lib/krb5/krb/s4u_creds.c
+ *
+ * Copyright (C) 2009 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ *
+ */
+
+#include "k5-int.h"
+#include "int-proto.h"
+
+/* Convert ticket flags to necessary KDC options */
+#define FLAGS2OPTS(flags) (flags & KDC_TKT_COMMON_MASK)
+
+/*
+ * Implements S4U2Self, by which a service can request a ticket to
+ * itself on behalf of an arbitrary principal.
+ */
+
+static krb5_error_code
+krb5_get_as_key_noop(
+ krb5_context context,
+ krb5_principal client,
+ krb5_enctype etype,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ krb5_data *salt,
+ krb5_data *params,
+ krb5_keyblock *as_key,
+ void *gak_data)
+{
+ /* force a hard error, we don't actually have the key */
+ return KDC_ERR_PREAUTH_FAILED;
+}
+
+static krb5_error_code
+s4u_identify_user(krb5_context context,
+ krb5_creds *in_creds,
+ krb5_data *subject_cert,
+ krb5_principal *canon_user)
+{
+ krb5_error_code code;
+ krb5_preauthtype ptypes[1] = { KRB5_PADATA_S4U_X509_USER };
+ krb5_creds creds;
+ int use_master = 0;
+ krb5_get_init_creds_opt *opts = NULL;
+ krb5_gic_opt_ext *opte = NULL;
+ krb5_principal_data client_data;
+ krb5_principal client;
+ krb5_s4u_userid userid;
+
+ *canon_user = NULL;
+
+ if (in_creds->client == NULL && subject_cert == NULL) {
+ return EINVAL;
+ }
+
+ if (in_creds->client != NULL &&
+ krb5_princ_type(context, in_creds->client) !=
+ KRB5_NT_ENTERPRISE_PRINCIPAL)
+ /* we already know the realm of the user */
+ return krb5_copy_principal(context, in_creds->client, canon_user);
+
+ memset(&creds, 0, sizeof(creds));
+
+ memset(&userid, 0, sizeof(userid));
+ if (subject_cert != NULL)
+ userid.subject_cert = *subject_cert;
+
+ code = krb5_get_init_creds_opt_alloc(context, &opts);
+ if (code != 0)
+ goto cleanup;
+ krb5_get_init_creds_opt_set_tkt_life(opts, 15);
+ krb5_get_init_creds_opt_set_renew_life(opts, 0);
+ krb5_get_init_creds_opt_set_forwardable(opts, 0);
+ krb5_get_init_creds_opt_set_proxiable(opts, 0);
+ krb5_get_init_creds_opt_set_canonicalize(opts, 1);
+ krb5_get_init_creds_opt_set_preauth_list(opts, ptypes, 1);
+ code = krb5int_gic_opt_to_opte(context, opts, &opte,
+ 0, "s4u_identify_user");
+ if (code != 0)
+ goto cleanup;
+
+ if (in_creds->client != NULL)
+ client = in_creds->client;
+ else {
+ client_data.magic = KV5M_PRINCIPAL;
+ client_data.realm = in_creds->server->realm;
+ /* should this be NULL, empty or a fixed string? XXX */
+ client_data.data = NULL;
+ client_data.length = 0;
+ client_data.type = KRB5_NT_ENTERPRISE_PRINCIPAL;
+ client = &client_data;
+ }
+
+ code = krb5_get_init_creds(context, &creds, in_creds->client,
+ NULL, NULL, 0, NULL, opte,
+ krb5_get_as_key_noop, &userid,
+ &use_master, NULL);
+ if (code == 0 ||
+ code == KDC_ERR_PREAUTH_REQUIRED ||
+ code == KDC_ERR_PREAUTH_FAILED) {
+ *canon_user = userid.user;
+ userid.user = NULL;
+ code = 0;
+ }
+
+cleanup:
+ krb5_free_cred_contents(context, &creds);
+ if (opts != NULL)
+ krb5_get_init_creds_opt_free(context, opts);
+ if (userid.user != NULL)
+ krb5_free_principal(context, userid.user);
+
+ return code;
+}
+
+static krb5_error_code
+make_pa_for_user_checksum(krb5_context context,
+ krb5_keyblock *key,
+ krb5_pa_for_user *req,
+ krb5_checksum *cksum)
+{
+ krb5_error_code code;
+ int i;
+ krb5_int32 name_type;
+ char *p;
+ krb5_data data;
+ krb5_cksumtype cksumtype;
+
+ data.length = 4;
+ for (i = 0; i < krb5_princ_size(context, req->user); i++) {
+ data.length += krb5_princ_component(context, req->user, i)->length;
+ }
+ data.length += krb5_princ_realm(context, req->user)->length;
+ data.length += req->auth_package.length;
+
+ p = data.data = malloc(data.length);
+ if (data.data == NULL)
+ return ENOMEM;
+
+ name_type = krb5_princ_type(context, req->user);
+ p[0] = (name_type >> 0 ) & 0xFF;
+ p[1] = (name_type >> 8 ) & 0xFF;
+ p[2] = (name_type >> 16) & 0xFF;
+ p[3] = (name_type >> 24) & 0xFF;
+ p += 4;
+
+ for (i = 0; i < krb5_princ_size(context, req->user); i++) {
+ memcpy(p, krb5_princ_component(context, req->user, i)->data,
+ krb5_princ_component(context, req->user, i)->length);
+ p += krb5_princ_component(context, req->user, i)->length;
+ }
+
+ memcpy(p, krb5_princ_realm(context, req->user)->data,
+ krb5_princ_realm(context, req->user)->length);
+ p += krb5_princ_realm(context, req->user)->length;
+
+ memcpy(p, req->auth_package.data, req->auth_package.length);
+
+ code = krb5int_c_mandatory_cksumtype(context, key->enctype, &cksumtype);
+ if (code != 0) {
+ free(data.data);
+ return code;
+ }
+
+ code = krb5_c_make_checksum(context, cksumtype, key,
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, &data,
+ cksum);
+
+ free(data.data);
+
+ return code;
+}
+
+static krb5_error_code
+build_pa_for_user(krb5_context context,
+ krb5_creds *tgt,
+ krb5_s4u_userid *userid,
+ krb5_pa_data **out_padata)
+{
+ krb5_error_code code;
+ krb5_pa_data *padata;
+ krb5_pa_for_user for_user;
+ krb5_data *for_user_data = NULL;
+ char package[] = "Kerberos";
+
+ if (userid->user == NULL) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ memset(&for_user, 0, sizeof(for_user));
+ for_user.user = userid->user;
+ for_user.auth_package.data = package;
+ for_user.auth_package.length = sizeof(package) - 1;
+
+ code = make_pa_for_user_checksum(context, &tgt->keyblock,
+ &for_user, &for_user.cksum);
+ if (code != 0)
+ goto cleanup;
+
+ code = encode_krb5_pa_for_user(&for_user, &for_user_data);
+ if (code != 0)
+ goto cleanup;
+
+ padata = malloc(sizeof(*padata));
+ if (padata == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ padata->magic = KV5M_PA_DATA;
+ padata->pa_type = KRB5_PADATA_FOR_USER;
+ padata->length = for_user_data->length;
+ padata->contents = (krb5_octet *)for_user_data->data;
+
+ free(for_user_data);
+ for_user_data = NULL;
+
+ *out_padata = padata;
+
+cleanup:
+ if (for_user.cksum.contents != NULL)
+ krb5_free_checksum_contents(context, &for_user.cksum);
+ krb5_free_data(context, for_user_data);
+
+ return code;
+}
+
+/*
+ * This function is invoked by krb5int_send_tgs() just before
+ * the request is encoded; it gives us access to the nonce and
+ * subkey without requiring them to be generated by the caller.
+ */
+static krb5_error_code
+build_pa_s4u_x509_user(krb5_context context,
+ krb5_keyblock *subkey,
+ krb5_kdc_req *tgsreq,
+ void *gcvt_data)
+{
+ krb5_error_code code;
+ krb5_pa_s4u_x509_user *s4u_user = (krb5_pa_s4u_x509_user *)gcvt_data;
+ krb5_data *data = NULL;
+ krb5_pa_data **padata;
+ krb5_cksumtype cksumtype;
+ int i;
+
+ assert(s4u_user->cksum.contents == NULL);
+
+ s4u_user->user_id.nonce = tgsreq->nonce;
+
+ code = encode_krb5_s4u_userid(&s4u_user->user_id, &data);
+ if (code != 0)
+ goto cleanup;
+
+ /* [MS-SFU] 2.2.2: unusual to say the least, but enc_padata secures it */
+ if (subkey->enctype == ENCTYPE_ARCFOUR_HMAC ||
+ subkey->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+ cksumtype = CKSUMTYPE_RSA_MD4;
+ } else {
+ code = krb5int_c_mandatory_cksumtype(context, subkey->enctype,
+ &cksumtype);
+ }
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_c_make_checksum(context, cksumtype, subkey,
+ KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST, data,
+ &s4u_user->cksum);
+ if (code != 0)
+ goto cleanup;
+
+ krb5_free_data(context, data);
+ data = NULL;
+
+ code = encode_krb5_pa_s4u_x509_user(s4u_user, &data);
+ if (code != 0)
+ goto cleanup;
+
+ assert(tgsreq->padata != NULL);
+
+ for (i = 0; tgsreq->padata[i] != NULL; i++)
+ ;
+
+ padata = realloc(tgsreq->padata,
+ (i + 2) * sizeof(krb5_pa_data *));
+ if (padata == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ tgsreq->padata = padata;
+
+ padata[i] = malloc(sizeof(krb5_pa_data));
+ if (padata[i] == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ padata[i]->magic = KV5M_PA_DATA;
+ padata[i]->pa_type = KRB5_PADATA_S4U_X509_USER;
+ padata[i]->length = data->length;
+ padata[i]->contents = (krb5_octet *)data->data;
+
+ padata[i + 1] = NULL;
+
+ free(data);
+ data = NULL;
+
+cleanup:
+ if (code != 0 && s4u_user->cksum.contents != NULL) {
+ krb5_free_checksum_contents(context, &s4u_user->cksum);
+ s4u_user->cksum.contents = NULL;
+ }
+ krb5_free_data(context, data);
+
+ return code;
+}
+
+static krb5_error_code
+verify_s4u2self_reply(krb5_context context,
+ krb5_keyblock *subkey,
+ krb5_pa_s4u_x509_user *req_s4u_user,
+ krb5_pa_data **rep_padata,
+ krb5_pa_data **enc_padata)
+{
+ krb5_error_code code;
+ krb5_pa_data *rep_s4u_padata, *enc_s4u_padata;
+ krb5_pa_s4u_x509_user *rep_s4u_user = NULL;
+ krb5_data data, *datap = NULL;
+ krb5_keyusage usage;
+ krb5_boolean valid;
+ krb5_boolean not_newer;
+
+ assert(req_s4u_user != NULL);
+
+ switch (subkey->enctype) {
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES_CBC_MD4:
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES3_CBC_SHA1:
+ case ENCTYPE_DES3_CBC_RAW:
+ case ENCTYPE_ARCFOUR_HMAC:
+ case ENCTYPE_ARCFOUR_HMAC_EXP :
+ not_newer = TRUE;
+ break;
+ default:
+ not_newer = FALSE;
+ break;
+ }
+
+ enc_s4u_padata = krb5int_find_pa_data(context,
+ enc_padata,
+ KRB5_PADATA_S4U_X509_USER);
+
+ /* XXX this will break newer enctypes with a MIT 1.7 KDC */
+ rep_s4u_padata = krb5int_find_pa_data(context,
+ rep_padata,
+ KRB5_PADATA_S4U_X509_USER);
+ if (rep_s4u_padata == NULL) {
+ if (not_newer == FALSE || enc_s4u_padata != NULL)
+ return KRB5_KDCREP_MODIFIED;
+ else
+ return 0;
+ }
+
+ data.length = rep_s4u_padata->length;
+ data.data = (char *)rep_s4u_padata->contents;
+
+ code = decode_krb5_pa_s4u_x509_user(&data, &rep_s4u_user);
+ if (code != 0)
+ goto cleanup;
+
+ if (rep_s4u_user->user_id.nonce != req_s4u_user->user_id.nonce) {
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+
+ code = encode_krb5_s4u_userid(&rep_s4u_user->user_id, &datap);
+ if (code != 0)
+ goto cleanup;
+
+ if (rep_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE)
+ usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY;
+ else
+ usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST;
+
+ code = krb5_c_verify_checksum(context, subkey, usage, datap,
+ &rep_s4u_user->cksum, &valid);
+ if (code != 0)
+ goto cleanup;
+ if (valid == FALSE) {
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+
+ /*
+ * KDCs that support KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE also return
+ * S4U enc_padata for older (pre-AES) encryption types only.
+ */
+ if (not_newer) {
+ if (enc_s4u_padata == NULL) {
+ if (rep_s4u_user->user_id.options &
+ KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE) {
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+ } else {
+ if (enc_s4u_padata->length !=
+ req_s4u_user->cksum.length + rep_s4u_user->cksum.length) {
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+ if (memcmp(enc_s4u_padata->contents,
+ req_s4u_user->cksum.contents,
+ req_s4u_user->cksum.length) ||
+ memcmp(&enc_s4u_padata->contents[req_s4u_user->cksum.length],
+ rep_s4u_user->cksum.contents,
+ rep_s4u_user->cksum.length)) {
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+ }
+ } else if (!krb5_c_is_keyed_cksum(rep_s4u_user->cksum.checksum_type)) {
+ code = KRB5KRB_AP_ERR_INAPP_CKSUM;
+ goto cleanup;
+ }
+
+cleanup:
+ krb5_free_pa_s4u_x509_user(context, rep_s4u_user);
+ krb5_free_data(context, datap);
+
+ return code;
+}
+
+static krb5_error_code
+krb5_get_self_cred_from_kdc(krb5_context context,
+ krb5_flags options,
+ krb5_ccache ccache,
+ krb5_creds *in_creds,
+ krb5_data *subject_cert,
+ krb5_data *user_realm,
+ krb5_creds **out_creds)
+{
+ krb5_error_code code;
+ krb5_principal tgs = NULL;
+ krb5_creds tgtq, s4u_creds, *tgt = NULL, *tgtptr;
+ krb5_creds *referral_tgts[KRB5_REFERRAL_MAXHOPS];
+ krb5_pa_s4u_x509_user s4u_user;
+ int referral_count = 0, i;
+ krb5_flags kdcopt;
+
+ memset(&tgtq, 0, sizeof(tgtq));
+ memset(&s4u_creds, 0, sizeof(s4u_creds));
+ memset(referral_tgts, 0, sizeof(referral_tgts));
+ *out_creds = NULL;
+
+ memset(&s4u_user, 0, sizeof(s4u_user));
+
+ if (in_creds->client != NULL &&
+ krb5_princ_size(context, in_creds->client)) {
+ if (krb5_princ_type(context, in_creds->client) ==
+ KRB5_NT_ENTERPRISE_PRINCIPAL)
+ {
+ code = krb5_build_principal_ext(context,
+ &s4u_user.user_id.user,
+ user_realm->length,
+ user_realm->data,
+ in_creds->client->data[0].length,
+ in_creds->client->data[0].data,
+ 0);
+ if (code != 0)
+ goto cleanup;
+ s4u_user.user_id.user->type = KRB5_NT_ENTERPRISE_PRINCIPAL;
+ } else {
+ code = krb5_copy_principal(context,
+ in_creds->client,
+ &s4u_user.user_id.user);
+ if (code != 0)
+ goto cleanup;
+ }
+ } else {
+ code = krb5_build_principal_ext(context, &s4u_user.user_id.user,
+ user_realm->length,
+ user_realm->data);
+ if (code != 0)
+ goto cleanup;
+ s4u_user.user_id.user->type = KRB5_NT_ENTERPRISE_PRINCIPAL;
+ }
+ if (subject_cert != NULL)
+ s4u_user.user_id.subject_cert = *subject_cert;
+ s4u_user.user_id.options = KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE;
+
+ /* First, acquire a TGT to the user's realm. */
+ code = krb5_tgtname(context, user_realm,
+ krb5_princ_realm(context, in_creds->server), &tgs);
+ if (code != 0)
+ goto cleanup;
+
+ tgtq.client = in_creds->server;
+ tgtq.server = tgs;
+
+ code = krb5_get_credentials(context, options, ccache, &tgtq, &tgt);
+ if (code != 0)
+ goto cleanup;
+
+ tgtptr = tgt;
+
+ code = krb5int_copy_creds_contents(context, in_creds, &s4u_creds);
+ if (code != 0)
+ goto cleanup;
+
+ if (s4u_creds.client != NULL) {
+ krb5_free_principal(context, s4u_creds.client);
+ s4u_creds.client = NULL;
+ }
+
+ code = krb5_copy_principal(context, in_creds->server, &s4u_creds.client);
+ if (code != 0)
+ goto cleanup;
+
+ /* Then, walk back the referral path to S4U2Self for user */
+ kdcopt = 0;
+ if (options & KRB5_GC_CANONICALIZE)
+ kdcopt |= KDC_OPT_CANONICALIZE;
+ if (options & KRB5_GC_FORWARDABLE)
+ kdcopt |= KDC_OPT_FORWARDABLE;
+ if (options & KRB5_GC_NO_TRANSIT_CHECK)
+ kdcopt |= KDC_OPT_DISABLE_TRANSITED_CHECK;
+
+ for (referral_count = 0;
+ referral_count < KRB5_REFERRAL_MAXHOPS;
+ referral_count++)
+ {
+ krb5_pa_data **in_padata = NULL;
+ krb5_pa_data **out_padata = NULL;
+ krb5_pa_data **enc_padata = NULL;
+ krb5_keyblock *subkey = NULL;
+
+ if (s4u_user.user_id.user != NULL &&
+ krb5_princ_size(context, s4u_user.user_id.user)) {
+ in_padata = calloc(2, sizeof(krb5_pa_data *));
+ if (in_padata == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ code = build_pa_for_user(context,
+ tgtptr,
+ &s4u_user.user_id, &in_padata[0]);
+ if (code != 0) {
+ krb5_free_pa_data(context, in_padata);
+ goto cleanup;
+ }
+ }
+
+ /* Rewrite server realm to match TGS realm */
+ krb5_free_data_contents(context, &s4u_creds.server->realm);
+
+ code = krb5int_copy_data_contents(context,
+ &tgtptr->server->data[1],
+ &s4u_creds.server->realm);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_get_cred_via_tkt_ext(context, tgtptr,
+ KDC_OPT_CANONICALIZE |
+ FLAGS2OPTS(tgtptr->ticket_flags) |
+ kdcopt,
+ tgtptr->addresses,
+ in_padata, &s4u_creds,
+ build_pa_s4u_x509_user, &s4u_user,
+ &out_padata, &enc_padata,
+ out_creds, &subkey);
+ if (code != 0) {
+ krb5_free_checksum_contents(context, &s4u_user.cksum);
+ krb5_free_pa_data(context, in_padata);
+ goto cleanup;
+ }
+
+ code = verify_s4u2self_reply(context, subkey, &s4u_user,
+ out_padata, enc_padata);
+
+ krb5_free_checksum_contents(context, &s4u_user.cksum);
+ krb5_free_pa_data(context, in_padata);
+ krb5_free_pa_data(context, out_padata);
+ krb5_free_pa_data(context, enc_padata);
+ krb5_free_keyblock(context, subkey);
+
+ if (code != 0)
+ goto cleanup;
+
+ if (krb5_principal_compare(context,
+ in_creds->server,
+ (*out_creds)->server)) {
+ code = 0;
+ goto cleanup;
+ } else if (IS_TGS_PRINC(context, (*out_creds)->server)) {
+ krb5_data *r1 = &tgtptr->server->data[1];
+ krb5_data *r2 = &(*out_creds)->server->data[1];
+
+ if (data_eq(*r1, *r2)) {
+ krb5_free_creds(context, *out_creds);
+ *out_creds = NULL;
+ code = KRB5_ERR_HOST_REALM_UNKNOWN;
+ break;
+ }
+ for (i = 0; i < referral_count; i++) {
+ if (krb5_principal_compare(context,
+ (*out_creds)->server,
+ referral_tgts[i]->server)) {
+ code = KRB5_KDC_UNREACH;
+ goto cleanup;
+ }
+ }
+
+ tgtptr = *out_creds;
+ referral_tgts[referral_count] = *out_creds;
+ *out_creds = NULL;
+ } else {
+ krb5_free_creds(context, *out_creds);
+ *out_creds = NULL;
+ code = KRB5KRB_AP_WRONG_PRINC; /* XXX */
+ break;
+ }
+ }
+
+cleanup:
+ for (i = 0; i < KRB5_REFERRAL_MAXHOPS; i++) {
+ if (referral_tgts[i] != NULL)
+ krb5_free_creds(context, referral_tgts[i]);
+ }
+ krb5_free_principal(context, tgs);
+ krb5_free_creds(context, tgt);
+ krb5_free_cred_contents(context, &s4u_creds);
+ krb5_free_principal(context, s4u_user.user_id.user);
+ krb5_free_checksum_contents(context, &s4u_user.cksum);
+
+ return code;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
+ krb5_ccache ccache, krb5_creds *in_creds,
+ krb5_data *subject_cert,
+ krb5_creds **out_creds)
+{
+ krb5_error_code code;
+ krb5_principal realm = NULL;
+
+ *out_creds = NULL;
+
+ if (options & KRB5_GC_CONSTRAINED_DELEGATION) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ if (in_creds->client != NULL) {
+ /* Uncanonicalised check */
+ code = krb5_get_credentials(context, options | KRB5_GC_CACHED,
+ ccache, in_creds, out_creds);
+ if (code != KRB5_CC_NOTFOUND && code != KRB5_CC_NOT_KTYPE)
+ goto cleanup;
+
+ if ((options & KRB5_GC_CACHED) && !(options & KRB5_GC_CANONICALIZE))
+ goto cleanup;
+ }
+
+ code = s4u_identify_user(context, in_creds, subject_cert, &realm);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_get_credentials(context, options | KRB5_GC_CACHED,
+ ccache, in_creds, out_creds);
+ if ((code != KRB5_CC_NOTFOUND && code != KRB5_CC_NOT_KTYPE)
+ || options & KRB5_GC_CACHED)
+ goto cleanup;
+
+ code = krb5_get_self_cred_from_kdc(context, options, ccache,
+ in_creds, subject_cert,
+ krb5_princ_realm(context, realm),
+ out_creds);
+ if (code != 0)
+ goto cleanup;
+
+ assert(*out_creds != NULL);
+
+ if ((options & KRB5_GC_NO_STORE) == 0) {
+ code = krb5_cc_store_cred(context, ccache, *out_creds);
+ if (code != 0)
+ goto cleanup;
+ }
+
+cleanup:
+ if (code != 0 && *out_creds != NULL) {
+ krb5_free_creds(context, *out_creds);
+ *out_creds = NULL;
+ }
+
+ krb5_free_principal(context, realm);
+
+ return code;
+}
+
+/*
+ * Exported API for constrained delegation (S4U2Proxy).
+ *
+ * This is preferable to using krb5_get_credentials directly because
+ * it can perform some additional checks.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_proxy(krb5_context context,
+ krb5_flags options,
+ krb5_ccache ccache,
+ krb5_creds *in_creds,
+ krb5_ticket *evidence_tkt,
+ krb5_creds **out_creds)
+{
+ krb5_error_code code;
+ krb5_creds mcreds;
+ krb5_creds *ncreds = NULL;
+ krb5_flags fields;
+ krb5_data *evidence_tkt_data = NULL;
+ krb5_creds s4u_creds;
+
+ *out_creds = NULL;
+
+ if (in_creds == NULL || in_creds->client == NULL ||
+ evidence_tkt == NULL || evidence_tkt->enc_part2 == NULL) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ /*
+ * Caller should have set in_creds->client to match evidence
+ * ticket client
+ */
+ if (!krb5_principal_compare(context, evidence_tkt->enc_part2->client,
+ in_creds->client)) {
+ code = EINVAL;
+ goto cleanup;
+ }
+
+ if ((evidence_tkt->enc_part2->flags & TKT_FLG_FORWARDABLE) == 0) {
+ code = KRB5_TKT_NOT_FORWARDABLE;
+ goto cleanup;
+ }
+
+ code = krb5_get_credentials_core(context, options, in_creds,
+ &mcreds, &fields);
+ if (code != 0)
+ goto cleanup;
+
+ ncreds = calloc(1, sizeof(*ncreds));
+ if (ncreds == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ ncreds->magic = KV5M_CRED;
+
+ code = krb5_cc_retrieve_cred(context, ccache, fields, &mcreds, ncreds);
+ if (code != 0) {
+ free(ncreds);
+ ncreds = in_creds;
+ } else {
+ *out_creds = ncreds;
+ }
+
+ if ((code != KRB5_CC_NOTFOUND && code != KRB5_CC_NOT_KTYPE)
+ || options & KRB5_GC_CACHED)
+ goto cleanup;
+
+ code = encode_krb5_ticket(evidence_tkt, &evidence_tkt_data);
+ if (code != 0)
+ goto cleanup;
+
+ s4u_creds = *in_creds;
+ s4u_creds.client = evidence_tkt->server;
+ s4u_creds.second_ticket = *evidence_tkt_data;
+
+ code = krb5_get_credentials(context,
+ options | KRB5_GC_CONSTRAINED_DELEGATION,
+ ccache,
+ &s4u_creds,
+ out_creds);
+ if (code != 0)
+ goto cleanup;
+
+ /*
+ * Check client name because we couldn't compare that inside
+ * krb5_get_credentials() (enc_part2 is unavailable in clear)
+ */
+ if (!krb5_principal_compare(context,
+ evidence_tkt->enc_part2->client,
+ (*out_creds)->client)) {
+ code = KRB5_KDCREP_MODIFIED;
+ goto cleanup;
+ }
+
+cleanup:
+ if (*out_creds != NULL && code != 0) {
+ krb5_free_creds(context, *out_creds);
+ *out_creds = NULL;
+ }
+ if (evidence_tkt_data != NULL)
+ krb5_free_data(context, evidence_tkt_data);
+
+ return code;
+}
if (retval)
goto cleanup;
}
-
+
/* Generate checksum */
if ((retval = krb5_c_make_checksum(context, cksumtype,
&in_cred->keyblock,
}
/*
* Note that this function fills in part of rep even on failure.
+ *
+ * The pacb_fct callback allows the caller access to the nonce
+ * and request subkey, for binding preauthentication data
*/
krb5_error_code
krb5int_send_tgs(krb5_context context, krb5_flags kdcoptions,
krb5_const_principal sname, krb5_address *const *addrs,
krb5_authdata *const *authorization_data,
krb5_pa_data *const *padata, const krb5_data *second_ticket,
- krb5_creds *in_cred, krb5_response *rep, krb5_keyblock **subkey)
+ krb5_creds *in_cred,
+ krb5_error_code (*pacb_fct)(krb5_context,
+ krb5_keyblock *,
+ krb5_kdc_req *,
+ void *),
+ void *pacb_data,
+ krb5_response *rep, krb5_keyblock **subkey)
{
krb5_error_code retval;
krb5_kdc_req tgsreq;
krb5_ticket *sec_ticket = 0;
krb5_ticket *sec_ticket_arr[2];
krb5_timestamp time_now;
- krb5_pa_data **combined_padata;
+ krb5_pa_data **combined_padata = NULL;
krb5_pa_data ap_req_padata;
int tcp_only = 0, use_master;
krb5_keyblock *local_subkey = NULL;
assert (subkey != NULL);
*subkey = NULL;
+
/*
* in_creds MUST be a valid credential NOT just a partially filled in
* place holder for us to get credentials for the caller.
/* Get the encryption types list */
if (ktypes) {
- /* Check passed ktypes and make sure they're valid. */
- for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
+ /* Check passed ktypes and make sure they're valid. */
+ for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes]))
return KRB5_PROG_ETYPE_NOSUPP;
}
} else
tgsreq.second_ticket = 0;
+ ap_req_padata.contents = NULL;
+
/* encode the body; then checksum it */
if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch)))
goto send_tgs_error_2;
}
krb5_free_data(context, scratch);
- ap_req_padata.pa_type = KRB5_PADATA_AP_REQ;
- ap_req_padata.length = scratch2.length;
- ap_req_padata.contents = (krb5_octet *)scratch2.data;
-
- /* combine in any other supplied padata */
+ tgsreq.padata = (krb5_pa_data **)calloc(2, sizeof(krb5_pa_data *));
+ if (tgsreq.padata == NULL) {
+ free(scratch2.data);
+ goto send_tgs_error_2;
+ }
+ tgsreq.padata[0] = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
+ if (tgsreq.padata[0] == NULL) {
+ free(scratch2.data);
+ goto send_tgs_error_2;
+ }
+ tgsreq.padata[0]->pa_type = KRB5_PADATA_AP_REQ;
+ tgsreq.padata[0]->length = scratch2.length;
+ tgsreq.padata[0]->contents = (krb5_octet *)scratch2.data;
+ tgsreq.padata[1] = NULL;
+
+ /* combine in any other supplied padata, unfortunately now it is
+ * necessary to copy it as the callback function might modify the
+ * padata, and having a separate path for the non-callback case,
+ * or attempting to determine which elements were changed by the
+ * callback, would have complicated the code significantly.
+ */
if (padata) {
- krb5_pa_data * const * counter;
- register unsigned int i = 0;
- for (counter = padata; *counter; counter++, i++);
- combined_padata = malloc((i+2) * sizeof(*combined_padata));
- if (!combined_padata) {
- free(ap_req_padata.contents);
- retval = ENOMEM;
- goto send_tgs_error_2;
- }
- combined_padata[0] = &ap_req_padata;
- for (i = 1, counter = padata; *counter; counter++, i++)
- combined_padata[i] = (krb5_pa_data *) *counter;
- combined_padata[i] = 0;
- } else {
- combined_padata = (krb5_pa_data **)malloc(2*sizeof(*combined_padata));
- if (!combined_padata) {
- free(ap_req_padata.contents);
- retval = ENOMEM;
+ krb5_pa_data **tmp;
+ int i;
+
+ for (i = 0; padata[i]; i++)
+ ;
+
+ tmp = (krb5_pa_data **)realloc(tgsreq.padata,
+ (i + 2) * sizeof(*combined_padata));
+ if (tmp == NULL)
goto send_tgs_error_2;
+
+ tgsreq.padata = tmp;
+
+ for (i = 0; padata[i]; i++) {
+ krb5_pa_data *pa;
+
+ pa = tgsreq.padata[1 + i] = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
+ if (tgsreq.padata == NULL) {
+ retval = ENOMEM;
+ goto send_tgs_error_2;
+ }
+
+ pa->pa_type = padata[i]->pa_type;
+ pa->length = padata[i]->length;
+ pa->contents = (krb5_octet *)malloc(padata[i]->length);
+ if (pa->contents == NULL) {
+ retval = ENOMEM;
+ goto send_tgs_error_2;
+ }
+ memcpy(pa->contents, padata[i]->contents, padata[i]->length);
}
- combined_padata[0] = &ap_req_padata;
- combined_padata[1] = 0;
+ tgsreq.padata[1 + i] = NULL;
}
- tgsreq.padata = combined_padata;
+ if (pacb_fct != NULL) {
+ if ((retval = (*pacb_fct)(context, local_subkey, &tgsreq, pacb_data)))
+ goto send_tgs_error_2;
+ }
/* the TGS_REQ is assembled in tgsreq, so encode it */
- if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch))) {
- free(ap_req_padata.contents);
- free(combined_padata);
+ if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch)))
goto send_tgs_error_2;
- }
- free(ap_req_padata.contents);
- free(combined_padata);
/* now send request & get response from KDC */
+ krb5_free_pa_data(context, tgsreq.padata);
+ tgsreq.padata = NULL;
+
send_again:
use_master = 0;
retval = krb5_sendto_kdc(context, scratch,
krb5_free_data(context, scratch);
send_tgs_error_2:;
+ if (tgsreq.padata)
+ krb5_free_pa_data(context, tgsreq.padata);
if (sec_ticket)
krb5_free_ticket(context, sec_ticket);
}
-krb5_error_code KRB5_CALLCONV
+krb5_error_code KRB5_CALLCONV
krb5_server_decrypt_ticket_keytab(krb5_context context,
- const krb5_keytab kt,
+ const krb5_keytab keytab,
krb5_ticket *ticket)
{
- krb5_error_code retval;
- krb5_enctype enctype;
- krb5_keytab_entry ktent;
+ krb5_error_code retval;
+ krb5_keytab_entry ktent;
+
+ retval = KRB5_KT_NOTFOUND;
+
+ if (keytab->ops->start_seq_get == NULL) {
+ retval = krb5_kt_get_entry(context, keytab,
+ ticket->server,
+ ticket->enc_part.kvno,
+ ticket->enc_part.enctype, &ktent);
+ if (retval == 0) {
+ retval = krb5int_server_decrypt_ticket_keyblock(context, &ktent.key, ticket);
+
+ (void) krb5_free_keytab_entry_contents(context, &ktent);
+ }
+ } else {
+ krb5_error_code code;
+ krb5_kt_cursor cursor;
+
+ retval = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (retval != 0)
+ goto map_error;
- enctype = ticket->enc_part.enctype;
+ while ((code = krb5_kt_next_entry(context, keytab,
+ &ktent, &cursor)) == 0) {
+ if (ktent.key.enctype != ticket->enc_part.enctype)
+ continue;
- if ((retval = krb5_kt_get_entry(context, kt, ticket->server,
- ticket->enc_part.kvno,
- enctype, &ktent)))
- return retval;
+ retval = krb5int_server_decrypt_ticket_keyblock(context, &ktent.key, ticket);
+ if (retval == 0) {
+ krb5_principal tmp;
- retval = krb5int_server_decrypt_ticket_keyblock(context,
- &ktent.key, ticket);
- /* Upon error, Free keytab entry first, then return */
+ retval = krb5_copy_principal(context, ktent.principal, &tmp);
+ if (retval == 0) {
+ krb5_free_principal(context, ticket->server);
+ ticket->server = tmp;
+ }
+ (void) krb5_free_keytab_entry_contents(context, &ktent);
+ break;
+ }
+ (void) krb5_free_keytab_entry_contents(context, &ktent);
+ }
+
+ code = krb5_kt_end_seq_get(context, keytab, &cursor);
+ if (code != 0)
+ retval = code;
+ }
+
+map_error:
+ switch (retval) {
+ case KRB5_KT_KVNONOTFOUND:
+ case KRB5_KT_NOTFOUND:
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+ retval = KRB5KRB_AP_WRONG_PRINC;
+ break;
+ default:
+ break;
+ }
- (void) krb5_kt_free_entry(context, &ktent);
return retval;
}
#endif /* LEAN_CLIENT */
decode_krb5_etype_info
decode_krb5_etype_info2
decode_krb5_fast_req
-decode_krb5_pa_fx_fast_request
decode_krb5_kdc_req_body
decode_krb5_pa_enc_ts
decode_krb5_pa_for_user
+decode_krb5_pa_fx_fast_request
decode_krb5_pa_pac_req
+decode_krb5_pa_s4u_x509_user
decode_krb5_padata_sequence
decode_krb5_predicted_sam_response
decode_krb5_priv
encode_krb5_etype_info
encode_krb5_etype_info2
encode_krb5_fast_response
-encode_krb5_pa_fx_fast_reply
encode_krb5_kdc_req_body
encode_krb5_pa_enc_ts
encode_krb5_pa_for_user
+encode_krb5_pa_fx_fast_reply
+encode_krb5_pa_s4u_x509_user
encode_krb5_pa_server_referral_data
encode_krb5_pa_svr_referral_data
encode_krb5_padata_sequence
encode_krb5_priv
encode_krb5_pwd_data
encode_krb5_pwd_sequence
+encode_krb5_s4u_userid
encode_krb5_safe
encode_krb5_sam_challenge
encode_krb5_sam_key
krb5_authdata_free_internal
krb5_authdata_import_attributes
krb5_build_principal
+krb5_build_principal_alloc_va
krb5_build_principal_ext
krb5_build_principal_va
-krb5_build_principal_alloc_va
krb5_cc_close
krb5_cc_copy_creds
krb5_cc_default
krb5_free_last_req
krb5_free_pa_data
krb5_free_pa_enc_ts
-krb5_free_pa_pac_req
krb5_free_pa_for_user
+krb5_free_pa_pac_req
+krb5_free_pa_s4u_x509_user
krb5_free_pa_server_referral_data
krb5_free_pa_svr_referral_data
krb5_free_passwd_phrase_element
krb5_get_cred_from_kdc_validate
krb5_get_cred_via_tkt
krb5_get_credentials
+krb5_get_credentials_for_proxy
+krb5_get_credentials_for_user
krb5_get_credentials_renew
krb5_get_credentials_validate
krb5_get_default_config_files
krb5_os_hostaddr
krb5_os_init_context
krb5_os_localaddr
-krb5int_get_domain_realm_mapping
krb5_overridekeyname
krb5_pac_add_buffer
krb5_pac_free
krb5int_foreach_localaddr
krb5int_free_addrlist
krb5int_free_data_list
+krb5int_get_domain_realm_mapping
krb5int_init_context_kdc
krb5int_initialize_library
krb5int_pac_sign
#define DEFAULT_UDP_PREF_LIMIT 1465
#define HARD_UDP_LIMIT 32700 /* could probably do 64K-epsilon ? */
-#undef DEBUG
+#define DEBUG 1
#ifdef DEBUG
int krb5int_debug_sendto_kdc = 0;
LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, principal_attributes);
for (ent=ldap_first_entry(ld, result); ent != NULL; ent=ldap_next_entry(ld, ent)) {
- if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
+ values=ldap_get_values(ld, ent, "krbcanonicalname");
+ if (values == NULL)
+ values=ldap_get_values(ld, ent, "krbprincipalname");
+ if (values != NULL) {
for (i=0; values[i] != NULL; ++i) {
if (krb5_ldap_parse_principal_name(values[i], &princ_name) != 0)
continue;
(*func)(func_arg, &entry);
krb5_dbe_free_contents(context, &entry);
(void) krb5_free_principal(context, principal);
- if (princ_name)
- free(princ_name);
+ free(princ_name);
break;
}
(void) krb5_free_principal(context, principal);
- if (princ_name)
- free(princ_name);
+ free(princ_name);
}
ldap_value_free(values);
}
return 0;
}
+/* Return true if it's okay to return aliases according to flags. */
+static krb5_boolean
+aliases_ok(unsigned int flags)
+{
+ /*
+ * The current DAL does not have a flag to indicate whether
+ * aliases are okay. For service name lookups (AS or TGT path),
+ * we can always return aliases. For client name lookups, we can
+ * only return aliases if the client passed the canonicalize flag.
+ * We abuse the CLIENT_REFERRALS_ONLY flag to detect client name
+ * lookups.
+ *
+ * This method has the side effect of permitting aliases for
+ * lookups by administrative interfaces (e.g. kadmin). Since we
+ * don't have explicit admin support for aliases yet, this is
+ * okay.
+ */
+ if (!(flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY))
+ return TRUE;
+ if (flags & KRB5_KDB_FLAG_CANONICALIZE)
+ return TRUE;
+ return FALSE;
+}
+
/*
* look up a principal in the directory.
*/
if ((values=ldap_get_values(ld, ent, "krbcanonicalname")) != NULL) {
if (values[0] && strcmp(values[0], user) != 0) {
/* We matched an alias, not the canonical name. */
- if (flags & KRB5_KDB_FLAG_CANONICALIZE) {
+ if (aliases_ok(flags)) {
st = krb5_ldap_parse_principal_name(values[0], &cname);
if (st != 0)
goto cleanup;
print_flags(unsigned int flags)
{
unsigned int i;
- static char *prflags[] = {
- "DISALLOW_POSTDATED", /* 0x00000001 */
- "DISALLOW_FORWARDABLE", /* 0x00000002 */
- "DISALLOW_TGT_BASED", /* 0x00000004 */
- "DISALLOW_RENEWABLE", /* 0x00000008 */
- "DISALLOW_PROXIABLE", /* 0x00000010 */
- "DISALLOW_DUP_SKEY", /* 0x00000020 */
- "DISALLOW_ALL_TIX", /* 0x00000040 */
- "REQUIRES_PRE_AUTH", /* 0x00000080 */
- "REQUIRES_HW_AUTH", /* 0x00000100 */
- "REQUIRES_PWCHANGE", /* 0x00000200 */
- "UNKNOWN_0x00000400", /* 0x00000400 */
- "UNKNOWN_0x00000800", /* 0x00000800 */
- "DISALLOW_SVR", /* 0x00001000 */
- "PWCHANGE_SERVICE", /* 0x00002000 */
- "SUPPORT_DESMD5", /* 0x00004000 */
- "NEW_PRINC", /* 0x00008000 */
+ static char *prflags[] = {
+ "DISALLOW_POSTDATED", /* 0x00000001 */
+ "DISALLOW_FORWARDABLE", /* 0x00000002 */
+ "DISALLOW_TGT_BASED", /* 0x00000004 */
+ "DISALLOW_RENEWABLE", /* 0x00000008 */
+ "DISALLOW_PROXIABLE", /* 0x00000010 */
+ "DISALLOW_DUP_SKEY", /* 0x00000020 */
+ "DISALLOW_ALL_TIX", /* 0x00000040 */
+ "REQUIRES_PRE_AUTH", /* 0x00000080 */
+ "REQUIRES_HW_AUTH", /* 0x00000100 */
+ "REQUIRES_PWCHANGE", /* 0x00000200 */
+ "UNKNOWN_0x00000400", /* 0x00000400 */
+ "UNKNOWN_0x00000800", /* 0x00000800 */
+ "DISALLOW_SVR", /* 0x00001000 */
+ "PWCHANGE_SERVICE", /* 0x00002000 */
+ "SUPPORT_DESMD5", /* 0x00004000 */
+ "NEW_PRINC", /* 0x00008000 */
+ "UNKNOWN_0x00010000", /* 0x00010000 */
+ "UNKNOWN_0x00020000", /* 0x00020000 */
+ "UNKNOWN_0x00040000", /* 0x00040000 */
+ "UNKNOWN_0x00080000", /* 0x00080000 */
+ "OK_AS_DELEGATE", /* 0x00100000 */
+ "OK_TO_AUTH_AS_DELEGATE", /* 0x00200000 */
+ "NO_AUTH_DATA_REQUIRED", /* 0x00400000 */
+
};
for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) {
for (i = 0; i < k->k_enctype.k_enctype_len; i++) {
printf("\t\t\tenc type: 0x%x\n",
- k->k_enctype.k_enctype_val[i]);
+ k->k_enctype.k_enctype_val[i]);
}
str = k->k_contents.k_contents_val;
ktest_empty_enc_sam_response_enc_2(&sam_ch2);
}
/****************************************************************/
+ /* encode_krb5_pa_s4u_x509_user */
+ {
+ krb5_pa_s4u_x509_user s4u, *tmp;
+ setup(s4u, "pa_s4u_x509_user",
+ ktest_make_sample_pa_s4u_x509_user);
+ leak_test(s4u, encode_krb5_pa_s4u_x509_user,
+ decode_krb5_pa_s4u_x509_user,
+ krb5_free_pa_s4u_x509_user);
+ ktest_empty_pa_s4u_x509_user(&s4u);
+ }
+ /****************************************************************/
/* encode_krb5_ad_kdcissued */
{
krb5_ad_kdcissued kdci, *tmp;
-
setup(kdci, "ad_kdcissued",
ktest_make_sample_ad_kdcissued);
leak_test(kdci, encode_krb5_ad_kdcissued,
ktest_empty_sam_response(&ref);
}
+
+ /****************************************************************/
+ /* decode_pa_s4u_x509_user */
+ {
+ setup(krb5_pa_s4u_x509_user,"krb5_pa_s4u_x509_user",ktest_make_sample_pa_s4u_x509_user);
+ decode_run("pa_s4u_x509_user","","30 68 A0 55 30 53 A0 06 02 04 00 CA 14 9A A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 12 04 10 70 61 5F 73 34 75 5F 78 35 30 39 5F 75 73 65 72 A4 07 03 05 00 80 00 00 00 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34",decode_krb5_pa_s4u_x509_user,ktest_equal_pa_s4u_x509_user,krb5_free_pa_s4u_x509_user);
+ ktest_empty_pa_s4u_x509_user(&ref);
+ }
+
+ /****************************************************************/
+ /* decode_ad_kdcissued */
{
setup(krb5_ad_kdcissued,"krb5_ad_kdcissued",ktest_make_sample_ad_kdcissued);
decode_run("ad_kdcissued","","30 65 A0 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72",decode_krb5_ad_kdcissued,ktest_equal_ad_kdcissued,krb5_free_ad_kdcissued);
ktest_empty_ad_kdcissued(&ref);
}
+
#ifdef ENABLE_LDAP
/* ldap sequence_of_keys */
{
ktest_empty_enc_sam_response_enc_2(&sam_ch2);
}
/****************************************************************/
+ /* encode_krb5_pa_s4u_x509_user */
+ {
+ krb5_pa_s4u_x509_user s4u;
+ setup(s4u,krb5_pa_s4u_x509_user,"pa_s4u_x509_user",
+ ktest_make_sample_pa_s4u_x509_user);
+ encode_run(s4u,krb5_pa_s4u_x509_user,
+ "pa_s4u_x509_user","",
+ encode_krb5_pa_s4u_x509_user);
+ ktest_empty_pa_s4u_x509_user(&s4u);
+ }
+ /****************************************************************/
/* encode_krb5_ad_kdcissued */
{
krb5_ad_kdcissued kdci;
return 0;
}
+krb5_error_code ktest_make_sample_pa_s4u_x509_user(p)
+ krb5_pa_s4u_x509_user *p;
+{
+ krb5_error_code retval;
+ krb5_s4u_userid *u = &p->user_id;
+ u->nonce = 13243546;
+ retval = ktest_make_sample_principal(&u->user);
+ if (retval) return retval;
+ u->subject_cert.data = strdup("pa_s4u_x509_user");
+ if (u->subject_cert.data == NULL) return ENOMEM;
+ u->subject_cert.length = strlen(u->subject_cert.data);
+ u->options = 0x80000000;
+ retval = ktest_make_sample_checksum(&p->cksum);
+ if (retval) return retval;
+ return 0;
+}
+
krb5_error_code ktest_make_sample_ad_kdcissued(p)
krb5_ad_kdcissued *p;
{
ktest_empty_data(&p->sam_sad);
}
+void ktest_empty_pa_s4u_x509_user(p)
+ krb5_pa_s4u_x509_user *p;
+{
+ ktest_destroy_principal(&p->user_id.user);
+ ktest_empty_data(&p->user_id.subject_cert);
+ if (p->cksum.contents) free(p->cksum.contents);
+}
+
void ktest_empty_ad_kdcissued(p)
krb5_ad_kdcissued *p;
{
(krb5_enc_sam_response_enc *p);
krb5_error_code ktest_make_sample_predicted_sam_response(krb5_predicted_sam_response *p);
krb5_error_code ktest_make_sample_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p);
+krb5_error_code ktest_make_sample_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p);
krb5_error_code ktest_make_sample_ad_kdcissued(krb5_ad_kdcissued *p);
#ifdef ENABLE_LDAP
void ktest_empty_predicted_sam_response(krb5_predicted_sam_response *p);
void ktest_empty_sam_response_2(krb5_sam_response_2 *p);
void ktest_empty_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p);
+void ktest_empty_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p);
void ktest_empty_ad_kdcissued(krb5_ad_kdcissued *p);
#ifdef ENABLE_LDAP
return p;
}
+int ktest_equal_pa_s4u_x509_user(ref, var)
+ krb5_pa_s4u_x509_user *ref;
+ krb5_pa_s4u_x509_user *var;
+{
+ int p = TRUE;
+ if (ref == var) return TRUE;
+ else if (ref == NULL || var == NULL) return FALSE;
+ p=p&&scalar_equal(user_id.nonce);
+ p=p&&ptr_equal(user_id.user,ktest_equal_principal_data);
+ p=p&&struct_equal(user_id.subject_cert,ktest_equal_data);
+ p=p&&scalar_equal(user_id.options);
+ p=p&&struct_equal(cksum,ktest_equal_checksum);
+ return p;
+}
+
int ktest_equal_ad_kdcissued(ref, var)
krb5_ad_kdcissued *ref;
krb5_ad_kdcissued *var;
(krb5_etype_info_entry * ref,
krb5_etype_info_entry * var);
+int ktest_equal_pa_s4u_x509_user
+ (krb5_pa_s4u_x509_user *ref,
+ krb5_pa_s4u_x509_user *var);
+
int ktest_equal_ad_kdcissued
(krb5_ad_kdcissued *ref,
krb5_ad_kdcissued *var);
encode_krb5_predicted_sam_response: 30 6D A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 07 03 05 00 00 00 00 09 A2 11 18 0F 31 39 37 30 30 31 30 31 30 30 30 30 31 37 5A A3 03 02 01 12 A4 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A5 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A6 07 04 05 68 65 6C 6C 6F
encode_krb5_sam_response_2: 30 42 A0 03 02 01 2B A1 07 03 05 00 80 00 00 00 A2 0C 04 0A 74 72 61 63 6B 20 64 61 74 61 A3 1D 30 1B A0 03 02 01 01 A1 04 02 02 0D 36 A2 0E 04 0C 6E 6F 6E 63 65 20 6F 72 20 73 61 64 A4 05 02 03 54 32 10
encode_krb5_enc_sam_response_enc_2: 30 1F A0 03 02 01 58 A1 18 04 16 65 6E 63 5F 73 61 6D 5F 72 65 73 70 6F 6E 73 65 5F 65 6E 63 5F 32
+encode_krb5_pa_s4u_x509_user: 30 68 A0 55 30 53 A0 06 02 04 00 CA 14 9A A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 12 04 10 70 61 5F 73 34 75 5F 78 35 30 39 5F 75 73 65 72 A4 07 03 05 00 80 00 00 00 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
encode_krb5_ad_kdcissued: 30 65 A0 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
. [0] [Integer] 88
. [1] [Octet String] "enc_sam_response_enc_2"
+encode_krb5_pa_s4u_x509_user:
+
+[Sequence/Sequence Of]
+. [0] [Sequence/Sequence Of]
+. . [0] [Integer] 13243546
+. . [1] [Sequence/Sequence Of]
+. . . [0] [Integer] 1
+. . . [1] [Sequence/Sequence Of]
+. . . . [General string] "hftsai"
+. . . . [General string] "extra"
+. . [2] [General string] "ATHENA.MIT.EDU"
+. . [3] [Octet String] "pa_s4u_x509_user"
+. . [4] [Bit String] 0x80000000
+. [1] [Sequence/Sequence Of]
+. . [0] [Integer] 1
+. . [1] [Octet String] "1234"
+
encode_krb5_ad_kdcissued:
[Sequence/Sequence Of]
PROG_LIBPATH=-L$(TOPLIBD)
PROG_RPATH=$(KRB5_LIBDIR)
-SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_namingexts.c
+SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c $(srcdir)/t_namingexts.c
-OBJS= t_imp_name.o t_namingexts.o
+OBJS= t_imp_name.o t_s4u.o t_namingexts.o
-all:: t_imp_name t_namingexts
+all:: t_imp_name t_s4u t_namingexts
t_imp_name: t_imp_name.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o t_imp_name t_imp_name.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
t_namingexts: t_namingexts.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o t_namingexts t_namingexts.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+t_s4u: t_s4u.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o t_s4u t_s4u.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
clean::
- $(RM) t_imp_name
+ $(RM) t_imp_name t_s4u t_namingexts
--- /dev/null
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gssapi/gssapi_krb5.h>
+
+/*
+ * Test program for protocol transition (S4U2Self) and constrained delegation
+ * (S4U2Proxy)
+ *
+ * Note: because of name canonicalization, the following tips may help
+ * when configuring with Active Directory:
+ *
+ * - Create a computer account FOO$
+ * - Set the UPN to host/foo.domain (no suffix); this is necessary to
+ * be able to send an AS-REQ as this principal, otherwise you would
+ * need to use the canonical name (FOO$), which will cause principal
+ * comparison errors in gss_accept_sec_context().
+ * - Add a SPN of host/foo.domain
+ * - Configure the computer account to support constrained delegation with
+ * protocol transition (Trust this computer for delegation to specified
+ * services only / Use any authentication protocol)
+ * - Add host/foo.domain to the keytab (possibly easiest to do this
+ * with ktadd)
+ *
+ * For S4U2Proxy to work the TGT must be forwardable too.
+ *
+ * Usage eg:
+ *
+ * kinit -k -t test.keytab -f 'host/test.win.mit.edu@WIN.MIT.EDU'
+ * ./t_s4u delegtest@WIN.MIT.EDU HOST/WIN-EQ7E4AA2WR8.win.mit.edu@WIN.MIT.EDU test.keytab
+ */
+
+static gss_OID_desc spnego_mech = { 6, "\053\006\001\005\005\002" };
+
+int use_spnego = 0;
+
+static void displayStatus_1(m, code, type)
+ char *m;
+ OM_uint32 code;
+ int type;
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc msg;
+ OM_uint32 msg_ctx;
+
+ msg_ctx = 0;
+ while (1) {
+ maj_stat = gss_display_status(&min_stat, code,
+ type, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ fprintf(stderr, "%s: %s\n", m, (char *)msg.value);
+ (void) gss_release_buffer(&min_stat, &msg);
+
+ if (!msg_ctx)
+ break;
+ }
+}
+
+static void displayStatus(msg, maj_stat, min_stat)
+ char *msg;
+ OM_uint32 maj_stat;
+ OM_uint32 min_stat;
+{
+ displayStatus_1(msg, maj_stat, GSS_C_GSS_CODE);
+ displayStatus_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static OM_uint32
+displayCanonName(OM_uint32 *minor, gss_name_t name, char *tag)
+{
+ gss_name_t canon;
+ OM_uint32 major, tmp_minor;
+ gss_buffer_desc buf;
+
+ major = gss_canonicalize_name(minor, name,
+ (gss_OID)gss_mech_krb5, &canon);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_canonicalize_name", major, *minor);
+ return major;
+ }
+
+ major = gss_display_name(minor, canon, &buf, NULL);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_display_name", major, *minor);
+ gss_release_name(&tmp_minor, &canon);
+ return major;
+ }
+
+ printf("%s:\t%s\n", tag, (char *)buf.value);
+
+ gss_release_buffer(&tmp_minor, &buf);
+ gss_release_name(&tmp_minor, &canon);
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+displayOID(OM_uint32 *minor, gss_OID oid, char *tag)
+{
+ OM_uint32 major, tmp_minor;
+ gss_buffer_desc buf;
+
+ major = gss_oid_to_str(minor, oid, &buf);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_oid_to_str", major, *minor);
+ return major;
+ }
+
+ printf("%s:\t%s\n", tag, (char *)buf.value);
+
+ gss_release_buffer(&tmp_minor, &buf);
+
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+initAcceptSecContext(OM_uint32 *minor,
+ gss_cred_id_t claimant_cred_handle,
+ gss_cred_id_t verifier_cred_handle,
+ gss_cred_id_t *deleg_cred_handle)
+{
+ OM_uint32 major, tmp_minor;
+ gss_buffer_desc token, tmp;
+ gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
+ gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT;
+ gss_name_t source_name = GSS_C_NO_NAME;
+ gss_name_t target_name = GSS_C_NO_NAME;
+ OM_uint32 time_rec;
+ gss_OID mech = GSS_C_NO_OID;
+
+ token.value = NULL;
+ token.length = 0;
+
+ tmp.value = NULL;
+ tmp.length = 0;
+
+ *deleg_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ major = gss_inquire_cred(minor, verifier_cred_handle,
+ &target_name, NULL, NULL, NULL);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_inquire_cred", major, *minor);
+ return major;
+ }
+
+ displayCanonName(minor, target_name, "Target name");
+
+ mech = use_spnego ? (gss_OID)&spnego_mech : (gss_OID)gss_mech_krb5;
+ displayOID(minor, mech, "Target mech");
+
+ major = gss_init_sec_context(minor,
+ claimant_cred_handle,
+ &initiator_context,
+ target_name,
+ mech,
+ GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_BUFFER,
+ NULL,
+ &token,
+ NULL,
+ &time_rec);
+
+ if (target_name != GSS_C_NO_NAME)
+ (void) gss_release_name(&tmp_minor, &target_name);
+
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_init_sec_context", major, *minor);
+ return major;
+ }
+
+ (void) gss_delete_sec_context(minor, &initiator_context, NULL);
+ mech = GSS_C_NO_OID;
+
+ major = gss_accept_sec_context(minor,
+ &acceptor_context,
+ verifier_cred_handle,
+ &token,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &source_name,
+ &mech,
+ &tmp,
+ NULL,
+ &time_rec,
+ deleg_cred_handle);
+
+ if (GSS_ERROR(major))
+ displayStatus("gss_accept_sec_context", major, *minor);
+ else {
+ displayCanonName(minor, source_name, "Source name");
+ displayOID(minor, mech, "Source mech");
+ }
+
+ (void) gss_release_name(&tmp_minor, &source_name);
+ (void) gss_delete_sec_context(&tmp_minor, &acceptor_context, NULL);
+ (void) gss_release_buffer(&tmp_minor, &token);
+ (void) gss_release_buffer(&tmp_minor, &tmp);
+ (void) gss_release_oid(&tmp_minor, &mech);
+
+ return major;
+}
+
+static OM_uint32
+constrainedDelegate(OM_uint32 *minor,
+ gss_OID_set desired_mechs,
+ gss_name_t target,
+ gss_cred_id_t delegated_cred_handle,
+ gss_cred_id_t verifier_cred_handle)
+{
+ OM_uint32 major, tmp_minor;
+ gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
+ gss_name_t cred_name = GSS_C_NO_NAME;
+ OM_uint32 time_rec, lifetime;
+ gss_cred_usage_t usage;
+ gss_buffer_desc token;
+ gss_OID_set mechs;
+
+ printf("Constrained delegation tests follow\n");
+ printf("-----------------------------------\n\n");
+
+ if (gss_inquire_cred(minor, verifier_cred_handle, &cred_name,
+ &lifetime, &usage, NULL) == GSS_S_COMPLETE) {
+ displayCanonName(minor, cred_name, "Proxy name");
+ gss_release_name(&tmp_minor, &cred_name);
+ }
+ displayCanonName(minor, target, "Target name");
+ if (gss_inquire_cred(minor, delegated_cred_handle, &cred_name,
+ &lifetime, &usage, &mechs) == GSS_S_COMPLETE) {
+ displayCanonName(minor, cred_name, "Delegated name");
+ displayOID(minor, &mechs->elements[0], "Delegated mech");
+ gss_release_name(&tmp_minor, &cred_name);
+ }
+
+ printf("\n");
+
+ major = gss_init_sec_context(minor,
+ delegated_cred_handle,
+ &initiator_context,
+ target,
+ mechs ? &mechs->elements[0] :
+ (gss_OID)gss_mech_krb5,
+ GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_BUFFER,
+ NULL,
+ &token,
+ NULL,
+ &time_rec);
+ if (GSS_ERROR(major))
+ displayStatus("gss_init_sec_context", major, *minor);
+
+ (void) gss_release_buffer(&tmp_minor, &token);
+ (void) gss_delete_sec_context(&tmp_minor, &initiator_context, NULL);
+ (void) gss_release_oid_set(&tmp_minor, &mechs);
+
+ return major;
+}
+
+int main(int argc, char *argv[])
+{
+ OM_uint32 minor, major;
+ gss_cred_id_t impersonator_cred_handle = GSS_C_NO_CREDENTIAL;
+ gss_cred_id_t user_cred_handle = GSS_C_NO_CREDENTIAL;
+ gss_cred_id_t delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+ gss_name_t user = GSS_C_NO_NAME, target = GSS_C_NO_NAME;
+ gss_OID_set_desc mechs;
+ gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
+ gss_buffer_desc buf;
+
+ if (argc < 2 || argc > 5) {
+ fprintf(stderr, "Usage: %s [--spnego] [user] "
+ "[proxy-target] [keytab]\n", argv[0]);
+ fprintf(stderr, " proxy-target and keytab are optional\n");
+ exit(1);
+ }
+
+ if (strcmp(argv[1], "--spnego") == 0) {
+ use_spnego++;
+ argc--;
+ argv++;
+ }
+
+ buf.value = argv[1];
+ buf.length = strlen((char *)buf.value);
+
+ major = gss_import_name(&minor, &buf,
+ (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
+ &user);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_import_name(user)", major, minor);
+ goto out;
+ }
+
+ if (argc > 2 && strcmp(argv[2], "-")) {
+ buf.value = argv[2];
+ buf.length = strlen((char *)buf.value);
+
+ major = gss_import_name(&minor, &buf,
+ (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
+ &target);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_import_name(target)", major, minor);
+ goto out;
+ }
+ } else {
+ target = GSS_C_NO_NAME;
+ }
+
+ if (argc > 3) {
+ major = krb5_gss_register_acceptor_identity(argv[3]);
+ if (GSS_ERROR(major)) {
+ displayStatus("krb5_gss_register_acceptor_identity",
+ major, minor);
+ goto out;
+ }
+ }
+
+ mechs.elements = use_spnego ? (gss_OID)&spnego_mech :
+ (gss_OID)gss_mech_krb5;
+ mechs.count = 1;
+
+ /* get default cred */
+ major = gss_acquire_cred(&minor,
+ GSS_C_NO_NAME,
+ GSS_C_INDEFINITE,
+ &mechs,
+ GSS_C_BOTH,
+ &impersonator_cred_handle,
+ &actual_mechs,
+ NULL);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_acquire_cred", major, minor);
+ goto out;
+ }
+
+ (void) gss_release_oid_set(&minor, &actual_mechs);
+
+ printf("Protocol transition tests follow\n");
+ printf("-----------------------------------\n\n");
+
+ /* get S4U2Self cred */
+ major = gss_acquire_cred_impersonate_name(&minor,
+ impersonator_cred_handle,
+ user,
+ GSS_C_INDEFINITE,
+ &mechs,
+ GSS_C_INITIATE,
+ &user_cred_handle,
+ &actual_mechs,
+ NULL);
+ if (GSS_ERROR(major)) {
+ displayStatus("gss_acquire_cred_impersonate_name", major, minor);
+ goto out;
+ }
+
+ major = initAcceptSecContext(&minor,
+ user_cred_handle,
+ impersonator_cred_handle,
+ &delegated_cred_handle);
+ if (GSS_ERROR(major))
+ goto out;
+
+ printf("\n");
+
+ if (target != GSS_C_NO_NAME &&
+ delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
+ major = constrainedDelegate(&minor, &mechs, target,
+ delegated_cred_handle,
+ impersonator_cred_handle);
+ } else if (target != GSS_C_NO_NAME) {
+ fprintf(stderr, "Warning: no delegated credentials handle returned\n\n");
+ fprintf(stderr, "Verify:\n\n");
+ fprintf(stderr, " - The TGT for the impersonating service is forwardable\n");
+ fprintf(stderr, " - The T2A4D flag set on the impersonating service's UAC\n");
+ fprintf(stderr, " - The user is not marked sensitive and cannot be delegated\n");
+ fprintf(stderr, "\n");
+ }
+
+out:
+ (void) gss_release_name(&minor, &user);
+ (void) gss_release_name(&minor, &target);
+ (void) gss_release_cred(&minor, &delegated_cred_handle);
+ (void) gss_release_cred(&minor, &impersonator_cred_handle);
+ (void) gss_release_cred(&minor, &user_cred_handle);
+ (void) gss_release_oid_set(&minor, &actual_mechs);
+
+ return GSS_ERROR(major) ? 1 : 0;
+}
+
--- /dev/null
+ABOUT:
+A translation of Will Fiveash's "mit_db2_mkey_migrate_testB" ksh code into Python with the default db2 backend. With minor fixes and changes. Written by HaoQi Li.
+
+DEFAULT SETTINGS:
+Options Name Default Setting
+ -h Help
+ -v Verbose: True
+ -p Testing pw: test123
+ -s Sandbox loc: src/tests/mk_migr/db2_backend/sandbox
+ -c Krb5kdc: src/kdc/krb5kdc
+ -d Kadmind: src/kadmin/server/kadmind
+ -b Kdb5_util: src/kadmin/dbutil/kdb5_util
+ -l Kadmin.local: src/kadmin/cli/kadmin.local
+ -n Kadmin: src/kadmin/cli/kadmin
+ -t Client paths: src/clients
+
+INPUTS:
+* src/tests/mk_migr/db2_backend/input_conf/kdc_template_db2.conf
+* src/tests/mk_migr/db2_backend/input_conf/krb5_template_db2.conf
+* src/tests/mk_migr/db2_backend/input_conf/kadm5_template_db2.acl
+
+OUTPUTS:
+* sandbox that contains customized outfile with all commands and their outputs, kdc.conf, krb5.conf, kadm6.acl, and others.
+* Statistics on screen of number of commands passed and failed.
+
+EXAMPLES:
+- MUST RUN from trunk/src.
+* python tests/mk_migr/db2_backend/mkmdb2.py
+ Using all Default Settings.
+* python tests/mk_migr/db2_backend/mkmdb2.py -s /tmp/mySandbox
+ Sandbox now can be found in /tmp/mySandbox.
+
+
+# Notes:
+# Exists only at the end, unless fatal errors are encountered. Otherwise, skips errors and continue!!
+# "haoqili" is a name that can be changed.
+# 2019 and 2029 are future dates that should best be written not as fixed. Such as now+10years.
--- /dev/null
+[kdcdefaults]
+ kdc_ports = 8888
+
+[realms]
+ K.MIT.EDU = {
+ database_name = %(sandboxdir)s/principal
+ acl_file = %(sandboxdir)s/kadm5.acl
+ key_stash_file = %(sandboxdir)s/keyStashFile
+ kdc_ports = 8888
+ kpasswd_port = 8887
+ kadmind_port = 8886
+ max_life = 10h 0m 0s
+ max_renewable_life = 7d 0h 0m 0s
+ }
--- /dev/null
+[libdefaults]
+ default_realm = K.MIT.EDU
+
+[realms]
+# use "kdc = ..." if realm admins haven't put SRV records into DNS
+ K.MIT.EDU = {
+ admin_server = %(localFQDN)s:8886
+ kpasswd_server = %(localFQDN)s:8887
+ default_domain = MIT.EDU
+ kdc = %(localFQDN)s:8888
+ v4_instance_convert = {
+ mit = mit.edu
+ lithium = lithium.lcs.mit.edu
+ }
+ }
+ ANDREW.CMU.EDU = {
+ admin_server = vice28.fs.andrew.cmu.edu
+ }
+
+[logging]
+# kdc = CONSOLE
--- /dev/null
+# Master Key Migration for db2
+
+import os, sys, shutil, socket, time, string
+from subprocess import Popen, PIPE
+from optparse import OptionParser
+from time import strftime
+
+class MasterKeyMigrationTest:
+ def __init__(self, verbose_in, pw_in, kdcPath_in, kdmdPath_in, kdbPath_in, kdmlPath_in, kdmPath_in, cltPath_in, sandir_in):
+ self.npass = 0
+ self.nfail = 0
+
+ self.verbose = verbose_in
+ self.pw = pw_in
+
+ self.krb5kdc = kdcPath_in #1 krb5kdc
+ self.kadmind = kdmdPath_in #2 kadmind
+ self.kdb5_util = kdbPath_in #3 kdb5_util
+ self.kadminlocal = kdmlPath_in #4 kadmin.local
+ self.kadmin = kdmPath_in #5 kadmin
+ self.clients = cltPath_in+"/" #6 clients
+
+ self.sandir = sandir_in
+
+ ########## SET UP Write Output File #####
+ self.outfile = open(self.sandir+"/outfile", 'w')
+
+ '''print os.environ'''
+
+ def _writeLine(self, astr, prt=False):
+ self.outfile.write(astr.strip()+"\n")
+ if prt:
+ print astr.strip()
+
+ def _writeHeader(self, astr, prt=True):
+ self.outfile.write("\n========== "+astr.strip()+" ==========\n")
+ if prt:
+ print "========== "+astr.strip()+" =========="
+
+ def _sysexit(self, fatal=False, finished=False):
+ self._writeLine("++++++++++++++++++++++++++++++", True)
+ if fatal:
+ self._writeLine("++++ Test did NOT finish +++++", True)
+ self._writeLine("++++ FATAL FAILURE! Stopped ++", True)
+ self._writeLine("++++ See sandbox/outfile +++++", True)
+ self._writeLine("++++++++++++++++++++++++++++++", True)
+ sys.exit()
+ elif not finished:
+ self._writeLine("++++ Test did NOT finish +++++", True)
+ self._writeLine("++++ FAIL Detected! keep going", True)
+ self._writeLine("++++++++++++++++++++++++++++++", True)
+ else: #finished
+ self._writeLine("++++ MKM Test Finished +++++++", True)
+ self._writeLine("++++++++++++++++++++++++++++++", True)
+ self._writeLine("++++ Commands Passed: %s +++++" % self.npass, True)
+ self._writeLine("++++ Commands Failed: %s +++++" % self.nfail, True)
+ sys.exit()
+
+ def _printig(self):
+ self._writeLine("~.~.~Error should be ignored~.~.~.~")
+
+ def _printerr(self, errm, stderr):
+ self._writeLine("#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#")
+ self._writeLine("-XX-FAILED: "+errm+". See stderr below:")
+ [self._writeLine(line) for line in stderr.readlines() ]
+
+ def _printout(self, cmd, pstdout):
+ if self.verbose:
+ self._writeLine("---------------------------------------")
+ self._writeLine("-command: "+cmd)
+ self._writeLine("-----out: ")
+ [self._writeLine(line) for line in pstdout.readlines()]
+
+ def _eval(self, succeed, pwait, errm, pstderr, fatal=False, msg2="", finished=False):
+ if int(pwait) != 0: # is bad
+ self._printerr(errm, pstderr)
+ if succeed==True: ## want good
+ self.nfail += 1
+ self._sysexit(fatal, finished)
+ else: ## want bad
+ self.npass += 1
+ self._printig()
+ else: # is good
+ if not succeed: ## want bad
+ if msg2 != "":
+ self._writeLine(msg2, True)
+ self.nfail += 1
+ self._sysexit(fatal, finished)
+ else: ## want good
+ self.npass += 1
+
+ def _metafunc(self, command, errmsg, moreinfo="", isLocal=False, succeed=True, fatal=False):
+ l = command
+ if isLocal:
+ pl = Popen(l.split(None,2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ else:
+ pl = Popen(l.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ self._printout(l+moreinfo, pl.stdout)
+
+ self._eval(succeed, pl.wait(), errmsg, pl.stderr, fatal)
+
+ ###########################################
+
+ # Start the KDC daemons
+ def _startkdc(self):
+ self._writeLine("\nstarting kdc daemons ...")
+ l0 = self.krb5kdc
+ errm = "error at starting krb5kdc"
+ self._metafunc(l0, errm)
+ # below has been changed
+ l0b = self.kadmind + ' -W -nofork' #the W is for during off strong random numbers
+ errm = "error at starting kadmind, maybe it's already started"
+ pl0b = Popen(l0b.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ self._writeLine( "kadmind -nofork")
+ started = False
+ while time.clock() < 3:
+ l = pl0b.stderr.readline()
+ if l.find("starting") > -1:
+ self._writeLine( l.strip())
+ self.npass += 1
+ started = True
+ break
+ else:
+ self.nfail += 1
+ self._printerr("kadmind not starting, check to see if there are any previous kadmind running with cmd: 'ps -ef | grep kadmind' and then do 'sudo kill -9 [# on the left]'", pl0b.stderr)
+ self._sysexit(fatal=True)
+ if not started:
+ self.nfail += 1
+ self._sysexit()
+ self._writeLine("end starting kdc daemons")
+
+ # Kill the KDC daemons in case they are running
+ def _killkdc(self, suc=True):
+ l1 = 'pkill -9 -x krb5kdc'
+ errm = "no krb5kdc killed"
+ self._metafunc(l1, errm, succeed=suc)
+
+ l2 = 'pkill -9 -x kadmind'
+ errm = "no kadmind killed"
+ self._metafunc(l2, errm, succeed=suc)
+
+ # Destroys current database
+ def _destroykdc(self, suc=True):
+ l3 = self.kdb5_util+' destroy -f' #forced
+ errm = "no kdb database destroyed"
+ self._metafunc(l3, errm, succeed=suc)
+
+ # Create a new database with a new master key
+ def _createdb(self, pw):
+ l4 = self.kdb5_util+' -P '+pw+' create -s -W' #added W for svn version 22435 to avoid reading strong random numbers
+ errm = "error when creating new database, _createdb()"
+ self._metafunc(l4, errm, fatal=True)
+
+ # Addprinc
+ def _locAddprinc(self, passw, usern):
+ l5 = self.kadminlocal+' -q addprinc -pw '+passw+' '+usern
+ errm = "error when adding princ, _locAddprinc"
+ self._metafunc(l5, errm, isLocal=True)
+
+ # List princs
+ def _locListprincs(self):
+ l6 = self.kadminlocal+' -q listprincs'
+ errm = "error when listing princs, _locListprincs"
+ self._metafunc(l6, errm, isLocal=True)
+
+ # Get princs
+ def _locGetprinc(self, usern, extra=False, succeed=True):
+ l7 = self.kadminlocal+' -q getprinc '+usern
+ errm="error when getting princ, _locGetprinc"
+
+ pl7 = Popen(l7.split(None,2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ if not extra:
+ self._printout(l7, pl7.stdout)
+ else:
+ if self.verbose:
+ self._writeLine("-command: "+l7)
+ self._writeLine("-----out: ")
+ for line in pl7.stdout.readlines():
+ if line.startswith("Princ") or line.startswith("MKey"):
+ self._writeLine(line)
+ self._eval(succeed, pl7.wait(), errm, pl7.stderr)
+
+ # Get princs and finds something in the output
+ def _locGetprincFind(self, usern, findstr, succeed=True):
+ l7b = self.kadminlocal+' -q getprinc ' +usern
+ errm="error when getting princs, _locGetprinc, (regular output of getprincs is not printed here), will NOT continue to find string="+findstr
+ pl7b = Popen(l7b.split(None, 2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ if self.verbose:
+ self._writeLine("-command: "+l7b)
+ if int(pl7b.wait()) != 0: # is bad
+ self._printerr(errm, pl7b.stderr)
+ if succeed: ## want good
+ self.nfail += 1
+ self._sysexit()
+ else: ## want bad
+ self.npass += 1
+ self._printig()
+ else: # is good
+ if self.verbose:
+ self._writeLine( "-----out: ")
+ boofound = False
+ for outl in pl7b.stdout.readlines():
+ self._writeLine(outl)
+ if string.find(outl, findstr) > -1:
+ boofound = True
+ if boofound:
+ self._writeLine("----FOUND: "+findstr)
+ else:
+ self._writeLine("----NOT FOUND: "+findstr)
+ if not succeed: ## want bad
+ self.nfail += 1
+ self._sysexit()
+ else: ## want good
+ self.npass += 1
+
+ # Add policy
+ def _locAddpol(self, maxtime, minlength, minclasses, history, policyname):
+ rest = ""
+ if maxtime != None:
+ rest += '-maxlife '+maxtime+' '
+ if minlength != None:
+ rest += '-minlength '+minlength+' '
+ if minclasses != None:
+ rest += '-minclasses '+minclasses+' '
+ if history != None:
+ rest += '-history '+history+' '
+ l8 = self.kadminlocal+' -q add_policy '+rest+policyname
+ errm = "error when adding policy, _locAddpol"
+ self._metafunc(l8, errm, isLocal=True)
+
+ # Get pol
+ def _locGetpol(self, poln):
+ l8b = self.kadminlocal+' -q getpol '+poln
+ errm="error when getting pol, _locGetpol"
+ self._metafunc(l8b, errm, isLocal=True)
+
+ # Modify Principal
+ def _locModprinc(self, rest):
+ l9 = self.kadminlocal+' -q modprinc '+rest
+ errm = "error when modifing principal, _locModprinc"
+ self._metafunc(l9, errm, isLocal=True)
+
+ # List mkeys
+ def _listmkeys(self):
+ l10 = self.kdb5_util+' list_mkeys'
+ errm = "error when listing mkeys, _listmkeys"
+ self._metafunc(l10, errm)
+
+ # Use mkeys
+ def _usemkey(self, kvno, time, succeed=True):
+ l11 = self.kdb5_util+' use_mkey '+kvno+' '+time
+ pl11 = Popen(l11.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ self._printout(l11, pl11.stdout)
+ self._eval(succeed, pl11.wait(), "error when using mkeys, _usemkey", pl11.stderr, msg2="-XX-ERROR: "+l11+" should have failed.")
+
+
+ # Change password (cpw)
+ def _locCpw(self, passw, usern):
+ l12 = self.kadminlocal+' -q cpw -pw '+passw+' '+usern
+ errm = "error when changing password, _locCpw"
+ self._metafunc(l12, errm, moreinfo="\n--------: newpw='"+passw+"'", isLocal=True)
+
+ # Purge mkeys
+ def _purgemkeys(self):
+ l13 = self.kdb5_util+' purge_mkeys -f -v' #-f is forced, -v is verbose
+ errm = "error when purging mkeys, _purgemkeys"
+ self._metafunc(l13, errm)
+
+ # Add mkey
+ def _addmkey(self, passw, extra="", succeed=True):
+ l14 = self.kdb5_util+' add_mkey '+extra
+ pl14 = Popen(l14.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ pl14.stdin.write(passw+'\n') #enter 1st time
+ pl14.stdin.write(passw+'\n') #re-enter
+ self._printout(l14+' [with password='+passw+']', pl14.stdout)
+ self._eval(succeed, pl14.wait(), "error when adding mkey, _addmkey", pl14.stderr)
+ self._writeLine( "----end of adding mkey")
+
+ # kinit user
+ def _kinit(self, passw_in, usern, succeed=True):
+ l15 = self.clients+'kinit/kinit '+usern
+ pl15 = Popen(l15.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ pl15.stdin.write(passw_in+'\n')
+ pl15.stdin.close()
+ self._printout(l15, pl15.stdout)
+ self._eval(succeed, pl15.wait(), "error when kinit user, _kinit", pl15.stderr)
+ self._writeLine( "----end of kiniting user")
+
+ # change password on client's side
+ def _kpasswd(self, oldpw, newpw, usern, succeed=True):
+ l16 = self.clients+'kpasswd/kpasswd '+usern
+ pl16 = Popen(l16.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ pl16.stdin.write(oldpw+'\n')
+ pl16.stdin.write(newpw+'\n')
+ pl16.stdin.write(newpw+'\n')
+ self._printout(l16+"\n--------: oldpw='"+oldpw+"' -> newpw='"+newpw+"'", pl16.stdout)
+ self._eval(succeed, pl16.wait(), "error when changing password on client's side, _kpasswd", pl16.stderr)
+ self._writeLine("----end of changing kpasswd")
+
+ # klist on client's side
+ def _klist(self):
+ l17 = self.clients+'klist/klist'
+ errm = "error when klist, _klist"
+ self._metafunc(l17, errm)
+
+ # Update principal encryption
+ def _updatePrincEnc(self):
+ l18 = self.kdb5_util+' update_princ_encryption -f -v'
+ errm = "error when updating principal encryption, _updatePrincEnc"
+ self._metafunc(l18, errm)
+
+ # kdestroy
+ def _kdestroy(self):
+ l19 = self.clients+'kdestroy/kdestroy'
+ errm = "error when kdestroy, _kdestroy"
+ self._metafunc(l19, errm)
+
+ # stash
+ def _stash(self):
+ l20 = self.kdb5_util+' stash'
+ errm="error at stash, _stash"
+ self._metafunc(l20, errm)
+
+ # any shell command
+ def _shell(self, command, succeed=True):
+ l21 = command
+ errm="error at executing this command in _shell(): "+l21
+ pl21 = Popen(l21, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ self._printout(l21, pl21.stdout)
+ self._eval(succeed, pl21.wait(), errm, pl21.stderr)
+ '''self._printerr(errm, pl21.stderr) Pointed out that kadmin had problems!'''
+
+ # get_princ_records()
+ def _get_princ_records(self, succeed=True):
+ l22 = self.kadminlocal+" -q listprincs 2>/dev/null|grep -v '^Authenticating as'|fgrep '@'|sort"
+ errm="error at listprincs in _get_princ_records() with this command: "+l22
+ pl22 = Popen(l22, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ if int(pl22.wait()) != 0: # is bad
+ self.printerr(errm, pl22.stderr)
+ if succeed: ## want good
+ self.nfail += 1
+ self._sysexit()
+ else: ## want badd
+ self.npass += 1
+ self._printig()
+ else: # is good
+ if not succeed: ## want bad
+ self.nfail += 1
+ self._sysexit()
+ else: ## want good
+ self.npass += 1
+ self._writeLine( "\nget_princ_records() executing all listprincs command: "+l22+"\n------its results:")
+ for princ in pl22.stdout.readlines():
+ self._locGetprinc(princ.strip(), extra=True)
+ self._writeLine("END executing command: "+l22+"\n~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~")
+
+######################################################
+ def run(self):
+ #############RUN###################
+ passw=self.pw
+
+ self._writeHeader("START MASTER KEY MIGRATION TEST")
+
+ # Set up database
+ self._writeHeader("SET UP: database")
+ self._killkdc("Either") #74 =1,2
+ self._destroykdc("Either") #77 =3
+ self._createdb(passw) #81 =4
+ #line 83-86 involves ktadd kadm5.keytab, which are out dated
+
+ # add, get, and list princs
+ self._writeHeader("SET UP: add/get/list princs")
+ self._locAddprinc(passw, 'kdc/admin') #87 =5
+ self._locListprincs() #89 =6
+ self._locGetprinc('K/M') #90 =7
+ self._locAddprinc('test123', 'haoqili') #91 =8
+ self._locGetprinc('haoqili') #92 =9
+ self._locAddprinc(passw, 'haoqili/admin') #93 =10
+ self._locAddprinc('foobar', 'test') #94 =11
+ self._locGetprinc('test') #95 =12
+ self._locListprincs() # I added =13
+ myfqdn = socket.getfqdn()
+ #self._shell(self.parentpath+"kadmin.local -q 'addprinc -randkey host/"+myfqdn+"'") #96
+ self._shell(self.kadminlocal+" -q 'addprinc -randkey host/"+myfqdn+"'") #96 =14
+
+ # create policies
+ self._writeHeader("SET UP: create policies")
+ #print "\n~~~~~~~~~ create policies ~~~~~~~~~~~"
+ self._locAddpol('8days', None, None, None, 'testpolicy')#100 =15
+ self._locAddpol('20days', '8', '3', None, 'testpolicy2')#101
+ self._locAddpol('90days', '2', '2', None, 'testpolicy3')#102
+ self._locAddpol('90days', '2', '2', '3', 'testpolicy4')#103
+
+ self._locModprinc('-policy testpolicy haoqili')#105
+ self._locAddprinc(passw, 'foo')#106
+ self._locModprinc('-policy testpolicy3 foo')#107 =21
+
+ # create all princ with all fields
+ self._writeHeader("SET UP: create all princ with all fields")
+ #print "\n~~~~~~~~~ create all princ with all fields ~~~~~"
+ self._locAddprinc(passw, 'all') #110 =22
+ self._locModprinc('-expire "2029-12-30 7pm" all') #112
+ self._locModprinc('-pwexpire 12/30/2029 all') #114
+ self._locGetprinc('all') #115
+ self._locModprinc('-maxlife 100days all') #116
+ self._locGetprinc('all') #117
+ self._locModprinc('-maxrenewlife 100days all') #118
+ self._locGetprinc('all') #119
+ self._locModprinc('+allow_postdated +allow_forwardable all') #120 =30
+ self._locModprinc('+allow_proxiable +allow_dup_skey all') #121
+ self._locModprinc('+requires_preauth +allow_svr +needchange all') #122
+ self._locModprinc('-policy testpolicy4 all') #123
+ self._locGetprinc('all') #124 =34
+
+ # Testing stuff
+ self._writeHeader("TEST: initial mkey list") #126
+ self._writeLine("===== Listing mkeys at start of test") #I add
+ self._listmkeys() #127 =35
+
+ self._writeLine( "Testing krb5kdc list_mkeys Done ==============================================") #128
+
+ self._writeLine("---------------\n xxxxxxxxxx \/\/\/ ERRORS (multiple) EXPECTED below xxxxxxxxxx")
+ self._writeLine("\nERRORS (multiple) EXPECTED below")
+ self._writeLine("Testing bogus use_mkey (setting only mkey to future date, using non-existent kvno, so should return error) =======") #129, 130
+ self._writeLine( "-> must have a mkey currently active (setting mkey to 2 days from now), should fail and return error") #132
+ self._usemkey('1', 'now+2days', False) #133-138 =36
+
+ self._writeLine("-> must have a mkey currently active (setting mkey to 2019 the future), should fail and return error") #140
+ self._usemkey('1', '5/30/2019', False) #141 =37
+ self._writeLine("-> bogus kvno and setting mkey to 2 days from now, should fail and return error") #147
+ self._usemkey('2', 'now+2days', False) #148 =38
+ self._writeLine("-> bogus kvno, should fail and return error") #I add
+ self._usemkey('2', 'now-2days', False) #I add =39
+ self._writeLine( "^^^ABOVE^^ SHOULD HAVE *ALL* FAILED\n-----------------")
+
+ self._writeLine( "Listing mkeys at end of test") #I add
+ self._listmkeys() #155 =40
+ self._writeLine("Testing bogus use_mkey (setting only mkey to future date) Done ===========================") #156
+
+
+ self._writeLine("\nmake sure cpw [change password] works") #158
+ # this changes the password of 'test' from 'foobar' in "add, get, and list princs" above
+ self._locCpw('test1', 'test') #159 =41
+
+ self._writeHeader("TEST: bogus purge_mkeys (should be no keys purged, no error returned")
+ #print "\nTesting bogus purge_mkeys (should be no keys purged, no error returned) ===========================" #161
+ self._purgemkeys() #162 =42
+ self._writeLine("Testing bogus purge_mkeys (no error) Done ===========================") #163
+
+ self._writeLine( "\nadd kvno 2") #164
+ self._addmkey('abcde', '-s') #165-167 =43
+ self._writeLine("\nlist mkeys")
+ self._listmkeys() #169 =44
+
+ #start daemons
+ self._startkdc() #172 =45 46
+ self._writeLine("make sure kdc is up, by kinit test") #176
+ self._kinit('test1', 'test') #177 =47
+
+ self._writeLine("---------------\n\/\/\/ ERROR EXPECTED below. Test passwd policy.:") #180
+ self._kinit(passw, 'all', succeed=False) #181 =48
+ self._writeLine("^^ABOVE^^ SHOULD HAVE FAILED\n-----------------")
+
+ #change passwd on client's side
+ self._kpasswd(passw, 'Test123.', 'all')#184-188 =49
+
+ self._kinit('Test123.', 'all') #189 =50
+ self._klist() #190 =51
+
+ self._writeHeader("TEST: password history for principal 'all', new passwords must not be a previous password") #191
+ self._kpasswd('Test123.', 'Foobar2!', 'all') #192-195 =52
+ self._writeLine("--------------\n\/\/\/ ERROR EXPECTED below") #197
+ self._kpasswd('Foobar2!', passw, 'all', succeed=False) #199-202 =53
+ self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n----------")
+
+ # this shouldn't change the mkvno for any princs (should be 1) #206
+ #self._updatePrincEnc() #207
+ # princs should still be protected by mkvno 1 #208
+ self._writeLine("@@@@@@@@ Wait for other people to fix bug in code 6507 update_princ_encryption to use mkey instead of latest mkey @@@@@@@@@@@@@\n")
+ self._locGetprincFind('test', 'MKey: vno 1') #209 =54
+
+ self._purgemkeys() #210 =55
+ self._listmkeys() #211 =56
+ self._usemkey('2', 'now-1day') #213 =57
+ self._listmkeys() #214 =58
+
+ self._writeLine("-----------\n\/\/\/ ERROR EXPECTED below") #216
+ self._kpasswd('Foobar2!', passw, 'all', succeed=False) #217-221 =59
+ self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n--------")
+
+ self._kpasswd('Foobar2!', 'Barfoo3.', 'all') #224-228 =60
+ self._kinit('Barfoo3.', 'all') #229
+ self._klist() #230 =62
+
+ self._writeLine("-------------\n\/\/\/ ERROR EXPECTED below") #231
+ self._kpasswd('Barfoo3.', 'Foobar2!', 'all',succeed=False) #233-235 =63
+ self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n---------")
+
+ self._writeLine("\nTest's key should be protected by mkvno 2" ) #239
+ self._locCpw('foo', 'test') #240 =64
+ self._locGetprincFind('test', 'MKey: vno 2') #241 =65
+ self._kdestroy() #242 =66
+
+ self._writeHeader("TEST: krb5kdc refetch of mkey")#243
+ self._kinit('foo', 'test') #244 =67
+ self._klist() #245 =68
+ self._writeLine("END. Testing krb5kdc refetch of mkey list Done ==============================================\n") #246
+
+ self._updatePrincEnc() #247 =69
+ self._get_princ_records() #248 =70 -83
+ self._kdestroy() #249 =84
+ self._kinit('foo', 'test') #250 =85
+ self._purgemkeys() #252 =86
+
+ self._stash() #254 =87
+ self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/keyStashFile") #255 =88
+
+ self._locGetprinc('K/M') #256 =89
+ self._purgemkeys() #257 =90
+ self._locGetprinc('K/M') #258
+ self._listmkeys() #259 =92
+ self._kdestroy() #260
+ self._kinit('foo', 'test') #261
+ self._klist() #262 =95
+
+ self._writeLine("\n Adding in Master Key Number 3")
+ self._listmkeys() #265 =96
+ self._addmkey('abcde') #266-268
+ self._listmkeys() #270 =98
+ self._locCpw('foo', 'all') #271
+ self._locGetprinc('all') #272 =100
+ self._usemkey('3', 'now') #273
+ self._listmkeys() #274 =102
+ self._locCpw('99acefghI0!', 'all') #275
+ self._locGetprinc('all') #276 =104
+ self._kdestroy() #277
+ self._kinit('foo', 'test') #279 =106
+ self._klist() #280
+ self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'listprincs'") #281 =108
+ self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'getprinc test'") #282 =109
+
+ self._writeHeader("TEST: add_mkey with aes128 enctype") #283
+ self._addmkey('abcde', '-e aes128-cts-hmac-sha1-96') #284-287 =110
+ self._listmkeys() #288 =111
+
+ self._writeLine( "END. Testing add_mkey with aes128 enctype done ==============================================")#289
+
+ self._writeHeader("TEST: krb5kdc refetch of mkey list")
+ self._usemkey('4', 'now') #290 =112
+ self._listmkeys() #291 =113
+ self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'cpw -pw abcde test'") #292 =114
+ self._shell(self.kadmin +" -p haoqili/admin -w "+passw+" -q 'getprinc test'") #293
+ self._kdestroy() #294 =116
+
+ self._writeLine("\nTesting krb5kdc refetch of mkey list =================================================") #295
+ self._kinit('abcde', 'test') #296 =117
+ #'self._klist() #297 =118
+ self._writeLine("Testing krb5kdc refetch of mkey list Done :) =================================================\n") #298
+
+ self._killkdc() #300 =119, 120
+ self._startkdc() #301 =121 122
+ self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'cpw -pw foo test'") #304 =123
+ self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc test'") #305 =124
+ self._kdestroy() #307 =125
+
+ self._writeLine("\nTesting krb5kdc refetch of mkey list =================================================") #308
+ self._kinit('foo', 'test') #309 =126
+ self._klist() #310 =127
+ self._writeLine("Testing krb5kdc refetch of mkey list Done =================================================\n") #311
+
+ self._updatePrincEnc() #313 =128
+ self._locGetprinc('K/M') #314
+ self._locGetprinc('all') #315 =130
+ self._locGetprinc('haoqili') #316
+ self._kdestroy() #317 =132
+ self._kinit('foo', 'test') #318
+ self._stash() #319 =134
+ self._shell(self.clients+'klist/klist' + " -ekt "+self.sandir+"/keyStashFile") #320
+ self._locGetprinc('K/M') #321 =136
+ self._purgemkeys() #322
+ self._locGetprinc('K/M') #323 =138
+ self._locGetprinc('all') #324
+ self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc test'") #325 =140
+ self._listmkeys() #326
+ self._kdestroy() #327 =142
+ self._kinit('foo', 'test') #328
+ self._klist() #329 =144
+
+ self._get_princ_records() #330 =145-158
+
+ self._writeHeader("TEST: add_meky with DES-crc enctype")
+ #print "\nTesting add_mkey with DES-crc enctype ==============================================" #331
+ self._addmkey('abcde', '-e des-cbc-crc') #332-335 =159
+ self._listmkeys() #336 =160
+ self._writeLine( "END. Testing add_mkey with DES-crc enctype Done ==============================================") #337
+ self._addmkey('abcde') #338-341 =161
+ self._listmkeys() #342 =162
+ self._writeLine( "current time: "+strftime("%Y-%m-%d %H:%M:%S") ) #343
+
+ self._usemkey('5', 'now-1day') #344 =163
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#345
+ self._listmkeys() #346 =164
+ self._usemkey('5', 'now') #347 =165
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#348
+ self._listmkeys() #349 =166
+ self._usemkey('5', 'now+3days') #350 =167
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#351
+ self._listmkeys() #352 =168
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#353
+ self._usemkey('5', 'now+5sec') #354 =169
+ self._listmkeys() #355 =170
+ time.sleep(5) #356
+ self._listmkeys() #357 =171
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#358
+ self._usemkey('4', 'now+5sec') #359 =172
+ self._listmkeys() #360 =173
+ time.sleep(5) #361
+ self._listmkeys() #362 =174
+ self._usemkey('5', 'now+3days') #363 =175
+
+ self._writeLine("------------\n\/\/\/ ERROR EXPECTED below" )#364
+ self._writeLine("should fail, because there must be one mkey currently active") #365
+ self._usemkey('4', 'now+2days', False) #366 =176
+ self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n---------------")
+
+ self._listmkeys() #373 =177
+ self._usemkey('4', '1/30/2009') #375 =178
+
+ self._writeHeader("TEST: purge_mkeys (removing mkey 5)")
+ #print "\nTesting purge_mkeys (removing mkey 5) ==============================================" #378
+ self._purgemkeys() #379 =179
+ self._stash() #380 =180
+ self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/keyStashFile") #381 =181
+ self._listmkeys() #382 =182
+ self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc K/M'") #383 =183
+ self._writeLine("Testing purge_mkeys Done ==============================================") #384
+ self._writeHeader("MASTER KEY MIGRATION TEST DONE. please consult 'outfile' in your sandbox for more info. The sandbox is at: %s" % self.sandir)
+ # I added
+ self._sysexit(finished=True)
+
+####################################################
+####################################################
+
+class Launcher:
+ def __init__(self, path, sandP):
+ # srcdir, self._buildDir = InPath
+ self._buildDir = path
+ # self._confDir = InPath/tests/mk_migr/input_conf
+ self._confDir = '%s/tests/mk_migr/db2_backend/input_conf' % self._buildDir
+
+ # setting up sand box
+ if sandP != "":
+ self._sandboxDir = sandP
+ else:
+ self._sandboxDir = '%s/tests/mk_migr/db2_backend/sandbox' % self._buildDir
+
+ self._vars = {'srcdir': self._buildDir,
+ 'sandboxdir': self._sandboxDir,
+ 'localFQDN':socket.getfqdn()}
+
+ def _prepSandbox(self):
+ sandir = self._sandboxDir
+ if os.path.exists(sandir):
+ shutil.rmtree(sandir)
+ print "------about to make sandbox, with the path of:"
+ print sandir
+ os.makedirs(sandir, 0777)
+ print "------sandbox made"
+ return sandir
+
+ def _createFileFromTemplate(self, outpath, template, vars):
+ fin = open(template, 'r')
+ result = fin.read() % vars
+ fin.close()
+ fout = open(outpath, 'w')
+ fout.write(result)
+ fout.close()
+
+ ####### Launcher RUN ################
+ def runLauncher(self):
+ # create sandbox file directory if it does not exit
+ sandir = self._prepSandbox()
+ '''print os.environ
+ '''
+ #save the initial 3 things setup
+ orig_libpath = os.getenv('LD_LIBRARY_PATH')
+ orig_krbconf = os.getenv('KRB5_CONFIG')
+ orig_kdcprof = os.getenv('KRB5_KDC_PROFILE')
+
+ # change the 3 things
+ os.environ["LD_LIBRARY_PATH"] = '%s/lib' % self._buildDir
+ #os.environ["SRCDIR"] = '%s' % self._buildDir
+
+ str1 = '%s/krb5.conf' % self._sandboxDir
+ os.environ["KRB5_CONFIG"] = str1
+
+ str2 = '%s/kdc.conf' % self._sandboxDir
+ os.environ["KRB5_KDC_PROFILE"] = str2
+
+ str3 = '%s/kadm5.acl' % self._sandboxDir
+
+ # Create adequate to the environment config files
+ self._createFileFromTemplate('%s' % str1, '%s/%s' % (self._confDir, 'krb5_template_db2.conf'), self._vars)
+ self._createFileFromTemplate('%s' % str2, '%s/%s' % (self._confDir, 'kdc_template_db2.conf'), self._vars)
+ self._createFileFromTemplate('%s' % str3, '%s/%s' % (self._confDir, 'kadm5_template_db2.acl'), self._vars)
+
+ return sandir
+
+####################################################
+####################################################
+def makeBool(aStr):
+ if aStr == "True" or aStr == "T":
+ return True
+ if aStr == "False" or aStr == "F":
+ return False
+ else:
+ print "did NOT execute due to invalid True False argument. Please enter either 'True', 'T', 'False', or 'F'"
+ sys.exit()
+
+# # # # # # # # # # # # # # # # # # # # # # # # #
+
+def processInputs(parser):
+ # get inputs
+ (options, args) = parser.parse_args()
+
+ verbose = makeBool(options.opVerbose)
+ pw = options.opPassword
+
+ kdcPath = options.opKdcPath #1
+ kdmdPath = options.opKdmdPath #2
+ kdbPath = options.opKdbPath #3
+ kdmlPath = options.opKdmlPath #4
+ kdmPath = options.opKdmPath #5
+ cltPath = options.opCltPath #6
+
+ sandPath = options.opSandbox
+
+ ########### Launch ###############
+
+ print "\n############ Start Launcher #############"
+ src_path=os.environ["PWD"]
+ print "SOURCE PATH ==>" , src_path
+
+ myLaunch = Launcher(src_path, sandPath)
+ sandir = myLaunch.runLauncher()
+
+ test = MasterKeyMigrationTest(verbose, pw, kdcPath, kdmdPath, kdbPath, kdmlPath, kdmPath, cltPath, sandir)
+ print "########## Finished Launcher ############\n"
+
+ return test
+# # # # # # # # # # # # # # # # # # # # # # # # #
+
+def makeParser():
+ usage = "\n\t%prog [-v][-p][-c][-d][-b][-l][-t][-s]"
+ description = "Description:\n\tTests for the master key migration commands."
+ parser = OptionParser(usage=usage, description=description)
+
+ parser.add_option("-v", "--verbose", type="string", dest="opVerbose",
+default="True", help="'True' or 'False'. Switch on for details of command lines and outputs. Default is 'True'")
+
+ parser.add_option("-p", "--password", type="string", dest="opPassword", default="test123", help="master password for many of the passwords in the test. Default is 'test123'")
+
+ ## Default Paths
+ dSrcPath = src_path=os.environ["PWD"]
+ dKdcPath = '%s/kdc/krb5kdc' % dSrcPath #1
+ dKdmdPath = '%s/kadmin/server/kadmind' % dSrcPath #2
+ dKdbPath = '%s/kadmin/dbutil/kdb5_util' % dSrcPath #3
+ dKdmlPath = '%s/kadmin/cli/kadmin.local' % dSrcPath #4
+ dKdmPath = '%s/kadmin/cli/kadmin' % dSrcPath #5
+ dCltPath = '%s/clients' % dSrcPath #6
+
+ parser.add_option("-c", "--krb5kdcpath",
+type="string", dest="opKdcPath",
+default=dKdcPath, help="set krb5kdc path, default="+dKdcPath) #1
+
+ parser.add_option("-d", "--kadmindpath",
+type="string", dest="opKdmdPath",
+default=dKdmdPath, help="set kadmind path, default="+dKdmdPath) #2
+
+ parser.add_option("-b", "--kdb5_utilpath",
+type="string", dest="opKdbPath",
+default=dKdbPath, help="set kdb5_util path, default="+dKdbPath) #3
+
+ parser.add_option("-l", "--kadminlocalpath",
+type="string", dest="opKdmlPath",
+default=dKdmlPath, help="set kadmin.local path, default="+dKdmlPath) #4
+
+ parser.add_option("-n", "--kadminpath",
+type="string", dest="opKdmPath",
+default=dKdmPath, help="set kadmin path, default="+dKdmPath) #5
+
+ parser.add_option("-t", "--clientspath",
+type="string", dest="opCltPath",
+default=dCltPath, help="set clients path, default="+dCltPath) #6
+
+ # set up / initializing stuff for the sandbox
+ parser.add_option("-s", "--sandbox",
+type="string", dest="opSandbox",
+default="",
+help="path for the sandbox. Default is '%s/tests/mk_migr/db2_backend/sandbox' % "+dSrcPath)
+
+ return parser
+
+####################################################
+if __name__ == '__main__':
+ parser = makeParser()
+ test = processInputs(parser)
+ result = test.run()
--- /dev/null
+##############################################################################
+###################### WARNING: DOES NOT WORK YET ############################
+##############################################################################
+
+ABOUT:
+A translation of Will Fiveash's "mit_db2_mkey_migrate_testB" ksh code into Python with ldap backend. With minor fixes and changes. Written by HaoQi Li.
+
+DEFAULT SETTINGS:
+Options Name Default Setting
+ -h Help
+ -v Verbose: True
+ -p Testing pw: test123
+ -s Sandbox loc: src/tests/kdc_realm2/sandbox
+ -c Krb5kdc: src/kdc/krb5kdc
+ -d Kadmind: src/kadmin/server/kadmind
+ -b Kdb5_util: src/kadmin/dbutil/kdb5_util
+ -a Kdb5_ldap_util: src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util
+ -l Kadmin.local: src/kadmin/cli/kadmin.local
+ -n Kadmin: src/kadmin/cli/kadmin
+ -t Client paths: src/clients
+
+INPUTS:
+* src/tests/mk_migr/ldap_backend/input_conf/kdc_template_ldap.conf
+* src/tests/mk_migr/ldap_backend/input_conf/krb5_template_ldap.conf
+* src/tests/mk_migr/ldap_backend/input_conf/kadm5_template_ldap.acl
+* src/tests/mk_migr/ldap_backend/input_conf/debconfile
+
+OUTPUTS:
+* sandbox that contains customized outfile with all commands and their outputs, kdc.conf, krb5.conf, kadm6.acl, and others.
+* Statistics on screen of number of commands passed and failed (if not interrupted by fatal failures).
+
+EXAMPLES:
+- MUST RUN from trunk/src.
+* python tests/mk_migr/ldap_backend/ldap7.py
+ Using all Default Settings.
+* python tests/mk_migr/ldap_backend/ldap7.py -s /tmp/mySandbox
+ Sandbox now can be found in /tmp/mySandbox.
+
+REFERENCE:
+http://k5wiki.kerberos.org/wiki/LDAP_on_Kerberos
+and http://k5wiki.kerberos.org/wiki/User_talk:Haoqili
+
+NOTES:
+* "haoqili" is a name that can be changed.
+* "kdb5_util stash" is equivalent to "-s" in "kdb5_ldap_util create -s"
+* 2019 and 2029 are future dates that should best be written not as fixed. Such as now+10years.
+
+FAILURES:
+
+* failure in kpasswd all, ERROR:"password history principal key version mismatch while trying to change password." This is caused by "-history 3" in testpolicy4
+
+* The beginning of a series of failures starts from: the "kdb5_util list_mkeys" fails after "kdb5_util add_mkey -e aes128-cts-hmac-sha1-96 [with password=abcde]"
+ERROR:-------------------------------------
+kdb5_util: Unable to decrypt latest master key with the provided master key
+while getting master key list
+kdb5_util: Warning: proceeding without master key list
+kdb5_util: master keylist not initialized
+can't decrypt the latest master key
+--------------------------------------------
+Convo with Tom:
+T: so you didn't activate the new mkey?
+H: correct i just added it
+T: the message looks familiar. does list_mkeys work before you do that add_mkey?
+H: yes it does
+T: Will might have mentioned some problems with the LDAP backend and the master key migration stuff.
+T: how up-to-date is your source tree? Will says he remembers fixing this.
+H: i'm at revision 22523
+T: hm, i think that should be recent enough.
+T: do you have any enctype settings in your config files?
+H: in krb5.conf
+[libdefaults]
+default_realm = EXAMPLE.ORG
+default_tkt_enctypes = des3-hmac-sha1 aes128-cts
+default_tgs_enctypes = des3-hmac-sha1 aes128-cts
+T: anything for supported_enctypes or master_key_type?
+H: no
+
--- /dev/null
+slapd slapd/no_configuration boolean false
+slapd slapd/domain string example.org
+slapd shared/organization string My Organization
+slapd slapd/backend select HDB
+slapd slapd/purge_database boolean true
+slapd slapd/move_old_database boolean true
+slapd slapd/password1 password a
+slapd slapd/password2 password a
+slapd slapd/allow_ldap_v2 boolean false
--- /dev/null
+[kdcdefaults]
+ kdc_ports = 8888
+
+[realms]
+ EXAMPLE.ORG = {
+ database_name = %(sandir)s/krb5kdc/principal
+ acl_file = %(sandir)s/kadm5.acl
+ key_stash_file = %(sandir)s/krb5kdc/.k5.EXAMPLE.ORG
+ admin_keytab = FILE:%(sandir)s/krb5kdc/kadm5.keytab
+ kdc_ports = 8888
+ kpasswd_port = 8887
+ kadmind_port = 8886
+ max_life = 10h 0m 0s
+ max_renewable_life = 7d 0h 0m 0s
+ }
+[logging]
+ kdc = FILE:/tmp/myrealKDC.log
--- /dev/null
+[libdefaults]
+ default_realm = EXAMPLE.ORG
+ default_tkt_enctypes = des3-hmac-sha1 aes128-cts
+ default_tgs_enctypes = des3-hmac-sha1 aes128-cts
+
+[realms]
+ EXAMPLE.ORG = {
+ admin_server = %(localFQDN)s:8886
+ kpasswd_server = %(localFQDN)s:8887
+ #default_domain = EXAMPLE.ORG
+ kdc = %(localFQDN)s:8888
+ database_module = LDAP
+ }
+
+[dbdefaults]
+ ldap_kerberos_container_dn = "cn=krbContainer,dc=example,dc=org"
+
+[dbmodules]
+ LDAP = {
+ db_library = kldap
+ ldap_kerberos_container_dn = "cn=krbContainer,dc=example,dc=org"
+ ldap_kdc_dn = cn=admin,dc=example,dc=org
+ ldap_kadmind_dn = cn=admin,dc=example,dc=org
+ ldap_service_password_file = %(sandir)s/krb5kdc/admin.stash
+ ldap_servers = ldapi:///
+ }
+[domain_realm]
+
+[logging]
+ kdc = FILE:/tmp/kdc_fromkrb.log
+ default = FILE:/tmp/krb5.log
+ admin_server = FILE:/tmp/admin.log
+
--- /dev/null
+##############################################################################
+###################### WARNING: DOES NOT WORK YET ############################
+##############################################################################
+
+import os, sys, shutil, socket, time, string
+from subprocess import Popen, PIPE
+from optparse import OptionParser
+from time import strftime
+
+class LDAPbackendSetup:
+ def __init__(self, verbose_in, pw_in, kdcPath_in, kdmdPath_in, kdbPath_in, ldapPath_in, kdmlPath_in, kdmPath_in, cltPath_in, sandir_in, confdir_in):
+ self.npass = 0
+
+ self.nfail = 0
+
+ self.verbose = verbose_in
+ self.pw = pw_in
+
+ self.krb5kdc = kdcPath_in #1 krb5kdc
+ self.kadmind = kdmdPath_in #2 kadmind
+ self.kdb5_util = kdbPath_in #3a kdb5_util
+ self.kdb5_ldap_util = ldapPath_in #3b kdb5_ldap_util
+ self.kadminlocal = kdmlPath_in #4 kadmin.local
+ self.kadmin = kdmPath_in #5 kadmin
+ self.clients = cltPath_in+"/" #6 clients
+
+ self.sandir = sandir_in
+ self.confdir = confdir_in
+
+ ########## SET UP Write Output File #####
+ print "outfile path"
+ print self.sandir
+ print self.sandir+"/outfile"
+
+ self.outfile = open(self.sandir+"/outfile", 'w')
+
+ #''print os.environ'
+
+ def _writeLine(self, astr, prt=False):
+ self.outfile.write(astr.strip()+"\n")
+ if prt:
+ print astr.strip()
+
+ def _writeHeader(self, astr, prt=True):
+ self.outfile.write("\n========== "+astr.strip()+" ==========\n")
+ if prt:
+ print "========== "+astr.strip()+" =========="
+
+ def _sysexit(self, fatal=False, finished=False):
+ self._writeLine("++++++++++++++++++++++++++++++", True)
+ if fatal:
+ self._writeLine("++++ Test did NOT finish +++++", True)
+ self._writeLine("++++ FATAL FAILURE! Stopped ++", True)
+ self._writeLine("++++ See sandbox/outfile +++++", True)
+ self._writeLine("++++++++++++++++++++++++++++++", True)
+ sys.exit()
+ elif not finished:
+ self._writeLine("++++ Test did NOT finish +++++", True)
+ self._writeLine("++++ FAIL Detected! keep going", True)
+ self._writeLine("++++++++++++++++++++++++++++++", True)
+ else: #finished
+ self._writeLine("++++ MKM Test Finished +++++++", True)
+ self._writeLine("++++++++++++++++++++++++++++++", True)
+ self._writeLine("++++ Commands Passed: %s +++++" % self.npass, True)
+ self._writeLine("++++ Commands Failed: %s +++++" % self.nfail, True)
+ sys.exit()
+
+ def _printig(self):
+ self._writeLine("~.~.~Error should be ignored~.~.~.~")
+
+ def _printerr(self, errm, stderr):
+ self._writeLine("#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#")
+ self._writeLine("-XX-FAILED: "+errm+". See stderr below:")
+ [self._writeLine(line) for line in stderr.readlines() ]
+
+ def _printout(self, cmd, pstdout):
+ if self.verbose:
+ self._writeLine("#######################################")
+ #self._writeLine("---------------------------------------")
+ self._writeLine("-command: "+cmd)
+ self._writeLine("-----out: ")
+ [self._writeLine(line) for line in pstdout.readlines()]
+
+ def _eval(self, succeed, pwait, errm, pstderr, fatal=False, msg2="", finished=False):
+ if int(pwait) != 0: # is bad
+ self._printerr(errm, pstderr)
+ if succeed==True: ## want good
+ self.nfail += 1
+ self._sysexit(fatal, finished)
+ else: ## want bad
+ self.npass += 1
+ self._printig()
+ else: # is good
+ if not succeed: ## want bad
+ if msg2 != "":
+ self._writeLine(msg2, True)
+ self.nfail += 1
+ self._sysexit(fatal, finished)
+ else: ## want good
+ self.npass += 1
+
+ def _metafunc(self, command, errmsg, moreinfo="", isLocal=False, succeed=True, fatal=False):
+ l = command
+ if isLocal:
+ pl = Popen(l.split(None,2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ else:
+ pl = Popen(l.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ self._printout(l+moreinfo, pl.stdout)
+
+ self._eval(succeed, pl.wait(), errmsg, pl.stderr, fatal)
+
+ ###########################################
+
+ # Start the KDC daemons
+ def _startkdc(self):
+ self._writeLine("\nstarting kdc daemons ...")
+ l0 = self.krb5kdc
+ errm = "error at starting krb5kdc"
+ self._metafunc(l0, errm)
+ # below has been changed
+
+ #starting kadmind
+ l0b = self.kadmind + ' -W -nofork' #the W is for during off strong random numbers
+ errm = "error at starting kadmind, maybe it's already started"
+ pl0b = Popen(l0b.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ self._writeLine( "kadmind -nofork")
+ started = False
+ while time.clock() < 3:
+ l = pl0b.stderr.readline()
+ if l.find("starting") > -1:
+ self._writeLine( l.strip())
+ self.npass += 1
+ started = True
+ break
+ else:
+ self.nfail += 1
+ self._printerr("kadmind not starting, check to see if there are any previous kadmind running with cmd: 'ps -ef | grep kadmind' and then do 'sudo kill -9 [# on the left]'", pl0b.stderr)
+ self._sysexit(fatal=True)
+ if not started:
+ self.nfail += 1
+ self._sysexit()
+ self._writeLine("end starting kdc daemons")
+
+ # Kill the KDC daemons in case they are running
+ def _killkdc(self, suc=True):
+ l1 = 'pkill -9 -x krb5kdc'
+ errm = "no krb5kdc killed"
+ self._metafunc(l1, errm, succeed=suc)
+ l2 = 'pkill -9 -x kadmind'
+ errm = "no kadmind killed"
+ self._metafunc(l2, errm, succeed=suc)
+
+ # Destroys current database
+ def _destroykdc(self, suc=True):
+ l3 = self.kdb5_util+' destroy -f' #forced
+ errm = "no kdb database destroyed"
+ self._metafunc(l3, errm, succeed=suc)
+
+ ''' Destroys current database
+ I don't use this because 1. I don't know the specific kdc's to destroy, 2. the debconf setting up of slapd has destroyed old databases already
+ def _destroykdc_ldap(self, suc=True):
+ l3 = self.kdb5_ldap_util+' destroy -f' #forced
+ errm = "no kdb database destroyed"
+ self._metafunc(l3, errm, succeed=suc)
+ '''
+
+ # Create a new database with a new master key
+ def _createdb(self, pw):
+ l4 = self.kdb5_util+' -P '+pw+' create -s -W' #added W for svn version 22435 to avoid reading strong random numbers
+ errm = "error when creating new database, _createdb()"
+ self._metafunc(l4, errm, fatal=True)
+
+ # Addprinc
+ def _locAddprinc(self, passw, usern):
+ l5 = self.kadminlocal+' -q addprinc -pw '+passw+' '+usern
+ errm = "error when adding princ, _locAddprinc"
+ self._metafunc(l5, errm, isLocal=True)
+
+ # List princs
+ def _locListprincs(self):
+ l6 = self.kadminlocal+' -q listprincs'
+ errm = "error when listing princs, _locListprincs"
+ self._metafunc(l6, errm, isLocal=True)
+
+ # Get princs
+ def _locGetprinc(self, usern, extra=False, succeed=True):
+ l7 = self.kadminlocal+' -q getprinc '+usern
+ errm="error when getting princ, _locGetprinc"
+
+ pl7 = Popen(l7.split(None,2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ if not extra:
+ self._printout(l7, pl7.stdout)
+ else:
+ if self.verbose:
+ self._writeLine("-command: "+l7)
+ self._writeLine("-----out: ")
+ for line in pl7.stdout.readlines():
+ if line.startswith("Princ") or line.startswith("MKey"):
+ self._writeLine(line)
+ self._eval(succeed, pl7.wait(), errm, pl7.stderr)
+
+ # Get princs and finds something in the output
+ def _locGetprincFind(self, usern, findstr, succeed=True):
+ l7b = self.kadminlocal+' -q getprinc ' +usern
+ errm="error when getting princs, _locGetprinc, (regular output of getprincs is not printed here), will NOT continue to find string="+findstr
+ pl7b = Popen(l7b.split(None, 2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ if self.verbose:
+ self._writeLine("-command: "+l7b)
+ if int(pl7b.wait()) != 0: # is bad
+ self._printerr(errm, pl7b.stderr)
+ if succeed: ## want good
+ self.nfail += 1
+ self._sysexit()
+ else: ## want bad
+ self.npass += 1
+ self._printig()
+ else: # is good
+ if self.verbose:
+ self._writeLine( "-----out: ")
+ boofound = False
+ for outl in pl7b.stdout.readlines():
+ self._writeLine(outl)
+ if string.find(outl, findstr) > -1:
+ boofound = True
+ if boofound:
+ self._writeLine("----FOUND: "+findstr)
+ else:
+ self._writeLine("----NOT FOUND: "+findstr)
+ if not succeed: ## want bad
+ self.nfail += 1
+ self._sysexit()
+ else: ## want good
+ self.npass += 1
+
+ # Add policy
+ def _locAddpol(self, maxtime, minlength, minclasses, history, policyname):
+ rest = ""
+ if maxtime != None:
+ rest += '-maxlife '+maxtime+' '
+ if minlength != None:
+ rest += '-minlength '+minlength+' '
+ if minclasses != None:
+ rest += '-minclasses '+minclasses+' '
+ if history != None:
+ rest += '-history '+history+' '
+ l8 = self.kadminlocal+' -q add_policy '+rest+policyname
+ errm = "error when adding policy, _locAddpol"
+ self._metafunc(l8, errm, isLocal=True)
+
+ # Get pol
+ def _locGetpol(self, poln):
+ l8b = self.kadminlocal+' -q getpol '+poln
+ errm="error when getting pol, _locGetpol"
+ self._metafunc(l8b, errm, isLocal=True)
+
+ # Modify Principal
+ def _locModprinc(self, rest):
+ l9 = self.kadminlocal+' -q modprinc '+rest
+ errm = "error when modifing principal, _locModprinc"
+ self._metafunc(l9, errm, isLocal=True)
+
+ # List mkeys
+ def _listmkeys(self):
+ l10 = self.kdb5_util+' list_mkeys'
+ errm = "error when listing mkeys, _listmkeys"
+ self._metafunc(l10, errm)
+
+ # Use mkeys
+ def _usemkey(self, kvno, time, succeed=True):
+ l11 = self.kdb5_util+' use_mkey '+kvno+' '+time
+ pl11 = Popen(l11.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ self._printout(l11, pl11.stdout)
+ self._eval(succeed, pl11.wait(), "error when using mkeys, _usemkey", pl11.stderr, msg2="-XX-ERROR: "+l11+" should have failed.")
+
+
+ # Change password (cpw)
+ def _locCpw(self, passw, usern):
+ l12 = self.kadminlocal+' -q cpw -pw '+passw+' '+usern
+ errm = "error when changing password, _locCpw"
+ self._metafunc(l12, errm, moreinfo="\n--------: newpw='"+passw+"'", isLocal=True)
+
+ # Purge mkeys
+ def _purgemkeys(self):
+ l13 = self.kdb5_util+' purge_mkeys -f -v' #-f is forced, -v is verbose
+ errm = "error when purging mkeys, _purgemkeys"
+ self._metafunc(l13, errm)
+
+ # Add mkey
+ def _addmkey(self, passw, extra="", succeed=True):
+ l14 = self.kdb5_util+' add_mkey '+extra
+ pl14 = Popen(l14.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ pl14.stdin.write(passw+'\n') #enter 1st time
+ pl14.stdin.write(passw+'\n') #re-enter
+ self._printout(l14+' [with password='+passw+']', pl14.stdout)
+ self._eval(succeed, pl14.wait(), "error when adding mkey, _addmkey", pl14.stderr)
+ self._writeLine( "----end of adding mkey")
+
+ # kinit user
+ def _kinit(self, passw_in, usern, succeed=True):
+ l15 = self.clients+'kinit/kinit '+usern
+ pl15 = Popen(l15.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ pl15.stdin.write(passw_in+'\n')
+ pl15.stdin.close()
+ self._printout(l15, pl15.stdout)
+ self._eval(succeed, pl15.wait(), "error when kinit user, _kinit", pl15.stderr)
+ self._writeLine( "----end of kiniting user")
+
+ # change password on client's side
+ def _kpasswd(self, oldpw, newpw, usern, succeed=True):
+ l16 = self.clients+'kpasswd/kpasswd '+usern
+ pl16 = Popen(l16.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ pl16.stdin.write(oldpw+'\n')
+ pl16.stdin.write(newpw+'\n')
+ pl16.stdin.write(newpw+'\n')
+ self._printout(l16+"\n--------: oldpw='"+oldpw+"' -> newpw='"+newpw+"'", pl16.stdout)
+ self._eval(succeed, pl16.wait(), "error when changing password on client's side, _kpasswd", pl16.stderr)
+ self._writeLine("----end of changing kpasswd")
+
+ # klist on client's side
+ def _klist(self):
+ l17 = self.clients+'klist/klist'
+ errm = "error when klist, _klist"
+ self._metafunc(l17, errm)
+
+ # Update principal encryption
+ def _updatePrincEnc(self):
+ l18 = self.kdb5_util+' update_princ_encryption -f -v'
+ errm = "error when updating principal encryption, _updatePrincEnc"
+ self._metafunc(l18, errm)
+
+ # kdestroy
+ def _kdestroy(self):
+ l19 = self.clients+'kdestroy/kdestroy'
+ errm = "error when kdestroy, _kdestroy"
+ self._metafunc(l19, errm)
+
+ # stash
+ def _stash(self):
+ l20 = self.kdb5_util+' stash'
+ errm="error at stash, _stash"
+ self._metafunc(l20, errm)
+
+ # any shell command
+ def _shell(self, command, succeed=True):
+ l21 = command
+ errm="error at executing this command in _shell(): "+l21
+ pl21 = Popen(l21, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ self._printout(l21, pl21.stdout)
+ self._eval(succeed, pl21.wait(), errm, pl21.stderr)
+ #'self._printerr(errm, pl21.stderr) Pointed out that kadmin had problems!'
+
+
+ def _shelltest(self, command, succeed=True):
+ l21 = command
+ errm="error at executing this command in _shell(): "+l21
+ pl21 = Popen(l21, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ first = pl21.communicate('a\na')[0]
+ print "first:"
+ print first
+ print "end first"
+
+ #self._printout(l21, pl21.stdout) self._printout(l21, first)
+ self._eval(succeed, pl21.wait(), errm, pl21.stderr)
+ #self._printerr(errm, pl21.stderr) #Pointed out that kadmin had problems!'
+
+
+ # get_princ_records()
+ def _get_princ_records(self, succeed=True):
+ l22 = self.kadminlocal+" -q listprincs 2>/dev/null|grep -v '^Authenticating as'|fgrep '@'|sort"
+ errm="error at listprincs in _get_princ_records() with this command: "+l22
+ pl22 = Popen(l22, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ if int(pl22.wait()) != 0: # is bad
+ self.printerr(errm, pl22.stderr)
+ if succeed: ## want good
+ self.nfail += 1
+ self._sysexit()
+ else: ## want badd
+ self.npass += 1
+ self._printig()
+ else: # is good
+ if not succeed: ## want bad
+ self.nfail += 1
+ self._sysexit()
+ else: ## want good
+ self.npass += 1
+ self._writeLine( "\nget_princ_records() executing all listprincs command: "+l22+"\n------its results:")
+ for princ in pl22.stdout.readlines():
+ self._locGetprinc(princ.strip(), extra=True)
+ self._writeLine("END executing command: "+l22+"\n~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~")
+
+######################################################
+ def run(self):
+ #############RUN###################
+ passw=self.pw
+
+ self._writeHeader("START MASTER KEY MIGRATION TEST")
+
+ # Set up database
+ self._writeHeader("SET UP: database")
+ self._killkdc("Either") #74 =1,2
+ #self._destroykdc("Either") #77 =3
+ #self._destroykdc_ldap("Either") #77 =3
+
+ self._shell('sudo cat '+self.confdir+'/debconfile')
+ self._shell('sudo debconf-set-selections '+self.confdir+'/debconfile')
+ self._shell('sudo dpkg-reconfigure --frontend=noninteractive slapd')
+ self._shell('sudo ldapadd -x -D cn=admin,cn=config -w a -f /tmp/ldif_output/cn\=config/cn\=schema/cn\=\{6\}kerberos.ldif -H ldapi:///')
+ self._shell('kdb5_ldap_util -D cn=admin,dc=example,dc=org -w a -H ldapi:/// create -P a -s') #self._createdb(passw) #81 =4
+ self._shelltest('kdb5_ldap_util -D cn=admin,dc=example,dc=org -w a -H ldapi:/// stashsrvpw cn=admin,dc=example,dc=org')
+ #self._shell('krb5kdc') ## MUST KILL krb5kdc before first!
+ self._writeHeader("+++++ START +++++")
+
+ #line 83-86 involves ktadd kadm5.keytab, which are out dated
+
+ # add, get, and list princs
+ self._writeHeader("SET UP: add/get/list princs")
+ self._locAddprinc(passw, 'kdc/admin') #87 =5
+ self._locListprincs() #89 =6
+ self._locGetprinc('K/M') #90 =7
+ self._locAddprinc('test123', 'haoqili') #91 =8
+ self._locGetprinc('haoqili') #92 =9
+ self._locAddprinc(passw, 'haoqili/admin') #93 =10
+ self._locAddprinc('foobar', 'test') #94 =11
+ self._locGetprinc('test') #95 =12
+ self._locListprincs() # I added =13
+ myfqdn = socket.getfqdn()
+ #self._shell(self.parentpath+"kadmin.local -q 'addprinc -randkey host/"+myfqdn+"'") #96
+ self._shell(self.kadminlocal+" -q 'addprinc -randkey host/"+myfqdn+"'") #96 =14
+
+ # create policies
+ self._writeHeader("SET UP: create policies")
+
+ #print "\n~~~~~~~~~ create policies ~~~~~~~~~~~"
+ self._locAddpol('8days', None, None, None, 'testpolicy')#100 =15
+ self._locAddpol('20days', '8', '3', None, 'testpolicy2')#101
+ self._locAddpol('90days', '2', '2', None, 'testpolicy3')#102
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ #!!!!!!!!!Changed to avoid problem in 'kpasswd all'!!!!!!!!!!!!!!!!!!!!
+ #self._locAddpol('90days', '2', '2', '3', 'testpolicy4')#103
+ self._locAddpol('90days', '2', '2', None, 'testpolicy4')#103
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ self._locModprinc('-policy testpolicy haoqili')#105
+ self._locAddprinc(passw, 'foo')#106
+ self._locModprinc('-policy testpolicy3 foo')#107 =21
+
+ # create all princ with all fields
+ self._writeHeader("SET UP: create all princ with all fields")
+ #print "\n~~~~~~~~~ create all princ with all fields ~~~~~"
+ self._locAddprinc(passw, 'all') #110 =22
+ self._locModprinc('-expire "2029-12-30 7pm" all') #112
+ self._locModprinc('-pwexpire 12/30/2029 all') #114
+ #self._locModprinc('-expire "now+10years" all') #112
+ #self._locModprinc('-pwexpire now+10years all') #114
+ self._locGetprinc('all') #115
+ self._locModprinc('-maxlife 100days all') #116
+ self._locGetprinc('all') #117
+ self._locModprinc('-maxrenewlife 100days all') #118
+ self._locGetprinc('all') #119
+ self._locModprinc('+allow_postdated +allow_forwardable all') #120 =30
+ self._locModprinc('+allow_proxiable +allow_dup_skey all') #121
+ self._locModprinc('+requires_preauth +allow_svr +needchange all') #122
+ self._locModprinc('-policy testpolicy4 all') #123 ###########
+ self._locGetprinc('all') #124 =34
+
+ # Testing stuff
+ self._writeHeader("TEST: initial mkey list") #126
+ self._writeLine("===== Listing mkeys at start of test") #I add
+ self._listmkeys() #127 =35
+
+ self._writeLine( "Testing krb5kdc list_mkeys Done ==============================================") #128
+
+ self._writeLine("---------------\n xxxxxxxxxx \/\/\/ ERRORS (multiple) EXPECTED below xxxxxxxxxx")
+ self._writeLine("\nERRORS (multiple) EXPECTED below")
+ self._writeLine("Testing bogus use_mkey (setting only mkey to future date, using non-existent kvno, so should return error) =======") #129, 130
+ self._writeLine( "-> must have a mkey currently active (setting mkey to 2 days from now), should fail and return error") #132
+ self._usemkey('1', 'now+2days', False) #133-138 =36
+
+ self._writeLine("-> must have a mkey currently active (setting mkey to 2019 the future), should fail and return error") #140
+ self._usemkey('1', '5/30/2019', False) #141 =37
+ self._writeLine("-> bogus kvno and setting mkey to 2 days from now, should fail and return error") #147
+ self._usemkey('2', 'now+2days', False) #148 =38
+ self._writeLine("-> bogus kvno, should fail and return error") #I add
+ self._usemkey('2', 'now-2days', False) #I add =39
+ self._writeLine( "^^^ABOVE^^ SHOULD HAVE *ALL* FAILED\n-----------------")
+
+ self._writeLine( "Listing mkeys at end of test") #I add
+ self._listmkeys() #155 =40
+ self._writeLine("Testing bogus use_mkey (setting only mkey to future date) Done ===========================") #156
+
+
+ self._writeLine("\nmake sure cpw [change password] works") #158
+ # this changes the password of 'test' from 'foobar' in "add, get, and list princs" above
+ self._locCpw('test1', 'test') #159 =41
+
+ self._writeHeader("TEST: bogus purge_mkeys (should be no keys purged, no error returned")
+ #print "\nTesting bogus purge_mkeys (should be no keys purged, no error returned) ===========================" #161
+ self._purgemkeys() #162 =42
+ self._writeLine("Testing bogus purge_mkeys (no error) Done ===========================") #163
+
+ self._writeHeader( "add kvno 2") #164
+
+ self._addmkey('abcde', '-s') #165-167 =43
+ self._writeLine(".\nlist mkeys")
+ self._listmkeys() #169 =44
+
+ #start daemons
+ #@@@@@@@@@@@@@@@@@@@@@@@@@@@############@@@@@@@@@@@@@@@@@@############
+ self._startkdc() #172 =45 46
+ self._writeLine("make sure kdc is up, by kinit test") #176
+ self._kinit('test1', 'test') #177 =47
+
+ self._writeLine("---------------\n\/\/\/ ERROR EXPECTED below. Test passwd policy.:") #180
+ self._kinit(passw, 'all', succeed=False) #181 =48
+ self._writeLine("^^ABOVE^^ SHOULD HAVE FAILED\n-----------------")
+
+ #change passwd on client's side
+
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ self._kpasswd(passw, 'Test123.', 'all')#184-188 =49 !!!!!!!!!!!!!!!!
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ self._kinit('Test123.', 'all') #189 =50
+ self._klist() #190 =51
+
+ self._writeHeader("TEST: password history for principal 'all', new passwords must not be a previous password") #191
+ self._kpasswd('Test123.', 'Foobar2!', 'all') #192-195 =52
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ '''
+ self._writeLine("--------------\n\/\/\/ ERROR EXPECTED below") #197
+ self._kpasswd('Foobar2!', passw, 'all', succeed=False) #199-202 =53
+ self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n----------")
+ '''
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ # this shouldn't change the mkvno for any princs (should be 1) #206
+ #self._updatePrincEnc() #207
+ # princs should still be protected by mkvno 1 #208
+ self._writeLine("@@@@@@@@ Wait for other people to fix bug in code 6507 update_princ_encryption to use mkey instead of latest mkey @@@@@@@@@@@@@\n")
+ self._locGetprincFind('test', 'MKey: vno 1') #209 =54
+
+ self._purgemkeys() #210 =55
+ self._listmkeys() #211 =56
+ self._usemkey('2', 'now-1day') #213 =57
+ self._listmkeys() #214 =58
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ '''
+ self._writeLine("-----------\n\/\/\/ ERROR EXPECTED below") #216
+ self._kpasswd('Foobar2!', passw, 'all', succeed=False) #217-221 =59
+ self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n--------")
+ '''
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ self._kpasswd('Foobar2!', 'Barfoo3.', 'all') #224-228 =60
+ self._kinit('Barfoo3.', 'all') #229
+ self._klist() #230 =62
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ '''
+ self._writeLine("-------------\n\/\/\/ ERROR EXPECTED below") #231
+ self._kpasswd('Barfoo3.', 'Foobar2!', 'all',succeed=False) #233-235 =63
+ self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n---------")
+ '''
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ self._writeLine("\nTest's key should be protected by mkvno 2" ) #239
+ self._locCpw('foo', 'test') #240 =64
+ self._locGetprincFind('test', 'MKey: vno 2') #241 =65
+ self._kdestroy() #242 =66
+
+ self._writeHeader("TEST: krb5kdc refetch of mkey")#243
+ self._kinit('foo', 'test') #244 =67
+ self._klist() #245 =68
+ self._writeLine("END. Testing krb5kdc refetch of mkey list Done ==============================================\n") #246
+
+ self._updatePrincEnc() #247 =69
+ self._get_princ_records() #248 =70 -83
+ self._kdestroy() #249 =84
+ self._kinit('foo', 'test') #250 =85
+ self._purgemkeys() #252 =86
+
+ #self._stash() #254 =87 #!!! Not necessary in ldap, done by 'create -s'
+ self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/krb5kdc/.k5.EXAMPLE.ORG") #255=88
+
+ self._locGetprinc('K/M') #256 =89
+ self._purgemkeys() #257 =90
+ self._locGetprinc('K/M') #258
+ self._listmkeys() #259 =92
+ self._kdestroy() #260
+ self._kinit('foo', 'test') #261
+ self._klist() #262 =95
+
+ self._writeLine("\n Adding in Master Key Number 3")
+ self._listmkeys() #265 =96
+ self._addmkey('abcde') #266-268
+ self._listmkeys() #270 =98
+ self._locCpw('foo', 'all') #271
+ self._locGetprinc('all') #272 =100
+ self._usemkey('3', 'now') #273
+ self._listmkeys() #274 =102
+ self._locCpw('99acefghI0!', 'all') #275
+ self._locGetprinc('all') #276 =104
+ self._kdestroy() #277
+ self._kinit('foo', 'test') #279 =106
+ self._klist() #280
+ self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'listprincs'") #281 =108
+ self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'getprinc test'") #282 =109
+
+ self._writeHeader("TEST: add_mkey with aes128 enctype") #283
+ self._addmkey('abcde', '-e aes128-cts-hmac-sha1-96') #284-287 =110
+ #!!!!!!!!!!!!!!!!Start to have problems !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ self._listmkeys() #288 =111
+ '''$ kdb5_util list_mkeys
+kdb5_util: Unable to decrypt latest master key with the provided master key
+ while getting master key list
+kdb5_util: Warning: proceeding without master key list
+kdb5_util: master keylist not initialized'''#!!!!!!!!!!!!!!!!!!!!!!!
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ self._writeLine( "END. Testing add_mkey with aes128 enctype done ==============================================")#289
+ self._writeHeader("TEST: krb5kdc refetch of mkey list")
+ #!!!!!!!!!!!!!!\/ errors \/ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ self._usemkey('4', 'now') #290 =112
+ self._listmkeys() #291 =113
+ #!!!!!!!!!!!!!!/\ errors /\ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'cpw -pw abcde test'") #292 =114
+ self._shell(self.kadmin +" -p haoqili/admin -w "+passw+" -q 'getprinc test'") #293
+
+ self._kdestroy() #294 =116
+
+ self._writeLine("\nTesting krb5kdc refetch of mkey list =================================================") #295
+ self._kinit('abcde', 'test') #296 =117
+ self._klist() #297 =118
+ self._writeLine("Testing krb5kdc refetch of mkey list Done :) =================================================\n") #298
+
+ self._killkdc() #300 =119, 120
+ self._startkdc() #301 =121 122
+
+ # The lines below are commented out because krb5kdc could not be restarted. For their error messages, see the outfile
+ '''
+ kdc.log:
+ Aug 31 12:21:23 reach-my-dream krb5kdc[24273](info): AS_REQ (2 etypes {16 17}) 127.0.1.1: ISSUE: authtime 1251746483, etypes {rep=16 tkt=18 ses=16}, test@EXAMPLE.ORG for krbtgt/EXAMPLE.ORG@EXAMPLE.ORG
+krb5kdc: Unable to decrypt latest master key with the provided master key
+ - while fetching master keys list for realm EXAMPLE.ORG
+ '''
+ '''
+ self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'cpw -pw foo test'") #304 =123
+ self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc test'") #305 =124
+ self._kdestroy() #307 =125
+
+ self._writeLine("\nTesting krb5kdc refetch of mkey list =================================================") #308
+ self._kinit('foo', 'test') #309 =126
+ self._klist() #310 =127
+ self._writeLine("Testing krb5kdc refetch of mkey list Done =================================================\n") #311
+
+ self._updatePrincEnc() #313 =128
+ self._locGetprinc('K/M') #314
+ self._locGetprinc('all') #315 =130
+ self._locGetprinc('haoqili') #316
+ self._kdestroy() #317 =132
+ self._kinit('foo', 'test') #318
+ self._stash() #319 =134
+ self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/krb5kdc/.k5.EXAMPLE.ORG") #320
+ self._locGetprinc('K/M') #321 =136
+ self._purgemkeys() #322
+ self._locGetprinc('K/M') #323 =138
+ self._locGetprinc('all') #324
+ self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc test'") #325 =140
+ self._listmkeys() #326
+ self._kdestroy() #327 =142
+ self._kinit('foo', 'test') #328
+ self._klist() #329 =144
+
+ self._get_princ_records() #330 =145-158
+
+ self._writeHeader("TEST: add_meky with DES-crc enctype")
+ #print "\nTesting add_mkey with DES-crc enctype ==============================================" #331
+ self._addmkey('abcde', '-e des-cbc-crc') #332-335 =159
+ self._listmkeys() #336 =160
+ self._writeLine( "END. Testing add_mkey with DES-crc enctype Done ==============================================") #337
+ self._addmkey('abcde') #338-341 =161
+ self._listmkeys() #342 =162
+ self._writeLine( "current time: "+strftime("%Y-%m-%d %H:%M:%S") ) #343
+
+ self._usemkey('5', 'now-1day') #344 =163
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#345
+ self._listmkeys() #346 =164
+ self._usemkey('5', 'now') #347 =165
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#348
+ self._listmkeys() #349 =166
+ self._usemkey('5', 'now+3days') #350 =167
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#351
+ self._listmkeys() #352 =168
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#353
+ self._usemkey('5', 'now+5sec') #354 =169
+ self._listmkeys() #355 =170
+ time.sleep(5) #356
+ self._listmkeys() #357 =171
+ self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#358
+ self._usemkey('4', 'now+5sec') #359 =172
+ self._listmkeys() #360 =173
+ time.sleep(5) #361
+ self._listmkeys() #362 =174
+ self._usemkey('5', 'now+3days') #363 =175
+
+ self._writeLine("------------\n\/\/\/ ERROR EXPECTED below" )#364
+ self._writeLine("should fail, because there must be one mkey currently active") #365
+ self._usemkey('4', 'now+2days', False) #366 =176
+ self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n---------------")
+
+ self._listmkeys() #373 =177
+ self._usemkey('4', '1/30/2009') #375 =178
+
+ self._writeHeader("TEST: purge_mkeys (removing mkey 5)")
+ #print "\nTesting purge_mkeys (removing mkey 5) ==============================================" #378
+ self._purgemkeys() #379 =179
+ #self._stash() #380 =180
+ self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/krb5kdc/.k5.EXAMPLE.ORG") #381=181
+ self._listmkeys() #382 =182
+ self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc K/M'") #383 =183
+ self._writeLine("Testing purge_mkeys Done ==============================================") #384
+ self._writeHeader("MASTER KEY MIGRATION TEST DONE. please consult 'outfile' in your sandbox for more info. The sandbox is at: %s" % self.sandir)
+ # I added
+ self._sysexit(finished=True)
+ '''
+####################################################
+####################################################
+
+class Launcher:
+ #def __init__(self, path, sandP):
+ #def __init__(self):
+ def __init__(self, sandP):
+ self._buildDir = os.environ["PWD"]
+ self._confDir = '%s/tests/mk_migr/ldap_backend/input_conf' % self._buildDir
+
+ #setting up sandbox
+ if sandP != "":
+ self._sandP = sandP
+ else: #default
+ self._sandP = '%s/tests/mk_migr/ldap_backend/sandbox' %self._buildDir
+
+ print self._sandP
+ print "sandP"
+ self._vars = {'sandir': self._sandP,
+ 'localFQDN': socket.getfqdn()}
+
+ def _prepSandbox(self, sandir):
+ if os.path.exists(sandir):
+ shutil.rmtree(sandir)
+ print "------about to make sandbox, with the path of:"
+ print sandir
+ os.makedirs(sandir, 0777)
+ os.mkdir(sandir+'/krb5kdc', 0777)
+ print "------sandbox made"
+
+ def _createFileFromTemplate(self, outpath, template, vars):
+ fin = open(template, 'r')
+ result = fin.read() % vars
+ fin.close()
+ fout = open(outpath, 'w')
+ fout.write(result)
+ fout.close()
+
+ ####### Launcher RUN ################
+ def runLauncher(self):
+ # create sandbox file directory (and sandbox/krb5kdc) if it does not exit
+ self._prepSandbox(self._sandP)
+
+ # Export the 3 env lines
+ src_path=os.environ["PWD"]
+ os.environ["LD_LIBRARY_PATH"] = '%s/lib' % src_path
+
+ str1 = '%s/krb5.conf' % self._sandP
+ os.environ["KRB5_CONFIG"] = str1
+
+ str2 = '%s/kdc.conf' % self._sandP
+ os.environ["KRB5_KDC_PROFILE"] = str2
+
+ str3 = '%s/kadm5.acl' % self._sandP
+
+ # Create adequate to the environment config files
+ self._createFileFromTemplate(str1, '%s/%s' % (self._confDir, 'krb5_template_ldap.conf'), self._vars)
+ self._createFileFromTemplate(str2, '%s/%s' % (self._confDir, 'kdc_template_ldap.conf'), self._vars)
+ self._createFileFromTemplate(str3, '%s/%s' % (self._confDir, 'kadm5_template_ldap.acl'), self._vars)
+
+ return (self._confDir, self._sandP)
+
+####################################################
+####################################################
+
+def makeBool(aStr):
+ if aStr == "True" or aStr == "T":
+ return True
+ if aStr == "False" or aStr == "F":
+ return False
+ else:
+ print "did NOT execute due to invalid True False argument. Please enter either 'True', 'T', 'False', or 'F'"
+ sys.exit()
+
+# # # # # # # # # # # # # # # # # # # # # # # # #
+
+def processInputs(parser):
+#def processInputs():
+
+ # get inputs
+ (options, args) = parser.parse_args()
+
+ verbose = makeBool(options.opVerbose)
+ pw = options.opPassword
+
+ kdcPath = options.opKdcPath #1
+ kdmdPath = options.opKdmdPath #2
+ kdbPath = options.opKdbPath #3a
+ ldapPath = options.opLdapPath #3b
+ kdmlPath = options.opKdmlPath #4
+ kdmPath = options.opKdmPath #5
+ cltPath = options.opCltPath #6
+
+ sandPath = options.opSandbox
+
+ ########### Launch ###############
+
+ print "\n############ Start Launcher #############"
+ myLaunch = Launcher(sandPath)
+ (confDir, sandPath) = myLaunch.runLauncher()
+
+ print ":D"
+ print sandPath
+
+ test = LDAPbackendSetup(verbose, pw, kdcPath, kdmdPath, kdbPath, ldapPath, kdmlPath, kdmPath, cltPath, sandPath, confDir)
+ print "########## Finished Launcher ############\n"
+
+ return test
+# # # # # # # # # # # # # # # # # # # # # # # # #
+
+def makeParser():
+ usage = "\n\t%prog [-v][-p][-c][-d][-b][-l][-t][-s]"
+ description = "Description:\n\tTests for the master key migration commands."
+ parser = OptionParser(usage=usage, description=description)
+
+ parser.add_option("-v", "--verbose", type="string", dest="opVerbose",
+default="True", help="'True' or 'False'. Switch on for details of command lines and outputs. Default is 'True'")
+
+ parser.add_option("-p", "--password", type="string", dest="opPassword", default="test123", help="master password for many of the passwords in the test. Default is 'test123'")
+
+ ## Default Paths
+ dSrcPath = src_path=os.environ["PWD"]
+ dKdcPath = '%s/kdc/krb5kdc' % dSrcPath #1
+ dKdmdPath = '%s/kadmin/server/kadmind' % dSrcPath #2
+ dKdbPath = '%s/kadmin/dbutil/kdb5_util' % dSrcPath #3a
+ dLdapPath = '%s/plugins/kdb/ldap/ldap_util/kdb5_ldap_util' % dSrcPath #3b
+ dKdmlPath = '%s/kadmin/cli/kadmin.local' % dSrcPath #4
+ dKdmPath = '%s/kadmin/cli/kadmin' % dSrcPath #5
+ dCltPath = '%s/clients' % dSrcPath #6
+
+ parser.add_option("-c", "--krb5kdcpath",
+type="string", dest="opKdcPath",
+default=dKdcPath, help="set krb5kdc path, default="+dKdcPath) #1
+
+ parser.add_option("-d", "--kadmindpath",
+type="string", dest="opKdmdPath",
+default=dKdmdPath, help="set kadmind path, default="+dKdmdPath) #2
+
+ parser.add_option("-b", "--kdb5_utilpath",
+type="string", dest="opKdbPath",
+default=dKdbPath, help="set kdb5_util path, default="+dKdbPath) #3a
+
+ parser.add_option("-a", "--kdb5_ldap_utilpath",
+type="string", dest="opLdapPath",
+default=dKdbPath, help="set kdb5_ldap_util path, default="+dLdapPath) #3b
+
+ parser.add_option("-l", "--kadminlocalpath",
+type="string", dest="opKdmlPath",
+default=dKdmlPath, help="set kadmin.local path, default="+dKdmlPath) #4
+
+ parser.add_option("-n", "--kadminpath",
+type="string", dest="opKdmPath",
+default=dKdmPath, help="set kadmin path, default="+dKdmPath) #5
+
+ parser.add_option("-t", "--clientspath",
+type="string", dest="opCltPath",
+default=dCltPath, help="set clients path, default="+dCltPath) #6
+
+ # set up / initializing stuff for the sandbox
+ parser.add_option("-s", "--sandbox",
+type="string", dest="opSandbox",
+default="",
+help="path for the sandbox. Default is 'src/tests/mk_migr/ldap_backend/sandbox'")
+
+ return parser
+
+####################################################
+if __name__ == '__main__':
+ #processInputs()
+
+ parser = makeParser()
+ test = processInputs(parser)
+ result = test.run()
../../lib/crypto/krb/crc32/OBJS.ST \
../../lib/crypto/builtin/des/OBJS.ST \
../../lib/crypto/krb/dk/OBJS.ST \
- ../../lib/crypto/krb/enc_provider/OBJS.ST \
+ ../../lib/crypto/builtin/enc_provider/OBJS.ST \
../../lib/crypto/krb/hash_provider/OBJS.ST \
../../lib/crypto/krb/keyhash_provider/OBJS.ST \
../../lib/crypto/builtin/md4/OBJS.ST \
#endif
#if defined (__linux__) && defined(HAVE_GETADDRINFO)
-# define COPY_FIRST_CANONNAME
+/* Define COPY_FIRST_CANONNAME for glibc 2.3 and prior. */
+#include <features.h>
+# ifdef __GLIBC_PREREQ
+# if ! __GLIBC_PREREQ(2, 4)
+# define COPY_FIRST_CANONNAME
+# endif
+# else
+# define COPY_FIRST_CANONNAME
+# endif
#endif
#ifdef _AIX
return aierr;
}
- /* Linux libc version 6 (libc-2.2.4.so on Debian) is broken.
+ /* Linux libc version 6 prior to 2.3.4 is broken.
RFC 2553 says that when AI_CANONNAME is set, the ai_canonname
flag of the first returned structure has the canonical name of
Ref: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=133668 .
Since it's dependent on the target hostname, it's hard to check
- for at configure time. Always do it on Linux for now. When
- they get around to fixing it, add a compile-time or run-time
- check for the glibc version in use.
+ for at configure time. The bug was fixed in glibc 2.3.4.
+ After the fix, the ai_canonname field is allocated, so our
+ workaround leaks memory. We disable the workaround for glibc
+ >= 2.4, but there is no easy way to test for glibc patch
+ versions, so we still leak memory under glibc 2.3.4 through
+ 2.3.6.
Some Windows documentation says that even when AI_CANONNAME is
set, the returned ai_canonname field can be null. The NetBSD